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