/[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.10 - (hide annotations)
Wed Oct 22 10:38:23 2025 UTC (4 months, 3 weeks ago) by sysadm
Branch: MAIN
Changes since 1.9: +43 -4 lines
Content type: text/x-csrc
Optimize index rebuild

1 sysadm 1.1 /***************************************************************************
2 sysadm 1.6 user_list.c - description
3     -------------------
4     Copyright : (C) 2004-2025 by Leaflet
5     Email : leaflet@leafok.com
6 sysadm 1.1 ***************************************************************************/
7    
8     /***************************************************************************
9     * *
10     * This program is free software; you can redistribute it and/or modify *
11     * it under the terms of the GNU General Public License as published by *
12     * the Free Software Foundation; either version 3 of the License, or *
13     * (at your option) any later version. *
14     * *
15     ***************************************************************************/
16    
17     #include "common.h"
18     #include "database.h"
19     #include "log.h"
20 sysadm 1.6 #include "trie_dict.h"
21 sysadm 1.1 #include "user_list.h"
22     #include <errno.h>
23     #include <stdlib.h>
24     #include <string.h>
25     #include <time.h>
26     #include <sys/ipc.h>
27     #include <sys/mman.h>
28 sysadm 1.2 #include <sys/param.h>
29 sysadm 1.1 #include <sys/sem.h>
30     #include <sys/shm.h>
31    
32     #ifdef _SEM_SEMUN_UNDEFINED
33     union semun
34     {
35 sysadm 1.6 int val; /* Value for SETVAL */
36     struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */
37     unsigned short *array; /* Array for GETALL, SETALL */
38     struct seminfo *__buf; /* Buffer for IPC_INFO
39     (Linux-specific) */
40 sysadm 1.1 };
41     #endif // #ifdef _SEM_SEMUN_UNDEFINED
42    
43     #define USER_LIST_TRY_LOCK_WAIT_TIME 1 // second
44     #define USER_LIST_TRY_LOCK_TIMES 10
45    
46     struct user_list_pool_t
47     {
48 sysadm 1.6 int shmid;
49     int semid;
50     USER_LIST user_list[2];
51     USER_LIST *p_current;
52     USER_LIST *p_new;
53     USER_ONLINE_LIST user_online_list[2];
54     USER_ONLINE_LIST *p_online_current;
55     USER_ONLINE_LIST *p_online_new;
56 sysadm 1.1 };
57     typedef struct user_list_pool_t USER_LIST_POOL;
58    
59     static USER_LIST_POOL *p_user_list_pool = NULL;
60 sysadm 1.6 static TRIE_NODE *p_trie_action_dict = NULL;
61    
62     typedef struct user_action_map_t
63     {
64     char name[BBS_current_action_max_len + 1];
65     char title[BBS_current_action_max_len + 1];
66     } USER_ACTION_MAP;
67    
68     const USER_ACTION_MAP user_action_map[] =
69     {
70     {"ARTICLE_FAVOR", "浏览收藏"},
71     {"BBS_NET", "站点穿梭"},
72     {"CHICKEN", "电子小鸡"},
73     {"EDIT_ARTICLE", "修改文章"},
74 sysadm 1.7 {"LOGIN", "进入大厅"},
75 sysadm 1.6 {"MENU", "菜单选择"},
76     {"POST_ARTICLE", "撰写文章"},
77     {"REPLY_ARTICLE", "回复文章"},
78     {"USER_LIST", "查花名册"},
79     {"USER_ONLINE", "环顾四周"},
80     {"VIEW_ARTICLE", "阅读文章"},
81 sysadm 1.7 {"VIEW_FILE", "查看文档"},
82     {"WWW", "Web浏览"}};
83 sysadm 1.6
84 sysadm 1.7 const int user_action_map_size = sizeof(user_action_map) / sizeof(USER_ACTION_MAP);
85 sysadm 1.1
86 sysadm 1.5 static int user_list_try_rd_lock(int semid, int wait_sec);
87     static int user_list_try_rw_lock(int semid, int wait_sec);
88     static int user_list_rd_unlock(int semid);
89     static int user_list_rw_unlock(int semid);
90     static int user_list_rd_lock(int semid);
91     static int user_list_rw_lock(int semid);
92    
93 sysadm 1.6 static int user_list_load(MYSQL *db, USER_LIST *p_list);
94     static int user_online_list_load(MYSQL *db, USER_ONLINE_LIST *p_list);
95    
96 sysadm 1.8 static int user_info_index_uid_comp(const void *ptr1, const void *ptr2)
97     {
98     const USER_INFO_INDEX_UID *p1 = ptr1;
99     const USER_INFO_INDEX_UID *p2 = ptr2;
100    
101     if (p1->uid < p2->uid)
102     {
103     return -1;
104     }
105     else if (p1->uid > p2->uid)
106     {
107     return 1;
108     }
109 sysadm 1.10 else if (p1->id < p2->id)
110     {
111     return -1;
112     }
113     else if (p1->id > p2->id)
114     {
115     return 1;
116     }
117 sysadm 1.8 return 0;
118     }
119    
120 sysadm 1.1 int user_list_load(MYSQL *db, USER_LIST *p_list)
121     {
122 sysadm 1.6 MYSQL_RES *rs = NULL;
123     MYSQL_ROW row;
124     char sql[SQL_BUFFER_LEN];
125     int ret = 0;
126     int i;
127 sysadm 1.10 int32_t last_uid = -1;
128 sysadm 1.6
129     if (db == NULL || p_list == NULL)
130     {
131     log_error("NULL pointer error\n");
132     return -1;
133     }
134    
135 sysadm 1.10 if (p_list->user_count > 0)
136     {
137     last_uid = p_list->users[p_list->user_count - 1].uid;
138     }
139    
140 sysadm 1.6 snprintf(sql, sizeof(sql),
141     "SELECT user_list.UID AS UID, username, nickname, gender, gender_pub, life, exp, "
142     "UNIX_TIMESTAMP(signup_dt), UNIX_TIMESTAMP(last_login_dt), UNIX_TIMESTAMP(birthday) "
143     "FROM user_list INNER JOIN user_pubinfo ON user_list.UID = user_pubinfo.UID "
144     "INNER JOIN user_reginfo ON user_list.UID = user_reginfo.UID "
145 sysadm 1.8 "WHERE enable ORDER BY username");
146 sysadm 1.6
147     if (mysql_query(db, sql) != 0)
148     {
149     log_error("Query user info error: %s\n", mysql_error(db));
150     ret = -1;
151     goto cleanup;
152     }
153    
154     if ((rs = mysql_use_result(db)) == NULL)
155     {
156     log_error("Get user info data failed\n");
157     ret = -1;
158     goto cleanup;
159     }
160    
161     i = 0;
162     while ((row = mysql_fetch_row(rs)))
163     {
164 sysadm 1.8 // record
165     p_list->users[i].id = i;
166 sysadm 1.6 p_list->users[i].uid = atoi(row[0]);
167     strncpy(p_list->users[i].username, row[1], sizeof(p_list->users[i].username) - 1);
168     p_list->users[i].username[sizeof(p_list->users[i].username) - 1] = '\0';
169     strncpy(p_list->users[i].nickname, row[2], sizeof(p_list->users[i].nickname) - 1);
170     p_list->users[i].nickname[sizeof(p_list->users[i].nickname) - 1] = '\0';
171     p_list->users[i].gender = row[3][0];
172     p_list->users[i].gender_pub = (int8_t)(row[4] == NULL ? 0 : atoi(row[4]));
173     p_list->users[i].life = (row[5] == NULL ? 0 : atoi(row[5]));
174     p_list->users[i].exp = (row[6] == NULL ? 0 : atoi(row[6]));
175     p_list->users[i].signup_dt = (row[7] == NULL ? 0 : atol(row[7]));
176     p_list->users[i].last_login_dt = (row[8] == NULL ? 0 : atol(row[8]));
177     p_list->users[i].birthday = (row[9] == NULL ? 0 : atol(row[9]));
178    
179 sysadm 1.8 // index
180     p_list->index_uid[i].uid = p_list->users[i].uid;
181     p_list->index_uid[i].id = i;
182    
183 sysadm 1.6 i++;
184     if (i >= BBS_max_user_count)
185     {
186     log_error("Too many users, exceed limit %d\n", BBS_max_user_count);
187     break;
188     }
189     }
190     mysql_free_result(rs);
191     rs = NULL;
192 sysadm 1.1
193 sysadm 1.10 // Sort index
194     if (i != p_list->user_count || p_list->users[i - 1].uid != last_uid) // Count of users changed
195     {
196     qsort(p_list->index_uid, (size_t)i, sizeof(USER_INFO_INDEX_UID), user_info_index_uid_comp);
197     #ifdef _DEBUG
198     log_error("Rebuild index of %d users, last_uid=%d\n", i, p_list->users[i - 1].uid);
199     #endif
200     }
201    
202 sysadm 1.6 p_list->user_count = i;
203 sysadm 1.1
204     #ifdef _DEBUG
205 sysadm 1.6 log_error("Loaded %d users\n", p_list->user_count);
206 sysadm 1.1 #endif
207    
208     cleanup:
209 sysadm 1.6 mysql_free_result(rs);
210 sysadm 1.1
211 sysadm 1.6 return ret;
212     }
213    
214     int user_online_list_load(MYSQL *db, USER_ONLINE_LIST *p_list)
215     {
216     MYSQL_RES *rs = NULL;
217     MYSQL_ROW row;
218     char sql[SQL_BUFFER_LEN];
219     int ret = 0;
220     int i;
221    
222     if (db == NULL || p_list == NULL)
223     {
224     log_error("NULL pointer error\n");
225     return -1;
226     }
227    
228     snprintf(sql, sizeof(sql),
229     "SELECT SID, UID, ip, current_action, UNIX_TIMESTAMP(login_tm), "
230     "UNIX_TIMESTAMP(last_tm) FROM user_online "
231 sysadm 1.9 "WHERE last_tm >= SUBDATE(NOW(), INTERVAL %d SECOND) AND UID <> 0 "
232 sysadm 1.6 "ORDER BY last_tm DESC",
233     BBS_user_off_line);
234    
235     if (mysql_query(db, sql) != 0)
236     {
237     log_error("Query user online error: %s\n", mysql_error(db));
238     ret = -1;
239     goto cleanup;
240     }
241    
242     if ((rs = mysql_use_result(db)) == NULL)
243     {
244     log_error("Get user online data failed\n");
245     ret = -1;
246     goto cleanup;
247     }
248    
249     i = 0;
250     while ((row = mysql_fetch_row(rs)))
251     {
252 sysadm 1.8 p_list->users[i].id = i;
253 sysadm 1.6 strncpy(p_list->users[i].session_id, row[0], sizeof(p_list->users[i].session_id) - 1);
254 sysadm 1.8 p_list->users[i].session_id[sizeof(p_list->users[i].session_id) - 1] = '\0';
255 sysadm 1.6
256 sysadm 1.8 if ((ret = query_user_info_by_uid(atoi(row[1]), &(p_list->users[i].user_info))) < 0)
257 sysadm 1.6 {
258     log_error("query_user_info(%d) error\n", atoi(row[1]));
259     continue;
260     }
261 sysadm 1.9 else if (ret == 0) // skip Guest
262 sysadm 1.7 {
263 sysadm 1.9 continue;
264 sysadm 1.7 }
265 sysadm 1.6
266     strncpy(p_list->users[i].ip, row[2], sizeof(p_list->users[i].ip) - 1);
267     p_list->users[i].ip[sizeof(p_list->users[i].ip) - 1] = '\0';
268    
269     strncpy(p_list->users[i].current_action, row[3], sizeof(p_list->users[i].current_action) - 1);
270     p_list->users[i].current_action[sizeof(p_list->users[i].current_action) - 1] = '\0';
271     p_list->users[i].current_action_title = NULL;
272     if (p_list->users[i].current_action[0] == '\0')
273     {
274 sysadm 1.7 p_list->users[i].current_action_title = "";
275 sysadm 1.6 }
276     else if (trie_dict_get(p_trie_action_dict, p_list->users[i].current_action, (int64_t *)(&(p_list->users[i].current_action_title))) < 0)
277     {
278     log_error("trie_dict_get(p_trie_action_dict, %s) error on session_id=%s\n",
279     p_list->users[i].current_action, p_list->users[i].session_id);
280     continue;
281     }
282    
283     p_list->users[i].login_tm = (row[4] == NULL ? 0 : atol(row[4]));
284     p_list->users[i].last_tm = (row[5] == NULL ? 0 : atol(row[5]));
285    
286 sysadm 1.10 // index
287     p_list->index_uid[i].uid = p_list->users[i].user_info.uid;
288     p_list->index_uid[i].id = i;
289    
290 sysadm 1.6 i++;
291     if (i >= BBS_max_user_online_count)
292     {
293     log_error("Too many online users, exceed limit %d\n", BBS_max_user_online_count);
294     break;
295     }
296     }
297     mysql_free_result(rs);
298     rs = NULL;
299    
300 sysadm 1.10 // Sort index
301     if (i > 0)
302     {
303     qsort(p_list->index_uid, (size_t)i, sizeof(USER_INFO_INDEX_UID), user_info_index_uid_comp);
304     #ifdef _DEBUG
305     log_error("Rebuild index of %d online users\n", i);
306     #endif
307     }
308    
309 sysadm 1.6 p_list->user_count = i;
310    
311     #ifdef _DEBUG
312 sysadm 1.10 log_error("Loaded %d online users\n", p_list->user_count);
313 sysadm 1.6 #endif
314    
315     cleanup:
316     mysql_free_result(rs);
317    
318     return ret;
319 sysadm 1.1 }
320    
321     int user_list_pool_init(void)
322     {
323 sysadm 1.6 int shmid;
324     int semid;
325     int proj_id;
326     key_t key;
327     size_t size;
328     void *p_shm;
329     union semun arg;
330     int i;
331    
332     if (p_user_list_pool != NULL || p_trie_action_dict != NULL)
333     {
334     log_error("p_user_list_pool already initialized\n");
335     return -1;
336     }
337    
338     p_trie_action_dict = trie_dict_create();
339     if (p_trie_action_dict == NULL)
340     {
341     log_error("trie_dict_create() error\n");
342     return -1;
343     }
344    
345     for (i = 0; i < user_action_map_size; i++)
346     {
347     if (trie_dict_set(p_trie_action_dict, user_action_map[i].name, (int64_t)(user_action_map[i].title)) < 0)
348     {
349     log_error("trie_dict_set(p_trie_action_dict, %s) error\n", user_action_map[i].name);
350     }
351     }
352    
353     // Allocate shared memory
354     proj_id = (int)(time(NULL) % getpid());
355     key = ftok(VAR_USER_LIST_SHM, proj_id);
356     if (key == -1)
357     {
358     log_error("ftok(%s %d) error (%d)\n", VAR_USER_LIST_SHM, proj_id, errno);
359     return -2;
360     }
361    
362     size = sizeof(USER_LIST_POOL);
363     shmid = shmget(key, size, IPC_CREAT | IPC_EXCL | 0600);
364     if (shmid == -1)
365     {
366     log_error("shmget(size = %d) error (%d)\n", size, errno);
367     return -3;
368     }
369     p_shm = shmat(shmid, NULL, 0);
370     if (p_shm == (void *)-1)
371     {
372     log_error("shmat(shmid=%d) error (%d)\n", shmid, errno);
373     return -3;
374     }
375    
376     p_user_list_pool = p_shm;
377     p_user_list_pool->shmid = shmid;
378    
379     // Allocate semaphore as user list pool lock
380     size = 2; // r_sem and w_sem
381     semid = semget(key, (int)size, IPC_CREAT | IPC_EXCL | 0600);
382     if (semid == -1)
383     {
384     log_error("semget(user_list_pool_sem, size = %d) error (%d)\n", size, errno);
385     return -3;
386     }
387    
388     // Initialize sem value to 0
389     arg.val = 0;
390     for (i = 0; i < size; i++)
391     {
392     if (semctl(semid, i, SETVAL, arg) == -1)
393     {
394     log_error("semctl(user_list_pool_sem, SETVAL) error (%d)\n", errno);
395     return -3;
396     }
397     }
398    
399     p_user_list_pool->semid = semid;
400    
401     // Set user counts to 0
402     p_user_list_pool->user_list[0].user_count = 0;
403     p_user_list_pool->user_list[1].user_count = 0;
404    
405     p_user_list_pool->p_current = &(p_user_list_pool->user_list[0]);
406     p_user_list_pool->p_new = &(p_user_list_pool->user_list[1]);
407 sysadm 1.1
408 sysadm 1.6 p_user_list_pool->p_online_current = &(p_user_list_pool->user_online_list[0]);
409     p_user_list_pool->p_online_new = &(p_user_list_pool->user_online_list[1]);
410 sysadm 1.1
411 sysadm 1.6 return 0;
412 sysadm 1.1 }
413    
414     void user_list_pool_cleanup(void)
415     {
416 sysadm 1.6 int shmid;
417 sysadm 1.1
418 sysadm 1.6 if (p_user_list_pool == NULL)
419     {
420     return;
421     }
422    
423     shmid = p_user_list_pool->shmid;
424    
425     if (semctl(p_user_list_pool->semid, 0, IPC_RMID) == -1)
426     {
427     log_error("semctl(semid = %d, IPC_RMID) error (%d)\n", p_user_list_pool->semid, errno);
428     }
429    
430     if (shmdt(p_user_list_pool) == -1)
431     {
432     log_error("shmdt(shmid = %d) error (%d)\n", shmid, errno);
433     }
434    
435     if (shmctl(shmid, IPC_RMID, NULL) == -1)
436     {
437     log_error("shmctl(shmid = %d, IPC_RMID) error (%d)\n", shmid, errno);
438     }
439    
440     p_user_list_pool = NULL;
441    
442     if (p_trie_action_dict != NULL)
443     {
444     trie_dict_destroy(p_trie_action_dict);
445 sysadm 1.1
446 sysadm 1.6 p_trie_action_dict = NULL;
447     }
448 sysadm 1.1 }
449    
450     int set_user_list_pool_shm_readonly(void)
451     {
452 sysadm 1.6 int shmid;
453     void *p_shm;
454 sysadm 1.1
455 sysadm 1.6 if (p_user_list_pool == NULL)
456     {
457     log_error("p_user_list_pool not initialized\n");
458     return -1;
459     }
460    
461     shmid = p_user_list_pool->shmid;
462    
463     // Remap shared memory in read-only mode
464     p_shm = shmat(shmid, p_user_list_pool, SHM_RDONLY | SHM_REMAP);
465     if (p_shm == (void *)-1)
466     {
467     log_error("shmat(user_list_pool shmid = %d) error (%d)\n", shmid, errno);
468     return -3;
469     }
470 sysadm 1.1
471 sysadm 1.6 p_user_list_pool = p_shm;
472 sysadm 1.1
473 sysadm 1.6 return 0;
474 sysadm 1.1 }
475    
476     int detach_user_list_pool_shm(void)
477     {
478 sysadm 1.6 if (p_user_list_pool != NULL && shmdt(p_user_list_pool) == -1)
479     {
480     log_error("shmdt(user_list_pool) error (%d)\n", errno);
481     return -1;
482     }
483    
484     p_user_list_pool = NULL;
485    
486     return 0;
487     }
488    
489     int user_list_pool_reload(int online_user)
490     {
491     MYSQL *db = NULL;
492     USER_LIST *p_tmp;
493     USER_ONLINE_LIST *p_online_tmp;
494    
495     if (p_user_list_pool == NULL)
496     {
497     log_error("p_user_list_pool not initialized\n");
498     return -1;
499     }
500    
501     db = db_open();
502     if (db == NULL)
503     {
504     log_error("db_open() error: %s\n", mysql_error(db));
505     return -1;
506     }
507    
508     if (online_user)
509     {
510     if (user_online_list_load(db, p_user_list_pool->p_online_new) < 0)
511     {
512     log_error("user_online_list_load() error\n");
513     return -2;
514     }
515 sysadm 1.10
516     // No online user, no need to swap lists
517     if (p_user_list_pool->p_online_current->user_count == 0 && p_user_list_pool->p_online_new->user_count == 0)
518     {
519     return 0;
520     }
521 sysadm 1.6 }
522     else
523     {
524     if (user_list_load(db, p_user_list_pool->p_new) < 0)
525     {
526     log_error("user_list_load() error\n");
527     return -2;
528     }
529     }
530    
531     mysql_close(db);
532    
533     if (user_list_rw_lock(p_user_list_pool->semid) < 0)
534     {
535     log_error("user_list_rw_lock() error\n");
536     return -3;
537     }
538    
539     if (online_user)
540     {
541     // Swap p_online_current and p_online_new
542     p_online_tmp = p_user_list_pool->p_online_current;
543     p_user_list_pool->p_online_current = p_user_list_pool->p_online_new;
544     p_user_list_pool->p_online_new = p_online_tmp;
545     }
546     else
547     {
548     // Swap p_current and p_new
549     p_tmp = p_user_list_pool->p_current;
550     p_user_list_pool->p_current = p_user_list_pool->p_new;
551     p_user_list_pool->p_new = p_tmp;
552     }
553    
554     if (user_list_rw_unlock(p_user_list_pool->semid) < 0)
555     {
556     log_error("user_list_rw_unlock() error\n");
557     return -3;
558     }
559 sysadm 1.1
560 sysadm 1.6 return 0;
561 sysadm 1.1 }
562    
563 sysadm 1.5 int user_list_try_rd_lock(int semid, int wait_sec)
564 sysadm 1.1 {
565 sysadm 1.6 struct sembuf sops[2];
566     struct timespec timeout;
567     int ret;
568    
569     sops[0].sem_num = 1; // w_sem
570     sops[0].sem_op = 0; // wait until unlocked
571     sops[0].sem_flg = 0;
572    
573     sops[1].sem_num = 0; // r_sem
574     sops[1].sem_op = 1; // lock
575     sops[1].sem_flg = SEM_UNDO; // undo on terminate
576    
577     timeout.tv_sec = wait_sec;
578     timeout.tv_nsec = 0;
579    
580     ret = semtimedop(semid, sops, 2, &timeout);
581     if (ret == -1 && errno != EAGAIN && errno != EINTR)
582     {
583     log_error("semtimedop(lock read) error %d\n", errno);
584     }
585 sysadm 1.1
586 sysadm 1.6 return ret;
587 sysadm 1.1 }
588    
589 sysadm 1.5 int user_list_try_rw_lock(int semid, int wait_sec)
590 sysadm 1.1 {
591 sysadm 1.6 struct sembuf sops[3];
592     struct timespec timeout;
593     int ret;
594    
595     sops[0].sem_num = 1; // w_sem
596     sops[0].sem_op = 0; // wait until unlocked
597     sops[0].sem_flg = 0;
598    
599     sops[1].sem_num = 1; // w_sem
600     sops[1].sem_op = 1; // lock
601     sops[1].sem_flg = SEM_UNDO; // undo on terminate
602    
603     sops[2].sem_num = 0; // r_sem
604     sops[2].sem_op = 0; // wait until unlocked
605     sops[2].sem_flg = 0;
606    
607     timeout.tv_sec = wait_sec;
608     timeout.tv_nsec = 0;
609    
610     ret = semtimedop(semid, sops, 3, &timeout);
611     if (ret == -1 && errno != EAGAIN && errno != EINTR)
612     {
613     log_error("semtimedop(lock write) error %d\n", errno);
614     }
615 sysadm 1.1
616 sysadm 1.6 return ret;
617 sysadm 1.1 }
618    
619 sysadm 1.5 int user_list_rd_unlock(int semid)
620 sysadm 1.1 {
621 sysadm 1.6 struct sembuf sops[2];
622     int ret;
623 sysadm 1.1
624 sysadm 1.6 sops[0].sem_num = 0; // r_sem
625     sops[0].sem_op = -1; // unlock
626     sops[0].sem_flg = IPC_NOWAIT | SEM_UNDO; // no wait
627    
628     ret = semop(semid, sops, 1);
629     if (ret == -1 && errno != EAGAIN && errno != EINTR)
630     {
631     log_error("semop(unlock read) error %d\n", errno);
632     }
633 sysadm 1.1
634 sysadm 1.6 return ret;
635 sysadm 1.1 }
636    
637 sysadm 1.5 int user_list_rw_unlock(int semid)
638 sysadm 1.1 {
639 sysadm 1.6 struct sembuf sops[1];
640     int ret;
641 sysadm 1.1
642 sysadm 1.6 sops[0].sem_num = 1; // w_sem
643     sops[0].sem_op = -1; // unlock
644     sops[0].sem_flg = IPC_NOWAIT | SEM_UNDO; // no wait
645    
646     ret = semop(semid, sops, 1);
647     if (ret == -1 && errno != EAGAIN && errno != EINTR)
648     {
649     log_error("semop(unlock write) error %d\n", errno);
650     }
651 sysadm 1.1
652 sysadm 1.6 return ret;
653 sysadm 1.1 }
654    
655 sysadm 1.5 int user_list_rd_lock(int semid)
656 sysadm 1.1 {
657 sysadm 1.6 int timer = 0;
658     int ret = -1;
659 sysadm 1.1
660 sysadm 1.6 while (!SYS_server_exit)
661     {
662     ret = user_list_try_rd_lock(semid, USER_LIST_TRY_LOCK_WAIT_TIME);
663     if (ret == 0) // success
664     {
665     break;
666     }
667     else if (errno == EAGAIN || errno == EINTR) // retry
668     {
669     timer++;
670     if (timer % USER_LIST_TRY_LOCK_TIMES == 0)
671     {
672     log_error("user_list_try_rd_lock() tried %d times\n", timer);
673     }
674     }
675     else // failed
676     {
677     log_error("user_list_try_rd_lock() failed\n");
678     break;
679     }
680     }
681 sysadm 1.1
682 sysadm 1.6 return ret;
683 sysadm 1.1 }
684    
685 sysadm 1.5 int user_list_rw_lock(int semid)
686 sysadm 1.1 {
687 sysadm 1.6 int timer = 0;
688     int ret = -1;
689 sysadm 1.1
690 sysadm 1.6 while (!SYS_server_exit)
691     {
692     ret = user_list_try_rw_lock(semid, USER_LIST_TRY_LOCK_WAIT_TIME);
693     if (ret == 0) // success
694     {
695     break;
696     }
697     else if (errno == EAGAIN || errno == EINTR) // retry
698     {
699     timer++;
700     if (timer % USER_LIST_TRY_LOCK_TIMES == 0)
701     {
702     log_error("user_list_try_rw_lock() tried %d times\n", timer);
703     }
704     }
705     else // failed
706     {
707     log_error("user_list_try_rw_lock() failed\n");
708     break;
709     }
710     }
711 sysadm 1.1
712 sysadm 1.6 return ret;
713 sysadm 1.1 }
714 sysadm 1.2
715     int query_user_list(int page_id, USER_INFO *p_users, int *p_user_count, int *p_page_count)
716     {
717 sysadm 1.6 int ret = 0;
718 sysadm 1.2
719 sysadm 1.6 if (p_users == NULL || p_user_count == NULL || p_page_count == NULL)
720     {
721     log_error("NULL pointer error\n");
722     return -1;
723     }
724    
725     // acquire lock of user list
726     if (user_list_rd_lock(p_user_list_pool->semid) < 0)
727     {
728     log_error("user_list_rd_lock() error\n");
729     return -2;
730     }
731    
732     if (p_user_list_pool->p_current->user_count == 0)
733     {
734     // empty list
735     ret = 0;
736     goto cleanup;
737     }
738    
739     *p_page_count = p_user_list_pool->p_current->user_count / BBS_user_limit_per_page +
740     (p_user_list_pool->p_current->user_count % BBS_user_limit_per_page == 0 ? 0 : 1);
741    
742     if (page_id < 0 || page_id >= *p_page_count)
743     {
744     log_error("Invalid page_id = %d, not in range [0, %d)\n", page_id, *p_page_count);
745     ret = -3;
746     goto cleanup;
747     }
748    
749     *p_user_count = MIN(BBS_user_limit_per_page,
750     p_user_list_pool->p_current->user_count -
751     page_id * BBS_user_limit_per_page);
752    
753     memcpy(p_users,
754     p_user_list_pool->p_current->users + page_id * BBS_user_limit_per_page,
755     sizeof(USER_INFO) * (size_t)(*p_user_count));
756    
757     cleanup:
758     // release lock of user list
759     if (user_list_rd_unlock(p_user_list_pool->semid) < 0)
760     {
761     log_error("user_list_rd_unlock() error\n");
762     ret = -1;
763     }
764    
765     return ret;
766     }
767    
768     int query_user_online_list(int page_id, USER_ONLINE_INFO *p_online_users, int *p_user_count, int *p_page_count)
769     {
770     int ret = 0;
771    
772     if (p_online_users == NULL || p_user_count == NULL || p_page_count == NULL)
773     {
774     log_error("NULL pointer error\n");
775     return -1;
776     }
777    
778     // acquire lock of user list
779     if (user_list_rd_lock(p_user_list_pool->semid) < 0)
780     {
781     log_error("user_list_rd_lock() error\n");
782     return -2;
783     }
784    
785     if (p_user_list_pool->p_online_current->user_count == 0)
786     {
787     // empty list
788     ret = 0;
789     goto cleanup;
790     }
791    
792     *p_page_count = p_user_list_pool->p_online_current->user_count / BBS_user_limit_per_page +
793     (p_user_list_pool->p_online_current->user_count % BBS_user_limit_per_page == 0 ? 0 : 1);
794    
795     if (page_id < 0 || page_id >= *p_page_count)
796     {
797     log_error("Invalid page_id = %d, not in range [0, %d)\n", page_id, *p_page_count);
798     ret = -3;
799     goto cleanup;
800     }
801    
802     *p_user_count = MIN(BBS_user_limit_per_page,
803     p_user_list_pool->p_online_current->user_count -
804     page_id * BBS_user_limit_per_page);
805    
806     memcpy(p_online_users,
807     p_user_list_pool->p_online_current->users + page_id * BBS_user_limit_per_page,
808     sizeof(USER_ONLINE_INFO) * (size_t)(*p_user_count));
809 sysadm 1.2
810     cleanup:
811 sysadm 1.6 // release lock of user list
812     if (user_list_rd_unlock(p_user_list_pool->semid) < 0)
813     {
814     log_error("user_list_rd_unlock() error\n");
815     ret = -1;
816     }
817 sysadm 1.2
818 sysadm 1.6 return ret;
819 sysadm 1.2 }
820 sysadm 1.4
821 sysadm 1.8 int query_user_info(int32_t id, USER_INFO *p_user)
822     {
823     int ret = 0;
824    
825     if (p_user == NULL)
826     {
827     log_error("NULL pointer error\n");
828     return -1;
829     }
830    
831     // acquire lock of user list
832     if (user_list_rd_lock(p_user_list_pool->semid) < 0)
833     {
834     log_error("user_list_rd_lock() error\n");
835     return -2;
836     }
837    
838     if (id >= 0 && id < p_user_list_pool->p_current->user_count) // Found
839     {
840     *p_user = p_user_list_pool->p_current->users[id];
841     ret = 1;
842     }
843    
844     // release lock of user list
845     if (user_list_rd_unlock(p_user_list_pool->semid) < 0)
846     {
847     log_error("user_list_rd_unlock() error\n");
848     ret = -1;
849     }
850    
851     return ret;
852     }
853    
854     int query_user_info_by_uid(int32_t uid, USER_INFO *p_user)
855 sysadm 1.4 {
856 sysadm 1.6 int left;
857     int right;
858     int mid;
859 sysadm 1.8 int32_t id;
860 sysadm 1.6 int ret = 0;
861    
862     if (p_user == NULL)
863     {
864     log_error("NULL pointer error\n");
865     return -1;
866     }
867    
868     // 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     left = 0;
876     right = p_user_list_pool->p_current->user_count - 1;
877    
878     while (left < right)
879     {
880     mid = (left + right) / 2;
881 sysadm 1.8 if (uid < p_user_list_pool->p_current->index_uid[mid].uid)
882 sysadm 1.6 {
883     right = mid;
884     }
885 sysadm 1.8 else if (uid > p_user_list_pool->p_current->index_uid[mid].uid)
886 sysadm 1.6 {
887     left = mid + 1;
888     }
889 sysadm 1.8 else // if (uid == p_user_list_pool->p_current->index_uid[mid].uid)
890 sysadm 1.6 {
891     left = mid;
892     break;
893     }
894     }
895    
896 sysadm 1.8 if (uid == p_user_list_pool->p_current->index_uid[left].uid) // Found
897     {
898     id = p_user_list_pool->p_current->index_uid[left].id;
899     if ((ret = query_user_info(id, p_user)) <= 0)
900     {
901     log_error("query_user_info(id=%d) error: %d\n", id, ret);
902     }
903     else
904     {
905     ret = 1;
906     }
907     }
908    
909     // release lock of user list
910     if (user_list_rd_unlock(p_user_list_pool->semid) < 0)
911     {
912     log_error("user_list_rd_unlock() error\n");
913     ret = -1;
914     }
915    
916     return ret;
917     }
918    
919     int query_user_online_info(int32_t id, USER_ONLINE_INFO *p_user)
920     {
921     int ret = 0;
922    
923     if (p_user == NULL)
924     {
925     log_error("NULL pointer error\n");
926     return -1;
927     }
928    
929     // acquire lock of user list
930     if (user_list_rd_lock(p_user_list_pool->semid) < 0)
931     {
932     log_error("user_list_rd_lock() error\n");
933     return -2;
934     }
935    
936     if (id >= 0 && id < p_user_list_pool->p_online_current->user_count) // Found
937 sysadm 1.6 {
938 sysadm 1.8 *p_user = p_user_list_pool->p_online_current->users[id];
939 sysadm 1.6 ret = 1;
940     }
941    
942     // release lock of user list
943     if (user_list_rd_unlock(p_user_list_pool->semid) < 0)
944     {
945     log_error("user_list_rd_unlock() error\n");
946     ret = -1;
947     }
948 sysadm 1.4
949 sysadm 1.6 return ret;
950 sysadm 1.4 }

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