/[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.37 - (hide annotations)
Tue Nov 18 14:43:35 2025 UTC (3 months, 4 weeks ago) by sysadm
Branch: MAIN
Changes since 1.36: +66 -67 lines
Content type: text/x-csrc
Fix issue caused by address change during SHM remap

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

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