/[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.5 - (show annotations)
Mon Jun 16 14:30:44 2025 UTC (9 months ago) by sysadm
Branch: MAIN
Changes since 1.4: +3 -3 lines
Content type: text/x-csrc
Change gcc std to c17
Update header macro accordingly

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 #define _XOPEN_SOURCE 500
18 #define _POSIX_C_SOURCE 200809L
19
20 #include "article_view_log.h"
21 #include "log.h"
22 #include "common.h"
23 #include "database.h"
24 #include <stdlib.h>
25 #include <string.h>
26
27 ARTICLE_VIEW_LOG BBS_article_view_log;
28
29 int article_view_log_load(int uid, ARTICLE_VIEW_LOG *p_view_log, int keep_inc)
30 {
31 MYSQL *db;
32 MYSQL_RES *rs;
33 MYSQL_ROW row;
34 char sql[SQL_BUFFER_LEN];
35
36 if (p_view_log == NULL)
37 {
38 log_error("article_view_log_load() error: NULL pointer\n");
39 return -1;
40 }
41
42 p_view_log->uid = uid;
43
44 if (uid == 0)
45 {
46 p_view_log->aid_base_cnt = 0;
47 p_view_log->aid_base = NULL;
48
49 if (!keep_inc)
50 {
51 p_view_log->aid_inc_cnt = 0;
52 }
53
54 return 0;
55 }
56
57 if ((db = db_open()) == NULL)
58 {
59 log_error("article_view_log_load() error: Unable to open DB\n");
60 return -2;
61 }
62
63 snprintf(sql, sizeof(sql),
64 "SELECT AID FROM view_article_log WHERE UID = %d "
65 "ORDER BY AID",
66 uid);
67 if (mysql_query(db, sql) != 0)
68 {
69 log_error("Query view_article_log error: %s\n", mysql_error(db));
70 return -3;
71 }
72 if ((rs = mysql_store_result(db)) == NULL)
73 {
74 log_error("Get view_article_log data failed\n");
75 return -3;
76 }
77
78 p_view_log->aid_base_cnt = 0;
79 p_view_log->aid_base = malloc(sizeof(int32_t) * mysql_num_rows(rs));
80 if (p_view_log->aid_base == NULL)
81 {
82 log_error("malloc(INT32 * %d) error: OOM\n", mysql_num_rows(rs));
83 mysql_free_result(rs);
84 mysql_close(db);
85 return -4;
86 }
87
88 while ((row = mysql_fetch_row(rs)))
89 {
90 p_view_log->aid_base[(p_view_log->aid_base_cnt)++] = atoi(row[0]);
91 }
92 mysql_free_result(rs);
93
94 mysql_close(db);
95
96 log_common("Loaded %d view_article_log records for uid=%d\n", p_view_log->aid_base_cnt, uid);
97
98 if (!keep_inc)
99 {
100 p_view_log->aid_inc_cnt = 0;
101 }
102
103 return 0;
104 }
105
106 int article_view_log_unload(ARTICLE_VIEW_LOG *p_view_log)
107 {
108 if (p_view_log == NULL)
109 {
110 log_error("article_view_log_unload() error: NULL pointer\n");
111 return -1;
112 }
113
114 if (p_view_log->aid_base != NULL)
115 {
116 free(p_view_log->aid_base);
117 p_view_log->aid_base = NULL;
118 p_view_log->aid_base_cnt = 0;
119 }
120
121 return 0;
122 }
123
124 int article_view_log_save_inc(const ARTICLE_VIEW_LOG *p_view_log)
125 {
126 MYSQL *db = NULL;
127 char sql[SQL_BUFFER_LEN];
128 char tuple_tmp[LINE_BUFFER_LEN];
129 int i;
130 int affected_record = 0;
131
132 if (p_view_log == NULL)
133 {
134 log_error("article_view_log_save_inc() error: NULL pointer\n");
135 return -1;
136 }
137
138 if (p_view_log->uid <= 0)
139 {
140 return 0;
141 }
142
143 if ((db = db_open()) == NULL)
144 {
145 log_error("article_view_log_load() error: Unable to open DB\n");
146 return -2;
147 }
148
149 snprintf(sql, sizeof(sql),
150 "INSERT IGNORE INTO view_article_log(AID, UID, dt) VALUES ");
151
152 for (i = 0; i < p_view_log->aid_inc_cnt; i++)
153 {
154 snprintf(tuple_tmp, sizeof(tuple_tmp),
155 "(%d, %d, NOW())",
156 p_view_log->aid_inc[i], p_view_log->uid);
157 strncat(sql, tuple_tmp, sizeof(sql) - 1 - strnlen(sql, sizeof(sql)));
158
159 if ((i + 1) % 100 == 0 || (i + 1) == p_view_log->aid_inc_cnt) // Insert 100 records per query
160 {
161 if (mysql_query(db, sql) != 0)
162 {
163 log_error("Add view_article_log error: %s\n", mysql_error(db));
164 mysql_close(db);
165 return -3;
166 }
167
168 affected_record += (int)mysql_affected_rows(db);
169
170 snprintf(sql, sizeof(sql),
171 "INSERT IGNORE INTO view_article_log(AID, UID, dt) VALUES ");
172 }
173 else
174 {
175 strncat(sql, ", ", sizeof(sql) - 1 - strnlen(sql, sizeof(sql)));
176 }
177 }
178
179 log_common("Saved %d view_article_log records for uid=%d\n", affected_record, p_view_log->uid);
180
181 mysql_close(db);
182
183 return 0;
184 }
185
186 int article_view_log_merge_inc(ARTICLE_VIEW_LOG *p_view_log)
187 {
188 int32_t *aid_new;
189 int aid_new_cnt;
190 int i, j, k;
191
192 if (p_view_log == NULL)
193 {
194 log_error("article_view_log_merge_inc() error: NULL pointer\n");
195 return -1;
196 }
197
198 if (p_view_log->aid_inc_cnt == 0) // Nothing to be merged
199 {
200 return 0;
201 }
202
203 aid_new_cnt = p_view_log->aid_base_cnt + p_view_log->aid_inc_cnt;
204
205 aid_new = malloc(sizeof(int32_t) * (size_t)aid_new_cnt);
206 if (aid_new == NULL)
207 {
208 log_error("malloc(INT32 * %d) error: OOM\n", aid_new_cnt);
209 return -2;
210 }
211
212 for (i = 0, j = 0, k = 0; i < p_view_log->aid_base_cnt && j < p_view_log->aid_inc_cnt;)
213 {
214 if (p_view_log->aid_base[i] <= p_view_log->aid_inc[j])
215 {
216 if (p_view_log->aid_base[i] == p_view_log->aid_inc[j])
217 {
218 log_error("Duplicate aid = %d found in both Base (offset = %d) and Inc (offset = %d)\n",
219 p_view_log->aid_base[i], i, j);
220 j++; // Skip duplicate one in Inc
221 }
222
223 aid_new[k++] = p_view_log->aid_base[i++];
224 }
225 else if (p_view_log->aid_base[i] > p_view_log->aid_inc[j])
226 {
227 aid_new[k++] = p_view_log->aid_inc[j++];
228 }
229 }
230
231 memcpy(aid_new + k, p_view_log->aid_base + i, sizeof(int32_t) * (size_t)(p_view_log->aid_base_cnt - i));
232 k += (p_view_log->aid_base_cnt - i);
233 memcpy(aid_new + k, p_view_log->aid_inc + j, sizeof(int32_t) * (size_t)(p_view_log->aid_inc_cnt - j));
234 k += (p_view_log->aid_inc_cnt - j);
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("article_view_log_is_viewed() error: NULL pointer\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;
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("article_view_log_set_viewed() error: NULL pointer\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;
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_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 for (i = p_view_log->aid_inc_cnt - 1; i >= right; i--)
367 {
368 p_view_log->aid_inc[i + 1] = p_view_log->aid_inc[i];
369 }
370
371 p_view_log->aid_inc[right] = aid;
372 (p_view_log->aid_inc_cnt)++;
373
374 return 1; // Set complete
375 }

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