/[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.22 - (hide annotations)
Sun May 25 23:47:36 2025 UTC (9 months, 3 weeks ago) by sysadm
Branch: MAIN
Changes since 1.21: +98 -82 lines
Content type: text/x-csrc
Move global variables to SHM

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

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