xref: /minix3/lib/libc/cdb/cdbw.c (revision f14fb602092e015ff630df58e17c2a9cd57d29b3)
1*f14fb602SLionel Sambuc /*	$NetBSD: cdbw.c,v 1.5 2012/07/21 22:49:37 joerg Exp $	*/
22fe8fb19SBen Gras /*-
32fe8fb19SBen Gras  * Copyright (c) 2009, 2010 The NetBSD Foundation, Inc.
42fe8fb19SBen Gras  * All rights reserved.
52fe8fb19SBen Gras  *
62fe8fb19SBen Gras  * This code is derived from software contributed to The NetBSD Foundation
72fe8fb19SBen Gras  * by Joerg Sonnenberger.
82fe8fb19SBen Gras  *
92fe8fb19SBen Gras  * Redistribution and use in source and binary forms, with or without
102fe8fb19SBen Gras  * modification, are permitted provided that the following conditions
112fe8fb19SBen Gras  * are met:
122fe8fb19SBen Gras  *
132fe8fb19SBen Gras  * 1. Redistributions of source code must retain the above copyright
142fe8fb19SBen Gras  *    notice, this list of conditions and the following disclaimer.
152fe8fb19SBen Gras  * 2. Redistributions in binary form must reproduce the above copyright
162fe8fb19SBen Gras  *    notice, this list of conditions and the following disclaimer in
172fe8fb19SBen Gras  *    the documentation and/or other materials provided with the
182fe8fb19SBen Gras  *    distribution.
192fe8fb19SBen Gras  *
202fe8fb19SBen Gras  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
212fe8fb19SBen Gras  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
222fe8fb19SBen Gras  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
232fe8fb19SBen Gras  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
242fe8fb19SBen Gras  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
252fe8fb19SBen Gras  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
262fe8fb19SBen Gras  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
272fe8fb19SBen Gras  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
282fe8fb19SBen Gras  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
292fe8fb19SBen Gras  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
302fe8fb19SBen Gras  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
312fe8fb19SBen Gras  * SUCH DAMAGE.
322fe8fb19SBen Gras  */
332fe8fb19SBen Gras 
342fe8fb19SBen Gras #if HAVE_NBTOOL_CONFIG_H
352fe8fb19SBen Gras #include "nbtool_config.h"
362fe8fb19SBen Gras #endif
372fe8fb19SBen Gras 
382fe8fb19SBen Gras #include <sys/cdefs.h>
39*f14fb602SLionel Sambuc __RCSID("$NetBSD: cdbw.c,v 1.5 2012/07/21 22:49:37 joerg Exp $");
402fe8fb19SBen Gras 
412fe8fb19SBen Gras #include "namespace.h"
422fe8fb19SBen Gras 
43*f14fb602SLionel Sambuc #if !HAVE_NBTOOL_CONFIG_H || HAVE_SYS_ENDIAN_H
442fe8fb19SBen Gras #include <sys/endian.h>
45*f14fb602SLionel Sambuc #endif
462fe8fb19SBen Gras #include <sys/queue.h>
472fe8fb19SBen Gras #include <cdbw.h>
482fe8fb19SBen Gras #include <stdlib.h>
492fe8fb19SBen Gras #include <string.h>
502fe8fb19SBen Gras #include <unistd.h>
512fe8fb19SBen Gras 
522fe8fb19SBen Gras #ifdef __weak_alias
532fe8fb19SBen Gras __weak_alias(cdbw_close,_cdbw_close)
542fe8fb19SBen Gras __weak_alias(cdbw_open,_cdbw_open)
552fe8fb19SBen Gras __weak_alias(cdbw_output,_cdbw_output)
562fe8fb19SBen Gras __weak_alias(cdbw_put,_cdbw_put)
572fe8fb19SBen Gras __weak_alias(cdbw_put_data,_cdbw_put_data)
582fe8fb19SBen Gras __weak_alias(cdbw_put_key,_cdbw_put_key)
592fe8fb19SBen Gras #endif
602fe8fb19SBen Gras 
612fe8fb19SBen Gras struct key_hash {
622fe8fb19SBen Gras 	SLIST_ENTRY(key_hash) link;
632fe8fb19SBen Gras 	uint32_t hashes[3];
642fe8fb19SBen Gras 	uint32_t idx;
652fe8fb19SBen Gras 	void *key;
662fe8fb19SBen Gras 	size_t keylen;
672fe8fb19SBen Gras };
682fe8fb19SBen Gras 
692fe8fb19SBen Gras SLIST_HEAD(key_hash_head, key_hash);
702fe8fb19SBen Gras 
712fe8fb19SBen Gras struct cdbw {
722fe8fb19SBen Gras 	size_t data_counter;
732fe8fb19SBen Gras 	size_t data_allocated;
742fe8fb19SBen Gras 	size_t data_size;
752fe8fb19SBen Gras 	size_t *data_len;
762fe8fb19SBen Gras 	void **data_ptr;
772fe8fb19SBen Gras 
782fe8fb19SBen Gras 	size_t hash_size;
792fe8fb19SBen Gras 	struct key_hash_head *hash;
802fe8fb19SBen Gras 	size_t key_counter;
812fe8fb19SBen Gras };
822fe8fb19SBen Gras 
832fe8fb19SBen Gras  /* Max. data counter that allows the index size to be 32bit. */
842fe8fb19SBen Gras static const uint32_t max_data_counter = 0xccccccccU;
852fe8fb19SBen Gras 
862fe8fb19SBen Gras struct cdbw *
cdbw_open(void)872fe8fb19SBen Gras cdbw_open(void)
882fe8fb19SBen Gras {
892fe8fb19SBen Gras 	struct cdbw *cdbw;
902fe8fb19SBen Gras 	size_t i;
912fe8fb19SBen Gras 
922fe8fb19SBen Gras 	cdbw = calloc(sizeof(*cdbw), 1);
932fe8fb19SBen Gras 	if (cdbw == NULL)
942fe8fb19SBen Gras 		return NULL;
952fe8fb19SBen Gras 
962fe8fb19SBen Gras 	cdbw->hash_size = 1024;
972fe8fb19SBen Gras 	cdbw->hash = calloc(cdbw->hash_size, sizeof(*cdbw->hash));
982fe8fb19SBen Gras 	if (cdbw->hash == NULL) {
992fe8fb19SBen Gras 		free(cdbw);
1002fe8fb19SBen Gras 		return NULL;
1012fe8fb19SBen Gras 	}
1022fe8fb19SBen Gras 
1032fe8fb19SBen Gras 	for (i = 0; i < cdbw->hash_size; ++i)
1042fe8fb19SBen Gras 		SLIST_INIT(cdbw->hash + i);
1052fe8fb19SBen Gras 
1062fe8fb19SBen Gras 	return cdbw;
1072fe8fb19SBen Gras }
1082fe8fb19SBen Gras 
1092fe8fb19SBen Gras int
cdbw_put(struct cdbw * cdbw,const void * key,size_t keylen,const void * data,size_t datalen)1102fe8fb19SBen Gras cdbw_put(struct cdbw *cdbw, const void *key, size_t keylen,
1112fe8fb19SBen Gras     const void *data, size_t datalen)
1122fe8fb19SBen Gras {
1132fe8fb19SBen Gras 	uint32_t idx;
1142fe8fb19SBen Gras 	int rv;
1152fe8fb19SBen Gras 
1162fe8fb19SBen Gras 	rv = cdbw_put_data(cdbw, data, datalen, &idx);
1172fe8fb19SBen Gras 	if (rv)
1182fe8fb19SBen Gras 		return rv;
1192fe8fb19SBen Gras 	rv = cdbw_put_key(cdbw, key, keylen, idx);
1202fe8fb19SBen Gras 	if (rv) {
1212fe8fb19SBen Gras 		--cdbw->data_counter;
1222fe8fb19SBen Gras 		free(cdbw->data_ptr[cdbw->data_counter]);
1232fe8fb19SBen Gras 		cdbw->data_size -= datalen;
1242fe8fb19SBen Gras 		return rv;
1252fe8fb19SBen Gras 	}
1262fe8fb19SBen Gras 	return 0;
1272fe8fb19SBen Gras }
1282fe8fb19SBen Gras 
1292fe8fb19SBen Gras int
cdbw_put_data(struct cdbw * cdbw,const void * data,size_t datalen,uint32_t * idx)1302fe8fb19SBen Gras cdbw_put_data(struct cdbw *cdbw, const void *data, size_t datalen,
1312fe8fb19SBen Gras     uint32_t *idx)
1322fe8fb19SBen Gras {
1332fe8fb19SBen Gras 
1342fe8fb19SBen Gras 	if (cdbw->data_counter == max_data_counter)
1352fe8fb19SBen Gras 		return -1;
1362fe8fb19SBen Gras 
1372fe8fb19SBen Gras 	if (cdbw->data_size + datalen < cdbw->data_size ||
1382fe8fb19SBen Gras 	    cdbw->data_size + datalen > 0xffffffffU)
1392fe8fb19SBen Gras 		return -1; /* Overflow */
1402fe8fb19SBen Gras 
1412fe8fb19SBen Gras 	if (cdbw->data_allocated == cdbw->data_counter) {
1422fe8fb19SBen Gras 		void **new_data_ptr;
1432fe8fb19SBen Gras 		size_t *new_data_len;
1442fe8fb19SBen Gras 		size_t new_allocated;
1452fe8fb19SBen Gras 
1462fe8fb19SBen Gras 		if (cdbw->data_allocated == 0)
1472fe8fb19SBen Gras 			new_allocated = 256;
1482fe8fb19SBen Gras 		else
1492fe8fb19SBen Gras 			new_allocated = cdbw->data_allocated * 2;
1502fe8fb19SBen Gras 
1512fe8fb19SBen Gras 		new_data_ptr = realloc(cdbw->data_ptr,
1522fe8fb19SBen Gras 		    sizeof(*cdbw->data_ptr) * new_allocated);
1532fe8fb19SBen Gras 		if (new_data_ptr == NULL)
1542fe8fb19SBen Gras 			return -1;
1552fe8fb19SBen Gras 		cdbw->data_ptr = new_data_ptr;
1562fe8fb19SBen Gras 
1572fe8fb19SBen Gras 		new_data_len = realloc(cdbw->data_len,
1582fe8fb19SBen Gras 		    sizeof(*cdbw->data_len) * new_allocated);
1592fe8fb19SBen Gras 		if (new_data_len == NULL)
1602fe8fb19SBen Gras 			return -1;
1612fe8fb19SBen Gras 		cdbw->data_len = new_data_len;
1622fe8fb19SBen Gras 
1632fe8fb19SBen Gras 		cdbw->data_allocated = new_allocated;
1642fe8fb19SBen Gras 	}
1652fe8fb19SBen Gras 
1662fe8fb19SBen Gras 	cdbw->data_ptr[cdbw->data_counter] = malloc(datalen);
1672fe8fb19SBen Gras 	if (cdbw->data_ptr[cdbw->data_counter] == NULL)
1682fe8fb19SBen Gras 		return -1;
1692fe8fb19SBen Gras 	memcpy(cdbw->data_ptr[cdbw->data_counter], data, datalen);
1702fe8fb19SBen Gras 	cdbw->data_len[cdbw->data_counter] = datalen;
1712fe8fb19SBen Gras 	cdbw->data_size += datalen;
1722fe8fb19SBen Gras 	*idx = cdbw->data_counter++;
1732fe8fb19SBen Gras 	return 0;
1742fe8fb19SBen Gras }
1752fe8fb19SBen Gras 
1762fe8fb19SBen Gras int
cdbw_put_key(struct cdbw * cdbw,const void * key,size_t keylen,uint32_t idx)1772fe8fb19SBen Gras cdbw_put_key(struct cdbw *cdbw, const void *key, size_t keylen, uint32_t idx)
1782fe8fb19SBen Gras {
1792fe8fb19SBen Gras 	uint32_t hashes[3];
1802fe8fb19SBen Gras 	struct key_hash_head *head, *head2, *new_head;
1812fe8fb19SBen Gras 	struct key_hash *key_hash;
1822fe8fb19SBen Gras 	size_t new_hash_size, i;
1832fe8fb19SBen Gras 
1842fe8fb19SBen Gras 	if (idx >= cdbw->data_counter ||
1852fe8fb19SBen Gras 	    cdbw->key_counter == max_data_counter)
1862fe8fb19SBen Gras 		return -1;
1872fe8fb19SBen Gras 
1882fe8fb19SBen Gras 	mi_vector_hash(key, keylen, 0, hashes);
1892fe8fb19SBen Gras 
1902fe8fb19SBen Gras 	head = cdbw->hash + (hashes[0] & (cdbw->hash_size - 1));
1912fe8fb19SBen Gras 	SLIST_FOREACH(key_hash, head, link) {
1922fe8fb19SBen Gras 		if (key_hash->keylen != keylen)
1932fe8fb19SBen Gras 			continue;
1942fe8fb19SBen Gras 		if (key_hash->hashes[0] != hashes[0])
1952fe8fb19SBen Gras 			continue;
1962fe8fb19SBen Gras 		if (key_hash->hashes[1] != hashes[1])
1972fe8fb19SBen Gras 			continue;
1982fe8fb19SBen Gras 		if (key_hash->hashes[2] != hashes[2])
1992fe8fb19SBen Gras 			continue;
2002fe8fb19SBen Gras 		if (memcmp(key, key_hash->key, keylen))
2012fe8fb19SBen Gras 			continue;
2022fe8fb19SBen Gras 		return -1;
2032fe8fb19SBen Gras 	}
2042fe8fb19SBen Gras 	key_hash = malloc(sizeof(*key_hash));
2052fe8fb19SBen Gras 	if (key_hash == NULL)
2062fe8fb19SBen Gras 		return -1;
2072fe8fb19SBen Gras 	key_hash->key = malloc(keylen);
2082fe8fb19SBen Gras 	if (key_hash->key == NULL) {
2092fe8fb19SBen Gras 		free(key_hash);
2102fe8fb19SBen Gras 		return -1;
2112fe8fb19SBen Gras 	}
2122fe8fb19SBen Gras 	memcpy(key_hash->key, key, keylen);
2132fe8fb19SBen Gras 	key_hash->hashes[0] = hashes[0];
2142fe8fb19SBen Gras 	key_hash->hashes[1] = hashes[1];
2152fe8fb19SBen Gras 	key_hash->hashes[2] = hashes[2];
2162fe8fb19SBen Gras 	key_hash->keylen = keylen;
2172fe8fb19SBen Gras 	key_hash->idx = idx;
2182fe8fb19SBen Gras 	SLIST_INSERT_HEAD(head, key_hash, link);
2192fe8fb19SBen Gras 	++cdbw->key_counter;
2202fe8fb19SBen Gras 
2212fe8fb19SBen Gras 	if (cdbw->key_counter <= cdbw->hash_size)
2222fe8fb19SBen Gras 		return 0;
2232fe8fb19SBen Gras 
2242fe8fb19SBen Gras 	/* Try to resize the hash table, but ignore errors. */
2252fe8fb19SBen Gras 	new_hash_size = cdbw->hash_size * 2;
2262fe8fb19SBen Gras 	new_head = calloc(sizeof(*new_head), new_hash_size);
2272fe8fb19SBen Gras 	if (new_head == NULL)
2282fe8fb19SBen Gras 		return 0;
2292fe8fb19SBen Gras 
2302fe8fb19SBen Gras 	head = &cdbw->hash[hashes[0] & (cdbw->hash_size - 1)];
2312fe8fb19SBen Gras 	for (i = 0; i < new_hash_size; ++i)
2322fe8fb19SBen Gras 		SLIST_INIT(new_head + i);
2332fe8fb19SBen Gras 
2342fe8fb19SBen Gras 	for (i = 0; i < cdbw->hash_size; ++i) {
2352fe8fb19SBen Gras 		head = cdbw->hash + i;
2362fe8fb19SBen Gras 
2372fe8fb19SBen Gras 		while ((key_hash = SLIST_FIRST(head)) != NULL) {
2382fe8fb19SBen Gras 			SLIST_REMOVE_HEAD(head, link);
2392fe8fb19SBen Gras 			head2 = new_head +
2402fe8fb19SBen Gras 			    (key_hash->hashes[0] & (new_hash_size - 1));
2412fe8fb19SBen Gras 			SLIST_INSERT_HEAD(head2, key_hash, link);
2422fe8fb19SBen Gras 		}
2432fe8fb19SBen Gras 	}
2442fe8fb19SBen Gras 	free(cdbw->hash);
2452fe8fb19SBen Gras 	cdbw->hash_size = new_hash_size;
2462fe8fb19SBen Gras 	cdbw->hash = new_head;
2472fe8fb19SBen Gras 
2482fe8fb19SBen Gras 	return 0;
2492fe8fb19SBen Gras }
2502fe8fb19SBen Gras 
2512fe8fb19SBen Gras void
cdbw_close(struct cdbw * cdbw)2522fe8fb19SBen Gras cdbw_close(struct cdbw *cdbw)
2532fe8fb19SBen Gras {
2542fe8fb19SBen Gras 	struct key_hash_head *head;
2552fe8fb19SBen Gras 	struct key_hash *key_hash;
2562fe8fb19SBen Gras 	size_t i;
2572fe8fb19SBen Gras 
2582fe8fb19SBen Gras 	for (i = 0; i < cdbw->hash_size; ++i) {
2592fe8fb19SBen Gras 		head = cdbw->hash + i;
2602fe8fb19SBen Gras 		while ((key_hash = SLIST_FIRST(head)) != NULL) {
2612fe8fb19SBen Gras 			SLIST_REMOVE_HEAD(head, link);
2622fe8fb19SBen Gras 			free(key_hash->key);
2632fe8fb19SBen Gras 			free(key_hash);
2642fe8fb19SBen Gras 		}
2652fe8fb19SBen Gras 	}
2662fe8fb19SBen Gras 
2672fe8fb19SBen Gras 	for (i = 0; i < cdbw->data_counter; ++i)
2682fe8fb19SBen Gras 		free(cdbw->data_ptr[i]);
2692fe8fb19SBen Gras 	free(cdbw->data_ptr);
2702fe8fb19SBen Gras 	free(cdbw->data_len);
2712fe8fb19SBen Gras 	free(cdbw->hash);
2722fe8fb19SBen Gras 	free(cdbw);
2732fe8fb19SBen Gras }
2742fe8fb19SBen Gras 
275*f14fb602SLionel Sambuc uint32_t
cdbw_stable_seeder(void)276*f14fb602SLionel Sambuc cdbw_stable_seeder(void)
277*f14fb602SLionel Sambuc {
278*f14fb602SLionel Sambuc 	return 0;
279*f14fb602SLionel Sambuc }
280*f14fb602SLionel Sambuc 
2812fe8fb19SBen Gras #define unused 0xffffffffU
2822fe8fb19SBen Gras 
2832fe8fb19SBen Gras struct vertex {
2842fe8fb19SBen Gras 	uint32_t l_edge, m_edge, r_edge;
2852fe8fb19SBen Gras };
2862fe8fb19SBen Gras 
2872fe8fb19SBen Gras struct edge {
2882fe8fb19SBen Gras 	uint32_t idx;
2892fe8fb19SBen Gras 
2902fe8fb19SBen Gras 	uint32_t left, middle, right;
2912fe8fb19SBen Gras 	uint32_t l_prev, m_prev, l_next;
2922fe8fb19SBen Gras 	uint32_t r_prev, m_next, r_next;
2932fe8fb19SBen Gras };
2942fe8fb19SBen Gras 
2952fe8fb19SBen Gras struct state {
2962fe8fb19SBen Gras 	uint32_t data_entries;
2972fe8fb19SBen Gras 	uint32_t entries;
2982fe8fb19SBen Gras 	uint32_t keys;
2992fe8fb19SBen Gras 	uint32_t seed;
3002fe8fb19SBen Gras 
3012fe8fb19SBen Gras 	uint32_t *g;
3022fe8fb19SBen Gras 	char *visited;
3032fe8fb19SBen Gras 
3042fe8fb19SBen Gras 	struct vertex *verts;
3052fe8fb19SBen Gras 	struct edge *edges;
3062fe8fb19SBen Gras 	uint32_t output_index;
3072fe8fb19SBen Gras 	uint32_t *output_order;
3082fe8fb19SBen Gras };
3092fe8fb19SBen Gras 
3102fe8fb19SBen Gras static void
remove_vertex(struct state * state,struct vertex * v)3112fe8fb19SBen Gras remove_vertex(struct state *state, struct vertex *v)
3122fe8fb19SBen Gras {
3132fe8fb19SBen Gras 	struct edge *e;
3142fe8fb19SBen Gras 	struct vertex *vl, *vm, *vr;
3152fe8fb19SBen Gras 
3162fe8fb19SBen Gras 	if (v->l_edge != unused && v->m_edge != unused)
3172fe8fb19SBen Gras 		return;
3182fe8fb19SBen Gras 	if (v->l_edge != unused && v->r_edge != unused)
3192fe8fb19SBen Gras 		return;
3202fe8fb19SBen Gras 	if (v->m_edge != unused && v->r_edge != unused)
3212fe8fb19SBen Gras 		return;
3222fe8fb19SBen Gras 	if (v->l_edge == unused && v->m_edge == unused && v->r_edge == unused)
3232fe8fb19SBen Gras 		return;
3242fe8fb19SBen Gras 
3252fe8fb19SBen Gras 	if (v->l_edge != unused) {
3262fe8fb19SBen Gras 		e = &state->edges[v->l_edge];
3272fe8fb19SBen Gras 		if (e->l_next != unused)
3282fe8fb19SBen Gras 			return;
3292fe8fb19SBen Gras 	} else if (v->m_edge != unused) {
3302fe8fb19SBen Gras 		e = &state->edges[v->m_edge];
3312fe8fb19SBen Gras 		if (e->m_next != unused)
3322fe8fb19SBen Gras 			return;
3332fe8fb19SBen Gras 	} else {
3342fe8fb19SBen Gras 		if (v->r_edge == unused)
3352fe8fb19SBen Gras 			abort();
3362fe8fb19SBen Gras 		e = &state->edges[v->r_edge];
3372fe8fb19SBen Gras 		if (e->r_next != unused)
3382fe8fb19SBen Gras 			return;
3392fe8fb19SBen Gras 	}
3402fe8fb19SBen Gras 
3412fe8fb19SBen Gras 	state->output_order[--state->output_index] = e - state->edges;
3422fe8fb19SBen Gras 
3432fe8fb19SBen Gras 	vl = &state->verts[e->left];
3442fe8fb19SBen Gras 	vm = &state->verts[e->middle];
3452fe8fb19SBen Gras 	vr = &state->verts[e->right];
3462fe8fb19SBen Gras 
3472fe8fb19SBen Gras 	if (e->l_prev == unused)
3482fe8fb19SBen Gras 		vl->l_edge = e->l_next;
3492fe8fb19SBen Gras 	else
3502fe8fb19SBen Gras 		state->edges[e->l_prev].l_next = e->l_next;
3512fe8fb19SBen Gras 	if (e->l_next != unused)
3522fe8fb19SBen Gras 		state->edges[e->l_next].l_prev = e->l_prev;
3532fe8fb19SBen Gras 
3542fe8fb19SBen Gras 	if (e->m_prev == unused)
3552fe8fb19SBen Gras 		vm->m_edge = e->m_next;
3562fe8fb19SBen Gras 	else
3572fe8fb19SBen Gras 		state->edges[e->m_prev].m_next = e->m_next;
3582fe8fb19SBen Gras 	if (e->m_next != unused)
3592fe8fb19SBen Gras 		state->edges[e->m_next].m_prev = e->m_prev;
3602fe8fb19SBen Gras 
3612fe8fb19SBen Gras 	if (e->r_prev == unused)
3622fe8fb19SBen Gras 		vr->r_edge = e->r_next;
3632fe8fb19SBen Gras 	else
3642fe8fb19SBen Gras 		state->edges[e->r_prev].r_next = e->r_next;
3652fe8fb19SBen Gras 	if (e->r_next != unused)
3662fe8fb19SBen Gras 		state->edges[e->r_next].r_prev = e->r_prev;
3672fe8fb19SBen Gras }
3682fe8fb19SBen Gras 
3692fe8fb19SBen Gras static int
build_graph(struct cdbw * cdbw,struct state * state)3702fe8fb19SBen Gras build_graph(struct cdbw *cdbw, struct state *state)
3712fe8fb19SBen Gras {
3722fe8fb19SBen Gras 	struct key_hash_head *head;
3732fe8fb19SBen Gras 	struct key_hash *key_hash;
3742fe8fb19SBen Gras 	struct vertex *v;
3752fe8fb19SBen Gras 	struct edge *e;
3762fe8fb19SBen Gras 	uint32_t hashes[3];
3772fe8fb19SBen Gras 	size_t i;
3782fe8fb19SBen Gras 
3792fe8fb19SBen Gras 	e = state->edges;
3802fe8fb19SBen Gras 	for (i = 0; i < cdbw->hash_size; ++i) {
3812fe8fb19SBen Gras 		head = &cdbw->hash[i];
3822fe8fb19SBen Gras 		SLIST_FOREACH(key_hash, head, link) {
3832fe8fb19SBen Gras 			e->idx = key_hash->idx;
3842fe8fb19SBen Gras 			mi_vector_hash(key_hash->key, key_hash->keylen,
3852fe8fb19SBen Gras 			    state->seed, hashes);
3862fe8fb19SBen Gras 			e->left = hashes[0] % state->entries;
3872fe8fb19SBen Gras 			e->middle = hashes[1] % state->entries;
3882fe8fb19SBen Gras 			e->right = hashes[2] % state->entries;
3892fe8fb19SBen Gras 
390*f14fb602SLionel Sambuc 			if (e->left == e->middle)
391*f14fb602SLionel Sambuc 				return -1;
392*f14fb602SLionel Sambuc 			if (e->left == e->right)
393*f14fb602SLionel Sambuc 				return -1;
394*f14fb602SLionel Sambuc 			if (e->middle == e->right)
395*f14fb602SLionel Sambuc 				return -1;
396*f14fb602SLionel Sambuc 
3972fe8fb19SBen Gras 			++e;
3982fe8fb19SBen Gras 		}
3992fe8fb19SBen Gras 	}
4002fe8fb19SBen Gras 
4012fe8fb19SBen Gras 	for (i = 0; i < state->entries; ++i) {
4022fe8fb19SBen Gras 		v = state->verts + i;
4032fe8fb19SBen Gras 		v->l_edge = unused;
4042fe8fb19SBen Gras 		v->m_edge = unused;
4052fe8fb19SBen Gras 		v->r_edge = unused;
4062fe8fb19SBen Gras 	}
4072fe8fb19SBen Gras 
4082fe8fb19SBen Gras 	for (i = 0; i < state->keys; ++i) {
4092fe8fb19SBen Gras 		e = state->edges + i;
4102fe8fb19SBen Gras 		v = state->verts + e->left;
4112fe8fb19SBen Gras 		if (v->l_edge != unused)
4122fe8fb19SBen Gras 			state->edges[v->l_edge].l_prev = i;
4132fe8fb19SBen Gras 		e->l_next = v->l_edge;
4142fe8fb19SBen Gras 		e->l_prev = unused;
4152fe8fb19SBen Gras 		v->l_edge = i;
4162fe8fb19SBen Gras 
4172fe8fb19SBen Gras 		v = &state->verts[e->middle];
4182fe8fb19SBen Gras 		if (v->m_edge != unused)
4192fe8fb19SBen Gras 			state->edges[v->m_edge].m_prev = i;
4202fe8fb19SBen Gras 		e->m_next = v->m_edge;
4212fe8fb19SBen Gras 		e->m_prev = unused;
4222fe8fb19SBen Gras 		v->m_edge = i;
4232fe8fb19SBen Gras 
4242fe8fb19SBen Gras 		v = &state->verts[e->right];
4252fe8fb19SBen Gras 		if (v->r_edge != unused)
4262fe8fb19SBen Gras 			state->edges[v->r_edge].r_prev = i;
4272fe8fb19SBen Gras 		e->r_next = v->r_edge;
4282fe8fb19SBen Gras 		e->r_prev = unused;
4292fe8fb19SBen Gras 		v->r_edge = i;
4302fe8fb19SBen Gras 	}
4312fe8fb19SBen Gras 
4322fe8fb19SBen Gras 	state->output_index = state->keys;
4332fe8fb19SBen Gras 	for (i = 0; i < state->entries; ++i)
4342fe8fb19SBen Gras 		remove_vertex(state, state->verts + i);
4352fe8fb19SBen Gras 
4362fe8fb19SBen Gras 	i = state->keys;
4372fe8fb19SBen Gras 	while (i > 0 && i > state->output_index) {
4382fe8fb19SBen Gras 		--i;
4392fe8fb19SBen Gras 		e = state->edges + state->output_order[i];
4402fe8fb19SBen Gras 		remove_vertex(state, state->verts + e->left);
4412fe8fb19SBen Gras 		remove_vertex(state, state->verts + e->middle);
4422fe8fb19SBen Gras 		remove_vertex(state, state->verts + e->right);
4432fe8fb19SBen Gras 	}
4442fe8fb19SBen Gras 
4452fe8fb19SBen Gras 	return state->output_index == 0 ? 0 : -1;
4462fe8fb19SBen Gras }
4472fe8fb19SBen Gras 
4482fe8fb19SBen Gras static void
assign_nodes(struct state * state)4492fe8fb19SBen Gras assign_nodes(struct state *state)
4502fe8fb19SBen Gras {
4512fe8fb19SBen Gras 	struct edge *e;
4522fe8fb19SBen Gras 	size_t i;
4532fe8fb19SBen Gras 
4542fe8fb19SBen Gras 	for (i = 0; i < state->keys; ++i) {
4552fe8fb19SBen Gras 		e = state->edges + state->output_order[i];
4562fe8fb19SBen Gras 
4572fe8fb19SBen Gras 		if (!state->visited[e->left]) {
4582fe8fb19SBen Gras 			state->g[e->left] =
4592fe8fb19SBen Gras 			    (2 * state->data_entries + e->idx
4602fe8fb19SBen Gras 			    - state->g[e->middle] - state->g[e->right])
4612fe8fb19SBen Gras 			    % state->data_entries;
4622fe8fb19SBen Gras 		} else if (!state->visited[e->middle]) {
4632fe8fb19SBen Gras 			state->g[e->middle] =
4642fe8fb19SBen Gras 			    (2 * state->data_entries + e->idx
4652fe8fb19SBen Gras 			    - state->g[e->left] - state->g[e->right])
4662fe8fb19SBen Gras 			    % state->data_entries;
4672fe8fb19SBen Gras 		} else {
4682fe8fb19SBen Gras 			state->g[e->right] =
4692fe8fb19SBen Gras 			    (2 * state->data_entries + e->idx
4702fe8fb19SBen Gras 			    - state->g[e->left] - state->g[e->middle])
4712fe8fb19SBen Gras 			    % state->data_entries;
4722fe8fb19SBen Gras 		}
4732fe8fb19SBen Gras 		state->visited[e->left] = 1;
4742fe8fb19SBen Gras 		state->visited[e->middle] = 1;
4752fe8fb19SBen Gras 		state->visited[e->right] = 1;
4762fe8fb19SBen Gras 	}
4772fe8fb19SBen Gras }
4782fe8fb19SBen Gras 
4792fe8fb19SBen Gras static size_t
compute_size(uint32_t size)4802fe8fb19SBen Gras compute_size(uint32_t size)
4812fe8fb19SBen Gras {
4822fe8fb19SBen Gras 	if (size < 0x100)
4832fe8fb19SBen Gras 		return 1;
4842fe8fb19SBen Gras 	else if (size < 0x10000)
4852fe8fb19SBen Gras 		return 2;
4862fe8fb19SBen Gras 	else
4872fe8fb19SBen Gras 		return 4;
4882fe8fb19SBen Gras }
4892fe8fb19SBen Gras 
4902fe8fb19SBen Gras #define COND_FLUSH_BUFFER(n) do { 				\
4912fe8fb19SBen Gras 	if (__predict_false(cur_pos + (n) >= sizeof(buf))) {	\
4922fe8fb19SBen Gras 		ret = write(fd, buf, cur_pos);			\
4932fe8fb19SBen Gras 		if (ret == -1 || (size_t)ret != cur_pos)	\
4942fe8fb19SBen Gras 			return -1;				\
4952fe8fb19SBen Gras 		cur_pos = 0;					\
4962fe8fb19SBen Gras 	}							\
4972fe8fb19SBen Gras } while (/* CONSTCOND */ 0)
4982fe8fb19SBen Gras 
4992fe8fb19SBen Gras static int
print_hash(struct cdbw * cdbw,struct state * state,int fd,const char * descr)5002fe8fb19SBen Gras print_hash(struct cdbw *cdbw, struct state *state, int fd, const char *descr)
5012fe8fb19SBen Gras {
5022fe8fb19SBen Gras 	uint32_t data_size;
5032fe8fb19SBen Gras 	uint8_t buf[90000];
5042fe8fb19SBen Gras 	size_t i, size, size2, cur_pos;
5052fe8fb19SBen Gras 	ssize_t ret;
5062fe8fb19SBen Gras 
5072fe8fb19SBen Gras 	memcpy(buf, "NBCDB\n\0", 7);
5082fe8fb19SBen Gras 	buf[7] = 1;
5092fe8fb19SBen Gras 	strncpy((char *)buf + 8, descr, 16);
5102fe8fb19SBen Gras 	le32enc(buf + 24, cdbw->data_size);
5112fe8fb19SBen Gras 	le32enc(buf + 28, cdbw->data_counter);
5122fe8fb19SBen Gras 	le32enc(buf + 32, state->entries);
5132fe8fb19SBen Gras 	le32enc(buf + 36, state->seed);
5142fe8fb19SBen Gras 	cur_pos = 40;
5152fe8fb19SBen Gras 
5162fe8fb19SBen Gras 	size = compute_size(state->entries);
5172fe8fb19SBen Gras 	for (i = 0; i < state->entries; ++i) {
5182fe8fb19SBen Gras 		COND_FLUSH_BUFFER(4);
5192fe8fb19SBen Gras 		le32enc(buf + cur_pos, state->g[i]);
5202fe8fb19SBen Gras 		cur_pos += size;
5212fe8fb19SBen Gras 	}
5222fe8fb19SBen Gras 	size2 = compute_size(cdbw->data_size);
5232fe8fb19SBen Gras 	size = size * state->entries % size2;
5242fe8fb19SBen Gras 	if (size != 0) {
5252fe8fb19SBen Gras 		size = size2 - size;
5262fe8fb19SBen Gras 		COND_FLUSH_BUFFER(4);
5272fe8fb19SBen Gras 		le32enc(buf + cur_pos, 0);
5282fe8fb19SBen Gras 		cur_pos += size;
5292fe8fb19SBen Gras 	}
5302fe8fb19SBen Gras 	for (data_size = 0, i = 0; i < cdbw->data_counter; ++i) {
5312fe8fb19SBen Gras 		COND_FLUSH_BUFFER(4);
5322fe8fb19SBen Gras 		le32enc(buf + cur_pos, data_size);
5332fe8fb19SBen Gras 		cur_pos += size2;
5342fe8fb19SBen Gras 		data_size += cdbw->data_len[i];
5352fe8fb19SBen Gras 	}
5362fe8fb19SBen Gras 	COND_FLUSH_BUFFER(4);
5372fe8fb19SBen Gras 	le32enc(buf + cur_pos, data_size);
5382fe8fb19SBen Gras 	cur_pos += size2;
5392fe8fb19SBen Gras 
5402fe8fb19SBen Gras 	for (i = 0; i < cdbw->data_counter; ++i) {
5412fe8fb19SBen Gras 		COND_FLUSH_BUFFER(cdbw->data_len[i]);
5422fe8fb19SBen Gras 		if (cdbw->data_len[i] < sizeof(buf)) {
5432fe8fb19SBen Gras 			memcpy(buf + cur_pos, cdbw->data_ptr[i],
5442fe8fb19SBen Gras 			    cdbw->data_len[i]);
5452fe8fb19SBen Gras 			cur_pos += cdbw->data_len[i];
5462fe8fb19SBen Gras 		} else {
5472fe8fb19SBen Gras 			ret = write(fd, cdbw->data_ptr[i], cdbw->data_len[i]);
5482fe8fb19SBen Gras 			if (ret == -1 || (size_t)ret != cdbw->data_len[i])
5492fe8fb19SBen Gras 				return -1;
5502fe8fb19SBen Gras 		}
5512fe8fb19SBen Gras 	}
5522fe8fb19SBen Gras 	if (cur_pos != 0) {
5532fe8fb19SBen Gras 		ret = write(fd, buf, cur_pos);
5542fe8fb19SBen Gras 		if (ret == -1 || (size_t)ret != cur_pos)
5552fe8fb19SBen Gras 			return -1;
5562fe8fb19SBen Gras 	}
5572fe8fb19SBen Gras 	return 0;
5582fe8fb19SBen Gras }
5592fe8fb19SBen Gras 
5602fe8fb19SBen Gras int
cdbw_output(struct cdbw * cdbw,int fd,const char descr[16],uint32_t (* seedgen)(void))5612fe8fb19SBen Gras cdbw_output(struct cdbw *cdbw, int fd, const char descr[16],
5622fe8fb19SBen Gras     uint32_t (*seedgen)(void))
5632fe8fb19SBen Gras {
5642fe8fb19SBen Gras 	struct state state;
5652fe8fb19SBen Gras 	int rv;
5662fe8fb19SBen Gras 
5672fe8fb19SBen Gras 	if (cdbw->data_counter == 0 || cdbw->key_counter == 0) {
5682fe8fb19SBen Gras 		state.entries = 0;
5692fe8fb19SBen Gras 		state.seed = 0;
5702fe8fb19SBen Gras 		print_hash(cdbw, &state, fd, descr);
5712fe8fb19SBen Gras 		return 0;
5722fe8fb19SBen Gras 	}
5732fe8fb19SBen Gras 
574*f14fb602SLionel Sambuc #if HAVE_NBTOOL_CONFIG_H
575*f14fb602SLionel Sambuc 	if (seedgen == NULL)
576*f14fb602SLionel Sambuc 		seedgen = cdbw_stable_seeder;
577*f14fb602SLionel Sambuc #else
5782fe8fb19SBen Gras 	if (seedgen == NULL)
5792fe8fb19SBen Gras 		seedgen = arc4random;
580*f14fb602SLionel Sambuc #endif
5812fe8fb19SBen Gras 
5822fe8fb19SBen Gras 	rv = 0;
5832fe8fb19SBen Gras 
5842fe8fb19SBen Gras 	state.keys = cdbw->key_counter;
5852fe8fb19SBen Gras 	state.data_entries = cdbw->data_counter;
5862fe8fb19SBen Gras 	state.entries = state.keys + (state.keys + 3) / 4;
5872fe8fb19SBen Gras 	if (state.entries < 10)
5882fe8fb19SBen Gras 		state.entries = 10;
5892fe8fb19SBen Gras 
5902fe8fb19SBen Gras #define	NALLOC(var, n)	var = calloc(sizeof(*var), n)
5912fe8fb19SBen Gras 	NALLOC(state.g, state.entries);
5922fe8fb19SBen Gras 	NALLOC(state.visited, state.entries);
5932fe8fb19SBen Gras 	NALLOC(state.verts, state.entries);
5942fe8fb19SBen Gras 	NALLOC(state.edges, state.entries);
5952fe8fb19SBen Gras 	NALLOC(state.output_order, state.keys);
5962fe8fb19SBen Gras #undef NALLOC
5972fe8fb19SBen Gras 
5982fe8fb19SBen Gras 	if (state.g == NULL || state.visited == NULL || state.verts == NULL ||
5992fe8fb19SBen Gras 	    state.edges == NULL || state.output_order == NULL) {
6002fe8fb19SBen Gras 		rv = -1;
6012fe8fb19SBen Gras 		goto release;
6022fe8fb19SBen Gras 	}
6032fe8fb19SBen Gras 
604*f14fb602SLionel Sambuc 	state.seed = 0;
6052fe8fb19SBen Gras 	do {
606*f14fb602SLionel Sambuc 		if (seedgen == cdbw_stable_seeder)
607*f14fb602SLionel Sambuc 			++state.seed;
608*f14fb602SLionel Sambuc 		else
6092fe8fb19SBen Gras 			state.seed = (*seedgen)();
6102fe8fb19SBen Gras 	} while (build_graph(cdbw, &state));
6112fe8fb19SBen Gras 
6122fe8fb19SBen Gras 	assign_nodes(&state);
6132fe8fb19SBen Gras 	rv = print_hash(cdbw, &state, fd, descr);
6142fe8fb19SBen Gras 
6152fe8fb19SBen Gras release:
6162fe8fb19SBen Gras 	free(state.g);
6172fe8fb19SBen Gras 	free(state.visited);
6182fe8fb19SBen Gras 	free(state.verts);
6192fe8fb19SBen Gras 	free(state.edges);
6202fe8fb19SBen Gras 	free(state.output_order);
6212fe8fb19SBen Gras 
6222fe8fb19SBen Gras 	return rv;
6232fe8fb19SBen Gras }
624