/[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.29 - (hide annotations)
Wed Nov 5 04:19:21 2025 UTC (4 months, 1 week ago) by sysadm
Branch: MAIN
Changes since 1.28: +5 -2 lines
Content type: text/x-csrc
Use enum / const int instead of macro define constant integers
Use const char * instead of macro define for constant strings

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     p_list->users[i].birthday = (row[10] == NULL ? 0 : atol(row[11]));
188     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.15
342 sysadm 1.10 #ifdef _DEBUG
343 sysadm 1.23 log_error("Rebuild index of %d online users\n", user_cnt);
344 sysadm 1.10 #endif
345     }
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     #ifdef _DEBUG
351 sysadm 1.23 log_error("Loaded %d online users and %d guest users\n", p_list->user_count, p_list->guest_count);
352 sysadm 1.6 #endif
353    
354     cleanup:
355     mysql_free_result(rs);
356    
357     return ret;
358 sysadm 1.1 }
359    
360 sysadm 1.24 int user_login_count_load(MYSQL *db)
361     {
362     MYSQL_RES *rs = NULL;
363     MYSQL_ROW row;
364     char sql[SQL_BUFFER_LEN];
365    
366     if (db == NULL)
367     {
368     log_error("NULL pointer error\n");
369     return -1;
370     }
371    
372     snprintf(sql, sizeof(sql),
373     "SELECT ID FROM user_login_log ORDER BY ID DESC LIMIT 1");
374     if (mysql_query(db, sql) != 0)
375     {
376     log_error("Query user_login_log error: %s\n", mysql_error(db));
377     return -2;
378     }
379     if ((rs = mysql_store_result(db)) == NULL)
380     {
381     log_error("Get user_login_log data failed\n");
382     return -2;
383     }
384     if ((row = mysql_fetch_row(rs)))
385     {
386     p_user_list_pool->user_login_count = atoi(row[0]);
387     }
388     mysql_free_result(rs);
389    
390     return 0;
391     }
392    
393 sysadm 1.22 int user_list_pool_init(const char *filename)
394 sysadm 1.1 {
395 sysadm 1.6 int shmid;
396     int semid;
397     int proj_id;
398     key_t key;
399     size_t size;
400     void *p_shm;
401     union semun arg;
402     int i;
403    
404     if (p_user_list_pool != NULL || p_trie_action_dict != NULL)
405     {
406     log_error("p_user_list_pool already initialized\n");
407     return -1;
408     }
409    
410     p_trie_action_dict = trie_dict_create();
411     if (p_trie_action_dict == NULL)
412     {
413     log_error("trie_dict_create() error\n");
414     return -1;
415     }
416    
417     for (i = 0; i < user_action_map_size; i++)
418     {
419     if (trie_dict_set(p_trie_action_dict, user_action_map[i].name, (int64_t)(user_action_map[i].title)) < 0)
420     {
421     log_error("trie_dict_set(p_trie_action_dict, %s) error\n", user_action_map[i].name);
422     }
423     }
424    
425     // Allocate shared memory
426     proj_id = (int)(time(NULL) % getpid());
427 sysadm 1.22 key = ftok(filename, proj_id);
428 sysadm 1.6 if (key == -1)
429     {
430 sysadm 1.22 log_error("ftok(%s %d) error (%d)\n", filename, proj_id, errno);
431 sysadm 1.6 return -2;
432     }
433    
434     size = sizeof(USER_LIST_POOL);
435     shmid = shmget(key, size, IPC_CREAT | IPC_EXCL | 0600);
436     if (shmid == -1)
437     {
438     log_error("shmget(size = %d) error (%d)\n", size, errno);
439     return -3;
440     }
441     p_shm = shmat(shmid, NULL, 0);
442     if (p_shm == (void *)-1)
443     {
444     log_error("shmat(shmid=%d) error (%d)\n", shmid, errno);
445     return -3;
446     }
447    
448     p_user_list_pool = p_shm;
449     p_user_list_pool->shmid = shmid;
450    
451     // Allocate semaphore as user list pool lock
452     size = 2; // r_sem and w_sem
453     semid = semget(key, (int)size, IPC_CREAT | IPC_EXCL | 0600);
454     if (semid == -1)
455     {
456     log_error("semget(user_list_pool_sem, size = %d) error (%d)\n", size, errno);
457     return -3;
458     }
459    
460     // Initialize sem value to 0
461     arg.val = 0;
462     for (i = 0; i < size; i++)
463     {
464     if (semctl(semid, i, SETVAL, arg) == -1)
465     {
466     log_error("semctl(user_list_pool_sem, SETVAL) error (%d)\n", errno);
467     return -3;
468     }
469     }
470    
471     p_user_list_pool->semid = semid;
472    
473     // Set user counts to 0
474     p_user_list_pool->user_list[0].user_count = 0;
475     p_user_list_pool->user_list[1].user_count = 0;
476    
477     p_user_list_pool->p_current = &(p_user_list_pool->user_list[0]);
478     p_user_list_pool->p_new = &(p_user_list_pool->user_list[1]);
479 sysadm 1.1
480 sysadm 1.6 p_user_list_pool->p_online_current = &(p_user_list_pool->user_online_list[0]);
481     p_user_list_pool->p_online_new = &(p_user_list_pool->user_online_list[1]);
482 sysadm 1.1
483 sysadm 1.18 user_stat_map_init(&(p_user_list_pool->user_stat_map));
484    
485 sysadm 1.6 return 0;
486 sysadm 1.1 }
487    
488     void user_list_pool_cleanup(void)
489     {
490 sysadm 1.6 int shmid;
491 sysadm 1.1
492 sysadm 1.6 if (p_user_list_pool == NULL)
493     {
494     return;
495     }
496    
497     shmid = p_user_list_pool->shmid;
498    
499     if (semctl(p_user_list_pool->semid, 0, IPC_RMID) == -1)
500     {
501     log_error("semctl(semid = %d, IPC_RMID) error (%d)\n", p_user_list_pool->semid, errno);
502     }
503    
504     if (shmdt(p_user_list_pool) == -1)
505     {
506     log_error("shmdt(shmid = %d) error (%d)\n", shmid, errno);
507     }
508    
509 sysadm 1.27 if (shmid != 0 && shmctl(shmid, IPC_RMID, NULL) == -1)
510 sysadm 1.6 {
511     log_error("shmctl(shmid = %d, IPC_RMID) error (%d)\n", shmid, errno);
512     }
513    
514     p_user_list_pool = NULL;
515    
516     if (p_trie_action_dict != NULL)
517     {
518     trie_dict_destroy(p_trie_action_dict);
519 sysadm 1.1
520 sysadm 1.6 p_trie_action_dict = NULL;
521     }
522 sysadm 1.1 }
523    
524     int set_user_list_pool_shm_readonly(void)
525     {
526 sysadm 1.6 int shmid;
527     void *p_shm;
528 sysadm 1.1
529 sysadm 1.6 if (p_user_list_pool == NULL)
530     {
531     log_error("p_user_list_pool not initialized\n");
532     return -1;
533     }
534    
535     shmid = p_user_list_pool->shmid;
536    
537     // Remap shared memory in read-only mode
538     p_shm = shmat(shmid, p_user_list_pool, SHM_RDONLY | SHM_REMAP);
539     if (p_shm == (void *)-1)
540     {
541     log_error("shmat(user_list_pool shmid = %d) error (%d)\n", shmid, errno);
542     return -3;
543     }
544 sysadm 1.1
545 sysadm 1.6 p_user_list_pool = p_shm;
546 sysadm 1.1
547 sysadm 1.6 return 0;
548 sysadm 1.1 }
549    
550     int detach_user_list_pool_shm(void)
551     {
552 sysadm 1.6 if (p_user_list_pool != NULL && shmdt(p_user_list_pool) == -1)
553     {
554     log_error("shmdt(user_list_pool) error (%d)\n", errno);
555     return -1;
556     }
557    
558     p_user_list_pool = NULL;
559    
560     return 0;
561     }
562    
563     int user_list_pool_reload(int online_user)
564     {
565     MYSQL *db = NULL;
566     USER_LIST *p_tmp;
567     USER_ONLINE_LIST *p_online_tmp;
568 sysadm 1.11 int ret = 0;
569 sysadm 1.6
570     if (p_user_list_pool == NULL)
571     {
572     log_error("p_user_list_pool not initialized\n");
573     return -1;
574     }
575    
576     db = db_open();
577     if (db == NULL)
578     {
579     log_error("db_open() error: %s\n", mysql_error(db));
580     return -1;
581     }
582    
583     if (online_user)
584     {
585     if (user_online_list_load(db, p_user_list_pool->p_online_new) < 0)
586     {
587     log_error("user_online_list_load() error\n");
588 sysadm 1.11 ret = -2;
589     goto cleanup;
590 sysadm 1.6 }
591 sysadm 1.24
592     if (user_login_count_load(db) < 0)
593     {
594     log_error("user_login_count_load() error\n");
595     ret = -2;
596     goto cleanup;
597     }
598 sysadm 1.6 }
599     else
600     {
601     if (user_list_load(db, p_user_list_pool->p_new) < 0)
602     {
603     log_error("user_list_load() error\n");
604 sysadm 1.11 ret = -2;
605     goto cleanup;
606 sysadm 1.6 }
607     }
608    
609     mysql_close(db);
610 sysadm 1.11 db = NULL;
611 sysadm 1.6
612     if (user_list_rw_lock(p_user_list_pool->semid) < 0)
613     {
614     log_error("user_list_rw_lock() error\n");
615 sysadm 1.11 ret = -3;
616     goto cleanup;
617 sysadm 1.6 }
618    
619     if (online_user)
620     {
621     // Swap p_online_current and p_online_new
622     p_online_tmp = p_user_list_pool->p_online_current;
623     p_user_list_pool->p_online_current = p_user_list_pool->p_online_new;
624     p_user_list_pool->p_online_new = p_online_tmp;
625     }
626     else
627     {
628     // Swap p_current and p_new
629     p_tmp = p_user_list_pool->p_current;
630     p_user_list_pool->p_current = p_user_list_pool->p_new;
631     p_user_list_pool->p_new = p_tmp;
632     }
633    
634     if (user_list_rw_unlock(p_user_list_pool->semid) < 0)
635     {
636     log_error("user_list_rw_unlock() error\n");
637 sysadm 1.11 ret = -3;
638     goto cleanup;
639 sysadm 1.6 }
640 sysadm 1.1
641 sysadm 1.11 cleanup:
642     mysql_close(db);
643    
644     return ret;
645 sysadm 1.1 }
646    
647 sysadm 1.5 int user_list_try_rd_lock(int semid, int wait_sec)
648 sysadm 1.1 {
649 sysadm 1.6 struct sembuf sops[2];
650     struct timespec timeout;
651     int ret;
652    
653     sops[0].sem_num = 1; // w_sem
654     sops[0].sem_op = 0; // wait until unlocked
655     sops[0].sem_flg = 0;
656    
657     sops[1].sem_num = 0; // r_sem
658     sops[1].sem_op = 1; // lock
659     sops[1].sem_flg = SEM_UNDO; // undo on terminate
660    
661     timeout.tv_sec = wait_sec;
662     timeout.tv_nsec = 0;
663    
664     ret = semtimedop(semid, sops, 2, &timeout);
665     if (ret == -1 && errno != EAGAIN && errno != EINTR)
666     {
667     log_error("semtimedop(lock read) error %d\n", errno);
668     }
669 sysadm 1.1
670 sysadm 1.6 return ret;
671 sysadm 1.1 }
672    
673 sysadm 1.5 int user_list_try_rw_lock(int semid, int wait_sec)
674 sysadm 1.1 {
675 sysadm 1.6 struct sembuf sops[3];
676     struct timespec timeout;
677     int ret;
678    
679     sops[0].sem_num = 1; // w_sem
680     sops[0].sem_op = 0; // wait until unlocked
681     sops[0].sem_flg = 0;
682    
683     sops[1].sem_num = 1; // w_sem
684     sops[1].sem_op = 1; // lock
685     sops[1].sem_flg = SEM_UNDO; // undo on terminate
686    
687     sops[2].sem_num = 0; // r_sem
688     sops[2].sem_op = 0; // wait until unlocked
689     sops[2].sem_flg = 0;
690    
691     timeout.tv_sec = wait_sec;
692     timeout.tv_nsec = 0;
693    
694     ret = semtimedop(semid, sops, 3, &timeout);
695     if (ret == -1 && errno != EAGAIN && errno != EINTR)
696     {
697     log_error("semtimedop(lock write) error %d\n", errno);
698     }
699 sysadm 1.1
700 sysadm 1.6 return ret;
701 sysadm 1.1 }
702    
703 sysadm 1.5 int user_list_rd_unlock(int semid)
704 sysadm 1.1 {
705 sysadm 1.6 struct sembuf sops[2];
706     int ret;
707 sysadm 1.1
708 sysadm 1.6 sops[0].sem_num = 0; // r_sem
709     sops[0].sem_op = -1; // unlock
710     sops[0].sem_flg = IPC_NOWAIT | SEM_UNDO; // no wait
711    
712     ret = semop(semid, sops, 1);
713     if (ret == -1 && errno != EAGAIN && errno != EINTR)
714     {
715     log_error("semop(unlock read) error %d\n", errno);
716     }
717 sysadm 1.1
718 sysadm 1.6 return ret;
719 sysadm 1.1 }
720    
721 sysadm 1.5 int user_list_rw_unlock(int semid)
722 sysadm 1.1 {
723 sysadm 1.6 struct sembuf sops[1];
724     int ret;
725 sysadm 1.1
726 sysadm 1.6 sops[0].sem_num = 1; // w_sem
727     sops[0].sem_op = -1; // unlock
728     sops[0].sem_flg = IPC_NOWAIT | SEM_UNDO; // no wait
729    
730     ret = semop(semid, sops, 1);
731     if (ret == -1 && errno != EAGAIN && errno != EINTR)
732     {
733     log_error("semop(unlock write) error %d\n", errno);
734     }
735 sysadm 1.1
736 sysadm 1.6 return ret;
737 sysadm 1.1 }
738    
739 sysadm 1.5 int user_list_rd_lock(int semid)
740 sysadm 1.1 {
741 sysadm 1.6 int timer = 0;
742     int ret = -1;
743 sysadm 1.1
744 sysadm 1.6 while (!SYS_server_exit)
745     {
746     ret = user_list_try_rd_lock(semid, USER_LIST_TRY_LOCK_WAIT_TIME);
747     if (ret == 0) // success
748     {
749     break;
750     }
751     else if (errno == EAGAIN || errno == EINTR) // retry
752     {
753     timer++;
754     if (timer % USER_LIST_TRY_LOCK_TIMES == 0)
755     {
756     log_error("user_list_try_rd_lock() tried %d times\n", timer);
757     }
758     }
759     else // failed
760     {
761     log_error("user_list_try_rd_lock() failed\n");
762     break;
763     }
764     }
765 sysadm 1.1
766 sysadm 1.6 return ret;
767 sysadm 1.1 }
768    
769 sysadm 1.5 int user_list_rw_lock(int semid)
770 sysadm 1.1 {
771 sysadm 1.6 int timer = 0;
772     int ret = -1;
773 sysadm 1.1
774 sysadm 1.6 while (!SYS_server_exit)
775     {
776     ret = user_list_try_rw_lock(semid, USER_LIST_TRY_LOCK_WAIT_TIME);
777     if (ret == 0) // success
778     {
779     break;
780     }
781     else if (errno == EAGAIN || errno == EINTR) // retry
782     {
783     timer++;
784     if (timer % USER_LIST_TRY_LOCK_TIMES == 0)
785     {
786     log_error("user_list_try_rw_lock() tried %d times\n", timer);
787     }
788     }
789     else // failed
790     {
791     log_error("user_list_try_rw_lock() failed\n");
792     break;
793     }
794     }
795 sysadm 1.1
796 sysadm 1.6 return ret;
797 sysadm 1.1 }
798 sysadm 1.2
799     int query_user_list(int page_id, USER_INFO *p_users, int *p_user_count, int *p_page_count)
800     {
801 sysadm 1.6 int ret = 0;
802 sysadm 1.2
803 sysadm 1.6 if (p_users == NULL || p_user_count == NULL || p_page_count == NULL)
804     {
805     log_error("NULL pointer error\n");
806     return -1;
807     }
808    
809 sysadm 1.12 *p_user_count = 0;
810     *p_page_count = 0;
811    
812 sysadm 1.6 // acquire lock of user list
813     if (user_list_rd_lock(p_user_list_pool->semid) < 0)
814     {
815     log_error("user_list_rd_lock() error\n");
816     return -2;
817     }
818    
819     if (p_user_list_pool->p_current->user_count == 0)
820     {
821     // empty list
822     ret = 0;
823     goto cleanup;
824     }
825    
826     *p_page_count = p_user_list_pool->p_current->user_count / BBS_user_limit_per_page +
827     (p_user_list_pool->p_current->user_count % BBS_user_limit_per_page == 0 ? 0 : 1);
828    
829     if (page_id < 0 || page_id >= *p_page_count)
830     {
831     log_error("Invalid page_id = %d, not in range [0, %d)\n", page_id, *p_page_count);
832     ret = -3;
833     goto cleanup;
834     }
835    
836     *p_user_count = MIN(BBS_user_limit_per_page,
837     p_user_list_pool->p_current->user_count -
838     page_id * BBS_user_limit_per_page);
839    
840     memcpy(p_users,
841     p_user_list_pool->p_current->users + page_id * BBS_user_limit_per_page,
842     sizeof(USER_INFO) * (size_t)(*p_user_count));
843    
844     cleanup:
845     // release lock of user list
846     if (user_list_rd_unlock(p_user_list_pool->semid) < 0)
847     {
848     log_error("user_list_rd_unlock() error\n");
849     ret = -1;
850     }
851    
852     return ret;
853     }
854    
855     int query_user_online_list(int page_id, USER_ONLINE_INFO *p_online_users, int *p_user_count, int *p_page_count)
856     {
857     int ret = 0;
858    
859     if (p_online_users == NULL || p_user_count == NULL || p_page_count == NULL)
860     {
861     log_error("NULL pointer error\n");
862     return -1;
863     }
864    
865 sysadm 1.12 *p_user_count = 0;
866     *p_page_count = 0;
867    
868 sysadm 1.6 // acquire lock of user list
869     if (user_list_rd_lock(p_user_list_pool->semid) < 0)
870     {
871     log_error("user_list_rd_lock() error\n");
872     return -2;
873     }
874    
875     if (p_user_list_pool->p_online_current->user_count == 0)
876     {
877     // empty list
878     ret = 0;
879     goto cleanup;
880     }
881    
882     *p_page_count = p_user_list_pool->p_online_current->user_count / BBS_user_limit_per_page +
883     (p_user_list_pool->p_online_current->user_count % BBS_user_limit_per_page == 0 ? 0 : 1);
884    
885     if (page_id < 0 || page_id >= *p_page_count)
886     {
887     log_error("Invalid page_id = %d, not in range [0, %d)\n", page_id, *p_page_count);
888     ret = -3;
889     goto cleanup;
890     }
891    
892     *p_user_count = MIN(BBS_user_limit_per_page,
893     p_user_list_pool->p_online_current->user_count -
894     page_id * BBS_user_limit_per_page);
895    
896     memcpy(p_online_users,
897     p_user_list_pool->p_online_current->users + page_id * BBS_user_limit_per_page,
898     sizeof(USER_ONLINE_INFO) * (size_t)(*p_user_count));
899 sysadm 1.2
900     cleanup:
901 sysadm 1.6 // release lock of user list
902     if (user_list_rd_unlock(p_user_list_pool->semid) < 0)
903     {
904     log_error("user_list_rd_unlock() error\n");
905     ret = -1;
906     }
907 sysadm 1.2
908 sysadm 1.6 return ret;
909 sysadm 1.2 }
910 sysadm 1.4
911 sysadm 1.23 int get_user_list_count(int *p_user_cnt)
912     {
913     if (p_user_cnt == NULL)
914     {
915     log_error("NULL pointer error\n");
916     return -1;
917     }
918    
919     // acquire lock of user list
920     if (user_list_rd_lock(p_user_list_pool->semid) < 0)
921     {
922     log_error("user_list_rd_lock() error\n");
923     return -2;
924     }
925    
926     *p_user_cnt = p_user_list_pool->p_current->user_count;
927    
928     // release lock of user list
929     if (user_list_rd_unlock(p_user_list_pool->semid) < 0)
930     {
931     log_error("user_list_rd_unlock() error\n");
932     return -2;
933     }
934    
935     return 0;
936     }
937    
938     int get_user_online_list_count(int *p_user_cnt, int *p_guest_cnt)
939     {
940     if (p_user_cnt == NULL || p_guest_cnt == NULL)
941     {
942     log_error("NULL pointer error\n");
943     return -1;
944     }
945    
946     // acquire lock of user list
947     if (user_list_rd_lock(p_user_list_pool->semid) < 0)
948     {
949     log_error("user_list_rd_lock() error\n");
950     return -2;
951     }
952    
953     *p_user_cnt = p_user_list_pool->p_online_current->user_count;
954     *p_guest_cnt = p_user_list_pool->p_online_current->guest_count;
955    
956     // release lock of user list
957     if (user_list_rd_unlock(p_user_list_pool->semid) < 0)
958     {
959     log_error("user_list_rd_unlock() error\n");
960     return -2;
961     }
962    
963     return 0;
964     }
965    
966 sysadm 1.24 int get_user_login_count(int *p_login_cnt)
967     {
968     if (p_login_cnt == NULL)
969     {
970     log_error("NULL pointer error\n");
971     return -1;
972     }
973    
974     *p_login_cnt = p_user_list_pool->user_login_count;
975    
976     return 0;
977     }
978    
979 sysadm 1.8 int query_user_info(int32_t id, USER_INFO *p_user)
980     {
981     int ret = 0;
982    
983     if (p_user == NULL)
984     {
985     log_error("NULL pointer error\n");
986     return -1;
987     }
988    
989     // acquire lock of user list
990     if (user_list_rd_lock(p_user_list_pool->semid) < 0)
991     {
992     log_error("user_list_rd_lock() error\n");
993     return -2;
994     }
995    
996     if (id >= 0 && id < p_user_list_pool->p_current->user_count) // Found
997     {
998     *p_user = p_user_list_pool->p_current->users[id];
999     ret = 1;
1000     }
1001    
1002     // release lock of user list
1003     if (user_list_rd_unlock(p_user_list_pool->semid) < 0)
1004     {
1005     log_error("user_list_rd_unlock() error\n");
1006     ret = -1;
1007     }
1008    
1009     return ret;
1010     }
1011    
1012 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)
1013 sysadm 1.4 {
1014 sysadm 1.6 int left;
1015     int right;
1016     int mid;
1017 sysadm 1.8 int32_t id;
1018 sysadm 1.6 int ret = 0;
1019    
1020     if (p_user == NULL)
1021     {
1022     log_error("NULL pointer error\n");
1023     return -1;
1024     }
1025    
1026     // acquire lock of user list
1027     if (user_list_rd_lock(p_user_list_pool->semid) < 0)
1028     {
1029     log_error("user_list_rd_lock() error\n");
1030     return -2;
1031     }
1032    
1033     left = 0;
1034     right = p_user_list_pool->p_current->user_count - 1;
1035    
1036     while (left < right)
1037     {
1038     mid = (left + right) / 2;
1039 sysadm 1.8 if (uid < p_user_list_pool->p_current->index_uid[mid].uid)
1040 sysadm 1.6 {
1041 sysadm 1.22 right = mid - 1;
1042 sysadm 1.6 }
1043 sysadm 1.8 else if (uid > p_user_list_pool->p_current->index_uid[mid].uid)
1044 sysadm 1.6 {
1045     left = mid + 1;
1046     }
1047 sysadm 1.8 else // if (uid == p_user_list_pool->p_current->index_uid[mid].uid)
1048 sysadm 1.6 {
1049     left = mid;
1050     break;
1051     }
1052     }
1053    
1054 sysadm 1.8 if (uid == p_user_list_pool->p_current->index_uid[left].uid) // Found
1055     {
1056     id = p_user_list_pool->p_current->index_uid[left].id;
1057 sysadm 1.12 *p_user = p_user_list_pool->p_current->users[id];
1058     ret = 1;
1059 sysadm 1.25
1060     if (p_intro_buf != NULL)
1061     {
1062     strncpy(p_intro_buf, p_user_list_pool->p_current->users[id].intro, intro_buf_len - 1);
1063     p_intro_buf[intro_buf_len - 1] = '\0';
1064     p_user->intro = p_intro_buf;
1065     }
1066     }
1067    
1068     // release lock of user list
1069     if (user_list_rd_unlock(p_user_list_pool->semid) < 0)
1070     {
1071     log_error("user_list_rd_unlock() error\n");
1072     ret = -1;
1073 sysadm 1.8 }
1074    
1075 sysadm 1.25 return ret;
1076     }
1077    
1078     int query_user_info_by_username(const char *username_prefix, int max_user_cnt,
1079     int32_t uid_list[], char username_list[][BBS_username_max_len + 1])
1080     {
1081     int left;
1082     int right;
1083     int mid;
1084     int left_save;
1085     int ret = 0;
1086     size_t prefix_len;
1087     int comp;
1088     int i;
1089    
1090     if (username_prefix == NULL || uid_list == NULL || username_list == NULL)
1091     {
1092     log_error("NULL pointer error\n");
1093     return -1;
1094     }
1095    
1096     prefix_len = strlen(username_prefix);
1097    
1098     // acquire lock of user list
1099     if (user_list_rd_lock(p_user_list_pool->semid) < 0)
1100     {
1101     log_error("user_list_rd_lock() error\n");
1102     return -2;
1103     }
1104    
1105     left = 0;
1106     right = p_user_list_pool->p_current->user_count - 1;
1107    
1108     while (left < right)
1109     {
1110     mid = (left + right) / 2;
1111     comp = strncasecmp(username_prefix, p_user_list_pool->p_current->users[mid].username, prefix_len);
1112     if (comp < 0)
1113     {
1114     right = mid - 1;
1115     }
1116     else if (comp > 0)
1117     {
1118     left = mid + 1;
1119     }
1120     else // if (comp == 0)
1121     {
1122     left = mid;
1123     break;
1124     }
1125     }
1126    
1127     if (strncasecmp(username_prefix, p_user_list_pool->p_current->users[left].username, prefix_len) == 0) // Found
1128     {
1129     #ifdef _DEBUG
1130     log_error("Debug: match found, pos=%d\n", left);
1131     #endif
1132    
1133     left_save = left;
1134     right = left;
1135     left = 0;
1136    
1137     while (left < right)
1138     {
1139     mid = (left + right) / 2;
1140     comp = strncasecmp(username_prefix, p_user_list_pool->p_current->users[mid].username, prefix_len);
1141     if (comp > 0)
1142     {
1143     left = mid + 1;
1144     }
1145     else if (comp == 0)
1146     {
1147     right = mid;
1148     }
1149     else // if (comp < 0)
1150     {
1151     log_error("Bug: left=%d right=%d mid=%d");
1152     ret = -2;
1153     goto cleanup;
1154     }
1155     }
1156    
1157     #ifdef _DEBUG
1158     log_error("Debug: first match found, pos=%d\n", right);
1159     #endif
1160    
1161     left = left_save;
1162     left_save = right;
1163     right = p_user_list_pool->p_current->user_count - 1;
1164    
1165     while (left < right)
1166     {
1167     mid = (left + right) / 2 + (left + right) % 2;
1168     comp = strncasecmp(username_prefix, p_user_list_pool->p_current->users[mid].username, prefix_len);
1169     if (comp < 0)
1170     {
1171     right = mid - 1;
1172     }
1173     else if (comp == 0)
1174     {
1175     left = mid;
1176     }
1177     else // if (comp > 0)
1178     {
1179     log_error("Bug: left=%d right=%d mid=%d");
1180     ret = -2;
1181     goto cleanup;
1182     }
1183     }
1184    
1185     #ifdef _DEBUG
1186     log_error("Debug: last match found, pos=%d\n", left);
1187     #endif
1188    
1189     right = left;
1190     left = left_save;
1191    
1192     for (i = 0; i < max_user_cnt && left + i <= right; i++)
1193     {
1194     uid_list[i] = p_user_list_pool->p_current->users[left + i].uid;
1195     strncpy(username_list[i], p_user_list_pool->p_current->users[left + i].username, sizeof(username_list[i]) - 1);
1196     username_list[i][sizeof(username_list[i]) - 1] = '\0';
1197     }
1198     ret = i;
1199     }
1200    
1201     cleanup:
1202 sysadm 1.8 // release lock of user list
1203     if (user_list_rd_unlock(p_user_list_pool->semid) < 0)
1204     {
1205     log_error("user_list_rd_unlock() error\n");
1206     ret = -1;
1207     }
1208    
1209     return ret;
1210     }
1211    
1212     int query_user_online_info(int32_t id, USER_ONLINE_INFO *p_user)
1213     {
1214     int ret = 0;
1215    
1216     if (p_user == NULL)
1217     {
1218     log_error("NULL pointer error\n");
1219     return -1;
1220     }
1221    
1222     // acquire lock of user list
1223     if (user_list_rd_lock(p_user_list_pool->semid) < 0)
1224     {
1225     log_error("user_list_rd_lock() error\n");
1226     return -2;
1227     }
1228    
1229     if (id >= 0 && id < p_user_list_pool->p_online_current->user_count) // Found
1230 sysadm 1.6 {
1231 sysadm 1.8 *p_user = p_user_list_pool->p_online_current->users[id];
1232 sysadm 1.6 ret = 1;
1233     }
1234    
1235     // release lock of user list
1236     if (user_list_rd_unlock(p_user_list_pool->semid) < 0)
1237     {
1238     log_error("user_list_rd_unlock() error\n");
1239     ret = -1;
1240     }
1241 sysadm 1.4
1242 sysadm 1.6 return ret;
1243 sysadm 1.4 }
1244 sysadm 1.11
1245     int query_user_online_info_by_uid(int32_t uid, USER_ONLINE_INFO *p_users, int *p_user_cnt, int start_id)
1246     {
1247     int left;
1248     int right;
1249     int mid;
1250     int32_t id;
1251     int ret = 0;
1252     int i;
1253 sysadm 1.20 int user_cnt;
1254 sysadm 1.11
1255     if (p_users == NULL || p_user_cnt == NULL)
1256     {
1257     log_error("NULL pointer error\n");
1258     return -1;
1259     }
1260    
1261 sysadm 1.20 user_cnt = *p_user_cnt;
1262     *p_user_cnt = 0;
1263    
1264 sysadm 1.11 // acquire lock of user list
1265     if (user_list_rd_lock(p_user_list_pool->semid) < 0)
1266     {
1267     log_error("user_list_rd_lock() error\n");
1268     return -2;
1269     }
1270    
1271     left = start_id;
1272     right = p_user_list_pool->p_online_current->user_count - 1;
1273    
1274     while (left < right)
1275     {
1276     mid = (left + right) / 2;
1277     if (uid < p_user_list_pool->p_online_current->index_uid[mid].uid)
1278     {
1279 sysadm 1.22 right = mid - 1;
1280 sysadm 1.11 }
1281     else if (uid > p_user_list_pool->p_online_current->index_uid[mid].uid)
1282     {
1283     left = mid + 1;
1284     }
1285     else // if (uid == p_user_list_pool->p_online_current->index_uid[mid].uid)
1286     {
1287     left = mid;
1288     break;
1289     }
1290     }
1291    
1292     if (uid == p_user_list_pool->p_online_current->index_uid[left].uid)
1293     {
1294     right = left;
1295     left = start_id;
1296    
1297     while (left < right)
1298     {
1299     mid = (left + right) / 2;
1300     if (uid - 1 < p_user_list_pool->p_online_current->index_uid[mid].uid)
1301     {
1302     right = mid;
1303     }
1304     else // if (uid - 1 >= p_user_list_pool->p_online_current->index_uid[mid].uid)
1305     {
1306     left = mid + 1;
1307     }
1308     }
1309    
1310 sysadm 1.13 for (i = 0;
1311 sysadm 1.20 left < p_user_list_pool->p_online_current->user_count && i < user_cnt &&
1312 sysadm 1.13 uid == p_user_list_pool->p_online_current->index_uid[left].uid;
1313     left++, i++)
1314 sysadm 1.11 {
1315 sysadm 1.13 id = p_user_list_pool->p_online_current->index_uid[left].id;
1316 sysadm 1.12 p_users[i] = p_user_list_pool->p_online_current->users[id];
1317 sysadm 1.11 }
1318    
1319 sysadm 1.12 if (i > 0)
1320 sysadm 1.11 {
1321     *p_user_cnt = i;
1322     ret = 1;
1323     }
1324     }
1325    
1326     // release lock of user list
1327     if (user_list_rd_unlock(p_user_list_pool->semid) < 0)
1328     {
1329     log_error("user_list_rd_unlock() error\n");
1330     ret = -1;
1331     }
1332    
1333     return ret;
1334     }
1335 sysadm 1.18
1336     int get_user_id_list(int32_t *p_uid_list, int *p_user_cnt, int start_uid)
1337     {
1338     int left;
1339     int right;
1340     int mid;
1341     int ret = 0;
1342     int i;
1343    
1344     if (p_uid_list == NULL || p_user_cnt == NULL)
1345     {
1346     log_error("NULL pointer error\n");
1347     return -1;
1348     }
1349    
1350     // acquire lock of user list
1351     if (user_list_rd_lock(p_user_list_pool->semid) < 0)
1352     {
1353     log_error("user_list_rd_lock() error\n");
1354     return -2;
1355     }
1356    
1357     left = 0;
1358     right = p_user_list_pool->p_current->user_count - 1;
1359    
1360     while (left < right)
1361     {
1362     mid = (left + right) / 2;
1363     if (start_uid < p_user_list_pool->p_current->index_uid[mid].uid)
1364     {
1365 sysadm 1.22 right = mid - 1;
1366 sysadm 1.18 }
1367     else if (start_uid > p_user_list_pool->p_current->index_uid[mid].uid)
1368     {
1369     left = mid + 1;
1370     }
1371     else // if (start_uid == p_user_list_pool->p_current->index_uid[mid].uid)
1372     {
1373     left = mid;
1374     break;
1375     }
1376     }
1377    
1378     for (i = 0; i < *p_user_cnt && left + i < p_user_list_pool->p_current->user_count; i++)
1379     {
1380     p_uid_list[i] = p_user_list_pool->p_current->index_uid[left + i].uid;
1381     }
1382     *p_user_cnt = i;
1383    
1384     // release lock of user list
1385     if (user_list_rd_unlock(p_user_list_pool->semid) < 0)
1386     {
1387     log_error("user_list_rd_unlock() error\n");
1388     ret = -1;
1389     }
1390    
1391     return ret;
1392     }
1393    
1394     int user_stat_update(void)
1395     {
1396     return user_stat_map_update(&(p_user_list_pool->user_stat_map));
1397     }
1398    
1399 sysadm 1.19 int user_article_cnt_inc(int32_t uid, int n)
1400     {
1401     return user_stat_article_cnt_inc(&(p_user_list_pool->user_stat_map), uid, n);
1402     }
1403    
1404     int get_user_article_cnt(int32_t uid)
1405 sysadm 1.18 {
1406     const USER_STAT *p_stat;
1407     int ret;
1408    
1409     ret = user_stat_get(&(p_user_list_pool->user_stat_map), uid, &p_stat);
1410     if (ret < 0)
1411     {
1412     log_error("user_stat_get(uid=%d) error: %d\n", uid, ret);
1413     return -1;
1414     }
1415     else if (ret == 0) // user not found
1416     {
1417     return -1;
1418     }
1419    
1420     return p_stat->article_count;
1421     }

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