Add mdb_dn2id_upgrade

Check if upgrade is needed in mdb_db_open()
Run from tool_reindex. Upgrade must not be interrupted.
This commit is contained in:
Howard Chu 2013-02-09 19:38:42 +00:00
parent 9ac070beb3
commit 2bbee4bb23
3 changed files with 176 additions and 2 deletions

View file

@ -96,6 +96,7 @@ struct mdb_info {
#define MDB_OPEN_INDEX 0x02
#define MDB_DEL_INDEX 0x08
#define MDB_RE_OPEN 0x10
#define MDB_NEED_UPGRADE 0x20
int mi_numads;

View file

@ -223,9 +223,40 @@ mdb_db_open( BackendDB *be, ConfigReply *cr )
if ( i == MDB_ID2ENTRY )
mdb_set_compare( txn, mdb->mi_dbis[i], mdb_id_compare );
else if ( i == MDB_DN2ID )
else if ( i == MDB_DN2ID ) {
MDB_cursor *mc;
MDB_val key, data;
ID id;
mdb_set_dupsort( txn, mdb->mi_dbis[i], mdb_dup_compare );
/* check for old dn2id format */
rc = mdb_cursor_open( txn, mdb->mi_dbis[i], &mc );
/* first record is always ID 0 */
rc = mdb_cursor_get( mc, &key, &data, MDB_FIRST );
if ( rc == 0 ) {
rc = mdb_cursor_get( mc, &key, &data, MDB_NEXT );
if ( rc == 0 ) {
int len;
unsigned char *ptr;
ptr = data.mv_data;
len = (ptr[0] & 0x7f) << 8 | ptr[1];
if (data.mv_size < 2*len + 4 + 2*sizeof(ID)) {
snprintf( cr->msg, sizeof(cr->msg),
"database \"%s\": DN index needs upgrade, "
"run \"slapindex entryDN\".",
be->be_suffix[0].bv_val );
Debug( LDAP_DEBUG_ANY,
LDAP_XSTRING(mdb_db_open) ": %s\n",
cr->msg, 0, 0 );
if ( !(slapMode & SLAP_TOOL_READMAIN ))
rc = LDAP_OTHER;
mdb->mi_flags |= MDB_NEED_UPGRADE;
}
}
}
mdb_cursor_close( mc );
if ( rc == LDAP_OTHER )
goto fail;
}
}
rc = mdb_ad_read( mdb, txn );

View file

@ -738,6 +738,8 @@ done:
return e->e_id;
}
static int mdb_dn2id_upgrade( BackendDB *be );
int mdb_tool_entry_reindex(
BackendDB *be,
ID id,
@ -755,6 +757,13 @@ int mdb_tool_entry_reindex(
assert( tool_base == NULL );
assert( tool_filter == NULL );
/* Special: do a dn2id upgrade */
if ( adv && adv[0] == slap_schema.si_ad_entryDN ) {
/* short-circuit tool_entry_next() */
mdb_cursor_get( cursor, &key, &data, MDB_LAST );
return mdb_dn2id_upgrade( be );
}
/* No indexes configured, nothing to do. Could return an
* error here to shortcut things.
*/
@ -1274,3 +1283,136 @@ int mdb_tool_idl_add(
return 0;
}
#endif /* MDB_TOOL_IDL_CACHING */
/* Upgrade from pre 2.4.34 dn2id format */
#include <ac/unistd.h>
#include <lutil_meter.h>
#define STACKSIZ 2048
typedef struct rec {
ID id;
size_t len;
char rdn[512];
} rec;
static int
mdb_dn2id_upgrade( BackendDB *be ) {
struct mdb_info *mi = (struct mdb_info *) be->be_private;
MDB_txn *mt;
MDB_cursor *mc;
MDB_val key, data;
char *ptr;
int rc, writes=0, depth=0;
int i, enable_meter = 0;
ID id = 0, *num, count = 0;
rec *stack;
lutil_meter_t meter;
if (!(mi->mi_flags & MDB_NEED_UPGRADE)) {
Debug( LDAP_DEBUG_ANY, "database %s: No upgrade needed.\n",
be->be_suffix[0].bv_val, 0, 0 );
return 0;
}
{
MDB_stat st;
mdb_stat(mdb_cursor_txn(cursor), mi->mi_dbis[MDB_ID2ENTRY], &st);
if (!st.ms_entries) {
/* Empty DB, nothing to upgrade? */
return 0;
}
if (isatty(2))
enable_meter = !lutil_meter_open(&meter,
&lutil_meter_text_display,
&lutil_meter_linear_estimator,
st.ms_entries);
}
num = ch_malloc(STACKSIZ * (sizeof(ID) + sizeof(rec)));
stack = (rec *)(num + STACKSIZ);
rc = mdb_txn_begin(mi->mi_dbenv, NULL, 0, &mt);
rc = mdb_cursor_open(mt, mi->mi_dbis[MDB_DN2ID], &mc);
key.mv_size = sizeof(ID);
/* post-order depth-first update */
for(;;) {
size_t dkids;
unsigned char *ptr;
/* visit */
key.mv_data = &id;
stack[depth].id = id;
rc = mdb_cursor_get(mc, &key, &data, MDB_SET);
num[depth] = 1;
/* update superior counts */
for (i=depth-1; i>=0; i--)
num[i] += num[depth];
rc = mdb_cursor_count(mc, &dkids);
if (dkids > 1) {
rc = mdb_cursor_get(mc, &key, &data, MDB_NEXT_DUP);
down:
ptr = data.mv_data + data.mv_size - sizeof(ID);
memcpy(&id, ptr, sizeof(ID));
depth++;
memcpy(stack[depth].rdn, data.mv_data, data.mv_size);
stack[depth].len = data.mv_size;
continue;
}
/* pop: write updated count, advance to next node */
pop:
key.mv_data = &id;
id = stack[depth-1].id;
data.mv_data = stack[depth].rdn;
data.mv_size = stack[depth].len;
rc = mdb_cursor_get(mc, &key, &data, MDB_GET_BOTH);
data.mv_data = stack[depth].rdn;
ptr = data.mv_data + data.mv_size;
memcpy(ptr, &num[depth], sizeof(ID));
data.mv_size += sizeof(ID);
rc = mdb_cursor_del(mc, 0);
rc = mdb_cursor_put(mc, &key, &data, 0);
count++;
if (enable_meter)
lutil_meter_update(&meter, count, 0);
#if 0
{
int len;
ptr = data.mv_data;
len = (ptr[0] & 0x7f) << 8 | ptr[1];
printf("ID: %zu, %zu, %.*s\n", stack[depth].id, num[depth], len, ptr+2);
}
#endif
writes++;
if (writes == 1000) {
mdb_cursor_close(mc);
rc = mdb_txn_commit(mt);
rc = mdb_txn_begin(mi->mi_dbenv, NULL, 0, &mt);
rc = mdb_cursor_open(mt, mi->mi_dbis[MDB_DN2ID], &mc);
rc = mdb_cursor_get(mc, &key, &data, MDB_GET_BOTH);
writes = 0;
}
depth--;
if (!depth)
break;
rc = mdb_cursor_get(mc, &key, &data, MDB_NEXT_DUP);
if (rc == 0)
goto down;
goto pop;
}
rc = mdb_txn_commit(mt);
ch_free(num);
if (enable_meter) {
lutil_meter_update(&meter, count, 1);
lutil_meter_close(&meter);
}
return rc;
}