Browse Source

issue 4653: refactor ldbm backend to allow replacement of BDB - phase 3e - dbscan (#4709)

* issue 4653: refactor ldbm backend to allow replacement of BDB - phase 3e - dbscan

* issue 4653: refactor ldbm backend to allow replacement of BDB - phase 3e - dbscan - fix indentation
progier389 4 years ago
parent
commit
1bd1411a69

+ 3 - 2
Makefile.am

@@ -181,6 +181,7 @@ ldaplib = @ldaplib@
 ldaplib_defs = @ldaplib_defs@
 
 DB_LINK = @db_lib@ -ldb-@db_libver@
+DB_IMPL = libback-ldbm.la
 SASL_LINK = $(SASL_LIBS)
 NETSNMP_LINK = @netsnmp_lib@ @netsnmp_link@
 PAM_LINK = -lpam
@@ -1788,8 +1789,8 @@ libwhoami_plugin_la_LDFLAGS = -avoid-version
 #------------------------
 dbscan_SOURCES = ldap/servers/slapd/tools/dbscan.c
 
-dbscan_CPPFLAGS = @db_inc@ $(NSPR_INCLUDES) $(AM_CPPFLAGS)
-dbscan_LDADD = $(NSPR_LINK) $(DB_LINK)
+dbscan_CPPFLAGS = $(NSPR_INCLUDES) $(AM_CPPFLAGS)
+dbscan_LDADD = $(NSPR_LINK) $(DB_IMPL)
 
 #------------------------
 # ldap-agent

+ 2 - 0
ldap/servers/slapd/back-ldbm/db-bdb/bdb_config.c

@@ -125,6 +125,8 @@ int bdb_init(struct ldbminfo *li, config_info *config_array)
     priv->dblayer_dbi_txn_abort_fn = &bdb_dbi_txn_abort;
     priv->dblayer_get_entries_count_fn = &bdb_get_entries_count;
     priv->dblayer_cursor_get_count_fn = &bdb_public_cursor_get_count;
+    priv->dblayer_private_open_fn = &bdb_public_private_open;
+    priv->dblayer_private_close_fn = &bdb_public_private_close;
 
     bdb_fake_priv = *priv; /* Copy the callbaks for bdb_be() */
     return 0;

+ 46 - 0
ldap/servers/slapd/back-ldbm/db-bdb/bdb_layer.c

@@ -6436,6 +6436,9 @@ int bdb_public_cursor_bulkop(dbi_cursor_t *cursor,  dbi_op_t op, dbi_val_t *key,
     bdb_dbival2dbt(&bulkdata->v, &bdb_data, PR_FALSE);
     switch (op)
     {
+        case DBI_OP_MOVE_TO_FIRST:
+            rc = bdb_cur->c_get(bdb_cur, &bdb_key, &bdb_data, DB_FIRST | DB_MULTIPLE);
+            break;
         case DBI_OP_MOVE_TO_KEY:
             rc = bdb_cur->c_get(bdb_cur, &bdb_key, &bdb_data, DB_SET | mflag);
             break;
@@ -6490,6 +6493,9 @@ int bdb_public_cursor_op(dbi_cursor_t *cursor,  dbi_op_t op, dbi_val_t *key, dbi
         case DBI_OP_MOVE_TO_RECNO:
             rc = bdb_cur->c_get(bdb_cur, &bdb_key, &bdb_data, DB_SET_RECNO);
             break;
+        case DBI_OP_MOVE_TO_FIRST:
+            rc = bdb_cur->c_get(bdb_cur, &bdb_key, &bdb_data, DB_FIRST);
+            break;
         case DBI_OP_MOVE_TO_LAST:
             rc = bdb_cur->c_get(bdb_cur, &bdb_key, &bdb_data, DB_LAST);
             break;
@@ -6713,3 +6719,43 @@ bdb_public_cursor_get_count(dbi_cursor_t *cursor, dbi_recno_t *count)
     int rc = cur->c_count(cur, count, 0);
     return bdb_map_error(__FUNCTION__, rc);
 }
+
+int
+bdb_public_private_open(const char *db_filename, dbi_env_t **env, dbi_db_t **db)
+{
+    int rc;
+    DB_ENV *bdb_env = NULL;
+    DB *bdb_db = NULL;
+
+    rc = db_env_create(&bdb_env, 0);
+    if (rc == 0) {
+        rc = bdb_env->open(bdb_env, NULL, DB_CREATE | DB_INIT_MPOOL | DB_PRIVATE, 0);
+    }
+    if (rc == 0) {
+        rc = db_create(&bdb_db, bdb_env, 0);
+    }
+    if (rc == 0) {
+        rc = bdb_db->open(bdb_db, NULL, db_filename, NULL, DB_UNKNOWN, DB_RDONLY, 0);
+    }
+    *env = bdb_env;
+    *db = bdb_db;
+    return bdb_map_error(__FUNCTION__, rc);
+}
+
+int
+bdb_public_private_close(dbi_env_t **env, dbi_db_t **db)
+{
+    DB_ENV *bdb_env = *env;
+    DB *bdb_db = *db;
+    int rc = 0;
+
+    if (bdb_db) {
+        rc = bdb_db->close(bdb_db, 0);
+    }
+    if (bdb_env) {
+        rc = bdb_env->close(bdb_env, 0);
+    }
+    *db = NULL;
+    *env = NULL;
+    return bdb_map_error(__FUNCTION__, rc);
+}

+ 2 - 0
ldap/servers/slapd/back-ldbm/db-bdb/bdb_layer.h

@@ -133,6 +133,8 @@ dblayer_dbi_txn_commit_fn_t bdb_dbi_txn_commit;
 dblayer_dbi_txn_abort_fn_t bdb_dbi_txn_abort;
 dblayer_get_entries_count_fn_t bdb_get_entries_count;
 dblayer_cursor_get_count_fn_t bdb_public_cursor_get_count;
+dblayer_private_open_fn_t bdb_public_private_open;
+dblayer_private_close_fn_t bdb_public_private_close;
 
 /* instance functions */
 int bdb_instance_cleanup(struct ldbm_instance *inst);

+ 50 - 2
ldap/servers/slapd/back-ldbm/dbimpl.c

@@ -125,6 +125,7 @@ int dblayer_cursor_bulkop(dbi_cursor_t *cursor,  dbi_op_t op, dbi_val_t *key, db
     dblayer_private *priv = dblayer_get_priv(cursor->be);
     int rc = DBI_RC_UNSUPPORTED;
     switch (op) {
+        case DBI_OP_MOVE_TO_FIRST:
         case DBI_OP_MOVE_TO_KEY:
         case DBI_OP_NEXT_DATA:
         case DBI_OP_NEXT_KEY:
@@ -157,6 +158,7 @@ int dblayer_cursor_op(dbi_cursor_t *cursor,  dbi_op_t op, dbi_val_t *key, dbi_va
         case DBI_OP_MOVE_TO_DATA:
         case DBI_OP_MOVE_NEAR_DATA:
         case DBI_OP_MOVE_TO_RECNO:
+        case DBI_OP_MOVE_TO_FIRST:
         case DBI_OP_MOVE_TO_LAST:
         case DBI_OP_GET_RECNO:
         case DBI_OP_NEXT:
@@ -178,7 +180,7 @@ int dblayer_cursor_op(dbi_cursor_t *cursor,  dbi_op_t op, dbi_val_t *key, dbi_va
     return rc;
 }
 
-int dblayer_db_op(Slapi_Backend *be, dbi_env_t *env,  dbi_txn_t *txn, dbi_op_t op, dbi_val_t *key, dbi_val_t *data)
+int dblayer_db_op(Slapi_Backend *be, dbi_db_t *db,  dbi_txn_t *txn, dbi_op_t op, dbi_val_t *key, dbi_val_t *data)
 {
     dblayer_private *priv = dblayer_get_priv(be);
     int rc = DBI_RC_UNSUPPORTED;
@@ -188,7 +190,7 @@ int dblayer_db_op(Slapi_Backend *be, dbi_env_t *env,  dbi_txn_t *txn, dbi_op_t o
         case DBI_OP_DEL:
         case DBI_OP_ADD:
         case DBI_OP_CLOSE:
-            rc = priv->dblayer_db_op_fn(env, txn, op, key, data);
+            rc = priv->dblayer_db_op_fn(db, txn, op, key, data);
             break;
         default:
             PR_ASSERT(0);
@@ -395,3 +397,49 @@ const char *dblayer_op2str(dbi_op_t op)
     return str[idx];
 }
 
+/* Open db env, db and db file privately */
+int dblayer_private_open(const char *plgname, const char *dbfilename, Slapi_Backend **be, dbi_env_t **env, dbi_db_t **db)
+{
+    struct ldbminfo *li;
+    int rc;
+
+    /* Setup a fake backend that supports dblayer_get_priv */
+    *be = (Slapi_Backend*) slapi_ch_calloc(1, sizeof (Slapi_Backend));
+    (*be)->be_database = (struct slapdplugin *)slapi_ch_calloc(1, sizeof(struct slapdplugin));
+    li = (struct ldbminfo *)slapi_ch_calloc(1, sizeof(struct ldbminfo));
+    (*be)->be_database->plg_private = li;
+    li->li_plugin = (*be)->be_database;
+    li->li_plugin->plg_name = "back-ldbm-dbimpl";
+    li->li_plugin->plg_libpath = "libback-ldbm";
+
+    /* Initialize database plugin */
+    rc = dbimpl_setup(li, plgname);
+    /* Then open the env database plugin */
+    if (!rc) {
+        dblayer_private *priv = li->li_dblayer_private;
+        rc = priv->dblayer_private_open_fn(dbfilename, env, db);
+    }
+    if (rc) {
+        dblayer_private_close(be, env, db);
+    }
+    return rc;
+}
+
+int dblayer_private_close(Slapi_Backend **be, dbi_env_t **env, dbi_db_t **db)
+{
+    int rc = 0;
+    if (*be) {
+        struct ldbminfo *li = (struct ldbminfo *)(*be)->be_database->plg_private;
+        dblayer_private *priv = li->li_dblayer_private;
+
+        if (priv && priv->dblayer_private_close_fn) {
+            rc = priv->dblayer_private_close_fn(env, db);
+        }
+        slapi_ch_free((void**)&li->li_dblayer_private);
+        slapi_ch_free((void**)&(*be)->be_database->plg_private);
+        slapi_ch_free((void**)&(*be)->be_database);
+        slapi_ch_free((void**)be);
+    }
+    return rc;
+}
+

+ 5 - 1
ldap/servers/slapd/back-ldbm/dbimpl.h

@@ -59,6 +59,7 @@ typedef enum {
                                  * then get the record.
                                  */
     DBI_OP_MOVE_TO_RECNO,       /* move cursor to specified record number */
+    DBI_OP_MOVE_TO_FIRST,       /* move cursor to first key */
     DBI_OP_MOVE_TO_LAST,
     DBI_OP_GET,                 /* db operation: get record associated with key */
     DBI_OP_GET_RECNO,           /* Get current record number */
@@ -122,7 +123,7 @@ int dblayer_bulk_set_buffer(Slapi_Backend *be, dbi_bulk_t *bulkdata, void *buff,
 int dblayer_bulk_start(dbi_bulk_t *bulkdata);
 int dblayer_cursor_bulkop(dbi_cursor_t *cursor,  dbi_op_t op, dbi_val_t *key, dbi_bulk_t *bulkdata);
 int dblayer_cursor_op(dbi_cursor_t *cursor,  dbi_op_t op, dbi_val_t *key, dbi_val_t *data);
-int dblayer_db_op(Slapi_Backend *be, dbi_env_t *env,  dbi_txn_t *txn, dbi_op_t op, dbi_val_t *key, dbi_val_t *data);
+int dblayer_db_op(Slapi_Backend *be, dbi_db_t *db,  dbi_txn_t *txn, dbi_op_t op, dbi_val_t *key, dbi_val_t *data);
 int dblayer_new_cursor(Slapi_Backend *be, dbi_db_t *db,  dbi_txn_t *txn, dbi_cursor_t *cursor);
 int dblayer_value_free(Slapi_Backend *be, dbi_val_t *data);
 int dblayer_value_init(Slapi_Backend *be, dbi_val_t *data);
@@ -149,4 +150,7 @@ const char *dblayer_strerror(int error);
 const char *dblayer_op2str(dbi_op_t op);
 int dblayer_cursor_get_count(dbi_cursor_t *cursor, dbi_recno_t *count);
 
+int dblayer_private_open(const char *plgname, const char *dbfilename, Slapi_Backend **be, dbi_env_t **env, dbi_db_t **db);
+int dblayer_private_close(Slapi_Backend **be, dbi_env_t **env, dbi_db_t **db);
+
 #endif /* _DBIMPL_H */

+ 16 - 5
ldap/servers/slapd/back-ldbm/dblayer.c

@@ -162,7 +162,7 @@ dblayer_init(struct ldbminfo *li)
 }
 
 int
-dblayer_setup(struct ldbminfo *li)
+dbimpl_setup(struct ldbminfo *li, const char *plgname)
 {
     int rc = 0;
     dblayer_private *priv = NULL;
@@ -179,7 +179,11 @@ dblayer_setup(struct ldbminfo *li)
      * structures with some default values */
     ldbm_config_setup_default(li);
 
-    backend_implement_init = slapi_ch_smprintf("%s_init", li->li_backend_implement);
+    if (!plgname) {
+        plgname = li->li_backend_implement;
+    }
+
+    backend_implement_init = slapi_ch_smprintf("%s_init", plgname);
     backend_implement_init_x = sym_load(li->li_plugin->plg_libpath, backend_implement_init, "dblayer_implement", 1);
     slapi_ch_free_string(&backend_implement_init);
 
@@ -190,13 +194,20 @@ dblayer_setup(struct ldbminfo *li)
         return -1;
     }
 
-    ldbm_config_load_dse_info(li);
-    priv = (dblayer_private *)li->li_dblayer_private;
-    rc = priv->dblayer_load_dse_fn(li);
+    if (plgname == li->li_backend_implement) {
+        ldbm_config_load_dse_info(li);
+        priv = (dblayer_private *)li->li_dblayer_private;
+        rc = priv->dblayer_load_dse_fn(li);
+    }
 
     return rc;
 }
 
+int dblayer_setup(struct ldbminfo *li)
+{
+    return dbimpl_setup(li, NULL);
+}
+
 /* Check a given filesystem directory for access we need */
 #define DBLAYER_DIRECTORY_READ_ACCESS 1
 #define DBLAYER_DIRECTORY_WRITE_ACCESS 2

+ 6 - 1
ldap/servers/slapd/back-ldbm/dblayer.h

@@ -98,7 +98,7 @@ typedef int dblayer_bulk_init_fn_t(dbi_bulk_t *bulkdata);
 typedef int dblayer_bulk_start_fn_t(dbi_bulk_t *bulkdata);
 typedef int dblayer_cursor_bulkop_fn_t(dbi_cursor_t *cursor,  dbi_op_t op, dbi_val_t *key, dbi_bulk_t *bulkdata);
 typedef int dblayer_cursor_op_fn_t(dbi_cursor_t *cursor,  dbi_op_t op, dbi_val_t *key, dbi_val_t *data);
-typedef int dblayer_db_op_fn_t(dbi_env_t *env,  dbi_txn_t *txn, dbi_op_t op, dbi_val_t *key, dbi_val_t *data);
+typedef int dblayer_db_op_fn_t(dbi_db_t *db,  dbi_txn_t *txn, dbi_op_t op, dbi_val_t *key, dbi_val_t *data);
 typedef int dblayer_new_cursor_fn_t(dbi_db_t *db,  dbi_cursor_t *cursor);
 typedef int dblayer_value_alloc_fn_t(dbi_val_t *data, size_t size);
 typedef int dblayer_value_free_fn_t(dbi_val_t *data);
@@ -109,6 +109,8 @@ typedef int dblayer_dbi_txn_commit_fn_t(dbi_txn_t *txn);
 typedef int dblayer_dbi_txn_abort_fn_t(dbi_txn_t *txn);
 typedef int dblayer_get_entries_count_fn_t(dbi_db_t *db, int *count);
 typedef int dblayer_cursor_get_count_fn_t(dbi_cursor_t *cursor, dbi_recno_t *count);
+typedef int dblayer_private_open_fn_t(const char *db_filename, dbi_env_t **env, dbi_db_t **db);
+typedef int dblayer_private_close_fn_t(dbi_env_t **env, dbi_db_t **db);
 
 struct dblayer_private
 {
@@ -178,6 +180,8 @@ struct dblayer_private
     dblayer_dbi_txn_abort_fn_t *dblayer_dbi_txn_abort_fn;
     dblayer_get_entries_count_fn_t *dblayer_get_entries_count_fn;
     dblayer_cursor_get_count_fn_t *dblayer_cursor_get_count_fn;
+    dblayer_private_open_fn_t *dblayer_private_open_fn;
+    dblayer_private_close_fn_t *dblayer_private_close_fn;
 };
 
 #define DBLAYER_PRIV_SET_DATA_DIR 0x1
@@ -188,6 +192,7 @@ back_txn *dblayer_get_pvt_txn(void);
 void dblayer_pop_pvt_txn(void);
 
 int dblayer_delete_indices(ldbm_instance *inst);
+int dbimpl_setup(struct ldbminfo *li, const char *plgname);
 
 
 /* Return the last four characters of a string; used for comparing extensions. */

+ 162 - 249
ldap/servers/slapd/tools/dbscan.c

@@ -25,7 +25,8 @@
 #include <string.h>
 #include <ctype.h>
 #include <errno.h>
-#include "db.h"
+#include "../back-ldbm/dbimpl.h"
+#include "../slapi-plugin.h"
 #include "nspr.h"
 #include <netinet/in.h>
 #include <inttypes.h>
@@ -104,10 +105,10 @@ typedef struct _rdn_elem
     ((elem)->rdn_elem_nrdn_rdn + \
      sizeushort_stored_to_internal((elem)->rdn_elem_nrdn_len))
 
-static void display_entryrdn_parent(DB *db, ID id, const char *nrdn, int indent);
-static void display_entryrdn_self(DB *db, ID id, const char *nrdn, int indent);
-static void display_entryrdn_children(DB *db, ID id, const char *nrdn, int indent);
-static void display_entryrdn_item(DB *db, DBC *cursor, DBT *key);
+static void display_entryrdn_parent(dbi_db_t *db, ID id, const char *nrdn, int indent);
+static void display_entryrdn_self(dbi_db_t *db, ID id, const char *nrdn, int indent);
+static void display_entryrdn_children(dbi_db_t *db, ID id, const char *nrdn, int indent);
+static void display_entryrdn_item(dbi_db_t *db, dbi_cursor_t *cursor, dbi_val_t *key);
 
 uint32_t file_type = 0;
 uint32_t min_display = 0;
@@ -122,6 +123,8 @@ long ind_cnt = 0;
 long allids_cnt = 0;
 long other_cnt = 0;
 
+Slapi_Backend *be = NULL;     /* Pseudo backend used to interact with db */
+
 /** db_printf - functioning same as printf but a place for manipluating output.
 */
 void
@@ -149,7 +152,7 @@ uint32_t MAX_BUFFER = 4096;
 uint32_t MIN_BUFFER = 20;
 
 static IDL *
-idl_make(DBT *data)
+idl_make(dbi_val_t *data)
 {
     IDL *idl = NULL, *xidl;
 
@@ -583,7 +586,7 @@ print_changelog(unsigned char *data, int len __attribute__((unused)))
 }
 
 static void
-display_index_item(DBC *cursor, DBT *key, DBT *data, unsigned char *buf, int buflen)
+display_index_item(dbi_cursor_t *cursor, dbi_val_t *key, dbi_val_t *data, unsigned char *buf, int buflen)
 {
     IDL *idl = NULL;
     int ret = 0;
@@ -603,8 +606,12 @@ display_index_item(DBC *cursor, DBT *key, DBT *data, unsigned char *buf, int buf
                 printf("%-40s\n", format(key->data, key->size, buf, buflen));
             }
             if (display_mode & SHOWDATA) {
-                cursor->c_get(cursor, key, data, DB_GET_RECNO);
-                printf("\t%5d\n", *(db_recno_t *)(data->data));
+                dblayer_cursor_op(cursor, DBI_OP_GET_RECNO, key, data);
+                if (data->data) {
+                    printf("\t%5d\n", *(dbi_recno_t *)(data->data));
+                } else {
+                    printf("\tNO DATA\n");
+                }
             }
         }
         goto index_done;
@@ -613,14 +620,14 @@ display_index_item(DBC *cursor, DBT *key, DBT *data, unsigned char *buf, int buf
     /* ordinary index file */
     /* fetch all other id's too */
     while (ret == 0) {
-        ret = cursor->c_get(cursor, key, data, DB_NEXT_DUP);
+        ret = dblayer_cursor_op(cursor, DBI_OP_NEXT_DATA, key, data);
         if (ret == 0)
             idl = idl_append(idl, *(uint32_t *)(data->data));
     }
-    if (ret == DB_NOTFOUND)
+    if (ret == DBI_RC_NOTFOUND)
         ret = 0;
     if (ret != 0) {
-        printf("Failure while looping dupes: %s\n", db_strerror(ret));
+        printf("Failure while looping dupes: %s\n", dblayer_strerror(ret));
         exit(1);
     }
 
@@ -708,7 +715,7 @@ index_done:
 }
 
 static void
-display_item(DBC *cursor, DBT *key, DBT *data)
+display_item(dbi_cursor_t *cursor, dbi_val_t *key, dbi_val_t *data)
 {
     static unsigned char *buf = NULL;
     static int buflen = 0;
@@ -787,256 +794,187 @@ _entryrdn_dump_rdn_elem(char *key, rdn_elem *elem, int indent)
 }
 
 static void
-display_entryrdn_self(DB *db, ID id, const char *nrdn __attribute__((unused)), int indent)
+display_entryrdn_self(dbi_db_t *db, ID id, const char *nrdn __attribute__((unused)), int indent)
 {
-    DBC *cursor = NULL;
-    DBT key, data;
-    char *keybuf = NULL;
-    int rc = 0;
+    dbi_cursor_t cursor = {0};
+    dbi_val_t key = {0}, data = {0};
     rdn_elem *elem;
-    char buffer[1024];
+    char buffer[30];
+    int rc = 0;
 
-    rc = db->cursor(db, NULL, &cursor, 0);
+    rc = dblayer_new_cursor(be, db, NULL, &cursor);
     if (rc) {
-        printf("Can't create db cursor: %s\n", db_strerror(rc));
+        printf("Can't create db cursor: %s\n", dblayer_strerror(rc));
         exit(1);
     }
     snprintf(buffer, sizeof(buffer), "%u", id);
-    keybuf = strdup(buffer);
-    key.data = keybuf;
-    key.size = key.ulen = strlen(keybuf) + 1;
-    key.flags = DB_DBT_USERMEM;
-
-    memset(&data, 0, sizeof(data));
+    dblayer_value_strdup(be, &key, buffer);
 
     /* Position cursor at the matching key */
-    rc = cursor->c_get(cursor, &key, &data, DB_SET);
+    rc = dblayer_cursor_op(&cursor, DBI_OP_MOVE_TO_KEY,  &key, &data);
     if (rc) {
         fprintf(stderr, "Failed to position cursor at the key: %s: %s "
                         "(%d)\n",
-                (char *)key.data, db_strerror(rc), rc);
+                (char *)key.data, dblayer_strerror(rc), rc);
         goto bail;
     }
 
     elem = (rdn_elem *)data.data;
-    _entryrdn_dump_rdn_elem(keybuf, elem, indent);
+    _entryrdn_dump_rdn_elem(key.data, elem, indent);
     display_entryrdn_parent(db, id_stored_to_internal(elem->rdn_elem_id),
                             elem->rdn_elem_nrdn_rdn, indent);
     display_entryrdn_children(db, id_stored_to_internal(elem->rdn_elem_id),
                               elem->rdn_elem_nrdn_rdn, indent);
 bail:
-    free(keybuf);
-    cursor->c_close(cursor);
-
-    return;
+    dblayer_value_free(be, &key);
+    dblayer_value_free(be, &data);
+    dblayer_cursor_op(&cursor, DBI_OP_CLOSE, NULL, NULL);
 }
 
 static void
-display_entryrdn_parent(DB *db, ID id, const char *nrdn __attribute__((unused)), int indent)
+display_entryrdn_parent(dbi_db_t *db, ID id, const char *nrdn __attribute__((unused)), int indent)
 {
-    DBC *cursor = NULL;
-    DBT key, data;
-    char *keybuf = NULL;
+    dbi_cursor_t cursor = {0};
+    dbi_val_t key = {0}, data = {0};
     int rc = 0;
     rdn_elem *elem;
-    char buffer[1024];
+    char buffer[30];
 
-    rc = db->cursor(db, NULL, &cursor, 0);
+    rc = dblayer_new_cursor(be, db, NULL, &cursor);
     if (rc) {
-        printf("Can't create db cursor: %s\n", db_strerror(rc));
+        printf("Can't create db cursor: %s\n", dblayer_strerror(rc));
         exit(1);
     }
     snprintf(buffer, sizeof(buffer), "P%d", id);
-    keybuf = strdup(buffer);
-    key.data = keybuf;
-    key.size = key.ulen = strlen(keybuf) + 1;
-    key.flags = DB_DBT_USERMEM;
-
-    memset(&data, 0, sizeof(data));
+    dblayer_value_strdup(be, &key, buffer);
 
     /* Position cursor at the matching key */
-    rc = cursor->c_get(cursor, &key, &data, DB_SET);
+    rc = dblayer_cursor_op(&cursor, DBI_OP_MOVE_TO_KEY,  &key, &data);
     if (rc) {
         fprintf(stderr, "Failed to position cursor at the key: %s: %s "
                         "(%d)\n",
-                (char *)key.data, db_strerror(rc), rc);
+                (char *)key.data, dblayer_strerror(rc), rc);
         goto bail;
     }
 
     elem = (rdn_elem *)data.data;
-    _entryrdn_dump_rdn_elem(keybuf, elem, indent);
+    _entryrdn_dump_rdn_elem(key.data, elem, indent);
 bail:
-    free(keybuf);
-    cursor->c_close(cursor);
-
-    return;
+    dblayer_value_free(be, &key);
+    dblayer_value_free(be, &data);
+    dblayer_cursor_op(&cursor, DBI_OP_CLOSE, NULL, NULL);
 }
 
 static void
-display_entryrdn_children(DB *db, ID id, const char *nrdn __attribute__((unused)), int indent)
+display_entryrdn_children(dbi_db_t *db, ID id, const char *nrdn __attribute__((unused)), int indent)
 {
-    DBC *cursor = NULL;
-    DBT key, data;
-    char *keybuf = NULL;
+    dbi_cursor_t cursor = {0};
+    dbi_val_t key = {0}, data = {0};
     int rc = 0;
     rdn_elem *elem = NULL;
-    ;
-    char buffer[1024];
+    char buffer[30];
 
-    rc = db->cursor(db, NULL, &cursor, 0);
+    rc = dblayer_new_cursor(be, db, NULL, &cursor);
     if (rc) {
-        printf("Can't create db cursor: %s\n", db_strerror(rc));
+        printf("Can't create db cursor: %s\n", dblayer_strerror(rc));
         exit(1);
     }
     indent += 2;
     snprintf(buffer, sizeof(buffer), "C%d", id);
-    keybuf = strdup(buffer);
-    key.data = keybuf;
-    key.size = key.ulen = strlen(keybuf) + 1;
-    key.flags = DB_DBT_USERMEM;
-
-    memset(&data, 0, sizeof(data));
-    data.ulen = sizeof(buffer);
-    data.size = sizeof(buffer);
-    data.data = buffer;
-    data.flags = DB_DBT_USERMEM;
+    dblayer_value_strdup(be, &key, buffer);
 
     /* Position cursor at the matching key */
-    rc = cursor->c_get(cursor, &key, &data, DB_SET);
+    rc = dblayer_cursor_op(&cursor, DBI_OP_MOVE_TO_KEY,  &key, &data);
+
     if (rc) {
-        if (DB_BUFFER_SMALL == rc) {
-            fprintf(stderr, "Entryrdn index is corrupt; "
-                            "data item for key %s is too large for our "
-                            "buffer (need=%d actual=%d)\n",
-                    (char *)key.data, data.size, data.ulen);
-        } else if (rc != DB_NOTFOUND) {
-            fprintf(stderr, "Failed to position cursor at the key: %s: %s "
-                            "(%d)\n",
-                    (char *)key.data, db_strerror(rc), rc);
-        }
+        fprintf(stderr, "Failed to position cursor at the key: %s: %s "
+                        "(%d)\n",
+                (char *)key.data, dblayer_strerror(rc), rc);
         goto bail;
     }
 
     /* Iterate over the duplicates */
     for (;;) {
         elem = (rdn_elem *)data.data;
-        _entryrdn_dump_rdn_elem(keybuf, elem, indent);
+        _entryrdn_dump_rdn_elem(key.data, elem, indent);
         display_entryrdn_self(db, id_stored_to_internal(elem->rdn_elem_id),
                               elem->rdn_elem_nrdn_rdn, indent);
-        rc = cursor->c_get(cursor, &key, &data, DB_NEXT_DUP);
+        rc = dblayer_cursor_op(&cursor, DBI_OP_NEXT_DATA,  &key, &data);
+        if (rc == DBI_RC_BUFFER_SMALL) {
+            dblayer_value_free(be, &data);
+            rc = dblayer_cursor_op(&cursor, DBI_OP_NEXT_DATA,  &key, &data);
+        }
         if (rc) {
             break;
         }
     }
     if (rc) {
-        if (DB_BUFFER_SMALL == rc) {
-            fprintf(stderr, "Entryrdn index is corrupt; "
-                            "data item for key %s is too large for our "
-                            "buffer (need=%d actual=%d)\n",
-                    (char *)key.data, data.size, data.ulen);
-        } else if (rc != DB_NOTFOUND) {
-            fprintf(stderr, "Failed to position cursor at the key: %s: %s "
-                            "(%d)\n",
-                    (char *)key.data, db_strerror(rc), rc);
-        }
+        fprintf(stderr, "Failed to position cursor at the key: %s: %s "
+                     "(%d)\n", (char *)key.data, dblayer_strerror(rc), rc);
     }
 bail:
-    free(keybuf);
-    cursor->c_close(cursor);
-
-    return;
+    dblayer_value_free(be, &key);
+    dblayer_value_free(be, &data);
+    dblayer_cursor_op(&cursor, DBI_OP_CLOSE, NULL, NULL);
 }
 
 static void
-display_entryrdn_item(DB *db, DBC *cursor, DBT *key)
+display_entryrdn_item(dbi_db_t *db, dbi_cursor_t *cursor, dbi_val_t *key)
 {
     rdn_elem *elem = NULL;
     int indent = 2;
-    DBT data;
-    int rc;
-    uint32_t flags = 0;
+    dbi_bulk_t bulkdata = {0};
+    dbi_val_t dataret = {0};
+    int rc = 0;
     char buffer[RDN_BULK_FETCH_BUFFER_SIZE];
-    DBT dataret;
+    dbi_op_t op = DBI_OP_MOVE_TO_FIRST;
     int find_key_flag = 0;
+    char *keyval = "";
 
     /* Setting the bulk fetch buffer */
-    memset(&data, 0, sizeof(data));
-    data.ulen = sizeof(buffer);
-    data.size = sizeof(buffer);
-    data.data = buffer;
-    data.flags = DB_DBT_USERMEM;
+    dblayer_bulk_set_buffer(be, &bulkdata, buffer, (sizeof buffer), DBI_VF_BULK_DATA);
 
     if (key->data) { /* key is given */
         /* Position cursor at the matching key */
-        flags = DB_SET | DB_MULTIPLE;
+        op = DBI_OP_MOVE_TO_KEY;
         find_key_flag = 1;
-    } else { /* key is not given; scan all */
-        flags = DB_FIRST | DB_MULTIPLE;
     }
     do {
         /* Position cursor at the matching key */
-        rc = cursor->c_get(cursor, key, &data, flags);
-        if (rc) {
-            if (DB_BUFFER_SMALL == rc) {
-                fprintf(stderr, "Entryrdn index is corrupt; "
-                                "data item for key %s is too large for our "
-                                "buffer (need=%d actual=%d)\n",
-                        (char *)key->data, data.size, data.ulen);
-            } else {
-                if (rc != DB_NOTFOUND) {
-                    fprintf(stderr, "Failed to position cursor "
-                                    "at the key: %s: %s (%d)\n",
-                            (char *)key->data, db_strerror(rc), rc);
-                }
-            }
-            goto bail;
-        }
-
-        /* Iterate over the duplicates */
-        for (;;) {
-            void *ptr;
-            DB_MULTIPLE_INIT(ptr, &data);
-            for (;;) {
-                memset(&dataret, 0, sizeof(dataret));
-                DB_MULTIPLE_NEXT(ptr, &data, dataret.data, dataret.size);
-                if (dataret.data == NULL)
-                    break;
-                if (ptr == NULL)
-                    break;
+        rc = dblayer_cursor_bulkop(cursor, op, key, &bulkdata);
+        keyval = key->data;
 
+        if (rc == DBI_RC_SUCCESS) {
+            /* Loop on all records stored in bulk buffer */
+            for(dblayer_bulk_start(&bulkdata); DBI_RC_SUCCESS == dblayer_bulk_nextdata(&bulkdata, &dataret);) {
                 elem = (rdn_elem *)dataret.data;
-                _entryrdn_dump_rdn_elem((char *)key->data, elem, indent);
+                _entryrdn_dump_rdn_elem(keyval, elem, indent);
                 display_entryrdn_children(db, id_stored_to_internal(elem->rdn_elem_id),
                                           elem->rdn_elem_nrdn_rdn, indent);
             }
-            rc = cursor->c_get(cursor, key, &data, DB_NEXT_DUP | DB_MULTIPLE);
-            if (rc) {
-                break;
-            }
+            /* Then check if there are more data associated with current key */
+            op = DBI_OP_NEXT_DATA;
+            continue;
         }
-        /* When it comes here, rc is not 0. */
-        if (DB_BUFFER_SMALL == rc) {
-            fprintf(stderr, "Entryrdn index is corrupt; "
-                            "data item for key %s is too large for our "
-                            "buffer (need=%d actual=%d)\n",
-                    (char *)key->data, data.size, data.ulen);
-            goto bail;
-        } else if (rc == DB_NOTFOUND) {
-            if (find_key_flag) { /* key is given */
-                goto bail;       /* done */
-            } else {             /* otherwise, continue scanning. */
-                rc = 0;
-            }
-        } else {
-            fprintf(stderr, "Failed to position cursor at the key: %s: %s "
-                            "(%d)\n",
-                    (char *)key->data, db_strerror(rc), rc);
-            goto bail;
+        if (rc == DBI_RC_NOTFOUND && !find_key_flag && op == DBI_OP_NEXT_DATA) {
+            /* no more data for this key and next key should be walked */
+            rc = DBI_RC_SUCCESS;
+            op = DBI_OP_NEXT_KEY;
+            continue;
         }
-        flags = DB_NEXT | DB_MULTIPLE;
-    } while (0 == rc);
-bail:
-    return;
+    } while (rc == DBI_RC_SUCCESS);
+    if (DBI_RC_BUFFER_SMALL == rc) {
+        fprintf(stderr, "Entryrdn index is corrupt; "
+                        "data item for key %s is too large for our "
+                        "buffer (need=%ld actual=%ld)\n",
+                        keyval, dataret.size, dataret.ulen);
+    } else if (rc != DBI_RC_NOTFOUND || op == DBI_OP_MOVE_TO_KEY) {
+        fprintf(stderr, "Failed to position cursor "
+                        "at the key: %s: %s (%d)\n",
+                        keyval, dblayer_strerror(rc), rc);
+    }
+    dblayer_value_free(be, &dataret);
+    dblayer_bulk_free(&bulkdata);
 }
 
 static int
@@ -1055,7 +993,7 @@ is_changelog(char *filename)
         ptr++;
     }
 
-    if (strstr(ptr, "replication_changelog.db")) return 1;
+    if (0 == strcmp(ptr, "replication_changelog.db")) return 1;
 
     for (; ptr && *ptr; ptr++) {
         if ('.' == *ptr) {
@@ -1107,6 +1045,7 @@ usage(char *argv0)
     }
     printf("\n%s - scan a db file and dump the contents\n", p0);
     printf("  common options:\n");
+    printf("    -D <dbimpl>     specify db implementaion (may be: bdb or mdb)\n");
     printf("    -f <filename>   specify db file\n");
     printf("    -R              dump as raw data\n");
     printf("    -t <size>       entry truncate size (bytes)\n");
@@ -1138,19 +1077,18 @@ usage(char *argv0)
 int
 main(int argc, char **argv)
 {
-    DB_ENV *env = NULL;
-    DB *db = NULL;
-    DBC *cursor = NULL;
+    dbi_env_t *env = NULL;
+    dbi_db_t *db = NULL;
+    dbi_cursor_t cursor = {0};
     char *filename = NULL;
-    DBT key = {0}, data = {0};
+    dbi_val_t key = {0}, data = {0};
     int ret = 0;
     char *find_key = NULL;
     uint32_t entry_id = 0xffffffff;
+    char * dbimpl_name = "bdb";
     int c;
 
-    key.flags = DB_DBT_REALLOC;
-    data.flags = DB_DBT_REALLOC;
-    while ((c = getopt(argc, argv, "f:Rl:nG:srk:K:hvt:")) != EOF) {
+    while ((c = getopt(argc, argv, "f:Rl:nG:srk:K:hvt:D:")) != EOF) {
         switch (c) {
         case 'f':
             filename = optarg;
@@ -1195,6 +1133,9 @@ main(int argc, char **argv)
         case 't':
             truncatesiz = atoi(optarg);
             break;
+        case 'D':
+            dbimpl_name = optarg;
+            break;
         case 'h':
         default:
             usage(argv[0]);
@@ -1217,108 +1158,91 @@ main(int argc, char **argv)
         }
     }
 
-    ret = db_env_create(&env, 0);
-    if (ret != 0) {
-        printf("Can't create dbenv: %s\n", db_strerror(ret));
-        ret = 1;
-        goto done;
-    }
-    ret = env->open(env, NULL, DB_CREATE | DB_INIT_MPOOL | DB_PRIVATE, 0);
-    if (ret != 0) {
-        printf("Can't open dbenv: %s\n", db_strerror(ret));
-        ret = 1;
-        goto done;
-    }
-
-    ret = db_create(&db, env, 0);
-    if (ret != 0) {
-        printf("Can't create db handle: %d\n", ret);
-        ret = 1;
-        goto done;
-    }
-    ret = db->open(db, NULL, filename, NULL, DB_UNKNOWN, DB_RDONLY, 0);
-    if (ret != 0) {
-        printf("Can't open db file '%s': %s\n", filename, db_strerror(ret));
+    if (dblayer_private_open(dbimpl_name, filename, &be, &env, &db)) {
+        printf("Can't initialize db plugin: %s\n", dbimpl_name);
         ret = 1;
         goto done;
     }
 
     /* cursor through the db */
 
-    ret = db->cursor(db, NULL, &cursor, 0);
+    ret = dblayer_new_cursor(be, db, NULL, &cursor);
     if (ret != 0) {
-        printf("Can't create db cursor: %s\n", db_strerror(ret));
+        printf("Can't create db cursor: %s\n", dblayer_strerror(ret));
         ret = 1;
         goto done;
     }
-    ret = cursor->c_get(cursor, &key, &data, DB_FIRST);
-    if (ret == DB_NOTFOUND) {
+
+    /* Position cursor at the matching key */
+    ret = dblayer_cursor_op(&cursor, DBI_OP_MOVE_TO_FIRST,  &key, &data);
+    if (ret == DBI_RC_NOTFOUND) {
         printf("Empty database!\n");
         ret = 0;
         goto done;
     }
     if (ret != 0) {
-        printf("Can't get first cursor: %s\n", db_strerror(ret));
+        printf("Can't get first cursor: %s\n", dblayer_strerror(ret));
         ret = 1;
         goto done;
     }
 
     if (find_key) {
-        key.size = strlen(find_key) + 1;
-        key.data = find_key;
-        ret = db->get(db, NULL, &key, &data, 0);
-        if (ret != 0) {
+        /* Position cursor at the matching key */
+        dblayer_value_set_buffer(be, &key, find_key, strlen(find_key) + 1);
+        dblayer_value_free(be, &data);
+        ret = dblayer_db_op(be, db, NULL, DBI_OP_GET,  &key, &data);
+        if (ret == DBI_RC_NOTFOUND) {
             /* could be a key that doesn't have the trailing null? */
             key.size--;
-            ret = db->get(db, NULL, &key, &data, 0);
-            if (ret != 0) {
-                printf("Can't find key '%s'\n", find_key);
-                ret = 1;
-                goto done;
-            }
+            ret = dblayer_db_op(be, db, NULL, DBI_OP_GET,  &key, &data);
+        }
+        if (ret != 0) {
+            printf("Can't find key '%s' error=%s [%d]\n", find_key, dblayer_strerror(ret), ret);
+            ret = 1;
+            goto done;
         }
         if (file_type & ENTRYRDNINDEXTYPE) {
-            display_entryrdn_item(db, cursor, &key);
+            display_entryrdn_item(db, &cursor, &key);
         } else {
-            ret = cursor->c_get(cursor, &key, &data, DB_SET);
+            ret = dblayer_cursor_op(&cursor, DBI_OP_MOVE_TO_KEY,  &key, &data);
             if (ret != 0) {
                 printf("Can't set cursor to returned item: %s\n",
-                       db_strerror(ret));
+                       dblayer_strerror(ret));
                 ret = 1;
                 goto done;
             }
             do {
-                display_item(cursor, &key, &data);
-                ret = cursor->c_get(cursor, &key, &data, DB_NEXT_DUP);
+                display_item(&cursor, &key, &data);
+                ret = dblayer_cursor_op(&cursor, DBI_OP_NEXT_DATA,  &key, &data);
             } while (0 == ret);
-            key.size = 0;
-            key.data = NULL;
+            dblayer_value_free(be, &key);
+            dblayer_value_init(be, &key);
         }
     } else if (entry_id != 0xffffffff) {
-        key.size = sizeof(entry_id);
-        key.data = &entry_id;
-        ret = db->get(db, NULL, &key, &data, 0);
+        dblayer_value_set_buffer(be, &key, &entry_id, sizeof(entry_id));
+        ret = dblayer_db_op(be, db, NULL, DBI_OP_GET,  &key, &data);
         if (ret != 0) {
             printf("Can't set cursor to returned item: %s\n",
-                   db_strerror(ret));
+                   dblayer_strerror(ret));
             ret = 1;
             goto done;
         }
-        display_item(cursor, &key, &data);
-        key.size = 0;
-        key.data = NULL;
+        display_item(&cursor, &key, &data);
+        dblayer_value_free(be, &key);
+        dblayer_value_init(be, &key);
     } else {
         if (file_type & ENTRYRDNINDEXTYPE) {
-            key.data = NULL;
-            display_entryrdn_item(db, cursor, &key);
+            dblayer_value_free(be, &key);
+            dblayer_value_init(be, &key);
+            display_entryrdn_item(db, &cursor, &key);
         } else {
             while (ret == 0) {
                 /* display */
-                display_item(cursor, &key, &data);
+                display_item(&cursor, &key, &data);
 
-                ret = cursor->c_get(cursor, &key, &data, DB_NEXT);
-                if ((ret != 0) && (ret != DB_NOTFOUND)) {
-                    printf("Bizarre error: %s\n", db_strerror(ret));
+                ret = dblayer_cursor_op(&cursor, DBI_OP_NEXT,  &key, &data);
+                if ((ret != 0) && (ret != DBI_RC_NOTFOUND)) {
+                    printf("Bizarre error: %s\n", dblayer_strerror(ret));
                     ret = 1;
                     goto done;
                 }
@@ -1370,23 +1294,12 @@ done:
     if (data.data) {
         free(data.data);
     }
-    if (cursor) {
-        if (cursor->c_close(cursor) != 0) {
-            printf("Can't close the cursor (?!): %s\n", db_strerror(1));
-            return 1;
-        }
-    }
-    if (db) {
-        if (db->close(db, 0) != 0) {
-            printf("Unable to close db file: %s\n", db_strerror(1));
-            return 1;
-        }
-    }
-    if (env) {
-        if (env->close(env, 0) != 0) {
-            printf("Unable to shutdown libdb: %s\n", db_strerror(1));
-            return 1;
-        }
+    dblayer_value_free(be, &key);
+    dblayer_value_free(be, &data);
+    dblayer_cursor_op(&cursor, DBI_OP_CLOSE, NULL, NULL);
+    if (dblayer_private_close(&be, &env, &db)) {
+        printf("Unable to shutdown the db plugin: %s\n", dblayer_strerror(1));
+        return 1;
     }
     return ret;
 }