Example #1
0
void G_COLD
map_test(void)
{
	sha1_t *keys;
	map_t *mh, *mp;
	int i;
	size_t count;
	int tests;
	struct {
		unsigned insertion, contains, removal;
	} faster = { 0, 0, 0};
	bool verbose = common_stats > 1;

	if (common_stats <= 0)
		return;

	XMALLOC_ARRAY(keys, ITEM_COUNT);

	for (i = 0; i < ITEM_COUNT; i++)
		random_bytes(keys[i].data, SHA1_RAW_SIZE);

	mh = map_create_hash(sha1_hash, sha1_eq);
	mp = map_create_patricia(KEYBITS);

	timeit(test_map_insert, mh, keys, ITEM_COUNT,
		LOOPS, "map hash insertion", verbose);

	timeit(test_map_insert, mp, keys, ITEM_COUNT,
		LOOPS, "map PATRICIA insertion", verbose);

	map_destroy(mh);
	map_destroy(mp);

	for (tests = 0, count = ITEM_COUNT; count > 1; count /= 10) {
		double htime;
		double ptime;

		tests++;

		mh = map_create_hash(sha1_hash, sha1_eq);
		mp = map_create_patricia(KEYBITS);

		htime = timeit(test_map_insert, mh, keys, count,
			1, "map hash reloading", verbose);

		ptime = timeit(test_map_insert, mp, keys, count,
			1, "map PATRICIA reloading", verbose);

		if (verbose)
			g_info("PATRICIA insertion %s than hash with %zu items",
				ptime < htime ? "faster" : "slower", count);

		if (ptime < htime)
			faster.insertion++;

		htime = timeit(test_map_contains, mh, keys, count,
			LOOPS, "map hash contains", verbose);

		ptime = timeit(test_map_contains, mp, keys, count,
			LOOPS, "map PATRICIA contains", verbose);

		if (verbose)
			g_info("PATRICIA contains %s than hash with %zu items",
				ptime < htime ? "faster" : "slower", count);

		if (ptime < htime)
			faster.contains++;

		htime = timeit(test_map_remove, mh, keys, count,
			1, "map hash remove", verbose);

		ptime = timeit(test_map_remove, mp, keys, count,
			1, "map PATRICIA remove", verbose);

		if (verbose)
			g_info("PATRICIA remove %s than hash with %zu items",
				ptime < htime ? "faster" : "slower", count);

		if (ptime < htime)
			faster.removal++;

		map_destroy(mh);
		map_destroy(mp);
	}

	if (faster.insertion)
		g_info("PATRICIA insert was faster than hash in %d out of %d tests",
			faster.insertion, tests);
	if (faster.contains)
		g_info(
			"PATRICIA contains was faster than hash in %d out of %d tests",
			faster.contains, tests);
	if (faster.removal)
		g_info("PATRICIA remove was faster than hash in %d out of %d tests",
			faster.removal, tests);

	XFREE_NULL(keys);
}
Example #2
0
/**
 * Create a new DBM wrapper over already created DB map.
 *
 * If value_data_size is 0, the length for value_size is used.
 *
 * @param dm				The database (already opened)
 * @param name				Database name, for logs
 * @param value_size		Maximum value size, in bytes (structure)
 * @param value_data_size	Maximum value size, in bytes (serialized form)
 * @param pack				Serialization routine for values
 * @param unpack			Deserialization routine for values
 * @param valfree			Free routine for value (or NULL if none needed)
 * @param cache_size		Amount of items to cache (0 = no cache, 1 = default)
 * @param hash_func			Key hash function
 * @param eq_func			Key equality test function
 *
 * If serialization and deserialization routines are NULL pointers, data
 * will be stored and retrieved as-is.  In that case, they must be both
 * NULL.
 */
dbmw_t *
dbmw_create(dbmap_t *dm, const char *name,
	size_t value_size, size_t value_data_size,
	dbmw_serialize_t pack, dbmw_deserialize_t unpack, dbmw_free_t valfree,
	size_t cache_size, GHashFunc hash_func, GEqualFunc eq_func)
{
	dbmw_t *dw;

	g_assert(pack == NULL || value_size);
	g_assert((pack != NULL) == (unpack != NULL));
	g_assert(valfree == NULL || unpack != NULL);
	g_assert(dm);

	WALLOC0(dw);
	dw->magic = DBMW_MAGIC;
	dw->dm = dm;
	dw->name = name;

	dw->key_size = dbmap_key_size(dm);
	dw->key_len = dbmap_key_length(dm);
	dw->value_size = value_size;
	dw->value_data_size = 0 == value_data_size ? value_size : value_data_size;

	/* Make sure we do not violate the SDBM constraint */
	g_assert(sdbm_is_storable(dw->key_size, dw->value_data_size));

	/*
	 * There must be a serialization routine if the serialized length is not
	 * the same as the structure length.
	 */
	g_assert(dw->value_size == dw->value_data_size || pack != NULL);

	/*
	 * For a small amount of items, a PATRICIA tree is more efficient
	 * than a hash table although it uses more memory.
	 */

	if (
		NULL == dw->key_len &&
		dw->key_size * 8 <= PATRICIA_MAXBITS &&
		cache_size <= DBMW_CACHE
	) {
		dw->values = map_create_patricia(dw->key_size * 8);
	} else {
		dw->values = map_create_hash(hash_func, eq_func);
	}

	dw->keys = hash_list_new(hash_func, eq_func);
	dw->pack = pack;
	dw->unpack = unpack;
	dw->valfree = valfree;

	/*
	 * If a serialization routine is provided, we'll also have a need for
	 * deserialization.  Allocate the message in/out streams.
	 *
	 * We're allocating one more byte than necessary to be able to check
	 * whether serialization stays within the imposed boundaries.
	 */

	if (dw->pack) {
		dw->bs = bstr_create();
		dw->mb = pmsg_new(PMSG_P_DATA, NULL, dw->value_data_size + 1);
	}

	/*
	 * If cache_size is zero, we won't cache anything but the latest
	 * value requested, in deserialized form.  If modified, it will be
	 * written back immediately.
	 *
	 * If cache_size is one, use the default (DBMW_CACHE).
	 *
	 * Any other value is used as-is.
	 */

	if (0 == cache_size)
		dw->max_cached = 1;		/* No cache, only keep latest around */
	else if (cache_size == 1)
		dw->max_cached = DBMW_CACHE;
	else
		dw->max_cached = cache_size;

	if (common_dbg)
		g_debug("DBMW created \"%s\" with %s back-end "
			"(max cached = %lu, key=%lu bytes, value=%lu bytes, "
			"%lu max serialized)",
			dw->name, dbmw_map_type(dw) == DBMAP_SDBM ? "sdbm" : "map",
			(gulong) dw->max_cached,
			(gulong) dw->key_size, (gulong) dw->value_size,
			(gulong) dw->value_data_size);

	return dw;
}