execution-efficient than the \fBbdb\fP backend, while being overall
much simpler to manage.
.SH CONFIGURATION
+These
+.B slapd.conf
+options apply to the \fBmdb\fP backend.
+That is, they must follow a "backend mdb" line and
+come before any subsequent "backend" or "database" lines.
+.TP
+.BI idlexp \ <exp>
+Specify a power of 2 for the maximum size of an index slot.
+The default is 16, yielding a maximum slot size of 2^16 or 65536.
+Once set, this option applies to every \fBmdb\fP database instance.
+.LP
+
These
.B slapd.conf
options apply to the \fBmdb\fP backend database.
#include <ac/errno.h>
#include "back-mdb.h"
+#include "idl.h"
#include "config.h"
#include "lutil.h"
#include "ldap_rq.h"
+
static ConfigDriver mdb_cf_gen;
+static ConfigDriver mdb_bk_cfg;
enum {
MDB_CHKPT = 1,
MDB_MODE,
MDB_SSTACK,
MDB_MULTIVAL,
+ MDB_IDLEXP,
};
static ConfigTable mdbcfg[] = {
+ { "idlexp", "log", 2, 2, 0, ARG_UINT|ARG_MAGIC|MDB_IDLEXP,
+ mdb_bk_cfg, "( OLcfgBkAt:12.1 NAME 'olcBkMdbIdlExp' "
+ "DESC 'Power of 2 used to set IDL size' "
+ "EQUALITY integerMatch "
+ "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
{ "directory", "dir", 2, 2, 0, ARG_STRING|ARG_MAGIC|MDB_DIRECTORY,
mdb_cf_gen, "( OLcfgDbAt:0.1 NAME 'olcDbDirectory' "
"DESC 'Directory for database content' "
};
static ConfigOCs mdbocs[] = {
+ {
+ "( OLcfgBkOc:12.1 "
+ "NAME 'olcMdbBkConfig' "
+ "DESC 'MDB backend configuration' "
+ "SUP olcBackendConfig "
+ "MAY olcBkMdbIdlExp )",
+ Cft_Backend, mdbcfg },
{
"( OLcfgDbOc:12.1 "
"NAME 'olcMdbConfig' "
- "DESC 'MDB backend configuration' "
+ "DESC 'MDB database configuration' "
"SUP olcDatabaseConfig "
"MUST olcDbDirectory "
"MAY ( olcDbCheckpoint $ olcDbEnvFlags $ "
"olcDbNoSync $ olcDbIndex $ olcDbMaxReaders $ olcDbMaxSize $ "
"olcDbMode $ olcDbSearchStack $ olcDbMaxEntrySize $ olcDbRtxnSize $ "
"olcDbMultival ) )",
- Cft_Database, mdbcfg },
+ Cft_Database, mdbcfg+1 },
{ NULL, 0, NULL }
};
{ BER_BVNULL, 0 }
};
+static int
+mdb_bk_cfg( ConfigArgs *c )
+{
+ int rc = 0;
+ if ( c->op == SLAP_CONFIG_EMIT ) {
+ if ( MDB_idl_logn != MDB_IDL_LOGN )
+ c->value_int = MDB_idl_logn;
+ else
+ rc = 1;
+ } else if ( c->op == LDAP_MOD_DELETE ) {
+ MDB_idl_logn = 0;
+ mdb_idl_reset();
+ } else {
+ if ( c->value_int >= MDB_IDL_LOGN && c->value_int < sizeof(int) * CHAR_BIT ) {
+ MDB_idl_logn = c->value_int;
+ mdb_idl_reset();
+ } else {
+ rc = 1;
+ }
+ }
+ return rc;
+}
+
/* perform periodic syncs */
static void *
mdb_checkpoint( void *ctx, void *arg )
ptr += data.mv_size - sizeof(ID);
memcpy( &id, ptr, sizeof(ID) );
if ( id == base ) {
- if ( res[0] >= MDB_IDL_DB_SIZE-1 ) {
+ if ( res[0] >= MDB_idl_db_max ) {
/* too many aliases in scope. Fallback to range */
MDB_IDL_RANGE( res, MDB_IDL_FIRST( ids ), MDB_IDL_LAST( ids ));
goto leave;
continue;
}
MDB_IDL_ZERO( save );
- rc = comp_candidates( op, rtxn, mra, f, save, tmp, save+MDB_IDL_UM_SIZE );
+ rc = comp_candidates( op, rtxn, mra, f, save, tmp, save+MDB_idl_um_size );
if ( rc != 0 ) {
if ( ftype == LDAP_COMP_FILTER_AND ) {
}
MDB_IDL_ZERO( save );
rc = mdb_filter_candidates( op, rtxn, f, save, tmp,
- save+MDB_IDL_UM_SIZE );
+ save+MDB_idl_um_size );
if ( rc != 0 ) {
if ( ftype == LDAP_FILTER_AND ) {
#include "back-mdb.h"
#include "idl.h"
+unsigned int MDB_idl_logn = MDB_IDL_LOGN;
+unsigned int MDB_idl_db_size = 1 << MDB_IDL_LOGN;
+unsigned int MDB_idl_um_size = 1 << (MDB_IDL_LOGN+1);
+unsigned int MDB_idl_db_max = (1 << MDB_IDL_LOGN) - 1;
+unsigned int MDB_idl_um_max = (1 << (MDB_IDL_LOGN+1) - 1);
+
#define IDL_MAX(x,y) ( (x) > (y) ? (x) : (y) )
#define IDL_MIN(x,y) ( (x) < (y) ? (x) : (y) )
#define IDL_CMP(x,y) ( (x) < (y) ? -1 : (x) > (y) )
#endif /* IDL_DEBUG > 1 */
#endif /* IDL_DEBUG > 0 */
+void mdb_idl_reset()
+{
+ if ( !MDB_idl_logn )
+ MDB_idl_logn = MDB_IDL_LOGN;
+
+ MDB_idl_db_size = 1 << MDB_idl_logn;
+ MDB_idl_um_size = 1 << (MDB_idl_logn+1);
+ MDB_idl_db_max = MDB_idl_db_size - 1;
+ MDB_idl_um_max = MDB_idl_um_size - 1;
+}
+
unsigned mdb_idl_search( ID *ids, ID id )
{
#define IDL_BINARY_SEARCH 1
return -1;
}
- if ( ++ids[0] >= MDB_IDL_DB_MAX ) {
+ if ( ++ids[0] >= MDB_idl_db_max ) {
if( id < ids[1] ) {
ids[1] = id;
ids[2] = ids[ids[0]-1];
err = "c_count";
goto fail;
}
- if ( count >= MDB_IDL_DB_MAX ) {
+ if ( count >= MDB_idl_db_max ) {
/* No room, convert to a range */
lo = *i;
rc = mdb_cursor_get( cursor, &key, &data, MDB_LAST_DUP );
/* The distinct elements of a are cat'd to b */
while( ida != NOID || idb != NOID ) {
if ( ida < idb ) {
- if( ++cursorc > MDB_IDL_UM_MAX ) {
+ if( ++cursorc > MDB_idl_um_max ) {
goto over;
}
b[cursorc] = ida;
}
}
ids[0]++;
- if ( ids[0] >= MDB_IDL_UM_MAX ) {
+ if ( ids[0] >= MDB_idl_um_max ) {
ids[0] = NOID;
ids[2] = id;
} else {
ida = MDB_IDL_LAST( a );
idb = MDB_IDL_LAST( b );
if ( MDB_IDL_IS_RANGE( a ) || MDB_IDL_IS_RANGE(b) ||
- a[0] + b[0] >= MDB_IDL_UM_MAX ) {
+ a[0] + b[0] >= MDB_idl_um_max ) {
a[2] = IDL_MAX( ida, idb );
a[1] = IDL_MIN( a[1], b[1] );
a[0] = NOID;
return -1;
}
- if ( ids[0].mid >= MDB_IDL_UM_MAX ) {
+ if ( ids[0].mid >= MDB_idl_um_max ) {
/* too big */
return -2;
* limiting factors: sizeof(ID), thread stack size
*/
#define MDB_IDL_LOGN 16 /* DB_SIZE is 2^16, UM_SIZE is 2^17 */
-#define MDB_IDL_DB_SIZE (1<<MDB_IDL_LOGN)
-#define MDB_IDL_UM_SIZE (1<<(MDB_IDL_LOGN+1))
-#define MDB_IDL_UM_SIZEOF (MDB_IDL_UM_SIZE * sizeof(ID))
-
-#define MDB_IDL_DB_MAX (MDB_IDL_DB_SIZE-1)
-
-#define MDB_IDL_UM_MAX (MDB_IDL_UM_SIZE-1)
+extern unsigned int MDB_idl_logn;
+extern unsigned int MDB_idl_db_size;
+extern unsigned int MDB_idl_um_size;
+extern unsigned int MDB_idl_db_max;
+extern unsigned int MDB_idl_um_max;
#define MDB_IDL_IS_RANGE(ids) ((ids)[0] == NOID)
#define MDB_IDL_RANGE_SIZE (3)
} IdScopes;
LDAP_BEGIN_DECL
+ /** Reset IDL params after changing logn */
+void mdb_idl_reset();
+
+
/** Search for an ID in an ID2L.
* @param[in] ids The ID2L to search.
* @param[in] id The ID to search for.
mdb->mi_multi_lo = UINT_MAX;
be->be_private = mdb;
- be->be_cf_ocs = be->bd_info->bi_cf_ocs;
+ be->be_cf_ocs = be->bd_info->bi_cf_ocs+1;
#ifndef MDB_MULTIPLE_SUFFIXES
SLAP_DBFLAGS( be ) |= SLAP_DBFLAG_ONE_SUFFIX;
Filter af;
aliases = stack; /* IDL of all aliases in the database */
- curscop = aliases + MDB_IDL_DB_SIZE; /* Aliases in the current scope */
- visited = curscop + MDB_IDL_DB_SIZE; /* IDs we've seen in this search */
- newsubs = visited + MDB_IDL_DB_SIZE; /* New subtrees we've added */
- oldsubs = newsubs + MDB_IDL_DB_SIZE; /* Subtrees added previously */
- tmp = oldsubs + MDB_IDL_DB_SIZE; /* Scratch space for deref_base() */
+ curscop = aliases + MDB_idl_db_size; /* Aliases in the current scope */
+ visited = curscop + MDB_idl_db_size; /* IDs we've seen in this search */
+ newsubs = visited + MDB_idl_db_size; /* New subtrees we've added */
+ oldsubs = newsubs + MDB_idl_db_size; /* Subtrees added previously */
+ tmp = oldsubs + MDB_idl_db_size; /* Scratch space for deref_base() */
af.f_choice = LDAP_FILTER_EQUALITY;
af.f_ava = &aa_alias;
ldap_pvt_thread_pool_getkey( op->o_threadctx, (void *)scope_chunk_get,
(void *)&ret, NULL );
if ( !ret ) {
- ret = ch_malloc( MDB_IDL_UM_SIZE * sizeof( ID2 ));
+ ret = ch_malloc( MDB_idl_um_size * sizeof( ID2 ));
} else {
void *r2 = ret[0].mval.mv_data;
ldap_pvt_thread_pool_setkey( op->o_threadctx, (void *)scope_chunk_get,
struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
ID id, cursor, nsubs, ncand, cscope;
ID lastid = NOID;
- ID candidates[MDB_IDL_UM_SIZE];
- ID iscopes[MDB_IDL_DB_SIZE];
+ ID candidates[MDB_idl_um_size];
+ ID iscopes[MDB_idl_db_size];
ID2 *scopes;
void *stack;
Entry *e = NULL, *base = NULL;
}
if ( !ret ) {
- ret = ch_malloc( mdb->mi_search_stack_depth * MDB_IDL_UM_SIZE
+ ret = ch_malloc( mdb->mi_search_stack_depth * MDB_idl_um_size
* sizeof( ID ) );
if ( op->o_threadctx ) {
ldap_pvt_thread_pool_setkey( op->o_threadctx, (void *)search_stack,
/* Allocate IDL stack, plus 1 more for former tmp */
if ( depth+1 > mdb->mi_search_stack_depth ) {
- stack = ch_malloc( (depth + 1) * MDB_IDL_UM_SIZE * sizeof( ID ) );
+ stack = ch_malloc( (depth + 1) * MDB_idl_um_size * sizeof( ID ) );
}
if( op->ors_deref & LDAP_DEREF_SEARCHING ) {
if ( rc == LDAP_SUCCESS ) {
rc = mdb_filter_candidates( op, isc->mt, f, ids,
- stack, stack+MDB_IDL_UM_SIZE );
+ stack, stack+MDB_idl_um_size );
}
if ( depth+1 > mdb->mi_search_stack_depth ) {
ID id, nid;
/* Freshly allocated, ignore it */
- if ( !ic->head && ic->count <= MDB_IDL_DB_SIZE ) {
+ if ( !ic->head && ic->count <= MDB_idl_db_size ) {
return 0;
}
key.mv_data = ic->kstr.bv_val;
key.mv_size = ic->kstr.bv_len;
- if ( ic->count > MDB_IDL_DB_SIZE ) {
+ if ( ic->count > MDB_idl_db_size ) {
while ( ic->flags & WAS_FOUND ) {
rc = mdb_cursor_get( mc, &key, data, MDB_SET );
if ( rc ) {
ic->flags |= WAS_FOUND;
nid = *(ID *)data.mv_data;
if ( nid == 0 ) {
- ic->count = MDB_IDL_DB_SIZE+1;
+ ic->count = MDB_idl_db_size+1;
ic->flags |= WAS_RANGE;
} else {
size_t count;
}
}
/* are we a range already? */
- if ( ic->count > MDB_IDL_DB_SIZE ) {
+ if ( ic->count > MDB_idl_db_size ) {
ic->last = id;
continue;
/* Are we at the limit, and converting to a range? */
- } else if ( ic->count == MDB_IDL_DB_SIZE ) {
+ } else if ( ic->count == MDB_idl_db_size ) {
if ( ic->head ) {
ic->tail->next = ax->ai_flist;
ax->ai_flist = ic->head;