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

Diff of /lbbs/src/user_list.c

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

Revision 1.1 by sysadm, Tue Oct 21 06:24:51 2025 UTC Revision 1.23 by sysadm, Sat Nov 1 10:35:42 2025 UTC
# Line 1  Line 1 
1  /***************************************************************************  /***************************************************************************
2                           user_list.c  -  description                                                   user_list.c  -  description
3                               -------------------                                                           -------------------
4      Copyright            : (C) 2004-2025 by Leaflet          Copyright            : (C) 2004-2025 by Leaflet
5      Email                : leaflet@leafok.com          Email                : leaflet@leafok.com
6   ***************************************************************************/   ***************************************************************************/
7    
8  /***************************************************************************  /***************************************************************************
# Line 17  Line 17 
17  #include "common.h"  #include "common.h"
18  #include "database.h"  #include "database.h"
19  #include "log.h"  #include "log.h"
20    #include "trie_dict.h"
21  #include "user_list.h"  #include "user_list.h"
22    #include "user_stat.h"
23  #include <errno.h>  #include <errno.h>
24  #include <stdlib.h>  #include <stdlib.h>
25  #include <string.h>  #include <string.h>
26  #include <time.h>  #include <time.h>
27  #include <sys/ipc.h>  #include <sys/ipc.h>
28  #include <sys/mman.h>  #include <sys/mman.h>
29    #include <sys/param.h>
30  #include <sys/sem.h>  #include <sys/sem.h>
31  #include <sys/shm.h>  #include <sys/shm.h>
32    
33  #ifdef _SEM_SEMUN_UNDEFINED  #ifdef _SEM_SEMUN_UNDEFINED
34  union semun  union semun
35  {  {
36      int val;               /* Value for SETVAL */          int val;                           /* Value for SETVAL */
37      struct semid_ds *buf;  /* Buffer for IPC_STAT, IPC_SET */          struct semid_ds *buf;  /* Buffer for IPC_STAT, IPC_SET */
38      unsigned short *array; /* Array for GETALL, SETALL */          unsigned short *array; /* Array for GETALL, SETALL */
39      struct seminfo *__buf; /* Buffer for IPC_INFO          struct seminfo *__buf; /* Buffer for IPC_INFO
40                                (Linux-specific) */                                                            (Linux-specific) */
41  };  };
42  #endif // #ifdef _SEM_SEMUN_UNDEFINED  #endif // #ifdef _SEM_SEMUN_UNDEFINED
43    
# Line 43  union semun Line 46  union semun
46    
47  struct user_list_pool_t  struct user_list_pool_t
48  {  {
49      int shmid;          int shmid;
50      int semid;          int semid;
51      USER_LIST user_list[2];          USER_LIST user_list[2];
52      USER_LIST *p_current;          USER_LIST *p_current;
53      USER_LIST *p_new;          USER_LIST *p_new;
54            USER_ONLINE_LIST user_online_list[2];
55            USER_ONLINE_LIST *p_online_current;
56            USER_ONLINE_LIST *p_online_new;
57            USER_STAT_MAP user_stat_map;
58  };  };
59  typedef struct user_list_pool_t USER_LIST_POOL;  typedef struct user_list_pool_t USER_LIST_POOL;
60    
61  static USER_LIST_POOL *p_user_list_pool = NULL;  static USER_LIST_POOL *p_user_list_pool = NULL;
62    static TRIE_NODE *p_trie_action_dict = NULL;
63    
64    typedef struct user_action_map_t
65    {
66            char name[BBS_current_action_max_len + 1];
67            char title[BBS_current_action_max_len + 1];
68    } USER_ACTION_MAP;
69    
70    const USER_ACTION_MAP user_action_map[] =
71            {
72                    {"ARTICLE_FAVOR", "浏览收藏"},
73                    {"BBS_NET", "站点穿梭"},
74                    {"CHICKEN", "电子小鸡"},
75                    {"EDIT_ARTICLE", "修改文章"},
76                    {"LOGIN", "进入大厅"},
77                    {"MENU", "菜单选择"},
78                    {"POST_ARTICLE", "撰写文章"},
79                    {"REPLY_ARTICLE", "回复文章"},
80                    {"USER_LIST", "查花名册"},
81                    {"USER_ONLINE", "环顾四周"},
82                    {"VIEW_ARTICLE", "阅读文章"},
83                    {"VIEW_FILE", "查看文档"},
84                    {"WWW", "Web浏览"}};
85    
86    const int user_action_map_size = sizeof(user_action_map) / sizeof(USER_ACTION_MAP);
87    
88    static int user_list_try_rd_lock(int semid, int wait_sec);
89    static int user_list_try_rw_lock(int semid, int wait_sec);
90    static int user_list_rd_unlock(int semid);
91    static int user_list_rw_unlock(int semid);
92    static int user_list_rd_lock(int semid);
93    static int user_list_rw_lock(int semid);
94    
95    static int user_list_load(MYSQL *db, USER_LIST *p_list);
96    static int user_online_list_load(MYSQL *db, USER_ONLINE_LIST *p_list);
97    
98    static int user_info_index_uid_comp(const void *ptr1, const void *ptr2)
99    {
100            const USER_INFO_INDEX_UID *p1 = ptr1;
101            const USER_INFO_INDEX_UID *p2 = ptr2;
102    
103            if (p1->uid < p2->uid)
104            {
105                    return -1;
106            }
107            else if (p1->uid > p2->uid)
108            {
109                    return 1;
110            }
111            else if (p1->id < p2->id)
112            {
113                    return -1;
114            }
115            else if (p1->id > p2->id)
116            {
117                    return 1;
118            }
119            return 0;
120    }
121    
122  int user_list_load(MYSQL *db, USER_LIST *p_list)  int user_list_load(MYSQL *db, USER_LIST *p_list)
123  {  {
124      MYSQL_RES *rs = NULL;          MYSQL_RES *rs = NULL;
125      MYSQL_ROW row;          MYSQL_ROW row;
126      char sql[SQL_BUFFER_LEN];          char sql[SQL_BUFFER_LEN];
127      int ret = 0;          int ret = 0;
128      int i;          int i;
129            int j;
130      if (db == NULL || p_list == NULL)          int32_t last_uid;
131      {          size_t intro_buf_offset;
132          log_error("NULL pointer error\n");          size_t intro_len;
133          return -1;  
134      }          if (db == NULL || p_list == NULL)
135            {
136      snprintf(sql, sizeof(sql),                  log_error("NULL pointer error\n");
137               "SELECT user_list.UID AS UID, username, nickname, gender, gender_pub, life, exp, "                  return -1;
138               "UNIX_TIMESTAMP(signup_dt), UNIX_TIMESTAMP(last_login_dt), UNIX_TIMESTAMP(birthday) "          }
139               "FROM user_list INNER JOIN user_pubinfo ON user_list.UID = user_pubinfo.UID "  
140               "INNER JOIN user_reginfo ON user_list.UID = user_reginfo.UID "          if (p_list->user_count > 0)
141               "WHERE enable ORDER BY UID");          {
142                    last_uid = p_list->users[p_list->user_count - 1].uid;
143      if (mysql_query(db, sql) != 0)          }
144      {          else
145          log_error("Query user info error: %s\n", mysql_error(db));          {
146          ret = -1;                  last_uid = -1;
147          goto cleanup;          }
148      }  
149            snprintf(sql, sizeof(sql),
150      if ((rs = mysql_use_result(db)) == NULL)                           "SELECT user_list.UID AS UID, username, nickname, gender, gender_pub, life, exp, visit_count, "
151      {                           "UNIX_TIMESTAMP(signup_dt), UNIX_TIMESTAMP(last_login_dt), UNIX_TIMESTAMP(last_logout_dt), "
152          log_error("Get user info data failed\n");                           "UNIX_TIMESTAMP(birthday), `introduction` "
153          ret = -1;                           "FROM user_list INNER JOIN user_pubinfo ON user_list.UID = user_pubinfo.UID "
154          goto cleanup;                           "INNER JOIN user_reginfo ON user_list.UID = user_reginfo.UID "
155      }                           "WHERE enable ORDER BY username");
156    
157      i = 0;          if (mysql_query(db, sql) != 0)
158      while ((row = mysql_fetch_row(rs)))          {
159      {                  log_error("Query user info error: %s\n", mysql_error(db));
160          p_list->users[i].uid = atoi(row[0]);                  ret = -1;
161          strncpy(p_list->users[i].username, row[1], sizeof(p_list->users[i].username) - 1);                  goto cleanup;
162          p_list->users[i].username[sizeof(p_list->users[i].username) - 1] = '\0';          }
163          strncpy(p_list->users[i].nickname, row[2], sizeof(p_list->users[i].nickname) - 1);  
164          p_list->users[i].nickname[sizeof(p_list->users[i].nickname) - 1] = '\0';          if ((rs = mysql_use_result(db)) == NULL)
165          p_list->users[i].gender = row[3][0];          {
166          p_list->users[i].gender_pub = (int8_t)(row[4] == NULL ? 0 : atoi(row[4]));                  log_error("Get user info data failed\n");
167          p_list->users[i].life = (row[5] == NULL ? 0 : atoi(row[5]));                  ret = -1;
168          p_list->users[i].exp = (row[6] == NULL ? 0 : atoi(row[6]));                  goto cleanup;
169          p_list->users[i].signup_dt = (row[7] == NULL ? 0 : atol(row[7]));          }
170          p_list->users[i].last_login_dt = (row[8] == NULL ? 0 : atol(row[8]));  
171          p_list->users[i].birthday = (row[9] == NULL ? 0 : atol(row[9]));          intro_buf_offset = 0;
172            i = 0;
173          i++;          while ((row = mysql_fetch_row(rs)))
174      }          {
175      mysql_free_result(rs);                  // record
176      rs = NULL;                  p_list->users[i].id = i;
177                    p_list->users[i].uid = atoi(row[0]);
178                    strncpy(p_list->users[i].username, row[1], sizeof(p_list->users[i].username) - 1);
179                    p_list->users[i].username[sizeof(p_list->users[i].username) - 1] = '\0';
180                    strncpy(p_list->users[i].nickname, row[2], sizeof(p_list->users[i].nickname) - 1);
181                    p_list->users[i].nickname[sizeof(p_list->users[i].nickname) - 1] = '\0';
182                    p_list->users[i].gender = row[3][0];
183                    p_list->users[i].gender_pub = (int8_t)(row[4] == NULL ? 0 : atoi(row[4]));
184                    p_list->users[i].life = (row[5] == NULL ? 0 : atoi(row[5]));
185                    p_list->users[i].exp = (row[6] == NULL ? 0 : atoi(row[6]));
186                    p_list->users[i].visit_count = (row[7] == NULL ? 0 : atoi(row[7]));
187                    p_list->users[i].signup_dt = (row[8] == NULL ? 0 : atol(row[8]));
188                    p_list->users[i].last_login_dt = (row[9] == NULL ? 0 : atol(row[9]));
189                    p_list->users[i].last_logout_dt = (row[10] == NULL ? 0 : atol(row[10]));
190                    p_list->users[i].birthday = (row[10] == NULL ? 0 : atol(row[11]));
191                    intro_len = strlen((row[12] == NULL ? "" : row[12]));
192                    if (intro_len >= sizeof(p_list->user_intro_buf) - 1 - intro_buf_offset)
193                    {
194                            log_error("OOM for user introduction: len=%d, i=%d\n", intro_len, i);
195                            break;
196                    }
197                    memcpy(p_list->user_intro_buf + intro_buf_offset,
198                               (row[12] == NULL ? "" : row[12]),
199                               intro_len + 1);
200                    p_list->users[i].intro = p_list->user_intro_buf + intro_buf_offset;
201                    intro_buf_offset += (intro_len + 1);
202    
203                    i++;
204                    if (i >= BBS_max_user_count)
205                    {
206                            log_error("Too many users, exceed limit %d\n", BBS_max_user_count);
207                            break;
208                    }
209            }
210            mysql_free_result(rs);
211            rs = NULL;
212    
213            if (i != p_list->user_count || p_list->users[i - 1].uid != last_uid) // Count of users changed
214            {
215                    // Rebuild index
216                    for (j = 0; j < i; j++)
217                    {
218                            p_list->index_uid[j].uid = p_list->users[j].uid;
219                            p_list->index_uid[j].id = j;
220                    }
221    
222      p_list->user_count = i;                  qsort(p_list->index_uid, (size_t)i, sizeof(USER_INFO_INDEX_UID), user_info_index_uid_comp);
223    
224  #ifdef _DEBUG  #ifdef _DEBUG
225      log_error("Loaded %d users\n", p_list->user_count);                  log_error("Rebuild index of %d users, last_uid=%d\n", i, p_list->users[i - 1].uid);
226    #endif
227            }
228    
229            p_list->user_count = i;
230    
231    #ifdef _DEBUG
232            log_error("Loaded %d users\n", p_list->user_count);
233  #endif  #endif
234    
235  cleanup:  cleanup:
236      mysql_free_result(rs);          mysql_free_result(rs);
237    
238      return ret;          return ret;
239  }  }
240    
241  int user_list_pool_init(void)  int user_online_list_load(MYSQL *db, USER_ONLINE_LIST *p_list)
242  {  {
243      int shmid;          MYSQL_RES *rs = NULL;
244      int semid;          MYSQL_ROW row;
245      int proj_id;          char sql[SQL_BUFFER_LEN];
246      key_t key;          int ret = 0;
247      size_t size;          int i;
248      void *p_shm;          int j;
249      union semun arg;          int user_cnt;
250      int i;          int guest_cnt;
251    
252      if (p_user_list_pool != NULL)          if (db == NULL || p_list == NULL)
253      {          {
254          log_error("p_user_list_pool already initialized\n");                  log_error("NULL pointer error\n");
255          return -1;                  return -1;
256      }          }
257    
258      // Allocate shared memory          snprintf(sql, sizeof(sql),
259      proj_id = (int)(time(NULL) % getpid());                           "SELECT SID, UID, ip, current_action, UNIX_TIMESTAMP(login_tm), "
260      key = ftok(VAR_USER_LIST_SHM, proj_id);                           "UNIX_TIMESTAMP(last_tm) FROM user_online "
261      if (key == -1)                           "WHERE last_tm >= SUBDATE(NOW(), INTERVAL %d SECOND) "
262      {                           "ORDER BY last_tm DESC",
263          log_error("ftok(%s %d) error (%d)\n", VAR_USER_LIST_SHM, proj_id, errno);                           BBS_user_off_line);
264          return -2;  
265      }          if (mysql_query(db, sql) != 0)
266            {
267      size = sizeof(USER_LIST_POOL);                  log_error("Query user online error: %s\n", mysql_error(db));
268      shmid = shmget(key, size, IPC_CREAT | IPC_EXCL | 0600);                  ret = -1;
269      if (shmid == -1)                  goto cleanup;
270      {          }
271          log_error("shmget(size = %d) error (%d)\n", size, errno);  
272          return -3;          if ((rs = mysql_use_result(db)) == NULL)
273      }          {
274      p_shm = shmat(shmid, NULL, 0);                  log_error("Get user online data failed\n");
275      if (p_shm == (void *)-1)                  ret = -1;
276      {                  goto cleanup;
277          log_error("shmat(shmid=%d) error (%d)\n", shmid, errno);          }
278          return -3;  
279      }          i = 0;
280            user_cnt = 0;
281      p_user_list_pool = p_shm;          guest_cnt = 0;
282      p_user_list_pool->shmid = shmid;          while ((row = mysql_fetch_row(rs)))
283            {
284      // Allocate semaphore as user list pool lock                  if (atoi(row[1]) == 0) // guest
285      size = 2; // r_sem and w_sem                  {
286      semid = semget(key, (int)size, IPC_CREAT | IPC_EXCL | 0600);                          guest_cnt++;
287      if (semid == -1)                          continue;
288      {                  }
289          log_error("semget(user_list_pool_sem, size = %d) error (%d)\n", size, errno);                  else
290          return -3;                  {
291      }                          user_cnt++;
292                    }
293      // Initialize sem value to 0  
294      arg.val = 0;                  p_list->users[i].id = i;
295      for (i = 0; i < size; i++)                  strncpy(p_list->users[i].session_id, row[0], sizeof(p_list->users[i].session_id) - 1);
296      {                  p_list->users[i].session_id[sizeof(p_list->users[i].session_id) - 1] = '\0';
297          if (semctl(semid, i, SETVAL, arg) == -1)  
298          {                  if ((ret = query_user_info_by_uid(atoi(row[1]), &(p_list->users[i].user_info))) <= 0)
299              log_error("semctl(user_list_pool_sem, SETVAL) error (%d)\n", errno);                  {
300              return -3;                          log_error("query_user_info_by_uid(%d) error\n", atoi(row[1]));
301          }                          continue;
302      }                  }
303    
304      p_user_list_pool->semid = semid;                  strncpy(p_list->users[i].ip, row[2], sizeof(p_list->users[i].ip) - 1);
305                    p_list->users[i].ip[sizeof(p_list->users[i].ip) - 1] = '\0';
306      // Set user counts to 0  
307      p_user_list_pool->user_list[0].user_count = 0;                  strncpy(p_list->users[i].current_action, row[3], sizeof(p_list->users[i].current_action) - 1);
308      p_user_list_pool->user_list[1].user_count = 0;                  p_list->users[i].current_action[sizeof(p_list->users[i].current_action) - 1] = '\0';
309                    p_list->users[i].current_action_title = NULL;
310                    if (p_list->users[i].current_action[0] == '\0')
311                    {
312                            p_list->users[i].current_action_title = "";
313                    }
314                    else if (trie_dict_get(p_trie_action_dict, p_list->users[i].current_action, (int64_t *)(&(p_list->users[i].current_action_title))) < 0)
315                    {
316                            log_error("trie_dict_get(p_trie_action_dict, %s) error on session_id=%s\n",
317                                              p_list->users[i].current_action, p_list->users[i].session_id);
318                            continue;
319                    }
320    
321                    p_list->users[i].login_tm = (row[4] == NULL ? 0 : atol(row[4]));
322                    p_list->users[i].last_tm = (row[5] == NULL ? 0 : atol(row[5]));
323    
324                    i++;
325                    if (i >= BBS_max_user_online_count)
326                    {
327                            log_error("Too many online users, exceed limit %d\n", BBS_max_user_online_count);
328                            break;
329                    }
330            }
331            mysql_free_result(rs);
332            rs = NULL;
333    
334            if (user_cnt > 0)
335            {
336                    // Rebuild index
337                    for (j = 0; j < user_cnt; j++)
338                    {
339                            p_list->index_uid[j].uid = p_list->users[j].user_info.uid;
340                            p_list->index_uid[j].id = j;
341                    }
342    
343                    qsort(p_list->index_uid, (size_t)user_cnt, sizeof(USER_INFO_INDEX_UID), user_info_index_uid_comp);
344    
345    #ifdef _DEBUG
346                    log_error("Rebuild index of %d online users\n", user_cnt);
347    #endif
348            }
349    
350      p_user_list_pool->p_current = &(p_user_list_pool->user_list[0]);          p_list->user_count = user_cnt;
351      p_user_list_pool->p_new = &(p_user_list_pool->user_list[1]);          p_list->guest_count = guest_cnt;
352    
353      return 0;  #ifdef _DEBUG
354            log_error("Loaded %d online users and %d guest users\n", p_list->user_count, p_list->guest_count);
355    #endif
356    
357    cleanup:
358            mysql_free_result(rs);
359    
360            return ret;
361    }
362    
363    int user_list_pool_init(const char *filename)
364    {
365            int shmid;
366            int semid;
367            int proj_id;
368            key_t key;
369            size_t size;
370            void *p_shm;
371            union semun arg;
372            int i;
373    
374            if (p_user_list_pool != NULL || p_trie_action_dict != NULL)
375            {
376                    log_error("p_user_list_pool already initialized\n");
377                    return -1;
378            }
379    
380            p_trie_action_dict = trie_dict_create();
381            if (p_trie_action_dict == NULL)
382            {
383                    log_error("trie_dict_create() error\n");
384                    return -1;
385            }
386    
387            for (i = 0; i < user_action_map_size; i++)
388            {
389                    if (trie_dict_set(p_trie_action_dict, user_action_map[i].name, (int64_t)(user_action_map[i].title)) < 0)
390                    {
391                            log_error("trie_dict_set(p_trie_action_dict, %s) error\n", user_action_map[i].name);
392                    }
393            }
394    
395            // Allocate shared memory
396            proj_id = (int)(time(NULL) % getpid());
397            key = ftok(filename, proj_id);
398            if (key == -1)
399            {
400                    log_error("ftok(%s %d) error (%d)\n", filename, proj_id, errno);
401                    return -2;
402            }
403    
404            size = sizeof(USER_LIST_POOL);
405            shmid = shmget(key, size, IPC_CREAT | IPC_EXCL | 0600);
406            if (shmid == -1)
407            {
408                    log_error("shmget(size = %d) error (%d)\n", size, errno);
409                    return -3;
410            }
411            p_shm = shmat(shmid, NULL, 0);
412            if (p_shm == (void *)-1)
413            {
414                    log_error("shmat(shmid=%d) error (%d)\n", shmid, errno);
415                    return -3;
416            }
417    
418            p_user_list_pool = p_shm;
419            p_user_list_pool->shmid = shmid;
420    
421            // Allocate semaphore as user list pool lock
422            size = 2; // r_sem and w_sem
423            semid = semget(key, (int)size, IPC_CREAT | IPC_EXCL | 0600);
424            if (semid == -1)
425            {
426                    log_error("semget(user_list_pool_sem, size = %d) error (%d)\n", size, errno);
427                    return -3;
428            }
429    
430            // Initialize sem value to 0
431            arg.val = 0;
432            for (i = 0; i < size; i++)
433            {
434                    if (semctl(semid, i, SETVAL, arg) == -1)
435                    {
436                            log_error("semctl(user_list_pool_sem, SETVAL) error (%d)\n", errno);
437                            return -3;
438                    }
439            }
440    
441            p_user_list_pool->semid = semid;
442    
443            // Set user counts to 0
444            p_user_list_pool->user_list[0].user_count = 0;
445            p_user_list_pool->user_list[1].user_count = 0;
446    
447            p_user_list_pool->p_current = &(p_user_list_pool->user_list[0]);
448            p_user_list_pool->p_new = &(p_user_list_pool->user_list[1]);
449    
450            p_user_list_pool->p_online_current = &(p_user_list_pool->user_online_list[0]);
451            p_user_list_pool->p_online_new = &(p_user_list_pool->user_online_list[1]);
452    
453            user_stat_map_init(&(p_user_list_pool->user_stat_map));
454    
455            return 0;
456  }  }
457    
458  void user_list_pool_cleanup(void)  void user_list_pool_cleanup(void)
459  {  {
460      int shmid;          int shmid;
461    
462      if (p_user_list_pool == NULL)          if (p_user_list_pool == NULL)
463      {          {
464          return;                  return;
465      }          }
466    
467      shmid = p_user_list_pool->shmid;          shmid = p_user_list_pool->shmid;
468    
469      if (semctl(p_user_list_pool->semid, 0, IPC_RMID) == -1)          if (semctl(p_user_list_pool->semid, 0, IPC_RMID) == -1)
470      {          {
471          log_error("semctl(semid = %d, IPC_RMID) error (%d)\n", p_user_list_pool->semid, errno);                  log_error("semctl(semid = %d, IPC_RMID) error (%d)\n", p_user_list_pool->semid, errno);
472      }          }
473    
474      if (shmdt(p_user_list_pool) == -1)          if (shmdt(p_user_list_pool) == -1)
475      {          {
476          log_error("shmdt(shmid = %d) error (%d)\n", shmid, errno);                  log_error("shmdt(shmid = %d) error (%d)\n", shmid, errno);
477      }          }
478    
479      if (shmctl(shmid, IPC_RMID, NULL) == -1)          if (shmctl(shmid, IPC_RMID, NULL) == -1)
480      {          {
481          log_error("shmctl(shmid = %d, IPC_RMID) error (%d)\n", shmid, errno);                  log_error("shmctl(shmid = %d, IPC_RMID) error (%d)\n", shmid, errno);
482      }          }
483    
484            p_user_list_pool = NULL;
485    
486            if (p_trie_action_dict != NULL)
487            {
488                    trie_dict_destroy(p_trie_action_dict);
489    
490      p_user_list_pool = NULL;                  p_trie_action_dict = NULL;
491            }
492  }  }
493    
494  int set_user_list_pool_shm_readonly(void)  int set_user_list_pool_shm_readonly(void)
495  {  {
496      int shmid;          int shmid;
497      void *p_shm;          void *p_shm;
498    
499      if (p_user_list_pool == NULL)          if (p_user_list_pool == NULL)
500      {          {
501          log_error("p_user_list_pool not initialized\n");                  log_error("p_user_list_pool not initialized\n");
502          return -1;                  return -1;
503      }          }
504    
505      shmid = p_user_list_pool->shmid;          shmid = p_user_list_pool->shmid;
506    
507      // Remap shared memory in read-only mode          // Remap shared memory in read-only mode
508      p_shm = shmat(shmid, p_user_list_pool, SHM_RDONLY | SHM_REMAP);          p_shm = shmat(shmid, p_user_list_pool, SHM_RDONLY | SHM_REMAP);
509      if (p_shm == (void *)-1)          if (p_shm == (void *)-1)
510      {          {
511          log_error("shmat(user_list_pool shmid = %d) error (%d)\n", shmid, errno);                  log_error("shmat(user_list_pool shmid = %d) error (%d)\n", shmid, errno);
512          return -3;                  return -3;
513      }          }
514    
515      p_user_list_pool = p_shm;          p_user_list_pool = p_shm;
516    
517      return 0;          return 0;
518  }  }
519    
520  int detach_user_list_pool_shm(void)  int detach_user_list_pool_shm(void)
521  {  {
522      if (p_user_list_pool != NULL && shmdt(p_user_list_pool) == -1)          if (p_user_list_pool != NULL && shmdt(p_user_list_pool) == -1)
523      {          {
524          log_error("shmdt(user_list_pool) error (%d)\n", errno);                  log_error("shmdt(user_list_pool) error (%d)\n", errno);
525          return -1;                  return -1;
526      }          }
527    
528      p_user_list_pool = NULL;          p_user_list_pool = NULL;
529    
530      return 0;          return 0;
531  }  }
532    
533  int user_list_pool_reload(void)  int user_list_pool_reload(int online_user)
534  {  {
535      MYSQL *db = NULL;          MYSQL *db = NULL;
536      USER_LIST *p_tmp;          USER_LIST *p_tmp;
537      int ret = 0;          USER_ONLINE_LIST *p_online_tmp;
538            int ret = 0;
539      if (p_user_list_pool == NULL)  
540      {          if (p_user_list_pool == NULL)
541          log_error("p_user_list_pool not initialized\n");          {
542          return -1;                  log_error("p_user_list_pool not initialized\n");
543      }                  return -1;
544            }
545      db = db_open();  
546      if (db == NULL)          db = db_open();
547      {          if (db == NULL)
548          log_error("db_open() error: %s\n", mysql_error(db));          {
549          return -1;                  log_error("db_open() error: %s\n", mysql_error(db));
550      }                  return -1;
551            }
552      if (user_list_rw_lock() < 0)  
553      {          if (online_user)
554          log_error("user_list_rw_lock() error\n");          {
555          return -2;                  if (user_online_list_load(db, p_user_list_pool->p_online_new) < 0)
556      }                  {
557                            log_error("user_online_list_load() error\n");
558      if (user_list_load(db, p_user_list_pool->p_new) < 0)                          ret = -2;
559      {                          goto cleanup;
560          log_error("user_list_rw_lock() error\n");                  }
561          ret = -3;          }
562          goto cleanup;          else
563      }          {
564                    if (user_list_load(db, p_user_list_pool->p_new) < 0)
565      // Swap p_current and p_new                  {
566      p_tmp = p_user_list_pool->p_current;                          log_error("user_list_load() error\n");
567      p_user_list_pool->p_current = p_user_list_pool->p_new;                          ret = -2;
568      p_user_list_pool->p_new = p_tmp;                          goto cleanup;
569                    }
570            }
571    
572            mysql_close(db);
573            db = NULL;
574    
575            if (user_list_rw_lock(p_user_list_pool->semid) < 0)
576            {
577                    log_error("user_list_rw_lock() error\n");
578                    ret = -3;
579                    goto cleanup;
580            }
581    
582            if (online_user)
583            {
584                    // Swap p_online_current and p_online_new
585                    p_online_tmp = p_user_list_pool->p_online_current;
586                    p_user_list_pool->p_online_current = p_user_list_pool->p_online_new;
587                    p_user_list_pool->p_online_new = p_online_tmp;
588            }
589            else
590            {
591                    // Swap p_current and p_new
592                    p_tmp = p_user_list_pool->p_current;
593                    p_user_list_pool->p_current = p_user_list_pool->p_new;
594                    p_user_list_pool->p_new = p_tmp;
595            }
596    
597            if (user_list_rw_unlock(p_user_list_pool->semid) < 0)
598            {
599                    log_error("user_list_rw_unlock() error\n");
600                    ret = -3;
601                    goto cleanup;
602            }
603    
604  cleanup:  cleanup:
605      if (user_list_rw_unlock() < 0)          mysql_close(db);
606      {  
607          log_error("user_list_rw_unlock() error\n");          return ret;
608          ret = -2;  }
609      }  
610    int user_list_try_rd_lock(int semid, int wait_sec)
611    {
612            struct sembuf sops[2];
613            struct timespec timeout;
614            int ret;
615    
616            sops[0].sem_num = 1; // w_sem
617            sops[0].sem_op = 0;      // wait until unlocked
618            sops[0].sem_flg = 0;
619    
620            sops[1].sem_num = 0;            // r_sem
621            sops[1].sem_op = 1;                     // lock
622            sops[1].sem_flg = SEM_UNDO; // undo on terminate
623    
624            timeout.tv_sec = wait_sec;
625            timeout.tv_nsec = 0;
626    
627            ret = semtimedop(semid, sops, 2, &timeout);
628            if (ret == -1 && errno != EAGAIN && errno != EINTR)
629            {
630                    log_error("semtimedop(lock read) error %d\n", errno);
631            }
632    
633            return ret;
634    }
635    
636      mysql_close(db);  int user_list_try_rw_lock(int semid, int wait_sec)
637    {
638            struct sembuf sops[3];
639            struct timespec timeout;
640            int ret;
641    
642            sops[0].sem_num = 1; // w_sem
643            sops[0].sem_op = 0;      // wait until unlocked
644            sops[0].sem_flg = 0;
645    
646            sops[1].sem_num = 1;            // w_sem
647            sops[1].sem_op = 1;                     // lock
648            sops[1].sem_flg = SEM_UNDO; // undo on terminate
649    
650            sops[2].sem_num = 0; // r_sem
651            sops[2].sem_op = 0;      // wait until unlocked
652            sops[2].sem_flg = 0;
653    
654            timeout.tv_sec = wait_sec;
655            timeout.tv_nsec = 0;
656    
657            ret = semtimedop(semid, sops, 3, &timeout);
658            if (ret == -1 && errno != EAGAIN && errno != EINTR)
659            {
660                    log_error("semtimedop(lock write) error %d\n", errno);
661            }
662    
663      return ret;          return ret;
664  }  }
665    
666  int user_list_try_rd_lock(int wait_sec)  int user_list_rd_unlock(int semid)
667  {  {
668      struct sembuf sops[2];          struct sembuf sops[2];
669      struct timespec timeout;          int ret;
     int ret;  
670    
671      sops[0].sem_num = 1; // w_sem          sops[0].sem_num = 0;                                     // r_sem
672      sops[0].sem_op = 0;  // wait until unlocked          sops[0].sem_op = -1;                                     // unlock
673      sops[0].sem_flg = 0;          sops[0].sem_flg = IPC_NOWAIT | SEM_UNDO; // no wait
674    
675            ret = semop(semid, sops, 1);
676            if (ret == -1 && errno != EAGAIN && errno != EINTR)
677            {
678                    log_error("semop(unlock read) error %d\n", errno);
679            }
680    
681      sops[1].sem_num = 0;        // r_sem          return ret;
682      sops[1].sem_op = 1;         // lock  }
     sops[1].sem_flg = SEM_UNDO; // undo on terminate  
683    
684      timeout.tv_sec = wait_sec;  int user_list_rw_unlock(int semid)
685      timeout.tv_nsec = 0;  {
686            struct sembuf sops[1];
687            int ret;
688    
689      ret = semtimedop(p_user_list_pool->semid, sops, 2, &timeout);          sops[0].sem_num = 1;                                     // w_sem
690      if (ret == -1 && errno != EAGAIN && errno != EINTR)          sops[0].sem_op = -1;                                     // unlock
691      {          sops[0].sem_flg = IPC_NOWAIT | SEM_UNDO; // no wait
692          log_error("semtimedop(lock read) error %d\n", errno);  
693      }          ret = semop(semid, sops, 1);
694            if (ret == -1 && errno != EAGAIN && errno != EINTR)
695            {
696                    log_error("semop(unlock write) error %d\n", errno);
697            }
698    
699      return ret;          return ret;
700  }  }
701    
702  int user_list_try_rw_lock(int wait_sec)  int user_list_rd_lock(int semid)
703  {  {
704      struct sembuf sops[3];          int timer = 0;
705      struct timespec timeout;          int ret = -1;
706      int ret;  
707            while (!SYS_server_exit)
708            {
709                    ret = user_list_try_rd_lock(semid, USER_LIST_TRY_LOCK_WAIT_TIME);
710                    if (ret == 0) // success
711                    {
712                            break;
713                    }
714                    else if (errno == EAGAIN || errno == EINTR) // retry
715                    {
716                            timer++;
717                            if (timer % USER_LIST_TRY_LOCK_TIMES == 0)
718                            {
719                                    log_error("user_list_try_rd_lock() tried %d times\n", timer);
720                            }
721                    }
722                    else // failed
723                    {
724                            log_error("user_list_try_rd_lock() failed\n");
725                            break;
726                    }
727            }
728    
729            return ret;
730    }
731    
732      sops[0].sem_num = 1; // w_sem  int user_list_rw_lock(int semid)
733      sops[0].sem_op = 0;  // wait until unlocked  {
734      sops[0].sem_flg = 0;          int timer = 0;
735            int ret = -1;
736    
737      sops[1].sem_num = 1;        // w_sem          while (!SYS_server_exit)
738      sops[1].sem_op = 1;         // lock          {
739      sops[1].sem_flg = SEM_UNDO; // undo on terminate                  ret = user_list_try_rw_lock(semid, USER_LIST_TRY_LOCK_WAIT_TIME);
740                    if (ret == 0) // success
741                    {
742                            break;
743                    }
744                    else if (errno == EAGAIN || errno == EINTR) // retry
745                    {
746                            timer++;
747                            if (timer % USER_LIST_TRY_LOCK_TIMES == 0)
748                            {
749                                    log_error("user_list_try_rw_lock() tried %d times\n", timer);
750                            }
751                    }
752                    else // failed
753                    {
754                            log_error("user_list_try_rw_lock() failed\n");
755                            break;
756                    }
757            }
758    
759      sops[2].sem_num = 0; // r_sem          return ret;
760      sops[2].sem_op = 0;  // wait until unlocked  }
     sops[2].sem_flg = 0;  
761    
762      timeout.tv_sec = wait_sec;  int query_user_list(int page_id, USER_INFO *p_users, int *p_user_count, int *p_page_count)
763      timeout.tv_nsec = 0;  {
764            int ret = 0;
765    
766      ret = semtimedop(p_user_list_pool->semid, sops, 3, &timeout);          if (p_users == NULL || p_user_count == NULL || p_page_count == NULL)
767      if (ret == -1 && errno != EAGAIN && errno != EINTR)          {
768      {                  log_error("NULL pointer error\n");
769          log_error("semtimedop(lock write) error %d\n", errno);                  return -1;
770      }          }
771    
772            *p_user_count = 0;
773            *p_page_count = 0;
774    
775            // acquire lock of user list
776            if (user_list_rd_lock(p_user_list_pool->semid) < 0)
777            {
778                    log_error("user_list_rd_lock() error\n");
779                    return -2;
780            }
781    
782            if (p_user_list_pool->p_current->user_count == 0)
783            {
784                    // empty list
785                    ret = 0;
786                    goto cleanup;
787            }
788    
789            *p_page_count = p_user_list_pool->p_current->user_count / BBS_user_limit_per_page +
790                                            (p_user_list_pool->p_current->user_count % BBS_user_limit_per_page == 0 ? 0 : 1);
791    
792            if (page_id < 0 || page_id >= *p_page_count)
793            {
794                    log_error("Invalid page_id = %d, not in range [0, %d)\n", page_id, *p_page_count);
795                    ret = -3;
796                    goto cleanup;
797            }
798    
799            *p_user_count = MIN(BBS_user_limit_per_page,
800                                                    p_user_list_pool->p_current->user_count -
801                                                            page_id * BBS_user_limit_per_page);
802    
803            memcpy(p_users,
804                       p_user_list_pool->p_current->users + page_id * BBS_user_limit_per_page,
805                       sizeof(USER_INFO) * (size_t)(*p_user_count));
806    
807      return ret;  cleanup:
808            // release lock of user list
809            if (user_list_rd_unlock(p_user_list_pool->semid) < 0)
810            {
811                    log_error("user_list_rd_unlock() error\n");
812                    ret = -1;
813            }
814    
815            return ret;
816  }  }
817    
818  int user_list_rd_unlock(void)  int query_user_online_list(int page_id, USER_ONLINE_INFO *p_online_users, int *p_user_count, int *p_page_count)
819  {  {
820      struct sembuf sops[2];          int ret = 0;
     int ret;  
821    
822      sops[0].sem_num = 0;                     // r_sem          if (p_online_users == NULL || p_user_count == NULL || p_page_count == NULL)
823      sops[0].sem_op = -1;                     // unlock          {
824      sops[0].sem_flg = IPC_NOWAIT | SEM_UNDO; // no wait                  log_error("NULL pointer error\n");
825                    return -1;
826            }
827    
828            *p_user_count = 0;
829            *p_page_count = 0;
830    
831            // acquire lock of user list
832            if (user_list_rd_lock(p_user_list_pool->semid) < 0)
833            {
834                    log_error("user_list_rd_lock() error\n");
835                    return -2;
836            }
837    
838            if (p_user_list_pool->p_online_current->user_count == 0)
839            {
840                    // empty list
841                    ret = 0;
842                    goto cleanup;
843            }
844    
845            *p_page_count = p_user_list_pool->p_online_current->user_count / BBS_user_limit_per_page +
846                                            (p_user_list_pool->p_online_current->user_count % BBS_user_limit_per_page == 0 ? 0 : 1);
847    
848            if (page_id < 0 || page_id >= *p_page_count)
849            {
850                    log_error("Invalid page_id = %d, not in range [0, %d)\n", page_id, *p_page_count);
851                    ret = -3;
852                    goto cleanup;
853            }
854    
855            *p_user_count = MIN(BBS_user_limit_per_page,
856                                                    p_user_list_pool->p_online_current->user_count -
857                                                            page_id * BBS_user_limit_per_page);
858    
859            memcpy(p_online_users,
860                       p_user_list_pool->p_online_current->users + page_id * BBS_user_limit_per_page,
861                       sizeof(USER_ONLINE_INFO) * (size_t)(*p_user_count));
862    
863      ret = semop(p_user_list_pool->semid, sops, 1);  cleanup:
864      if (ret == -1 && errno != EAGAIN && errno != EINTR)          // release lock of user list
865      {          if (user_list_rd_unlock(p_user_list_pool->semid) < 0)
866          log_error("semop(unlock read) error %d\n", errno);          {
867      }                  log_error("user_list_rd_unlock() error\n");
868                    ret = -1;
869            }
870    
871      return ret;          return ret;
872  }  }
873    
874  int user_list_rw_unlock(void)  int get_user_list_count(int *p_user_cnt)
875  {  {
876      struct sembuf sops[1];          if (p_user_cnt == NULL)
877      int ret;          {
878                    log_error("NULL pointer error\n");
879                    return -1;
880            }
881    
882            // acquire lock of user list
883            if (user_list_rd_lock(p_user_list_pool->semid) < 0)
884            {
885                    log_error("user_list_rd_lock() error\n");
886                    return -2;
887            }
888    
889            *p_user_cnt = p_user_list_pool->p_current->user_count;
890    
891            // release lock of user list
892            if (user_list_rd_unlock(p_user_list_pool->semid) < 0)
893            {
894                    log_error("user_list_rd_unlock() error\n");
895                    return -2;
896            }
897    
898      sops[0].sem_num = 1;                     // w_sem          return 0;
899      sops[0].sem_op = -1;                     // unlock  }
     sops[0].sem_flg = IPC_NOWAIT | SEM_UNDO; // no wait  
900    
901      ret = semop(p_user_list_pool->semid, sops, 1);  int get_user_online_list_count(int *p_user_cnt, int *p_guest_cnt)
902      if (ret == -1 && errno != EAGAIN && errno != EINTR)  {
903      {          if (p_user_cnt == NULL || p_guest_cnt == NULL)
904          log_error("semop(unlock write) error %d\n", errno);          {
905      }                  log_error("NULL pointer error\n");
906                    return -1;
907            }
908    
909            // acquire lock of user list
910            if (user_list_rd_lock(p_user_list_pool->semid) < 0)
911            {
912                    log_error("user_list_rd_lock() error\n");
913                    return -2;
914            }
915    
916            *p_user_cnt = p_user_list_pool->p_online_current->user_count;
917            *p_guest_cnt = p_user_list_pool->p_online_current->guest_count;
918    
919            // release lock of user list
920            if (user_list_rd_unlock(p_user_list_pool->semid) < 0)
921            {
922                    log_error("user_list_rd_unlock() error\n");
923                    return -2;
924            }
925    
926      return ret;          return 0;
927  }  }
928    
929  int user_list_rd_lock(void)  int query_user_info(int32_t id, USER_INFO *p_user)
930  {  {
931      int timer = 0;          int ret = 0;
     int ret = -1;  
932    
933      while (!SYS_server_exit)          if (p_user == NULL)
934      {          {
935          ret = user_list_try_rd_lock(USER_LIST_TRY_LOCK_WAIT_TIME);                  log_error("NULL pointer error\n");
936          if (ret == 0) // success                  return -1;
937          {          }
938              break;  
939          }          // acquire lock of user list
940          else if (errno == EAGAIN || errno == EINTR) // retry          if (user_list_rd_lock(p_user_list_pool->semid) < 0)
941          {          {
942              timer++;                  log_error("user_list_rd_lock() error\n");
943              if (timer % USER_LIST_TRY_LOCK_TIMES == 0)                  return -2;
944              {          }
945                  log_error("user_list_try_rd_lock() tried %d times\n", timer);  
946              }          if (id >= 0 && id < p_user_list_pool->p_current->user_count) // Found
947          }          {
948          else // failed                  *p_user = p_user_list_pool->p_current->users[id];
949          {                  ret = 1;
950              log_error("user_list_try_rd_lock() failed\n");          }
951              break;  
952          }          // release lock of user list
953      }          if (user_list_rd_unlock(p_user_list_pool->semid) < 0)
954            {
955                    log_error("user_list_rd_unlock() error\n");
956                    ret = -1;
957            }
958    
959      return ret;          return ret;
960    }
961    
962    int query_user_info_by_uid(int32_t uid, USER_INFO *p_user)
963    {
964            int left;
965            int right;
966            int mid;
967            int32_t id;
968            int ret = 0;
969    
970            if (p_user == NULL)
971            {
972                    log_error("NULL pointer error\n");
973                    return -1;
974            }
975    
976            // acquire lock of user list
977            if (user_list_rd_lock(p_user_list_pool->semid) < 0)
978            {
979                    log_error("user_list_rd_lock() error\n");
980                    return -2;
981            }
982    
983            left = 0;
984            right = p_user_list_pool->p_current->user_count - 1;
985    
986            while (left < right)
987            {
988                    mid = (left + right) / 2;
989                    if (uid < p_user_list_pool->p_current->index_uid[mid].uid)
990                    {
991                            right = mid - 1;
992                    }
993                    else if (uid > p_user_list_pool->p_current->index_uid[mid].uid)
994                    {
995                            left = mid + 1;
996                    }
997                    else // if (uid == p_user_list_pool->p_current->index_uid[mid].uid)
998                    {
999                            left = mid;
1000                            break;
1001                    }
1002            }
1003    
1004            if (uid == p_user_list_pool->p_current->index_uid[left].uid) // Found
1005            {
1006                    id = p_user_list_pool->p_current->index_uid[left].id;
1007                    *p_user = p_user_list_pool->p_current->users[id];
1008                    ret = 1;
1009            }
1010    
1011            // release lock of user list
1012            if (user_list_rd_unlock(p_user_list_pool->semid) < 0)
1013            {
1014                    log_error("user_list_rd_unlock() error\n");
1015                    ret = -1;
1016            }
1017    
1018            return ret;
1019    }
1020    
1021    int query_user_online_info(int32_t id, USER_ONLINE_INFO *p_user)
1022    {
1023            int ret = 0;
1024    
1025            if (p_user == NULL)
1026            {
1027                    log_error("NULL pointer error\n");
1028                    return -1;
1029            }
1030    
1031            // acquire lock of user list
1032            if (user_list_rd_lock(p_user_list_pool->semid) < 0)
1033            {
1034                    log_error("user_list_rd_lock() error\n");
1035                    return -2;
1036            }
1037    
1038            if (id >= 0 && id < p_user_list_pool->p_online_current->user_count) // Found
1039            {
1040                    *p_user = p_user_list_pool->p_online_current->users[id];
1041                    ret = 1;
1042            }
1043    
1044            // release lock of user list
1045            if (user_list_rd_unlock(p_user_list_pool->semid) < 0)
1046            {
1047                    log_error("user_list_rd_unlock() error\n");
1048                    ret = -1;
1049            }
1050    
1051            return ret;
1052    }
1053    
1054    int query_user_online_info_by_uid(int32_t uid, USER_ONLINE_INFO *p_users, int *p_user_cnt, int start_id)
1055    {
1056            int left;
1057            int right;
1058            int mid;
1059            int32_t id;
1060            int ret = 0;
1061            int i;
1062            int user_cnt;
1063    
1064            if (p_users == NULL || p_user_cnt == NULL)
1065            {
1066                    log_error("NULL pointer error\n");
1067                    return -1;
1068            }
1069    
1070            user_cnt = *p_user_cnt;
1071            *p_user_cnt = 0;
1072    
1073            // acquire lock of user list
1074            if (user_list_rd_lock(p_user_list_pool->semid) < 0)
1075            {
1076                    log_error("user_list_rd_lock() error\n");
1077                    return -2;
1078            }
1079    
1080            left = start_id;
1081            right = p_user_list_pool->p_online_current->user_count - 1;
1082    
1083            while (left < right)
1084            {
1085                    mid = (left + right) / 2;
1086                    if (uid < p_user_list_pool->p_online_current->index_uid[mid].uid)
1087                    {
1088                            right = mid - 1;
1089                    }
1090                    else if (uid > p_user_list_pool->p_online_current->index_uid[mid].uid)
1091                    {
1092                            left = mid + 1;
1093                    }
1094                    else // if (uid == p_user_list_pool->p_online_current->index_uid[mid].uid)
1095                    {
1096                            left = mid;
1097                            break;
1098                    }
1099            }
1100    
1101            if (uid == p_user_list_pool->p_online_current->index_uid[left].uid)
1102            {
1103                    right = left;
1104                    left = start_id;
1105    
1106                    while (left < right)
1107                    {
1108                            mid = (left + right) / 2;
1109                            if (uid - 1 < p_user_list_pool->p_online_current->index_uid[mid].uid)
1110                            {
1111                                    right = mid;
1112                            }
1113                            else // if (uid - 1 >= p_user_list_pool->p_online_current->index_uid[mid].uid)
1114                            {
1115                                    left = mid + 1;
1116                            }
1117                    }
1118    
1119                    for (i = 0;
1120                             left < p_user_list_pool->p_online_current->user_count && i < user_cnt &&
1121                             uid == p_user_list_pool->p_online_current->index_uid[left].uid;
1122                             left++, i++)
1123                    {
1124                            id = p_user_list_pool->p_online_current->index_uid[left].id;
1125                            p_users[i] = p_user_list_pool->p_online_current->users[id];
1126                    }
1127    
1128                    if (i > 0)
1129                    {
1130                            *p_user_cnt = i;
1131                            ret = 1;
1132                    }
1133            }
1134    
1135            // release lock of user list
1136            if (user_list_rd_unlock(p_user_list_pool->semid) < 0)
1137            {
1138                    log_error("user_list_rd_unlock() error\n");
1139                    ret = -1;
1140            }
1141    
1142            return ret;
1143    }
1144    
1145    int get_user_id_list(int32_t *p_uid_list, int *p_user_cnt, int start_uid)
1146    {
1147            int left;
1148            int right;
1149            int mid;
1150            int ret = 0;
1151            int i;
1152    
1153            if (p_uid_list == NULL || p_user_cnt == NULL)
1154            {
1155                    log_error("NULL pointer error\n");
1156                    return -1;
1157            }
1158    
1159            // acquire lock of user list
1160            if (user_list_rd_lock(p_user_list_pool->semid) < 0)
1161            {
1162                    log_error("user_list_rd_lock() error\n");
1163                    return -2;
1164            }
1165    
1166            left = 0;
1167            right = p_user_list_pool->p_current->user_count - 1;
1168    
1169            while (left < right)
1170            {
1171                    mid = (left + right) / 2;
1172                    if (start_uid < p_user_list_pool->p_current->index_uid[mid].uid)
1173                    {
1174                            right = mid - 1;
1175                    }
1176                    else if (start_uid > p_user_list_pool->p_current->index_uid[mid].uid)
1177                    {
1178                            left = mid + 1;
1179                    }
1180                    else // if (start_uid == p_user_list_pool->p_current->index_uid[mid].uid)
1181                    {
1182                            left = mid;
1183                            break;
1184                    }
1185            }
1186    
1187            for (i = 0; i < *p_user_cnt && left + i < p_user_list_pool->p_current->user_count; i++)
1188            {
1189                    p_uid_list[i] = p_user_list_pool->p_current->index_uid[left + i].uid;
1190            }
1191            *p_user_cnt = i;
1192    
1193            // release lock of user list
1194            if (user_list_rd_unlock(p_user_list_pool->semid) < 0)
1195            {
1196                    log_error("user_list_rd_unlock() error\n");
1197                    ret = -1;
1198            }
1199    
1200            return ret;
1201    }
1202    
1203    int user_stat_update(void)
1204    {
1205            return user_stat_map_update(&(p_user_list_pool->user_stat_map));
1206    }
1207    
1208    int user_article_cnt_inc(int32_t uid, int n)
1209    {
1210            return user_stat_article_cnt_inc(&(p_user_list_pool->user_stat_map), uid, n);
1211  }  }
1212    
1213  int user_list_rw_lock(void)  int get_user_article_cnt(int32_t uid)
1214  {  {
1215      int timer = 0;          const USER_STAT *p_stat;
1216      int ret = -1;          int ret;
1217    
1218      while (!SYS_server_exit)          ret = user_stat_get(&(p_user_list_pool->user_stat_map), uid, &p_stat);
1219      {          if (ret < 0)
1220          ret = user_list_try_rw_lock(USER_LIST_TRY_LOCK_WAIT_TIME);          {
1221          if (ret == 0) // success                  log_error("user_stat_get(uid=%d) error: %d\n", uid, ret);
1222          {                  return -1;
1223              break;          }
1224          }          else if (ret == 0) // user not found
1225          else if (errno == EAGAIN || errno == EINTR) // retry          {
1226          {                  return -1;
1227              timer++;          }
             if (timer % USER_LIST_TRY_LOCK_TIMES == 0)  
             {  
                 log_error("user_list_try_rw_lock() tried %d times\n", timer);  
             }  
         }  
         else // failed  
         {  
             log_error("user_list_try_rw_lock() failed\n");  
             break;  
         }  
     }  
1228    
1229      return ret;          return p_stat->article_count;
1230  }  }


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

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