tools.c revision 1.4 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