/[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.5 by sysadm, Tue May 27 07:21:43 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                                    // Move topic
492                                    if ((ret = section_list_move_topic(p_section, p_section_dest, p_article->aid)) < 0)
493                                    {
494                                            break;
495                                    }
496                            }
497                            break;
498                    case 'E': // Set article as excerption
499                            p_article->excerption = 1;
500                            break;
501                    case 'O': // Unset article as excerption
502                            p_article->excerption = 0;
503                            break;
504                    case 'F': // Set article on top
505                            p_article->ontop = 1;
506                            break;
507                    case 'V': // Unset article on top
508                            p_article->ontop = 0;
509                            break;
510                    case 'Z': // Set article as trnasship
511                            p_article->transship = 1;
512                            break;
513                    default:
514                            // log_error("Operation type=%s unknown, mid=%s\n", row[2], row[0]);
515                            break;
516                    }
517    
518                    if (ret < 0)
519                    {
520                            break;
521                    }
522    
523                    // Update MID with last successfully proceeded article_op_log
524                    last_article_op_log_mid = atoi(row[0]);
525            }
526    
527            // release lock of last section
528            if (last_sid != 0)
529            {
530                    if ((ret = section_list_rw_unlock(p_section)) < 0)
531                    {
532                            log_error("section_list_rw_unlock(sid = %d) error\n", p_section->sid);
533                    }
534            }
535    
536            mysql_free_result(rs);
537    
538            mysql_close(db);
539    
540            return ret;
541    }
542    
543    int section_list_loader_launch(void)
544    {
545            int pid;
546            int ret;
547            int32_t last_aid;
548            int article_count;
549            int load_count;
550            int last_mid;
551            int i;
552    
553            if (section_list_loader_pid != 0)
554            {
555                    log_error("section_list_loader already running, pid = %d\n", section_list_loader_pid);
556                    return -2;
557            }
558    
559            pid = fork();
560    
561            if (pid > 0) // Parent process
562            {
563                    SYS_child_process_count++;
564                    section_list_loader_pid = pid;
565                    log_std("Section list loader process (%d) start\n", pid);
566                    return 0;
567            }
568            else if (pid < 0) // Error
569            {
570                    log_error("fork() error (%d)\n", errno);
571                    return -1;
572            }
573    
574            // Child process
575            SYS_child_process_count = 0;
576    
577            // Detach menu in shared memory
578            detach_menu_shm(p_bbs_menu);
579            free(p_bbs_menu);
580            p_bbs_menu = NULL;
581    
582            // Do section data loader periodically
583            while (!SYS_server_exit)
584            {
585                    if (SYS_section_list_reload)
586                    {
587                            SYS_section_list_reload = 0;
588    
589                            // Load section config
590                            if (load_section_config_from_db() < 0)
591                            {
592                                    log_error("load_section_config_from_db() error\n");
593                            }
594                            else
595                            {
596                                    log_error("Reload section config successfully\n");
597                            }
598                    }
599    
600                    // Load section articles
601                    last_aid = article_block_last_aid();
602                    article_count = article_block_article_count();
603    
604                    if ((ret = append_articles_from_db(last_aid + 1, 0)) < 0)
605                    {
606                            log_error("append_articles_from_db(%d, 0) error\n", last_aid + 1);
607    
608                            if (ret == ERR_UNKNOWN_SECTION)
609                            {
610                                    SYS_section_list_reload = 1; // Force reload section_list
611                            }
612                    }
613    
614                    load_count = article_block_article_count() - article_count;
615    
616                    if (load_count > 0)
617                    {
618                            log_std("Incrementally load %d articles, last_aid = %d\n", load_count, article_block_last_aid());
619                    }
620    
621                    if (SYS_section_list_reload)
622                    {
623                            continue;
624                    }
625    
626                    // Load article_op log
627                    last_mid = last_article_op_log_mid;
628    
629                    if ((ret = apply_article_op_log_from_db()) < 0)
630                    {
631                            log_error("apply_article_op_log_from_db() error\n");
632    
633                            if (ret == ERR_UNKNOWN_SECTION)
634                            {
635                                    SYS_section_list_reload = 1; // Force reload section_list
636                            }
637                    }
638    
639                    if (last_article_op_log_mid > last_mid)
640                    {
641                            log_std("Proceeded %d article logs, last_mid = %d\n", last_article_op_log_mid - last_mid, last_article_op_log_mid);
642                    }
643    
644                    if (SYS_section_list_reload)
645                    {
646                            continue;
647                    }
648    
649                    for (i = 0; i < SECTION_LIST_LOAD_INTERVAL && !SYS_server_exit && !SYS_section_list_reload; i++)
650                    {
651                            sleep(1);
652                    }
653            }
654    
655            // Child process exit
656    
657            // Detach data pools shm
658            detach_section_list_shm();
659            detach_article_block_shm();
660            detach_trie_dict_shm();
661    
662            log_std("Section list loader process exit normally\n");
663            log_end();
664    
665            section_list_loader_pid = 0;
666    
667            _exit(0);
668    
669            return 0;
670    }
671    
672    int section_list_loader_reload(void)
673    {
674            if (section_list_loader_pid == 0)
675            {
676                    log_error("section_list_loader not running\n");
677                    return -2;
678            }
679    
680            if (kill(section_list_loader_pid, SIGHUP) < 0)
681            {
682                    log_error("Send SIGTERM signal failed (%d)\n", errno);
683                    return -1;
684            }
685    
686          return 0;          return 0;
687  }  }


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

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