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

Annotation of /lbbs/src/trie_dict.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.14 - (hide annotations)
Tue Nov 4 14:30:44 2025 UTC (4 months, 1 week ago) by sysadm
Branch: MAIN
Changes since 1.13: +1 -1 lines
Content type: text/x-csrc
Call shmctl() on valid shmid only

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

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