/[LeafOK_CVS]/lbbs/src/section_list.c
ViewVC logotype

Diff of /lbbs/src/section_list.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

Revision 1.10 by sysadm, Fri May 23 00:12:59 2025 UTC Revision 1.13 by sysadm, Fri May 23 14:04:05 2025 UTC
# Line 31  Line 31 
31  #define ARTICLE_BLOCK_SHM_COUNT_LIMIT 256 // limited by length (8-bit) of proj_id in ftok(path, proj_id)  #define ARTICLE_BLOCK_SHM_COUNT_LIMIT 256 // limited by length (8-bit) of proj_id in ftok(path, proj_id)
32  #define ARTICLE_BLOCK_PER_POOL (ARTICLE_BLOCK_PER_SHM * ARTICLE_BLOCK_SHM_COUNT_LIMIT)  #define ARTICLE_BLOCK_PER_POOL (ARTICLE_BLOCK_PER_SHM * ARTICLE_BLOCK_SHM_COUNT_LIMIT)
33    
34    #define CALCULATE_PAGE_THRESHOLD 100 // Adjust to tune performance of move topic
35    
36  struct article_block_t  struct article_block_t
37  {  {
38          ARTICLE articles[ARTICLE_PER_BLOCK];          ARTICLE articles[ARTICLE_PER_BLOCK];
# Line 58  typedef struct article_block_pool_t ARTI Line 60  typedef struct article_block_pool_t ARTI
60    
61  static ARTICLE_BLOCK_POOL *p_article_block_pool = NULL;  static ARTICLE_BLOCK_POOL *p_article_block_pool = NULL;
62    
63    static int section_list_pool_shmid;
64  static SECTION_LIST *p_section_list_pool = NULL;  static SECTION_LIST *p_section_list_pool = NULL;
65  static int section_list_count = 0;  static int section_list_count = 0;
66  static TRIE_NODE *p_trie_dict_section_list = NULL;  static TRIE_NODE *p_trie_dict_section_list = NULL;
# Line 309  ARTICLE *article_block_find_by_index(int Line 312  ARTICLE *article_block_find_by_index(int
312          return (p_block->articles + (index % ARTICLE_PER_BLOCK));          return (p_block->articles + (index % ARTICLE_PER_BLOCK));
313  }  }
314    
315  SECTION_LIST *section_list_create(const char *sname, const char *stitle, const char *master_name)  extern int section_list_pool_init(const char *filename)
316  {  {
317          SECTION_LIST *p_section;          int shmid;
318            int proj_id;
319            key_t key;
320            size_t size;
321            void *p_shm;
322    
323            if (p_section_list_pool == NULL || p_trie_dict_section_list == NULL)
324            {
325                    section_list_pool_cleanup();
326            }
327    
328            p_section_list_pool = calloc(BBS_max_section, sizeof(SECTION_LIST));
329          if (p_section_list_pool == NULL)          if (p_section_list_pool == NULL)
330          {          {
331                  p_section_list_pool = calloc(BBS_max_section, sizeof(SECTION_LIST));                  log_error("calloc(%d SECTION_LIST) OOM\n", BBS_max_section);
332                  if (p_section_list_pool == NULL)                  return -1;
333                  {          }
                         log_error("calloc(%d SECTION_LIST) OOM\n", BBS_max_section);  
                         return NULL;  
                 }  
334    
335                  section_list_count = 0;          proj_id = (int)(time(NULL) % getpid());
336            key = ftok(filename, proj_id);
337            if (key == -1)
338            {
339                    log_error("ftok(%s, %d) error (%d)\n", filename, proj_id, errno);
340                    return -3;
341          }          }
342    
343            size = sizeof(shmid) + sizeof(SECTION_LIST) * BBS_max_section;
344            shmid = shmget(key, size, IPC_CREAT | IPC_EXCL | 0600);
345            if (shmid == -1)
346            {
347                    log_error("shmget(section_list_pool, size = %d) error (%d)\n", size, errno);
348                    return -3;
349            }
350            p_shm = shmat(shmid, NULL, 0);
351            if (p_shm == (void *)-1)
352            {
353                    log_error("shmat(shmid = %d) error (%d)\n", shmid, errno);
354                    return -3;
355            }
356    
357            section_list_pool_shmid = shmid;
358            p_section_list_pool = p_shm;
359            section_list_count = 0;
360    
361            p_trie_dict_section_list = trie_dict_create();
362          if (p_trie_dict_section_list == NULL)          if (p_trie_dict_section_list == NULL)
363          {          {
364                  p_trie_dict_section_list = trie_dict_create();                  log_error("trie_dict_create() OOM\n", BBS_max_section);
365                  if (p_trie_dict_section_list == NULL)                  return -2;
366                  {          }
367                          log_error("trie_dict_create() OOM\n", BBS_max_section);  
368                          return NULL;          return 0;
369                  }  }
370    
371    SECTION_LIST *section_list_create(int32_t sid, const char *sname, const char *stitle, const char *master_name)
372    {
373            SECTION_LIST *p_section;
374    
375            if (p_section_list_pool == NULL || p_trie_dict_section_list == NULL)
376            {
377                    log_error("session_list_pool not initialized\n");
378                    return NULL;
379          }          }
380    
381          if (section_list_count >= BBS_max_section)          if (section_list_count >= BBS_max_section)
382          {          {
383                  log_error("section_list_count exceed limit %d\n", BBS_max_section);                  log_error("section_list_count exceed limit %d >= %d\n", section_list_count, BBS_max_section);
384                  return NULL;                  return NULL;
385          }          }
386    
387          p_section = p_section_list_pool + section_list_count;          p_section = p_section_list_pool + section_list_count;
388    
389            p_section->sid = sid;
390    
391          strncpy(p_section->sname, sname, sizeof(p_section->sname - 1));          strncpy(p_section->sname, sname, sizeof(p_section->sname - 1));
392          p_section->sname[sizeof(p_section->sname - 1)] = '\0';          p_section->sname[sizeof(p_section->sname - 1)] = '\0';
393    
# Line 378  void section_list_reset_articles(SECTION Line 423  void section_list_reset_articles(SECTION
423          p_section->last_page_visible_article_count = 0;          p_section->last_page_visible_article_count = 0;
424  }  }
425    
426  void section_list_cleanup(void)  void section_list_pool_cleanup(void)
427  {  {
428          if (p_trie_dict_section_list != NULL)          if (p_trie_dict_section_list != NULL)
429          {          {
# Line 388  void section_list_cleanup(void) Line 433  void section_list_cleanup(void)
433    
434          if (p_section_list_pool != NULL)          if (p_section_list_pool != NULL)
435          {          {
436                  free(p_section_list_pool);                  if (shmdt(p_section_list_pool) == -1)
437                    {
438                            log_error("shmdt(shmid = %d) error (%d)\n", section_list_pool_shmid, errno);
439                    }
440                  p_section_list_pool = NULL;                  p_section_list_pool = NULL;
441    
442                    if (shmctl(section_list_pool_shmid, IPC_RMID, NULL) == -1)
443                    {
444                            log_error("shmctl(shmid = %d, IPC_RMID) error (%d)\n", section_list_pool_shmid, errno);
445                    }
446          }          }
447    
448          section_list_count = 0;          section_list_count = 0;
# Line 530  int section_list_append_article(SECTION_ Line 583  int section_list_append_article(SECTION_
583          p_section->p_article_tail = p_article;          p_section->p_article_tail = p_article;
584    
585          // Update page          // Update page
586          if (p_article->visible && p_section->last_page_visible_article_count % BBS_article_limit_per_page == 0)          if ((p_article->visible && p_section->last_page_visible_article_count % BBS_article_limit_per_page == 0) ||
587                    p_section->article_count == 1)
588          {          {
589                  p_section->p_page_first_article[p_section->page_count] = p_article;                  p_section->p_page_first_article[p_section->page_count] = p_article;
590                  p_section->page_count++;                  p_section->page_count++;
# Line 610  int section_list_set_article_visible(SEC Line 664  int section_list_set_article_visible(SEC
664          return affected_count;          return affected_count;
665  }  }
666    
667  ARTICLE *section_list_find_article_with_offset(SECTION_LIST *p_section, int32_t aid, int32_t *p_page, int32_t *p_offset)  ARTICLE *section_list_find_article_with_offset(SECTION_LIST *p_section, int32_t aid, int32_t *p_page, int32_t *p_offset, ARTICLE **pp_next)
668  {  {
669          ARTICLE *p_article;          ARTICLE *p_article;
670          int left;          int left;
# Line 619  ARTICLE *section_list_find_article_with_ Line 673  ARTICLE *section_list_find_article_with_
673    
674          *p_page = -1;          *p_page = -1;
675          *p_offset = -1;          *p_offset = -1;
676            *pp_next = NULL;
677    
678          if (p_section == NULL)          if (p_section == NULL)
679          {          {
# Line 663  ARTICLE *section_list_find_article_with_ Line 718  ARTICLE *section_list_find_article_with_
718          p_article = p_section->p_page_first_article[*p_page];          p_article = p_section->p_page_first_article[*p_page];
719    
720          // p_section->p_page_first_article[*p_page]->aid <= aid < p_section->p_page_first_article[*p_page + 1]->aid          // p_section->p_page_first_article[*p_page]->aid <= aid < p_section->p_page_first_article[*p_page + 1]->aid
721          right = (*p_page == MAX(1, p_section->page_count) - 1 ? INT32_MAX : p_section->p_page_first_article[*p_page + 1]->aid);          right = (*p_page == MAX(0, p_section->page_count - 1) ? INT32_MAX : p_section->p_page_first_article[*p_page + 1]->aid);
722    
723          // left will be the offset of article found or offset to insert          // left will be the offset of article found or offset to insert
724          left = 0;          left = 0;
725    
726          while (aid > p_article->aid)          while (aid > p_article->aid)
727          {          {
                 // aid > p_article->aid  
728                  p_article = p_article->p_next;                  p_article = p_article->p_next;
729                  left++;                  left++;
730    
731                    if (aid == p_article->aid)
732                    {
733                            *pp_next = p_article->p_next;
734                            break;
735                    }
736    
737                  // over last article in the page                  // over last article in the page
738                  if (p_article == p_section->p_article_head || p_article->aid >= right)                  if (p_article == p_section->p_article_head || p_article->aid >= right)
739                  {                  {
740                          break;                          *pp_next = (p_article == p_section->p_article_head ? p_section->p_article_head : p_section->p_page_first_article[*p_page + 1]);
741                            *p_offset = left;
742                            return NULL; // not found
743                  }                  }
744          }          }
745    
746          if (aid != p_article->aid) // not exist          if (aid < p_article->aid)
747            {
748                    *pp_next = p_article;
749                    p_article = NULL; // not found
750            }
751            else // aid == p_article->aid
752          {          {
753                  p_article = NULL;                  *pp_next = p_article->p_next;
754          }          }
755    
756          *p_offset = left;          *p_offset = left;
# Line 694  ARTICLE *section_list_find_article_with_ Line 761  ARTICLE *section_list_find_article_with_
761  int section_list_calculate_page(SECTION_LIST *p_section, int32_t start_aid)  int section_list_calculate_page(SECTION_LIST *p_section, int32_t start_aid)
762  {  {
763          ARTICLE *p_article;          ARTICLE *p_article;
764            ARTICLE *p_next;
765          int32_t page;          int32_t page;
766          int32_t offset;          int32_t offset;
767          int visible_article_count;          int visible_article_count;
# Line 705  int section_list_calculate_page(SECTION_ Line 773  int section_list_calculate_page(SECTION_
773                  return -1;                  return -1;
774          }          }
775    
776          p_article = section_list_find_article_with_offset(p_section, start_aid, &page, &offset);          if (p_section->article_count == 0) // empty
         if (p_article == NULL)  
777          {          {
778                  if (page < 0)                  p_section->page_count = 0;
779                    p_section->last_page_visible_article_count = 0;
780    
781                    return 0;
782            }
783    
784            if (start_aid > 0)
785            {
786                    p_article = section_list_find_article_with_offset(p_section, start_aid, &page, &offset, &p_next);
787                    if (p_article == NULL)
788                  {                  {
789                          return 0;                          if (page < 0)
790                            {
791                                    return -1;
792                            }
793                            log_error("section_list_calculate_page() aid = %d not found in section sid = %d\n",
794                                              start_aid, p_section->sid);
795                            return -2;
796                  }                  }
797    
798                  log_error("section_list_calculate_page() aid = %d not found in section sid = %d\n", start_aid, p_section->sid);                  if (offset > 0)
799                    {
800                            p_article = p_section->p_page_first_article[page];
801                    }
802          }          }
803            else
         if (offset > 0)  
804          {          {
805                  p_article = p_section->p_page_first_article[page];                  p_article = p_section->p_article_head;
806                    page = 0;
807                    offset = 0;
808          }          }
809    
810          visible_article_count = 0;          visible_article_count = 0;
# Line 764  int section_list_calculate_page(SECTION_ Line 850  int section_list_calculate_page(SECTION_
850    
851          return 0;          return 0;
852  }  }
853    
854    int section_list_count_of_topic_articles(int32_t aid)
855    {
856            ARTICLE *p_article;
857            int article_count;
858    
859            p_article = article_block_find_by_aid(aid);
860            if (p_article == NULL)
861            {
862                    return 0; // Not found
863            }
864    
865            article_count = 0;
866    
867            do
868            {
869                    article_count++;
870                    p_article = p_article->p_topic_next;
871            } while (p_article->aid != aid);
872    
873            return article_count;
874    }
875    
876    int section_list_move_topic(SECTION_LIST *p_section_src, SECTION_LIST *p_section_dest, int32_t aid)
877    {
878            ARTICLE *p_article;
879            ARTICLE *p_next;
880            int32_t page;
881            int32_t offset;
882            int32_t move_article_count;
883            int32_t dest_article_count_old;
884            int32_t last_unaffected_aid_src;
885            int32_t first_inserted_aid_dest;
886            int move_counter;
887    
888            if (p_section_dest == NULL)
889            {
890                    log_error("section_list_move_topic() NULL pointer error\n");
891                    return -1;
892            }
893    
894            if ((p_article = section_list_find_article_with_offset(p_section_src, aid, &page, &offset, &p_next)) == NULL)
895            {
896                    log_error("section_list_move_topic() error: article %d not found in section %d\n", aid, p_section_src->sid);
897                    return -2;
898            }
899    
900            if (p_article->tid != 0)
901            {
902                    log_error("section_list_move_topic(aid = %d) error: article is not head of topic, tid = %d\n", aid, p_article->tid);
903                    return -2;
904            }
905    
906            last_unaffected_aid_src = (p_article == p_section_src->p_article_head ? 0 : p_article->p_prior->aid);
907    
908            move_article_count = section_list_count_of_topic_articles(aid);
909            if (move_article_count <= 0)
910            {
911                    log_error("section_list_count_of_topic_articles(aid = %d) <= 0\n", aid);
912                    return -2;
913            }
914    
915            if (p_section_dest->article_count + move_article_count > BBS_article_limit_per_section)
916            {
917                    log_error("section_list_move_topic() error: article_count %d reach limit in section %d\n",
918                                      p_section_dest->article_count + move_article_count, p_section_dest->sid);
919                    return -3;
920            }
921    
922            dest_article_count_old = p_section_dest->article_count;
923            move_counter = 0;
924            first_inserted_aid_dest = p_article->aid;
925    
926            do
927            {
928                    if (section_list_find_article_with_offset(p_section_dest, p_article->aid, &page, &offset, &p_next) != NULL)
929                    {
930                            log_error("section_list_move_topic() error: article %d already in section %d\n", p_article->aid, p_section_dest->sid);
931                            return -4;
932                    }
933    
934                    // Remove from bi-directional article list of src section
935                    if (p_section_src->p_article_head == p_article)
936                    {
937                            p_section_src->p_article_head = p_article->p_next;
938                    }
939                    if (p_section_src->p_article_tail == p_article)
940                    {
941                            p_section_src->p_article_tail = p_article->p_prior;
942                    }
943                    if (p_section_src->p_article_head == p_article) // || p_section_src->p_article_tail == p_article
944                    {
945                            p_section_src->p_article_head = NULL;
946                            p_section_src->p_article_tail = NULL;
947                    }
948    
949                    p_article->p_prior->p_next = p_article->p_next;
950                    p_article->p_next->p_prior = p_article->p_prior;
951    
952                    // Insert into bi-directional article list of dest section
953                    if (p_next == NULL) // empty section
954                    {
955                            p_section_dest->p_article_head = p_article;
956                            p_section_dest->p_article_tail = p_article;
957                            p_article->p_prior = p_article;
958                            p_article->p_next = p_article;
959                    }
960                    else
961                    {
962                            if (p_section_dest->p_article_head == p_next)
963                            {
964                                    if (p_article->aid < p_next->aid)
965                                    {
966                                            p_section_dest->p_article_head = p_article;
967                                    }
968                                    else // p_article->aid > p_next->aid
969                                    {
970                                            p_section_dest->p_article_tail = p_article;
971                                    }
972                            }
973    
974                            p_article->p_prior = p_next->p_prior;
975                            p_article->p_next = p_next;
976                            p_next->p_prior->p_next = p_article;
977                            p_next->p_prior = p_article;
978                    }
979    
980                    // Update article / topic counter of src / desc section
981                    p_section_src->article_count--;
982                    p_section_dest->article_count++;
983                    if (p_article->tid == 0)
984                    {
985                            p_section_src->topic_count--;
986                            p_section_dest->topic_count++;
987                    }
988    
989                    // Update visible article / topic counter of src / desc section
990                    if (p_article->visible)
991                    {
992                            p_section_src->visible_article_count--;
993                            p_section_dest->visible_article_count++;
994                            if (p_article->tid == 0)
995                            {
996                                    p_section_src->visible_topic_count--;
997                                    p_section_dest->visible_topic_count++;
998                            }
999                    }
1000    
1001                    // Update page for empty dest section
1002                    if (p_section_dest->article_count == 1)
1003                    {
1004                            p_section_dest->p_page_first_article[0] = p_article;
1005                            p_section_dest->page_count = 1;
1006                            p_section_dest->last_page_visible_article_count = (p_article->visible ? 1 : 0);
1007                    }
1008    
1009                    p_article = p_article->p_topic_next;
1010    
1011                    move_counter++;
1012                    if (move_counter % CALCULATE_PAGE_THRESHOLD == 0)
1013                    {
1014                            // Re-calculate pages of desc section
1015                            if (section_list_calculate_page(p_section_dest, first_inserted_aid_dest) < 0)
1016                            {
1017                                    log_error("section_list_calculate_page(section = %d, aid = %d) error\n",
1018                                                      p_section_dest->sid, first_inserted_aid_dest);
1019                            }
1020    
1021                            first_inserted_aid_dest = p_article->aid;
1022                    }
1023            } while (p_article->aid != aid);
1024    
1025            if (p_section_dest->article_count - dest_article_count_old != move_article_count)
1026            {
1027                    log_error("section_list_move_topic() error: count of moved articles %d != %d\n",
1028                                      p_section_dest->article_count - dest_article_count_old, move_article_count);
1029            }
1030    
1031            // Re-calculate pages of src section
1032            if (section_list_calculate_page(p_section_src, last_unaffected_aid_src) < 0)
1033            {
1034                    log_error("section_list_calculate_page(section = %d, aid = %d) error at aid = %d\n",
1035                                      p_section_src->sid, last_unaffected_aid_src, aid);
1036            }
1037    
1038            if (move_counter % CALCULATE_PAGE_THRESHOLD != 0)
1039            {
1040                    // Re-calculate pages of desc section
1041                    if (section_list_calculate_page(p_section_dest, first_inserted_aid_dest) < 0)
1042                    {
1043                            log_error("section_list_calculate_page(section = %d, aid = %d) error\n",
1044                                              p_section_dest->sid, first_inserted_aid_dest);
1045                    }
1046            }
1047    
1048            return move_article_count;
1049    }


Legend:
Removed lines/characters  
Changed lines/characters
  Added lines/characters

webmaster@leafok.com
ViewVC Help
Powered by ViewVC 1.3.0-beta1