/[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.25 - (hide annotations)
Sun Nov 2 14:38:53 2025 UTC (4 months, 1 week ago) by sysadm
Branch: MAIN
Changes since 1.24: +165 -24 lines
Content type: text/x-csrc
Add user search in user list display
Fix bug: memory of user introduction pointed by USER_INFO.intro might be overwritten during user_list_pool_reload(),
         use external buffer passed into query_user_info_by_uid() to prevent this issue.

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

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