Home | History | Annotate | Line # | Download | only in back-mdb
      1  1.3  christos /*	$NetBSD: tools.c,v 1.4 2025/09/05 21:16:28 christos Exp $	*/
      2  1.1      tron 
      3  1.1      tron /* tools.c - tools for slap tools */
      4  1.1      tron /* $OpenLDAP$ */
      5  1.1      tron /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
      6  1.1      tron  *
      7  1.4  christos  * Copyright 2011-2024 The OpenLDAP Foundation.
      8  1.1      tron  * All rights reserved.
      9  1.1      tron  *
     10  1.1      tron  * Redistribution and use in source and binary forms, with or without
     11  1.1      tron  * modification, are permitted only as authorized by the OpenLDAP
     12  1.1      tron  * Public License.
     13  1.1      tron  *
     14  1.1      tron  * A copy of this license is available in the file LICENSE in the
     15  1.1      tron  * top-level directory of the distribution or, alternatively, at
     16  1.1      tron  * <http://www.OpenLDAP.org/license.html>.
     17  1.1      tron  */
     18  1.1      tron 
     19  1.2  christos #include <sys/cdefs.h>
     20  1.3  christos __RCSID("$NetBSD: tools.c,v 1.4 2025/09/05 21:16:28 christos Exp $");
     21  1.2  christos 
     22  1.1      tron #include "portable.h"
     23  1.1      tron 
     24  1.1      tron #include <stdio.h>
     25  1.1      tron #include <ac/string.h>
     26  1.1      tron #include <ac/errno.h>
     27  1.1      tron 
     28  1.1      tron #define AVL_INTERNAL
     29  1.1      tron #include "back-mdb.h"
     30  1.1      tron #include "idl.h"
     31  1.1      tron 
     32  1.1      tron #ifdef MDB_TOOL_IDL_CACHING
     33  1.1      tron static int mdb_tool_idl_flush( BackendDB *be, MDB_txn *txn );
     34  1.1      tron 
     35  1.1      tron #define	IDBLOCK	1024
     36  1.1      tron 
     37  1.1      tron typedef struct mdb_tool_idl_cache_entry {
     38  1.1      tron 	struct mdb_tool_idl_cache_entry *next;
     39  1.1      tron 	ID ids[IDBLOCK];
     40  1.1      tron } mdb_tool_idl_cache_entry;
     41  1.1      tron 
     42  1.1      tron typedef struct mdb_tool_idl_cache {
     43  1.1      tron 	struct berval kstr;
     44  1.1      tron 	mdb_tool_idl_cache_entry *head, *tail;
     45  1.1      tron 	ID first, last;
     46  1.1      tron 	int count;
     47  1.1      tron 	short offset;
     48  1.1      tron 	short flags;
     49  1.1      tron } mdb_tool_idl_cache;
     50  1.1      tron #define WAS_FOUND	0x01
     51  1.1      tron #define WAS_RANGE	0x02
     52  1.1      tron 
     53  1.1      tron #define MDB_TOOL_IDL_FLUSH(be, txn)	mdb_tool_idl_flush(be, txn)
     54  1.1      tron #else
     55  1.1      tron #define MDB_TOOL_IDL_FLUSH(be, txn)
     56  1.1      tron #endif /* MDB_TOOL_IDL_CACHING */
     57  1.1      tron 
     58  1.2  christos MDB_txn *mdb_tool_txn = NULL;
     59  1.2  christos 
     60  1.2  christos static MDB_txn *txi = NULL;
     61  1.1      tron static MDB_cursor *cursor = NULL, *idcursor = NULL;
     62  1.1      tron static MDB_cursor *mcp = NULL, *mcd = NULL;
     63  1.1      tron static MDB_val key, data;
     64  1.1      tron static ID previd = NOID;
     65  1.1      tron 
     66  1.4  christos static int reindexing;
     67  1.4  christos 
     68  1.1      tron typedef struct dn_id {
     69  1.1      tron 	ID id;
     70  1.1      tron 	struct berval dn;
     71  1.1      tron } dn_id;
     72  1.1      tron 
     73  1.1      tron #define	HOLE_SIZE	4096
     74  1.1      tron static dn_id hbuf[HOLE_SIZE], *holes = hbuf;
     75  1.1      tron static unsigned nhmax = HOLE_SIZE;
     76  1.1      tron static unsigned nholes;
     77  1.1      tron 
     78  1.1      tron static struct berval	*tool_base;
     79  1.1      tron static int		tool_scope;
     80  1.1      tron static Filter		*tool_filter;
     81  1.1      tron static Entry		*tool_next_entry;
     82  1.1      tron 
     83  1.1      tron static ID mdb_tool_ix_id;
     84  1.3  christos static BackendDB *mdb_tool_ix_be;
     85  1.1      tron static MDB_txn *mdb_tool_ix_txn;
     86  1.1      tron static int mdb_tool_index_tcount, mdb_tool_threads;
     87  1.1      tron static IndexRec *mdb_tool_index_rec;
     88  1.3  christos static AttrIxInfo **mdb_tool_axinfo;
     89  1.1      tron static struct mdb_info *mdb_tool_info;
     90  1.1      tron static ldap_pvt_thread_mutex_t mdb_tool_index_mutex;
     91  1.1      tron static ldap_pvt_thread_cond_t mdb_tool_index_cond_main;
     92  1.1      tron static ldap_pvt_thread_cond_t mdb_tool_index_cond_work;
     93  1.1      tron static void * mdb_tool_index_task( void *ctx, void *ptr );
     94  1.1      tron 
     95  1.1      tron static int	mdb_writes, mdb_writes_per_commit;
     96  1.1      tron 
     97  1.1      tron /* Number of ops per commit in Quick mode.
     98  1.1      tron  * Batching speeds writes overall, but too large a
     99  1.1      tron  * batch will fail with MDB_TXN_FULL.
    100  1.1      tron  */
    101  1.1      tron #ifndef MDB_WRITES_PER_COMMIT
    102  1.1      tron #define MDB_WRITES_PER_COMMIT	500
    103  1.1      tron #endif
    104  1.1      tron 
    105  1.1      tron static int
    106  1.1      tron mdb_tool_entry_get_int( BackendDB *be, ID id, Entry **ep );
    107  1.1      tron 
    108  1.1      tron int mdb_tool_entry_open(
    109  1.1      tron 	BackendDB *be, int mode )
    110  1.1      tron {
    111  1.4  christos 	if ( slapMode & SLAP_TOOL_DRYRUN )
    112  1.4  christos 		return 0;
    113  1.4  christos 
    114  1.1      tron 	/* In Quick mode, commit once per 500 entries */
    115  1.1      tron 	mdb_writes = 0;
    116  1.1      tron 	if ( slapMode & SLAP_TOOL_QUICK )
    117  1.1      tron 		mdb_writes_per_commit = MDB_WRITES_PER_COMMIT;
    118  1.1      tron 	else
    119  1.1      tron 		mdb_writes_per_commit = 1;
    120  1.1      tron 
    121  1.3  christos #ifdef MDB_TOOL_IDL_CACHING			/* threaded indexing has no performance advantage */
    122  1.1      tron 	/* Set up for threaded slapindex */
    123  1.1      tron 	if (( slapMode & (SLAP_TOOL_QUICK|SLAP_TOOL_READONLY)) == SLAP_TOOL_QUICK ) {
    124  1.1      tron 		if ( !mdb_tool_info ) {
    125  1.1      tron 			struct mdb_info *mdb = (struct mdb_info *) be->be_private;
    126  1.1      tron 			ldap_pvt_thread_mutex_init( &mdb_tool_index_mutex );
    127  1.1      tron 			ldap_pvt_thread_cond_init( &mdb_tool_index_cond_main );
    128  1.1      tron 			ldap_pvt_thread_cond_init( &mdb_tool_index_cond_work );
    129  1.1      tron 			if ( mdb->mi_nattrs ) {
    130  1.1      tron 				int i;
    131  1.1      tron 				mdb_tool_threads = slap_tool_thread_max - 1;
    132  1.1      tron 				if ( mdb_tool_threads > 1 ) {
    133  1.1      tron 					mdb_tool_index_rec = ch_calloc( mdb->mi_nattrs, sizeof( IndexRec ));
    134  1.3  christos 					mdb_tool_axinfo = ch_calloc( mdb_tool_threads, sizeof( AttrIxInfo* ) +
    135  1.3  christos 						sizeof( AttrIxInfo ));
    136  1.3  christos 					mdb_tool_axinfo[0] = (AttrIxInfo *)(mdb_tool_axinfo + mdb_tool_threads);
    137  1.3  christos 					for (i=1; i<mdb_tool_threads; i++)
    138  1.3  christos 						mdb_tool_axinfo[i] = mdb_tool_axinfo[i-1]+1;
    139  1.1      tron 					mdb_tool_index_tcount = mdb_tool_threads - 1;
    140  1.3  christos 					mdb_tool_ix_be = be;
    141  1.1      tron 					for (i=1; i<mdb_tool_threads; i++) {
    142  1.1      tron 						int *ptr = ch_malloc( sizeof( int ));
    143  1.1      tron 						*ptr = i;
    144  1.1      tron 						ldap_pvt_thread_pool_submit( &connection_pool,
    145  1.1      tron 							mdb_tool_index_task, ptr );
    146  1.1      tron 					}
    147  1.1      tron 					mdb_tool_info = mdb;
    148  1.1      tron 				}
    149  1.1      tron 			}
    150  1.1      tron 		}
    151  1.1      tron 	}
    152  1.3  christos #endif
    153  1.1      tron 
    154  1.1      tron 	return 0;
    155  1.1      tron }
    156  1.1      tron 
    157  1.1      tron int mdb_tool_entry_close(
    158  1.1      tron 	BackendDB *be )
    159  1.1      tron {
    160  1.4  christos 	if ( slapMode & SLAP_TOOL_DRYRUN )
    161  1.4  christos 		return 0;
    162  1.4  christos 
    163  1.3  christos #ifdef MDB_TOOL_IDL_CACHING
    164  1.1      tron 	if ( mdb_tool_info ) {
    165  1.3  christos 		int i;
    166  1.1      tron 		slapd_shutdown = 1;
    167  1.1      tron 		ldap_pvt_thread_mutex_lock( &mdb_tool_index_mutex );
    168  1.1      tron 
    169  1.1      tron 		/* There might still be some threads starting */
    170  1.1      tron 		while ( mdb_tool_index_tcount > 0 ) {
    171  1.1      tron 			ldap_pvt_thread_cond_wait( &mdb_tool_index_cond_main,
    172  1.1      tron 					&mdb_tool_index_mutex );
    173  1.1      tron 		}
    174  1.1      tron 
    175  1.1      tron 		mdb_tool_index_tcount = mdb_tool_threads - 1;
    176  1.1      tron 		ldap_pvt_thread_cond_broadcast( &mdb_tool_index_cond_work );
    177  1.1      tron 
    178  1.1      tron 		/* Make sure all threads are stopped */
    179  1.1      tron 		while ( mdb_tool_index_tcount > 0 ) {
    180  1.1      tron 			ldap_pvt_thread_cond_wait( &mdb_tool_index_cond_main,
    181  1.1      tron 				&mdb_tool_index_mutex );
    182  1.1      tron 		}
    183  1.1      tron 		ldap_pvt_thread_mutex_unlock( &mdb_tool_index_mutex );
    184  1.1      tron 
    185  1.1      tron 		mdb_tool_info = NULL;
    186  1.1      tron 		slapd_shutdown = 0;
    187  1.1      tron 		ch_free( mdb_tool_index_rec );
    188  1.1      tron 		mdb_tool_index_tcount = mdb_tool_threads - 1;
    189  1.3  christos 		if (mdb_tool_txn)
    190  1.3  christos 			MDB_TOOL_IDL_FLUSH( be, mdb_tool_txn );
    191  1.3  christos 		for (i=0; i<mdb_tool_threads; i++) {
    192  1.3  christos 			mdb_tool_idl_cache *ic;
    193  1.3  christos 			mdb_tool_idl_cache_entry *ice;
    194  1.3  christos 			while ((ic = mdb_tool_axinfo[i]->ai_clist)) {
    195  1.3  christos 				mdb_tool_axinfo[i]->ai_clist = ic->head;
    196  1.3  christos 				free(ic);
    197  1.3  christos 			}
    198  1.3  christos 			while ((ice = mdb_tool_axinfo[i]->ai_flist)) {
    199  1.3  christos 				mdb_tool_axinfo[i]->ai_flist = ice->next;
    200  1.3  christos 				free(ice);
    201  1.3  christos 			}
    202  1.3  christos 		}
    203  1.1      tron 	}
    204  1.3  christos #endif
    205  1.1      tron 
    206  1.1      tron 	if( idcursor ) {
    207  1.1      tron 		mdb_cursor_close( idcursor );
    208  1.1      tron 		idcursor = NULL;
    209  1.1      tron 	}
    210  1.1      tron 	if( cursor ) {
    211  1.1      tron 		mdb_cursor_close( cursor );
    212  1.1      tron 		cursor = NULL;
    213  1.1      tron 	}
    214  1.2  christos 	{
    215  1.2  christos 		struct mdb_info *mdb = be->be_private;
    216  1.2  christos 		if ( mdb ) {
    217  1.2  christos 			int i;
    218  1.2  christos 			for (i=0; i<mdb->mi_nattrs; i++)
    219  1.2  christos 				mdb->mi_attrs[i]->ai_cursor = NULL;
    220  1.2  christos 		}
    221  1.2  christos 	}
    222  1.2  christos 	if( mdb_tool_txn ) {
    223  1.1      tron 		int rc;
    224  1.2  christos 		if (( rc = mdb_txn_commit( mdb_tool_txn ))) {
    225  1.1      tron 			Debug( LDAP_DEBUG_ANY,
    226  1.1      tron 				LDAP_XSTRING(mdb_tool_entry_close) ": database %s: "
    227  1.1      tron 				"txn_commit failed: %s (%d)\n",
    228  1.1      tron 				be->be_suffix[0].bv_val, mdb_strerror(rc), rc );
    229  1.1      tron 			return -1;
    230  1.1      tron 		}
    231  1.2  christos 		mdb_tool_txn = NULL;
    232  1.2  christos 	}
    233  1.4  christos 	if( reindexing ) {
    234  1.4  christos 		struct mdb_info *mdb = be->be_private;
    235  1.4  christos 		if ( !txi ) {
    236  1.4  christos 			int rc = mdb_txn_begin( mdb->mi_dbenv, NULL, 0, &txi );
    237  1.4  christos 			if( rc != 0 ) {
    238  1.4  christos 				Debug( LDAP_DEBUG_ANY,
    239  1.4  christos 					"=> " LDAP_XSTRING(mdb_tool_entry_close) ": database %s: "
    240  1.4  christos 					"txn_begin failed: %s (%d)\n",
    241  1.4  christos 					be->be_suffix[0].bv_val, mdb_strerror(rc), rc );
    242  1.4  christos 				return -1;
    243  1.4  christos 			}
    244  1.4  christos 		}
    245  1.4  christos 		mdb_drop( txi, mdb->mi_idxckp, 0 );
    246  1.4  christos 	}
    247  1.2  christos 	if( txi ) {
    248  1.2  christos 		int rc;
    249  1.2  christos 		if (( rc = mdb_txn_commit( txi ))) {
    250  1.2  christos 			Debug( LDAP_DEBUG_ANY,
    251  1.2  christos 				LDAP_XSTRING(mdb_tool_entry_close) ": database %s: "
    252  1.2  christos 				"txn_commit failed: %s (%d)\n",
    253  1.2  christos 				be->be_suffix[0].bv_val, mdb_strerror(rc), rc );
    254  1.2  christos 			return -1;
    255  1.2  christos 		}
    256  1.2  christos 		txi = NULL;
    257  1.1      tron 	}
    258  1.1      tron 
    259  1.1      tron 	if( nholes ) {
    260  1.1      tron 		unsigned i;
    261  1.1      tron 		fprintf( stderr, "Error, entries missing!\n");
    262  1.1      tron 		for (i=0; i<nholes; i++) {
    263  1.1      tron 			fprintf(stderr, "  entry %ld: %s\n",
    264  1.1      tron 				holes[i].id, holes[i].dn.bv_val);
    265  1.1      tron 		}
    266  1.1      tron 		nholes = 0;
    267  1.1      tron 		return -1;
    268  1.1      tron 	}
    269  1.1      tron 
    270  1.1      tron 	return 0;
    271  1.1      tron }
    272  1.1      tron 
    273  1.1      tron ID
    274  1.1      tron mdb_tool_entry_first_x(
    275  1.1      tron 	BackendDB *be,
    276  1.1      tron 	struct berval *base,
    277  1.1      tron 	int scope,
    278  1.1      tron 	Filter *f )
    279  1.1      tron {
    280  1.1      tron 	tool_base = base;
    281  1.1      tron 	tool_scope = scope;
    282  1.1      tron 	tool_filter = f;
    283  1.1      tron 
    284  1.1      tron 	return mdb_tool_entry_next( be );
    285  1.1      tron }
    286  1.1      tron 
    287  1.1      tron ID mdb_tool_entry_next(
    288  1.1      tron 	BackendDB *be )
    289  1.1      tron {
    290  1.1      tron 	int rc;
    291  1.1      tron 	ID id;
    292  1.1      tron 	struct mdb_info *mdb;
    293  1.1      tron 
    294  1.1      tron 	assert( be != NULL );
    295  1.1      tron 	assert( slapMode & SLAP_TOOL_MODE );
    296  1.1      tron 
    297  1.1      tron 	mdb = (struct mdb_info *) be->be_private;
    298  1.1      tron 	assert( mdb != NULL );
    299  1.1      tron 
    300  1.2  christos 	if ( !mdb_tool_txn ) {
    301  1.2  christos 		rc = mdb_txn_begin( mdb->mi_dbenv, NULL, MDB_RDONLY, &mdb_tool_txn );
    302  1.1      tron 		if ( rc )
    303  1.1      tron 			return NOID;
    304  1.2  christos 		rc = mdb_cursor_open( mdb_tool_txn, mdb->mi_id2entry, &cursor );
    305  1.1      tron 		if ( rc ) {
    306  1.2  christos 			mdb_txn_abort( mdb_tool_txn );
    307  1.1      tron 			return NOID;
    308  1.1      tron 		}
    309  1.1      tron 	}
    310  1.1      tron 
    311  1.1      tron next:;
    312  1.1      tron 	rc = mdb_cursor_get( cursor, &key, &data, MDB_NEXT );
    313  1.1      tron 
    314  1.1      tron 	if( rc ) {
    315  1.1      tron 		return NOID;
    316  1.1      tron 	}
    317  1.1      tron 
    318  1.1      tron 	previd = *(ID *)key.mv_data;
    319  1.1      tron 	id = previd;
    320  1.1      tron 
    321  1.1      tron 	if ( !data.mv_size )
    322  1.1      tron 		goto next;
    323  1.1      tron 
    324  1.1      tron 	if ( tool_filter || tool_base ) {
    325  1.1      tron 		static Operation op = {0};
    326  1.1      tron 		static Opheader ohdr = {0};
    327  1.1      tron 
    328  1.1      tron 		op.o_hdr = &ohdr;
    329  1.1      tron 		op.o_bd = be;
    330  1.1      tron 		op.o_tmpmemctx = NULL;
    331  1.1      tron 		op.o_tmpmfuncs = &ch_mfuncs;
    332  1.1      tron 
    333  1.1      tron 		if ( tool_next_entry ) {
    334  1.1      tron 			mdb_entry_release( &op, tool_next_entry, 0 );
    335  1.1      tron 			tool_next_entry = NULL;
    336  1.1      tron 		}
    337  1.1      tron 
    338  1.1      tron 		rc = mdb_tool_entry_get_int( be, id, &tool_next_entry );
    339  1.1      tron 		if ( rc == LDAP_NO_SUCH_OBJECT ) {
    340  1.1      tron 			goto next;
    341  1.1      tron 		}
    342  1.1      tron 
    343  1.1      tron 		assert( tool_next_entry != NULL );
    344  1.1      tron 
    345  1.1      tron 		if ( tool_filter && test_filter( NULL, tool_next_entry, tool_filter ) != LDAP_COMPARE_TRUE )
    346  1.1      tron 		{
    347  1.1      tron 			mdb_entry_release( &op, tool_next_entry, 0 );
    348  1.1      tron 			tool_next_entry = NULL;
    349  1.1      tron 			goto next;
    350  1.1      tron 		}
    351  1.1      tron 	}
    352  1.1      tron 
    353  1.1      tron 	return id;
    354  1.1      tron }
    355  1.1      tron 
    356  1.1      tron ID mdb_tool_dn2id_get(
    357  1.1      tron 	Backend *be,
    358  1.1      tron 	struct berval *dn
    359  1.1      tron )
    360  1.1      tron {
    361  1.1      tron 	struct mdb_info *mdb;
    362  1.1      tron 	Operation op = {0};
    363  1.1      tron 	Opheader ohdr = {0};
    364  1.1      tron 	ID id;
    365  1.1      tron 	int rc;
    366  1.1      tron 
    367  1.1      tron 	if ( BER_BVISEMPTY(dn) )
    368  1.1      tron 		return 0;
    369  1.1      tron 
    370  1.1      tron 	mdb = (struct mdb_info *) be->be_private;
    371  1.1      tron 
    372  1.2  christos 	if ( !mdb_tool_txn ) {
    373  1.1      tron 		rc = mdb_txn_begin( mdb->mi_dbenv, NULL, (slapMode & SLAP_TOOL_READONLY) != 0 ?
    374  1.2  christos 			MDB_RDONLY : 0, &mdb_tool_txn );
    375  1.1      tron 		if ( rc )
    376  1.1      tron 			return NOID;
    377  1.1      tron 	}
    378  1.1      tron 
    379  1.1      tron 	op.o_hdr = &ohdr;
    380  1.1      tron 	op.o_bd = be;
    381  1.1      tron 	op.o_tmpmemctx = NULL;
    382  1.1      tron 	op.o_tmpmfuncs = &ch_mfuncs;
    383  1.1      tron 
    384  1.2  christos 	rc = mdb_dn2id( &op, mdb_tool_txn, NULL, dn, &id, NULL, NULL, NULL );
    385  1.1      tron 	if ( rc == MDB_NOTFOUND )
    386  1.1      tron 		return NOID;
    387  1.1      tron 
    388  1.1      tron 	return id;
    389  1.1      tron }
    390  1.1      tron 
    391  1.1      tron static int
    392  1.1      tron mdb_tool_entry_get_int( BackendDB *be, ID id, Entry **ep )
    393  1.1      tron {
    394  1.1      tron 	Operation op = {0};
    395  1.1      tron 	Opheader ohdr = {0};
    396  1.1      tron 
    397  1.1      tron 	Entry *e = NULL;
    398  1.1      tron 	struct berval dn = BER_BVNULL, ndn = BER_BVNULL;
    399  1.1      tron 	int rc;
    400  1.1      tron 
    401  1.1      tron 	assert( be != NULL );
    402  1.1      tron 	assert( slapMode & SLAP_TOOL_MODE );
    403  1.1      tron 
    404  1.1      tron 	if ( ( tool_filter || tool_base ) && id == previd && tool_next_entry != NULL ) {
    405  1.1      tron 		*ep = tool_next_entry;
    406  1.1      tron 		tool_next_entry = NULL;
    407  1.1      tron 		return LDAP_SUCCESS;
    408  1.1      tron 	}
    409  1.1      tron 
    410  1.1      tron 	if ( id != previd ) {
    411  1.1      tron 		key.mv_size = sizeof(ID);
    412  1.1      tron 		key.mv_data = &id;
    413  1.1      tron 		rc = mdb_cursor_get( cursor, &key, &data, MDB_SET );
    414  1.1      tron 		if ( rc ) {
    415  1.1      tron 			rc = LDAP_OTHER;
    416  1.1      tron 			goto done;
    417  1.1      tron 		}
    418  1.1      tron 	}
    419  1.1      tron 	if ( !data.mv_size ) {
    420  1.1      tron 		rc = LDAP_NO_SUCH_OBJECT;
    421  1.1      tron 		goto done;
    422  1.1      tron 	}
    423  1.1      tron 
    424  1.1      tron 	op.o_hdr = &ohdr;
    425  1.1      tron 	op.o_bd = be;
    426  1.1      tron 	op.o_tmpmemctx = NULL;
    427  1.1      tron 	op.o_tmpmfuncs = &ch_mfuncs;
    428  1.1      tron 	if ( slapMode & SLAP_TOOL_READONLY ) {
    429  1.2  christos 		rc = mdb_id2name( &op, mdb_tool_txn, &idcursor, id, &dn, &ndn );
    430  1.1      tron 		if ( rc  ) {
    431  1.1      tron 			rc = LDAP_OTHER;
    432  1.1      tron 			goto done;
    433  1.1      tron 		}
    434  1.1      tron 		if ( tool_base != NULL ) {
    435  1.1      tron 			if ( !dnIsSuffixScope( &ndn, tool_base, tool_scope ) ) {
    436  1.1      tron 				ch_free( dn.bv_val );
    437  1.1      tron 				ch_free( ndn.bv_val );
    438  1.1      tron 				rc = LDAP_NO_SUCH_OBJECT;
    439  1.1      tron 				goto done;
    440  1.1      tron 			}
    441  1.1      tron 		}
    442  1.1      tron 	}
    443  1.3  christos 	rc = mdb_entry_decode( &op, mdb_tool_txn, &data, id, &e );
    444  1.1      tron 	e->e_id = id;
    445  1.1      tron 	if ( !BER_BVISNULL( &dn )) {
    446  1.1      tron 		e->e_name = dn;
    447  1.1      tron 		e->e_nname = ndn;
    448  1.1      tron 	} else {
    449  1.4  christos 		e->e_name.bv_len = 0;
    450  1.1      tron 		e->e_name.bv_val = NULL;
    451  1.4  christos 		e->e_nname.bv_len = 0;
    452  1.1      tron 		e->e_nname.bv_val = NULL;
    453  1.1      tron 	}
    454  1.1      tron 
    455  1.1      tron done:
    456  1.1      tron 	if ( e != NULL ) {
    457  1.1      tron 		*ep = e;
    458  1.1      tron 	}
    459  1.1      tron 
    460  1.1      tron 	return rc;
    461  1.1      tron }
    462  1.1      tron 
    463  1.1      tron Entry*
    464  1.1      tron mdb_tool_entry_get( BackendDB *be, ID id )
    465  1.1      tron {
    466  1.1      tron 	Entry *e = NULL;
    467  1.1      tron 	int rc;
    468  1.1      tron 
    469  1.2  christos 	if ( !mdb_tool_txn ) {
    470  1.1      tron 		struct mdb_info *mdb = (struct mdb_info *) be->be_private;
    471  1.1      tron 		rc = mdb_txn_begin( mdb->mi_dbenv, NULL,
    472  1.2  christos 			(slapMode & SLAP_TOOL_READONLY) ? MDB_RDONLY : 0, &mdb_tool_txn );
    473  1.1      tron 		if ( rc )
    474  1.1      tron 			return NULL;
    475  1.1      tron 	}
    476  1.1      tron 	if ( !cursor ) {
    477  1.1      tron 		struct mdb_info *mdb = (struct mdb_info *) be->be_private;
    478  1.2  christos 		rc = mdb_cursor_open( mdb_tool_txn, mdb->mi_id2entry, &cursor );
    479  1.1      tron 		if ( rc ) {
    480  1.2  christos 			mdb_txn_abort( mdb_tool_txn );
    481  1.2  christos 			mdb_tool_txn = NULL;
    482  1.1      tron 			return NULL;
    483  1.1      tron 		}
    484  1.1      tron 	}
    485  1.1      tron 	(void)mdb_tool_entry_get_int( be, id, &e );
    486  1.1      tron 	return e;
    487  1.1      tron }
    488  1.1      tron 
    489  1.1      tron static int mdb_tool_next_id(
    490  1.1      tron 	Operation *op,
    491  1.1      tron 	MDB_txn *tid,
    492  1.1      tron 	Entry *e,
    493  1.1      tron 	struct berval *text,
    494  1.1      tron 	int hole )
    495  1.1      tron {
    496  1.1      tron 	struct berval dn = e->e_name;
    497  1.1      tron 	struct berval ndn = e->e_nname;
    498  1.1      tron 	struct berval pdn, npdn, nmatched;
    499  1.1      tron 	ID id, pid = 0;
    500  1.1      tron 	int rc;
    501  1.1      tron 
    502  1.1      tron 	if (ndn.bv_len == 0) {
    503  1.1      tron 		e->e_id = 0;
    504  1.1      tron 		return 0;
    505  1.1      tron 	}
    506  1.1      tron 
    507  1.1      tron 	rc = mdb_dn2id( op, tid, mcp, &ndn, &id, NULL, NULL, &nmatched );
    508  1.1      tron 	if ( rc == MDB_NOTFOUND ) {
    509  1.1      tron 		if ( !be_issuffix( op->o_bd, &ndn ) ) {
    510  1.1      tron 			ID eid = e->e_id;
    511  1.1      tron 			dnParent( &ndn, &npdn );
    512  1.1      tron 			if ( nmatched.bv_len != npdn.bv_len ) {
    513  1.1      tron 				dnParent( &dn, &pdn );
    514  1.1      tron 				e->e_name = pdn;
    515  1.1      tron 				e->e_nname = npdn;
    516  1.1      tron 				rc = mdb_tool_next_id( op, tid, e, text, 1 );
    517  1.1      tron 				e->e_name = dn;
    518  1.1      tron 				e->e_nname = ndn;
    519  1.1      tron 				if ( rc ) {
    520  1.1      tron 					return rc;
    521  1.1      tron 				}
    522  1.1      tron 				/* If parent didn't exist, it was created just now
    523  1.1      tron 				 * and its ID is now in e->e_id. Make sure the current
    524  1.1      tron 				 * entry gets added under the new parent ID.
    525  1.1      tron 				 */
    526  1.1      tron 				if ( eid != e->e_id ) {
    527  1.1      tron 					pid = e->e_id;
    528  1.1      tron 				}
    529  1.1      tron 			} else {
    530  1.1      tron 				pid = id;
    531  1.1      tron 			}
    532  1.1      tron 		}
    533  1.1      tron 		rc = mdb_next_id( op->o_bd, idcursor, &e->e_id );
    534  1.1      tron 		if ( rc ) {
    535  1.1      tron 			snprintf( text->bv_val, text->bv_len,
    536  1.1      tron 				"next_id failed: %s (%d)",
    537  1.1      tron 				mdb_strerror(rc), rc );
    538  1.1      tron 		Debug( LDAP_DEBUG_ANY,
    539  1.3  christos 			"=> mdb_tool_next_id: %s\n", text->bv_val );
    540  1.1      tron 			return rc;
    541  1.1      tron 		}
    542  1.1      tron 		rc = mdb_dn2id_add( op, mcp, mcd, pid, 1, 1, e );
    543  1.1      tron 		if ( rc ) {
    544  1.1      tron 			snprintf( text->bv_val, text->bv_len,
    545  1.1      tron 				"dn2id_add failed: %s (%d)",
    546  1.1      tron 				mdb_strerror(rc), rc );
    547  1.1      tron 			Debug( LDAP_DEBUG_ANY,
    548  1.3  christos 				"=> mdb_tool_next_id: %s\n", text->bv_val );
    549  1.1      tron 		} else if ( hole ) {
    550  1.1      tron 			MDB_val key, data;
    551  1.1      tron 			if ( nholes == nhmax - 1 ) {
    552  1.1      tron 				if ( holes == hbuf ) {
    553  1.1      tron 					holes = ch_malloc( nhmax * sizeof(dn_id) * 2 );
    554  1.1      tron 					AC_MEMCPY( holes, hbuf, sizeof(hbuf) );
    555  1.1      tron 				} else {
    556  1.1      tron 					holes = ch_realloc( holes, nhmax * sizeof(dn_id) * 2 );
    557  1.1      tron 				}
    558  1.1      tron 				nhmax *= 2;
    559  1.1      tron 			}
    560  1.1      tron 			ber_dupbv( &holes[nholes].dn, &ndn );
    561  1.1      tron 			holes[nholes++].id = e->e_id;
    562  1.1      tron 			key.mv_size = sizeof(ID);
    563  1.1      tron 			key.mv_data = &e->e_id;
    564  1.1      tron 			data.mv_size = 0;
    565  1.1      tron 			data.mv_data = NULL;
    566  1.1      tron 			rc = mdb_cursor_put( idcursor, &key, &data, MDB_NOOVERWRITE );
    567  1.1      tron 			if ( rc == MDB_KEYEXIST )
    568  1.1      tron 				rc = 0;
    569  1.1      tron 			if ( rc ) {
    570  1.1      tron 				snprintf( text->bv_val, text->bv_len,
    571  1.1      tron 					"dummy id2entry add failed: %s (%d)",
    572  1.1      tron 					mdb_strerror(rc), rc );
    573  1.1      tron 				Debug( LDAP_DEBUG_ANY,
    574  1.3  christos 					"=> mdb_tool_next_id: %s\n", text->bv_val );
    575  1.1      tron 			}
    576  1.1      tron 		}
    577  1.1      tron 	} else if ( !hole ) {
    578  1.1      tron 		unsigned i, j;
    579  1.1      tron 
    580  1.1      tron 		e->e_id = id;
    581  1.1      tron 
    582  1.1      tron 		for ( i=0; i<nholes; i++) {
    583  1.1      tron 			if ( holes[i].id == e->e_id ) {
    584  1.1      tron 				free(holes[i].dn.bv_val);
    585  1.1      tron 				for (j=i;j<nholes;j++) holes[j] = holes[j+1];
    586  1.1      tron 				holes[j].id = 0;
    587  1.1      tron 				nholes--;
    588  1.1      tron 				break;
    589  1.1      tron 			} else if ( holes[i].id > e->e_id ) {
    590  1.1      tron 				break;
    591  1.1      tron 			}
    592  1.1      tron 		}
    593  1.1      tron 	}
    594  1.1      tron 	return rc;
    595  1.1      tron }
    596  1.1      tron 
    597  1.1      tron static int
    598  1.1      tron mdb_tool_index_add(
    599  1.1      tron 	Operation *op,
    600  1.1      tron 	MDB_txn *txn,
    601  1.1      tron 	Entry *e )
    602  1.1      tron {
    603  1.1      tron 	struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
    604  1.1      tron 
    605  1.1      tron 	if ( !mdb->mi_nattrs )
    606  1.1      tron 		return 0;
    607  1.1      tron 
    608  1.1      tron 	if ( mdb_tool_threads > 1 ) {
    609  1.1      tron 		IndexRec *ir;
    610  1.1      tron 		int i, rc;
    611  1.1      tron 		Attribute *a;
    612  1.1      tron 
    613  1.1      tron 		ir = mdb_tool_index_rec;
    614  1.1      tron 		for (i=0; i<mdb->mi_nattrs; i++)
    615  1.1      tron 			ir[i].ir_attrs = NULL;
    616  1.1      tron 
    617  1.1      tron 		for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
    618  1.1      tron 			rc = mdb_index_recset( mdb, a, a->a_desc->ad_type,
    619  1.1      tron 				&a->a_desc->ad_tags, ir );
    620  1.1      tron 			if ( rc )
    621  1.1      tron 				return rc;
    622  1.1      tron 		}
    623  1.1      tron 		for (i=0; i<mdb->mi_nattrs; i++) {
    624  1.1      tron 			if ( !ir[i].ir_ai )
    625  1.1      tron 				break;
    626  1.1      tron 			rc = mdb_cursor_open( txn, ir[i].ir_ai->ai_dbi,
    627  1.1      tron 				 &ir[i].ir_ai->ai_cursor );
    628  1.1      tron 			if ( rc )
    629  1.1      tron 				return rc;
    630  1.1      tron 		}
    631  1.1      tron 		mdb_tool_ix_id = e->e_id;
    632  1.1      tron 		mdb_tool_ix_txn = txn;
    633  1.1      tron 		ldap_pvt_thread_mutex_lock( &mdb_tool_index_mutex );
    634  1.1      tron 		/* Wait for all threads to be ready */
    635  1.1      tron 		while ( mdb_tool_index_tcount ) {
    636  1.1      tron 			ldap_pvt_thread_cond_wait( &mdb_tool_index_cond_main,
    637  1.1      tron 				&mdb_tool_index_mutex );
    638  1.1      tron 		}
    639  1.1      tron 
    640  1.1      tron 		for ( i=1; i<mdb_tool_threads; i++ )
    641  1.1      tron 			mdb_tool_index_rec[i].ir_i = LDAP_BUSY;
    642  1.1      tron 		mdb_tool_index_tcount = mdb_tool_threads - 1;
    643  1.3  christos 		ldap_pvt_thread_cond_broadcast( &mdb_tool_index_cond_work );
    644  1.1      tron 		ldap_pvt_thread_mutex_unlock( &mdb_tool_index_mutex );
    645  1.1      tron 
    646  1.3  christos 		return mdb_index_recrun( op, txn, mdb, ir, e->e_id, 0 );
    647  1.1      tron 	} else
    648  1.1      tron 	{
    649  1.1      tron 		return mdb_index_entry_add( op, txn, e );
    650  1.1      tron 	}
    651  1.1      tron }
    652  1.1      tron 
    653  1.3  christos static int
    654  1.3  christos mdb_tool_index_finish()
    655  1.3  christos {
    656  1.3  christos 	int i, rc = 0;
    657  1.3  christos 	ldap_pvt_thread_mutex_lock( &mdb_tool_index_mutex );
    658  1.3  christos 	for ( i=1; i<mdb_tool_threads; i++ ) {
    659  1.3  christos 		if ( mdb_tool_index_rec[i].ir_i == LDAP_BUSY ) {
    660  1.3  christos 			ldap_pvt_thread_cond_wait( &mdb_tool_index_cond_main,
    661  1.3  christos 				&mdb_tool_index_mutex );
    662  1.3  christos 			i--;
    663  1.3  christos 			continue;
    664  1.3  christos 		}
    665  1.3  christos 		if ( mdb_tool_index_rec[i].ir_i ) {
    666  1.3  christos 			rc = mdb_tool_index_rec[i].ir_i;
    667  1.3  christos 			break;
    668  1.3  christos 		}
    669  1.3  christos 	}
    670  1.3  christos 	ldap_pvt_thread_mutex_unlock( &mdb_tool_index_mutex );
    671  1.3  christos 	return rc;
    672  1.3  christos }
    673  1.3  christos 
    674  1.1      tron ID mdb_tool_entry_put(
    675  1.1      tron 	BackendDB *be,
    676  1.1      tron 	Entry *e,
    677  1.1      tron 	struct berval *text )
    678  1.1      tron {
    679  1.1      tron 	int rc;
    680  1.1      tron 	struct mdb_info *mdb;
    681  1.1      tron 	Operation op = {0};
    682  1.1      tron 	Opheader ohdr = {0};
    683  1.1      tron 
    684  1.4  christos 	if ( slapMode & SLAP_TOOL_DRYRUN )
    685  1.4  christos 		return 0;
    686  1.4  christos 
    687  1.1      tron 	assert( be != NULL );
    688  1.1      tron 	assert( slapMode & SLAP_TOOL_MODE );
    689  1.1      tron 
    690  1.1      tron 	assert( text != NULL );
    691  1.1      tron 	assert( text->bv_val != NULL );
    692  1.1      tron 	assert( text->bv_val[0] == '\0' );	/* overconservative? */
    693  1.1      tron 
    694  1.1      tron 	Debug( LDAP_DEBUG_TRACE, "=> " LDAP_XSTRING(mdb_tool_entry_put)
    695  1.3  christos 		"( %ld, \"%s\" )\n", (long) e->e_id, e->e_dn );
    696  1.1      tron 
    697  1.1      tron 	mdb = (struct mdb_info *) be->be_private;
    698  1.1      tron 
    699  1.2  christos 	if ( !mdb_tool_txn ) {
    700  1.2  christos 		rc = mdb_txn_begin( mdb->mi_dbenv, NULL, 0, &mdb_tool_txn );
    701  1.1      tron 		if( rc != 0 ) {
    702  1.1      tron 			snprintf( text->bv_val, text->bv_len,
    703  1.1      tron 				"txn_begin failed: %s (%d)",
    704  1.1      tron 				mdb_strerror(rc), rc );
    705  1.1      tron 			Debug( LDAP_DEBUG_ANY,
    706  1.1      tron 				"=> " LDAP_XSTRING(mdb_tool_entry_put) ": %s\n",
    707  1.3  christos 				 text->bv_val );
    708  1.1      tron 			return NOID;
    709  1.1      tron 		}
    710  1.3  christos 	}
    711  1.3  christos 	if ( !idcursor ) {
    712  1.2  christos 		rc = mdb_cursor_open( mdb_tool_txn, mdb->mi_id2entry, &idcursor );
    713  1.1      tron 		if( rc != 0 ) {
    714  1.1      tron 			snprintf( text->bv_val, text->bv_len,
    715  1.1      tron 				"cursor_open failed: %s (%d)",
    716  1.1      tron 				mdb_strerror(rc), rc );
    717  1.1      tron 			Debug( LDAP_DEBUG_ANY,
    718  1.1      tron 				"=> " LDAP_XSTRING(mdb_tool_entry_put) ": %s\n",
    719  1.3  christos 				 text->bv_val );
    720  1.1      tron 			return NOID;
    721  1.1      tron 		}
    722  1.1      tron 		if ( !mdb->mi_nextid ) {
    723  1.1      tron 			ID dummy;
    724  1.1      tron 			mdb_next_id( be, idcursor, &dummy );
    725  1.1      tron 		}
    726  1.2  christos 		rc = mdb_cursor_open( mdb_tool_txn, mdb->mi_dn2id, &mcp );
    727  1.1      tron 		if( rc != 0 ) {
    728  1.1      tron 			snprintf( text->bv_val, text->bv_len,
    729  1.1      tron 				"cursor_open failed: %s (%d)",
    730  1.1      tron 				mdb_strerror(rc), rc );
    731  1.1      tron 			Debug( LDAP_DEBUG_ANY,
    732  1.1      tron 				"=> " LDAP_XSTRING(mdb_tool_entry_put) ": %s\n",
    733  1.3  christos 				 text->bv_val );
    734  1.1      tron 			return NOID;
    735  1.1      tron 		}
    736  1.2  christos 		rc = mdb_cursor_open( mdb_tool_txn, mdb->mi_dn2id, &mcd );
    737  1.1      tron 		if( rc != 0 ) {
    738  1.1      tron 			snprintf( text->bv_val, text->bv_len,
    739  1.1      tron 				"cursor_open failed: %s (%d)",
    740  1.1      tron 				mdb_strerror(rc), rc );
    741  1.1      tron 			Debug( LDAP_DEBUG_ANY,
    742  1.1      tron 				"=> " LDAP_XSTRING(mdb_tool_entry_put) ": %s\n",
    743  1.3  christos 				 text->bv_val );
    744  1.1      tron 			return NOID;
    745  1.1      tron 		}
    746  1.1      tron 	}
    747  1.1      tron 
    748  1.1      tron 	op.o_hdr = &ohdr;
    749  1.1      tron 	op.o_bd = be;
    750  1.1      tron 	op.o_tmpmemctx = NULL;
    751  1.1      tron 	op.o_tmpmfuncs = &ch_mfuncs;
    752  1.1      tron 
    753  1.1      tron 	/* add dn2id indices */
    754  1.2  christos 	rc = mdb_tool_next_id( &op, mdb_tool_txn, e, text, 0 );
    755  1.1      tron 	if( rc != 0 ) {
    756  1.1      tron 		goto done;
    757  1.1      tron 	}
    758  1.1      tron 
    759  1.3  christos 	if ( mdb_tool_threads > 1 ) {
    760  1.3  christos 		LDAP_SLIST_INSERT_HEAD( &op.o_extra, &mdb_tool_axinfo[0]->ai_oe, oe_next );
    761  1.3  christos 	}
    762  1.2  christos 	rc = mdb_tool_index_add( &op, mdb_tool_txn, e );
    763  1.1      tron 	if( rc != 0 ) {
    764  1.1      tron 		snprintf( text->bv_val, text->bv_len,
    765  1.1      tron 				"index_entry_add failed: err=%d", rc );
    766  1.1      tron 		Debug( LDAP_DEBUG_ANY,
    767  1.1      tron 			"=> " LDAP_XSTRING(mdb_tool_entry_put) ": %s\n",
    768  1.3  christos 			text->bv_val );
    769  1.1      tron 		goto done;
    770  1.1      tron 	}
    771  1.1      tron 
    772  1.1      tron 
    773  1.1      tron 	/* id2entry index */
    774  1.2  christos 	rc = mdb_id2entry_add( &op, mdb_tool_txn, idcursor, e );
    775  1.1      tron 	if( rc != 0 ) {
    776  1.1      tron 		snprintf( text->bv_val, text->bv_len,
    777  1.1      tron 				"id2entry_add failed: err=%d", rc );
    778  1.1      tron 		Debug( LDAP_DEBUG_ANY,
    779  1.1      tron 			"=> " LDAP_XSTRING(mdb_tool_entry_put) ": %s\n",
    780  1.3  christos 			text->bv_val );
    781  1.1      tron 		goto done;
    782  1.1      tron 	}
    783  1.1      tron 
    784  1.3  christos 	if( mdb->mi_nattrs && mdb_tool_threads > 1 )
    785  1.3  christos 		rc = mdb_tool_index_finish();
    786  1.3  christos 
    787  1.1      tron done:
    788  1.1      tron 	if( rc == 0 ) {
    789  1.1      tron 		mdb_writes++;
    790  1.1      tron 		if ( mdb_writes >= mdb_writes_per_commit ) {
    791  1.1      tron 			unsigned i;
    792  1.2  christos 			MDB_TOOL_IDL_FLUSH( be, mdb_tool_txn );
    793  1.2  christos 			rc = mdb_txn_commit( mdb_tool_txn );
    794  1.1      tron 			for ( i=0; i<mdb->mi_nattrs; i++ )
    795  1.1      tron 				mdb->mi_attrs[i]->ai_cursor = NULL;
    796  1.1      tron 			mdb_writes = 0;
    797  1.2  christos 			mdb_tool_txn = NULL;
    798  1.1      tron 			idcursor = NULL;
    799  1.1      tron 			if( rc != 0 ) {
    800  1.2  christos 				mdb->mi_numads = 0;
    801  1.1      tron 				snprintf( text->bv_val, text->bv_len,
    802  1.1      tron 						"txn_commit failed: %s (%d)",
    803  1.1      tron 						mdb_strerror(rc), rc );
    804  1.1      tron 				Debug( LDAP_DEBUG_ANY,
    805  1.1      tron 					"=> " LDAP_XSTRING(mdb_tool_entry_put) ": %s\n",
    806  1.3  christos 					text->bv_val );
    807  1.1      tron 				e->e_id = NOID;
    808  1.1      tron 			}
    809  1.1      tron 		}
    810  1.1      tron 
    811  1.1      tron 	} else {
    812  1.1      tron 		unsigned i;
    813  1.2  christos 		mdb_txn_abort( mdb_tool_txn );
    814  1.2  christos 		mdb_tool_txn = NULL;
    815  1.1      tron 		idcursor = NULL;
    816  1.1      tron 		for ( i=0; i<mdb->mi_nattrs; i++ )
    817  1.1      tron 			mdb->mi_attrs[i]->ai_cursor = NULL;
    818  1.1      tron 		mdb_writes = 0;
    819  1.1      tron 		snprintf( text->bv_val, text->bv_len,
    820  1.1      tron 			"txn_aborted! %s (%d)",
    821  1.1      tron 			rc == LDAP_OTHER ? "Internal error" :
    822  1.1      tron 			mdb_strerror(rc), rc );
    823  1.1      tron 		Debug( LDAP_DEBUG_ANY,
    824  1.1      tron 			"=> " LDAP_XSTRING(mdb_tool_entry_put) ": %s\n",
    825  1.3  christos 			text->bv_val );
    826  1.1      tron 		e->e_id = NOID;
    827  1.1      tron 	}
    828  1.1      tron 
    829  1.1      tron 	return e->e_id;
    830  1.1      tron }
    831  1.1      tron 
    832  1.1      tron static int mdb_dn2id_upgrade( BackendDB *be );
    833  1.1      tron 
    834  1.1      tron int mdb_tool_entry_reindex(
    835  1.1      tron 	BackendDB *be,
    836  1.1      tron 	ID id,
    837  1.1      tron 	AttributeDescription **adv )
    838  1.1      tron {
    839  1.1      tron 	struct mdb_info *mi = (struct mdb_info *) be->be_private;
    840  1.1      tron 	int rc;
    841  1.1      tron 	Entry *e;
    842  1.1      tron 	Operation op = {0};
    843  1.1      tron 	Opheader ohdr = {0};
    844  1.1      tron 
    845  1.1      tron 	Debug( LDAP_DEBUG_ARGS,
    846  1.1      tron 		"=> " LDAP_XSTRING(mdb_tool_entry_reindex) "( %ld )\n",
    847  1.3  christos 		(long) id );
    848  1.1      tron 	assert( tool_base == NULL );
    849  1.1      tron 	assert( tool_filter == NULL );
    850  1.1      tron 
    851  1.1      tron 	/* Special: do a dn2id upgrade */
    852  1.1      tron 	if ( adv && adv[0] == slap_schema.si_ad_entryDN ) {
    853  1.1      tron 		/* short-circuit tool_entry_next() */
    854  1.1      tron 		mdb_cursor_get( cursor, &key, &data, MDB_LAST );
    855  1.1      tron 		return mdb_dn2id_upgrade( be );
    856  1.1      tron 	}
    857  1.1      tron 
    858  1.1      tron 	/* No indexes configured, nothing to do. Could return an
    859  1.1      tron 	 * error here to shortcut things.
    860  1.1      tron 	 */
    861  1.1      tron 	if (!mi->mi_attrs) {
    862  1.1      tron 		return 0;
    863  1.1      tron 	}
    864  1.1      tron 
    865  1.4  christos 	reindexing = 1;
    866  1.4  christos 
    867  1.1      tron 	/* Check for explicit list of attrs to index */
    868  1.1      tron 	if ( adv ) {
    869  1.1      tron 		int i, j, n;
    870  1.1      tron 
    871  1.1      tron 		if ( mi->mi_attrs[0]->ai_desc != adv[0] ) {
    872  1.1      tron 			/* count */
    873  1.1      tron 			for ( n = 0; adv[n]; n++ ) ;
    874  1.1      tron 
    875  1.1      tron 			/* insertion sort */
    876  1.1      tron 			for ( i = 0; i < n; i++ ) {
    877  1.1      tron 				AttributeDescription *ad = adv[i];
    878  1.1      tron 				for ( j = i-1; j>=0; j--) {
    879  1.1      tron 					if ( SLAP_PTRCMP( adv[j], ad ) <= 0 ) break;
    880  1.1      tron 					adv[j+1] = adv[j];
    881  1.1      tron 				}
    882  1.1      tron 				adv[j+1] = ad;
    883  1.1      tron 			}
    884  1.1      tron 		}
    885  1.1      tron 
    886  1.1      tron 		for ( i = 0; adv[i]; i++ ) {
    887  1.1      tron 			if ( mi->mi_attrs[i]->ai_desc != adv[i] ) {
    888  1.1      tron 				for ( j = i+1; j < mi->mi_nattrs; j++ ) {
    889  1.1      tron 					if ( mi->mi_attrs[j]->ai_desc == adv[i] ) {
    890  1.1      tron 						AttrInfo *ai = mi->mi_attrs[i];
    891  1.1      tron 						mi->mi_attrs[i] = mi->mi_attrs[j];
    892  1.1      tron 						mi->mi_attrs[j] = ai;
    893  1.1      tron 						break;
    894  1.1      tron 					}
    895  1.1      tron 				}
    896  1.1      tron 				if ( j == mi->mi_nattrs ) {
    897  1.1      tron 					Debug( LDAP_DEBUG_ANY,
    898  1.1      tron 						LDAP_XSTRING(mdb_tool_entry_reindex)
    899  1.1      tron 						": no index configured for %s\n",
    900  1.3  christos 						adv[i]->ad_cname.bv_val );
    901  1.1      tron 					return -1;
    902  1.1      tron 				}
    903  1.1      tron 			}
    904  1.1      tron 		}
    905  1.1      tron 		mi->mi_nattrs = i;
    906  1.1      tron 	}
    907  1.1      tron 
    908  1.1      tron 	e = mdb_tool_entry_get( be, id );
    909  1.1      tron 
    910  1.1      tron 	if( e == NULL ) {
    911  1.1      tron 		Debug( LDAP_DEBUG_ANY,
    912  1.1      tron 			LDAP_XSTRING(mdb_tool_entry_reindex)
    913  1.1      tron 			": could not locate id=%ld\n",
    914  1.3  christos 			(long) id );
    915  1.1      tron 		return -1;
    916  1.1      tron 	}
    917  1.1      tron 
    918  1.1      tron 	if ( !txi ) {
    919  1.1      tron 		rc = mdb_txn_begin( mi->mi_dbenv, NULL, 0, &txi );
    920  1.1      tron 		if( rc != 0 ) {
    921  1.1      tron 			Debug( LDAP_DEBUG_ANY,
    922  1.1      tron 				"=> " LDAP_XSTRING(mdb_tool_entry_reindex) ": "
    923  1.1      tron 				"txn_begin failed: %s (%d)\n",
    924  1.3  christos 				mdb_strerror(rc), rc );
    925  1.1      tron 			goto done;
    926  1.1      tron 		}
    927  1.1      tron 	}
    928  1.1      tron 
    929  1.1      tron 	if ( slapMode & SLAP_TRUNCATE_MODE ) {
    930  1.1      tron 		int i;
    931  1.1      tron 		for ( i=0; i < mi->mi_nattrs; i++ ) {
    932  1.1      tron 			rc = mdb_drop( txi, mi->mi_attrs[i]->ai_dbi, 0 );
    933  1.1      tron 			if ( rc ) {
    934  1.1      tron 				Debug( LDAP_DEBUG_ANY,
    935  1.1      tron 					LDAP_XSTRING(mdb_tool_entry_reindex)
    936  1.1      tron 					": (Truncate) mdb_drop(%s) failed: %s (%d)\n",
    937  1.1      tron 					mi->mi_attrs[i]->ai_desc->ad_type->sat_cname.bv_val,
    938  1.1      tron 					mdb_strerror(rc), rc );
    939  1.1      tron 				return -1;
    940  1.1      tron 			}
    941  1.1      tron 		}
    942  1.1      tron 		slapMode ^= SLAP_TRUNCATE_MODE;
    943  1.1      tron 	}
    944  1.1      tron 
    945  1.1      tron 	/*
    946  1.1      tron 	 * just (re)add them for now
    947  1.1      tron 	 * Use truncate mode to empty/reset index databases
    948  1.1      tron 	 */
    949  1.1      tron 
    950  1.1      tron 	Debug( LDAP_DEBUG_TRACE,
    951  1.1      tron 		"=> " LDAP_XSTRING(mdb_tool_entry_reindex) "( %ld )\n",
    952  1.3  christos 		(long) id );
    953  1.1      tron 
    954  1.1      tron 	op.o_hdr = &ohdr;
    955  1.1      tron 	op.o_bd = be;
    956  1.1      tron 	op.o_tmpmemctx = NULL;
    957  1.1      tron 	op.o_tmpmfuncs = &ch_mfuncs;
    958  1.1      tron 
    959  1.1      tron 	rc = mdb_tool_index_add( &op, txi, e );
    960  1.1      tron 
    961  1.1      tron done:
    962  1.1      tron 	if( rc == 0 ) {
    963  1.1      tron 		mdb_writes++;
    964  1.1      tron 		if ( mdb_writes >= mdb_writes_per_commit ) {
    965  1.1      tron 			MDB_val key;
    966  1.1      tron 			unsigned i;
    967  1.1      tron 			MDB_TOOL_IDL_FLUSH( be, txi );
    968  1.1      tron 			rc = mdb_txn_commit( txi );
    969  1.1      tron 			mdb_writes = 0;
    970  1.1      tron 			for ( i=0; i<mi->mi_nattrs; i++ )
    971  1.1      tron 				mi->mi_attrs[i]->ai_cursor = NULL;
    972  1.1      tron 			if( rc != 0 ) {
    973  1.1      tron 				Debug( LDAP_DEBUG_ANY,
    974  1.1      tron 					"=> " LDAP_XSTRING(mdb_tool_entry_reindex)
    975  1.1      tron 					": txn_commit failed: %s (%d)\n",
    976  1.3  christos 					mdb_strerror(rc), rc );
    977  1.1      tron 				e->e_id = NOID;
    978  1.1      tron 			}
    979  1.1      tron 			mdb_cursor_close( cursor );
    980  1.1      tron 			txi = NULL;
    981  1.1      tron 			/* Must close the read txn to allow old pages to be reclaimed. */
    982  1.2  christos 			mdb_txn_abort( mdb_tool_txn );
    983  1.1      tron 			/* and then reopen it so that tool_entry_next still works. */
    984  1.2  christos 			mdb_txn_begin( mi->mi_dbenv, NULL, MDB_RDONLY, &mdb_tool_txn );
    985  1.2  christos 			mdb_cursor_open( mdb_tool_txn, mi->mi_id2entry, &cursor );
    986  1.1      tron 			key.mv_data = &id;
    987  1.1      tron 			key.mv_size = sizeof(ID);
    988  1.1      tron 			mdb_cursor_get( cursor, &key, NULL, MDB_SET );
    989  1.1      tron 		}
    990  1.1      tron 
    991  1.1      tron 	} else {
    992  1.1      tron 		unsigned i;
    993  1.1      tron 		mdb_writes = 0;
    994  1.1      tron 		mdb_cursor_close( cursor );
    995  1.1      tron 		cursor = NULL;
    996  1.1      tron 		mdb_txn_abort( txi );
    997  1.1      tron 		for ( i=0; i<mi->mi_nattrs; i++ )
    998  1.1      tron 			mi->mi_attrs[i]->ai_cursor = NULL;
    999  1.1      tron 		Debug( LDAP_DEBUG_ANY,
   1000  1.1      tron 			"=> " LDAP_XSTRING(mdb_tool_entry_reindex)
   1001  1.1      tron 			": txn_aborted! err=%d\n",
   1002  1.3  christos 			rc );
   1003  1.1      tron 		e->e_id = NOID;
   1004  1.1      tron 		txi = NULL;
   1005  1.1      tron 	}
   1006  1.1      tron 	mdb_entry_release( &op, e, 0 );
   1007  1.1      tron 
   1008  1.1      tron 	return rc;
   1009  1.1      tron }
   1010  1.1      tron 
   1011  1.1      tron ID mdb_tool_entry_modify(
   1012  1.1      tron 	BackendDB *be,
   1013  1.1      tron 	Entry *e,
   1014  1.1      tron 	struct berval *text )
   1015  1.1      tron {
   1016  1.1      tron 	int rc;
   1017  1.1      tron 	struct mdb_info *mdb;
   1018  1.1      tron 	Operation op = {0};
   1019  1.1      tron 	Opheader ohdr = {0};
   1020  1.1      tron 
   1021  1.1      tron 	assert( be != NULL );
   1022  1.1      tron 	assert( slapMode & SLAP_TOOL_MODE );
   1023  1.1      tron 
   1024  1.1      tron 	assert( text != NULL );
   1025  1.1      tron 	assert( text->bv_val != NULL );
   1026  1.1      tron 	assert( text->bv_val[0] == '\0' );	/* overconservative? */
   1027  1.1      tron 
   1028  1.1      tron 	assert ( e->e_id != NOID );
   1029  1.1      tron 
   1030  1.1      tron 	Debug( LDAP_DEBUG_TRACE,
   1031  1.1      tron 		"=> " LDAP_XSTRING(mdb_tool_entry_modify) "( %ld, \"%s\" )\n",
   1032  1.3  christos 		(long) e->e_id, e->e_dn );
   1033  1.1      tron 
   1034  1.1      tron 	mdb = (struct mdb_info *) be->be_private;
   1035  1.1      tron 
   1036  1.1      tron 	if( cursor ) {
   1037  1.1      tron 		mdb_cursor_close( cursor );
   1038  1.1      tron 		cursor = NULL;
   1039  1.1      tron 	}
   1040  1.2  christos 	if ( !mdb_tool_txn ) {
   1041  1.2  christos 		rc = mdb_txn_begin( mdb->mi_dbenv, NULL, 0, &mdb_tool_txn );
   1042  1.1      tron 		if( rc != 0 ) {
   1043  1.1      tron 			snprintf( text->bv_val, text->bv_len,
   1044  1.1      tron 				"txn_begin failed: %s (%d)",
   1045  1.1      tron 				mdb_strerror(rc), rc );
   1046  1.1      tron 			Debug( LDAP_DEBUG_ANY,
   1047  1.1      tron 				"=> " LDAP_XSTRING(mdb_tool_entry_modify) ": %s\n",
   1048  1.3  christos 				 text->bv_val );
   1049  1.1      tron 			return NOID;
   1050  1.1      tron 		}
   1051  1.1      tron 	}
   1052  1.1      tron 
   1053  1.1      tron 	op.o_hdr = &ohdr;
   1054  1.1      tron 	op.o_bd = be;
   1055  1.1      tron 	op.o_tmpmemctx = NULL;
   1056  1.1      tron 	op.o_tmpmfuncs = &ch_mfuncs;
   1057  1.1      tron 
   1058  1.1      tron 	/* id2entry index */
   1059  1.4  christos 	rc = mdb_id2entry_update( &op, mdb_tool_txn, idcursor, e );
   1060  1.1      tron 	if( rc != 0 ) {
   1061  1.1      tron 		snprintf( text->bv_val, text->bv_len,
   1062  1.1      tron 				"id2entry_update failed: err=%d", rc );
   1063  1.1      tron 		Debug( LDAP_DEBUG_ANY,
   1064  1.1      tron 			"=> " LDAP_XSTRING(mdb_tool_entry_modify) ": %s\n",
   1065  1.3  christos 			text->bv_val );
   1066  1.1      tron 		goto done;
   1067  1.1      tron 	}
   1068  1.1      tron 
   1069  1.1      tron done:
   1070  1.1      tron 	if( rc == 0 ) {
   1071  1.2  christos 		rc = mdb_txn_commit( mdb_tool_txn );
   1072  1.1      tron 		if( rc != 0 ) {
   1073  1.2  christos 			mdb->mi_numads = 0;
   1074  1.1      tron 			snprintf( text->bv_val, text->bv_len,
   1075  1.1      tron 					"txn_commit failed: %s (%d)",
   1076  1.1      tron 					mdb_strerror(rc), rc );
   1077  1.1      tron 			Debug( LDAP_DEBUG_ANY,
   1078  1.1      tron 				"=> " LDAP_XSTRING(mdb_tool_entry_modify) ": "
   1079  1.3  christos 				"%s\n", text->bv_val );
   1080  1.1      tron 			e->e_id = NOID;
   1081  1.1      tron 		}
   1082  1.1      tron 
   1083  1.1      tron 	} else {
   1084  1.2  christos 		mdb_txn_abort( mdb_tool_txn );
   1085  1.1      tron 		snprintf( text->bv_val, text->bv_len,
   1086  1.1      tron 			"txn_aborted! %s (%d)",
   1087  1.1      tron 			mdb_strerror(rc), rc );
   1088  1.1      tron 		Debug( LDAP_DEBUG_ANY,
   1089  1.1      tron 			"=> " LDAP_XSTRING(mdb_tool_entry_modify) ": %s\n",
   1090  1.3  christos 			text->bv_val );
   1091  1.1      tron 		e->e_id = NOID;
   1092  1.1      tron 	}
   1093  1.2  christos 	mdb_tool_txn = NULL;
   1094  1.4  christos 	idcursor = NULL;
   1095  1.1      tron 
   1096  1.1      tron 	return e->e_id;
   1097  1.1      tron }
   1098  1.1      tron 
   1099  1.3  christos int mdb_tool_entry_delete(
   1100  1.3  christos 	BackendDB *be,
   1101  1.3  christos 	struct berval *ndn,
   1102  1.3  christos 	struct berval *text )
   1103  1.3  christos {
   1104  1.3  christos 	int rc;
   1105  1.3  christos 	struct mdb_info *mdb;
   1106  1.3  christos 	Operation op = {0};
   1107  1.3  christos 	Opheader ohdr = {0};
   1108  1.3  christos 	Entry *e;
   1109  1.3  christos 
   1110  1.3  christos 	assert( be != NULL );
   1111  1.3  christos 	assert( slapMode & SLAP_TOOL_MODE );
   1112  1.3  christos 
   1113  1.3  christos 	assert( text != NULL );
   1114  1.3  christos 	assert( text->bv_val != NULL );
   1115  1.3  christos 	assert( text->bv_val[0] == '\0' );	/* overconservative? */
   1116  1.3  christos 
   1117  1.3  christos 	assert ( ndn != NULL );
   1118  1.3  christos 	assert ( ndn->bv_val != NULL );
   1119  1.3  christos 
   1120  1.3  christos 	Debug( LDAP_DEBUG_TRACE,
   1121  1.3  christos 		"=> " LDAP_XSTRING(mdb_tool_entry_delete) "( %s )\n",
   1122  1.3  christos 		ndn->bv_val );
   1123  1.3  christos 
   1124  1.3  christos 	mdb = (struct mdb_info *) be->be_private;
   1125  1.3  christos 
   1126  1.3  christos 	assert( cursor == NULL );
   1127  1.3  christos 	if( cursor ) {
   1128  1.3  christos 		mdb_cursor_close( cursor );
   1129  1.3  christos 		cursor = NULL;
   1130  1.3  christos 	}
   1131  1.3  christos 	if( !mdb_tool_txn ) {
   1132  1.3  christos 		rc = mdb_txn_begin( mdb->mi_dbenv, NULL, 0, &mdb_tool_txn );
   1133  1.3  christos 		if( rc != 0 ) {
   1134  1.3  christos 			snprintf( text->bv_val, text->bv_len,
   1135  1.3  christos 				"txn_begin failed: %s (%d)",
   1136  1.3  christos 				mdb_strerror(rc), rc );
   1137  1.3  christos 			Debug( LDAP_DEBUG_ANY,
   1138  1.3  christos 				"=> " LDAP_XSTRING(mdb_tool_entry_delete) ": %s\n",
   1139  1.3  christos 				 text->bv_val );
   1140  1.3  christos 			return LDAP_OTHER;
   1141  1.3  christos 		}
   1142  1.3  christos 	}
   1143  1.3  christos 
   1144  1.3  christos 	rc = mdb_cursor_open( mdb_tool_txn, mdb->mi_dn2id, &cursor );
   1145  1.3  christos 	if( rc != 0 ) {
   1146  1.3  christos 		snprintf( text->bv_val, text->bv_len,
   1147  1.3  christos 			"cursor_open failed: %s (%d)",
   1148  1.3  christos 			mdb_strerror(rc), rc );
   1149  1.3  christos 		Debug( LDAP_DEBUG_ANY,
   1150  1.3  christos 			"=> " LDAP_XSTRING(mdb_tool_entry_delete) ": %s\n",
   1151  1.3  christos 			 text->bv_val );
   1152  1.3  christos 		return LDAP_OTHER;
   1153  1.3  christos 	}
   1154  1.3  christos 
   1155  1.3  christos 	op.o_hdr = &ohdr;
   1156  1.3  christos 	op.o_bd = be;
   1157  1.3  christos 	op.o_tmpmemctx = NULL;
   1158  1.3  christos 	op.o_tmpmfuncs = &ch_mfuncs;
   1159  1.3  christos 
   1160  1.3  christos 	rc = mdb_dn2entry( &op, mdb_tool_txn, cursor, ndn, &e, NULL, 0 );
   1161  1.3  christos 	if( rc != 0 ) {
   1162  1.3  christos 		snprintf( text->bv_val, text->bv_len,
   1163  1.3  christos 			"dn2entry failed: %s (%d)",
   1164  1.3  christos 			mdb_strerror(rc), rc );
   1165  1.3  christos 		Debug( LDAP_DEBUG_ANY,
   1166  1.3  christos 			"=> " LDAP_XSTRING(mdb_tool_entry_delete) ": %s\n",
   1167  1.3  christos 			 text->bv_val );
   1168  1.3  christos 		goto done;
   1169  1.3  christos 	}
   1170  1.3  christos 
   1171  1.3  christos 	/* check that we wouldn't orphan any children */
   1172  1.3  christos 	rc = mdb_dn2id_children( &op, mdb_tool_txn, e );
   1173  1.3  christos 	if( rc != MDB_NOTFOUND ) {
   1174  1.3  christos 		switch( rc ) {
   1175  1.3  christos 		case 0:
   1176  1.3  christos 			snprintf( text->bv_val, text->bv_len,
   1177  1.3  christos 				"delete failed:"
   1178  1.3  christos 				" subordinate objects must be deleted first");
   1179  1.3  christos 			break;
   1180  1.3  christos 		default:
   1181  1.3  christos 			snprintf( text->bv_val, text->bv_len,
   1182  1.3  christos 				"has_children failed: %s (%d)",
   1183  1.3  christos 				mdb_strerror(rc), rc );
   1184  1.3  christos 			break;
   1185  1.3  christos 		}
   1186  1.3  christos 		rc = -1;
   1187  1.3  christos 		Debug( LDAP_DEBUG_ANY,
   1188  1.3  christos 			"=> " LDAP_XSTRING(mdb_tool_entry_delete) ": %s\n",
   1189  1.3  christos 			 text->bv_val );
   1190  1.3  christos 		goto done;
   1191  1.3  christos 	}
   1192  1.3  christos 
   1193  1.3  christos 	/* delete from dn2id */
   1194  1.3  christos 	rc = mdb_dn2id_delete( &op, cursor, e->e_id, 1 );
   1195  1.3  christos 	if( rc != 0 ) {
   1196  1.3  christos 		snprintf( text->bv_val, text->bv_len,
   1197  1.3  christos 				"dn2id_delete failed: err=%d", rc );
   1198  1.3  christos 		Debug( LDAP_DEBUG_ANY,
   1199  1.3  christos 			"=> " LDAP_XSTRING(mdb_tool_entry_delete) ": %s\n",
   1200  1.3  christos 			text->bv_val );
   1201  1.3  christos 		goto done;
   1202  1.3  christos 	}
   1203  1.3  christos 
   1204  1.3  christos 	/* deindex values */
   1205  1.3  christos 	rc = mdb_index_entry_del( &op, mdb_tool_txn, e );
   1206  1.3  christos 	if( rc != 0 ) {
   1207  1.3  christos 		snprintf( text->bv_val, text->bv_len,
   1208  1.3  christos 				"entry_delete failed: err=%d", rc );
   1209  1.3  christos 		Debug( LDAP_DEBUG_ANY,
   1210  1.3  christos 			"=> " LDAP_XSTRING(mdb_tool_entry_delete) ": %s\n",
   1211  1.3  christos 			text->bv_val );
   1212  1.3  christos 		goto done;
   1213  1.3  christos 	}
   1214  1.3  christos 
   1215  1.3  christos 	/* do the deletion */
   1216  1.3  christos 	rc = mdb_id2entry_delete( be, mdb_tool_txn, e );
   1217  1.3  christos 	if( rc != 0 ) {
   1218  1.3  christos 		snprintf( text->bv_val, text->bv_len,
   1219  1.3  christos 				"id2entry_update failed: err=%d", rc );
   1220  1.3  christos 		Debug( LDAP_DEBUG_ANY,
   1221  1.3  christos 			"=> " LDAP_XSTRING(mdb_tool_entry_delete) ": %s\n",
   1222  1.3  christos 			text->bv_val );
   1223  1.3  christos 		goto done;
   1224  1.3  christos 	}
   1225  1.3  christos 
   1226  1.3  christos done:
   1227  1.3  christos 	/* free entry */
   1228  1.3  christos 	if( e != NULL ) {
   1229  1.3  christos 		mdb_entry_return( &op, e );
   1230  1.3  christos 	}
   1231  1.3  christos 
   1232  1.3  christos 	if( rc == 0 ) {
   1233  1.3  christos 		rc = mdb_txn_commit( mdb_tool_txn );
   1234  1.3  christos 		if( rc != 0 ) {
   1235  1.3  christos 			snprintf( text->bv_val, text->bv_len,
   1236  1.3  christos 					"txn_commit failed: %s (%d)",
   1237  1.3  christos 					mdb_strerror(rc), rc );
   1238  1.3  christos 			Debug( LDAP_DEBUG_ANY,
   1239  1.3  christos 				"=> " LDAP_XSTRING(mdb_tool_entry_delete) ": "
   1240  1.3  christos 				"%s\n", text->bv_val );
   1241  1.3  christos 		}
   1242  1.3  christos 
   1243  1.3  christos 	} else {
   1244  1.3  christos 		mdb_txn_abort( mdb_tool_txn );
   1245  1.3  christos 		snprintf( text->bv_val, text->bv_len,
   1246  1.3  christos 			"txn_aborted! %s (%d)",
   1247  1.3  christos 			mdb_strerror(rc), rc );
   1248  1.3  christos 		Debug( LDAP_DEBUG_ANY,
   1249  1.3  christos 			"=> " LDAP_XSTRING(mdb_tool_entry_delete) ": %s\n",
   1250  1.3  christos 			text->bv_val );
   1251  1.3  christos 	}
   1252  1.3  christos 	mdb_tool_txn = NULL;
   1253  1.3  christos 	cursor = NULL;
   1254  1.3  christos 
   1255  1.3  christos 	return rc;
   1256  1.3  christos }
   1257  1.3  christos 
   1258  1.1      tron static void *
   1259  1.1      tron mdb_tool_index_task( void *ctx, void *ptr )
   1260  1.1      tron {
   1261  1.1      tron 	int base = *(int *)ptr;
   1262  1.3  christos 	Operation op = {0};
   1263  1.3  christos 	Opheader ohdr = {0};
   1264  1.3  christos 	AttrIxInfo ai = {0}, *aio;
   1265  1.1      tron 
   1266  1.1      tron 	free( ptr );
   1267  1.3  christos 	op.o_hdr = &ohdr;
   1268  1.3  christos 	op.o_bd = mdb_tool_ix_be;
   1269  1.3  christos 	op.o_tmpmemctx = NULL;
   1270  1.3  christos 	op.o_tmpmfuncs = &ch_mfuncs;
   1271  1.3  christos 	aio = mdb_tool_axinfo[base];
   1272  1.3  christos 	mdb_tool_axinfo[base] = &ai;
   1273  1.3  christos 	LDAP_SLIST_INSERT_HEAD( &op.o_extra, &ai.ai_oe, oe_next );
   1274  1.1      tron 	while ( 1 ) {
   1275  1.1      tron 		ldap_pvt_thread_mutex_lock( &mdb_tool_index_mutex );
   1276  1.1      tron 		mdb_tool_index_tcount--;
   1277  1.1      tron 		if ( !mdb_tool_index_tcount )
   1278  1.1      tron 			ldap_pvt_thread_cond_signal( &mdb_tool_index_cond_main );
   1279  1.1      tron 		ldap_pvt_thread_cond_wait( &mdb_tool_index_cond_work,
   1280  1.1      tron 			&mdb_tool_index_mutex );
   1281  1.1      tron 		if ( slapd_shutdown ) {
   1282  1.1      tron 			mdb_tool_index_tcount--;
   1283  1.1      tron 			if ( !mdb_tool_index_tcount )
   1284  1.1      tron 				ldap_pvt_thread_cond_signal( &mdb_tool_index_cond_main );
   1285  1.3  christos 			*aio = ai;
   1286  1.3  christos 			mdb_tool_axinfo[base] = aio;
   1287  1.1      tron 			ldap_pvt_thread_mutex_unlock( &mdb_tool_index_mutex );
   1288  1.1      tron 			break;
   1289  1.1      tron 		}
   1290  1.1      tron 		ldap_pvt_thread_mutex_unlock( &mdb_tool_index_mutex );
   1291  1.3  christos 		mdb_tool_index_rec[base].ir_i = mdb_index_recrun( &op,
   1292  1.1      tron 			mdb_tool_ix_txn,
   1293  1.1      tron 			mdb_tool_info, mdb_tool_index_rec, mdb_tool_ix_id, base );
   1294  1.1      tron 	}
   1295  1.1      tron 
   1296  1.1      tron 	return NULL;
   1297  1.1      tron }
   1298  1.1      tron 
   1299  1.1      tron #ifdef MDB_TOOL_IDL_CACHING
   1300  1.1      tron static int
   1301  1.1      tron mdb_tool_idl_cmp( const void *v1, const void *v2 )
   1302  1.1      tron {
   1303  1.1      tron 	const mdb_tool_idl_cache *c1 = v1, *c2 = v2;
   1304  1.1      tron 	int rc;
   1305  1.1      tron 
   1306  1.1      tron 	if (( rc = c1->kstr.bv_len - c2->kstr.bv_len )) return rc;
   1307  1.1      tron 	return memcmp( c1->kstr.bv_val, c2->kstr.bv_val, c1->kstr.bv_len );
   1308  1.1      tron }
   1309  1.1      tron 
   1310  1.1      tron static int
   1311  1.3  christos mdb_tool_idl_flush_one( MDB_cursor *mc, AttrIxInfo *ai, mdb_tool_idl_cache *ic )
   1312  1.1      tron {
   1313  1.1      tron 	mdb_tool_idl_cache_entry *ice;
   1314  1.1      tron 	MDB_val key, data[2];
   1315  1.1      tron 	int i, rc;
   1316  1.1      tron 	ID id, nid;
   1317  1.1      tron 
   1318  1.1      tron 	/* Freshly allocated, ignore it */
   1319  1.3  christos 	if ( !ic->head && ic->count <= MDB_idl_db_size ) {
   1320  1.1      tron 		return 0;
   1321  1.1      tron 	}
   1322  1.1      tron 
   1323  1.1      tron 	key.mv_data = ic->kstr.bv_val;
   1324  1.1      tron 	key.mv_size = ic->kstr.bv_len;
   1325  1.1      tron 
   1326  1.3  christos 	if ( ic->count > MDB_idl_db_size ) {
   1327  1.1      tron 		while ( ic->flags & WAS_FOUND ) {
   1328  1.1      tron 			rc = mdb_cursor_get( mc, &key, data, MDB_SET );
   1329  1.1      tron 			if ( rc ) {
   1330  1.1      tron 				/* FIXME: find out why this happens */
   1331  1.1      tron 				ic->flags = 0;
   1332  1.1      tron 				break;
   1333  1.1      tron 			}
   1334  1.1      tron 			if ( ic->flags & WAS_RANGE ) {
   1335  1.1      tron 				/* Skip lo */
   1336  1.1      tron 				rc = mdb_cursor_get( mc, &key, data, MDB_NEXT_DUP );
   1337  1.1      tron 
   1338  1.1      tron 				/* Get hi */
   1339  1.1      tron 				rc = mdb_cursor_get( mc, &key, data, MDB_NEXT_DUP );
   1340  1.1      tron 
   1341  1.1      tron 				/* Store range hi */
   1342  1.1      tron 				data[0].mv_data = &ic->last;
   1343  1.1      tron 				rc = mdb_cursor_put( mc, &key, data, MDB_CURRENT );
   1344  1.1      tron 			} else {
   1345  1.1      tron 				/* Delete old data, replace with range */
   1346  1.1      tron 				ic->first = *(ID *)data[0].mv_data;
   1347  1.1      tron 				mdb_cursor_del( mc, MDB_NODUPDATA );
   1348  1.1      tron 			}
   1349  1.1      tron 			break;
   1350  1.1      tron 		}
   1351  1.1      tron 		if ( !(ic->flags & WAS_RANGE)) {
   1352  1.1      tron 			/* range, didn't exist before */
   1353  1.1      tron 			nid = 0;
   1354  1.1      tron 			data[0].mv_size = sizeof(ID);
   1355  1.1      tron 			data[0].mv_data = &nid;
   1356  1.1      tron 			rc = mdb_cursor_put( mc, &key, data, 0 );
   1357  1.1      tron 			if ( rc == 0 ) {
   1358  1.1      tron 				data[0].mv_data = &ic->first;
   1359  1.1      tron 				rc = mdb_cursor_put( mc, &key, data, 0 );
   1360  1.1      tron 				if ( rc == 0 ) {
   1361  1.1      tron 					data[0].mv_data = &ic->last;
   1362  1.1      tron 					rc = mdb_cursor_put( mc, &key, data, 0 );
   1363  1.1      tron 				}
   1364  1.1      tron 			}
   1365  1.1      tron 			if ( rc ) {
   1366  1.1      tron 				rc = -1;
   1367  1.1      tron 			}
   1368  1.1      tron 		}
   1369  1.1      tron 	} else {
   1370  1.1      tron 		/* Normal write */
   1371  1.1      tron 		int n;
   1372  1.1      tron 
   1373  1.1      tron 		data[0].mv_size = sizeof(ID);
   1374  1.1      tron 		rc = 0;
   1375  1.1      tron 		for ( ice = ic->head, n=0; ice; ice = ice->next, n++ ) {
   1376  1.1      tron 			int end;
   1377  1.1      tron 			if ( ice->next ) {
   1378  1.1      tron 				end = IDBLOCK;
   1379  1.1      tron 			} else {
   1380  1.3  christos 				end = (ic->count-ic->offset) & (IDBLOCK-1);
   1381  1.1      tron 				if ( !end )
   1382  1.1      tron 					end = IDBLOCK;
   1383  1.1      tron 			}
   1384  1.3  christos 			data[1].mv_size = end;
   1385  1.3  christos 			data[0].mv_data = ice->ids;
   1386  1.3  christos 			rc = mdb_cursor_put( mc, &key, data, MDB_APPENDDUP|MDB_MULTIPLE );
   1387  1.1      tron 			if ( rc ) {
   1388  1.1      tron 				rc = -1;
   1389  1.1      tron 				break;
   1390  1.1      tron 			}
   1391  1.1      tron 		}
   1392  1.1      tron 		if ( ic->head ) {
   1393  1.1      tron 			ic->tail->next = ai->ai_flist;
   1394  1.1      tron 			ai->ai_flist = ic->head;
   1395  1.1      tron 		}
   1396  1.1      tron 	}
   1397  1.1      tron 	ic->head = ai->ai_clist;
   1398  1.1      tron 	ai->ai_clist = ic;
   1399  1.1      tron 	return rc;
   1400  1.1      tron }
   1401  1.1      tron 
   1402  1.1      tron static int
   1403  1.3  christos mdb_tool_idl_flush_db( MDB_txn *txn, AttrInfo *ai, AttrIxInfo *ax )
   1404  1.1      tron {
   1405  1.1      tron 	MDB_cursor *mc;
   1406  1.1      tron 	Avlnode *root;
   1407  1.1      tron 	int rc;
   1408  1.1      tron 
   1409  1.1      tron 	mdb_cursor_open( txn, ai->ai_dbi, &mc );
   1410  1.3  christos 	root = ldap_tavl_end( ai->ai_root, TAVL_DIR_LEFT );
   1411  1.1      tron 	do {
   1412  1.3  christos 		rc = mdb_tool_idl_flush_one( mc, ax, root->avl_data );
   1413  1.1      tron 		if ( rc != -1 )
   1414  1.1      tron 			rc = 0;
   1415  1.3  christos 	} while ((root = ldap_tavl_next(root, TAVL_DIR_RIGHT)));
   1416  1.1      tron 	mdb_cursor_close( mc );
   1417  1.1      tron 
   1418  1.1      tron 	return rc;
   1419  1.1      tron }
   1420  1.1      tron 
   1421  1.1      tron static int
   1422  1.1      tron mdb_tool_idl_flush( BackendDB *be, MDB_txn *txn )
   1423  1.1      tron {
   1424  1.1      tron 	struct mdb_info *mdb = (struct mdb_info *) be->be_private;
   1425  1.1      tron 	int rc = 0;
   1426  1.1      tron 	unsigned int i, dbi;
   1427  1.1      tron 
   1428  1.1      tron 	for ( i=0; i < mdb->mi_nattrs; i++ ) {
   1429  1.1      tron 		if ( !mdb->mi_attrs[i]->ai_root ) continue;
   1430  1.3  christos 		rc = mdb_tool_idl_flush_db( txn, mdb->mi_attrs[i], mdb_tool_axinfo[i % mdb_tool_threads] );
   1431  1.3  christos 		ldap_tavl_free(mdb->mi_attrs[i]->ai_root, NULL);
   1432  1.1      tron 		mdb->mi_attrs[i]->ai_root = NULL;
   1433  1.1      tron 		if ( rc )
   1434  1.1      tron 			break;
   1435  1.1      tron 	}
   1436  1.1      tron 	return rc;
   1437  1.1      tron }
   1438  1.1      tron 
   1439  1.1      tron int mdb_tool_idl_add(
   1440  1.1      tron 	BackendDB *be,
   1441  1.1      tron 	MDB_cursor *mc,
   1442  1.1      tron 	struct berval *keys,
   1443  1.1      tron 	ID id )
   1444  1.1      tron {
   1445  1.1      tron 	MDB_dbi dbi;
   1446  1.1      tron 	mdb_tool_idl_cache *ic, itmp;
   1447  1.1      tron 	mdb_tool_idl_cache_entry *ice;
   1448  1.1      tron 	int i, rc, lcount;
   1449  1.3  christos 	AttrIxInfo *ax = (AttrIxInfo *)mc;
   1450  1.3  christos 	AttrInfo *ai = (AttrInfo *)ax->ai_ai;
   1451  1.1      tron 	mc = ai->ai_cursor;
   1452  1.1      tron 
   1453  1.1      tron 	dbi = ai->ai_dbi;
   1454  1.1      tron 	for (i=0; keys[i].bv_val; i++) {
   1455  1.1      tron 	itmp.kstr = keys[i];
   1456  1.3  christos 	ic = ldap_tavl_find( ai->ai_root, &itmp, mdb_tool_idl_cmp );
   1457  1.1      tron 
   1458  1.1      tron 	/* No entry yet, create one */
   1459  1.1      tron 	if ( !ic ) {
   1460  1.1      tron 		MDB_val key, data;
   1461  1.1      tron 		ID nid;
   1462  1.1      tron 		int rc;
   1463  1.1      tron 
   1464  1.3  christos 		if ( ax->ai_clist ) {
   1465  1.3  christos 			ic = ax->ai_clist;
   1466  1.3  christos 			ax->ai_clist = ic->head;
   1467  1.1      tron 		} else {
   1468  1.1      tron 			ic = ch_malloc( sizeof( mdb_tool_idl_cache ) + itmp.kstr.bv_len + 4 );
   1469  1.1      tron 		}
   1470  1.1      tron 		ic->kstr.bv_len = itmp.kstr.bv_len;
   1471  1.1      tron 		ic->kstr.bv_val = (char *)(ic+1);
   1472  1.1      tron 		memcpy( ic->kstr.bv_val, itmp.kstr.bv_val, ic->kstr.bv_len );
   1473  1.1      tron 		ic->head = ic->tail = NULL;
   1474  1.1      tron 		ic->last = 0;
   1475  1.1      tron 		ic->count = 0;
   1476  1.1      tron 		ic->offset = 0;
   1477  1.1      tron 		ic->flags = 0;
   1478  1.3  christos 		ldap_tavl_insert( &ai->ai_root, ic, mdb_tool_idl_cmp,
   1479  1.3  christos 			ldap_avl_dup_error );
   1480  1.1      tron 
   1481  1.1      tron 		/* load existing key count here */
   1482  1.1      tron 		key.mv_size = keys[i].bv_len;
   1483  1.1      tron 		key.mv_data = keys[i].bv_val;
   1484  1.1      tron 		rc = mdb_cursor_get( mc, &key, &data, MDB_SET );
   1485  1.1      tron 		if ( rc == 0 ) {
   1486  1.1      tron 			ic->flags |= WAS_FOUND;
   1487  1.1      tron 			nid = *(ID *)data.mv_data;
   1488  1.1      tron 			if ( nid == 0 ) {
   1489  1.3  christos 				ic->count = MDB_idl_db_size+1;
   1490  1.1      tron 				ic->flags |= WAS_RANGE;
   1491  1.1      tron 			} else {
   1492  1.1      tron 				size_t count;
   1493  1.1      tron 
   1494  1.1      tron 				mdb_cursor_count( mc, &count );
   1495  1.1      tron 				ic->count = count;
   1496  1.1      tron 				ic->first = nid;
   1497  1.1      tron 				ic->offset = count & (IDBLOCK-1);
   1498  1.1      tron 			}
   1499  1.1      tron 		}
   1500  1.1      tron 	}
   1501  1.1      tron 	/* are we a range already? */
   1502  1.3  christos 	if ( ic->count > MDB_idl_db_size ) {
   1503  1.1      tron 		ic->last = id;
   1504  1.1      tron 		continue;
   1505  1.1      tron 	/* Are we at the limit, and converting to a range? */
   1506  1.3  christos 	} else if ( ic->count == MDB_idl_db_size ) {
   1507  1.1      tron 		if ( ic->head ) {
   1508  1.3  christos 			ic->tail->next = ax->ai_flist;
   1509  1.3  christos 			ax->ai_flist = ic->head;
   1510  1.1      tron 		}
   1511  1.1      tron 		ic->head = ic->tail = NULL;
   1512  1.1      tron 		ic->last = id;
   1513  1.1      tron 		ic->count++;
   1514  1.1      tron 		continue;
   1515  1.1      tron 	}
   1516  1.1      tron 	/* No free block, create that too */
   1517  1.3  christos 	lcount = (ic->count-ic->offset) & (IDBLOCK-1);
   1518  1.1      tron 	if ( !ic->tail || lcount == 0) {
   1519  1.3  christos 		if ( ax->ai_flist ) {
   1520  1.3  christos 			ice = ax->ai_flist;
   1521  1.3  christos 			ax->ai_flist = ice->next;
   1522  1.1      tron 		} else {
   1523  1.1      tron 			ice = ch_malloc( sizeof( mdb_tool_idl_cache_entry ));
   1524  1.1      tron 		}
   1525  1.1      tron 		ice->next = NULL;
   1526  1.1      tron 		if ( !ic->head ) {
   1527  1.1      tron 			ic->head = ice;
   1528  1.1      tron 		} else {
   1529  1.1      tron 			ic->tail->next = ice;
   1530  1.1      tron 		}
   1531  1.1      tron 		ic->tail = ice;
   1532  1.1      tron 		if ( lcount )
   1533  1.1      tron 			ice->ids[lcount-1] = 0;
   1534  1.1      tron 		if ( !ic->count )
   1535  1.1      tron 			ic->first = id;
   1536  1.1      tron 	}
   1537  1.1      tron 	ice = ic->tail;
   1538  1.3  christos 	if (!lcount || ice->ids[lcount-1] != id) {
   1539  1.1      tron 		ice->ids[lcount] = id;
   1540  1.3  christos 		ic->count++;
   1541  1.3  christos 	}
   1542  1.1      tron 	}
   1543  1.1      tron 
   1544  1.1      tron 	return 0;
   1545  1.1      tron }
   1546  1.1      tron #endif /* MDB_TOOL_IDL_CACHING */
   1547  1.1      tron 
   1548  1.1      tron /* Upgrade from pre 2.4.34 dn2id format */
   1549  1.1      tron 
   1550  1.1      tron #include <ac/unistd.h>
   1551  1.1      tron #include <lutil_meter.h>
   1552  1.1      tron 
   1553  1.1      tron #define STACKSIZ	2048
   1554  1.1      tron 
   1555  1.1      tron typedef struct rec {
   1556  1.1      tron 	ID id;
   1557  1.1      tron 	size_t len;
   1558  1.1      tron 	char rdn[512];
   1559  1.1      tron } rec;
   1560  1.1      tron 
   1561  1.1      tron static int
   1562  1.1      tron mdb_dn2id_upgrade( BackendDB *be ) {
   1563  1.1      tron 	struct mdb_info *mi = (struct mdb_info *) be->be_private;
   1564  1.1      tron 	MDB_txn *mt;
   1565  1.1      tron 	MDB_cursor *mc = NULL;
   1566  1.1      tron 	MDB_val key, data;
   1567  1.1      tron 	int rc, writes=0, depth=0;
   1568  1.1      tron 	int enable_meter = 0;
   1569  1.1      tron 	ID id = 0, *num, count = 0;
   1570  1.1      tron 	rec *stack;
   1571  1.1      tron 	lutil_meter_t meter;
   1572  1.1      tron 
   1573  1.1      tron 	if (!(mi->mi_flags & MDB_NEED_UPGRADE)) {
   1574  1.1      tron 		Debug( LDAP_DEBUG_ANY, "database %s: No upgrade needed.\n",
   1575  1.3  christos 			be->be_suffix[0].bv_val );
   1576  1.1      tron 		return 0;
   1577  1.1      tron 	}
   1578  1.1      tron 
   1579  1.1      tron 	{
   1580  1.1      tron 		MDB_stat st;
   1581  1.1      tron 
   1582  1.1      tron 		mdb_stat(mdb_cursor_txn(cursor), mi->mi_dbis[MDB_ID2ENTRY], &st);
   1583  1.1      tron 		if (!st.ms_entries) {
   1584  1.1      tron 			/* Empty DB, nothing to upgrade? */
   1585  1.1      tron 			return 0;
   1586  1.1      tron 		}
   1587  1.1      tron 		if (isatty(2))
   1588  1.1      tron 			enable_meter = !lutil_meter_open(&meter,
   1589  1.1      tron 				&lutil_meter_text_display,
   1590  1.1      tron 				&lutil_meter_linear_estimator,
   1591  1.1      tron 				st.ms_entries);
   1592  1.1      tron 	}
   1593  1.1      tron 
   1594  1.1      tron 	num = ch_malloc(STACKSIZ * (sizeof(ID) + sizeof(rec)));
   1595  1.1      tron 	stack = (rec *)(num + STACKSIZ);
   1596  1.1      tron 
   1597  1.1      tron 	rc = mdb_txn_begin(mi->mi_dbenv, NULL, 0, &mt);
   1598  1.1      tron 	if (rc) {
   1599  1.1      tron 		Debug(LDAP_DEBUG_ANY, "mdb_dn2id_upgrade: mdb_txn_begin failed, %s (%d)\n",
   1600  1.3  christos 			mdb_strerror(rc), rc );
   1601  1.1      tron 		goto leave;
   1602  1.1      tron 	}
   1603  1.1      tron 	rc = mdb_cursor_open(mt, mi->mi_dbis[MDB_DN2ID], &mc);
   1604  1.1      tron 	if (rc) {
   1605  1.1      tron 		Debug(LDAP_DEBUG_ANY, "mdb_dn2id_upgrade: mdb_cursor_open failed, %s (%d)\n",
   1606  1.3  christos 			mdb_strerror(rc), rc );
   1607  1.1      tron 		goto leave;
   1608  1.1      tron 	}
   1609  1.1      tron 
   1610  1.1      tron 	key.mv_size = sizeof(ID);
   1611  1.1      tron 	/* post-order depth-first update */
   1612  1.1      tron 	for(;;) {
   1613  1.1      tron 		size_t dkids;
   1614  1.1      tron 		unsigned char *ptr;
   1615  1.1      tron 
   1616  1.1      tron 		/* visit */
   1617  1.1      tron 		key.mv_data = &id;
   1618  1.1      tron 		stack[depth].id = id;
   1619  1.1      tron 		rc = mdb_cursor_get(mc, &key, &data, MDB_SET);
   1620  1.1      tron 		if (rc) {
   1621  1.1      tron 			Debug(LDAP_DEBUG_ANY, "mdb_dn2id_upgrade: mdb_cursor_get failed, %s (%d)\n",
   1622  1.3  christos 				mdb_strerror(rc), rc );
   1623  1.1      tron 			goto leave;
   1624  1.1      tron 		}
   1625  1.1      tron 		num[depth] = 1;
   1626  1.1      tron 
   1627  1.1      tron 		rc = mdb_cursor_count(mc, &dkids);
   1628  1.1      tron 		if (rc) {
   1629  1.1      tron 			Debug(LDAP_DEBUG_ANY, "mdb_dn2id_upgrade: mdb_cursor_count failed, %s (%d)\n",
   1630  1.3  christos 				mdb_strerror(rc), rc );
   1631  1.1      tron 			goto leave;
   1632  1.1      tron 		}
   1633  1.1      tron 		if (dkids > 1) {
   1634  1.1      tron 			rc = mdb_cursor_get(mc, &key, &data, MDB_NEXT_DUP);
   1635  1.1      tron down:
   1636  1.1      tron 			ptr = (unsigned char *)data.mv_data + data.mv_size - sizeof(ID);
   1637  1.1      tron 			memcpy(&id, ptr, sizeof(ID));
   1638  1.1      tron 			depth++;
   1639  1.1      tron 			memcpy(stack[depth].rdn, data.mv_data, data.mv_size);
   1640  1.1      tron 			stack[depth].len = data.mv_size;
   1641  1.1      tron 			continue;
   1642  1.1      tron 		}
   1643  1.1      tron 
   1644  1.1      tron 
   1645  1.1      tron 		/* pop: write updated count, advance to next node */
   1646  1.1      tron pop:
   1647  1.1      tron 		/* update superior counts */
   1648  1.1      tron 		if (depth)
   1649  1.1      tron 			num[depth-1] += num[depth];
   1650  1.1      tron 
   1651  1.1      tron 		key.mv_data = &id;
   1652  1.1      tron 		id = stack[depth-1].id;
   1653  1.1      tron 		data.mv_data = stack[depth].rdn;
   1654  1.1      tron 		data.mv_size = stack[depth].len;
   1655  1.1      tron 		rc = mdb_cursor_get(mc, &key, &data, MDB_GET_BOTH);
   1656  1.1      tron 		if (rc) {
   1657  1.1      tron 			Debug(LDAP_DEBUG_ANY, "mdb_dn2id_upgrade: mdb_cursor_get(BOTH) failed, %s (%d)\n",
   1658  1.3  christos 				mdb_strerror(rc), rc );
   1659  1.1      tron 			goto leave;
   1660  1.1      tron 		}
   1661  1.1      tron 		data.mv_data = stack[depth].rdn;
   1662  1.1      tron 		ptr = (unsigned char *)data.mv_data + data.mv_size;
   1663  1.1      tron 		memcpy(ptr, &num[depth], sizeof(ID));
   1664  1.1      tron 		data.mv_size += sizeof(ID);
   1665  1.1      tron 		rc = mdb_cursor_del(mc, 0);
   1666  1.1      tron 		if (rc) {
   1667  1.1      tron 			Debug(LDAP_DEBUG_ANY, "mdb_dn2id_upgrade: mdb_cursor_del failed, %s (%d)\n",
   1668  1.3  christos 				mdb_strerror(rc), rc );
   1669  1.1      tron 			goto leave;
   1670  1.1      tron 		}
   1671  1.1      tron 		rc = mdb_cursor_put(mc, &key, &data, 0);
   1672  1.1      tron 		if (rc) {
   1673  1.1      tron 			Debug(LDAP_DEBUG_ANY, "mdb_dn2id_upgrade: mdb_cursor_put failed, %s (%d)\n",
   1674  1.3  christos 				mdb_strerror(rc), rc );
   1675  1.1      tron 			goto leave;
   1676  1.1      tron 		}
   1677  1.1      tron 		count++;
   1678  1.1      tron #if 1
   1679  1.1      tron 		if (enable_meter)
   1680  1.1      tron 			lutil_meter_update(&meter, count, 0);
   1681  1.1      tron #else
   1682  1.1      tron 		{
   1683  1.1      tron 			int len;
   1684  1.1      tron 			ptr = data.mv_data;
   1685  1.1      tron 			len = (ptr[0] & 0x7f) << 8 | ptr[1];
   1686  1.1      tron 			printf("ID: %zu, %zu, %.*s\n", stack[depth].id, num[depth], len, ptr+2);
   1687  1.1      tron 		}
   1688  1.1      tron #endif
   1689  1.1      tron 		writes++;
   1690  1.1      tron 		if (writes == 1000) {
   1691  1.1      tron 			mdb_cursor_close(mc);
   1692  1.1      tron 			rc = mdb_txn_commit(mt);
   1693  1.1      tron 			if (rc) {
   1694  1.1      tron 				Debug(LDAP_DEBUG_ANY, "mdb_dn2id_upgrade: mdb_txn_commit failed, %s (%d)\n",
   1695  1.3  christos 					mdb_strerror(rc), rc );
   1696  1.1      tron 				goto leave;
   1697  1.1      tron 			}
   1698  1.1      tron 			rc = mdb_txn_begin(mi->mi_dbenv, NULL, 0, &mt);
   1699  1.1      tron 			if (rc) {
   1700  1.1      tron 				Debug(LDAP_DEBUG_ANY, "mdb_dn2id_upgrade: mdb_txn_begin(2) failed, %s (%d)\n",
   1701  1.3  christos 					mdb_strerror(rc), rc );
   1702  1.1      tron 				goto leave;
   1703  1.1      tron 			}
   1704  1.1      tron 			rc = mdb_cursor_open(mt, mi->mi_dbis[MDB_DN2ID], &mc);
   1705  1.1      tron 			if (rc) {
   1706  1.1      tron 				Debug(LDAP_DEBUG_ANY, "mdb_dn2id_upgrade: mdb_cursor_open(2) failed, %s (%d)\n",
   1707  1.3  christos 					mdb_strerror(rc), rc );
   1708  1.1      tron 				goto leave;
   1709  1.1      tron 			}
   1710  1.1      tron 			rc = mdb_cursor_get(mc, &key, &data, MDB_GET_BOTH);
   1711  1.1      tron 			if (rc) {
   1712  1.1      tron 				Debug(LDAP_DEBUG_ANY, "mdb_dn2id_upgrade: mdb_cursor_get(2) failed, %s (%d)\n",
   1713  1.3  christos 					mdb_strerror(rc), rc );
   1714  1.1      tron 				goto leave;
   1715  1.1      tron 			}
   1716  1.1      tron 			writes = 0;
   1717  1.1      tron 		}
   1718  1.1      tron 		depth--;
   1719  1.1      tron 
   1720  1.1      tron 		rc = mdb_cursor_get(mc, &key, &data, MDB_NEXT_DUP);
   1721  1.1      tron 		if (rc == 0)
   1722  1.1      tron 			goto down;
   1723  1.1      tron 		rc = 0;
   1724  1.1      tron 		if (depth)
   1725  1.1      tron 			goto pop;
   1726  1.1      tron 		else
   1727  1.1      tron 			break;
   1728  1.1      tron 	}
   1729  1.1      tron leave:
   1730  1.1      tron 	mdb_cursor_close(mc);
   1731  1.1      tron 	if (mt) {
   1732  1.1      tron 		int r2;
   1733  1.1      tron 		r2 = mdb_txn_commit(mt);
   1734  1.1      tron 		if (r2) {
   1735  1.1      tron 			Debug(LDAP_DEBUG_ANY, "mdb_dn2id_upgrade: mdb_txn_commit(2) failed, %s (%d)\n",
   1736  1.3  christos 				mdb_strerror(r2), r2 );
   1737  1.1      tron 			if (!rc)
   1738  1.1      tron 				rc = r2;
   1739  1.1      tron 		}
   1740  1.1      tron 	}
   1741  1.1      tron 	ch_free(num);
   1742  1.1      tron 	if (enable_meter) {
   1743  1.1      tron 		lutil_meter_update(&meter, count, 1);
   1744  1.1      tron 		lutil_meter_close(&meter);
   1745  1.1      tron 	}
   1746  1.1      tron 	return rc;
   1747  1.1      tron }
   1748