Beispiel #1
0
/*
 * __curjoin_extract_insert --
 *	Handle a key produced by a custom extractor.
 */
static int
__curjoin_extract_insert(WT_CURSOR *cursor)
{
	WT_CURJOIN_EXTRACTOR *cextract;
	WT_DECL_RET;
	WT_ITEM ikey;
	WT_SESSION_IMPL *session;

	/*
	 * This insert method may be called multiple times during a single
	 * extraction.  If we already have a definitive answer to the
	 * membership question, exit early.
	 */
	cextract = (WT_CURJOIN_EXTRACTOR *)cursor;
	if (cextract->ismember)
		return (0);

	CURSOR_API_CALL(cursor, session, insert, NULL);

	WT_ITEM_SET(ikey, cursor->key);
	/*
	 * We appended a padding byte to the key to avoid rewriting the last
	 * column.  Strip that away here.
	 */
	WT_ASSERT(session, ikey.size > 0);
	--ikey.size;

	ret = __curjoin_entry_in_range(session, cextract->entry, &ikey, false);
	if (ret == WT_NOTFOUND)
		ret = 0;
	else if (ret == 0)
		cextract->ismember = true;

err:	API_END_RET(session, ret);
}
Beispiel #2
0
/*
 * __curjoin_split_key --
 *	Copy the primary key from a cursor (either main table or index)
 *	to another cursor.  When copying from an index file, the index
 *	key is also returned.
 *
 */
static int
__curjoin_split_key(WT_SESSION_IMPL *session, WT_CURSOR_JOIN *cjoin,
    WT_ITEM *idxkey, WT_CURSOR *tocur, WT_CURSOR *fromcur,
    const char *repack_fmt, bool isindex)
{
	WT_CURSOR *firstcg_cur;
	WT_CURSOR_INDEX *cindex;
	WT_ITEM *keyp;
	const uint8_t *p;

	if (isindex) {
		cindex = ((WT_CURSOR_INDEX *)fromcur);
		/*
		 * Repack tells us where the index key ends; advance past
		 * that to get where the raw primary key starts.
		 */
		WT_RET(__wt_struct_repack(session, cindex->child->key_format,
		    repack_fmt != NULL ? repack_fmt : cindex->iface.key_format,
		    &cindex->child->key, idxkey));
		WT_ASSERT(session, cindex->child->key.size > idxkey->size);
		tocur->key.data = (uint8_t *)idxkey->data + idxkey->size;
		tocur->key.size = cindex->child->key.size - idxkey->size;
		if (WT_CURSOR_RECNO(tocur)) {
			p = (const uint8_t *)tocur->key.data;
			WT_RET(__wt_vunpack_uint(&p, tocur->key.size,
			    &tocur->recno));
		} else
			tocur->recno = 0;
	} else {
		firstcg_cur = ((WT_CURSOR_TABLE *)fromcur)->cg_cursors[0];
		keyp = &firstcg_cur->key;
		if (WT_CURSOR_RECNO(tocur)) {
			WT_ASSERT(session, keyp->size == sizeof(uint64_t));
			tocur->recno = *(uint64_t *)keyp->data;
			WT_RET(__curjoin_pack_recno(session, tocur->recno,
			    cjoin->recno_buf, sizeof(cjoin->recno_buf),
			    &tocur->key));
		} else {
			WT_ITEM_SET(tocur->key, *keyp);
			tocur->recno = 0;
		}
		idxkey->data = NULL;
		idxkey->size = 0;
	}
	return (0);
}
Beispiel #3
0
/*
 * __curjoin_entry_iter_next --
 *	Get the next item in an iteration.
 *
 */
static int
__curjoin_entry_iter_next(WT_CURSOR_JOIN_ITER *iter, WT_ITEM *primkey,
    uint64_t *rp)
{
	WT_CURSOR *firstcg_cur;
	WT_CURSOR_JOIN *cjoin;
	WT_DECL_RET;
	WT_SESSION_IMPL *session;
	uint64_t r;

	if (iter->advance)
		WT_ERR(iter->cursor->next(iter->cursor));
	else
		iter->advance = true;

	session = iter->session;
	cjoin = iter->cjoin;

	/*
	 * Set our key to the primary key, we'll also need this
	 * to check membership.
	 */
	if (iter->entry->index != NULL)
		firstcg_cur = ((WT_CURSOR_INDEX *)iter->cursor)->cg_cursors[0];
	else
		firstcg_cur = ((WT_CURSOR_TABLE *)iter->cursor)->cg_cursors[0];
	if (WT_CURSOR_RECNO(&cjoin->iface)) {
		r = *(uint64_t *)firstcg_cur->key.data;
		WT_ERR(__curjoin_pack_recno(session, r, cjoin->recno_buf,
		    sizeof(cjoin->recno_buf), primkey));
		*rp = r;
	} else {
		WT_ITEM_SET(*primkey, firstcg_cur->key);
		*rp = 0;
	}
	iter->curkey = primkey;
	iter->entry->stats.actual_count++;
	iter->entry->stats.accesses++;

err:	return (ret);
}
Beispiel #4
0
/*
 * __curextract_insert --
 *	Handle a key produced by a custom extractor.
 */
static int
__curextract_insert(WT_CURSOR *cursor) {
	WT_CURSOR_EXTRACTOR *cextract;
	WT_ITEM *key, ikey, pkey;
	WT_SESSION_IMPL *session;

	cextract = (WT_CURSOR_EXTRACTOR *)cursor;
	session = (WT_SESSION_IMPL *)cursor->session;

	WT_ITEM_SET(ikey, cursor->key);
	/*
	 * We appended a padding byte to the key to avoid rewriting the last
	 * column.  Strip that away here.
	 */
	WT_ASSERT(session, ikey.size > 0);
	--ikey.size;
	WT_RET(__wt_cursor_get_raw_key(cextract->ctable->cg_cursors[0], &pkey));

	/*
	 * We have the index key in the format we need, and all of the primary
	 * key columns are required: just append them.
	 */
	key = &cextract->idxc->key;
	WT_RET(__wt_buf_grow(session, key, ikey.size + pkey.size));
	memcpy((uint8_t *)key->mem, ikey.data, ikey.size);
	memcpy((uint8_t *)key->mem + ikey.size, pkey.data, pkey.size);
	key->size = ikey.size + pkey.size;

	/*
	 * The index key is now set and the value is empty (it starts clear and
	 * is never set).
	 */
	F_SET(cextract->idxc, WT_CURSTD_KEY_EXT | WT_CURSTD_VALUE_EXT);

	/* Call the underlying cursor function to update the index. */
	return (cextract->f(cextract->idxc));
}
Beispiel #5
0
/*
 * __curjoin_entry_member --
 *	Do a membership check for a particular index that was joined,
 *	if not a member, returns WT_NOTFOUND.
 */
static int
__curjoin_entry_member(WT_SESSION_IMPL *session, WT_CURSOR_JOIN_ENTRY *entry,
    WT_ITEM *key, WT_CURSOR_JOIN_ITER *iter)
{
	WT_CURJOIN_EXTRACTOR extract_cursor;
	WT_CURSOR *c;
	WT_CURSOR_STATIC_INIT(iface,
	    __wt_cursor_get_key,		/* get-key */
	    __wt_cursor_get_value,		/* get-value */
	    __wt_cursor_set_key,		/* set-key */
	    __wt_cursor_set_value,		/* set-value */
	    __wt_cursor_compare_notsup,		/* compare */
	    __wt_cursor_equals_notsup,		/* equals */
	    __wt_cursor_notsup,			/* next */
	    __wt_cursor_notsup,			/* prev */
	    __wt_cursor_notsup,			/* reset */
	    __wt_cursor_notsup,			/* search */
	    __wt_cursor_search_near_notsup,	/* search-near */
	    __curjoin_extract_insert,		/* insert */
	    __wt_cursor_modify_notsup,		/* modify */
	    __wt_cursor_notsup,			/* update */
	    __wt_cursor_notsup,			/* remove */
	    __wt_cursor_notsup,			/* reserve */
	    __wt_cursor_reconfigure_notsup,	/* reconfigure */
	    __wt_cursor_notsup,			/* cache */
	    __wt_cursor_reopen_notsup,		/* reopen */
	    __wt_cursor_notsup);		/* close */
	WT_DECL_RET;
	WT_INDEX *idx;
	WT_ITEM v;
	bool bloom_found;

	if (entry->subjoin == NULL && iter != NULL &&
	    (iter->end_pos + iter->end_skip >= entry->ends_next ||
	    (iter->end_skip > 0 &&
	    F_ISSET(entry, WT_CURJOIN_ENTRY_DISJUNCTION))))
		return (0);	/* no checks to make */

	entry->stats.membership_check++;
	bloom_found = false;

	if (entry->bloom != NULL) {
		/*
		 * If the item is not in the Bloom filter, we return
		 * immediately, otherwise, we still may need to check the
		 * long way, since it may be a false positive.
		 *
		 * If we don't own the Bloom filter, we must be sharing one
		 * in a previous entry. So the shared filter has already
		 * been checked and passed, we don't need to check it again.
		 * We'll still need to check the long way.
		 */
		if (F_ISSET(entry, WT_CURJOIN_ENTRY_OWN_BLOOM))
			WT_ERR(__wt_bloom_inmem_get(entry->bloom, key));
		if (F_ISSET(entry, WT_CURJOIN_ENTRY_FALSE_POSITIVES))
			return (0);
		bloom_found = true;
	}
	if (entry->subjoin != NULL) {
		WT_ASSERT(session,
		    iter == NULL || entry->subjoin == iter->child->cjoin);
		ret = __curjoin_entries_in_range(session, entry->subjoin,
		    key, iter == NULL ? NULL : iter->child);
		if (iter != NULL &&
		    WT_CURJOIN_ITER_CONSUMED(iter->child)) {
			WT_ERR(__curjoin_iter_bump(iter));
			ret = WT_NOTFOUND;
		}
		return (ret);
	}
	if (entry->index != NULL) {
		/*
		 * If this entry is used by the iterator, then we already
		 * have the index key, and we won't have to do any
		 * extraction either.
		 */
		if (iter != NULL && entry == iter->entry)
			WT_ITEM_SET(v, iter->idxkey);
		else {
			memset(&v, 0, sizeof(v));	/* Keep lint quiet. */
			c = entry->main;
			c->set_key(c, key);
			entry->stats.main_access++;
			if ((ret = c->search(c)) == 0)
				ret = c->get_value(c, &v);
			else if (ret == WT_NOTFOUND) {
				__wt_err(session, ret,
				    "main table for join is missing entry");
				ret = WT_ERROR;
			}
			WT_TRET(c->reset(c));
			WT_ERR(ret);
		}
	} else
		WT_ITEM_SET(v, *key);

	if ((idx = entry->index) != NULL && idx->extractor != NULL &&
	    (iter == NULL || entry != iter->entry)) {
		WT_CLEAR(extract_cursor);
		extract_cursor.iface = iface;
		extract_cursor.iface.session = &session->iface;
		extract_cursor.iface.key_format = idx->exkey_format;
		extract_cursor.ismember = false;
		extract_cursor.entry = entry;
		WT_ERR(idx->extractor->extract(idx->extractor,
		    &session->iface, key, &v, &extract_cursor.iface));
		__wt_buf_free(session, &extract_cursor.iface.key);
		__wt_buf_free(session, &extract_cursor.iface.value);
		if (!extract_cursor.ismember)
			WT_ERR(WT_NOTFOUND);
	} else
		WT_ERR(__curjoin_entry_in_range(session, entry, &v, iter));

	if (0) {
err:		if (ret == WT_NOTFOUND && bloom_found)
			entry->stats.bloom_false_positive++;
	}
	return (ret);
}