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