/[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.30 - (hide annotations)
Thu May 29 00:52:09 2025 UTC (9 months, 2 weeks ago) by sysadm
Branch: MAIN
Changes since 1.29: +2 -2 lines
Content type: text/x-csrc
Refine

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 sysadm 1.16 #define _GNU_SOURCE
18    
19 sysadm 1.1 #include "section_list.h"
20     #include "log.h"
21     #include "trie_dict.h"
22     #include <stdio.h>
23     #include <string.h>
24     #include <signal.h>
25     #include <unistd.h>
26     #include <stdlib.h>
27     #include <errno.h>
28 sysadm 1.7 #include <sys/param.h>
29 sysadm 1.16 #include <sys/sem.h>
30 sysadm 1.1 #include <sys/shm.h>
31     #include <sys/ipc.h>
32    
33 sysadm 1.17 #ifdef _SEM_SEMUN_UNDEFINED
34     union semun
35     {
36     int val; /* Value for SETVAL */
37     struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */
38     unsigned short *array; /* Array for GETALL, SETALL */
39     struct seminfo *__buf; /* Buffer for IPC_INFO
40     (Linux-specific) */
41     };
42     #endif // #ifdef _SEM_SEMUN_UNDEFINED
43    
44 sysadm 1.23 #define SECTION_TRY_LOCK_WAIT_TIME 1 // second
45     #define SECTION_TRY_LOCK_TIMES 10
46    
47 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
48 sysadm 1.18 #define ARTICLE_BLOCK_SHM_COUNT_LIMIT 200 // limited by length (8-bit) of proj_id in ftok(path, proj_id)
49 sysadm 1.7 #define ARTICLE_BLOCK_PER_POOL (ARTICLE_BLOCK_PER_SHM * ARTICLE_BLOCK_SHM_COUNT_LIMIT)
50    
51 sysadm 1.12 #define CALCULATE_PAGE_THRESHOLD 100 // Adjust to tune performance of move topic
52    
53 sysadm 1.14 #define SID_STR_LEN 5 // 32-bit + NULL
54    
55 sysadm 1.7 struct article_block_t
56     {
57     ARTICLE articles[ARTICLE_PER_BLOCK];
58 sysadm 1.22 int article_count;
59 sysadm 1.7 struct article_block_t *p_next_block;
60     };
61     typedef struct article_block_t ARTICLE_BLOCK;
62 sysadm 1.1
63 sysadm 1.22 struct article_block_pool_t
64 sysadm 1.1 {
65     int shmid;
66 sysadm 1.22 struct
67     {
68     int shmid;
69     void *p_shm;
70     } shm_pool[ARTICLE_BLOCK_SHM_COUNT_LIMIT];
71 sysadm 1.7 int shm_count;
72     ARTICLE_BLOCK *p_block_free_list;
73     ARTICLE_BLOCK *p_block[ARTICLE_BLOCK_PER_POOL];
74 sysadm 1.22 int block_count;
75 sysadm 1.7 };
76     typedef struct article_block_pool_t ARTICLE_BLOCK_POOL;
77    
78     static ARTICLE_BLOCK_POOL *p_article_block_pool = NULL;
79 sysadm 1.1
80 sysadm 1.22 struct section_list_pool_t
81     {
82     int shmid;
83     SECTION_LIST sections[BBS_max_section];
84     int section_count;
85     int semid;
86     TRIE_NODE *p_trie_dict_section_by_name;
87     TRIE_NODE *p_trie_dict_section_by_sid;
88     };
89     typedef struct section_list_pool_t SECTION_LIST_POOL;
90    
91     static SECTION_LIST_POOL *p_section_list_pool = NULL;
92 sysadm 1.7
93     int article_block_init(const char *filename, int block_count)
94 sysadm 1.1 {
95     int shmid;
96     int proj_id;
97     key_t key;
98     size_t size;
99     void *p_shm;
100     int i;
101 sysadm 1.7 int block_count_in_shm;
102     ARTICLE_BLOCK *p_block_in_shm;
103     ARTICLE_BLOCK **pp_block_next;
104    
105     if (p_article_block_pool != NULL)
106 sysadm 1.1 {
107 sysadm 1.7 log_error("article_block_pool already initialized\n");
108 sysadm 1.1 return -1;
109     }
110    
111 sysadm 1.27 if (block_count <= 0 || block_count > ARTICLE_BLOCK_PER_POOL)
112 sysadm 1.1 {
113 sysadm 1.7 log_error("article_block_count exceed limit %d\n", ARTICLE_BLOCK_PER_POOL);
114 sysadm 1.1 return -2;
115     }
116    
117 sysadm 1.18 // Allocate shared memory
118     proj_id = ARTICLE_BLOCK_SHM_COUNT_LIMIT; // keep different from proj_id used to create block shm
119     key = ftok(filename, proj_id);
120     if (key == -1)
121     {
122     log_error("ftok(%s, %d) error (%d)\n", filename, proj_id, errno);
123     return -3;
124     }
125    
126     size = sizeof(ARTICLE_BLOCK_POOL);
127     shmid = shmget(key, size, IPC_CREAT | IPC_EXCL | 0600);
128     if (shmid == -1)
129     {
130     log_error("shmget(article_block_pool_shm, size = %d) error (%d)\n", size, errno);
131     return -3;
132     }
133     p_shm = shmat(shmid, NULL, 0);
134     if (p_shm == (void *)-1)
135 sysadm 1.1 {
136 sysadm 1.18 log_error("shmat(shmid = %d) error (%d)\n", shmid, errno);
137     return -3;
138 sysadm 1.1 }
139    
140 sysadm 1.18 p_article_block_pool = p_shm;
141 sysadm 1.22 p_article_block_pool->shmid = shmid;
142 sysadm 1.18
143 sysadm 1.7 p_article_block_pool->shm_count = 0;
144     pp_block_next = &(p_article_block_pool->p_block_free_list);
145 sysadm 1.1
146 sysadm 1.7 while (block_count > 0)
147 sysadm 1.1 {
148 sysadm 1.7 block_count_in_shm = MIN(block_count, ARTICLE_BLOCK_PER_SHM);
149     block_count -= block_count_in_shm;
150 sysadm 1.1
151 sysadm 1.18 proj_id = p_article_block_pool->shm_count;
152 sysadm 1.1 key = ftok(filename, proj_id);
153     if (key == -1)
154     {
155     log_error("ftok(%s, %d) error (%d)\n", filename, proj_id, errno);
156 sysadm 1.7 article_block_cleanup();
157 sysadm 1.1 return -3;
158     }
159    
160 sysadm 1.19 size = sizeof(ARTICLE_BLOCK) * (size_t)block_count_in_shm;
161 sysadm 1.1 shmid = shmget(key, size, IPC_CREAT | IPC_EXCL | 0600);
162     if (shmid == -1)
163     {
164 sysadm 1.7 log_error("shmget(shm_index = %d, size = %d) error (%d)\n", p_article_block_pool->shm_count, size, errno);
165     article_block_cleanup();
166 sysadm 1.1 return -3;
167     }
168     p_shm = shmat(shmid, NULL, 0);
169     if (p_shm == (void *)-1)
170     {
171     log_error("shmat(shmid = %d) error (%d)\n", shmid, errno);
172 sysadm 1.7 article_block_cleanup();
173 sysadm 1.1 return -3;
174     }
175    
176 sysadm 1.7 (p_article_block_pool->shm_pool + p_article_block_pool->shm_count)->shmid = shmid;
177     (p_article_block_pool->shm_pool + p_article_block_pool->shm_count)->p_shm = p_shm;
178     p_article_block_pool->shm_count++;
179 sysadm 1.1
180 sysadm 1.7 p_block_in_shm = p_shm;
181     *pp_block_next = p_block_in_shm;
182 sysadm 1.1
183 sysadm 1.7 for (i = 0; i < block_count_in_shm; i++)
184 sysadm 1.1 {
185 sysadm 1.7 if (i < block_count_in_shm - 1)
186 sysadm 1.1 {
187 sysadm 1.7 (p_block_in_shm + i)->p_next_block = (p_block_in_shm + i + 1);
188 sysadm 1.1 }
189     else
190     {
191 sysadm 1.7 (p_block_in_shm + i)->p_next_block = NULL;
192     pp_block_next = &((p_block_in_shm + i)->p_next_block);
193 sysadm 1.1 }
194     }
195     }
196    
197 sysadm 1.7 p_article_block_pool->block_count = 0;
198    
199 sysadm 1.1 return 0;
200     }
201    
202 sysadm 1.7 void article_block_cleanup(void)
203     {
204 sysadm 1.22 int shmid;
205    
206 sysadm 1.18 if (p_article_block_pool == NULL)
207     {
208     return;
209     }
210    
211     for (int i = 0; i < p_article_block_pool->shm_count; i++)
212 sysadm 1.7 {
213 sysadm 1.18 if (shmdt((p_article_block_pool->shm_pool + i)->p_shm) == -1)
214 sysadm 1.7 {
215 sysadm 1.18 log_error("shmdt(shmid = %d) error (%d)\n", (p_article_block_pool->shm_pool + i)->shmid, errno);
216     }
217 sysadm 1.7
218 sysadm 1.18 if (shmctl((p_article_block_pool->shm_pool + i)->shmid, IPC_RMID, NULL) == -1)
219     {
220     log_error("shmctl(shmid = %d, IPC_RMID) error (%d)\n", (p_article_block_pool->shm_pool + i)->shmid, errno);
221 sysadm 1.7 }
222 sysadm 1.18 }
223    
224 sysadm 1.22 shmid = p_article_block_pool->shmid;
225    
226 sysadm 1.18 if (shmdt(p_article_block_pool) == -1)
227     {
228 sysadm 1.22 log_error("shmdt(shmid = %d) error (%d)\n", shmid, errno);
229 sysadm 1.18 }
230 sysadm 1.7
231 sysadm 1.22 if (shmctl(shmid, IPC_RMID, NULL) == -1)
232 sysadm 1.18 {
233 sysadm 1.22 log_error("shmctl(shmid = %d, IPC_RMID) error (%d)\n", shmid, errno);
234 sysadm 1.7 }
235 sysadm 1.18
236     p_article_block_pool = NULL;
237 sysadm 1.7 }
238    
239 sysadm 1.26 int set_article_block_shm_readonly(void)
240     {
241     int shmid;
242     void *p_shm;
243     int i;
244    
245     if (p_article_block_pool == NULL)
246     {
247     log_error("article_block_pool not initialized\n");
248     return -1;
249     }
250    
251     for (i = 0; i < p_article_block_pool->shm_count; i++)
252     {
253     shmid = (p_article_block_pool->shm_pool + i)->shmid;
254    
255     // Remap shared memory in read-only mode
256     p_shm = shmat(shmid, (p_article_block_pool->shm_pool + i)->p_shm, SHM_RDONLY | SHM_REMAP);
257     if (p_shm == (void *)-1)
258     {
259     log_error("shmat(article_block_pool shmid = %d) error (%d)\n", shmid, errno);
260     return -2;
261     }
262     }
263    
264     return 0;
265     }
266    
267     int detach_article_block_shm(void)
268     {
269     int shmid;
270    
271     if (p_article_block_pool == NULL)
272     {
273     return -1;
274     }
275    
276     for (int i = 0; i < p_article_block_pool->shm_count; i++)
277     {
278     if ((p_article_block_pool->shm_pool + i)->p_shm != NULL && shmdt((p_article_block_pool->shm_pool + i)->p_shm) == -1)
279     {
280     log_error("shmdt(shmid = %d) error (%d)\n", (p_article_block_pool->shm_pool + i)->shmid, errno);
281     return -2;
282     }
283     }
284    
285     shmid = p_article_block_pool->shmid;
286    
287     if (shmdt(p_article_block_pool) == -1)
288     {
289     log_error("shmdt(shmid = %d) error (%d)\n", shmid, errno);
290     return -3;
291     }
292    
293     p_article_block_pool = NULL;
294    
295     return 0;
296     }
297    
298 sysadm 1.7 inline static ARTICLE_BLOCK *pop_free_article_block(void)
299     {
300     ARTICLE_BLOCK *p_block = NULL;
301    
302     if (p_article_block_pool->p_block_free_list != NULL)
303     {
304     p_block = p_article_block_pool->p_block_free_list;
305     p_article_block_pool->p_block_free_list = p_block->p_next_block;
306     p_block->p_next_block = NULL;
307     p_block->article_count = 0;
308     }
309    
310     return p_block;
311     }
312    
313     inline static void push_free_article_block(ARTICLE_BLOCK *p_block)
314 sysadm 1.1 {
315 sysadm 1.7 p_block->p_next_block = p_article_block_pool->p_block_free_list;
316     p_article_block_pool->p_block_free_list = p_block;
317     }
318    
319     int article_block_reset(void)
320     {
321     ARTICLE_BLOCK *p_block;
322    
323     if (p_article_block_pool == NULL)
324     {
325     log_error("article_block_pool not initialized\n");
326     return -1;
327     }
328 sysadm 1.1
329 sysadm 1.7 while (p_article_block_pool->block_count > 0)
330 sysadm 1.1 {
331 sysadm 1.7 p_article_block_pool->block_count--;
332     p_block = p_article_block_pool->p_block[p_article_block_pool->block_count];
333     push_free_article_block(p_block);
334 sysadm 1.1 }
335    
336 sysadm 1.7 return 0;
337     }
338    
339     ARTICLE *article_block_find_by_aid(int32_t aid)
340     {
341     ARTICLE_BLOCK *p_block;
342     int left;
343     int right;
344     int mid;
345    
346     if (p_article_block_pool == NULL)
347 sysadm 1.1 {
348 sysadm 1.7 log_error("article_block_pool not initialized\n");
349     return NULL;
350 sysadm 1.1 }
351    
352 sysadm 1.7 if (p_article_block_pool->block_count == 0) // empty
353 sysadm 1.1 {
354 sysadm 1.7 return NULL;
355 sysadm 1.1 }
356    
357 sysadm 1.7 left = 0;
358     right = p_article_block_pool->block_count;
359    
360     // aid in the range [ head aid of blocks[left], tail aid of blocks[right - 1] ]
361     while (left < right - 1)
362 sysadm 1.1 {
363 sysadm 1.7 // get block offset no less than mid value of left and right block offsets
364     mid = (left + right) / 2 + (right - left) % 2;
365    
366     if (mid >= p_article_block_pool->block_count)
367 sysadm 1.1 {
368 sysadm 1.7 log_error("block(mid = %d) is out of boundary\n", mid);
369     return NULL;
370     }
371 sysadm 1.1
372 sysadm 1.7 if (aid < p_article_block_pool->p_block[mid]->articles[0].aid)
373     {
374     right = mid;
375     }
376     else
377     {
378     left = mid;
379 sysadm 1.1 }
380 sysadm 1.7 }
381    
382     p_block = p_article_block_pool->p_block[left];
383    
384     left = 0;
385     right = p_block->article_count - 1;
386    
387     // aid in the range [ aid of articles[left], aid of articles[right] ]
388     while (left < right)
389     {
390     mid = (left + right) / 2;
391 sysadm 1.1
392 sysadm 1.7 if (aid <= p_block->articles[mid].aid)
393     {
394     right = mid;
395     }
396     else
397     {
398     left = mid + 1;
399     }
400 sysadm 1.1 }
401 sysadm 1.7
402 sysadm 1.28 if (aid != p_block->articles[left].aid) // not found
403     {
404     return NULL;
405     }
406    
407     return (p_block->articles + left); // found
408 sysadm 1.1 }
409    
410 sysadm 1.7 ARTICLE *article_block_find_by_index(int index)
411 sysadm 1.1 {
412 sysadm 1.7 ARTICLE_BLOCK *p_block;
413    
414     if (p_article_block_pool == NULL)
415     {
416     log_error("article_block_pool not initialized\n");
417     return NULL;
418     }
419    
420     if (index < 0 || index / ARTICLE_PER_BLOCK >= p_article_block_pool->block_count)
421     {
422 sysadm 1.14 log_error("article_block_find_by_index(%d) is out of boundary of block [0, %d)\n", index, p_article_block_pool->block_count);
423 sysadm 1.7 return NULL;
424     }
425    
426     p_block = p_article_block_pool->p_block[index / ARTICLE_PER_BLOCK];
427 sysadm 1.1
428 sysadm 1.7 if (index % ARTICLE_PER_BLOCK >= p_block->article_count)
429 sysadm 1.1 {
430 sysadm 1.14 log_error("article_block_find_by_index(%d) is out of boundary of article [0, %d)\n", index, p_block->article_count);
431 sysadm 1.7 return NULL;
432 sysadm 1.1 }
433    
434 sysadm 1.7 return (p_block->articles + (index % ARTICLE_PER_BLOCK));
435 sysadm 1.1 }
436    
437 sysadm 1.19 extern int section_list_init(const char *filename)
438 sysadm 1.1 {
439 sysadm 1.16 int semid;
440 sysadm 1.13 int shmid;
441     int proj_id;
442     key_t key;
443     size_t size;
444     void *p_shm;
445 sysadm 1.17 union semun arg;
446     int i;
447 sysadm 1.13
448 sysadm 1.22 if (p_section_list_pool != NULL)
449 sysadm 1.13 {
450 sysadm 1.19 section_list_cleanup();
451 sysadm 1.13 }
452 sysadm 1.7
453 sysadm 1.13 proj_id = (int)(time(NULL) % getpid());
454     key = ftok(filename, proj_id);
455     if (key == -1)
456     {
457     log_error("ftok(%s, %d) error (%d)\n", filename, proj_id, errno);
458     return -3;
459     }
460 sysadm 1.1
461 sysadm 1.22 // Allocate shared memory
462     size = sizeof(SECTION_LIST_POOL);
463     shmid = shmget(key, size, IPC_CREAT | IPC_EXCL | 0600);
464     if (shmid == -1)
465     {
466     log_error("shmget(section_list_pool_shm, size = %d) error (%d)\n", size, errno);
467     return -3;
468     }
469     p_shm = shmat(shmid, NULL, 0);
470     if (p_shm == (void *)-1)
471     {
472     log_error("shmat(shmid = %d) error (%d)\n", shmid, errno);
473     return -3;
474     }
475    
476     p_section_list_pool = p_shm;
477     p_section_list_pool->shmid = shmid;
478     p_section_list_pool->section_count = 0;
479    
480     // Allocate semaphore as section locks
481 sysadm 1.16 size = 2 * (BBS_max_section + 1); // r_sem and w_sem per section, the last pair for all sections
482     semid = semget(key, (int)size, IPC_CREAT | IPC_EXCL | 0600);
483     if (semid == -1)
484     {
485 sysadm 1.17 log_error("semget(section_list_pool_sem, size = %d) error (%d)\n", size, errno);
486 sysadm 1.16 return -3;
487     }
488    
489 sysadm 1.17 // Initialize sem value to 0
490     arg.val = 0;
491     for (i = 0; i < size; i++)
492     {
493     if (semctl(semid, i, SETVAL, arg) == -1)
494     {
495     log_error("semctl(section_list_pool_sem, SETVAL) error (%d)\n", errno);
496     return -3;
497     }
498     }
499    
500 sysadm 1.22 p_section_list_pool->semid = semid;
501 sysadm 1.16
502 sysadm 1.22 p_section_list_pool->p_trie_dict_section_by_name = trie_dict_create();
503     if (p_section_list_pool->p_trie_dict_section_by_name == NULL)
504 sysadm 1.14 {
505     log_error("trie_dict_create() OOM\n", BBS_max_section);
506     return -2;
507     }
508    
509 sysadm 1.22 p_section_list_pool->p_trie_dict_section_by_sid = trie_dict_create();
510     if (p_section_list_pool->p_trie_dict_section_by_sid == NULL)
511 sysadm 1.1 {
512 sysadm 1.13 log_error("trie_dict_create() OOM\n", BBS_max_section);
513     return -2;
514     }
515    
516     return 0;
517     }
518    
519 sysadm 1.26 void section_list_cleanup(void)
520     {
521     int shmid;
522    
523     if (p_section_list_pool == NULL)
524     {
525     return;
526     }
527    
528     if (p_section_list_pool->p_trie_dict_section_by_name != NULL)
529     {
530     trie_dict_destroy(p_section_list_pool->p_trie_dict_section_by_name);
531     p_section_list_pool->p_trie_dict_section_by_name = NULL;
532     }
533    
534     if (p_section_list_pool->p_trie_dict_section_by_sid != NULL)
535     {
536     trie_dict_destroy(p_section_list_pool->p_trie_dict_section_by_sid);
537     p_section_list_pool->p_trie_dict_section_by_sid = NULL;
538     }
539    
540     shmid = p_section_list_pool->shmid;
541    
542     if (semctl(p_section_list_pool->semid, 0, IPC_RMID) == -1)
543     {
544     log_error("semctl(semid = %d, IPC_RMID) error (%d)\n", p_section_list_pool->semid, errno);
545     }
546    
547     if (shmdt(p_section_list_pool) == -1)
548     {
549     log_error("shmdt(shmid = %d) error (%d)\n", shmid, errno);
550     }
551    
552     if (shmctl(shmid, IPC_RMID, NULL) == -1)
553     {
554     log_error("shmctl(shmid = %d, IPC_RMID) error (%d)\n", shmid, errno);
555     }
556    
557     p_section_list_pool = NULL;
558     }
559    
560     int set_section_list_shm_readonly(void)
561     {
562     int shmid;
563     void *p_shm;
564    
565     if (p_section_list_pool == NULL)
566     {
567     log_error("p_section_list_pool not initialized\n");
568     return -1;
569     }
570    
571     shmid = p_section_list_pool->shmid;
572    
573     // Remap shared memory in read-only mode
574     p_shm = shmat(shmid, p_section_list_pool, SHM_RDONLY | SHM_REMAP);
575     if (p_shm == (void *)-1)
576     {
577     log_error("shmat(section_list_pool shmid = %d) error (%d)\n", shmid, errno);
578     return -3;
579     }
580    
581     p_section_list_pool = p_shm;
582    
583     return 0;
584     }
585    
586     int detach_section_list_shm(void)
587     {
588     if (p_section_list_pool != NULL && shmdt(p_section_list_pool) == -1)
589     {
590     log_error("shmdt(section_list_pool) error (%d)\n", errno);
591     return -1;
592     }
593    
594     p_section_list_pool = NULL;
595    
596     return 0;
597     }
598    
599 sysadm 1.14 inline static void sid_to_str(int32_t sid, char *p_sid_str)
600     {
601     uint32_t u_sid;
602     int i;
603    
604     u_sid = (uint32_t)sid;
605     for (i = 0; i < SID_STR_LEN - 1; i++)
606     {
607     p_sid_str[i] = (char)(u_sid % 255 + 1);
608     u_sid /= 255;
609     }
610     p_sid_str[i] = '\0';
611     }
612    
613 sysadm 1.30 SECTION_LIST *section_list_create(int32_t sid, const char *sname, const char *stitle, const char *master_list)
614 sysadm 1.13 {
615     SECTION_LIST *p_section;
616 sysadm 1.14 char sid_str[SID_STR_LEN];
617 sysadm 1.13
618 sysadm 1.22 if (p_section_list_pool == NULL)
619 sysadm 1.13 {
620     log_error("session_list_pool not initialized\n");
621     return NULL;
622 sysadm 1.1 }
623    
624 sysadm 1.22 if (p_section_list_pool->section_count >= BBS_max_section)
625 sysadm 1.1 {
626 sysadm 1.22 log_error("section_count reach limit %d >= %d\n", p_section_list_pool->section_count, BBS_max_section);
627 sysadm 1.1 return NULL;
628     }
629    
630 sysadm 1.14 sid_to_str(sid, sid_str);
631    
632 sysadm 1.22 p_section = p_section_list_pool->sections + p_section_list_pool->section_count;
633 sysadm 1.1
634 sysadm 1.11 p_section->sid = sid;
635    
636 sysadm 1.29 strncpy(p_section->sname, sname, sizeof(p_section->sname) - 1);
637     p_section->sname[sizeof(p_section->sname) - 1] = '\0';
638 sysadm 1.1
639 sysadm 1.29 strncpy(p_section->stitle, stitle, sizeof(p_section->stitle) - 1);
640     p_section->stitle[sizeof(p_section->stitle) - 1] = '\0';
641 sysadm 1.1
642 sysadm 1.30 strncpy(p_section->master_list, master_list, sizeof(p_section->master_list) - 1);
643 sysadm 1.29 p_section->master_list[sizeof(p_section->master_list) - 1] = '\0';
644 sysadm 1.1
645 sysadm 1.22 if (trie_dict_set(p_section_list_pool->p_trie_dict_section_by_name, sname, p_section_list_pool->section_count) != 1)
646 sysadm 1.14 {
647 sysadm 1.22 log_error("trie_dict_set(section, %s, %d) error\n", sname, p_section_list_pool->section_count);
648 sysadm 1.14 return NULL;
649     }
650    
651 sysadm 1.22 if (trie_dict_set(p_section_list_pool->p_trie_dict_section_by_sid, sid_str, p_section_list_pool->section_count) != 1)
652 sysadm 1.1 {
653 sysadm 1.22 log_error("trie_dict_set(section, %d, %d) error\n", sid, p_section_list_pool->section_count);
654 sysadm 1.1 return NULL;
655     }
656    
657 sysadm 1.7 section_list_reset_articles(p_section);
658    
659 sysadm 1.22 p_section_list_pool->section_count++;
660 sysadm 1.1
661     return p_section;
662     }
663    
664 sysadm 1.7 void section_list_reset_articles(SECTION_LIST *p_section)
665 sysadm 1.1 {
666 sysadm 1.7 p_section->article_count = 0;
667 sysadm 1.8 p_section->topic_count = 0;
668     p_section->visible_article_count = 0;
669     p_section->visible_topic_count = 0;
670 sysadm 1.7 p_section->p_article_head = NULL;
671     p_section->p_article_tail = NULL;
672 sysadm 1.1
673 sysadm 1.7 p_section->page_count = 0;
674 sysadm 1.8 p_section->last_page_visible_article_count = 0;
675 sysadm 1.7 }
676 sysadm 1.1
677 sysadm 1.7 SECTION_LIST *section_list_find_by_name(const char *sname)
678 sysadm 1.1 {
679     int64_t index;
680 sysadm 1.24 int ret;
681 sysadm 1.1
682 sysadm 1.22 if (p_section_list_pool == NULL)
683 sysadm 1.14 {
684     log_error("section_list not initialized\n");
685     return NULL;
686     }
687    
688 sysadm 1.24 ret = trie_dict_get(p_section_list_pool->p_trie_dict_section_by_name, sname, &index);
689     if (ret < 0)
690 sysadm 1.14 {
691     log_error("trie_dict_get(section, %s) error\n", sname);
692     return NULL;
693     }
694 sysadm 1.24 else if (ret == 0)
695     {
696     return NULL;
697     }
698 sysadm 1.14
699 sysadm 1.22 return (p_section_list_pool->sections + index);
700 sysadm 1.14 }
701    
702     SECTION_LIST *section_list_find_by_sid(int32_t sid)
703     {
704     int64_t index;
705 sysadm 1.24 int ret;
706 sysadm 1.14 char sid_str[SID_STR_LEN];
707    
708 sysadm 1.22 if (p_section_list_pool == NULL)
709 sysadm 1.1 {
710 sysadm 1.7 log_error("section_list not initialized\n");
711 sysadm 1.1 return NULL;
712     }
713    
714 sysadm 1.14 sid_to_str(sid, sid_str);
715    
716 sysadm 1.24 ret = trie_dict_get(p_section_list_pool->p_trie_dict_section_by_sid, sid_str, &index);
717     if (ret < 0)
718 sysadm 1.1 {
719 sysadm 1.14 log_error("trie_dict_get(section, %d) error\n", sid);
720 sysadm 1.1 return NULL;
721     }
722 sysadm 1.24 else if (ret == 0)
723     {
724     return NULL;
725     }
726 sysadm 1.1
727 sysadm 1.22 return (p_section_list_pool->sections + index);
728 sysadm 1.1 }
729    
730 sysadm 1.7 int section_list_append_article(SECTION_LIST *p_section, const ARTICLE *p_article_src)
731 sysadm 1.1 {
732     ARTICLE_BLOCK *p_block;
733     int32_t last_aid = 0;
734 sysadm 1.6 ARTICLE *p_article;
735 sysadm 1.1 ARTICLE *p_topic_head;
736     ARTICLE *p_topic_tail;
737    
738 sysadm 1.6 if (p_section == NULL || p_article_src == NULL)
739 sysadm 1.1 {
740 sysadm 1.7 log_error("section_list_append_article() NULL pointer error\n");
741 sysadm 1.1 return -1;
742     }
743    
744 sysadm 1.7 if (p_article_block_pool == NULL)
745 sysadm 1.1 {
746 sysadm 1.7 log_error("article_block_pool not initialized\n");
747 sysadm 1.1 return -1;
748     }
749    
750 sysadm 1.14 if (p_section->sid != p_article_src->sid)
751     {
752     log_error("section_list_append_article() error: section sid %d != article sid %d\n", p_section->sid, p_article_src->sid);
753     return -2;
754     }
755    
756 sysadm 1.9 if (p_section->article_count >= BBS_article_limit_per_section)
757     {
758     log_error("section_list_append_article() error: article_count reach limit in section %d\n", p_section->sid);
759     return -2;
760     }
761    
762 sysadm 1.7 if (p_article_block_pool->block_count == 0 ||
763     p_article_block_pool->p_block[p_article_block_pool->block_count - 1]->article_count >= ARTICLE_PER_BLOCK)
764 sysadm 1.1 {
765     if ((p_block = pop_free_article_block()) == NULL)
766     {
767     log_error("pop_free_article_block() error\n");
768     return -2;
769     }
770    
771 sysadm 1.7 if (p_article_block_pool->block_count > 0)
772 sysadm 1.1 {
773 sysadm 1.7 last_aid = p_article_block_pool->p_block[p_article_block_pool->block_count - 1]->articles[ARTICLE_PER_BLOCK - 1].aid;
774 sysadm 1.1 }
775 sysadm 1.7
776     p_article_block_pool->p_block[p_article_block_pool->block_count] = p_block;
777     p_article_block_pool->block_count++;
778 sysadm 1.1 }
779     else
780     {
781 sysadm 1.7 p_block = p_article_block_pool->p_block[p_article_block_pool->block_count - 1];
782     last_aid = p_block->articles[p_block->article_count - 1].aid;
783 sysadm 1.1 }
784    
785     // AID of articles should be strictly ascending
786 sysadm 1.6 if (p_article_src->aid <= last_aid)
787 sysadm 1.1 {
788 sysadm 1.14 log_error("section_list_append_article(aid=%d) error: last_aid=%d\n", p_article_src->aid, last_aid);
789 sysadm 1.1 return -3;
790     }
791    
792 sysadm 1.7 p_article = (p_block->articles + p_block->article_count);
793     p_block->article_count++;
794     p_section->article_count++;
795    
796     // Copy article data
797     *p_article = *p_article_src;
798 sysadm 1.1
799 sysadm 1.8 if (p_article->visible)
800     {
801     p_section->visible_article_count++;
802     }
803    
804 sysadm 1.7 // Link appended article as tail node of topic bi-directional list
805     if (p_article->tid != 0)
806 sysadm 1.1 {
807 sysadm 1.7 p_topic_head = article_block_find_by_aid(p_article->tid);
808 sysadm 1.1 if (p_topic_head == NULL)
809     {
810 sysadm 1.7 log_error("search head of topic (aid=%d) error\n", p_article->tid);
811 sysadm 1.1 return -4;
812     }
813    
814 sysadm 1.6 p_topic_tail = p_topic_head->p_topic_prior;
815 sysadm 1.1 if (p_topic_tail == NULL)
816     {
817 sysadm 1.7 log_error("tail of topic (aid=%d) is NULL\n", p_article->tid);
818 sysadm 1.1 return -4;
819     }
820     }
821     else
822     {
823 sysadm 1.8 p_section->topic_count++;
824    
825     if (p_article->visible)
826     {
827     p_section->visible_topic_count++;
828     }
829    
830 sysadm 1.7 p_topic_head = p_article;
831     p_topic_tail = p_article;
832 sysadm 1.1 }
833    
834 sysadm 1.7 p_article->p_topic_prior = p_topic_tail;
835     p_article->p_topic_next = p_topic_head;
836     p_topic_head->p_topic_prior = p_article;
837     p_topic_tail->p_topic_next = p_article;
838 sysadm 1.1
839 sysadm 1.6 // Link appended article as tail node of article bi-directional list
840     if (p_section->p_article_head == NULL)
841     {
842     p_section->p_article_head = p_article;
843     p_section->p_article_tail = p_article;
844     }
845     p_article->p_prior = p_section->p_article_tail;
846     p_article->p_next = p_section->p_article_head;
847     p_section->p_article_head->p_prior = p_article;
848     p_section->p_article_tail->p_next = p_article;
849     p_section->p_article_tail = p_article;
850    
851 sysadm 1.7 // Update page
852 sysadm 1.11 if ((p_article->visible && p_section->last_page_visible_article_count % BBS_article_limit_per_page == 0) ||
853     p_section->article_count == 1)
854 sysadm 1.1 {
855 sysadm 1.7 p_section->p_page_first_article[p_section->page_count] = p_article;
856     p_section->page_count++;
857 sysadm 1.8 p_section->last_page_visible_article_count = 0;
858 sysadm 1.1 }
859 sysadm 1.9
860     if (p_article->visible)
861     {
862     p_section->last_page_visible_article_count++;
863     }
864 sysadm 1.1
865 sysadm 1.7 return 0;
866 sysadm 1.2 }
867    
868 sysadm 1.7 int section_list_set_article_visible(SECTION_LIST *p_section, int32_t aid, int8_t visible)
869 sysadm 1.1 {
870     ARTICLE *p_article;
871 sysadm 1.8 ARTICLE *p_reply;
872     int affected_count = 0;
873 sysadm 1.1
874 sysadm 1.2 if (p_section == NULL)
875     {
876 sysadm 1.7 log_error("section_list_set_article_visible() NULL pointer error\n");
877 sysadm 1.2 return -2;
878     }
879    
880 sysadm 1.7 p_article = article_block_find_by_aid(aid);
881 sysadm 1.1 if (p_article == NULL)
882     {
883     return -1; // Not found
884     }
885    
886 sysadm 1.14 if (p_section->sid != p_article->sid)
887     {
888     log_error("section_list_set_article_visible() error: section sid %d != article sid %d\n", p_section->sid, p_article->sid);
889     return -2;
890     }
891    
892 sysadm 1.7 if (p_article->visible == visible)
893 sysadm 1.1 {
894 sysadm 1.7 return 0; // Already set
895 sysadm 1.1 }
896    
897 sysadm 1.8 if (visible == 0) // 1 -> 0
898     {
899     p_section->visible_article_count--;
900    
901     if (p_article->tid == 0)
902     {
903     p_section->visible_topic_count--;
904    
905     // Set related visible replies to invisible
906     for (p_reply = p_article->p_topic_next; p_reply->tid != 0; p_reply = p_reply->p_topic_next)
907     {
908     if (p_reply->tid != aid)
909     {
910     log_error("Inconsistent tid = %d found in reply %d of topic %d\n", p_reply->tid, p_reply->aid, aid);
911     continue;
912     }
913    
914     if (p_reply->visible == 1)
915     {
916     p_reply->visible = 0;
917     p_section->visible_article_count--;
918     affected_count++;
919     }
920     }
921     }
922     }
923     else // 0 -> 1
924     {
925     p_section->visible_article_count++;
926    
927     if (p_article->tid == 0)
928     {
929     p_section->visible_topic_count++;
930     }
931     }
932    
933 sysadm 1.7 p_article->visible = visible;
934 sysadm 1.8 affected_count++;
935    
936     return affected_count;
937     }
938    
939 sysadm 1.11 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)
940 sysadm 1.8 {
941     ARTICLE *p_article;
942     int left;
943     int right;
944     int mid;
945    
946     *p_page = -1;
947     *p_offset = -1;
948 sysadm 1.11 *pp_next = NULL;
949 sysadm 1.8
950     if (p_section == NULL)
951     {
952     log_error("section_list_find_article_with_offset() NULL pointer error\n");
953     return NULL;
954     }
955 sysadm 1.7
956 sysadm 1.8 if (p_section->article_count == 0) // empty
957     {
958     *p_page = 0;
959     *p_offset = 0;
960     return NULL;
961     }
962    
963     left = 0;
964     right = p_section->page_count;
965    
966     // aid in the range [ head aid of pages[left], tail aid of pages[right - 1] ]
967     while (left < right - 1)
968     {
969     // get page id no less than mid value of left page id and right page id
970     mid = (left + right) / 2 + (right - left) % 2;
971 sysadm 1.1
972 sysadm 1.8 if (mid >= p_section->page_count)
973     {
974     log_error("page id (mid = %d) is out of boundary\n", mid);
975     return NULL;
976     }
977    
978     if (aid < p_section->p_page_first_article[mid]->aid)
979     {
980     right = mid;
981     }
982     else
983     {
984     left = mid;
985     }
986     }
987    
988     *p_page = left;
989    
990     p_article = p_section->p_page_first_article[*p_page];
991    
992     // p_section->p_page_first_article[*p_page]->aid <= aid < p_section->p_page_first_article[*p_page + 1]->aid
993 sysadm 1.11 right = (*p_page == MAX(0, p_section->page_count - 1) ? INT32_MAX : p_section->p_page_first_article[*p_page + 1]->aid);
994 sysadm 1.8
995     // left will be the offset of article found or offset to insert
996     left = 0;
997    
998 sysadm 1.10 while (aid > p_article->aid)
999 sysadm 1.8 {
1000     p_article = p_article->p_next;
1001     left++;
1002    
1003 sysadm 1.11 if (aid == p_article->aid)
1004     {
1005     *pp_next = p_article->p_next;
1006     break;
1007     }
1008    
1009 sysadm 1.8 // over last article in the page
1010     if (p_article == p_section->p_article_head || p_article->aid >= right)
1011     {
1012 sysadm 1.11 *pp_next = (p_article == p_section->p_article_head ? p_section->p_article_head : p_section->p_page_first_article[*p_page + 1]);
1013     *p_offset = left;
1014     return NULL; // not found
1015 sysadm 1.8 }
1016     }
1017    
1018 sysadm 1.11 if (aid < p_article->aid)
1019     {
1020     *pp_next = p_article;
1021     p_article = NULL; // not found
1022     }
1023     else // aid == p_article->aid
1024 sysadm 1.10 {
1025 sysadm 1.11 *pp_next = p_article->p_next;
1026 sysadm 1.10 }
1027    
1028 sysadm 1.8 *p_offset = left;
1029    
1030     return p_article;
1031     }
1032    
1033     int section_list_calculate_page(SECTION_LIST *p_section, int32_t start_aid)
1034     {
1035 sysadm 1.9 ARTICLE *p_article;
1036 sysadm 1.11 ARTICLE *p_next;
1037 sysadm 1.9 int32_t page;
1038     int32_t offset;
1039     int visible_article_count;
1040     int page_head_set;
1041 sysadm 1.8
1042     if (p_section == NULL)
1043     {
1044     log_error("section_list_calculate_page() NULL pointer error\n");
1045     return -1;
1046     }
1047    
1048 sysadm 1.11 if (p_section->article_count == 0) // empty
1049     {
1050     p_section->page_count = 0;
1051     p_section->last_page_visible_article_count = 0;
1052    
1053     return 0;
1054     }
1055    
1056     if (start_aid > 0)
1057 sysadm 1.9 {
1058 sysadm 1.14 p_article = article_block_find_by_aid(start_aid);
1059     if (p_article == NULL)
1060     {
1061     return -1; // Not found
1062     }
1063    
1064     if (p_section->sid != p_article->sid)
1065     {
1066     log_error("section_list_calculate_page() error: section sid %d != start article sid %d\n", p_section->sid, p_article->sid);
1067     return -2;
1068     }
1069    
1070 sysadm 1.11 p_article = section_list_find_article_with_offset(p_section, start_aid, &page, &offset, &p_next);
1071     if (p_article == NULL)
1072 sysadm 1.9 {
1073 sysadm 1.11 if (page < 0)
1074     {
1075     return -1;
1076     }
1077     log_error("section_list_calculate_page() aid = %d not found in section sid = %d\n",
1078     start_aid, p_section->sid);
1079     return -2;
1080 sysadm 1.9 }
1081    
1082 sysadm 1.11 if (offset > 0)
1083     {
1084     p_article = p_section->p_page_first_article[page];
1085     }
1086 sysadm 1.9 }
1087 sysadm 1.11 else
1088 sysadm 1.9 {
1089 sysadm 1.11 p_article = p_section->p_article_head;
1090     page = 0;
1091     offset = 0;
1092 sysadm 1.9 }
1093    
1094     visible_article_count = 0;
1095     page_head_set = 0;
1096    
1097     do
1098     {
1099     if (!page_head_set && visible_article_count == 0)
1100     {
1101     p_section->p_page_first_article[page] = p_article;
1102     page_head_set = 1;
1103     }
1104    
1105     if (p_article->visible)
1106     {
1107     visible_article_count++;
1108     }
1109    
1110     p_article = p_article->p_next;
1111    
1112     // skip remaining invisible articles
1113     while (p_article->visible == 0 && p_article != p_section->p_article_head)
1114     {
1115     p_article = p_article->p_next;
1116     }
1117    
1118     if (visible_article_count >= BBS_article_limit_per_page && p_article != p_section->p_article_head)
1119     {
1120     page++;
1121     visible_article_count = 0;
1122     page_head_set = 0;
1123    
1124     if (page >= BBS_article_limit_per_section / BBS_article_limit_per_page && p_article != p_section->p_article_head)
1125     {
1126     log_error("Count of page exceed limit in section %d\n", p_section->sid);
1127     break;
1128     }
1129     }
1130     } while (p_article != p_section->p_article_head);
1131    
1132     p_section->page_count = page + (visible_article_count > 0 ? 1 : 0);
1133     p_section->last_page_visible_article_count = visible_article_count;
1134    
1135 sysadm 1.8 return 0;
1136 sysadm 1.1 }
1137 sysadm 1.11
1138 sysadm 1.25 int32_t article_block_last_aid(void)
1139     {
1140     ARTICLE_BLOCK *p_block = p_article_block_pool->p_block[p_article_block_pool->block_count - 1];
1141     int32_t last_aid = p_block->articles[p_block->article_count - 1].aid;
1142    
1143     return last_aid;
1144     }
1145    
1146 sysadm 1.27 int article_block_article_count(void)
1147     {
1148     int ret;
1149    
1150     if (p_article_block_pool == NULL || p_article_block_pool->block_count <= 0)
1151     {
1152     return -1;
1153     }
1154    
1155     ret = (p_article_block_pool->block_count - 1) * ARTICLE_PER_BLOCK +
1156     p_article_block_pool->p_block[p_article_block_pool->block_count - 1]->article_count;
1157    
1158     return ret;
1159     }
1160    
1161 sysadm 1.14 int article_count_of_topic(int32_t aid)
1162 sysadm 1.11 {
1163     ARTICLE *p_article;
1164     int article_count;
1165    
1166     p_article = article_block_find_by_aid(aid);
1167     if (p_article == NULL)
1168     {
1169     return 0; // Not found
1170     }
1171    
1172     article_count = 0;
1173    
1174     do
1175     {
1176 sysadm 1.15 if (p_article->tid != 0 && p_article->tid != aid)
1177     {
1178     log_error("article_count_of_topic(%d) error: article %d not linked to the topic\n", aid, p_article->aid);
1179     break;
1180     }
1181    
1182 sysadm 1.11 article_count++;
1183     p_article = p_article->p_topic_next;
1184     } while (p_article->aid != aid);
1185    
1186     return article_count;
1187     }
1188    
1189     int section_list_move_topic(SECTION_LIST *p_section_src, SECTION_LIST *p_section_dest, int32_t aid)
1190     {
1191     ARTICLE *p_article;
1192     ARTICLE *p_next;
1193     int32_t page;
1194     int32_t offset;
1195     int32_t move_article_count;
1196     int32_t dest_article_count_old;
1197     int32_t last_unaffected_aid_src;
1198 sysadm 1.12 int32_t first_inserted_aid_dest;
1199     int move_counter;
1200 sysadm 1.11
1201 sysadm 1.28 if (p_section_src == NULL || p_section_dest == NULL)
1202 sysadm 1.11 {
1203     log_error("section_list_move_topic() NULL pointer error\n");
1204     return -1;
1205     }
1206    
1207 sysadm 1.28 if (p_section_src->sid == p_section_dest->sid)
1208     {
1209     log_error("section_list_move_topic() src and dest section are the same\n");
1210     return -1;
1211     }
1212    
1213 sysadm 1.14 if ((p_article = article_block_find_by_aid(aid)) == NULL)
1214 sysadm 1.11 {
1215 sysadm 1.28 log_error("article_block_find_by_aid(aid = %d) error: article not found\n", aid);
1216 sysadm 1.14 return -2;
1217     }
1218    
1219     if (p_section_src->sid != p_article->sid)
1220     {
1221     log_error("section_list_move_topic() error: src section sid %d != article %d sid %d\n",
1222     p_section_src->sid, p_article->aid, p_article->sid);
1223 sysadm 1.11 return -2;
1224     }
1225    
1226     if (p_article->tid != 0)
1227     {
1228     log_error("section_list_move_topic(aid = %d) error: article is not head of topic, tid = %d\n", aid, p_article->tid);
1229     return -2;
1230     }
1231    
1232     last_unaffected_aid_src = (p_article == p_section_src->p_article_head ? 0 : p_article->p_prior->aid);
1233    
1234 sysadm 1.14 move_article_count = article_count_of_topic(aid);
1235 sysadm 1.11 if (move_article_count <= 0)
1236     {
1237 sysadm 1.22 log_error("article_count_of_topic(aid = %d) <= 0\n", aid);
1238 sysadm 1.11 return -2;
1239     }
1240    
1241     if (p_section_dest->article_count + move_article_count > BBS_article_limit_per_section)
1242     {
1243     log_error("section_list_move_topic() error: article_count %d reach limit in section %d\n",
1244     p_section_dest->article_count + move_article_count, p_section_dest->sid);
1245     return -3;
1246     }
1247    
1248     dest_article_count_old = p_section_dest->article_count;
1249 sysadm 1.12 move_counter = 0;
1250     first_inserted_aid_dest = p_article->aid;
1251 sysadm 1.11
1252     do
1253     {
1254 sysadm 1.14 if (p_section_src->sid != p_article->sid)
1255 sysadm 1.11 {
1256 sysadm 1.28 log_error("section_list_move_topic() warning: src section sid %d != article %d sid %d\n",
1257 sysadm 1.14 p_section_src->sid, p_article->aid, p_article->sid);
1258 sysadm 1.28 p_article = p_article->p_topic_next;
1259     continue;
1260 sysadm 1.11 }
1261    
1262     // Remove from bi-directional article list of src section
1263     if (p_section_src->p_article_head == p_article)
1264     {
1265     p_section_src->p_article_head = p_article->p_next;
1266     }
1267     if (p_section_src->p_article_tail == p_article)
1268     {
1269     p_section_src->p_article_tail = p_article->p_prior;
1270     }
1271     if (p_section_src->p_article_head == p_article) // || p_section_src->p_article_tail == p_article
1272     {
1273     p_section_src->p_article_head = NULL;
1274     p_section_src->p_article_tail = NULL;
1275     }
1276    
1277     p_article->p_prior->p_next = p_article->p_next;
1278     p_article->p_next->p_prior = p_article->p_prior;
1279    
1280 sysadm 1.14 // Update sid of article
1281     p_article->sid = p_section_dest->sid;
1282    
1283     if (section_list_find_article_with_offset(p_section_dest, p_article->aid, &page, &offset, &p_next) != NULL)
1284     {
1285 sysadm 1.28 log_error("section_list_move_topic() warning: article %d already in section %d\n", p_article->aid, p_section_dest->sid);
1286     p_article = p_article->p_topic_next;
1287     continue;
1288 sysadm 1.14 }
1289    
1290 sysadm 1.11 // Insert into bi-directional article list of dest section
1291     if (p_next == NULL) // empty section
1292     {
1293     p_section_dest->p_article_head = p_article;
1294     p_section_dest->p_article_tail = p_article;
1295     p_article->p_prior = p_article;
1296     p_article->p_next = p_article;
1297     }
1298     else
1299     {
1300     if (p_section_dest->p_article_head == p_next)
1301     {
1302     if (p_article->aid < p_next->aid)
1303     {
1304     p_section_dest->p_article_head = p_article;
1305     }
1306     else // p_article->aid > p_next->aid
1307     {
1308     p_section_dest->p_article_tail = p_article;
1309     }
1310     }
1311    
1312     p_article->p_prior = p_next->p_prior;
1313     p_article->p_next = p_next;
1314     p_next->p_prior->p_next = p_article;
1315     p_next->p_prior = p_article;
1316     }
1317    
1318     // Update article / topic counter of src / desc section
1319     p_section_src->article_count--;
1320     p_section_dest->article_count++;
1321     if (p_article->tid == 0)
1322     {
1323     p_section_src->topic_count--;
1324     p_section_dest->topic_count++;
1325     }
1326    
1327     // Update visible article / topic counter of src / desc section
1328     if (p_article->visible)
1329     {
1330     p_section_src->visible_article_count--;
1331     p_section_dest->visible_article_count++;
1332     if (p_article->tid == 0)
1333     {
1334     p_section_src->visible_topic_count--;
1335     p_section_dest->visible_topic_count++;
1336     }
1337     }
1338    
1339     // Update page for empty dest section
1340     if (p_section_dest->article_count == 1)
1341     {
1342     p_section_dest->p_page_first_article[0] = p_article;
1343     p_section_dest->page_count = 1;
1344     p_section_dest->last_page_visible_article_count = (p_article->visible ? 1 : 0);
1345     }
1346    
1347     p_article = p_article->p_topic_next;
1348 sysadm 1.12
1349     move_counter++;
1350     if (move_counter % CALCULATE_PAGE_THRESHOLD == 0)
1351     {
1352     // Re-calculate pages of desc section
1353     if (section_list_calculate_page(p_section_dest, first_inserted_aid_dest) < 0)
1354     {
1355 sysadm 1.14 log_error("section_list_calculate_page(dest section = %d, aid = %d) error\n",
1356 sysadm 1.12 p_section_dest->sid, first_inserted_aid_dest);
1357     }
1358    
1359     first_inserted_aid_dest = p_article->aid;
1360     }
1361 sysadm 1.11 } while (p_article->aid != aid);
1362    
1363     if (p_section_dest->article_count - dest_article_count_old != move_article_count)
1364     {
1365 sysadm 1.28 log_error("section_list_move_topic() warning: count of moved articles %d != %d\n",
1366 sysadm 1.11 p_section_dest->article_count - dest_article_count_old, move_article_count);
1367     }
1368    
1369 sysadm 1.12 // Re-calculate pages of src section
1370 sysadm 1.11 if (section_list_calculate_page(p_section_src, last_unaffected_aid_src) < 0)
1371     {
1372 sysadm 1.14 log_error("section_list_calculate_page(src section = %d, aid = %d) error at aid = %d\n",
1373 sysadm 1.12 p_section_src->sid, last_unaffected_aid_src, aid);
1374 sysadm 1.11 }
1375 sysadm 1.12
1376     if (move_counter % CALCULATE_PAGE_THRESHOLD != 0)
1377 sysadm 1.11 {
1378 sysadm 1.12 // Re-calculate pages of desc section
1379     if (section_list_calculate_page(p_section_dest, first_inserted_aid_dest) < 0)
1380     {
1381 sysadm 1.14 log_error("section_list_calculate_page(dest section = %d, aid = %d) error\n",
1382 sysadm 1.12 p_section_dest->sid, first_inserted_aid_dest);
1383     }
1384 sysadm 1.11 }
1385    
1386     return move_article_count;
1387     }
1388 sysadm 1.16
1389     int get_section_index(SECTION_LIST *p_section)
1390     {
1391     int index;
1392    
1393     if (p_section_list_pool == NULL)
1394     {
1395     log_error("get_section_index() error: uninitialized\n");
1396     return -1;
1397     }
1398    
1399     if (p_section == NULL)
1400     {
1401     index = BBS_max_section;
1402     }
1403     else
1404     {
1405 sysadm 1.22 index = (int)(p_section - p_section_list_pool->sections);
1406 sysadm 1.16 if (index < 0 || index >= BBS_max_section)
1407     {
1408     log_error("get_section_index(%d) error: index out of range\n", index);
1409     return -2;
1410     }
1411     }
1412    
1413     return index;
1414     }
1415    
1416     int section_list_try_rd_lock(SECTION_LIST *p_section, int wait_sec)
1417     {
1418     int index;
1419 sysadm 1.17 struct sembuf sops[4];
1420 sysadm 1.16 struct timespec timeout;
1421     int ret;
1422    
1423     index = get_section_index(p_section);
1424     if (index < 0)
1425     {
1426     return -2;
1427     }
1428    
1429 sysadm 1.17 sops[0].sem_num = (unsigned short)(index * 2 + 1); // w_sem of section index
1430     sops[0].sem_op = 0; // wait until unlocked
1431 sysadm 1.16 sops[0].sem_flg = 0;
1432    
1433 sysadm 1.17 sops[1].sem_num = (unsigned short)(index * 2); // r_sem of section index
1434     sops[1].sem_op = 1; // lock
1435     sops[1].sem_flg = SEM_UNDO; // undo on terminate
1436    
1437     // Read lock on any specific section will also acquire single read lock on "all section"
1438     // so that write lock on all section only need to acquire single write on on "all section"
1439     // rather than to acquire multiple write locks on all the available sections.
1440 sysadm 1.21 if (index != BBS_max_section)
1441 sysadm 1.17 {
1442     sops[2].sem_num = BBS_max_section * 2 + 1; // w_sem of all section
1443     sops[2].sem_op = 0; // wait until unlocked
1444     sops[2].sem_flg = 0;
1445    
1446     sops[3].sem_num = BBS_max_section * 2; // r_sem of all section
1447     sops[3].sem_op = 1; // lock
1448     sops[3].sem_flg = SEM_UNDO; // undo on terminate
1449     }
1450 sysadm 1.16
1451     timeout.tv_sec = wait_sec;
1452     timeout.tv_nsec = 0;
1453    
1454 sysadm 1.22 ret = semtimedop(p_section_list_pool->semid, sops, (index == BBS_max_section ? 2 : 4), &timeout);
1455 sysadm 1.17 if (ret == -1 && errno != EAGAIN && errno != EINTR)
1456     {
1457     log_error("semtimedop(index = %d, lock read) error %d\n", index, errno);
1458     }
1459 sysadm 1.16
1460     return ret;
1461     }
1462    
1463     int section_list_try_rw_lock(SECTION_LIST *p_section, int wait_sec)
1464     {
1465     int index;
1466     struct sembuf sops[3];
1467     struct timespec timeout;
1468     int ret;
1469    
1470     index = get_section_index(p_section);
1471     if (index < 0)
1472     {
1473     return -2;
1474     }
1475    
1476 sysadm 1.17 sops[0].sem_num = (unsigned short)(index * 2 + 1); // w_sem of section index
1477     sops[0].sem_op = 0; // wait until unlocked
1478 sysadm 1.16 sops[0].sem_flg = 0;
1479    
1480 sysadm 1.17 sops[1].sem_num = (unsigned short)(index * 2 + 1); // w_sem of section index
1481     sops[1].sem_op = 1; // lock
1482     sops[1].sem_flg = SEM_UNDO; // undo on terminate
1483    
1484     sops[2].sem_num = (unsigned short)(index * 2); // r_sem of section index
1485     sops[2].sem_op = 0; // wait until unlocked
1486     sops[2].sem_flg = 0;
1487 sysadm 1.16
1488     timeout.tv_sec = wait_sec;
1489     timeout.tv_nsec = 0;
1490    
1491 sysadm 1.22 ret = semtimedop(p_section_list_pool->semid, sops, 3, &timeout);
1492 sysadm 1.17 if (ret == -1 && errno != EAGAIN && errno != EINTR)
1493     {
1494     log_error("semtimedop(index = %d, lock write) error %d\n", index, errno);
1495     }
1496 sysadm 1.16
1497     return ret;
1498     }
1499    
1500     int section_list_rd_unlock(SECTION_LIST *p_section)
1501     {
1502     int index;
1503 sysadm 1.17 struct sembuf sops[2];
1504 sysadm 1.16 int ret;
1505    
1506     index = get_section_index(p_section);
1507     if (index < 0)
1508     {
1509     return -2;
1510     }
1511    
1512 sysadm 1.17 sops[0].sem_num = (unsigned short)(index * 2); // r_sem of section index
1513     sops[0].sem_op = -1; // unlock
1514     sops[0].sem_flg = IPC_NOWAIT | SEM_UNDO; // no wait
1515 sysadm 1.16
1516 sysadm 1.21 if (index != BBS_max_section)
1517 sysadm 1.17 {
1518     sops[1].sem_num = BBS_max_section * 2; // r_sem of all section
1519     sops[1].sem_op = -1; // unlock
1520     sops[1].sem_flg = IPC_NOWAIT | SEM_UNDO; // no wait
1521     }
1522    
1523 sysadm 1.22 ret = semop(p_section_list_pool->semid, sops, (index == BBS_max_section ? 1 : 2));
1524 sysadm 1.17 if (ret == -1 && errno != EAGAIN && errno != EINTR)
1525     {
1526     log_error("semop(index = %d, unlock read) error %d\n", index, errno);
1527     }
1528 sysadm 1.16
1529     return ret;
1530     }
1531    
1532     int section_list_rw_unlock(SECTION_LIST *p_section)
1533     {
1534     int index;
1535     struct sembuf sops[1];
1536     int ret;
1537    
1538     index = get_section_index(p_section);
1539     if (index < 0)
1540     {
1541     return -2;
1542     }
1543    
1544 sysadm 1.17 sops[0].sem_num = (unsigned short)(index * 2 + 1); // w_sem of section index
1545     sops[0].sem_op = -1; // unlock
1546     sops[0].sem_flg = IPC_NOWAIT | SEM_UNDO; // no wait
1547 sysadm 1.16
1548 sysadm 1.22 ret = semop(p_section_list_pool->semid, sops, 1);
1549 sysadm 1.17 if (ret == -1 && errno != EAGAIN && errno != EINTR)
1550     {
1551     log_error("semop(index = %d, unlock write) error %d\n", index, errno);
1552     }
1553 sysadm 1.16
1554     return ret;
1555     }
1556 sysadm 1.23
1557     int section_list_rd_lock(SECTION_LIST *p_section)
1558     {
1559     int timer = 0;
1560     int sid = (p_section == NULL ? 0 : p_section->sid);
1561     int ret = -1;
1562    
1563     while (!SYS_server_exit)
1564     {
1565     ret = section_list_try_rd_lock(p_section, SECTION_TRY_LOCK_WAIT_TIME);
1566     if (ret == 0) // success
1567     {
1568     break;
1569     }
1570     else if (errno == EAGAIN || errno == EINTR) // retry
1571     {
1572     timer++;
1573     if (timer % SECTION_TRY_LOCK_TIMES == 0)
1574     {
1575     log_error("section_list_rd_lock() tried %d times on section %d\n", sid, timer);
1576     }
1577     }
1578     else // failed
1579     {
1580     log_error("section_list_rd_lock() failed on section %d\n", sid);
1581     break;
1582     }
1583     }
1584    
1585     return ret;
1586     }
1587    
1588     int section_list_rw_lock(SECTION_LIST *p_section)
1589     {
1590     int timer = 0;
1591     int sid = (p_section == NULL ? 0 : p_section->sid);
1592     int ret = -1;
1593    
1594     while (!SYS_server_exit)
1595     {
1596     ret = section_list_try_rw_lock(p_section, SECTION_TRY_LOCK_WAIT_TIME);
1597     if (ret == 0) // success
1598     {
1599     break;
1600     }
1601     else if (errno == EAGAIN || errno == EINTR) // retry
1602     {
1603     timer++;
1604     if (timer % SECTION_TRY_LOCK_TIMES == 0)
1605     {
1606     log_error("acquire_section_rw_lock() tried %d times on section %d\n", sid, timer);
1607     }
1608     }
1609     else // failed
1610     {
1611     log_error("acquire_section_rw_lock() failed on section %d\n", sid);
1612     break;
1613     }
1614     }
1615    
1616     return ret;
1617     }

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