/[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.24 - (hide annotations)
Mon May 26 04:47:45 2025 UTC (9 months, 3 weeks ago) by sysadm
Branch: MAIN
Changes since 1.23: +14 -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.7 if (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     inline static ARTICLE_BLOCK *pop_free_article_block(void)
240     {
241     ARTICLE_BLOCK *p_block = NULL;
242    
243     if (p_article_block_pool->p_block_free_list != NULL)
244     {
245     p_block = p_article_block_pool->p_block_free_list;
246     p_article_block_pool->p_block_free_list = p_block->p_next_block;
247     p_block->p_next_block = NULL;
248     p_block->article_count = 0;
249     }
250    
251     return p_block;
252     }
253    
254     inline static void push_free_article_block(ARTICLE_BLOCK *p_block)
255 sysadm 1.1 {
256 sysadm 1.7 p_block->p_next_block = p_article_block_pool->p_block_free_list;
257     p_article_block_pool->p_block_free_list = p_block;
258     }
259    
260     int article_block_reset(void)
261     {
262     ARTICLE_BLOCK *p_block;
263    
264     if (p_article_block_pool == NULL)
265     {
266     log_error("article_block_pool not initialized\n");
267     return -1;
268     }
269 sysadm 1.1
270 sysadm 1.7 while (p_article_block_pool->block_count > 0)
271 sysadm 1.1 {
272 sysadm 1.7 p_article_block_pool->block_count--;
273     p_block = p_article_block_pool->p_block[p_article_block_pool->block_count];
274     push_free_article_block(p_block);
275 sysadm 1.1 }
276    
277 sysadm 1.7 return 0;
278     }
279    
280     ARTICLE *article_block_find_by_aid(int32_t aid)
281     {
282     ARTICLE_BLOCK *p_block;
283     int left;
284     int right;
285     int mid;
286    
287     if (p_article_block_pool == NULL)
288 sysadm 1.1 {
289 sysadm 1.7 log_error("article_block_pool not initialized\n");
290     return NULL;
291 sysadm 1.1 }
292    
293 sysadm 1.7 if (p_article_block_pool->block_count == 0) // empty
294 sysadm 1.1 {
295 sysadm 1.7 return NULL;
296 sysadm 1.1 }
297    
298 sysadm 1.7 left = 0;
299     right = p_article_block_pool->block_count;
300    
301     // aid in the range [ head aid of blocks[left], tail aid of blocks[right - 1] ]
302     while (left < right - 1)
303 sysadm 1.1 {
304 sysadm 1.7 // get block offset no less than mid value of left and right block offsets
305     mid = (left + right) / 2 + (right - left) % 2;
306    
307     if (mid >= p_article_block_pool->block_count)
308 sysadm 1.1 {
309 sysadm 1.7 log_error("block(mid = %d) is out of boundary\n", mid);
310     return NULL;
311     }
312 sysadm 1.1
313 sysadm 1.7 if (aid < p_article_block_pool->p_block[mid]->articles[0].aid)
314     {
315     right = mid;
316     }
317     else
318     {
319     left = mid;
320 sysadm 1.1 }
321 sysadm 1.7 }
322    
323     p_block = p_article_block_pool->p_block[left];
324    
325     left = 0;
326     right = p_block->article_count - 1;
327    
328     // aid in the range [ aid of articles[left], aid of articles[right] ]
329     while (left < right)
330     {
331     mid = (left + right) / 2;
332 sysadm 1.1
333 sysadm 1.7 if (aid <= p_block->articles[mid].aid)
334     {
335     right = mid;
336     }
337     else
338     {
339     left = mid + 1;
340     }
341 sysadm 1.1 }
342 sysadm 1.7
343     return (p_block->articles + left);
344 sysadm 1.1 }
345    
346 sysadm 1.7 ARTICLE *article_block_find_by_index(int index)
347 sysadm 1.1 {
348 sysadm 1.7 ARTICLE_BLOCK *p_block;
349    
350     if (p_article_block_pool == NULL)
351     {
352     log_error("article_block_pool not initialized\n");
353     return NULL;
354     }
355    
356     if (index < 0 || index / ARTICLE_PER_BLOCK >= p_article_block_pool->block_count)
357     {
358 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);
359 sysadm 1.7 return NULL;
360     }
361    
362     p_block = p_article_block_pool->p_block[index / ARTICLE_PER_BLOCK];
363 sysadm 1.1
364 sysadm 1.7 if (index % ARTICLE_PER_BLOCK >= p_block->article_count)
365 sysadm 1.1 {
366 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);
367 sysadm 1.7 return NULL;
368 sysadm 1.1 }
369    
370 sysadm 1.7 return (p_block->articles + (index % ARTICLE_PER_BLOCK));
371 sysadm 1.1 }
372    
373 sysadm 1.19 extern int section_list_init(const char *filename)
374 sysadm 1.1 {
375 sysadm 1.16 int semid;
376 sysadm 1.13 int shmid;
377     int proj_id;
378     key_t key;
379     size_t size;
380     void *p_shm;
381 sysadm 1.17 union semun arg;
382     int i;
383 sysadm 1.13
384 sysadm 1.22 if (p_section_list_pool != NULL)
385 sysadm 1.13 {
386 sysadm 1.19 section_list_cleanup();
387 sysadm 1.13 }
388 sysadm 1.7
389 sysadm 1.13 proj_id = (int)(time(NULL) % getpid());
390     key = ftok(filename, proj_id);
391     if (key == -1)
392     {
393     log_error("ftok(%s, %d) error (%d)\n", filename, proj_id, errno);
394     return -3;
395     }
396 sysadm 1.1
397 sysadm 1.22 // Allocate shared memory
398     size = sizeof(SECTION_LIST_POOL);
399     shmid = shmget(key, size, IPC_CREAT | IPC_EXCL | 0600);
400     if (shmid == -1)
401     {
402     log_error("shmget(section_list_pool_shm, size = %d) error (%d)\n", size, errno);
403     return -3;
404     }
405     p_shm = shmat(shmid, NULL, 0);
406     if (p_shm == (void *)-1)
407     {
408     log_error("shmat(shmid = %d) error (%d)\n", shmid, errno);
409     return -3;
410     }
411    
412     p_section_list_pool = p_shm;
413     p_section_list_pool->shmid = shmid;
414     p_section_list_pool->section_count = 0;
415    
416     // Allocate semaphore as section locks
417 sysadm 1.16 size = 2 * (BBS_max_section + 1); // r_sem and w_sem per section, the last pair for all sections
418     semid = semget(key, (int)size, IPC_CREAT | IPC_EXCL | 0600);
419     if (semid == -1)
420     {
421 sysadm 1.17 log_error("semget(section_list_pool_sem, size = %d) error (%d)\n", size, errno);
422 sysadm 1.16 return -3;
423     }
424    
425 sysadm 1.17 // Initialize sem value to 0
426     arg.val = 0;
427     for (i = 0; i < size; i++)
428     {
429     if (semctl(semid, i, SETVAL, arg) == -1)
430     {
431     log_error("semctl(section_list_pool_sem, SETVAL) error (%d)\n", errno);
432     return -3;
433     }
434     }
435    
436 sysadm 1.22 p_section_list_pool->semid = semid;
437 sysadm 1.16
438 sysadm 1.22 p_section_list_pool->p_trie_dict_section_by_name = trie_dict_create();
439     if (p_section_list_pool->p_trie_dict_section_by_name == NULL)
440 sysadm 1.14 {
441     log_error("trie_dict_create() OOM\n", BBS_max_section);
442     return -2;
443     }
444    
445 sysadm 1.22 p_section_list_pool->p_trie_dict_section_by_sid = trie_dict_create();
446     if (p_section_list_pool->p_trie_dict_section_by_sid == NULL)
447 sysadm 1.1 {
448 sysadm 1.13 log_error("trie_dict_create() OOM\n", BBS_max_section);
449     return -2;
450     }
451    
452     return 0;
453     }
454    
455 sysadm 1.14 inline static void sid_to_str(int32_t sid, char *p_sid_str)
456     {
457     uint32_t u_sid;
458     int i;
459    
460     u_sid = (uint32_t)sid;
461     for (i = 0; i < SID_STR_LEN - 1; i++)
462     {
463     p_sid_str[i] = (char)(u_sid % 255 + 1);
464     u_sid /= 255;
465     }
466     p_sid_str[i] = '\0';
467     }
468    
469 sysadm 1.13 SECTION_LIST *section_list_create(int32_t sid, const char *sname, const char *stitle, const char *master_name)
470     {
471     SECTION_LIST *p_section;
472 sysadm 1.14 char sid_str[SID_STR_LEN];
473 sysadm 1.13
474 sysadm 1.22 if (p_section_list_pool == NULL)
475 sysadm 1.13 {
476     log_error("session_list_pool not initialized\n");
477     return NULL;
478 sysadm 1.1 }
479    
480 sysadm 1.22 if (p_section_list_pool->section_count >= BBS_max_section)
481 sysadm 1.1 {
482 sysadm 1.22 log_error("section_count reach limit %d >= %d\n", p_section_list_pool->section_count, BBS_max_section);
483 sysadm 1.1 return NULL;
484     }
485    
486 sysadm 1.14 sid_to_str(sid, sid_str);
487    
488 sysadm 1.22 p_section = p_section_list_pool->sections + p_section_list_pool->section_count;
489 sysadm 1.1
490 sysadm 1.11 p_section->sid = sid;
491    
492 sysadm 1.1 strncpy(p_section->sname, sname, sizeof(p_section->sname - 1));
493     p_section->sname[sizeof(p_section->sname - 1)] = '\0';
494    
495     strncpy(p_section->stitle, stitle, sizeof(p_section->stitle - 1));
496     p_section->stitle[sizeof(p_section->stitle - 1)] = '\0';
497    
498     strncpy(p_section->master_name, master_name, sizeof(p_section->master_name - 1));
499     p_section->master_name[sizeof(p_section->master_name - 1)] = '\0';
500    
501 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)
502 sysadm 1.14 {
503 sysadm 1.22 log_error("trie_dict_set(section, %s, %d) error\n", sname, p_section_list_pool->section_count);
504 sysadm 1.14 return NULL;
505     }
506    
507 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)
508 sysadm 1.1 {
509 sysadm 1.22 log_error("trie_dict_set(section, %d, %d) error\n", sid, p_section_list_pool->section_count);
510 sysadm 1.1 return NULL;
511     }
512    
513 sysadm 1.7 section_list_reset_articles(p_section);
514    
515 sysadm 1.22 p_section_list_pool->section_count++;
516 sysadm 1.1
517     return p_section;
518     }
519    
520 sysadm 1.7 void section_list_reset_articles(SECTION_LIST *p_section)
521 sysadm 1.1 {
522 sysadm 1.7 p_section->article_count = 0;
523 sysadm 1.8 p_section->topic_count = 0;
524     p_section->visible_article_count = 0;
525     p_section->visible_topic_count = 0;
526 sysadm 1.7 p_section->p_article_head = NULL;
527     p_section->p_article_tail = NULL;
528 sysadm 1.1
529 sysadm 1.7 p_section->page_count = 0;
530 sysadm 1.8 p_section->last_page_visible_article_count = 0;
531 sysadm 1.7 }
532 sysadm 1.1
533 sysadm 1.19 void section_list_cleanup(void)
534 sysadm 1.7 {
535 sysadm 1.22 int shmid;
536    
537     if (p_section_list_pool == NULL)
538     {
539     return;
540     }
541    
542     if (p_section_list_pool->p_trie_dict_section_by_name != NULL)
543 sysadm 1.1 {
544 sysadm 1.22 trie_dict_destroy(p_section_list_pool->p_trie_dict_section_by_name);
545     p_section_list_pool->p_trie_dict_section_by_name = NULL;
546 sysadm 1.14 }
547    
548 sysadm 1.22 if (p_section_list_pool->p_trie_dict_section_by_sid != NULL)
549 sysadm 1.14 {
550 sysadm 1.22 trie_dict_destroy(p_section_list_pool->p_trie_dict_section_by_sid);
551     p_section_list_pool->p_trie_dict_section_by_sid = NULL;
552 sysadm 1.1 }
553    
554 sysadm 1.7 if (p_section_list_pool != NULL)
555 sysadm 1.1 {
556 sysadm 1.22 if (semctl(p_section_list_pool->semid, 0, IPC_RMID) == -1)
557 sysadm 1.13 {
558 sysadm 1.22 log_error("semctl(semid = %d, IPC_RMID) error (%d)\n", p_section_list_pool->semid, errno);
559 sysadm 1.13 }
560    
561 sysadm 1.22 shmid = p_section_list_pool->shmid;
562    
563     if (shmdt(p_section_list_pool) == -1)
564 sysadm 1.13 {
565 sysadm 1.22 log_error("shmdt(shmid = %d) error (%d)\n", shmid, errno);
566 sysadm 1.13 }
567 sysadm 1.16
568 sysadm 1.22 if (shmctl(shmid, IPC_RMID, NULL) == -1)
569 sysadm 1.16 {
570 sysadm 1.22 log_error("shmctl(shmid = %d, IPC_RMID) error (%d)\n", shmid, errno);
571 sysadm 1.16 }
572 sysadm 1.22
573     p_section_list_pool = NULL;
574 sysadm 1.1 }
575     }
576    
577 sysadm 1.7 SECTION_LIST *section_list_find_by_name(const char *sname)
578 sysadm 1.1 {
579     int64_t index;
580 sysadm 1.24 int ret;
581 sysadm 1.1
582 sysadm 1.22 if (p_section_list_pool == NULL)
583 sysadm 1.14 {
584     log_error("section_list not initialized\n");
585     return NULL;
586     }
587    
588 sysadm 1.24 ret = trie_dict_get(p_section_list_pool->p_trie_dict_section_by_name, sname, &index);
589     if (ret < 0)
590 sysadm 1.14 {
591     log_error("trie_dict_get(section, %s) error\n", sname);
592     return NULL;
593     }
594 sysadm 1.24 else if (ret == 0)
595     {
596     return NULL;
597     }
598 sysadm 1.14
599 sysadm 1.22 return (p_section_list_pool->sections + index);
600 sysadm 1.14 }
601    
602     SECTION_LIST *section_list_find_by_sid(int32_t sid)
603     {
604     int64_t index;
605 sysadm 1.24 int ret;
606 sysadm 1.14 char sid_str[SID_STR_LEN];
607    
608 sysadm 1.22 if (p_section_list_pool == NULL)
609 sysadm 1.1 {
610 sysadm 1.7 log_error("section_list not initialized\n");
611 sysadm 1.1 return NULL;
612     }
613    
614 sysadm 1.14 sid_to_str(sid, sid_str);
615    
616 sysadm 1.24 ret = trie_dict_get(p_section_list_pool->p_trie_dict_section_by_sid, sid_str, &index);
617     if (ret < 0)
618 sysadm 1.1 {
619 sysadm 1.14 log_error("trie_dict_get(section, %d) error\n", sid);
620 sysadm 1.1 return NULL;
621     }
622 sysadm 1.24 else if (ret == 0)
623     {
624     return NULL;
625     }
626 sysadm 1.1
627 sysadm 1.22 return (p_section_list_pool->sections + index);
628 sysadm 1.1 }
629    
630 sysadm 1.7 int section_list_append_article(SECTION_LIST *p_section, const ARTICLE *p_article_src)
631 sysadm 1.1 {
632     ARTICLE_BLOCK *p_block;
633     int32_t last_aid = 0;
634 sysadm 1.6 ARTICLE *p_article;
635 sysadm 1.1 ARTICLE *p_topic_head;
636     ARTICLE *p_topic_tail;
637    
638 sysadm 1.6 if (p_section == NULL || p_article_src == NULL)
639 sysadm 1.1 {
640 sysadm 1.7 log_error("section_list_append_article() NULL pointer error\n");
641 sysadm 1.1 return -1;
642     }
643    
644 sysadm 1.7 if (p_article_block_pool == NULL)
645 sysadm 1.1 {
646 sysadm 1.7 log_error("article_block_pool not initialized\n");
647 sysadm 1.1 return -1;
648     }
649    
650 sysadm 1.14 if (p_section->sid != p_article_src->sid)
651     {
652     log_error("section_list_append_article() error: section sid %d != article sid %d\n", p_section->sid, p_article_src->sid);
653     return -2;
654     }
655    
656 sysadm 1.9 if (p_section->article_count >= BBS_article_limit_per_section)
657     {
658     log_error("section_list_append_article() error: article_count reach limit in section %d\n", p_section->sid);
659     return -2;
660     }
661    
662 sysadm 1.7 if (p_article_block_pool->block_count == 0 ||
663     p_article_block_pool->p_block[p_article_block_pool->block_count - 1]->article_count >= ARTICLE_PER_BLOCK)
664 sysadm 1.1 {
665     if ((p_block = pop_free_article_block()) == NULL)
666     {
667     log_error("pop_free_article_block() error\n");
668     return -2;
669     }
670    
671 sysadm 1.7 if (p_article_block_pool->block_count > 0)
672 sysadm 1.1 {
673 sysadm 1.7 last_aid = p_article_block_pool->p_block[p_article_block_pool->block_count - 1]->articles[ARTICLE_PER_BLOCK - 1].aid;
674 sysadm 1.1 }
675 sysadm 1.7
676     p_article_block_pool->p_block[p_article_block_pool->block_count] = p_block;
677     p_article_block_pool->block_count++;
678 sysadm 1.1 }
679     else
680     {
681 sysadm 1.7 p_block = p_article_block_pool->p_block[p_article_block_pool->block_count - 1];
682     last_aid = p_block->articles[p_block->article_count - 1].aid;
683 sysadm 1.1 }
684    
685     // AID of articles should be strictly ascending
686 sysadm 1.6 if (p_article_src->aid <= last_aid)
687 sysadm 1.1 {
688 sysadm 1.14 log_error("section_list_append_article(aid=%d) error: last_aid=%d\n", p_article_src->aid, last_aid);
689 sysadm 1.1 return -3;
690     }
691    
692 sysadm 1.7 p_article = (p_block->articles + p_block->article_count);
693     p_block->article_count++;
694     p_section->article_count++;
695    
696     // Copy article data
697     *p_article = *p_article_src;
698 sysadm 1.1
699 sysadm 1.8 if (p_article->visible)
700     {
701     p_section->visible_article_count++;
702     }
703    
704 sysadm 1.7 // Link appended article as tail node of topic bi-directional list
705     if (p_article->tid != 0)
706 sysadm 1.1 {
707 sysadm 1.7 p_topic_head = article_block_find_by_aid(p_article->tid);
708 sysadm 1.1 if (p_topic_head == NULL)
709     {
710 sysadm 1.7 log_error("search head of topic (aid=%d) error\n", p_article->tid);
711 sysadm 1.1 return -4;
712     }
713    
714 sysadm 1.6 p_topic_tail = p_topic_head->p_topic_prior;
715 sysadm 1.1 if (p_topic_tail == NULL)
716     {
717 sysadm 1.7 log_error("tail of topic (aid=%d) is NULL\n", p_article->tid);
718 sysadm 1.1 return -4;
719     }
720     }
721     else
722     {
723 sysadm 1.8 p_section->topic_count++;
724    
725     if (p_article->visible)
726     {
727     p_section->visible_topic_count++;
728     }
729    
730 sysadm 1.7 p_topic_head = p_article;
731     p_topic_tail = p_article;
732 sysadm 1.1 }
733    
734 sysadm 1.7 p_article->p_topic_prior = p_topic_tail;
735     p_article->p_topic_next = p_topic_head;
736     p_topic_head->p_topic_prior = p_article;
737     p_topic_tail->p_topic_next = p_article;
738 sysadm 1.1
739 sysadm 1.6 // Link appended article as tail node of article bi-directional list
740     if (p_section->p_article_head == NULL)
741     {
742     p_section->p_article_head = p_article;
743     p_section->p_article_tail = p_article;
744     }
745     p_article->p_prior = p_section->p_article_tail;
746     p_article->p_next = p_section->p_article_head;
747     p_section->p_article_head->p_prior = p_article;
748     p_section->p_article_tail->p_next = p_article;
749     p_section->p_article_tail = p_article;
750    
751 sysadm 1.7 // Update page
752 sysadm 1.11 if ((p_article->visible && p_section->last_page_visible_article_count % BBS_article_limit_per_page == 0) ||
753     p_section->article_count == 1)
754 sysadm 1.1 {
755 sysadm 1.7 p_section->p_page_first_article[p_section->page_count] = p_article;
756     p_section->page_count++;
757 sysadm 1.8 p_section->last_page_visible_article_count = 0;
758 sysadm 1.1 }
759 sysadm 1.9
760     if (p_article->visible)
761     {
762     p_section->last_page_visible_article_count++;
763     }
764 sysadm 1.1
765 sysadm 1.7 return 0;
766 sysadm 1.2 }
767    
768 sysadm 1.7 int section_list_set_article_visible(SECTION_LIST *p_section, int32_t aid, int8_t visible)
769 sysadm 1.1 {
770     ARTICLE *p_article;
771 sysadm 1.8 ARTICLE *p_reply;
772     int affected_count = 0;
773 sysadm 1.1
774 sysadm 1.2 if (p_section == NULL)
775     {
776 sysadm 1.7 log_error("section_list_set_article_visible() NULL pointer error\n");
777 sysadm 1.2 return -2;
778     }
779    
780 sysadm 1.7 p_article = article_block_find_by_aid(aid);
781 sysadm 1.1 if (p_article == NULL)
782     {
783     return -1; // Not found
784     }
785    
786 sysadm 1.14 if (p_section->sid != p_article->sid)
787     {
788     log_error("section_list_set_article_visible() error: section sid %d != article sid %d\n", p_section->sid, p_article->sid);
789     return -2;
790     }
791    
792 sysadm 1.7 if (p_article->visible == visible)
793 sysadm 1.1 {
794 sysadm 1.7 return 0; // Already set
795 sysadm 1.1 }
796    
797 sysadm 1.8 if (visible == 0) // 1 -> 0
798     {
799     p_section->visible_article_count--;
800    
801     if (p_article->tid == 0)
802     {
803     p_section->visible_topic_count--;
804    
805     // Set related visible replies to invisible
806     for (p_reply = p_article->p_topic_next; p_reply->tid != 0; p_reply = p_reply->p_topic_next)
807     {
808     if (p_reply->tid != aid)
809     {
810     log_error("Inconsistent tid = %d found in reply %d of topic %d\n", p_reply->tid, p_reply->aid, aid);
811     continue;
812     }
813    
814     if (p_reply->visible == 1)
815     {
816     p_reply->visible = 0;
817     p_section->visible_article_count--;
818     affected_count++;
819     }
820     }
821     }
822     }
823     else // 0 -> 1
824     {
825     p_section->visible_article_count++;
826    
827     if (p_article->tid == 0)
828     {
829     p_section->visible_topic_count++;
830     }
831     }
832    
833 sysadm 1.7 p_article->visible = visible;
834 sysadm 1.8 affected_count++;
835    
836     return affected_count;
837     }
838    
839 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)
840 sysadm 1.8 {
841     ARTICLE *p_article;
842     int left;
843     int right;
844     int mid;
845    
846     *p_page = -1;
847     *p_offset = -1;
848 sysadm 1.11 *pp_next = NULL;
849 sysadm 1.8
850     if (p_section == NULL)
851     {
852     log_error("section_list_find_article_with_offset() NULL pointer error\n");
853     return NULL;
854     }
855 sysadm 1.7
856 sysadm 1.8 if (p_section->article_count == 0) // empty
857     {
858     *p_page = 0;
859     *p_offset = 0;
860     return NULL;
861     }
862    
863     left = 0;
864     right = p_section->page_count;
865    
866     // aid in the range [ head aid of pages[left], tail aid of pages[right - 1] ]
867     while (left < right - 1)
868     {
869     // get page id no less than mid value of left page id and right page id
870     mid = (left + right) / 2 + (right - left) % 2;
871 sysadm 1.1
872 sysadm 1.8 if (mid >= p_section->page_count)
873     {
874     log_error("page id (mid = %d) is out of boundary\n", mid);
875     return NULL;
876     }
877    
878     if (aid < p_section->p_page_first_article[mid]->aid)
879     {
880     right = mid;
881     }
882     else
883     {
884     left = mid;
885     }
886     }
887    
888     *p_page = left;
889    
890     p_article = p_section->p_page_first_article[*p_page];
891    
892     // p_section->p_page_first_article[*p_page]->aid <= aid < p_section->p_page_first_article[*p_page + 1]->aid
893 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);
894 sysadm 1.8
895     // left will be the offset of article found or offset to insert
896     left = 0;
897    
898 sysadm 1.10 while (aid > p_article->aid)
899 sysadm 1.8 {
900     p_article = p_article->p_next;
901     left++;
902    
903 sysadm 1.11 if (aid == p_article->aid)
904     {
905     *pp_next = p_article->p_next;
906     break;
907     }
908    
909 sysadm 1.8 // over last article in the page
910     if (p_article == p_section->p_article_head || p_article->aid >= right)
911     {
912 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]);
913     *p_offset = left;
914     return NULL; // not found
915 sysadm 1.8 }
916     }
917    
918 sysadm 1.11 if (aid < p_article->aid)
919     {
920     *pp_next = p_article;
921     p_article = NULL; // not found
922     }
923     else // aid == p_article->aid
924 sysadm 1.10 {
925 sysadm 1.11 *pp_next = p_article->p_next;
926 sysadm 1.10 }
927    
928 sysadm 1.8 *p_offset = left;
929    
930     return p_article;
931     }
932    
933     int section_list_calculate_page(SECTION_LIST *p_section, int32_t start_aid)
934     {
935 sysadm 1.9 ARTICLE *p_article;
936 sysadm 1.11 ARTICLE *p_next;
937 sysadm 1.9 int32_t page;
938     int32_t offset;
939     int visible_article_count;
940     int page_head_set;
941 sysadm 1.8
942     if (p_section == NULL)
943     {
944     log_error("section_list_calculate_page() NULL pointer error\n");
945     return -1;
946     }
947    
948 sysadm 1.11 if (p_section->article_count == 0) // empty
949     {
950     p_section->page_count = 0;
951     p_section->last_page_visible_article_count = 0;
952    
953     return 0;
954     }
955    
956     if (start_aid > 0)
957 sysadm 1.9 {
958 sysadm 1.14 p_article = article_block_find_by_aid(start_aid);
959     if (p_article == NULL)
960     {
961     return -1; // Not found
962     }
963    
964     if (p_section->sid != p_article->sid)
965     {
966     log_error("section_list_calculate_page() error: section sid %d != start article sid %d\n", p_section->sid, p_article->sid);
967     return -2;
968     }
969    
970 sysadm 1.11 p_article = section_list_find_article_with_offset(p_section, start_aid, &page, &offset, &p_next);
971     if (p_article == NULL)
972 sysadm 1.9 {
973 sysadm 1.11 if (page < 0)
974     {
975     return -1;
976     }
977     log_error("section_list_calculate_page() aid = %d not found in section sid = %d\n",
978     start_aid, p_section->sid);
979     return -2;
980 sysadm 1.9 }
981    
982 sysadm 1.11 if (offset > 0)
983     {
984     p_article = p_section->p_page_first_article[page];
985     }
986 sysadm 1.9 }
987 sysadm 1.11 else
988 sysadm 1.9 {
989 sysadm 1.11 p_article = p_section->p_article_head;
990     page = 0;
991     offset = 0;
992 sysadm 1.9 }
993    
994     visible_article_count = 0;
995     page_head_set = 0;
996    
997     do
998     {
999     if (!page_head_set && visible_article_count == 0)
1000     {
1001     p_section->p_page_first_article[page] = p_article;
1002     page_head_set = 1;
1003     }
1004    
1005     if (p_article->visible)
1006     {
1007     visible_article_count++;
1008     }
1009    
1010     p_article = p_article->p_next;
1011    
1012     // skip remaining invisible articles
1013     while (p_article->visible == 0 && p_article != p_section->p_article_head)
1014     {
1015     p_article = p_article->p_next;
1016     }
1017    
1018     if (visible_article_count >= BBS_article_limit_per_page && p_article != p_section->p_article_head)
1019     {
1020     page++;
1021     visible_article_count = 0;
1022     page_head_set = 0;
1023    
1024     if (page >= BBS_article_limit_per_section / BBS_article_limit_per_page && p_article != p_section->p_article_head)
1025     {
1026     log_error("Count of page exceed limit in section %d\n", p_section->sid);
1027     break;
1028     }
1029     }
1030     } while (p_article != p_section->p_article_head);
1031    
1032     p_section->page_count = page + (visible_article_count > 0 ? 1 : 0);
1033     p_section->last_page_visible_article_count = visible_article_count;
1034    
1035 sysadm 1.8 return 0;
1036 sysadm 1.1 }
1037 sysadm 1.11
1038 sysadm 1.14 int article_count_of_topic(int32_t aid)
1039 sysadm 1.11 {
1040     ARTICLE *p_article;
1041     int article_count;
1042    
1043     p_article = article_block_find_by_aid(aid);
1044     if (p_article == NULL)
1045     {
1046     return 0; // Not found
1047     }
1048    
1049     article_count = 0;
1050    
1051     do
1052     {
1053 sysadm 1.15 if (p_article->tid != 0 && p_article->tid != aid)
1054     {
1055     log_error("article_count_of_topic(%d) error: article %d not linked to the topic\n", aid, p_article->aid);
1056     break;
1057     }
1058    
1059 sysadm 1.11 article_count++;
1060     p_article = p_article->p_topic_next;
1061     } while (p_article->aid != aid);
1062    
1063     return article_count;
1064     }
1065    
1066     int section_list_move_topic(SECTION_LIST *p_section_src, SECTION_LIST *p_section_dest, int32_t aid)
1067     {
1068     ARTICLE *p_article;
1069     ARTICLE *p_next;
1070     int32_t page;
1071     int32_t offset;
1072     int32_t move_article_count;
1073     int32_t dest_article_count_old;
1074     int32_t last_unaffected_aid_src;
1075 sysadm 1.12 int32_t first_inserted_aid_dest;
1076     int move_counter;
1077 sysadm 1.11
1078     if (p_section_dest == NULL)
1079     {
1080     log_error("section_list_move_topic() NULL pointer error\n");
1081     return -1;
1082     }
1083    
1084 sysadm 1.14 if ((p_article = article_block_find_by_aid(aid)) == NULL)
1085 sysadm 1.11 {
1086 sysadm 1.14 log_error("section_list_move_topic() error: article %d not found in block\n", aid);
1087     return -2;
1088     }
1089    
1090     if (p_section_src->sid != p_article->sid)
1091     {
1092     log_error("section_list_move_topic() error: src section sid %d != article %d sid %d\n",
1093     p_section_src->sid, p_article->aid, p_article->sid);
1094 sysadm 1.11 return -2;
1095     }
1096    
1097     if (p_article->tid != 0)
1098     {
1099     log_error("section_list_move_topic(aid = %d) error: article is not head of topic, tid = %d\n", aid, p_article->tid);
1100     return -2;
1101     }
1102    
1103     last_unaffected_aid_src = (p_article == p_section_src->p_article_head ? 0 : p_article->p_prior->aid);
1104    
1105 sysadm 1.14 move_article_count = article_count_of_topic(aid);
1106 sysadm 1.11 if (move_article_count <= 0)
1107     {
1108 sysadm 1.22 log_error("article_count_of_topic(aid = %d) <= 0\n", aid);
1109 sysadm 1.11 return -2;
1110     }
1111    
1112     if (p_section_dest->article_count + move_article_count > BBS_article_limit_per_section)
1113     {
1114     log_error("section_list_move_topic() error: article_count %d reach limit in section %d\n",
1115     p_section_dest->article_count + move_article_count, p_section_dest->sid);
1116     return -3;
1117     }
1118    
1119     dest_article_count_old = p_section_dest->article_count;
1120 sysadm 1.12 move_counter = 0;
1121     first_inserted_aid_dest = p_article->aid;
1122 sysadm 1.11
1123     do
1124     {
1125 sysadm 1.14 if (p_section_src->sid != p_article->sid)
1126 sysadm 1.11 {
1127 sysadm 1.14 log_error("section_list_move_topic() error: src section sid %d != article %d sid %d\n",
1128     p_section_src->sid, p_article->aid, p_article->sid);
1129     return -2;
1130 sysadm 1.11 }
1131    
1132     // Remove from bi-directional article list of src section
1133     if (p_section_src->p_article_head == p_article)
1134     {
1135     p_section_src->p_article_head = p_article->p_next;
1136     }
1137     if (p_section_src->p_article_tail == p_article)
1138     {
1139     p_section_src->p_article_tail = p_article->p_prior;
1140     }
1141     if (p_section_src->p_article_head == p_article) // || p_section_src->p_article_tail == p_article
1142     {
1143     p_section_src->p_article_head = NULL;
1144     p_section_src->p_article_tail = NULL;
1145     }
1146    
1147     p_article->p_prior->p_next = p_article->p_next;
1148     p_article->p_next->p_prior = p_article->p_prior;
1149    
1150 sysadm 1.14 // Update sid of article
1151     p_article->sid = p_section_dest->sid;
1152    
1153     if (section_list_find_article_with_offset(p_section_dest, p_article->aid, &page, &offset, &p_next) != NULL)
1154     {
1155     log_error("section_list_move_topic() error: article %d already in section %d\n", p_article->aid, p_section_dest->sid);
1156     return -4;
1157     }
1158    
1159 sysadm 1.11 // Insert into bi-directional article list of dest section
1160     if (p_next == NULL) // empty section
1161     {
1162     p_section_dest->p_article_head = p_article;
1163     p_section_dest->p_article_tail = p_article;
1164     p_article->p_prior = p_article;
1165     p_article->p_next = p_article;
1166     }
1167     else
1168     {
1169     if (p_section_dest->p_article_head == p_next)
1170     {
1171     if (p_article->aid < p_next->aid)
1172     {
1173     p_section_dest->p_article_head = p_article;
1174     }
1175     else // p_article->aid > p_next->aid
1176     {
1177     p_section_dest->p_article_tail = p_article;
1178     }
1179     }
1180    
1181     p_article->p_prior = p_next->p_prior;
1182     p_article->p_next = p_next;
1183     p_next->p_prior->p_next = p_article;
1184     p_next->p_prior = p_article;
1185     }
1186    
1187     // Update article / topic counter of src / desc section
1188     p_section_src->article_count--;
1189     p_section_dest->article_count++;
1190     if (p_article->tid == 0)
1191     {
1192     p_section_src->topic_count--;
1193     p_section_dest->topic_count++;
1194     }
1195    
1196     // Update visible article / topic counter of src / desc section
1197     if (p_article->visible)
1198     {
1199     p_section_src->visible_article_count--;
1200     p_section_dest->visible_article_count++;
1201     if (p_article->tid == 0)
1202     {
1203     p_section_src->visible_topic_count--;
1204     p_section_dest->visible_topic_count++;
1205     }
1206     }
1207    
1208     // Update page for empty dest section
1209     if (p_section_dest->article_count == 1)
1210     {
1211     p_section_dest->p_page_first_article[0] = p_article;
1212     p_section_dest->page_count = 1;
1213     p_section_dest->last_page_visible_article_count = (p_article->visible ? 1 : 0);
1214     }
1215    
1216     p_article = p_article->p_topic_next;
1217 sysadm 1.12
1218     move_counter++;
1219     if (move_counter % CALCULATE_PAGE_THRESHOLD == 0)
1220     {
1221     // Re-calculate pages of desc section
1222     if (section_list_calculate_page(p_section_dest, first_inserted_aid_dest) < 0)
1223     {
1224 sysadm 1.14 log_error("section_list_calculate_page(dest section = %d, aid = %d) error\n",
1225 sysadm 1.12 p_section_dest->sid, first_inserted_aid_dest);
1226     }
1227    
1228     first_inserted_aid_dest = p_article->aid;
1229     }
1230 sysadm 1.11 } while (p_article->aid != aid);
1231    
1232     if (p_section_dest->article_count - dest_article_count_old != move_article_count)
1233     {
1234     log_error("section_list_move_topic() error: count of moved articles %d != %d\n",
1235     p_section_dest->article_count - dest_article_count_old, move_article_count);
1236     }
1237    
1238 sysadm 1.12 // Re-calculate pages of src section
1239 sysadm 1.11 if (section_list_calculate_page(p_section_src, last_unaffected_aid_src) < 0)
1240     {
1241 sysadm 1.14 log_error("section_list_calculate_page(src section = %d, aid = %d) error at aid = %d\n",
1242 sysadm 1.12 p_section_src->sid, last_unaffected_aid_src, aid);
1243 sysadm 1.11 }
1244 sysadm 1.12
1245     if (move_counter % CALCULATE_PAGE_THRESHOLD != 0)
1246 sysadm 1.11 {
1247 sysadm 1.12 // Re-calculate pages of desc section
1248     if (section_list_calculate_page(p_section_dest, first_inserted_aid_dest) < 0)
1249     {
1250 sysadm 1.14 log_error("section_list_calculate_page(dest section = %d, aid = %d) error\n",
1251 sysadm 1.12 p_section_dest->sid, first_inserted_aid_dest);
1252     }
1253 sysadm 1.11 }
1254    
1255     return move_article_count;
1256     }
1257 sysadm 1.16
1258     int get_section_index(SECTION_LIST *p_section)
1259     {
1260     int index;
1261    
1262     if (p_section_list_pool == NULL)
1263     {
1264     log_error("get_section_index() error: uninitialized\n");
1265     return -1;
1266     }
1267    
1268     if (p_section == NULL)
1269     {
1270     index = BBS_max_section;
1271     }
1272     else
1273     {
1274 sysadm 1.22 index = (int)(p_section - p_section_list_pool->sections);
1275 sysadm 1.16 if (index < 0 || index >= BBS_max_section)
1276     {
1277     log_error("get_section_index(%d) error: index out of range\n", index);
1278     return -2;
1279     }
1280     }
1281    
1282     return index;
1283     }
1284    
1285     int section_list_try_rd_lock(SECTION_LIST *p_section, int wait_sec)
1286     {
1287     int index;
1288 sysadm 1.17 struct sembuf sops[4];
1289 sysadm 1.16 struct timespec timeout;
1290     int ret;
1291    
1292     index = get_section_index(p_section);
1293     if (index < 0)
1294     {
1295     return -2;
1296     }
1297    
1298 sysadm 1.17 sops[0].sem_num = (unsigned short)(index * 2 + 1); // w_sem of section index
1299     sops[0].sem_op = 0; // wait until unlocked
1300 sysadm 1.16 sops[0].sem_flg = 0;
1301    
1302 sysadm 1.17 sops[1].sem_num = (unsigned short)(index * 2); // r_sem of section index
1303     sops[1].sem_op = 1; // lock
1304     sops[1].sem_flg = SEM_UNDO; // undo on terminate
1305    
1306     // Read lock on any specific section will also acquire single read lock on "all section"
1307     // so that write lock on all section only need to acquire single write on on "all section"
1308     // rather than to acquire multiple write locks on all the available sections.
1309 sysadm 1.21 if (index != BBS_max_section)
1310 sysadm 1.17 {
1311     sops[2].sem_num = BBS_max_section * 2 + 1; // w_sem of all section
1312     sops[2].sem_op = 0; // wait until unlocked
1313     sops[2].sem_flg = 0;
1314    
1315     sops[3].sem_num = BBS_max_section * 2; // r_sem of all section
1316     sops[3].sem_op = 1; // lock
1317     sops[3].sem_flg = SEM_UNDO; // undo on terminate
1318     }
1319 sysadm 1.16
1320     timeout.tv_sec = wait_sec;
1321     timeout.tv_nsec = 0;
1322    
1323 sysadm 1.22 ret = semtimedop(p_section_list_pool->semid, sops, (index == BBS_max_section ? 2 : 4), &timeout);
1324 sysadm 1.17 if (ret == -1 && errno != EAGAIN && errno != EINTR)
1325     {
1326     log_error("semtimedop(index = %d, lock read) error %d\n", index, errno);
1327     }
1328 sysadm 1.16
1329     return ret;
1330     }
1331    
1332     int section_list_try_rw_lock(SECTION_LIST *p_section, int wait_sec)
1333     {
1334     int index;
1335     struct sembuf sops[3];
1336     struct timespec timeout;
1337     int ret;
1338    
1339     index = get_section_index(p_section);
1340     if (index < 0)
1341     {
1342     return -2;
1343     }
1344    
1345 sysadm 1.17 sops[0].sem_num = (unsigned short)(index * 2 + 1); // w_sem of section index
1346     sops[0].sem_op = 0; // wait until unlocked
1347 sysadm 1.16 sops[0].sem_flg = 0;
1348    
1349 sysadm 1.17 sops[1].sem_num = (unsigned short)(index * 2 + 1); // w_sem of section index
1350     sops[1].sem_op = 1; // lock
1351     sops[1].sem_flg = SEM_UNDO; // undo on terminate
1352    
1353     sops[2].sem_num = (unsigned short)(index * 2); // r_sem of section index
1354     sops[2].sem_op = 0; // wait until unlocked
1355     sops[2].sem_flg = 0;
1356 sysadm 1.16
1357     timeout.tv_sec = wait_sec;
1358     timeout.tv_nsec = 0;
1359    
1360 sysadm 1.22 ret = semtimedop(p_section_list_pool->semid, sops, 3, &timeout);
1361 sysadm 1.17 if (ret == -1 && errno != EAGAIN && errno != EINTR)
1362     {
1363     log_error("semtimedop(index = %d, lock write) error %d\n", index, errno);
1364     }
1365 sysadm 1.16
1366     return ret;
1367     }
1368    
1369     int section_list_rd_unlock(SECTION_LIST *p_section)
1370     {
1371     int index;
1372 sysadm 1.17 struct sembuf sops[2];
1373 sysadm 1.16 int ret;
1374    
1375     index = get_section_index(p_section);
1376     if (index < 0)
1377     {
1378     return -2;
1379     }
1380    
1381 sysadm 1.17 sops[0].sem_num = (unsigned short)(index * 2); // r_sem of section index
1382     sops[0].sem_op = -1; // unlock
1383     sops[0].sem_flg = IPC_NOWAIT | SEM_UNDO; // no wait
1384 sysadm 1.16
1385 sysadm 1.21 if (index != BBS_max_section)
1386 sysadm 1.17 {
1387     sops[1].sem_num = BBS_max_section * 2; // r_sem of all section
1388     sops[1].sem_op = -1; // unlock
1389     sops[1].sem_flg = IPC_NOWAIT | SEM_UNDO; // no wait
1390     }
1391    
1392 sysadm 1.22 ret = semop(p_section_list_pool->semid, sops, (index == BBS_max_section ? 1 : 2));
1393 sysadm 1.17 if (ret == -1 && errno != EAGAIN && errno != EINTR)
1394     {
1395     log_error("semop(index = %d, unlock read) error %d\n", index, errno);
1396     }
1397 sysadm 1.16
1398     return ret;
1399     }
1400    
1401     int section_list_rw_unlock(SECTION_LIST *p_section)
1402     {
1403     int index;
1404     struct sembuf sops[1];
1405     int ret;
1406    
1407     index = get_section_index(p_section);
1408     if (index < 0)
1409     {
1410     return -2;
1411     }
1412    
1413 sysadm 1.17 sops[0].sem_num = (unsigned short)(index * 2 + 1); // w_sem of section index
1414     sops[0].sem_op = -1; // unlock
1415     sops[0].sem_flg = IPC_NOWAIT | SEM_UNDO; // no wait
1416 sysadm 1.16
1417 sysadm 1.22 ret = semop(p_section_list_pool->semid, sops, 1);
1418 sysadm 1.17 if (ret == -1 && errno != EAGAIN && errno != EINTR)
1419     {
1420     log_error("semop(index = %d, unlock write) error %d\n", index, errno);
1421     }
1422 sysadm 1.16
1423     return ret;
1424     }
1425 sysadm 1.23
1426     int section_list_rd_lock(SECTION_LIST *p_section)
1427     {
1428     int timer = 0;
1429     int sid = (p_section == NULL ? 0 : p_section->sid);
1430     int ret = -1;
1431    
1432     while (!SYS_server_exit)
1433     {
1434     ret = section_list_try_rd_lock(p_section, SECTION_TRY_LOCK_WAIT_TIME);
1435     if (ret == 0) // success
1436     {
1437     break;
1438     }
1439     else if (errno == EAGAIN || errno == EINTR) // retry
1440     {
1441     timer++;
1442     if (timer % SECTION_TRY_LOCK_TIMES == 0)
1443     {
1444     log_error("section_list_rd_lock() tried %d times on section %d\n", sid, timer);
1445     }
1446     }
1447     else // failed
1448     {
1449     log_error("section_list_rd_lock() failed on section %d\n", sid);
1450     break;
1451     }
1452     }
1453    
1454     return ret;
1455     }
1456    
1457     int section_list_rw_lock(SECTION_LIST *p_section)
1458     {
1459     int timer = 0;
1460     int sid = (p_section == NULL ? 0 : p_section->sid);
1461     int ret = -1;
1462    
1463     while (!SYS_server_exit)
1464     {
1465     ret = section_list_try_rw_lock(p_section, SECTION_TRY_LOCK_WAIT_TIME);
1466     if (ret == 0) // success
1467     {
1468     break;
1469     }
1470     else if (errno == EAGAIN || errno == EINTR) // retry
1471     {
1472     timer++;
1473     if (timer % SECTION_TRY_LOCK_TIMES == 0)
1474     {
1475     log_error("acquire_section_rw_lock() tried %d times on section %d\n", sid, timer);
1476     }
1477     }
1478     else // failed
1479     {
1480     log_error("acquire_section_rw_lock() failed on section %d\n", sid);
1481     break;
1482     }
1483     }
1484    
1485     return ret;
1486     }

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