From: Howard Chu Date: Sat, 9 Feb 2013 19:38:42 +0000 (+0000) Subject: Add mdb_dn2id_upgrade X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=2bbee4bb2356961c43d302e99b2d2dedc014135f;p=openldap Add mdb_dn2id_upgrade Check if upgrade is needed in mdb_db_open() Run from tool_reindex. Upgrade must not be interrupted. --- diff --git a/servers/slapd/back-mdb/back-mdb.h b/servers/slapd/back-mdb/back-mdb.h index 63f555521a..ba291dee76 100644 --- a/servers/slapd/back-mdb/back-mdb.h +++ b/servers/slapd/back-mdb/back-mdb.h @@ -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; diff --git a/servers/slapd/back-mdb/init.c b/servers/slapd/back-mdb/init.c index 8833de4089..7ccdd67b8f 100644 --- a/servers/slapd/back-mdb/init.c +++ b/servers/slapd/back-mdb/init.c @@ -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 ); diff --git a/servers/slapd/back-mdb/tools.c b/servers/slapd/back-mdb/tools.c index 2ef6091dad..47691baf2b 100644 --- a/servers/slapd/back-mdb/tools.c +++ b/servers/slapd/back-mdb/tools.c @@ -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 +#include + +#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; +}