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

Contents of /lbbs/src/article_view_log.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.17 - (show annotations)
Tue Nov 4 14:58:56 2025 UTC (4 months, 1 week ago) by sysadm
Branch: MAIN
Changes since 1.16: +1 -1 lines
Content type: text/x-csrc
Refine file header information comments

1 /* SPDX-License-Identifier: GPL-3.0-or-later */
2 /*
3 * article_view_log
4 * - data persistence and query of article view log
5 *
6 * Copyright (C) 2004-2025 Leaflet <leaflet@leafok.com>
7 */
8
9 #include "article_view_log.h"
10 #include "common.h"
11 #include "database.h"
12 #include "log.h"
13 #include <stdlib.h>
14 #include <string.h>
15
16 ARTICLE_VIEW_LOG BBS_article_view_log;
17
18 int article_view_log_load(int uid, ARTICLE_VIEW_LOG *p_view_log, int keep_inc)
19 {
20 MYSQL *db;
21 MYSQL_RES *rs;
22 MYSQL_ROW row;
23 char sql[SQL_BUFFER_LEN];
24
25 if (p_view_log == NULL)
26 {
27 log_error("NULL pointer error\n");
28 return -1;
29 }
30
31 p_view_log->uid = uid;
32
33 if (uid == 0)
34 {
35 p_view_log->aid_base_cnt = 0;
36 p_view_log->aid_base = NULL;
37
38 if (!keep_inc)
39 {
40 p_view_log->aid_inc_cnt = 0;
41 }
42
43 return 0;
44 }
45
46 if ((db = db_open()) == NULL)
47 {
48 log_error("article_view_log_load() error: Unable to open DB\n");
49 return -2;
50 }
51
52 snprintf(sql, sizeof(sql),
53 "SELECT AID FROM view_article_log WHERE UID = %d "
54 "ORDER BY AID",
55 uid);
56 if (mysql_query(db, sql) != 0)
57 {
58 log_error("Query view_article_log error: %s\n", mysql_error(db));
59 return -3;
60 }
61 if ((rs = mysql_store_result(db)) == NULL)
62 {
63 log_error("Get view_article_log data failed\n");
64 return -3;
65 }
66
67 p_view_log->aid_base_cnt = 0;
68 p_view_log->aid_base = malloc(sizeof(int32_t) * mysql_num_rows(rs));
69 if (p_view_log->aid_base == NULL)
70 {
71 log_error("malloc(INT32 * %d) error: OOM\n", mysql_num_rows(rs));
72 mysql_free_result(rs);
73 mysql_close(db);
74 return -4;
75 }
76
77 while ((row = mysql_fetch_row(rs)))
78 {
79 p_view_log->aid_base[(p_view_log->aid_base_cnt)++] = atoi(row[0]);
80 }
81 mysql_free_result(rs);
82
83 mysql_close(db);
84
85 log_common("Loaded %d view_article_log records for uid=%d\n", p_view_log->aid_base_cnt, uid);
86
87 if (!keep_inc)
88 {
89 p_view_log->aid_inc_cnt = 0;
90 }
91
92 return 0;
93 }
94
95 int article_view_log_unload(ARTICLE_VIEW_LOG *p_view_log)
96 {
97 if (p_view_log == NULL)
98 {
99 log_error("NULL pointer error\n");
100 return -1;
101 }
102
103 if (p_view_log->aid_base != NULL)
104 {
105 free(p_view_log->aid_base);
106 p_view_log->aid_base = NULL;
107 p_view_log->aid_base_cnt = 0;
108 }
109
110 return 0;
111 }
112
113 int article_view_log_save_inc(const ARTICLE_VIEW_LOG *p_view_log)
114 {
115 MYSQL *db = NULL;
116 char sql[SQL_BUFFER_LEN];
117 char tuple_tmp[LINE_BUFFER_LEN];
118 int i;
119 int affected_record = 0;
120
121 if (p_view_log == NULL)
122 {
123 log_error("NULL pointer error\n");
124 return -1;
125 }
126
127 if (p_view_log->uid <= 0 || p_view_log->aid_inc_cnt == 0)
128 {
129 return 0;
130 }
131
132 if ((db = db_open()) == NULL)
133 {
134 log_error("article_view_log_load() error: Unable to open DB\n");
135 return -2;
136 }
137
138 snprintf(sql, sizeof(sql),
139 "INSERT IGNORE INTO view_article_log(AID, UID, dt) VALUES ");
140
141 for (i = 0; i < p_view_log->aid_inc_cnt; i++)
142 {
143 snprintf(tuple_tmp, sizeof(tuple_tmp),
144 "(%d, %d, NOW())",
145 p_view_log->aid_inc[i], p_view_log->uid);
146 strncat(sql, tuple_tmp, sizeof(sql) - 1 - strnlen(sql, sizeof(sql)));
147
148 if ((i + 1) % 100 == 0 || (i + 1) == p_view_log->aid_inc_cnt) // Insert 100 records per query
149 {
150 if (mysql_query(db, sql) != 0)
151 {
152 log_error("Add view_article_log error: %s\n", mysql_error(db));
153 mysql_close(db);
154 return -3;
155 }
156
157 affected_record += (int)mysql_affected_rows(db);
158
159 snprintf(sql, sizeof(sql),
160 "INSERT IGNORE INTO view_article_log(AID, UID, dt) VALUES ");
161 }
162 else
163 {
164 strncat(sql, ", ", sizeof(sql) - 1 - strnlen(sql, sizeof(sql)));
165 }
166 }
167
168 log_common("Saved %d view_article_log records for uid=%d\n", affected_record, p_view_log->uid);
169
170 mysql_close(db);
171
172 return 0;
173 }
174
175 int article_view_log_merge_inc(ARTICLE_VIEW_LOG *p_view_log)
176 {
177 int32_t *aid_new;
178 int aid_new_cnt;
179 int i, j, k;
180 int len;
181
182 if (p_view_log == NULL)
183 {
184 log_error("NULL pointer error\n");
185 return -1;
186 }
187
188 if (p_view_log->aid_inc_cnt == 0) // Nothing to be merged
189 {
190 return 0;
191 }
192
193 aid_new_cnt = p_view_log->aid_base_cnt + p_view_log->aid_inc_cnt;
194
195 aid_new = malloc(sizeof(int32_t) * (size_t)aid_new_cnt);
196 if (aid_new == NULL)
197 {
198 log_error("malloc(INT32 * %d) error: OOM\n", aid_new_cnt);
199 return -2;
200 }
201
202 for (i = 0, j = 0, k = 0; i < p_view_log->aid_base_cnt && j < p_view_log->aid_inc_cnt;)
203 {
204 if (p_view_log->aid_base[i] <= p_view_log->aid_inc[j])
205 {
206 if (p_view_log->aid_base[i] == p_view_log->aid_inc[j])
207 {
208 log_error("Duplicate aid = %d found in both Base (offset = %d) and Inc (offset = %d)\n",
209 p_view_log->aid_base[i], i, j);
210 j++; // Skip duplicate one in Inc
211 }
212
213 aid_new[k++] = p_view_log->aid_base[i++];
214 }
215 else if (p_view_log->aid_base[i] > p_view_log->aid_inc[j])
216 {
217 aid_new[k++] = p_view_log->aid_inc[j++];
218 }
219 }
220
221 len = p_view_log->aid_base_cnt - i;
222 if (len > 0)
223 {
224 memcpy(aid_new + k, p_view_log->aid_base + i,
225 sizeof(int32_t) * (size_t)len);
226 k += len;
227 }
228 len = p_view_log->aid_inc_cnt - j;
229 if (len > 0)
230 {
231 memcpy(aid_new + k, p_view_log->aid_inc + j,
232 sizeof(int32_t) * (size_t)len);
233 k += len;
234 }
235
236 free(p_view_log->aid_base);
237 p_view_log->aid_base = aid_new;
238 p_view_log->aid_base_cnt = k;
239
240 p_view_log->aid_inc_cnt = 0;
241
242 return 0;
243 }
244
245 int article_view_log_is_viewed(int32_t aid, const ARTICLE_VIEW_LOG *p_view_log)
246 {
247 int left;
248 int right;
249 int mid;
250 int i;
251
252 if (p_view_log == NULL)
253 {
254 log_error("NULL pointer error\n");
255 return -1;
256 }
257
258 for (i = 0; i < 2; i++)
259 {
260 left = 0;
261 right = (i == 0 ? p_view_log->aid_base_cnt : p_view_log->aid_inc_cnt) - 1;
262
263 if (right < 0)
264 {
265 continue;
266 }
267
268 while (left < right)
269 {
270 mid = (left + right) / 2;
271 if (aid < (i == 0 ? p_view_log->aid_base[mid] : p_view_log->aid_inc[mid]))
272 {
273 right = mid - 1;
274 }
275 else if (aid > (i == 0 ? p_view_log->aid_base[mid] : p_view_log->aid_inc[mid]))
276 {
277 left = mid + 1;
278 }
279 else // if (aid == p_view_log->aid_base[mid])
280 {
281 return 1;
282 }
283 }
284
285 if (aid == (i == 0 ? p_view_log->aid_base[left] : p_view_log->aid_inc[left])) // Found
286 {
287 return 1;
288 }
289 }
290
291 return 0;
292 }
293
294 int article_view_log_set_viewed(int32_t aid, ARTICLE_VIEW_LOG *p_view_log)
295 {
296 int left;
297 int right;
298 int mid;
299 int i;
300
301 if (p_view_log == NULL)
302 {
303 log_error("NULL pointer error\n");
304 return -1;
305 }
306
307 for (i = 0; i < 2; i++)
308 {
309 left = 0;
310 right = (i == 0 ? p_view_log->aid_base_cnt : p_view_log->aid_inc_cnt) - 1;
311
312 if (right < 0)
313 {
314 continue;
315 }
316
317 while (left < right)
318 {
319 mid = (left + right) / 2;
320 if (aid < (i == 0 ? p_view_log->aid_base[mid] : p_view_log->aid_inc[mid]))
321 {
322 right = mid - 1;
323 }
324 else if (aid > (i == 0 ? p_view_log->aid_base[mid] : p_view_log->aid_inc[mid]))
325 {
326 left = mid + 1;
327 }
328 else // if (aid == p_view_log->aid_base[mid])
329 {
330 return 0; // Already set
331 }
332 }
333
334 if (aid == (i == 0 ? p_view_log->aid_base[left] : p_view_log->aid_inc[left])) // Found
335 {
336 return 0; // Already set
337 }
338 }
339
340 // Merge if Inc is full
341 if (p_view_log->aid_inc_cnt >= MAX_VIEWED_AID_INC_CNT)
342 {
343 // Save incremental article view log
344 if (article_view_log_save_inc(p_view_log) < 0)
345 {
346 log_error("article_view_log_save_inc() error\n");
347 return -2;
348 }
349
350 article_view_log_merge_inc(p_view_log);
351
352 p_view_log->aid_inc[(p_view_log->aid_inc_cnt)++] = aid;
353
354 return 1; // Set complete
355 }
356
357 if (right < 0)
358 {
359 right = 0;
360 }
361 else if (aid > p_view_log->aid_inc[left])
362 {
363 right = left + 1;
364 }
365
366 if (p_view_log->aid_inc_cnt > right)
367 {
368 memmove(p_view_log->aid_inc + right + 1,
369 p_view_log->aid_inc + right,
370 sizeof(int32_t) * (size_t)(p_view_log->aid_inc_cnt - right));
371 }
372
373 p_view_log->aid_inc[right] = aid;
374 (p_view_log->aid_inc_cnt)++;
375
376 return 1; // Set complete
377 }

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