/[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.19 - (hide annotations)
Thu Oct 23 05:54:16 2025 UTC (4 months, 3 weeks ago) by sysadm
Branch: MAIN
Changes since 1.18: +6 -1 lines
Content type: text/x-csrc
Update user_stat_article_cnt in section_list_set_article_visible()

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

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