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

Annotation of /lbbs/src/user_list.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.31 - (hide annotations)
Sun Nov 9 06:44:02 2025 UTC (4 months, 1 week ago) by sysadm
Branch: MAIN
Changes since 1.30: +1 -1 lines
Content type: text/x-csrc
Fix bug

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

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