/[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.7 by sysadm, Thu May 22 06:20:47 2025 UTC Revision 1.12 by sysadm, Fri May 23 10:45:54 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 309  ARTICLE *article_block_find_by_index(int Line 311  ARTICLE *article_block_find_by_index(int
311          return (p_block->articles + (index % ARTICLE_PER_BLOCK));          return (p_block->articles + (index % ARTICLE_PER_BLOCK));
312  }  }
313    
314  SECTION_LIST *section_list_create(const char *sname, const char *stitle, const char *master_name)  SECTION_LIST *section_list_create(int32_t sid, const char *sname, const char *stitle, const char *master_name)
315  {  {
316          SECTION_LIST *p_section;          SECTION_LIST *p_section;
317    
# Line 343  SECTION_LIST *section_list_create(const Line 345  SECTION_LIST *section_list_create(const
345    
346          p_section = p_section_list_pool + section_list_count;          p_section = p_section_list_pool + section_list_count;
347    
348            p_section->sid = sid;
349    
350          strncpy(p_section->sname, sname, sizeof(p_section->sname - 1));          strncpy(p_section->sname, sname, sizeof(p_section->sname - 1));
351          p_section->sname[sizeof(p_section->sname - 1)] = '\0';          p_section->sname[sizeof(p_section->sname - 1)] = '\0';
352    
# Line 368  SECTION_LIST *section_list_create(const Line 372  SECTION_LIST *section_list_create(const
372  void section_list_reset_articles(SECTION_LIST *p_section)  void section_list_reset_articles(SECTION_LIST *p_section)
373  {  {
374          p_section->article_count = 0;          p_section->article_count = 0;
375            p_section->topic_count = 0;
376            p_section->visible_article_count = 0;
377            p_section->visible_topic_count = 0;
378          p_section->p_article_head = NULL;          p_section->p_article_head = NULL;
379          p_section->p_article_tail = NULL;          p_section->p_article_tail = NULL;
380    
381          p_section->page_count = 0;          p_section->page_count = 0;
382          p_section->last_page_article_count = 0;          p_section->last_page_visible_article_count = 0;
383  }  }
384    
385  void section_list_cleanup(void)  void section_list_cleanup(void)
# Line 431  int section_list_append_article(SECTION_ Line 438  int section_list_append_article(SECTION_
438                  return -1;                  return -1;
439          }          }
440    
441            if (p_section->article_count >= BBS_article_limit_per_section)
442            {
443                    log_error("section_list_append_article() error: article_count reach limit in section %d\n", p_section->sid);
444                    return -2;
445            }
446    
447          if (p_article_block_pool->block_count == 0 ||          if (p_article_block_pool->block_count == 0 ||
448                  p_article_block_pool->p_block[p_article_block_pool->block_count - 1]->article_count >= ARTICLE_PER_BLOCK)                  p_article_block_pool->p_block[p_article_block_pool->block_count - 1]->article_count >= ARTICLE_PER_BLOCK)
449          {          {
# Line 468  int section_list_append_article(SECTION_ Line 481  int section_list_append_article(SECTION_
481          // Copy article data          // Copy article data
482          *p_article = *p_article_src;          *p_article = *p_article_src;
483    
484            if (p_article->visible)
485            {
486                    p_section->visible_article_count++;
487            }
488    
489          // Link appended article as tail node of topic bi-directional list          // Link appended article as tail node of topic bi-directional list
490          if (p_article->tid != 0)          if (p_article->tid != 0)
491          {          {
# Line 487  int section_list_append_article(SECTION_ Line 505  int section_list_append_article(SECTION_
505          }          }
506          else          else
507          {          {
508                    p_section->topic_count++;
509    
510                    if (p_article->visible)
511                    {
512                            p_section->visible_topic_count++;
513                    }
514    
515                  p_topic_head = p_article;                  p_topic_head = p_article;
516                  p_topic_tail = p_article;                  p_topic_tail = p_article;
517          }          }
# Line 509  int section_list_append_article(SECTION_ Line 534  int section_list_append_article(SECTION_
534          p_section->p_article_tail = p_article;          p_section->p_article_tail = p_article;
535    
536          // Update page          // Update page
537          if (p_section->last_page_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) ||
538                    p_section->article_count == 1)
539          {          {
540                  p_section->p_page_first_article[p_section->page_count] = p_article;                  p_section->p_page_first_article[p_section->page_count] = p_article;
541                  p_section->page_count++;                  p_section->page_count++;
542                  p_section->last_page_article_count = 0;                  p_section->last_page_visible_article_count = 0;
543            }
544    
545            if (p_article->visible)
546            {
547                    p_section->last_page_visible_article_count++;
548          }          }
         p_section->last_page_article_count++;  
549    
550          return 0;          return 0;
551  }  }
# Line 523  int section_list_append_article(SECTION_ Line 553  int section_list_append_article(SECTION_
553  int section_list_set_article_visible(SECTION_LIST *p_section, int32_t aid, int8_t visible)  int section_list_set_article_visible(SECTION_LIST *p_section, int32_t aid, int8_t visible)
554  {  {
555          ARTICLE *p_article;          ARTICLE *p_article;
556            ARTICLE *p_reply;
557            int affected_count = 0;
558    
559          if (p_section == NULL)          if (p_section == NULL)
560          {          {
# Line 541  int section_list_set_article_visible(SEC Line 573  int section_list_set_article_visible(SEC
573                  return 0; // Already set                  return 0; // Already set
574          }          }
575    
576            if (visible == 0) // 1 -> 0
577            {
578                    p_section->visible_article_count--;
579    
580                    if (p_article->tid == 0)
581                    {
582                            p_section->visible_topic_count--;
583    
584                            // Set related visible replies to invisible
585                            for (p_reply = p_article->p_topic_next; p_reply->tid != 0; p_reply = p_reply->p_topic_next)
586                            {
587                                    if (p_reply->tid != aid)
588                                    {
589                                            log_error("Inconsistent tid = %d found in reply %d of topic %d\n", p_reply->tid, p_reply->aid, aid);
590                                            continue;
591                                    }
592    
593                                    if (p_reply->visible == 1)
594                                    {
595                                            p_reply->visible = 0;
596                                            p_section->visible_article_count--;
597                                            affected_count++;
598                                    }
599                            }
600                    }
601            }
602            else // 0 -> 1
603            {
604                    p_section->visible_article_count++;
605    
606                    if (p_article->tid == 0)
607                    {
608                            p_section->visible_topic_count++;
609                    }
610            }
611    
612          p_article->visible = visible;          p_article->visible = visible;
613            affected_count++;
614    
615            return affected_count;
616    }
617    
618    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)
619    {
620            ARTICLE *p_article;
621            int left;
622            int right;
623            int mid;
624    
625            *p_page = -1;
626            *p_offset = -1;
627            *pp_next = NULL;
628    
629            if (p_section == NULL)
630            {
631                    log_error("section_list_find_article_with_offset() NULL pointer error\n");
632                    return NULL;
633            }
634    
635            if (p_section->article_count == 0) // empty
636            {
637                    *p_page = 0;
638                    *p_offset = 0;
639                    return NULL;
640            }
641    
642            left = 0;
643            right = p_section->page_count;
644    
645            // aid in the range [ head aid of pages[left], tail aid of pages[right - 1] ]
646            while (left < right - 1)
647            {
648                    // get page id no less than mid value of left page id and right page id
649                    mid = (left + right) / 2 + (right - left) % 2;
650    
651                    if (mid >= p_section->page_count)
652                    {
653                            log_error("page id (mid = %d) is out of boundary\n", mid);
654                            return NULL;
655                    }
656    
657                    if (aid < p_section->p_page_first_article[mid]->aid)
658                    {
659                            right = mid;
660                    }
661                    else
662                    {
663                            left = mid;
664                    }
665            }
666    
667            *p_page = left;
668    
669            p_article = p_section->p_page_first_article[*p_page];
670    
671            // p_section->p_page_first_article[*p_page]->aid <= aid < p_section->p_page_first_article[*p_page + 1]->aid
672            right = (*p_page == MAX(0, p_section->page_count - 1) ? INT32_MAX : p_section->p_page_first_article[*p_page + 1]->aid);
673    
674            // left will be the offset of article found or offset to insert
675            left = 0;
676    
677            while (aid > p_article->aid)
678            {
679                    p_article = p_article->p_next;
680                    left++;
681    
682                    if (aid == p_article->aid)
683                    {
684                            *pp_next = p_article->p_next;
685                            break;
686                    }
687    
688                    // over last article in the page
689                    if (p_article == p_section->p_article_head || p_article->aid >= right)
690                    {
691                            *pp_next = (p_article == p_section->p_article_head ? p_section->p_article_head : p_section->p_page_first_article[*p_page + 1]);
692                            *p_offset = left;
693                            return NULL; // not found
694                    }
695            }
696    
697            if (aid < p_article->aid)
698            {
699                    *pp_next = p_article;
700                    p_article = NULL; // not found
701            }
702            else // aid == p_article->aid
703            {
704                    *pp_next = p_article->p_next;
705            }
706    
707            *p_offset = left;
708    
709            return p_article;
710    }
711    
712    int section_list_calculate_page(SECTION_LIST *p_section, int32_t start_aid)
713    {
714            ARTICLE *p_article;
715            ARTICLE *p_next;
716            int32_t page;
717            int32_t offset;
718            int visible_article_count;
719            int page_head_set;
720    
721            if (p_section == NULL)
722            {
723                    log_error("section_list_calculate_page() NULL pointer error\n");
724                    return -1;
725            }
726    
727            if (p_section->article_count == 0) // empty
728            {
729                    p_section->page_count = 0;
730                    p_section->last_page_visible_article_count = 0;
731    
732                    return 0;
733            }
734    
735            if (start_aid > 0)
736            {
737                    p_article = section_list_find_article_with_offset(p_section, start_aid, &page, &offset, &p_next);
738                    if (p_article == NULL)
739                    {
740                            if (page < 0)
741                            {
742                                    return -1;
743                            }
744                            log_error("section_list_calculate_page() aid = %d not found in section sid = %d\n",
745                                              start_aid, p_section->sid);
746                            return -2;
747                    }
748    
749                    if (offset > 0)
750                    {
751                            p_article = p_section->p_page_first_article[page];
752                    }
753            }
754            else
755            {
756                    p_article = p_section->p_article_head;
757                    page = 0;
758                    offset = 0;
759            }
760    
761            visible_article_count = 0;
762            page_head_set = 0;
763    
764            do
765            {
766                    if (!page_head_set && visible_article_count == 0)
767                    {
768                            p_section->p_page_first_article[page] = p_article;
769                            page_head_set = 1;
770                    }
771    
772          // TODO:                  if (p_article->visible)
773                    {
774                            visible_article_count++;
775                    }
776    
777                    p_article = p_article->p_next;
778    
779                    // skip remaining invisible articles
780                    while (p_article->visible == 0 && p_article != p_section->p_article_head)
781                    {
782                            p_article = p_article->p_next;
783                    }
784    
785                    if (visible_article_count >= BBS_article_limit_per_page && p_article != p_section->p_article_head)
786                    {
787                            page++;
788                            visible_article_count = 0;
789                            page_head_set = 0;
790    
791                            if (page >= BBS_article_limit_per_section / BBS_article_limit_per_page && p_article != p_section->p_article_head)
792                            {
793                                    log_error("Count of page exceed limit in section %d\n", p_section->sid);
794                                    break;
795                            }
796                    }
797            } while (p_article != p_section->p_article_head);
798    
799            p_section->page_count = page + (visible_article_count > 0 ? 1 : 0);
800            p_section->last_page_visible_article_count = visible_article_count;
801    
802            return 0;
803    }
804    
805    int section_list_count_of_topic_articles(int32_t aid)
806    {
807            ARTICLE *p_article;
808            int article_count;
809    
810            p_article = article_block_find_by_aid(aid);
811            if (p_article == NULL)
812            {
813                    return 0; // Not found
814            }
815    
816            article_count = 0;
817    
818            do
819            {
820                    article_count++;
821                    p_article = p_article->p_topic_next;
822            } while (p_article->aid != aid);
823    
824            return article_count;
825    }
826    
827    int section_list_move_topic(SECTION_LIST *p_section_src, SECTION_LIST *p_section_dest, int32_t aid)
828    {
829            ARTICLE *p_article;
830            ARTICLE *p_next;
831            int32_t page;
832            int32_t offset;
833            int32_t move_article_count;
834            int32_t dest_article_count_old;
835            int32_t last_unaffected_aid_src;
836            int32_t first_inserted_aid_dest;
837            int move_counter;
838    
839            if (p_section_dest == NULL)
840            {
841                    log_error("section_list_move_topic() NULL pointer error\n");
842                    return -1;
843            }
844    
845            if ((p_article = section_list_find_article_with_offset(p_section_src, aid, &page, &offset, &p_next)) == NULL)
846            {
847                    log_error("section_list_move_topic() error: article %d not found in section %d\n", aid, p_section_src->sid);
848                    return -2;
849            }
850    
851            if (p_article->tid != 0)
852            {
853                    log_error("section_list_move_topic(aid = %d) error: article is not head of topic, tid = %d\n", aid, p_article->tid);
854                    return -2;
855            }
856    
857            last_unaffected_aid_src = (p_article == p_section_src->p_article_head ? 0 : p_article->p_prior->aid);
858    
859            move_article_count = section_list_count_of_topic_articles(aid);
860            if (move_article_count <= 0)
861            {
862                    log_error("section_list_count_of_topic_articles(aid = %d) <= 0\n", aid);
863                    return -2;
864            }
865    
866            if (p_section_dest->article_count + move_article_count > BBS_article_limit_per_section)
867            {
868                    log_error("section_list_move_topic() error: article_count %d reach limit in section %d\n",
869                                      p_section_dest->article_count + move_article_count, p_section_dest->sid);
870                    return -3;
871            }
872    
873            dest_article_count_old = p_section_dest->article_count;
874            move_counter = 0;
875            first_inserted_aid_dest = p_article->aid;
876    
877            do
878            {
879                    if (section_list_find_article_with_offset(p_section_dest, p_article->aid, &page, &offset, &p_next) != NULL)
880                    {
881                            log_error("section_list_move_topic() error: article %d already in section %d\n", p_article->aid, p_section_dest->sid);
882                            return -4;
883                    }
884    
885                    // Remove from bi-directional article list of src section
886                    if (p_section_src->p_article_head == p_article)
887                    {
888                            p_section_src->p_article_head = p_article->p_next;
889                    }
890                    if (p_section_src->p_article_tail == p_article)
891                    {
892                            p_section_src->p_article_tail = p_article->p_prior;
893                    }
894                    if (p_section_src->p_article_head == p_article) // || p_section_src->p_article_tail == p_article
895                    {
896                            p_section_src->p_article_head = NULL;
897                            p_section_src->p_article_tail = NULL;
898                    }
899    
900                    p_article->p_prior->p_next = p_article->p_next;
901                    p_article->p_next->p_prior = p_article->p_prior;
902    
903                    // Insert into bi-directional article list of dest section
904                    if (p_next == NULL) // empty section
905                    {
906                            p_section_dest->p_article_head = p_article;
907                            p_section_dest->p_article_tail = p_article;
908                            p_article->p_prior = p_article;
909                            p_article->p_next = p_article;
910                    }
911                    else
912                    {
913                            if (p_section_dest->p_article_head == p_next)
914                            {
915                                    if (p_article->aid < p_next->aid)
916                                    {
917                                            p_section_dest->p_article_head = p_article;
918                                    }
919                                    else // p_article->aid > p_next->aid
920                                    {
921                                            p_section_dest->p_article_tail = p_article;
922                                    }
923                            }
924    
925                            p_article->p_prior = p_next->p_prior;
926                            p_article->p_next = p_next;
927                            p_next->p_prior->p_next = p_article;
928                            p_next->p_prior = p_article;
929                    }
930    
931                    // Update article / topic counter of src / desc section
932                    p_section_src->article_count--;
933                    p_section_dest->article_count++;
934                    if (p_article->tid == 0)
935                    {
936                            p_section_src->topic_count--;
937                            p_section_dest->topic_count++;
938                    }
939    
940                    // Update visible article / topic counter of src / desc section
941                    if (p_article->visible)
942                    {
943                            p_section_src->visible_article_count--;
944                            p_section_dest->visible_article_count++;
945                            if (p_article->tid == 0)
946                            {
947                                    p_section_src->visible_topic_count--;
948                                    p_section_dest->visible_topic_count++;
949                            }
950                    }
951    
952                    // Update page for empty dest section
953                    if (p_section_dest->article_count == 1)
954                    {
955                            p_section_dest->p_page_first_article[0] = p_article;
956                            p_section_dest->page_count = 1;
957                            p_section_dest->last_page_visible_article_count = (p_article->visible ? 1 : 0);
958                    }
959    
960                    p_article = p_article->p_topic_next;
961    
962                    move_counter++;
963                    if (move_counter % CALCULATE_PAGE_THRESHOLD == 0)
964                    {
965                            // Re-calculate pages of desc section
966                            if (section_list_calculate_page(p_section_dest, first_inserted_aid_dest) < 0)
967                            {
968                                    log_error("section_list_calculate_page(section = %d, aid = %d) error\n",
969                                                      p_section_dest->sid, first_inserted_aid_dest);
970                            }
971    
972                            first_inserted_aid_dest = p_article->aid;
973                    }
974            } while (p_article->aid != aid);
975    
976            if (p_section_dest->article_count - dest_article_count_old != move_article_count)
977            {
978                    log_error("section_list_move_topic() error: count of moved articles %d != %d\n",
979                                      p_section_dest->article_count - dest_article_count_old, move_article_count);
980            }
981    
982            // Re-calculate pages of src section
983            if (section_list_calculate_page(p_section_src, last_unaffected_aid_src) < 0)
984            {
985                    log_error("section_list_calculate_page(section = %d, aid = %d) error at aid = %d\n",
986                                      p_section_src->sid, last_unaffected_aid_src, aid);
987            }
988    
989            if (move_counter % CALCULATE_PAGE_THRESHOLD != 0)
990            {
991                    // Re-calculate pages of desc section
992                    if (section_list_calculate_page(p_section_dest, first_inserted_aid_dest) < 0)
993                    {
994                            log_error("section_list_calculate_page(section = %d, aid = %d) error\n",
995                                              p_section_dest->sid, first_inserted_aid_dest);
996                    }
997            }
998    
999          return 1;          return move_article_count;
1000  }  }


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

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