/[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.3 - (show annotations)
Sat Jun 7 10:00:10 2025 UTC (9 months, 1 week ago) by sysadm
Branch: MAIN
Changes since 1.2: +28 -7 lines
Content type: text/x-csrc
Appy article_view_log to section_list

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 "log.h"
19 #include "common.h"
20 #include "database.h"
21 #include <stdlib.h>
22
23 #define _XOPEN_SOURCE 500
24 #define _POSIX_C_SOURCE 200809L
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;
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 return -3;
165 }
166
167 affected_record += (int)mysql_affected_rows(db);
168
169 snprintf(sql, sizeof(sql),
170 "INSERT IGNORE INTO view_article_log(AID, UID, dt) VALUES ");
171 }
172 else
173 {
174 strncat(sql, ", ", sizeof(sql) - 1 - strnlen(sql, sizeof(sql)));
175 }
176 }
177
178 log_common("Saved %d view_article_log records for uid=%d\n", affected_record, p_view_log->uid);
179
180 mysql_close(db);
181
182 return 0;
183 }
184
185 int article_view_log_merge_inc(ARTICLE_VIEW_LOG *p_view_log)
186 {
187 int32_t *aid_new;
188 int aid_new_cnt;
189 int i, j, k;
190
191 if (p_view_log == NULL)
192 {
193 log_error("article_view_log_merge_inc() error: NULL pointer\n");
194 return -1;
195 }
196
197 if (p_view_log->aid_inc_cnt == 0) // Nothing to be merged
198 {
199 return 0;
200 }
201
202 aid_new_cnt = p_view_log->aid_base_cnt + p_view_log->aid_inc_cnt;
203
204 aid_new = malloc(sizeof(int32_t) * (size_t)aid_new_cnt);
205 if (aid_new == NULL)
206 {
207 log_error("malloc(INT32 * %d) error: OOM\n", aid_new_cnt);
208 return -2;
209 }
210
211 for (i = 0, j = 0, k = 0; i < p_view_log->aid_base_cnt && j < p_view_log->aid_inc_cnt;)
212 {
213 if (p_view_log->aid_base[i] <= p_view_log->aid_inc[j])
214 {
215 if (p_view_log->aid_base[i] == p_view_log->aid_inc[j])
216 {
217 log_error("Duplicate aid = %d found in both Base (offset = %d) and Inc (offset = %d)\n",
218 p_view_log->aid_base[i], i, j);
219 j++; // Skip duplicate one in Inc
220 }
221
222 aid_new[k++] = p_view_log->aid_base[i++];
223 }
224 else if (p_view_log->aid_base[i] > p_view_log->aid_inc[j])
225 {
226 aid_new[k++] = p_view_log->aid_inc[j++];
227 }
228 }
229
230 memcpy(aid_new + k, p_view_log->aid_base + i, sizeof(int32_t) * (size_t)(p_view_log->aid_base_cnt - i));
231 k += (p_view_log->aid_base_cnt - i);
232 memcpy(aid_new + k, p_view_log->aid_inc + j, sizeof(int32_t) * (size_t)(p_view_log->aid_inc_cnt - j));
233 k += (p_view_log->aid_inc_cnt - j);
234
235 free(p_view_log->aid_base);
236 p_view_log->aid_base = aid_new;
237 p_view_log->aid_base_cnt = k;
238
239 p_view_log->aid_inc_cnt = 0;
240
241 return 0;
242 }
243
244 int article_view_log_is_viewed(int32_t aid, const ARTICLE_VIEW_LOG *p_view_log)
245 {
246 int left;
247 int right;
248 int mid;
249 int i;
250
251 if (p_view_log == NULL)
252 {
253 log_error("article_view_log_is_viewed() error: NULL pointer\n");
254 return -1;
255 }
256
257 for (i = 0; i < 2; i++)
258 {
259 left = 0;
260 right = (i == 0 ? p_view_log->aid_base_cnt : p_view_log->aid_inc_cnt) - 1;
261
262 if (right < 0)
263 {
264 continue;
265 }
266
267 while (left < right)
268 {
269 mid = (left + right) / 2;
270 if (aid < (i == 0 ? p_view_log->aid_base[mid] : p_view_log->aid_inc[mid]))
271 {
272 right = mid;
273 }
274 else if (aid > (i == 0 ? p_view_log->aid_base[mid] : p_view_log->aid_inc[mid]))
275 {
276 left = mid + 1;
277 }
278 else // if (aid == p_view_log->aid_base[mid])
279 {
280 return 1;
281 }
282 }
283
284 if (aid == (i == 0 ? p_view_log->aid_base[left] : p_view_log->aid_inc[left])) // Found
285 {
286 return 1;
287 }
288 }
289
290 return 0;
291 }
292
293 int article_view_log_set_viewed(int32_t aid, ARTICLE_VIEW_LOG *p_view_log)
294 {
295 int left;
296 int right;
297 int mid;
298 int i;
299
300 if (p_view_log == NULL)
301 {
302 log_error("article_view_log_set_viewed() error: NULL pointer\n");
303 return -1;
304 }
305
306 for (i = 0; i < 2; i++)
307 {
308 left = 0;
309 right = (i == 0 ? p_view_log->aid_base_cnt : p_view_log->aid_inc_cnt) - 1;
310
311 if (right < 0)
312 {
313 continue;
314 }
315
316 while (left < right)
317 {
318 mid = (left + right) / 2;
319 if (aid < (i == 0 ? p_view_log->aid_base[mid] : p_view_log->aid_inc[mid]))
320 {
321 right = mid;
322 }
323 else if (aid > (i == 0 ? p_view_log->aid_base[mid] : p_view_log->aid_inc[mid]))
324 {
325 left = mid + 1;
326 }
327 else // if (aid == p_view_log->aid_base[mid])
328 {
329 return 0; // Already set
330 }
331 }
332
333 if (aid == (i == 0 ? p_view_log->aid_base[left] : p_view_log->aid_inc[left])) // Found
334 {
335 return 0; // Already set
336 }
337 }
338
339 // Merge if Inc is full
340 if (p_view_log->aid_inc_cnt >= MAX_AID_INC_CNT)
341 {
342 // Save incremental article view log
343 if (article_view_log_save_inc(p_view_log) < 0)
344 {
345 log_error("article_view_log_save_inc() error\n");
346 return -2;
347 }
348
349 article_view_log_merge_inc(p_view_log);
350
351 p_view_log->aid_inc[(p_view_log->aid_inc_cnt)++] = aid;
352
353 return 1; // Set complete
354 }
355
356 if (right < 0)
357 {
358 right = 0;
359 }
360 else if (aid > p_view_log->aid_inc[left])
361 {
362 right = left + 1;
363 }
364
365 for (i = p_view_log->aid_inc_cnt - 1; i >= right; i--)
366 {
367 p_view_log->aid_inc[i + 1] = p_view_log->aid_inc[i];
368 }
369
370 p_view_log->aid_inc[right] = aid;
371 (p_view_log->aid_inc_cnt)++;
372
373 return 1; // Set complete
374 }

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