/[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.26 - (hide annotations)
Tue Nov 4 13:49:51 2025 UTC (4 months, 1 week ago) by sysadm
Branch: MAIN
Changes since 1.25: +7 -15 lines
Content type: text/x-csrc
Update file header information comments

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

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