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

Diff of /lbbs/src/section_list.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

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


Legend:
Removed lines/characters  
Changed lines/characters
  Added lines/characters

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