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

Contents of /lbbs/src/trie_dict.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.9 - (show annotations)
Tue May 27 00:54:01 2025 UTC (9 months, 3 weeks ago) by sysadm
Branch: MAIN
Changes since 1.8: +2 -2 lines
Content type: text/x-csrc
Add attach/detach SHM in readonly mode for child process

1 /***************************************************************************
2 trie_dict.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 "trie_dict.h"
18 #include "log.h"
19 #include <errno.h>
20 #include <stdlib.h>
21 #include <strings.h>
22 #include <stdio.h>
23 #include <time.h>
24 #include <unistd.h>
25 #include <sys/shm.h>
26 #include <sys/ipc.h>
27
28 struct trie_node_pool_t
29 {
30 int shmid;
31 int node_count_limit;
32 int node_count;
33 TRIE_NODE *p_node_free_list;
34 };
35 typedef struct trie_node_pool_t TRIE_NODE_POOL;
36
37 static TRIE_NODE_POOL *p_trie_node_pool;
38
39 int trie_dict_init(const char *filename, int node_count_limit)
40 {
41 int shmid;
42 int proj_id;
43 key_t key;
44 size_t size;
45 void *p_shm;
46 TRIE_NODE *p_trie_nodes;
47 int i;
48
49 if (p_trie_node_pool != NULL)
50 {
51 log_error("trie_dict_pool already initialized\n");
52 return -1;
53 }
54
55 if (node_count_limit <= 0 || node_count_limit > TRIE_NODE_PER_POOL)
56 {
57 log_error("trie_dict_init(%d) error: invalid node_count_limit\n", node_count_limit);
58 return -1;
59 }
60
61 // Allocate shared memory
62 proj_id = (int)(time(NULL) % getpid());
63 key = ftok(filename, proj_id);
64 if (key == -1)
65 {
66 log_error("ftok(%s, %d) error (%d)\n", filename, proj_id, errno);
67 return -2;
68 }
69
70 size = sizeof(TRIE_NODE_POOL) + sizeof(TRIE_NODE) * (size_t)node_count_limit;
71 shmid = shmget(key, size, IPC_CREAT | IPC_EXCL | 0600);
72 if (shmid == -1)
73 {
74 log_error("shmget(size = %d) error (%d)\n", size, errno);
75 return -3;
76 }
77 p_shm = shmat(shmid, NULL, 0);
78 if (p_shm == (void *)-1)
79 {
80 log_error("shmat(shmid = %d) error (%d)\n", shmid, errno);
81 return -3;
82 }
83
84 p_trie_node_pool = p_shm;
85 p_trie_node_pool->shmid = shmid;
86 p_trie_node_pool->node_count_limit = node_count_limit;
87 p_trie_node_pool->node_count = 0;
88
89 p_trie_nodes = p_shm + sizeof(TRIE_NODE_POOL);
90 p_trie_node_pool->p_node_free_list = &(p_trie_nodes[0]);
91 for (i = 0; i < node_count_limit - 1; i++)
92 {
93 p_trie_nodes[i].p_nodes[0] = &(p_trie_nodes[i + 1]);
94 }
95 p_trie_nodes[node_count_limit - 1].p_nodes[0] = NULL;
96
97 return 0;
98 }
99
100 void trie_dict_cleanup(void)
101 {
102 int shmid;
103
104 if (p_trie_node_pool == NULL)
105 {
106 return;
107 }
108
109 shmid = p_trie_node_pool->shmid;
110
111 detach_trie_dict_shm();
112
113 if (shmctl(shmid, IPC_RMID, NULL) == -1)
114 {
115 log_error("shmctl(shmid = %d, IPC_RMID) error (%d)\n", shmid, errno);
116 }
117 }
118
119 int set_trie_dict_shm_readonly(void)
120 {
121 int shmid;
122 void *p_shm;
123
124 if (p_trie_node_pool == NULL)
125 {
126 log_error("trie_dict_pool not initialized\n");
127 return -1;
128 }
129
130 shmid = p_trie_node_pool->shmid;
131
132 // Remap shared memory in read-only mode
133 p_shm = shmat(shmid, p_trie_node_pool, SHM_RDONLY | SHM_REMAP);
134 if (p_shm == (void *)-1)
135 {
136 log_error("shmat(trie_node_pool shmid=%d) error (%d)\n", shmid, errno);
137 return -1;
138 }
139
140 p_trie_node_pool = p_shm;
141
142 return 0;
143 }
144
145 int detach_trie_dict_shm(void)
146 {
147 if (p_trie_node_pool != NULL && shmdt(p_trie_node_pool) == -1)
148 {
149 log_error("shmdt(trie_node_pool) error (%d)\n", errno);
150 return -1;
151 }
152
153 p_trie_node_pool = NULL;
154
155 return 0;
156 }
157
158 TRIE_NODE *trie_dict_create(void)
159 {
160 TRIE_NODE *p_dict = NULL;
161
162 if (p_trie_node_pool != NULL && p_trie_node_pool->p_node_free_list != NULL)
163 {
164 p_dict = p_trie_node_pool->p_node_free_list;
165 p_trie_node_pool->p_node_free_list = p_dict->p_nodes[0];
166
167 bzero(p_dict, sizeof(*p_dict));
168
169 p_trie_node_pool->node_count++;
170 }
171 else if (p_trie_node_pool != NULL)
172 {
173 log_error("trie_dict_create() error: node depleted %d >= %d\n", p_trie_node_pool->node_count, p_trie_node_pool->node_count_limit);
174 }
175
176 return p_dict;
177 }
178
179 void trie_dict_destroy(TRIE_NODE *p_dict)
180 {
181 if (p_trie_node_pool == NULL || p_dict == NULL)
182 {
183 return;
184 }
185
186 for (int i = 0; i < TRIE_CHILDREN; i++)
187 {
188 if (p_dict->p_nodes[i] != NULL)
189 {
190 trie_dict_destroy(p_dict->p_nodes[i]);
191 }
192 }
193
194 bzero(p_dict, sizeof(*p_dict));
195
196 p_dict->p_nodes[0] = p_trie_node_pool->p_node_free_list;
197 p_trie_node_pool->p_node_free_list = p_dict;
198
199 p_trie_node_pool->node_count--;
200 }
201
202 int trie_dict_set(TRIE_NODE *p_dict, const char *key, int64_t value)
203 {
204 int offset;
205
206 if (p_dict == NULL)
207 {
208 return -1;
209 }
210
211 while (key != NULL && *key != '\0')
212 {
213 offset = (256 + *key) % 256;
214 if (offset < 0 || offset >= TRIE_CHILDREN) // incorrect key character
215 {
216 return -1;
217 }
218
219 if (*(key + 1) == '\0')
220 {
221 if (p_dict->flags[offset] == 0 || p_dict->values[offset] != value)
222 {
223 p_dict->values[offset] = value;
224 p_dict->flags[offset] = 1;
225 return 1; // Set to new value
226 }
227 return 0; // Unchanged
228 }
229 else
230 {
231 if (p_dict->p_nodes[offset] == NULL)
232 {
233 if ((p_dict->p_nodes[offset] = trie_dict_create()) == NULL)
234 {
235 return -2; // OOM
236 }
237 }
238 p_dict = p_dict->p_nodes[offset];
239 key++;
240 }
241 }
242
243 return -1; // NULL key
244 }
245
246 int trie_dict_get(TRIE_NODE *p_dict, const char *key, int64_t *p_value)
247 {
248 int offset;
249
250 if (p_dict == NULL)
251 {
252 return -1;
253 }
254
255 while (key != NULL && *key != '\0')
256 {
257 offset = (256 + *key) % 256;
258 if (offset < 0 || offset >= TRIE_CHILDREN) // incorrect key character
259 {
260 return -1;
261 }
262
263 if (*(key + 1) == '\0')
264 {
265 if (p_dict->flags[offset] != 0)
266 {
267 *p_value = p_dict->values[offset];
268 return 1; // Found
269 }
270 else
271 {
272 return 0; // Not exist
273 }
274 }
275 else if (p_dict->p_nodes[offset] == NULL)
276 {
277 return 0; // Not exist
278 }
279 else
280 {
281 p_dict = p_dict->p_nodes[offset];
282 key++;
283 }
284 }
285
286 return -1; // NULL key
287 }
288
289 int trie_dict_del(TRIE_NODE *p_dict, const char *key)
290 {
291 int offset;
292
293 if (p_dict == NULL)
294 {
295 return -1;
296 }
297
298 while (key != NULL && *key != '\0')
299 {
300 offset = (256 + *key) % 256;
301 if (offset < 0 || offset >= TRIE_CHILDREN) // incorrect key character
302 {
303 return -1;
304 }
305
306 if (*(key + 1) == '\0')
307 {
308 if (p_dict->flags[offset] != 0)
309 {
310 p_dict->flags[offset] = 0;
311 p_dict->values[offset] = 0;
312 return 1; // Done
313 }
314 else
315 {
316 return 0; // Not exist
317 }
318 }
319 else if (p_dict->p_nodes[offset] == NULL)
320 {
321 return 0; // Not exist
322 }
323 else
324 {
325 p_dict = p_dict->p_nodes[offset];
326 key++;
327 }
328 }
329
330 return -1; // NULL key
331 }
332
333 static void _trie_dict_traverse(TRIE_NODE *p_dict, trie_dict_traverse_cb cb, char *key, int depth)
334 {
335 if (p_dict == NULL || depth >= TRIE_MAX_KEY_LEN)
336 {
337 return;
338 }
339
340 for (int i = 0; i < TRIE_CHILDREN; i++)
341 {
342 if (p_dict->flags[i] != 0)
343 {
344 key[depth] = (char)i;
345 key[depth + 1] = '\0';
346 (*cb)(key, p_dict->values[i]);
347 }
348
349 if (p_dict->p_nodes[i] != NULL && depth + 1 < TRIE_MAX_KEY_LEN)
350 {
351 key[depth] = (char)i;
352 _trie_dict_traverse(p_dict->p_nodes[i], cb, key, depth + 1);
353 }
354 }
355 }
356
357 void trie_dict_traverse(TRIE_NODE *p_dict, trie_dict_traverse_cb cb)
358 {
359 char key[TRIE_MAX_KEY_LEN + 1];
360
361 if (p_dict == NULL)
362 {
363 return;
364 }
365
366 _trie_dict_traverse(p_dict, cb, key, 0);
367 }
368
369 int trie_dict_used_nodes(void)
370 {
371 return (p_trie_node_pool == NULL ? -1 : p_trie_node_pool->node_count);
372 }

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