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