/[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.14 - (show annotations)
Wed Oct 15 03:10:47 2025 UTC (5 months ago) by sysadm
Branch: MAIN
Changes since 1.13: +15 -4 lines
Content type: text/x-csrc
Refine

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

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