Example #1
0
int main(int argc, char *argv[])
{
	unsigned int i;
	uint64_t val;
	struct tdb_context *tdb;
	int flags[] = { TDB_INTERNAL, TDB_DEFAULT, TDB_NOMMAP,
			TDB_INTERNAL|TDB_CONVERT, TDB_CONVERT,
			TDB_NOMMAP|TDB_CONVERT };

	plan_tests(sizeof(flags) / sizeof(flags[0]) * 11 + 1);

	failtest_init(argc, argv);
	failtest_hook = block_repeat_failures;
	failtest_exit_check = exit_check_log;

	for (i = 0; i < sizeof(flags) / sizeof(flags[0]); i++) {
		failtest_suppress = true;
		tdb = tdb_open("run-expand.tdb", flags[i],
			       O_RDWR|O_CREAT|O_TRUNC, 0600, &tap_log_attr);
		if (!ok1(tdb))
			break;

		val = tdb->file->map_size;
		/* Need some hash lock for expand. */
		ok1(tdb_lock_hashes(tdb, 0, 1, F_WRLCK, TDB_LOCK_WAIT) == 0);
		failtest_suppress = false;
		if (!ok1(tdb_expand(tdb, 1) == 0)) {
			failtest_suppress = true;
			tdb_close(tdb);
			break;
		}
		failtest_suppress = true;

		ok1(tdb->file->map_size >= val + 1 * TDB_EXTENSION_FACTOR);
		ok1(tdb_unlock_hashes(tdb, 0, 1, F_WRLCK) == 0);
		ok1(tdb_check(tdb, NULL, NULL) == 0);

		val = tdb->file->map_size;
		ok1(tdb_lock_hashes(tdb, 0, 1, F_WRLCK, TDB_LOCK_WAIT) == 0);
		failtest_suppress = false;
		if (!ok1(tdb_expand(tdb, 1024) == 0)) {
			failtest_suppress = true;
			tdb_close(tdb);
			break;
		}
		failtest_suppress = true;
		ok1(tdb_unlock_hashes(tdb, 0, 1, F_WRLCK) == 0);
		ok1(tdb->file->map_size >= val + 1024 * TDB_EXTENSION_FACTOR);
		ok1(tdb_check(tdb, NULL, NULL) == 0);
		tdb_close(tdb);
	}

	ok1(tap_log_messages == 0);
	failtest_exit(exit_status());
}
int main(int argc, char *argv[])
{
	unsigned int i, j;
	struct tdb_context *tdb;
	int flags[] = { TDB_INTERNAL, TDB_DEFAULT, TDB_NOMMAP,
			TDB_INTERNAL|TDB_CONVERT, TDB_CONVERT,
			TDB_NOMMAP|TDB_CONVERT };

	plan_tests(sizeof(flags) / sizeof(flags[0]) * 9 + 1);

	for (i = 0; i < sizeof(flags) / sizeof(flags[0]); i++) {
		TDB_DATA k;
		uint64_t size;
		bool was_empty = false;

		k.dptr = (void *)&j;
		k.dsize = sizeof(j);

		tdb = tdb_open("run-30-exhaust-before-expand.tdb", flags[i],
			       O_RDWR|O_CREAT|O_TRUNC, 0600, &tap_log_attr);
		ok1(tdb);
		if (!tdb)
			continue;

		ok1(empty_freetable(tdb));
		/* Need some hash lock for expand. */
		ok1(tdb_lock_hashes(tdb, 0, 1, F_WRLCK, TDB_LOCK_WAIT) == 0);
		/* Create some free space. */
		ok1(tdb_expand(tdb, 1) == 0);
		ok1(tdb_unlock_hashes(tdb, 0, 1, F_WRLCK) == 0);
		ok1(tdb_check(tdb, NULL, NULL) == 0);
		ok1(!empty_freetable(tdb));

		size = tdb->map_size;
		/* Insert minimal-length records until we expand. */
		for (j = 0; tdb->map_size == size; j++) {
			was_empty = empty_freetable(tdb);
			if (tdb_store(tdb, k, k, TDB_INSERT) != 0)
				err(1, "Failed to store record %i", j);
		}

		/* Would have been empty before expansion, but no longer. */
		ok1(was_empty);
		ok1(!empty_freetable(tdb));
		tdb_close(tdb);
	}

	ok1(tap_log_messages == 0);
	return exit_status();
}
Example #3
0
File: hash.c Project: Arkhont/samba
/* This is the core routine which searches the hashtable for an entry.
 * On error, no locks are held and -ve is returned.
 * Otherwise, hinfo is filled in (and the optional tinfo).
 * If not found, the return value is 0.
 * If found, the return value is the offset, and *rec is the record. */
tdb_off_t find_and_lock(struct tdb_context *tdb,
			struct tdb_data key,
			int ltype,
			struct hash_info *h,
			struct tdb_used_record *rec,
			struct traverse_info *tinfo)
{
	uint32_t i, group;
	tdb_off_t hashtable;
	enum TDB_ERROR ecode;

	h->h = tdb_hash(tdb, key.dptr, key.dsize);
	h->hash_used = 0;
	group = use_bits(h, TDB_TOPLEVEL_HASH_BITS - TDB_HASH_GROUP_BITS);
	h->home_bucket = use_bits(h, TDB_HASH_GROUP_BITS);

	h->hlock_start = hlock_range(group, &h->hlock_range);
	ecode = tdb_lock_hashes(tdb, h->hlock_start, h->hlock_range, ltype,
				TDB_LOCK_WAIT);
	if (ecode != TDB_SUCCESS) {
		return ecode;
	}

	hashtable = offsetof(struct tdb_header, hashtable);
	if (tinfo) {
		tinfo->toplevel_group = group;
		tinfo->num_levels = 1;
		tinfo->levels[0].entry = 0;
		tinfo->levels[0].hashtable = hashtable
			+ (group << TDB_HASH_GROUP_BITS) * sizeof(tdb_off_t);
		tinfo->levels[0].total_buckets = 1 << TDB_HASH_GROUP_BITS;
	}

	while (h->hash_used <= 64) {
		/* Read in the hash group. */
		h->group_start = hashtable
			+ group * (sizeof(tdb_off_t) << TDB_HASH_GROUP_BITS);

		ecode = tdb_read_convert(tdb, h->group_start, &h->group,
					 sizeof(h->group));
		if (ecode != TDB_SUCCESS) {
			goto fail;
		}

		/* Pointer to another hash table?  Go down... */
		if (is_subhash(h->group[h->home_bucket])) {
			hashtable = (h->group[h->home_bucket] & TDB_OFF_MASK)
				+ sizeof(struct tdb_used_record);
			if (tinfo) {
				/* When we come back, use *next* bucket */
				tinfo->levels[tinfo->num_levels-1].entry
					+= h->home_bucket + 1;
			}
			group = use_bits(h, TDB_SUBLEVEL_HASH_BITS
					 - TDB_HASH_GROUP_BITS);
			h->home_bucket = use_bits(h, TDB_HASH_GROUP_BITS);
			if (tinfo) {
				tinfo->levels[tinfo->num_levels].hashtable
					= hashtable;
				tinfo->levels[tinfo->num_levels].total_buckets
					= 1 << TDB_SUBLEVEL_HASH_BITS;
				tinfo->levels[tinfo->num_levels].entry
					= group << TDB_HASH_GROUP_BITS;
				tinfo->num_levels++;
			}
			continue;
		}

		/* It's in this group: search (until 0 or all searched) */
		for (i = 0, h->found_bucket = h->home_bucket;
		     i < (1 << TDB_HASH_GROUP_BITS);
		     i++, h->found_bucket = ((h->found_bucket+1)
					     % (1 << TDB_HASH_GROUP_BITS))) {
			tdb_bool_err berr;
			if (is_subhash(h->group[h->found_bucket]))
				continue;

			if (!h->group[h->found_bucket])
				break;

			berr = match(tdb, h, &key, h->group[h->found_bucket],
				     rec);
			if (berr < 0) {
				ecode = berr;
				goto fail;
			}
			if (berr) {
				if (tinfo) {
					tinfo->levels[tinfo->num_levels-1].entry
						+= h->found_bucket;
				}
				return h->group[h->found_bucket] & TDB_OFF_MASK;
			}
		}
		/* Didn't find it: h indicates where it would go. */
		return 0;
	}

	return find_in_chain(tdb, key, hashtable, h, rec, tinfo);

fail:
	tdb_unlock_hashes(tdb, h->hlock_start, h->hlock_range, ltype);
	return ecode;
}