citrus_db_factory.c revision 1.6 1 /* $NetBSD: citrus_db_factory.c,v 1.6 2003/10/27 00:12:42 lukem Exp $ */
2
3 /*-
4 * Copyright (c)2003 Citrus Project,
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29 #if HAVE_NBTOOL_CONFIG_H
30 #include "nbtool_config.h"
31 #endif
32
33 #include <sys/cdefs.h>
34 #if defined(LIBC_SCCS) && !defined(lint)
35 __RCSID("$NetBSD: citrus_db_factory.c,v 1.6 2003/10/27 00:12:42 lukem Exp $");
36 #endif /* LIBC_SCCS and not lint */
37
38 #include <assert.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <errno.h>
43 #include <sys/types.h>
44 #include <sys/queue.h>
45
46 #include "citrus_namespace.h"
47 #include "citrus_region.h"
48 #include "citrus_db_file.h"
49 #include "citrus_db_factory.h"
50
51 struct _citrus_db_factory_entry {
52 SIMPLEQ_ENTRY(_citrus_db_factory_entry) de_entry;
53 struct _citrus_db_factory_entry *de_next;
54 u_int32_t de_hashvalue;
55 struct _region de_key;
56 int de_key_free;
57 struct _region de_data;
58 int de_data_free;
59 int de_idx;
60 };
61
62 struct _citrus_db_factory {
63 size_t df_num_entries;
64 SIMPLEQ_HEAD(, _citrus_db_factory_entry) df_entries;
65 size_t df_total_key_size;
66 size_t df_total_data_size;
67 u_int32_t (*df_hashfunc)(void *, struct _citrus_region *);
68 void *df_hashfunc_closure;
69 };
70
71 #define DB_ALIGN 16
72
73 int
74 _citrus_db_factory_create(struct _citrus_db_factory **rdf,
75 _citrus_db_hash_func_t hashfunc,
76 void *hashfunc_closure)
77 {
78 struct _citrus_db_factory *df;
79
80 df = malloc(sizeof(*df));
81 if (df == NULL)
82 return errno;
83 df->df_num_entries = 0;
84 df->df_total_key_size = df->df_total_data_size = 0;
85 SIMPLEQ_INIT(&df->df_entries);
86 df->df_hashfunc = hashfunc;
87 df->df_hashfunc_closure = hashfunc_closure;
88
89 *rdf = df;
90
91 return 0;
92 }
93
94 void
95 _citrus_db_factory_free(struct _citrus_db_factory *df)
96 {
97 struct _citrus_db_factory_entry *de;
98
99 while ((de = SIMPLEQ_FIRST(&df->df_entries)) != NULL) {
100 SIMPLEQ_REMOVE_HEAD(&df->df_entries, de_entry);
101 if (de->de_key_free)
102 free(_region_head(&de->de_key));
103 if (de->de_data_free)
104 free(_region_head(&de->de_data));
105 free(de);
106 }
107 free(df);
108 }
109
110 static __inline size_t
111 ceilto(size_t sz)
112 {
113 return (sz+DB_ALIGN-1) & ~(DB_ALIGN-1);
114 }
115
116 int
117 _citrus_db_factory_add(struct _citrus_db_factory *df,
118 struct _region *key, int keyfree,
119 struct _region *data, int datafree)
120 {
121 struct _citrus_db_factory_entry *de;
122
123 de = malloc(sizeof(*de));
124 if (de == NULL)
125 return -1;
126
127 de->de_hashvalue = df->df_hashfunc(df->df_hashfunc_closure, key);
128 de->de_key = *key;
129 de->de_key_free = keyfree;
130 de->de_data = *data;
131 de->de_data_free = datafree;
132 de->de_idx = -1;
133
134 SIMPLEQ_INSERT_TAIL(&df->df_entries, de, de_entry);
135 df->df_total_key_size += _region_size(key);
136 df->df_total_data_size += ceilto(_region_size(data));
137 df->df_num_entries++;
138
139 return 0;
140
141 }
142
143 int
144 _citrus_db_factory_add_by_string(struct _citrus_db_factory *df,
145 const char *key,
146 struct _citrus_region *data, int datafree)
147 {
148 struct _region r;
149 char *tmp;
150 tmp = strdup(key);
151 if (tmp == NULL)
152 return errno;
153 _region_init(&r, tmp, strlen(key));
154 return _citrus_db_factory_add(df, &r, 1, data, datafree);
155 }
156
157 int
158 _citrus_db_factory_add8_by_string(struct _citrus_db_factory *df,
159 const char *key, u_int8_t val)
160 {
161 struct _region r;
162 u_int8_t *p;
163
164 p = malloc(sizeof(*p));
165 if (p == NULL)
166 return errno;
167 *p = val;
168 _region_init(&r, p, 1);
169 return _citrus_db_factory_add_by_string(df, key, &r, 1);
170 }
171
172 int
173 _citrus_db_factory_add16_by_string(struct _citrus_db_factory *df,
174 const char *key, u_int16_t val)
175 {
176 struct _region r;
177 u_int16_t *p;
178
179 p = malloc(sizeof(*p));
180 if (p == NULL)
181 return errno;
182 *p = htons(val);
183 _region_init(&r, p, 2);
184 return _citrus_db_factory_add_by_string(df, key, &r, 1);
185 }
186
187 int
188 _citrus_db_factory_add32_by_string(struct _citrus_db_factory *df,
189 const char *key, u_int32_t val)
190 {
191 struct _region r;
192 u_int32_t *p;
193
194 p = malloc(sizeof(*p));
195 if (p == NULL)
196 return errno;
197 *p = htonl(val);
198 _region_init(&r, p, 4);
199 return _citrus_db_factory_add_by_string(df, key, &r, 1);
200 }
201
202 int
203 _citrus_db_factory_add_string_by_string(struct _citrus_db_factory *df,
204 const char *key, const char *data)
205 {
206 char *p;
207 struct _region r;
208
209 p = strdup(data);
210 if (p == NULL)
211 return errno;
212 _region_init(&r, p, strlen(p)+1);
213 return _citrus_db_factory_add_by_string(df, key, &r, 1);
214 }
215
216 size_t
217 _citrus_db_factory_calc_size(struct _citrus_db_factory *df)
218 {
219 size_t sz;
220
221 sz = ceilto(_CITRUS_DB_HEADER_SIZE);
222 sz += ceilto(_CITRUS_DB_ENTRY_SIZE * df->df_num_entries);
223 sz += ceilto(df->df_total_key_size);
224 sz += df->df_total_data_size;
225
226 return sz;
227 }
228
229 static __inline void
230 put8(struct _region *r, size_t *rofs, u_int8_t val)
231 {
232 *(u_int8_t *)_region_offset(r, *rofs) = val;
233 *rofs += 1;
234 }
235
236 static __inline void
237 put16(struct _region *r, size_t *rofs, u_int16_t val)
238 {
239 val = htons(val);
240 memcpy(_region_offset(r, *rofs), &val, 2);
241 *rofs += 2;
242 }
243
244 static __inline void
245 put32(struct _region *r, size_t *rofs, u_int32_t val)
246 {
247 val = htonl(val);
248 memcpy(_region_offset(r, *rofs), &val, 4);
249 *rofs += 4;
250 }
251
252 static __inline void
253 putpad(struct _region *r, size_t *rofs)
254 {
255 size_t i;
256 for (i=ceilto(*rofs)-*rofs; i>0; i--)
257 put8(r, rofs, 0);
258 }
259
260 static __inline void
261 dump_header(struct _region *r, const char *magic, size_t *rofs,
262 size_t num_entries)
263 {
264 while (*rofs<_CITRUS_DB_MAGIC_SIZE)
265 put8(r, rofs, *magic++);
266 put32(r, rofs, num_entries);
267 put32(r, rofs, _CITRUS_DB_HEADER_SIZE);
268 }
269
270 int
271 _citrus_db_factory_serialize(struct _citrus_db_factory *df, const char *magic,
272 struct _region *r)
273 {
274 size_t i, ofs, keyofs, dataofs, nextofs;
275 struct _citrus_db_factory_entry *de, **depp, *det;
276
277 ofs = 0;
278 /* check whether more than 0 entries exist */
279 if (df->df_num_entries == 0) {
280 dump_header(r, magic, &ofs, 0);
281 return 0;
282 }
283 /* allocate hash table */
284 depp = malloc(sizeof(*depp) * df->df_num_entries);
285 if (depp == NULL)
286 return -1;
287 for (i = 0; i < df->df_num_entries; i++)
288 depp[i] = NULL;
289
290 /* step1: store the entries which are not conflicting */
291 SIMPLEQ_FOREACH(de, &df->df_entries, de_entry) {
292 de->de_hashvalue %= df->df_num_entries;
293 de->de_idx = -1;
294 de->de_next = NULL;
295 if (depp[de->de_hashvalue] == NULL) {
296 depp[de->de_hashvalue] = de;
297 de->de_idx = (int)de->de_hashvalue;
298 }
299 }
300
301 /* step2: resolve conflicts */
302 i = 0;
303 SIMPLEQ_FOREACH(de, &df->df_entries, de_entry) {
304 if (de->de_idx == -1) {
305 det = depp[de->de_hashvalue];
306 while (det->de_next != NULL)
307 det = det->de_next;
308 det->de_next = de;
309 while (depp[i] != NULL)
310 i++;
311 depp[i] = de;
312 de->de_idx = (int)i;
313 }
314 }
315
316 keyofs =
317 _CITRUS_DB_HEADER_SIZE +
318 ceilto(df->df_num_entries*_CITRUS_DB_ENTRY_SIZE);
319 dataofs = keyofs + ceilto(df->df_total_key_size);
320
321 /* dump header */
322 dump_header(r, magic, &ofs, df->df_num_entries);
323
324 /* dump entries */
325 for (i=0; i<df->df_num_entries; i++) {
326 de = depp[i];
327 nextofs = 0;
328 if (de->de_next) {
329 nextofs =
330 _CITRUS_DB_HEADER_SIZE +
331 de->de_next->de_idx * _CITRUS_DB_ENTRY_SIZE;
332 }
333 put32(r, &ofs, de->de_hashvalue);
334 put32(r, &ofs, nextofs);
335 put32(r, &ofs, keyofs);
336 put32(r, &ofs, _region_size(&de->de_key));
337 put32(r, &ofs, dataofs);
338 put32(r, &ofs, _region_size(&de->de_data));
339 memcpy(_region_offset(r, keyofs),
340 _region_head(&de->de_key), _region_size(&de->de_key));
341 keyofs += _region_size(&de->de_key);
342 memcpy(_region_offset(r, dataofs),
343 _region_head(&de->de_data), _region_size(&de->de_data));
344 dataofs += _region_size(&de->de_data);
345 putpad(r, &dataofs);
346 }
347 putpad(r, &ofs);
348 putpad(r, &keyofs);
349 free(depp);
350
351 return 0;
352 }
353