/[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.20 - (show annotations)
Sat Jan 3 10:27:14 2026 UTC (2 months, 1 week ago) by sysadm
Branch: MAIN
CVS Tags: HEAD
Changes since 1.19: +1 -1 lines
Content type: text/x-csrc
Update copyright info

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

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