/[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.7 - (show annotations)
Sun May 25 06:45:42 2025 UTC (9 months, 3 weeks ago) by sysadm
Branch: MAIN
Changes since 1.6: +144 -7 lines
Content type: text/x-csrc
Move trie_dict to SHM

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

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