/[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.33 - (hide annotations)
Fri Jun 20 09:01:16 2025 UTC (8 months, 3 weeks ago) by sysadm
Branch: MAIN
Changes since 1.32: +2 -2 lines
Content type: text/x-csrc
Adjust shm size and count

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

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