コード例 #1
0
ファイル: pair.c プロジェクト: qgewfg/gtk-gnutella
datum
getnkey(DBM *db, char *pag, int num)
{
	datum key;
	int i;
	int off;
	const unsigned short *ino = (const unsigned short *) pag;

	g_assert(num > 0);

	i = num * 2 - 1;
	if (ino[0] == 0 || i > ino[0])
		return nullitem;

	off = (i > 1) ? offset(ino[i - 1]) : DBM_PBLKSIZ;

	key.dptr = pag + offset(ino[i]);
	key.dsize = off - offset(ino[i]);

#ifdef BIGDATA
	if (is_big(ino[i])) {
		size_t dsize = big_length(key.dptr);
		key.dptr = bigkey_get(db, key.dptr, key.dsize);
		key.dsize = (NULL == key.dptr) ? 0 : dsize;
	}
#else
	(void) db;
#endif

	return key;
}
コード例 #2
0
ファイル: pair.c プロジェクト: qgewfg/gtk-gnutella
datum
getpair(DBM *db, char *pag, datum key)
{
	int i;
	unsigned n;
	datum val;
	const unsigned short *ino = (const unsigned short *) pag;

	if ((n = ino[0]) == 0)
		return nullitem;

	if ((i = seepair(db, pag, n, key.dptr, key.dsize)) == 0)
		return nullitem;

	val.dptr = pag + offset(ino[i + 1]);
	val.dsize = offset(ino[i]) - offset(ino[i + 1]);

#ifdef BIGDATA
	if (is_big(ino[i + 1])) {
		size_t dsize = big_length(val.dptr);
		val.dptr = bigval_get(db, val.dptr, val.dsize);
		val.dsize = (NULL == val.dptr) ? 0 : dsize;
	}
#endif

	return val;
}
コード例 #3
0
ファイル: pair.c プロジェクト: qgewfg/gtk-gnutella
/**
 * Get value for the num-th key in the page.
 */
datum
getnval(DBM *db, char *pag, int num)
{
	int i;
	int n;
	datum val;
	const unsigned short *ino = (const unsigned short *) pag;

	g_assert(num > 0);

	i = num * 2 - 1;

	if ((n = ino[0]) == 0 || i >= n)
		return nullitem;

	val.dptr = pag + offset(ino[i + 1]);
	val.dsize = offset(ino[i]) - offset(ino[i + 1]);

#ifdef BIGDATA
	if (is_big(ino[i + 1])) {
		size_t dsize = big_length(val.dptr);
		val.dptr = bigval_get(db, val.dptr, val.dsize);
		val.dsize = (NULL == val.dptr) ? 0 : dsize;
	}
#else
	(void) db;
#endif

	return val;
}
コード例 #4
0
ファイル: pair.c プロジェクト: qgewfg/gtk-gnutella
/**
 * Get information about a key: length of its value and index within the page.
 *
 * @return TRUE if key was found, value length via *length, index via *idx,
 * and whether value is stored in a .dat file via *big.
 */
bool
infopair(DBM *db, char *pag, datum key, size_t *length, int *idx, bool *big)
{
	int i;
	unsigned n;
	size_t dsize;
	const unsigned short *ino = (const unsigned short *) pag;

	if ((n = ino[0]) == 0)
		return FALSE;

	if ((i = seepair(db, pag, n, key.dptr, key.dsize)) == 0)
		return FALSE;

	dsize = offset(ino[i]) - offset(ino[i + 1]);

#ifdef BIGDATA
	if (is_big(ino[i + 1])) {
		g_assert(dsize >= sizeof(uint32));
		dsize = big_length(pag + offset(ino[i + 1]));
	}
#endif

	if (length != NULL)
		*length = dsize;
	if (idx != NULL)
		*idx = i;
	if (big != NULL)
		*big = is_big(ino[i + 1]);

	return TRUE;	/* Key exists */
}
コード例 #5
0
/**
 * Mark .dat blocks used to hold the value described in the .pag space as
 * being allocated in the bitmap checking array.
 *
 * @param db		the sdbm database
 * @param bval		start of big value in the page
 * @param blen		length of big value in the page
 */
void
bigval_mark_used(DBM *db, const char *bval, size_t blen)
{
	size_t len = big_length(bval);

	if (bigval_length(len) != blen) {
		g_carp("sdbm: \"%s\": %s: inconsistent value length %lu in .pag",
			sdbm_name(db), G_STRFUNC, (unsigned long) len);
		return;
	}

	big_file_mark_used(db, bigval_blocks(bval), bigblocks(len));
}
コード例 #6
0
/**
 * Validate .dat blocks used to hold the value described in the .pag space.
 *
 * @param db		the sdbm database
 * @param bval		start of big value in the page
 * @param blen		length of big value in the page
 *
 * @return TRUE on success.
 */
gboolean
bigval_check(DBM *db, const char *bval, size_t blen)
{
	size_t len = big_length(bval);

	if (bigval_length(len) != blen) {
		g_warning("sdbm: \"%s\": found inconsistent value length %lu, "
			"would span %lu bytes in .pag instead of the %lu present",
			sdbm_name(db), (unsigned long) len,
			(unsigned long) bigkey_length(len), (unsigned long) blen);
		return FALSE;
	}

	return big_file_check("value", db, bigval_blocks(bval), bigblocks(len));
}
コード例 #7
0
/**
 * Free .dat blocks used to hold the value described in the .pag space.
 *
 * @param db		the sdbm database
 * @param bval		start of big value in the page
 * @param blen		length of big value in the page
 *
 * @return TRUE on success.
 */
gboolean
bigval_free(DBM *db, const char *bval, size_t blen)
{
	size_t len = big_length(bval);

	if (bigval_length(len) != blen) {
		g_warning("sdbm: \"%s\": "
			"bigval_free: inconsistent key length %lu in .pag",
			sdbm_name(db), (unsigned long) len);
		return FALSE;
	}

	big_file_free(db, bigval_blocks(bval), bigblocks(len));
	return TRUE;
}
コード例 #8
0
/**
 * Replace value data in-place.
 *
 * @param db		the sdbm database
 * @param bval		start of big value in the page
 * @param data		the new value
 * @param len		length of data
 *
 * @return 0 if OK, -1 on error with errno set.
 */
int
big_replace(DBM *db, char *bval, const char *data, size_t len)
{
	size_t old_len = big_length(bval);

	g_assert(size_is_non_negative(len));
	g_assert(bigblocks(old_len) == bigblocks(len));
	g_assert(len <= MAX_INT_VAL(guint32));

	/*
	 * Write data on the same blocks as before, since we know it will fit.
	 */

	poke_be32(bval, (guint32) len);		/* First 4 bytes: real data length */

	return big_store(db, bigval_blocks(bval), data, len);
}
コード例 #9
0
/**
 * Get value data from the block numbers held in the .pag value.
 *
 * @param db		the sdbm database
 * @param bval		start of big value in the page
 * @param blen		length of big value in the page
 *
 * @return pointer to read value (scratch buffer) if OK, NULL on error.
 */
char *
bigval_get(DBM *db, const char *bval, size_t blen)
{
	size_t len = big_length(bval);
	DBMBIG *dbg = db->big;

	if (bigval_length(len) != blen) {
		g_warning("sdbm: \"%s\": "
			"bigval_get: inconsistent value length %lu in .pag",
			sdbm_name(db), (unsigned long) len);
		return NULL;
	}

	if (-1 == big_fetch(db, bigval_blocks(bval), len))
		return NULL;

	return dbg->scratch;
}
コード例 #10
0
/**
 * Is a big key stored at bkey in an SDBM .pag file equal to a siz-byte key?
 *
 * @param db		the sdbm database
 * @param bkey		start of big key in the page
 * @param blen		length of big key in the page
 * @param key		the key we're trying to match against
 * @param siz		length of the key
 *
 * @return TRUE if the key matches.
 */
gboolean
bigkey_eq(DBM *db, const char *bkey, size_t blen, const char *key, size_t siz)
{
	size_t len = big_length(bkey);
	DBMBIG *dbg = db->big;

	g_assert(bigkey_length(len) == blen);

	/*
	 * Comparing a key in memory with a big key on disk is potentially a
	 * costly operation because it requires some I/O to fetch the key from
	 * the .dat file, which may involve several system calls, simply to find
	 * out that the key is not matching.
	 *
	 * To avoid useless reads as much as possible, we store the length of
	 * the big key at the beginning of the .pag key indirection data.  If the
	 * size does not match, there's no need to go further.
	 *
	 * Then we keep the first and last BIG_KEYSAVED bytes of the key as part
	 * of the .pag data so that we may quickly filter out keys that are
	 * obviously not matching.
	 *
	 * Only when things look like it could be a match do we engage in the
	 * process of fetching the big key data to perform the actual comparison.
	 *
	 * Nonetheless this means fetching data indexed by large keys requires
	 * extra I/Os and therefore large keys should be avoided if possible.
	 * In practice, keys are shorthand to the actual data and therefore are
	 * likely to be kept short enough so that they are always expanded in the
	 * .pag data and never stored as big keys.
	 */

	if (siz != len)
		return FALSE;

	dbg->key_matching++;

	if (0 != memcmp(key, bigkey_head(bkey), BIG_KEYSAVED))
		return FALSE;

	if (0 != memcmp(key + (siz-BIG_KEYSAVED), bigkey_tail(bkey), BIG_KEYSAVED))
		return FALSE;

	dbg->key_short_match++;

	/*
	 * Need to read the key to make sure it's an exact match.
	 *
	 * There is a high probability as the head and the tail already match,
	 * and the length is the same.
	 */

	if (-1 == big_fetch(db, bigkey_blocks(bkey), siz))
		return FALSE;

	/*
	 * Data stored in the .dat file must match what the .pag had for the key
	 */

	if (
		0 != memcmp(db->big->scratch, bigkey_head(bkey), BIG_KEYSAVED) ||
		0 != memcmp(db->big->scratch + (siz-BIG_KEYSAVED),
				bigkey_tail(bkey), BIG_KEYSAVED)
	) {
		g_warning("sdbm: \"%s\": found %lu-byte key page/data inconsistency",
			sdbm_name(db), (unsigned long) siz);
		return FALSE;
	}

	if (0 == memcmp(db->big->scratch, key, siz)) {
		dbg->key_full_match++;
		return TRUE;
	}

	return FALSE;
}