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

Contents of /lbbs/src/section_list_loader.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.4 - (show annotations)
Tue May 27 03:25:02 2025 UTC (9 months, 3 weeks ago) by sysadm
Branch: MAIN
Changes since 1.3: +128 -2 lines
Content type: text/x-csrc
Add section_list_loader_launch() and section_list_loader_reload()

1 /***************************************************************************
2 section_list_loader.c - description
3 -------------------
4 Copyright : (C) 2004-2025 by Leaflet
5 Email : leaflet@leafok.com
6 ***************************************************************************/
7
8 /***************************************************************************
9 * *
10 * This program is free software; you can redistribute it and/or modify *
11 * it under the terms of the GNU General Public License as published by *
12 * the Free Software Foundation; either version 3 of the License, or *
13 * (at your option) any later version. *
14 * *
15 ***************************************************************************/
16
17 #include "section_list_loader.h"
18 #include "log.h"
19 #include "database.h"
20 #include "menu.h"
21 #include <stdio.h>
22 #include <string.h>
23 #include <errno.h>
24 #include <signal.h>
25 #include <stdlib.h>
26 #include <strings.h>
27 #include <unistd.h>
28
29 #define SECTION_LIST_LOAD_INTERVAL 10 // second
30
31 static int section_list_loader_pid;
32
33 int load_section_config_from_db(void)
34 {
35 MYSQL *db;
36 MYSQL_RES *rs, *rs2;
37 MYSQL_ROW row, row2;
38 char sql[SQL_BUFFER_LEN];
39 int32_t sid;
40 char master_name[BBS_username_max_len + 1];
41 SECTION_LIST *p_section;
42 int ret;
43
44 db = db_open();
45 if (db == NULL)
46 {
47 log_error("db_open() error: %s\n", mysql_error(db));
48 return -2;
49 }
50
51 snprintf(sql, sizeof(sql),
52 "SELECT section_config.SID, sname, section_config.title, section_config.CID, "
53 "read_user_level, write_user_level, section_config.enable * section_class.enable AS enable "
54 "FROM section_config INNER JOIN section_class ON section_config.CID = section_class.CID "
55 "ORDER BY section_config.SID");
56
57 if (mysql_query(db, sql) != 0)
58 {
59 log_error("Query section_list error: %s\n", mysql_error(db));
60 return -3;
61 }
62 if ((rs = mysql_store_result(db)) == NULL)
63 {
64 log_error("Get section_list data failed\n");
65 return -3;
66 }
67
68 ret = 0;
69 while ((row = mysql_fetch_row(rs)))
70 {
71 sid = atoi(row[0]);
72
73 // Query section master
74 snprintf(sql, sizeof(sql),
75 "SELECT username FROM section_master "
76 "INNER JOIN user_list ON section_master.UID = user_list.UID "
77 "WHERE SID = %d AND section_master.enable AND (NOW() BETWEEN begin_dt AND end_dt) "
78 "ORDER BY major DESC LIMIT 1",
79 sid);
80
81 if (mysql_query(db, sql) != 0)
82 {
83 log_error("Query section_master error: %s\n", mysql_error(db));
84 ret = -3;
85 break;
86 }
87 if ((rs2 = mysql_store_result(db)) == NULL)
88 {
89 log_error("Get section_master data failed\n");
90 ret = -3;
91 break;
92 }
93 if ((row2 = mysql_fetch_row(rs2)))
94 {
95 strncpy(master_name, row2[0], sizeof(master_name) - 1);
96 master_name[sizeof(master_name) - 1] = '\0';
97 }
98 else
99 {
100 master_name[0] = '\0';
101 }
102 mysql_free_result(rs2);
103
104 p_section = section_list_find_by_sid(sid);
105
106 if (p_section == NULL)
107 {
108 p_section = section_list_create(sid, row[1], row[2], "");
109 if (p_section == NULL)
110 {
111 log_error("section_list_create() error: load new section sid = %d sname = %s\n", sid, row[1]);
112 ret = -4;
113 break;
114 }
115
116 // acquire rw lock
117 ret = section_list_rw_lock(p_section);
118 if (ret < 0)
119 {
120 break;
121 }
122 }
123 else
124 {
125 // acquire rw lock
126 ret = section_list_rw_lock(p_section);
127 if (ret < 0)
128 {
129 break;
130 }
131
132 strncpy(p_section->sname, row[1], sizeof(p_section->sname) - 1);
133 p_section->sname[sizeof(p_section->sname) - 1] = '\0';
134 strncpy(p_section->stitle, row[1], sizeof(p_section->stitle) - 1);
135 p_section->stitle[sizeof(p_section->stitle) - 1] = '\0';
136 strncpy(p_section->master_name, master_name, sizeof(p_section->master_name) - 1);
137 p_section->master_name[sizeof(p_section->master_name) - 1] = '\0';
138 }
139
140 p_section->class_id = atoi(row[3]);
141 p_section->read_user_level = atoi(row[4]);
142 p_section->write_user_level = atoi(row[5]);
143 p_section->enable = (int8_t)atoi(row[6]);
144
145 // release rw lock
146 ret = section_list_rw_unlock(p_section);
147 if (ret < 0)
148 {
149 break;
150 }
151 }
152 mysql_free_result(rs);
153
154 mysql_close(db);
155
156 return ret;
157 }
158
159 int append_articles_from_db(int32_t start_aid, int global_lock)
160 {
161 MYSQL *db;
162 MYSQL_RES *rs;
163 MYSQL_ROW row;
164 char sql[SQL_BUFFER_LEN];
165 ARTICLE article;
166 SECTION_LIST *p_section = NULL;
167 int32_t last_sid = 0;
168 int ret = 0;
169 int i;
170
171 db = db_open();
172 if (db == NULL)
173 {
174 log_error("db_open() error: %s\n", mysql_error(db));
175 return -2;
176 }
177
178 snprintf(sql, sizeof(sql),
179 "SELECT AID, TID, SID, CID, UID, visible, excerption, "
180 "ontop, `lock`, username, nickname, title, UNIX_TIMESTAMP(sub_dt) AS sub_dt "
181 "FROM bbs WHERE AID >= %d ORDER BY AID",
182 start_aid);
183
184 if (mysql_query(db, sql) != 0)
185 {
186 log_error("Query article list error: %s\n", mysql_error(db));
187 return -3;
188 }
189 if ((rs = mysql_use_result(db)) == NULL)
190 {
191 log_error("Get article list data failed\n");
192 return -3;
193 }
194
195 // acquire global lock
196 if (global_lock)
197 {
198 if ((ret = section_list_rw_lock(NULL)) < 0)
199 {
200 log_error("section_list_rw_lock(sid = 0) error\n");
201 goto cleanup;
202 }
203 }
204
205 while ((row = mysql_fetch_row(rs)))
206 {
207 bzero(&article, sizeof(ARTICLE));
208
209 // copy data of article
210 i = 0;
211
212 article.aid = atoi(row[i++]);
213 article.tid = atoi(row[i++]);
214 article.sid = atoi(row[i++]);
215 article.cid = atoi(row[i++]);
216 article.uid = atoi(row[i++]);
217 article.visible = (int8_t)atoi(row[i++]);
218 article.excerption = (int8_t)atoi(row[i++]);
219 article.ontop = (int8_t)atoi(row[i++]);
220 article.lock = (int8_t)atoi(row[i++]);
221
222 strncpy(article.username, row[i++], sizeof(article.username) - 1);
223 article.username[sizeof(article.username) - 1] = '\0';
224 strncpy(article.nickname, row[i++], sizeof(article.nickname) - 1);
225 article.nickname[sizeof(article.nickname) - 1] = '\0';
226 strncpy(article.title, row[i++], sizeof(article.title) - 1);
227 article.title[sizeof(article.title) - 1] = '\0';
228
229 article.sub_dt = atol(row[i++]);
230
231 // release lock of last section if different from current one
232 if (!global_lock && article.sid != last_sid && last_sid != 0)
233 {
234 if ((ret = section_list_rw_unlock(p_section)) < 0)
235 {
236 log_error("section_list_rw_unlock(sid = %d) error\n", p_section->sid);
237 break;
238 }
239 }
240
241 if ((p_section = section_list_find_by_sid(article.sid)) == NULL)
242 {
243 log_error("section_list_find_by_sid(%d) error: unknown section, try reloading section config\n", article.sid);
244 ret = ERR_UNKNOWN_SECTION; // Unknown section found
245 break;
246 }
247
248 // acquire lock of current section if different from last one
249 if (!global_lock && article.sid != last_sid)
250 {
251 if ((ret = section_list_rw_lock(p_section)) < 0)
252 {
253 log_error("section_list_rw_lock(sid = 0) error\n");
254 break;
255 }
256 }
257
258 // append article to section list
259 last_sid = article.sid;
260
261 if (section_list_append_article(p_section, &article) < 0)
262 {
263 log_error("section_list_append_article(sid = %d, aid = %d) error\n",
264 p_section->sid, article.aid);
265 ret = -3;
266 break;
267 }
268 }
269
270 // release lock of last section
271 if (!global_lock && last_sid != 0)
272 {
273 if ((ret = section_list_rw_unlock(p_section)) < 0)
274 {
275 log_error("section_list_rw_unlock(sid = %d) error\n", p_section->sid);
276 }
277 }
278
279 // release global lock
280 if (global_lock)
281 {
282 if ((ret = section_list_rw_unlock(NULL)) < 0)
283 {
284 log_error("section_list_rw_unlock(sid = 0) error\n");
285 }
286 }
287
288 cleanup:
289 mysql_free_result(rs);
290
291 mysql_close(db);
292
293 return ret;
294 }
295
296 int section_list_loader_launch(void)
297 {
298 int pid;
299 int ret;
300 int32_t last_aid;
301 int article_count;
302 int load_count;
303 int i;
304
305 if (section_list_loader_pid != 0)
306 {
307 log_error("section_list_loader already running, pid = %d\n", section_list_loader_pid);
308 return -2;
309 }
310
311 pid = fork();
312
313 if (pid > 0) // Parent process
314 {
315 SYS_child_process_count++;
316 section_list_loader_pid = pid;
317 log_std("Section list loader process (%d) start\n", pid);
318 return 0;
319 }
320 else if (pid < 0) // Error
321 {
322 log_error("fork() error (%d)\n", errno);
323 return -1;
324 }
325
326 // Child process
327 SYS_child_process_count = 0;
328
329 // Detach menu in shared memory
330 detach_menu_shm(p_bbs_menu);
331 free(p_bbs_menu);
332 p_bbs_menu = NULL;
333
334 // Do section data loader periodically
335 while (!SYS_server_exit)
336 {
337 if (SYS_section_list_reload)
338 {
339 SYS_section_list_reload = 0;
340
341 // Load section config
342 if (load_section_config_from_db() < 0)
343 {
344 log_error("load_section_config_from_db() error\n");
345 }
346 else
347 {
348 log_error("Reload section config successfully\n");
349 }
350 }
351
352 // Load section articles
353 last_aid = article_block_last_aid();
354 article_count = article_block_article_count();
355
356 if ((ret = append_articles_from_db(last_aid + 1, 0)) < 0)
357 {
358 log_error("append_articles_from_db(%d, 0) error\n", last_aid + 1);
359
360 if (ret == ERR_UNKNOWN_SECTION)
361 {
362 SYS_section_list_reload = 1; // Force reload section_list
363 }
364 }
365 else
366 {
367 load_count = article_block_article_count() - article_count;
368
369 if (load_count > 0)
370 {
371 log_std("Incrementally load %d articles, last_aid = %d\n", load_count, article_block_last_aid());
372 }
373
374 for (i = 0; i < SECTION_LIST_LOAD_INTERVAL && !SYS_server_exit && !SYS_section_list_reload; i++)
375 {
376 sleep(1);
377 }
378 }
379 }
380
381 // Child process exit
382
383 // Detach data pools shm
384 detach_section_list_shm();
385 detach_article_block_shm();
386 detach_trie_dict_shm();
387
388 log_std("Section list loader process exit normally\n");
389 log_end();
390
391 section_list_loader_pid = 0;
392
393 _exit(0);
394
395 return 0;
396 }
397
398 int section_list_loader_reload(void)
399 {
400 if (section_list_loader_pid == 0)
401 {
402 log_error("section_list_loader not running\n");
403 return -2;
404 }
405
406 if (kill(section_list_loader_pid, SIGHUP) < 0)
407 {
408 log_error("Send SIGTERM signal failed (%d)\n", errno);
409 return -1;
410 }
411
412 return 0;
413 }

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