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

Annotation of /lbbs/src/section_list.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.7 - (hide annotations)
Thu May 22 06:20:47 2025 UTC (9 months, 3 weeks ago) by sysadm
Branch: MAIN
Changes since 1.6: +285 -294 lines
Content type: text/x-csrc
Use single article_block_pool for all sections

1 sysadm 1.1 /***************************************************************************
2     section_list.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.h"
18     #include "log.h"
19     #include "trie_dict.h"
20     #include <stdio.h>
21     #include <string.h>
22     #include <signal.h>
23     #include <unistd.h>
24     #include <stdlib.h>
25     #include <errno.h>
26 sysadm 1.7 #include <sys/param.h>
27 sysadm 1.1 #include <sys/shm.h>
28     #include <sys/ipc.h>
29    
30 sysadm 1.7 #define ARTICLE_BLOCK_PER_SHM 400 // sizeof(ARTICLE_BLOCK) * ARTICLE_BLOCK_PER_SHM is the size of each shm segment to allocate
31 sysadm 1.3 #define ARTICLE_BLOCK_SHM_COUNT_LIMIT 256 // limited by length (8-bit) of proj_id in ftok(path, proj_id)
32 sysadm 1.7 #define ARTICLE_BLOCK_PER_POOL (ARTICLE_BLOCK_PER_SHM * ARTICLE_BLOCK_SHM_COUNT_LIMIT)
33    
34     struct article_block_t
35     {
36     ARTICLE articles[ARTICLE_PER_BLOCK];
37     int32_t article_count;
38     struct article_block_t *p_next_block;
39     };
40     typedef struct article_block_t ARTICLE_BLOCK;
41 sysadm 1.1
42     struct article_block_shm_t
43     {
44     int shmid;
45     void *p_shm;
46     };
47     typedef struct article_block_shm_t ARTICLE_BLOCK_SHM;
48    
49 sysadm 1.7 struct article_block_pool_t
50     {
51     ARTICLE_BLOCK_SHM shm_pool[ARTICLE_BLOCK_SHM_COUNT_LIMIT];
52     int shm_count;
53     ARTICLE_BLOCK *p_block_free_list;
54     ARTICLE_BLOCK *p_block[ARTICLE_BLOCK_PER_POOL];
55     int32_t block_count;
56     };
57     typedef struct article_block_pool_t ARTICLE_BLOCK_POOL;
58    
59     static ARTICLE_BLOCK_POOL *p_article_block_pool = NULL;
60 sysadm 1.1
61 sysadm 1.7 static SECTION_LIST *p_section_list_pool = NULL;
62     static int section_list_count = 0;
63     static TRIE_NODE *p_trie_dict_section_list = NULL;
64    
65     int article_block_init(const char *filename, int block_count)
66 sysadm 1.1 {
67     int shmid;
68     int proj_id;
69     key_t key;
70     size_t size;
71     void *p_shm;
72     int i;
73 sysadm 1.7 int block_count_in_shm;
74     ARTICLE_BLOCK *p_block_in_shm;
75     ARTICLE_BLOCK **pp_block_next;
76    
77     if (p_article_block_pool != NULL)
78 sysadm 1.1 {
79 sysadm 1.7 log_error("article_block_pool already initialized\n");
80 sysadm 1.1 return -1;
81     }
82    
83 sysadm 1.7 if (block_count > ARTICLE_BLOCK_PER_POOL)
84 sysadm 1.1 {
85 sysadm 1.7 log_error("article_block_count exceed limit %d\n", ARTICLE_BLOCK_PER_POOL);
86 sysadm 1.1 return -2;
87     }
88    
89 sysadm 1.7 p_article_block_pool = calloc(1, sizeof(ARTICLE_BLOCK_POOL));
90     if (p_article_block_pool == NULL)
91 sysadm 1.1 {
92 sysadm 1.7 log_error("calloc(ARTICLE_BLOCK_POOL) OOM\n");
93 sysadm 1.1 return -2;
94     }
95    
96     // Allocate shared memory
97 sysadm 1.7 p_article_block_pool->shm_count = 0;
98     pp_block_next = &(p_article_block_pool->p_block_free_list);
99 sysadm 1.1
100 sysadm 1.7 while (block_count > 0)
101 sysadm 1.1 {
102 sysadm 1.7 block_count_in_shm = MIN(block_count, ARTICLE_BLOCK_PER_SHM);
103     block_count -= block_count_in_shm;
104 sysadm 1.1
105 sysadm 1.7 proj_id = getpid() + p_article_block_pool->shm_count;
106 sysadm 1.1 key = ftok(filename, proj_id);
107     if (key == -1)
108     {
109     log_error("ftok(%s, %d) error (%d)\n", filename, proj_id, errno);
110 sysadm 1.7 article_block_cleanup();
111 sysadm 1.1 return -3;
112     }
113    
114 sysadm 1.7 size = sizeof(shmid) + sizeof(ARTICLE_BLOCK) * (size_t)block_count_in_shm;
115 sysadm 1.1 shmid = shmget(key, size, IPC_CREAT | IPC_EXCL | 0600);
116     if (shmid == -1)
117     {
118 sysadm 1.7 log_error("shmget(shm_index = %d, size = %d) error (%d)\n", p_article_block_pool->shm_count, size, errno);
119     article_block_cleanup();
120 sysadm 1.1 return -3;
121     }
122     p_shm = shmat(shmid, NULL, 0);
123     if (p_shm == (void *)-1)
124     {
125     log_error("shmat(shmid = %d) error (%d)\n", shmid, errno);
126 sysadm 1.7 article_block_cleanup();
127 sysadm 1.1 return -3;
128     }
129    
130 sysadm 1.7 (p_article_block_pool->shm_pool + p_article_block_pool->shm_count)->shmid = shmid;
131     (p_article_block_pool->shm_pool + p_article_block_pool->shm_count)->p_shm = p_shm;
132     p_article_block_pool->shm_count++;
133 sysadm 1.1
134 sysadm 1.7 p_block_in_shm = p_shm;
135     *pp_block_next = p_block_in_shm;
136 sysadm 1.1
137 sysadm 1.7 for (i = 0; i < block_count_in_shm; i++)
138 sysadm 1.1 {
139 sysadm 1.7 if (i < block_count_in_shm - 1)
140 sysadm 1.1 {
141 sysadm 1.7 (p_block_in_shm + i)->p_next_block = (p_block_in_shm + i + 1);
142 sysadm 1.1 }
143     else
144     {
145 sysadm 1.7 (p_block_in_shm + i)->p_next_block = NULL;
146     pp_block_next = &((p_block_in_shm + i)->p_next_block);
147 sysadm 1.1 }
148     }
149     }
150    
151 sysadm 1.7 p_article_block_pool->block_count = 0;
152    
153 sysadm 1.1 return 0;
154     }
155    
156 sysadm 1.7 void article_block_cleanup(void)
157     {
158     if (p_article_block_pool != NULL)
159     {
160     for (int i = 0; i < p_article_block_pool->shm_count; i++)
161     {
162     if (shmdt((p_article_block_pool->shm_pool + i)->p_shm) == -1)
163     {
164     log_error("shmdt(shmid = %d) error (%d)\n", (p_article_block_pool->shm_pool + i)->shmid, errno);
165     }
166    
167     if (shmctl((p_article_block_pool->shm_pool + i)->shmid, IPC_RMID, NULL) == -1)
168     {
169     log_error("shmctl(shmid = %d, IPC_RMID) error (%d)\n", (p_article_block_pool->shm_pool + i)->shmid, errno);
170     }
171     }
172    
173     free(p_article_block_pool);
174     p_article_block_pool = NULL;
175     }
176     }
177    
178     inline static ARTICLE_BLOCK *pop_free_article_block(void)
179     {
180     ARTICLE_BLOCK *p_block = NULL;
181    
182     if (p_article_block_pool->p_block_free_list != NULL)
183     {
184     p_block = p_article_block_pool->p_block_free_list;
185     p_article_block_pool->p_block_free_list = p_block->p_next_block;
186     p_block->p_next_block = NULL;
187     p_block->article_count = 0;
188     }
189    
190     return p_block;
191     }
192    
193     inline static void push_free_article_block(ARTICLE_BLOCK *p_block)
194 sysadm 1.1 {
195 sysadm 1.7 p_block->p_next_block = p_article_block_pool->p_block_free_list;
196     p_article_block_pool->p_block_free_list = p_block;
197     }
198    
199     int article_block_reset(void)
200     {
201     ARTICLE_BLOCK *p_block;
202    
203     if (p_article_block_pool == NULL)
204     {
205     log_error("article_block_pool not initialized\n");
206     return -1;
207     }
208 sysadm 1.1
209 sysadm 1.7 while (p_article_block_pool->block_count > 0)
210 sysadm 1.1 {
211 sysadm 1.7 p_article_block_pool->block_count--;
212     p_block = p_article_block_pool->p_block[p_article_block_pool->block_count];
213     push_free_article_block(p_block);
214 sysadm 1.1 }
215    
216 sysadm 1.7 return 0;
217     }
218    
219     ARTICLE *article_block_find_by_aid(int32_t aid)
220     {
221     ARTICLE_BLOCK *p_block;
222     int left;
223     int right;
224     int mid;
225    
226     if (p_article_block_pool == NULL)
227 sysadm 1.1 {
228 sysadm 1.7 log_error("article_block_pool not initialized\n");
229     return NULL;
230 sysadm 1.1 }
231    
232 sysadm 1.7 if (p_article_block_pool->block_count == 0) // empty
233 sysadm 1.1 {
234 sysadm 1.7 return NULL;
235 sysadm 1.1 }
236    
237 sysadm 1.7 left = 0;
238     right = p_article_block_pool->block_count;
239    
240     // aid in the range [ head aid of blocks[left], tail aid of blocks[right - 1] ]
241     while (left < right - 1)
242 sysadm 1.1 {
243 sysadm 1.7 // get block offset no less than mid value of left and right block offsets
244     mid = (left + right) / 2 + (right - left) % 2;
245    
246     if (mid >= p_article_block_pool->block_count)
247 sysadm 1.1 {
248 sysadm 1.7 log_error("block(mid = %d) is out of boundary\n", mid);
249     return NULL;
250     }
251 sysadm 1.1
252 sysadm 1.7 if (aid < p_article_block_pool->p_block[mid]->articles[0].aid)
253     {
254     right = mid;
255     }
256     else
257     {
258     left = mid;
259 sysadm 1.1 }
260 sysadm 1.7 }
261    
262     p_block = p_article_block_pool->p_block[left];
263    
264     left = 0;
265     right = p_block->article_count - 1;
266    
267     // aid in the range [ aid of articles[left], aid of articles[right] ]
268     while (left < right)
269     {
270     mid = (left + right) / 2;
271 sysadm 1.1
272 sysadm 1.7 if (aid <= p_block->articles[mid].aid)
273     {
274     right = mid;
275     }
276     else
277     {
278     left = mid + 1;
279     }
280 sysadm 1.1 }
281 sysadm 1.7
282     return (p_block->articles + left);
283 sysadm 1.1 }
284    
285 sysadm 1.7 ARTICLE *article_block_find_by_index(int index)
286 sysadm 1.1 {
287 sysadm 1.7 ARTICLE_BLOCK *p_block;
288    
289     if (p_article_block_pool == NULL)
290     {
291     log_error("article_block_pool not initialized\n");
292     return NULL;
293     }
294    
295     if (index < 0 || index / ARTICLE_PER_BLOCK >= p_article_block_pool->block_count)
296     {
297     log_error("section_data_find_article_by_index(%d) is out of boundary of block [0, %d)\n", index, p_article_block_pool->block_count);
298     return NULL;
299     }
300    
301     p_block = p_article_block_pool->p_block[index / ARTICLE_PER_BLOCK];
302 sysadm 1.1
303 sysadm 1.7 if (index % ARTICLE_PER_BLOCK >= p_block->article_count)
304 sysadm 1.1 {
305 sysadm 1.7 log_error("section_data_find_article_by_index(%d) is out of boundary of article [0, %d)\n", index, p_block->article_count);
306     return NULL;
307 sysadm 1.1 }
308    
309 sysadm 1.7 return (p_block->articles + (index % ARTICLE_PER_BLOCK));
310 sysadm 1.1 }
311    
312 sysadm 1.7 SECTION_LIST *section_list_create(const char *sname, const char *stitle, const char *master_name)
313 sysadm 1.1 {
314 sysadm 1.7 SECTION_LIST *p_section;
315    
316     if (p_section_list_pool == NULL)
317     {
318     p_section_list_pool = calloc(BBS_max_section, sizeof(SECTION_LIST));
319     if (p_section_list_pool == NULL)
320     {
321     log_error("calloc(%d SECTION_LIST) OOM\n", BBS_max_section);
322     return NULL;
323     }
324 sysadm 1.1
325 sysadm 1.7 section_list_count = 0;
326     }
327 sysadm 1.1
328 sysadm 1.7 if (p_trie_dict_section_list == NULL)
329 sysadm 1.1 {
330 sysadm 1.7 p_trie_dict_section_list = trie_dict_create();
331     if (p_trie_dict_section_list == NULL)
332     {
333     log_error("trie_dict_create() OOM\n", BBS_max_section);
334     return NULL;
335     }
336 sysadm 1.1 }
337    
338 sysadm 1.7 if (section_list_count >= BBS_max_section)
339 sysadm 1.1 {
340 sysadm 1.7 log_error("section_list_count exceed limit %d\n", BBS_max_section);
341 sysadm 1.1 return NULL;
342     }
343    
344 sysadm 1.7 p_section = p_section_list_pool + section_list_count;
345 sysadm 1.1
346     strncpy(p_section->sname, sname, sizeof(p_section->sname - 1));
347     p_section->sname[sizeof(p_section->sname - 1)] = '\0';
348    
349     strncpy(p_section->stitle, stitle, sizeof(p_section->stitle - 1));
350     p_section->stitle[sizeof(p_section->stitle - 1)] = '\0';
351    
352     strncpy(p_section->master_name, master_name, sizeof(p_section->master_name - 1));
353     p_section->master_name[sizeof(p_section->master_name - 1)] = '\0';
354    
355 sysadm 1.7 if (trie_dict_set(p_trie_dict_section_list, sname, section_list_count) != 1)
356 sysadm 1.1 {
357 sysadm 1.7 log_error("trie_dict_set(section_data, %s, %d) error\n", sname, section_list_count);
358 sysadm 1.1 return NULL;
359     }
360    
361 sysadm 1.7 section_list_reset_articles(p_section);
362    
363     section_list_count++;
364 sysadm 1.1
365     return p_section;
366     }
367    
368 sysadm 1.7 void section_list_reset_articles(SECTION_LIST *p_section)
369 sysadm 1.1 {
370 sysadm 1.7 p_section->article_count = 0;
371     p_section->p_article_head = NULL;
372     p_section->p_article_tail = NULL;
373 sysadm 1.1
374 sysadm 1.7 p_section->page_count = 0;
375     p_section->last_page_article_count = 0;
376     }
377 sysadm 1.1
378 sysadm 1.7 void section_list_cleanup(void)
379     {
380     if (p_trie_dict_section_list != NULL)
381 sysadm 1.1 {
382 sysadm 1.7 trie_dict_destroy(p_trie_dict_section_list);
383     p_trie_dict_section_list = NULL;
384 sysadm 1.1 }
385    
386 sysadm 1.7 if (p_section_list_pool != NULL)
387 sysadm 1.1 {
388 sysadm 1.7 free(p_section_list_pool);
389     p_section_list_pool = NULL;
390 sysadm 1.1 }
391    
392 sysadm 1.7 section_list_count = 0;
393 sysadm 1.1 }
394    
395 sysadm 1.7 SECTION_LIST *section_list_find_by_name(const char *sname)
396 sysadm 1.1 {
397     int64_t index;
398    
399 sysadm 1.7 if (p_section_list_pool == NULL || p_trie_dict_section_list == NULL)
400 sysadm 1.1 {
401 sysadm 1.7 log_error("section_list not initialized\n");
402 sysadm 1.1 return NULL;
403     }
404    
405 sysadm 1.7 if (trie_dict_get(p_trie_dict_section_list, sname, &index) != 1)
406 sysadm 1.1 {
407     log_error("trie_dict_get(section_data, %s) error\n", sname);
408     return NULL;
409     }
410    
411 sysadm 1.7 return (p_section_list_pool + index);
412 sysadm 1.1 }
413    
414 sysadm 1.7 int section_list_append_article(SECTION_LIST *p_section, const ARTICLE *p_article_src)
415 sysadm 1.1 {
416     ARTICLE_BLOCK *p_block;
417     int32_t last_aid = 0;
418 sysadm 1.6 ARTICLE *p_article;
419 sysadm 1.1 ARTICLE *p_topic_head;
420     ARTICLE *p_topic_tail;
421    
422 sysadm 1.6 if (p_section == NULL || p_article_src == NULL)
423 sysadm 1.1 {
424 sysadm 1.7 log_error("section_list_append_article() NULL pointer error\n");
425 sysadm 1.1 return -1;
426     }
427    
428 sysadm 1.7 if (p_article_block_pool == NULL)
429 sysadm 1.1 {
430 sysadm 1.7 log_error("article_block_pool not initialized\n");
431 sysadm 1.1 return -1;
432     }
433    
434 sysadm 1.7 if (p_article_block_pool->block_count == 0 ||
435     p_article_block_pool->p_block[p_article_block_pool->block_count - 1]->article_count >= ARTICLE_PER_BLOCK)
436 sysadm 1.1 {
437     if ((p_block = pop_free_article_block()) == NULL)
438     {
439     log_error("pop_free_article_block() error\n");
440     return -2;
441     }
442    
443 sysadm 1.7 if (p_article_block_pool->block_count > 0)
444 sysadm 1.1 {
445 sysadm 1.7 last_aid = p_article_block_pool->p_block[p_article_block_pool->block_count - 1]->articles[ARTICLE_PER_BLOCK - 1].aid;
446 sysadm 1.1 }
447 sysadm 1.7
448     p_article_block_pool->p_block[p_article_block_pool->block_count] = p_block;
449     p_article_block_pool->block_count++;
450 sysadm 1.1 }
451     else
452     {
453 sysadm 1.7 p_block = p_article_block_pool->p_block[p_article_block_pool->block_count - 1];
454     last_aid = p_block->articles[p_block->article_count - 1].aid;
455 sysadm 1.1 }
456    
457     // AID of articles should be strictly ascending
458 sysadm 1.6 if (p_article_src->aid <= last_aid)
459 sysadm 1.1 {
460 sysadm 1.6 log_error("section_data_append_article(aid=%d) error: last_aid=%d\n", p_article_src->aid, last_aid);
461 sysadm 1.1 return -3;
462     }
463    
464 sysadm 1.7 p_article = (p_block->articles + p_block->article_count);
465     p_block->article_count++;
466     p_section->article_count++;
467    
468     // Copy article data
469     *p_article = *p_article_src;
470 sysadm 1.1
471 sysadm 1.7 // Link appended article as tail node of topic bi-directional list
472     if (p_article->tid != 0)
473 sysadm 1.1 {
474 sysadm 1.7 p_topic_head = article_block_find_by_aid(p_article->tid);
475 sysadm 1.1 if (p_topic_head == NULL)
476     {
477 sysadm 1.7 log_error("search head of topic (aid=%d) error\n", p_article->tid);
478 sysadm 1.1 return -4;
479     }
480    
481 sysadm 1.6 p_topic_tail = p_topic_head->p_topic_prior;
482 sysadm 1.1 if (p_topic_tail == NULL)
483     {
484 sysadm 1.7 log_error("tail of topic (aid=%d) is NULL\n", p_article->tid);
485 sysadm 1.1 return -4;
486     }
487     }
488     else
489     {
490 sysadm 1.7 p_topic_head = p_article;
491     p_topic_tail = p_article;
492 sysadm 1.1 }
493    
494 sysadm 1.7 p_article->p_topic_prior = p_topic_tail;
495     p_article->p_topic_next = p_topic_head;
496     p_topic_head->p_topic_prior = p_article;
497     p_topic_tail->p_topic_next = p_article;
498 sysadm 1.1
499 sysadm 1.6 // Link appended article as tail node of article bi-directional list
500     if (p_section->p_article_head == NULL)
501     {
502     p_section->p_article_head = p_article;
503     p_section->p_article_tail = p_article;
504     }
505     p_article->p_prior = p_section->p_article_tail;
506     p_article->p_next = p_section->p_article_head;
507     p_section->p_article_head->p_prior = p_article;
508     p_section->p_article_tail->p_next = p_article;
509     p_section->p_article_tail = p_article;
510    
511 sysadm 1.7 // Update page
512     if (p_section->last_page_article_count % BBS_article_limit_per_page == 0)
513 sysadm 1.1 {
514 sysadm 1.7 p_section->p_page_first_article[p_section->page_count] = p_article;
515     p_section->page_count++;
516     p_section->last_page_article_count = 0;
517 sysadm 1.1 }
518 sysadm 1.7 p_section->last_page_article_count++;
519 sysadm 1.1
520 sysadm 1.7 return 0;
521 sysadm 1.2 }
522    
523 sysadm 1.7 int section_list_set_article_visible(SECTION_LIST *p_section, int32_t aid, int8_t visible)
524 sysadm 1.1 {
525     ARTICLE *p_article;
526    
527 sysadm 1.2 if (p_section == NULL)
528     {
529 sysadm 1.7 log_error("section_list_set_article_visible() NULL pointer error\n");
530 sysadm 1.2 return -2;
531     }
532    
533 sysadm 1.7 p_article = article_block_find_by_aid(aid);
534 sysadm 1.1 if (p_article == NULL)
535     {
536     return -1; // Not found
537     }
538    
539 sysadm 1.7 if (p_article->visible == visible)
540 sysadm 1.1 {
541 sysadm 1.7 return 0; // Already set
542 sysadm 1.1 }
543    
544 sysadm 1.7 p_article->visible = visible;
545    
546     // TODO:
547 sysadm 1.1
548     return 1;
549     }

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