MDB_val *data);
static size_t mdb_branch_size(MDB_env *env, MDB_val *key);
-static int memncmp(const void *s1, size_t n1,
- const void *s2, size_t n2);
-static int memnrcmp(const void *s1, size_t n1,
- const void *s2, size_t n2);
+static void mdb_default_cmp(MDB_txn *txn, MDB_dbi dbi);
+
+static MDB_cmp_func memncmp, memnrcmp, intcmp;
#ifdef _WIN32
static SECURITY_DESCRIPTOR mdb_null_sd;
static int mdb_sec_inited;
#endif
-static int
-memncmp(const void *s1, size_t n1, const void *s2, size_t n2)
-{
- int diff, len_diff = -1;
-
- if (n1 >= n2) {
- len_diff = (n1 > n2);
- n1 = n2;
- }
- diff = memcmp(s1, s2, n1);
- return diff ? diff : len_diff;
-}
-
-static int
-memnrcmp(const void *s1, size_t n1, const void *s2, size_t n2)
-{
- const unsigned char *p1, *p2, *p1_lim;
-
- if (n2 == 0)
- return n1 != 0;
- if (n1 == 0)
- return -1;
-
- p1 = (const unsigned char *)s1 + n1 - 1;
- p2 = (const unsigned char *)s2 + n2 - 1;
-
- for (p1_lim = (n1 <= n2 ? s1 : s2); *p1 == *p2; p1--, p2--) {
- if (p1 == p1_lim)
- return (p1 != s1) ? (p1 != p2) : (p2 != s2) ? -1 : 0;
- }
- return *p1 - *p2;
-}
-
char *
mdb_version(int *maj, int *min, int *pat)
{
int
mdb_cmp(MDB_txn *txn, MDB_dbi dbi, const MDB_val *a, const MDB_val *b)
{
- if (txn->mt_dbxs[dbi].md_cmp)
- return txn->mt_dbxs[dbi].md_cmp(a, b);
-
- if (txn->mt_dbs[dbi].md_flags & (MDB_REVERSEKEY
-#if __BYTE_ORDER == __LITTLE_ENDIAN
- |MDB_INTEGERKEY
-#endif
- ))
- return memnrcmp(a->mv_data, a->mv_size, b->mv_data, b->mv_size);
- else
- return memncmp((char *)a->mv_data, a->mv_size, b->mv_data, b->mv_size);
+ return txn->mt_dbxs[dbi].md_cmp(a, b);
}
int
{
if (txn->mt_dbxs[dbi].md_dcmp)
return txn->mt_dbxs[dbi].md_dcmp(a, b);
-
- if (txn->mt_dbs[dbi].md_flags & (0
-#if __BYTE_ORDER == __LITTLE_ENDIAN
- |MDB_INTEGERDUP
-#endif
- ))
- return memnrcmp(a->mv_data, a->mv_size, b->mv_data, b->mv_size);
else
- return memncmp((char *)a->mv_data, a->mv_size, b->mv_data, b->mv_size);
+ return EINVAL; /* too bad you can't distinguish this from a valid result */
}
/* Allocate new page(s) for writing */
free(env);
}
+static int
+intcmp(const MDB_val *a, const MDB_val *b)
+{
+ if (a->mv_size == sizeof(long))
+ {
+ unsigned long *la, *lb;
+ la = a->mv_data;
+ lb = b->mv_data;
+ return *la - *lb;
+ } else {
+ unsigned int *ia, *ib;
+ ia = a->mv_data;
+ ib = b->mv_data;
+ return *ia - *ib;
+ }
+}
+
+static int
+memncmp(const MDB_val *a, const MDB_val *b)
+{
+ int diff, len_diff;
+ unsigned int len;
+
+ len = a->mv_size;
+ len_diff = a->mv_size - b->mv_size;
+ if (len_diff > 0)
+ len = b->mv_size;
+ diff = memcmp(a->mv_data, b->mv_data, len);
+ return diff ? diff : len_diff;
+}
+
+static int
+memnrcmp(const MDB_val *a, const MDB_val *b)
+{
+ const unsigned char *p1, *p2, *p1_lim;
+ int diff, len_diff;
+
+ if (b->mv_size == 0)
+ return a->mv_size != 0;
+ if (a->mv_size == 0)
+ return -1;
+
+ p1 = (const unsigned char *)a->mv_data + a->mv_size - 1;
+ p2 = (const unsigned char *)b->mv_data + b->mv_size - 1;
+
+ len_diff = a->mv_size - b->mv_size;
+ if (len_diff < 0)
+ p1_lim = p1 - a->mv_size;
+ else
+ p1_lim = p1 - b->mv_size;
+
+ while (p1 >= p1_lim) {
+ diff = *p1 - *p2;
+ if (diff)
+ return diff;
+ p1--;
+ p2--;
+ }
+ return len_diff;
+}
+
/* Search for key within a leaf page, using binary search.
* Returns the smallest entry larger or equal to the key.
* If exactp is non-null, stores whether the found entry was an exact match
mdb_search_node(MDB_txn *txn, MDB_dbi dbi, MDB_page *mp, MDB_val *key,
int *exactp, unsigned int *kip)
{
- unsigned int i = 0;
+ unsigned int i = 0, nkeys;
int low, high;
int rc = 0;
MDB_node *node = NULL;
MDB_val nodekey;
+ MDB_cmp_func *cmp;
DKBUF;
+ nkeys = NUMKEYS(mp);
+
DPRINTF("searching %u keys in %s page %lu",
- NUMKEYS(mp),
- IS_LEAF(mp) ? "leaf" : "branch",
+ nkeys, IS_LEAF(mp) ? "leaf" : "branch",
mp->mp_pgno);
- assert(NUMKEYS(mp) > 0);
-
- memset(&nodekey, 0, sizeof(nodekey));
+ assert(nkeys > 0);
low = IS_LEAF(mp) ? 0 : 1;
- high = NUMKEYS(mp) - 1;
+ high = nkeys - 1;
+ cmp = txn->mt_dbxs[dbi].md_cmp;
+ if (IS_LEAF2(mp)) {
+ nodekey.mv_size = txn->mt_dbs[dbi].md_pad;
+ node = NODEPTR(mp, 0); /* fake */
+ }
while (low <= high) {
i = (low + high) >> 1;
if (IS_LEAF2(mp)) {
- nodekey.mv_size = txn->mt_dbs[dbi].md_pad;
nodekey.mv_data = LEAF2KEY(mp, i, nodekey.mv_size);
} else {
node = NODEPTR(mp, i);
nodekey.mv_data = NODEKEY(node);
}
- rc = mdb_cmp(txn, dbi, key, &nodekey);
+ rc = cmp(key, &nodekey);
+#if DEBUG
if (IS_LEAF(mp))
DPRINTF("found leaf index %u [%s], rc = %i",
i, DKEY(&nodekey), rc);
else
DPRINTF("found branch index %u [%s -> %lu], rc = %i",
i, DKEY(&nodekey), NODEPGNO(node), rc);
+#endif
if (rc == 0)
break;
*exactp = (rc == 0);
if (kip) /* Store the key index if requested. */
*kip = i;
- if (i >= NUMKEYS(mp))
+ if (i >= nkeys)
/* There is no entry larger or equal to the key. */
return NULL;
/* nodeptr is fake for LEAF2 */
- return IS_LEAF2(mp) ? NODEPTR(mp, 0) : NODEPTR(mp, i);
+ return node;
}
static void
return ENOMEM;
if (modify) {
- MDB_dhead *dh = ((MDB_dhead *)mp)-1;
+ MDB_dhead *dh;
if ((rc = mdb_touch(txn, dbi, mpp)) != 0)
return rc;
dh = ((MDB_dhead *)mpp->mp_page)-1;
leaf = NODEPTR(top->mp_page, 0);
MDB_SET_KEY(leaf, &nodekey);
}
- rc = mdb_cmp(cursor->mc_txn, cursor->mc_dbi, key, &nodekey);
+ rc = cursor->mc_txn->mt_dbxs[cursor->mc_dbi].md_cmp(key, &nodekey);
if (rc == 0) {
set1:
/* we're already on the right page */
leaf = NODEPTR(top->mp_page, NUMKEYS(top->mp_page)-1);
MDB_SET_KEY(leaf, &nodekey);
}
- rc = mdb_cmp(cursor->mc_txn, cursor->mc_dbi, key, &nodekey);
+ rc = cursor->mc_txn->mt_dbxs[cursor->mc_dbi].md_cmp(key, &nodekey);
if (rc <= 0) goto set1;
}
/* If any parents have right-sibs, search.
MDB_val d2;
if ((rc = mdb_read_data(cursor->mc_txn, leaf, &d2)) != MDB_SUCCESS)
return rc;
- rc = mdb_dcmp(cursor->mc_txn, cursor->mc_dbi, data, &d2);
+ rc = cursor->mc_txn->mt_dbxs[cursor->mc_dbi].md_cmp(data, &d2);
if (rc) {
if (op == MDB_GET_BOTH || rc > 0)
return MDB_NOTFOUND;
if (rc == MDB_SUCCESS) {
/* there's only a key anyway, so this is a no-op */
if (IS_LEAF2(top->mp_page)) {
- int ksize = mc->mc_txn->mt_dbs[mc->mc_dbi].md_pad;
+ unsigned int ksize = mc->mc_txn->mt_dbs[mc->mc_dbi].md_pad;
if (key->mv_size != ksize)
return EINVAL;
if (flags == MDB_CURRENT) {
NULL, &mc->mc_xcursor->mx_cursor, 0, &mp2);
if (rc == MDB_SUCCESS) {
MDB_ppage *top, *parent;
- MDB_dpage *dp;
- ID2 mid;
MDB_node *ni;
unsigned int i;
+#if 0
+ MDB_dpage *dp;
+ ID2 mid;
int dirty_root = 0;
+#endif
mc->mc_txn->mt_dbs[mc->mc_dbi].md_entries -=
mc->mc_xcursor->mx_txn.mt_dbs[mc->mc_xcursor->mx_cursor.mc_dbi].md_entries;
{
MDB_cursor mc;
MDB_xcursor mx;
- int rc;
assert(key != NULL);
assert(data != NULL);
return mdb_stat0(env, &env->me_metas[toggle]->mm_dbs[MAIN_DBI], arg);
}
+static void
+mdb_default_cmp(MDB_txn *txn, MDB_dbi dbi)
+{
+ if (txn->mt_dbs[dbi].md_flags & (MDB_REVERSEKEY
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ |MDB_INTEGERKEY
+#endif
+ ))
+ txn->mt_dbxs[dbi].md_cmp = memnrcmp;
+ else
+ txn->mt_dbxs[dbi].md_cmp = memncmp;
+
+ if (txn->mt_dbs[dbi].md_flags & MDB_DUPSORT) {
+ if (txn->mt_dbs[dbi].md_flags & MDB_INTEGERDUP) {
+ if (txn->mt_dbs[dbi].md_flags & MDB_DUPFIXED)
+ txn->mt_dbxs[dbi].md_dcmp = intcmp;
+ else
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ txn->mt_dbxs[dbi].md_dcmp = memnrcmp;
+#else
+ txn->mt_dbxs[dbi].md_dcmp = memncmp;
+#endif
+ } else if (txn->mt_dbs[dbi].md_flags & MDB_REVERSEDUP) {
+ txn->mt_dbxs[dbi].md_dcmp = memnrcmp;
+ } else {
+ txn->mt_dbxs[dbi].md_dcmp = memncmp;
+ }
+ } else {
+ txn->mt_dbxs[dbi].md_dcmp = NULL;
+ }
+}
+
int mdb_open(MDB_txn *txn, const char *name, unsigned int flags, MDB_dbi *dbi)
{
MDB_val key, data;
int rc, dirty = 0;
size_t len;
+ if (txn->mt_dbxs[FREE_DBI].md_cmp == NULL) {
+ mdb_default_cmp(txn, FREE_DBI);
+ }
+
/* main DB? */
if (!name) {
*dbi = MAIN_DBI;
if (flags & (MDB_DUPSORT|MDB_REVERSEKEY|MDB_INTEGERKEY))
txn->mt_dbs[MAIN_DBI].md_flags |= (flags & (MDB_DUPSORT|MDB_REVERSEKEY|MDB_INTEGERKEY));
+ mdb_default_cmp(txn, MAIN_DBI);
return MDB_SUCCESS;
}
+ if (txn->mt_dbxs[MAIN_DBI].md_cmp == NULL) {
+ mdb_default_cmp(txn, MAIN_DBI);
+ }
+
/* Is the DB already open? */
len = strlen(name);
for (i=2; i<txn->mt_numdbs; i++) {
if (rc == MDB_SUCCESS) {
txn->mt_dbxs[txn->mt_numdbs].md_name.mv_data = strdup(name);
txn->mt_dbxs[txn->mt_numdbs].md_name.mv_size = len;
- txn->mt_dbxs[txn->mt_numdbs].md_cmp = NULL;
- txn->mt_dbxs[txn->mt_numdbs].md_dcmp = NULL;
txn->mt_dbxs[txn->mt_numdbs].md_rel = NULL;
txn->mt_dbxs[txn->mt_numdbs].md_parent = MAIN_DBI;
txn->mt_dbxs[txn->mt_numdbs].md_dirty = dirty;
*dbi = txn->mt_numdbs;
txn->mt_env->me_dbs[0][txn->mt_numdbs] = txn->mt_dbs[txn->mt_numdbs];
txn->mt_env->me_dbs[1][txn->mt_numdbs] = txn->mt_dbs[txn->mt_numdbs];
+ mdb_default_cmp(txn, txn->mt_numdbs);
txn->mt_numdbs++;
}