/[LeafOK_CVS]/lbbs/src/user_list.c
ViewVC logotype

Diff of /lbbs/src/user_list.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

Revision 1.9 by sysadm, Wed Oct 22 07:39:02 2025 UTC Revision 1.22 by sysadm, Fri Oct 24 02:03:15 2025 UTC
# Line 19  Line 19 
19  #include "log.h"  #include "log.h"
20  #include "trie_dict.h"  #include "trie_dict.h"
21  #include "user_list.h"  #include "user_list.h"
22    #include "user_stat.h"
23  #include <errno.h>  #include <errno.h>
24  #include <stdlib.h>  #include <stdlib.h>
25  #include <string.h>  #include <string.h>
# Line 53  struct user_list_pool_t Line 54  struct user_list_pool_t
54          USER_ONLINE_LIST user_online_list[2];          USER_ONLINE_LIST user_online_list[2];
55          USER_ONLINE_LIST *p_online_current;          USER_ONLINE_LIST *p_online_current;
56          USER_ONLINE_LIST *p_online_new;          USER_ONLINE_LIST *p_online_new;
57            USER_STAT_MAP user_stat_map;
58  };  };
59  typedef struct user_list_pool_t USER_LIST_POOL;  typedef struct user_list_pool_t USER_LIST_POOL;
60    
# Line 106  static int user_info_index_uid_comp(cons Line 108  static int user_info_index_uid_comp(cons
108          {          {
109                  return 1;                  return 1;
110          }          }
111            else if (p1->id < p2->id)
112            {
113                    return -1;
114            }
115            else if (p1->id > p2->id)
116            {
117                    return 1;
118            }
119          return 0;          return 0;
120  }  }
121    
# Line 116  int user_list_load(MYSQL *db, USER_LIST Line 126  int user_list_load(MYSQL *db, USER_LIST
126          char sql[SQL_BUFFER_LEN];          char sql[SQL_BUFFER_LEN];
127          int ret = 0;          int ret = 0;
128          int i;          int i;
129            int j;
130            int32_t last_uid;
131            size_t intro_buf_offset;
132            size_t intro_len;
133    
134          if (db == NULL || p_list == NULL)          if (db == NULL || p_list == NULL)
135          {          {
# Line 123  int user_list_load(MYSQL *db, USER_LIST Line 137  int user_list_load(MYSQL *db, USER_LIST
137                  return -1;                  return -1;
138          }          }
139    
140            if (p_list->user_count > 0)
141            {
142                    last_uid = p_list->users[p_list->user_count - 1].uid;
143            }
144            else
145            {
146                    last_uid = -1;
147            }
148    
149          snprintf(sql, sizeof(sql),          snprintf(sql, sizeof(sql),
150                           "SELECT user_list.UID AS UID, username, nickname, gender, gender_pub, life, exp, "                           "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) "                           "UNIX_TIMESTAMP(signup_dt), UNIX_TIMESTAMP(last_login_dt), UNIX_TIMESTAMP(last_logout_dt), "
152                             "UNIX_TIMESTAMP(birthday), `introduction` "
153                           "FROM user_list INNER JOIN user_pubinfo ON user_list.UID = user_pubinfo.UID "                           "FROM user_list INNER JOIN user_pubinfo ON user_list.UID = user_pubinfo.UID "
154                           "INNER JOIN user_reginfo ON user_list.UID = user_reginfo.UID "                           "INNER JOIN user_reginfo ON user_list.UID = user_reginfo.UID "
155                           "WHERE enable ORDER BY username");                           "WHERE enable ORDER BY username");
# Line 144  int user_list_load(MYSQL *db, USER_LIST Line 168  int user_list_load(MYSQL *db, USER_LIST
168                  goto cleanup;                  goto cleanup;
169          }          }
170    
171            intro_buf_offset = 0;
172          i = 0;          i = 0;
173          while ((row = mysql_fetch_row(rs)))          while ((row = mysql_fetch_row(rs)))
174          {          {
# Line 158  int user_list_load(MYSQL *db, USER_LIST Line 183  int user_list_load(MYSQL *db, USER_LIST
183                  p_list->users[i].gender_pub = (int8_t)(row[4] == NULL ? 0 : atoi(row[4]));                  p_list->users[i].gender_pub = (int8_t)(row[4] == NULL ? 0 : atoi(row[4]));
184                  p_list->users[i].life = (row[5] == NULL ? 0 : atoi(row[5]));                  p_list->users[i].life = (row[5] == NULL ? 0 : atoi(row[5]));
185                  p_list->users[i].exp = (row[6] == NULL ? 0 : atoi(row[6]));                  p_list->users[i].exp = (row[6] == NULL ? 0 : atoi(row[6]));
186                  p_list->users[i].signup_dt = (row[7] == NULL ? 0 : atol(row[7]));                  p_list->users[i].visit_count = (row[7] == NULL ? 0 : atoi(row[7]));
187                  p_list->users[i].last_login_dt = (row[8] == NULL ? 0 : atol(row[8]));                  p_list->users[i].signup_dt = (row[8] == NULL ? 0 : atol(row[8]));
188                  p_list->users[i].birthday = (row[9] == NULL ? 0 : atol(row[9]));                  p_list->users[i].last_login_dt = (row[9] == NULL ? 0 : atol(row[9]));
189                    p_list->users[i].last_logout_dt = (row[10] == NULL ? 0 : atol(row[10]));
190                  // index                  p_list->users[i].birthday = (row[10] == NULL ? 0 : atol(row[11]));
191                  p_list->index_uid[i].uid = p_list->users[i].uid;                  intro_len = strlen((row[12] == NULL ? "" : row[12]));
192                  p_list->index_uid[i].id = i;                  if (intro_len >= sizeof(p_list->user_intro_buf) - 1 - intro_buf_offset)
193                    {
194                            log_error("OOM for user introduction: len=%d, i=%d\n", intro_len, i);
195                            break;
196                    }
197                    memcpy(p_list->user_intro_buf + intro_buf_offset,
198                               (row[12] == NULL ? "" : row[12]),
199                               intro_len + 1);
200                    p_list->users[i].intro = p_list->user_intro_buf + intro_buf_offset;
201                    intro_buf_offset += (intro_len + 1);
202    
203                  i++;                  i++;
204                  if (i >= BBS_max_user_count)                  if (i >= BBS_max_user_count)
# Line 176  int user_list_load(MYSQL *db, USER_LIST Line 210  int user_list_load(MYSQL *db, USER_LIST
210          mysql_free_result(rs);          mysql_free_result(rs);
211          rs = NULL;          rs = NULL;
212    
213          p_list->user_count = i;          if (i != p_list->user_count || p_list->users[i - 1].uid != last_uid) // Count of users changed
214            {
215                    // Rebuild index
216                    for (j = 0; j < i; j++)
217                    {
218                            p_list->index_uid[j].uid = p_list->users[j].uid;
219                            p_list->index_uid[j].id = j;
220                    }
221    
222                    qsort(p_list->index_uid, (size_t)i, sizeof(USER_INFO_INDEX_UID), user_info_index_uid_comp);
223    
224    #ifdef _DEBUG
225                    log_error("Rebuild index of %d users, last_uid=%d\n", i, p_list->users[i - 1].uid);
226    #endif
227            }
228    
229          // Sort index          p_list->user_count = i;
         qsort(p_list->index_uid, (size_t)i, sizeof(USER_INFO_INDEX_UID), user_info_index_uid_comp);  
230    
231  #ifdef _DEBUG  #ifdef _DEBUG
232          log_error("Loaded %d users\n", p_list->user_count);          log_error("Loaded %d users\n", p_list->user_count);
# Line 198  int user_online_list_load(MYSQL *db, USE Line 245  int user_online_list_load(MYSQL *db, USE
245          char sql[SQL_BUFFER_LEN];          char sql[SQL_BUFFER_LEN];
246          int ret = 0;          int ret = 0;
247          int i;          int i;
248            int j;
249    
250          if (db == NULL || p_list == NULL)          if (db == NULL || p_list == NULL)
251          {          {
# Line 233  int user_online_list_load(MYSQL *db, USE Line 281  int user_online_list_load(MYSQL *db, USE
281                  strncpy(p_list->users[i].session_id, row[0], sizeof(p_list->users[i].session_id) - 1);                  strncpy(p_list->users[i].session_id, row[0], sizeof(p_list->users[i].session_id) - 1);
282                  p_list->users[i].session_id[sizeof(p_list->users[i].session_id) - 1] = '\0';                  p_list->users[i].session_id[sizeof(p_list->users[i].session_id) - 1] = '\0';
283    
284                  if ((ret = query_user_info_by_uid(atoi(row[1]), &(p_list->users[i].user_info))) < 0)                  if ((ret = query_user_info_by_uid(atoi(row[1]), &(p_list->users[i].user_info))) <= 0)
                 {  
                         log_error("query_user_info(%d) error\n", atoi(row[1]));  
                         continue;  
                 }  
                 else if (ret == 0) // skip Guest  
285                  {                  {
286                            log_error("query_user_info_by_uid(%d) error\n", atoi(row[1]));
287                          continue;                          continue;
288                  }                  }
289    
# Line 273  int user_online_list_load(MYSQL *db, USE Line 317  int user_online_list_load(MYSQL *db, USE
317          mysql_free_result(rs);          mysql_free_result(rs);
318          rs = NULL;          rs = NULL;
319    
320            if (i > 0)
321            {
322                    // Rebuild index
323                    for (j = 0; j < i; j++)
324                    {
325                            p_list->index_uid[j].uid = p_list->users[j].user_info.uid;
326                            p_list->index_uid[j].id = j;
327                    }
328    
329                    qsort(p_list->index_uid, (size_t)i, sizeof(USER_INFO_INDEX_UID), user_info_index_uid_comp);
330    
331    #ifdef _DEBUG
332                    log_error("Rebuild index of %d online users\n", i);
333    #endif
334            }
335    
336          p_list->user_count = i;          p_list->user_count = i;
337    
338  #ifdef _DEBUG  #ifdef _DEBUG
339          log_error("Loaded %d users\n", p_list->user_count);          log_error("Loaded %d online users\n", p_list->user_count);
340  #endif  #endif
341    
342  cleanup:  cleanup:
# Line 285  cleanup: Line 345  cleanup:
345          return ret;          return ret;
346  }  }
347    
348  int user_list_pool_init(void)  int user_list_pool_init(const char *filename)
349  {  {
350          int shmid;          int shmid;
351          int semid;          int semid;
# Line 319  int user_list_pool_init(void) Line 379  int user_list_pool_init(void)
379    
380          // Allocate shared memory          // Allocate shared memory
381          proj_id = (int)(time(NULL) % getpid());          proj_id = (int)(time(NULL) % getpid());
382          key = ftok(VAR_USER_LIST_SHM, proj_id);          key = ftok(filename, proj_id);
383          if (key == -1)          if (key == -1)
384          {          {
385                  log_error("ftok(%s %d) error (%d)\n", VAR_USER_LIST_SHM, proj_id, errno);                  log_error("ftok(%s %d) error (%d)\n", filename, proj_id, errno);
386                  return -2;                  return -2;
387          }          }
388    
# Line 375  int user_list_pool_init(void) Line 435  int user_list_pool_init(void)
435          p_user_list_pool->p_online_current = &(p_user_list_pool->user_online_list[0]);          p_user_list_pool->p_online_current = &(p_user_list_pool->user_online_list[0]);
436          p_user_list_pool->p_online_new = &(p_user_list_pool->user_online_list[1]);          p_user_list_pool->p_online_new = &(p_user_list_pool->user_online_list[1]);
437    
438            user_stat_map_init(&(p_user_list_pool->user_stat_map));
439    
440          return 0;          return 0;
441  }  }
442    
# Line 458  int user_list_pool_reload(int online_use Line 520  int user_list_pool_reload(int online_use
520          MYSQL *db = NULL;          MYSQL *db = NULL;
521          USER_LIST *p_tmp;          USER_LIST *p_tmp;
522          USER_ONLINE_LIST *p_online_tmp;          USER_ONLINE_LIST *p_online_tmp;
523            int ret = 0;
524    
525          if (p_user_list_pool == NULL)          if (p_user_list_pool == NULL)
526          {          {
# Line 477  int user_list_pool_reload(int online_use Line 540  int user_list_pool_reload(int online_use
540                  if (user_online_list_load(db, p_user_list_pool->p_online_new) < 0)                  if (user_online_list_load(db, p_user_list_pool->p_online_new) < 0)
541                  {                  {
542                          log_error("user_online_list_load() error\n");                          log_error("user_online_list_load() error\n");
543                          return -2;                          ret = -2;
544                            goto cleanup;
545                  }                  }
546          }          }
547          else          else
# Line 485  int user_list_pool_reload(int online_use Line 549  int user_list_pool_reload(int online_use
549                  if (user_list_load(db, p_user_list_pool->p_new) < 0)                  if (user_list_load(db, p_user_list_pool->p_new) < 0)
550                  {                  {
551                          log_error("user_list_load() error\n");                          log_error("user_list_load() error\n");
552                          return -2;                          ret = -2;
553                            goto cleanup;
554                  }                  }
555          }          }
556    
557          mysql_close(db);          mysql_close(db);
558            db = NULL;
559    
560          if (user_list_rw_lock(p_user_list_pool->semid) < 0)          if (user_list_rw_lock(p_user_list_pool->semid) < 0)
561          {          {
562                  log_error("user_list_rw_lock() error\n");                  log_error("user_list_rw_lock() error\n");
563                  return -3;                  ret = -3;
564                    goto cleanup;
565          }          }
566    
567          if (online_user)          if (online_user)
# Line 515  int user_list_pool_reload(int online_use Line 582  int user_list_pool_reload(int online_use
582          if (user_list_rw_unlock(p_user_list_pool->semid) < 0)          if (user_list_rw_unlock(p_user_list_pool->semid) < 0)
583          {          {
584                  log_error("user_list_rw_unlock() error\n");                  log_error("user_list_rw_unlock() error\n");
585                  return -3;                  ret = -3;
586                    goto cleanup;
587          }          }
588    
589          return 0;  cleanup:
590            mysql_close(db);
591    
592            return ret;
593  }  }
594    
595  int user_list_try_rd_lock(int semid, int wait_sec)  int user_list_try_rd_lock(int semid, int wait_sec)
# Line 683  int query_user_list(int page_id, USER_IN Line 754  int query_user_list(int page_id, USER_IN
754                  return -1;                  return -1;
755          }          }
756    
757            *p_user_count = 0;
758            *p_page_count = 0;
759    
760          // acquire lock of user list          // acquire lock of user list
761          if (user_list_rd_lock(p_user_list_pool->semid) < 0)          if (user_list_rd_lock(p_user_list_pool->semid) < 0)
762          {          {
# Line 736  int query_user_online_list(int page_id, Line 810  int query_user_online_list(int page_id,
810                  return -1;                  return -1;
811          }          }
812    
813            *p_user_count = 0;
814            *p_page_count = 0;
815    
816          // acquire lock of user list          // acquire lock of user list
817          if (user_list_rd_lock(p_user_list_pool->semid) < 0)          if (user_list_rd_lock(p_user_list_pool->semid) < 0)
818          {          {
# Line 841  int query_user_info_by_uid(int32_t uid, Line 918  int query_user_info_by_uid(int32_t uid,
918                  mid = (left + right) / 2;                  mid = (left + right) / 2;
919                  if (uid < p_user_list_pool->p_current->index_uid[mid].uid)                  if (uid < p_user_list_pool->p_current->index_uid[mid].uid)
920                  {                  {
921                          right = mid;                          right = mid - 1;
922                  }                  }
923                  else if (uid > p_user_list_pool->p_current->index_uid[mid].uid)                  else if (uid > p_user_list_pool->p_current->index_uid[mid].uid)
924                  {                  {
# Line 857  int query_user_info_by_uid(int32_t uid, Line 934  int query_user_info_by_uid(int32_t uid,
934          if (uid == p_user_list_pool->p_current->index_uid[left].uid) // Found          if (uid == p_user_list_pool->p_current->index_uid[left].uid) // Found
935          {          {
936                  id = p_user_list_pool->p_current->index_uid[left].id;                  id = p_user_list_pool->p_current->index_uid[left].id;
937                  if ((ret = query_user_info(id, p_user)) <= 0)                  *p_user = p_user_list_pool->p_current->users[id];
938                  {                  ret = 1;
                         log_error("query_user_info(id=%d) error: %d\n", id, ret);  
                 }  
                 else  
                 {  
                         ret = 1;  
                 }  
939          }          }
940    
941          // release lock of user list          // release lock of user list
# Line 909  int query_user_online_info(int32_t id, U Line 980  int query_user_online_info(int32_t id, U
980    
981          return ret;          return ret;
982  }  }
983    
984    int query_user_online_info_by_uid(int32_t uid, USER_ONLINE_INFO *p_users, int *p_user_cnt, int start_id)
985    {
986            int left;
987            int right;
988            int mid;
989            int32_t id;
990            int ret = 0;
991            int i;
992            int user_cnt;
993    
994            if (p_users == NULL || p_user_cnt == NULL)
995            {
996                    log_error("NULL pointer error\n");
997                    return -1;
998            }
999    
1000            user_cnt = *p_user_cnt;
1001            *p_user_cnt = 0;
1002    
1003            // acquire lock of user list
1004            if (user_list_rd_lock(p_user_list_pool->semid) < 0)
1005            {
1006                    log_error("user_list_rd_lock() error\n");
1007                    return -2;
1008            }
1009    
1010            left = start_id;
1011            right = p_user_list_pool->p_online_current->user_count - 1;
1012    
1013            while (left < right)
1014            {
1015                    mid = (left + right) / 2;
1016                    if (uid < p_user_list_pool->p_online_current->index_uid[mid].uid)
1017                    {
1018                            right = mid - 1;
1019                    }
1020                    else if (uid > p_user_list_pool->p_online_current->index_uid[mid].uid)
1021                    {
1022                            left = mid + 1;
1023                    }
1024                    else // if (uid == p_user_list_pool->p_online_current->index_uid[mid].uid)
1025                    {
1026                            left = mid;
1027                            break;
1028                    }
1029            }
1030    
1031            if (uid == p_user_list_pool->p_online_current->index_uid[left].uid)
1032            {
1033                    right = left;
1034                    left = start_id;
1035    
1036                    while (left < right)
1037                    {
1038                            mid = (left + right) / 2;
1039                            if (uid - 1 < p_user_list_pool->p_online_current->index_uid[mid].uid)
1040                            {
1041                                    right = mid;
1042                            }
1043                            else // if (uid - 1 >= p_user_list_pool->p_online_current->index_uid[mid].uid)
1044                            {
1045                                    left = mid + 1;
1046                            }
1047                    }
1048    
1049                    for (i = 0;
1050                             left < p_user_list_pool->p_online_current->user_count && i < user_cnt &&
1051                             uid == p_user_list_pool->p_online_current->index_uid[left].uid;
1052                             left++, i++)
1053                    {
1054                            id = p_user_list_pool->p_online_current->index_uid[left].id;
1055                            p_users[i] = p_user_list_pool->p_online_current->users[id];
1056                    }
1057    
1058                    if (i > 0)
1059                    {
1060                            *p_user_cnt = i;
1061                            ret = 1;
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            }
1071    
1072            return ret;
1073    }
1074    
1075    int get_user_id_list(int32_t *p_uid_list, int *p_user_cnt, int start_uid)
1076    {
1077            int left;
1078            int right;
1079            int mid;
1080            int ret = 0;
1081            int i;
1082    
1083            if (p_uid_list == NULL || p_user_cnt == NULL)
1084            {
1085                    log_error("NULL pointer error\n");
1086                    return -1;
1087            }
1088    
1089            // acquire lock of user list
1090            if (user_list_rd_lock(p_user_list_pool->semid) < 0)
1091            {
1092                    log_error("user_list_rd_lock() error\n");
1093                    return -2;
1094            }
1095    
1096            left = 0;
1097            right = p_user_list_pool->p_current->user_count - 1;
1098    
1099            while (left < right)
1100            {
1101                    mid = (left + right) / 2;
1102                    if (start_uid < p_user_list_pool->p_current->index_uid[mid].uid)
1103                    {
1104                            right = mid - 1;
1105                    }
1106                    else if (start_uid > p_user_list_pool->p_current->index_uid[mid].uid)
1107                    {
1108                            left = mid + 1;
1109                    }
1110                    else // if (start_uid == p_user_list_pool->p_current->index_uid[mid].uid)
1111                    {
1112                            left = mid;
1113                            break;
1114                    }
1115            }
1116    
1117            for (i = 0; i < *p_user_cnt && left + i < p_user_list_pool->p_current->user_count; i++)
1118            {
1119                    p_uid_list[i] = p_user_list_pool->p_current->index_uid[left + i].uid;
1120            }
1121            *p_user_cnt = i;
1122    
1123            // release lock of user list
1124            if (user_list_rd_unlock(p_user_list_pool->semid) < 0)
1125            {
1126                    log_error("user_list_rd_unlock() error\n");
1127                    ret = -1;
1128            }
1129    
1130            return ret;
1131    }
1132    
1133    int user_stat_update(void)
1134    {
1135            return user_stat_map_update(&(p_user_list_pool->user_stat_map));
1136    }
1137    
1138    int user_article_cnt_inc(int32_t uid, int n)
1139    {
1140            return user_stat_article_cnt_inc(&(p_user_list_pool->user_stat_map), uid, n);
1141    }
1142    
1143    int get_user_article_cnt(int32_t uid)
1144    {
1145            const USER_STAT *p_stat;
1146            int ret;
1147    
1148            ret = user_stat_get(&(p_user_list_pool->user_stat_map), uid, &p_stat);
1149            if (ret < 0)
1150            {
1151                    log_error("user_stat_get(uid=%d) error: %d\n", uid, ret);
1152                    return -1;
1153            }
1154            else if (ret == 0) // user not found
1155            {
1156                    return -1;
1157            }
1158    
1159            return p_stat->article_count;
1160    }


Legend:
Removed lines/characters  
Changed lines/characters
  Added lines/characters

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