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

Diff of /lbbs/src/section_list_loader.c

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

Revision 1.1 by sysadm, Mon May 26 03:42:45 2025 UTC Revision 1.6 by sysadm, Tue May 27 09:33:11 2025 UTC
# Line 17  Line 17 
17  #include "section_list_loader.h"  #include "section_list_loader.h"
18  #include "log.h"  #include "log.h"
19  #include "database.h"  #include "database.h"
20    #include "menu.h"
21  #include <stdio.h>  #include <stdio.h>
22  #include <string.h>  #include <string.h>
23  #include <errno.h>  #include <errno.h>
24    #include <signal.h>
25  #include <stdlib.h>  #include <stdlib.h>
26    #include <strings.h>
27    #include <unistd.h>
28    
29  int load_section_config_from_db(MYSQL *db)  #define SECTION_LIST_LOAD_INTERVAL 10 // second
30    
31    int section_list_loader_pid;
32    int last_article_op_log_mid;
33    
34    int load_section_config_from_db(void)
35  {  {
36            MYSQL *db;
37          MYSQL_RES *rs, *rs2;          MYSQL_RES *rs, *rs2;
38          MYSQL_ROW row, row2;          MYSQL_ROW row, row2;
39          char sql[SQL_BUFFER_LEN];          char sql[SQL_BUFFER_LEN];
# Line 32  int load_section_config_from_db(MYSQL *d Line 42  int load_section_config_from_db(MYSQL *d
42          SECTION_LIST *p_section;          SECTION_LIST *p_section;
43          int ret;          int ret;
44    
45            db = db_open();
46            if (db == NULL)
47            {
48                    log_error("db_open() error: %s\n", mysql_error(db));
49                    return -2;
50            }
51    
52          snprintf(sql, sizeof(sql),          snprintf(sql, sizeof(sql),
53                           "SELECT section_config.SID, sname, title, section_config.CID, read_user_level, write_user_level, "                           "SELECT section_config.SID, sname, section_config.title, section_config.CID, "
54                           "section_config.enable * section_class.enable AS enable "                           "read_user_level, write_user_level, section_config.enable * section_class.enable AS enable "
55                           "FROM section_config INNER JOIN section_class ON section_config.CID = sectioN_class.CID "                           "FROM section_config INNER JOIN section_class ON section_config.CID = section_class.CID "
56                           "ORDER BY section_config.SID");                           "ORDER BY section_config.SID");
57    
58          if (mysql_query(db, sql) != 0)          if (mysql_query(db, sql) != 0)
59          {          {
60                  log_error("Query section_list error: %s\n", mysql_error(db));                  log_error("Query section_list error: %s\n", mysql_error(db));
61                  return -1;                  return -3;
62          }          }
63          if ((rs = mysql_store_result(db)) == NULL)          if ((rs = mysql_store_result(db)) == NULL)
64          {          {
65                  log_error("Get section_list data failed\n");                  log_error("Get section_list data failed\n");
66                  return -1;                  return -3;
67          }          }
68    
69            ret = 0;
70          while ((row = mysql_fetch_row(rs)))          while ((row = mysql_fetch_row(rs)))
71          {          {
72                  sid = atoi(row[0]);                  sid = atoi(row[0]);
# Line 63  int load_section_config_from_db(MYSQL *d Line 82  int load_section_config_from_db(MYSQL *d
82                  if (mysql_query(db, sql) != 0)                  if (mysql_query(db, sql) != 0)
83                  {                  {
84                          log_error("Query section_master error: %s\n", mysql_error(db));                          log_error("Query section_master error: %s\n", mysql_error(db));
85                          return -2;                          ret = -3;
86                            break;
87                  }                  }
88                  if ((rs2 = mysql_store_result(db)) == NULL)                  if ((rs2 = mysql_store_result(db)) == NULL)
89                  {                  {
90                          log_error("Get section_master data failed\n");                          log_error("Get section_master data failed\n");
91                          return -2;                          ret = -3;
92                            break;
93                  }                  }
94                  if ((row2 = mysql_fetch_row(rs2)))                  if ((row2 = mysql_fetch_row(rs2)))
95                  {                  {
# Line 88  int load_section_config_from_db(MYSQL *d Line 109  int load_section_config_from_db(MYSQL *d
109                          p_section = section_list_create(sid, row[1], row[2], "");                          p_section = section_list_create(sid, row[1], row[2], "");
110                          if (p_section == NULL)                          if (p_section == NULL)
111                          {                          {
112                                  log_error("load_section_config_from_db() error: load new section sid = %d sname = %s\n", sid, row[1]);                                  log_error("section_list_create() error: load new section sid = %d sname = %s\n", sid, row[1]);
113                                    ret = -4;
114                                  break;                                  break;
115                          }                          }
116    
# Line 130  int load_section_config_from_db(MYSQL *d Line 152  int load_section_config_from_db(MYSQL *d
152          }          }
153          mysql_free_result(rs);          mysql_free_result(rs);
154    
155            mysql_close(db);
156    
157            return ret;
158    }
159    
160    int append_articles_from_db(int32_t start_aid, int global_lock)
161    {
162            MYSQL *db;
163            MYSQL_RES *rs;
164            MYSQL_ROW row;
165            char sql[SQL_BUFFER_LEN];
166            ARTICLE article;
167            ARTICLE *p_topic;
168            SECTION_LIST *p_section = NULL;
169            int32_t last_sid = 0;
170            int ret = 0;
171            int i;
172    
173            db = db_open();
174            if (db == NULL)
175            {
176                    log_error("db_open() error: %s\n", mysql_error(db));
177                    return -2;
178            }
179    
180            snprintf(sql, sizeof(sql),
181                             "SELECT AID, TID, SID, CID, UID, visible, excerption, ontop, `lock`, "
182                             "transship, username, nickname, title, UNIX_TIMESTAMP(sub_dt) AS sub_dt "
183                             "FROM bbs WHERE AID >= %d ORDER BY AID",
184                             start_aid);
185    
186            if (mysql_query(db, sql) != 0)
187            {
188                    log_error("Query article list error: %s\n", mysql_error(db));
189                    return -3;
190            }
191            if ((rs = mysql_use_result(db)) == NULL)
192            {
193                    log_error("Get article list data failed\n");
194                    return -3;
195            }
196    
197            // acquire global lock
198            if (global_lock)
199            {
200                    if ((ret = section_list_rw_lock(NULL)) < 0)
201                    {
202                            log_error("section_list_rw_lock(sid = 0) error\n");
203                            goto cleanup;
204                    }
205            }
206    
207            while ((row = mysql_fetch_row(rs)))
208            {
209                    bzero(&article, sizeof(ARTICLE));
210    
211                    // copy data of article
212                    i = 0;
213    
214                    article.aid = atoi(row[i++]);
215                    article.tid = atoi(row[i++]);
216                    article.sid = atoi(row[i++]);
217                    article.cid = atoi(row[i++]);
218                    article.uid = atoi(row[i++]);
219                    article.visible = (int8_t)atoi(row[i++]);
220                    article.excerption = (int8_t)atoi(row[i++]);
221                    article.ontop = (int8_t)atoi(row[i++]);
222                    article.lock = (int8_t)atoi(row[i++]);
223                    article.transship = (int8_t)atoi(row[i++]);
224    
225                    strncpy(article.username, row[i++], sizeof(article.username) - 1);
226                    article.username[sizeof(article.username) - 1] = '\0';
227                    strncpy(article.nickname, row[i++], sizeof(article.nickname) - 1);
228                    article.nickname[sizeof(article.nickname) - 1] = '\0';
229                    strncpy(article.title, row[i++], sizeof(article.title) - 1);
230                    article.title[sizeof(article.title) - 1] = '\0';
231    
232                    article.sub_dt = atol(row[i++]);
233    
234                    // release lock of last section if different from current one
235                    if (!global_lock && article.sid != last_sid && last_sid != 0)
236                    {
237                            if ((ret = section_list_rw_unlock(p_section)) < 0)
238                            {
239                                    log_error("section_list_rw_unlock(sid = %d) error\n", p_section->sid);
240                                    break;
241                            }
242                    }
243    
244                    if ((p_section = section_list_find_by_sid(article.sid)) == NULL)
245                    {
246                            log_error("section_list_find_by_sid(%d) error: unknown section, try reloading section config\n", article.sid);
247                            ret = ERR_UNKNOWN_SECTION; // Unknown section found
248                            break;
249                    }
250    
251                    if (article.visible != 0 && article.tid != 0)
252                    {
253                            // Check if topic article is visible
254                            p_topic = article_block_find_by_aid(article.tid);
255                            if (p_topic == NULL || p_topic->visible == 0)
256                            {
257                                    // log_error("Set article (aid = %d) as invisible due to invisible or non-existing topic head\n", article.aid);
258                                    article.tid = 0;
259                                    article.visible = 0;
260                            }
261                    }
262    
263                    // acquire lock of current section if different from last one
264                    if (!global_lock && article.sid != last_sid)
265                    {
266                            if ((ret = section_list_rw_lock(p_section)) < 0)
267                            {
268                                    log_error("section_list_rw_lock(sid = 0) error\n");
269                                    break;
270                            }
271                    }
272    
273                    // append article to section list
274                    last_sid = article.sid;
275    
276                    if (section_list_append_article(p_section, &article) < 0)
277                    {
278                            log_error("section_list_append_article(sid = %d, aid = %d) error\n",
279                                              p_section->sid, article.aid);
280                            ret = -3;
281                            break;
282                    }
283            }
284    
285            // release lock of last section
286            if (!global_lock && last_sid != 0)
287            {
288                    if ((ret = section_list_rw_unlock(p_section)) < 0)
289                    {
290                            log_error("section_list_rw_unlock(sid = %d) error\n", p_section->sid);
291                    }
292            }
293    
294            // release global lock
295            if (global_lock)
296            {
297                    if ((ret = section_list_rw_unlock(NULL)) < 0)
298                    {
299                            log_error("section_list_rw_unlock(sid = 0) error\n");
300                    }
301            }
302    
303    cleanup:
304            mysql_free_result(rs);
305    
306            mysql_close(db);
307    
308            return ret;
309    }
310    
311    int set_last_article_op_log_from_db(void)
312    {
313            MYSQL *db;
314            MYSQL_RES *rs;
315            MYSQL_ROW row;
316            char sql[SQL_BUFFER_LEN];
317    
318            db = db_open();
319            if (db == NULL)
320            {
321                    log_error("db_open() error: %s\n", mysql_error(db));
322                    return -1;
323            }
324    
325            snprintf(sql, sizeof(sql),
326                             "SELECT MID FROM bbs_article_op ORDER BY MID DESC LIMIT 1");
327    
328            if (mysql_query(db, sql) != 0)
329            {
330                    log_error("Query article op error: %s\n", mysql_error(db));
331                    return -2;
332            }
333            if ((rs = mysql_store_result(db)) == NULL)
334            {
335                    log_error("Get article op data failed\n");
336                    return -2;
337            }
338    
339            if ((row = mysql_fetch_row(rs)))
340            {
341                    last_article_op_log_mid = atoi(row[0]);
342            }
343    
344            mysql_free_result(rs);
345    
346            mysql_close(db);
347    
348            return last_article_op_log_mid;
349    }
350    
351    int apply_article_op_log_from_db(void)
352    {
353            MYSQL *db;
354            MYSQL_RES *rs, *rs2;
355            MYSQL_ROW row, row2;
356            char sql[SQL_BUFFER_LEN];
357            ARTICLE *p_article;
358            SECTION_LIST *p_section = NULL;
359            SECTION_LIST *p_section_dest;
360            int32_t last_sid = 0;
361            int32_t sid_dest;
362            int ret = 0;
363    
364            db = db_open();
365            if (db == NULL)
366            {
367                    log_error("db_open() error: %s\n", mysql_error(db));
368                    return -3;
369            }
370    
371            snprintf(sql, sizeof(sql),
372                             "SELECT MID, AID, type FROM bbs_article_op "
373                             "WHERE MID > %d AND type NOT IN ('A', 'M') ORDER BY MID",
374                             last_article_op_log_mid);
375    
376            if (mysql_query(db, sql) != 0)
377            {
378                    log_error("Query article log error: %s\n", mysql_error(db));
379                    return -3;
380            }
381            if ((rs = mysql_store_result(db)) == NULL)
382            {
383                    log_error("Get article log data failed\n");
384                    return -3;
385            }
386    
387            while ((row = mysql_fetch_row(rs)))
388            {
389                    p_article = article_block_find_by_aid(atoi(row[1]));
390                    if (p_article == NULL) // related article has not been appended yet
391                    {
392                            ret = -2;
393                            break;
394                    }
395    
396                    // release lock of last section if different from current one
397                    if (p_article->sid != last_sid && last_sid != 0)
398                    {
399                            if ((ret = section_list_rw_unlock(p_section)) < 0)
400                            {
401                                    log_error("section_list_rw_unlock(sid = %d) error\n", p_section->sid);
402                                    break;
403                            }
404                    }
405    
406                    if ((p_section = section_list_find_by_sid(p_article->sid)) == NULL)
407                    {
408                            log_error("section_list_find_by_sid(%d) error: unknown section, try reloading section config\n", p_article->sid);
409                            ret = ERR_UNKNOWN_SECTION; // Unknown section found
410                            break;
411                    }
412    
413                    // acquire lock of current section if different from last one
414                    if (p_article->sid != last_sid)
415                    {
416                            if ((ret = section_list_rw_lock(p_section)) < 0)
417                            {
418                                    log_error("section_list_rw_lock(sid = 0) error\n");
419                                    break;
420                            }
421                    }
422    
423                    last_sid = p_article->sid;
424    
425                    switch (row[2][0])
426                    {
427                    case 'A': // Add article
428                            log_error("Operation type=A should not be found\n");
429                            break;
430                    case 'D': // Delete article
431                    case 'X': // Delete article by Admin
432                            p_article->visible = 0;
433                            if (p_article->tid == 0)
434                            {
435                                    // Set articles in the topic to be invisible
436                                    do
437                                    {
438                                            p_article = p_article->p_topic_next;
439                                            p_article->visible = 0;
440                                    } while (p_article->tid != 0);
441                            }
442                            break;
443                    case 'S': // Restore article
444                            p_article->visible = 1;
445                            break;
446                    case 'L': // Lock article
447                            p_article->lock = 1;
448                            break;
449                    case 'U': // Unlock article
450                            p_article->lock = 0;
451                            break;
452                    case 'M': // Modify article
453                            log_error("Operation type=M should not be found\n");
454                            break;
455                    case 'T': // Move article
456                            snprintf(sql, sizeof(sql),
457                                             "SELECT SID FROM bbs WHERE AID = %d",
458                                             p_article->aid);
459    
460                            if (mysql_query(db, sql) != 0)
461                            {
462                                    log_error("Query article error: %s\n", mysql_error(db));
463                                    ret = -3;
464                                    break;
465                            }
466                            if ((rs2 = mysql_store_result(db)) == NULL)
467                            {
468                                    log_error("Get article data failed\n");
469                                    ret = -3;
470                                    break;
471                            }
472                            if ((row2 = mysql_fetch_row(rs2)))
473                            {
474                                    sid_dest = atoi(row2[0]);
475                            }
476                            else
477                            {
478                                    sid_dest = 0;
479                                    ret = -4;
480                            }
481                            mysql_free_result(rs2);
482    
483                            if (sid_dest > 0 && sid_dest != p_article->sid)
484                            {
485                                    p_section_dest = section_list_find_by_sid(sid_dest);
486                                    if (p_section_dest == NULL)
487                                    {
488                                            ret = ERR_UNKNOWN_SECTION;
489                                            break;
490                                    }
491                                    // acquire lock of dest section
492                                    if ((ret = section_list_rw_lock(p_section_dest)) < 0)
493                                    {
494                                            log_error("section_list_rw_lock(sid = %d) error\n", p_section_dest);
495                                            break;
496                                    }
497                                    // Move topic
498                                    if ((ret = section_list_move_topic(p_section, p_section_dest, p_article->aid)) < 0)
499                                    {
500                                            log_error("section_list_move_topic(src_sid=%d, dest_sid=%d, aid=%d) error (%d), retry in the next loop\n",
501                                                              p_section->sid, p_section_dest->sid, p_article->aid, ret);
502                                    }
503                                    // release lock of dest section
504                                    if (section_list_rw_unlock(p_section_dest) < 0)
505                                    {
506                                            log_error("section_list_rw_unlock(sid = %d) error\n", p_section_dest);
507                                            ret = -1;
508                                    }
509                            }
510                            break;
511                    case 'E': // Set article as excerption
512                            p_article->excerption = 1;
513                            break;
514                    case 'O': // Unset article as excerption
515                            p_article->excerption = 0;
516                            break;
517                    case 'F': // Set article on top
518                            p_article->ontop = 1;
519                            break;
520                    case 'V': // Unset article on top
521                            p_article->ontop = 0;
522                            break;
523                    case 'Z': // Set article as trnasship
524                            p_article->transship = 1;
525                            break;
526                    default:
527                            // log_error("Operation type=%s unknown, mid=%s\n", row[2], row[0]);
528                            break;
529                    }
530    
531                    if (ret < 0)
532                    {
533                            break;
534                    }
535    
536                    // Update MID with last successfully proceeded article_op_log
537                    last_article_op_log_mid = atoi(row[0]);
538            }
539    
540            // release lock of last section
541            if (last_sid != 0)
542            {
543                    if ((ret = section_list_rw_unlock(p_section)) < 0)
544                    {
545                            log_error("section_list_rw_unlock(sid = %d) error\n", p_section->sid);
546                    }
547            }
548    
549            mysql_free_result(rs);
550    
551            mysql_close(db);
552    
553            return ret;
554    }
555    
556    int section_list_loader_launch(void)
557    {
558            int pid;
559            int ret;
560            int32_t last_aid;
561            int article_count;
562            int load_count;
563            int last_mid;
564            int i;
565    
566            if (section_list_loader_pid != 0)
567            {
568                    log_error("section_list_loader already running, pid = %d\n", section_list_loader_pid);
569                    return -2;
570            }
571    
572            pid = fork();
573    
574            if (pid > 0) // Parent process
575            {
576                    SYS_child_process_count++;
577                    section_list_loader_pid = pid;
578                    log_std("Section list loader process (%d) start\n", pid);
579                    return 0;
580            }
581            else if (pid < 0) // Error
582            {
583                    log_error("fork() error (%d)\n", errno);
584                    return -1;
585            }
586    
587            // Child process
588            SYS_child_process_count = 0;
589    
590            // Detach menu in shared memory
591            detach_menu_shm(p_bbs_menu);
592            free(p_bbs_menu);
593            p_bbs_menu = NULL;
594    
595            // Do section data loader periodically
596            while (!SYS_server_exit)
597            {
598                    if (SYS_section_list_reload)
599                    {
600                            SYS_section_list_reload = 0;
601    
602                            // Load section config
603                            if (load_section_config_from_db() < 0)
604                            {
605                                    log_error("load_section_config_from_db() error\n");
606                            }
607                            else
608                            {
609                                    log_error("Reload section config successfully\n");
610                            }
611                    }
612    
613                    // Load section articles
614                    last_aid = article_block_last_aid();
615                    article_count = article_block_article_count();
616    
617                    if ((ret = append_articles_from_db(last_aid + 1, 0)) < 0)
618                    {
619                            log_error("append_articles_from_db(%d, 0) error\n", last_aid + 1);
620    
621                            if (ret == ERR_UNKNOWN_SECTION)
622                            {
623                                    SYS_section_list_reload = 1; // Force reload section_list
624                            }
625                    }
626    
627                    load_count = article_block_article_count() - article_count;
628    
629                    if (load_count > 0)
630                    {
631                            log_std("Incrementally load %d articles, last_aid = %d\n", load_count, article_block_last_aid());
632                    }
633    
634                    if (SYS_section_list_reload)
635                    {
636                            continue;
637                    }
638    
639                    // Load article_op log
640                    last_mid = last_article_op_log_mid;
641    
642                    if ((ret = apply_article_op_log_from_db()) < 0)
643                    {
644                            log_error("apply_article_op_log_from_db() error\n");
645    
646                            if (ret == ERR_UNKNOWN_SECTION)
647                            {
648                                    SYS_section_list_reload = 1; // Force reload section_list
649                            }
650                    }
651    
652                    if (last_article_op_log_mid > last_mid)
653                    {
654                            log_std("Proceeded %d article logs, last_mid = %d\n", last_article_op_log_mid - last_mid, last_article_op_log_mid);
655                    }
656    
657                    if (SYS_section_list_reload)
658                    {
659                            continue;
660                    }
661    
662                    for (i = 0; i < SECTION_LIST_LOAD_INTERVAL && !SYS_server_exit && !SYS_section_list_reload; i++)
663                    {
664                            sleep(1);
665                    }
666            }
667    
668            // Child process exit
669    
670            // Detach data pools shm
671            detach_section_list_shm();
672            detach_article_block_shm();
673            detach_trie_dict_shm();
674    
675            log_std("Section list loader process exit normally\n");
676            log_end();
677    
678            section_list_loader_pid = 0;
679    
680            _exit(0);
681    
682            return 0;
683    }
684    
685    int section_list_loader_reload(void)
686    {
687            if (section_list_loader_pid == 0)
688            {
689                    log_error("section_list_loader not running\n");
690                    return -2;
691            }
692    
693            if (kill(section_list_loader_pid, SIGHUP) < 0)
694            {
695                    log_error("Send SIGTERM signal failed (%d)\n", errno);
696                    return -1;
697            }
698    
699          return 0;          return 0;
700  }  }


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

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