xref: /netbsd-src/external/bsd/openldap/dist/servers/slapd/back-wt/tools.c (revision 549b59ed3ccf0d36d3097190a0db27b770f3a839)
1 /*	$NetBSD: tools.c,v 1.2 2021/08/14 16:15:02 christos Exp $	*/
2 
3 /* OpenLDAP WiredTiger backend */
4 /* $OpenLDAP$ */
5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
6  *
7  * Copyright 2002-2021 The OpenLDAP Foundation.
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted only as authorized by the OpenLDAP
12  * Public License.
13  *
14  * A copy of this license is available in the file LICENSE in the
15  * top-level directory of the distribution or, alternatively, at
16  * <http://www.OpenLDAP.org/license.html>.
17  */
18 /* ACKNOWLEDGEMENTS:
19  * This work was developed by HAMANO Tsukasa <hamano@osstech.co.jp>
20  * based on back-bdb for inclusion in OpenLDAP Software.
21  * WiredTiger is a product of MongoDB Inc.
22  */
23 
24 #include <sys/cdefs.h>
25 __RCSID("$NetBSD: tools.c,v 1.2 2021/08/14 16:15:02 christos Exp $");
26 
27 #include "portable.h"
28 
29 #include <stdio.h>
30 #include <ac/string.h>
31 #include "back-wt.h"
32 #include "slap-config.h"
33 
34 typedef struct dn_id {
35     ID id;
36     struct berval dn;
37 } dn_id;
38 
39 #define HOLE_SIZE   4096
40 static dn_id hbuf[HOLE_SIZE], *holes = hbuf;
41 static unsigned nhmax = HOLE_SIZE;
42 static unsigned nholes;
43 
44 static int index_nattrs;
45 
46 static struct berval    *tool_base;
47 static int      tool_scope;
48 static Filter       *tool_filter;
49 static Entry        *tool_next_entry;
50 
51 static wt_ctx *wc;
52 static WT_CURSOR *reader;
53 static WT_ITEM item;
54 
55 int
wt_tool_entry_open(BackendDB * be,int mode)56 wt_tool_entry_open( BackendDB *be, int mode )
57 {
58     struct wt_info *wi = (struct wt_info *) be->be_private;
59 	WT_CONNECTION *conn = wi->wi_conn;
60 	int rc;
61 
62 	wc = wt_ctx_init(wi);
63     if( !wc ){
64 		Debug( LDAP_DEBUG_ANY,
65 			   LDAP_XSTRING(wt_tool_entry_open)
66 			   ": wt_ctx_get failed\n" );
67 		return -1;
68     }
69 
70 	rc = wc->session->open_cursor(wc->session, WT_TABLE_ID2ENTRY"(entry)"
71 								  ,NULL, NULL, &reader);
72 	if ( rc ) {
73 		Debug( LDAP_DEBUG_ANY,
74 			   LDAP_XSTRING(wt_tool_entry_open)
75 			   ": cursor open failed: %s (%d)\n",
76 			   wiredtiger_strerror(rc), rc );
77 		return -1;
78 	}
79 
80 	return 0;
81 }
82 
83 int
wt_tool_entry_close(BackendDB * be)84 wt_tool_entry_close( BackendDB *be )
85 {
86 	int rc;
87 
88 	if( reader ) {
89 		reader->close(reader);
90 		reader = NULL;
91 	}
92 
93 	wt_ctx_free(NULL, wc);
94 
95     if( nholes ) {
96         unsigned i;
97         fprintf( stderr, "Error, entries missing!\n");
98         for (i=0; i<nholes; i++) {
99             fprintf(stderr, "  entry %ld: %s\n",
100 					holes[i].id, holes[i].dn.bv_val);
101         }
102         return -1;
103     }
104 
105 	return 0;
106 }
107 
108 ID
wt_tool_entry_first_x(BackendDB * be,struct berval * base,int scope,Filter * f)109 wt_tool_entry_first_x( BackendDB *be,
110 					   struct berval *base,
111 					   int scope,
112 					   Filter *f )
113 {
114 	tool_base = base;
115 	tool_scope = scope;
116 	tool_filter = f;
117 
118 	return wt_tool_entry_next( be );
119 }
120 
121 ID
wt_tool_entry_next(BackendDB * be)122 wt_tool_entry_next( BackendDB *be )
123 {
124 	int rc;
125 	ID id;
126 
127 	rc = reader->next(reader);
128 	switch( rc ){
129 	case 0:
130 		break;
131 	case WT_NOTFOUND:
132 		return NOID;
133 	default:
134 		Debug( LDAP_DEBUG_ANY,
135 			   LDAP_XSTRING(wt_tool_entry_next)
136 			   ": next failed: %s (%d)\n",
137 			   wiredtiger_strerror(rc), rc );
138 		return NOID;
139 	}
140 
141 	rc = reader->get_key(reader, &id);
142 	if( rc ){
143 		Debug( LDAP_DEBUG_ANY,
144 			   LDAP_XSTRING(wt_tool_entry_next)
145 			   ": get_key failed: %s (%d)\n",
146 			   wiredtiger_strerror(rc), rc );
147 	}
148 
149 	rc = reader->get_value(reader, &item);
150 	if( rc ){
151 		Debug( LDAP_DEBUG_ANY,
152 			   LDAP_XSTRING(wt_tool_entry_next)
153 			   ": get_value failed: %s (%d)\n",
154 			   wiredtiger_strerror(rc), rc );
155 	}
156 	return id;
157 }
158 
159 static ber_len_t
entry_getlen(unsigned char ** buf)160 entry_getlen(unsigned char **buf)
161 {
162     ber_len_t len;
163     int i;
164 
165     len = *(*buf)++;
166     if (len <= 0x7f)
167         return len;
168     i = len & 0x7f;
169     len = 0;
170     for (;i > 0; i--) {
171         len <<= 8;
172         len |= *(*buf)++;
173     }
174     return len;
175 }
176 
wt_entry_header(WT_ITEM * item,EntryHeader * eh)177 int wt_entry_header(WT_ITEM *item, EntryHeader *eh){
178 	unsigned char *ptr = (unsigned char *)item->data;
179 
180     /* Some overlays can create empty entries
181      * so don't check for zeros here.
182      */
183 	eh->nattrs = entry_getlen(&ptr);
184     eh->nvals = entry_getlen(&ptr);
185     eh->data = (char *)ptr;
186 	return LDAP_SUCCESS;
187 }
188 
189 Entry *
wt_tool_entry_get(BackendDB * be,ID id)190 wt_tool_entry_get( BackendDB *be, ID id )
191 {
192 	Entry *e = NULL;
193 	static EntryHeader eh;
194 	int rc, eoff;
195 
196 	assert( be != NULL );
197 	assert( slapMode & SLAP_TOOL_MODE );
198 
199 	rc = wt_entry_header( &item,  &eh );
200 	assert( rc == 0 );
201 	eoff = eh.data - (char *)item.data;
202 
203 	eh.bv.bv_len = eh.nvals * sizeof( struct berval ) + item.size;
204 	eh.bv.bv_val = ch_realloc( eh.bv.bv_val, eh.bv.bv_len );
205     memset(eh.bv.bv_val, 0xff, eh.bv.bv_len);
206 	eh.data = eh.bv.bv_val + eh.nvals * sizeof( struct berval );
207     memcpy(eh.data, item.data, item.size);
208     eh.data += eoff;
209 
210 	rc = entry_decode( &eh, &e );
211 	assert( rc == 0 );
212 
213 	if( rc == LDAP_SUCCESS ) {
214 		e->e_id = id;
215 	}
216 
217 	return e;
218 }
219 
wt_tool_next_id(Operation * op,Entry * e,struct berval * text,int hole)220 static int wt_tool_next_id(
221     Operation *op,
222     Entry *e,
223     struct berval *text,
224     int hole )
225 {
226     struct wt_info *wi = (struct wt_info *) op->o_bd->be_private;
227 	struct berval dn = e->e_name;
228 	struct berval ndn = e->e_nname;
229 	struct berval pdn, npdn;
230 	int rc;
231 	ID id = 0;
232 	ID pid = 0;
233 
234     if(ndn.bv_len == 0){
235         e->e_id = 0;
236         return 0;
237     }
238 
239 	rc = wt_dn2id(op, wc->session, &ndn, &id);
240 	if(rc == 0){
241 		e->e_id = id;
242 	}else if( rc == WT_NOTFOUND ){
243 		if ( !be_issuffix( op->o_bd, &ndn ) ) {
244 			ID eid = e->e_id;
245 			dnParent( &dn, &pdn );
246 			dnParent( &ndn, &npdn );
247 			e->e_name = pdn;
248 			e->e_nname = npdn;
249 			rc = wt_tool_next_id( op, e, text, 1 );
250 			e->e_name = dn;
251 			e->e_nname = ndn;
252 			if ( rc ) {
253 				return rc;
254 			}
255 			/* If parent didn't exist, it was created just now
256 			 * and its ID is now in e->e_id. Make sure the current
257 			 * entry gets added under the new parent ID.
258 			 */
259 			if ( eid != e->e_id ) {
260 				pid = e->e_id;
261 			}
262 		}else{
263 			pid = id;
264 		}
265 		wt_next_id( op->o_bd, &e->e_id );
266 		rc = wt_dn2id_add(op, wc->session, pid, e);
267 		if( rc ){
268 			snprintf( text->bv_val, text->bv_len,
269 					  "wt_dn2id_add failed: %s (%d)",
270 					  wiredtiger_strerror(rc), rc );
271 			Debug( LDAP_DEBUG_ANY,
272 				   "=> wt_tool_next_id: %s\n", text->bv_val );
273 		}
274 
275 	}else if ( !hole ) {
276 		unsigned i, j;
277 		e->e_id = id;
278 
279 		for ( i=0; i<nholes; i++) {
280 			if ( holes[i].id == e->e_id ) {
281 				free(holes[i].dn.bv_val);
282 				for (j=i;j<nholes;j++) holes[j] = holes[j+1];
283 				holes[j].id = 0;
284 				nholes--;
285 				break;
286 			} else if ( holes[i].id > e->e_id ) {
287 				break;
288 			}
289 		}
290 	}
291     return rc;
292 }
293 
294 static int
wt_tool_index_add(Operation * op,wt_ctx * wc,Entry * e)295 wt_tool_index_add(
296     Operation *op,
297     wt_ctx *wc,
298     Entry *e )
299 {
300 	return wt_index_entry_add( op, wc, e );
301 }
302 
303 ID
wt_tool_entry_put(BackendDB * be,Entry * e,struct berval * text)304 wt_tool_entry_put( BackendDB *be, Entry *e, struct berval *text )
305 {
306     struct wt_info *wi = (struct wt_info *) be->be_private;
307     int rc;
308 
309     Operation op = {0};
310     Opheader ohdr = {0};
311 
312 	assert( slapMode & SLAP_TOOL_MODE );
313 	assert( text != NULL );
314 	assert( text->bv_val != NULL );
315 	assert( text->bv_val[0] == '\0' ); /* overconservative? */
316 
317     Debug( LDAP_DEBUG_TRACE,
318 		   "=> " LDAP_XSTRING(wt_tool_entry_put)
319 		   ": ( \"%s\" )\n", e->e_dn );
320 
321     rc = wc->session->begin_transaction(wc->session, NULL);
322 	if( rc ){
323 		Debug( LDAP_DEBUG_ANY,
324 			   LDAP_XSTRING(wt_dn2id_add)
325 			   ": begin_transaction failed: %s (%d)\n",
326 			   wiredtiger_strerror(rc), rc );
327 		return NOID;
328 	}
329 
330 	op.o_hdr = &ohdr;
331     op.o_bd = be;
332     op.o_tmpmemctx = NULL;
333     op.o_tmpmfuncs = &ch_mfuncs;
334 
335     rc = wt_tool_next_id( &op, e, text, 0 );
336 	if( rc != 0 ) {
337         snprintf( text->bv_val, text->bv_len,
338 				  "wt_tool_next_id failed: %s (%d)",
339 				  wiredtiger_strerror(rc), rc );
340         Debug( LDAP_DEBUG_ANY,
341 			   "=> " LDAP_XSTRING(wt_tool_entry_put) ": %s\n",
342 			   text->bv_val );
343 		goto done;
344 	}
345 
346 	rc = wt_id2entry_add( &op, wc->session, e );
347 	if( rc != 0 ) {
348         snprintf( text->bv_val, text->bv_len,
349 				  "id2entry_add failed: %s (%d)",
350 				  wiredtiger_strerror(rc), rc );
351         Debug( LDAP_DEBUG_ANY,
352 			   "=> " LDAP_XSTRING(wt_tool_entry_put) ": %s\n",
353 			   text->bv_val );
354         goto done;
355     }
356 
357 	rc = wt_tool_index_add( &op, wc, e );
358     if( rc != 0 ) {
359         snprintf( text->bv_val, text->bv_len,
360 				  "index_entry_add failed: %s (%d)",
361 				  rc == LDAP_OTHER ? "Internal error" :
362 				  wiredtiger_strerror(rc), rc );
363         Debug( LDAP_DEBUG_ANY,
364 			   "=> " LDAP_XSTRING(wt_tool_entry_put) ": %s\n",
365 			   text->bv_val );
366         goto done;
367     }
368 
369 done:
370 	if ( rc == 0 ){
371 		rc = wc->session->commit_transaction(wc->session, NULL);
372 		if( rc != 0 ) {
373 			snprintf( text->bv_val, text->bv_len,
374 					  "txn_commit failed: %s (%d)",
375 					  wiredtiger_strerror(rc), rc );
376 			Debug( LDAP_DEBUG_ANY,
377 				   "=> " LDAP_XSTRING(wt_tool_entry_put) ": %s\n",
378 				   text->bv_val );
379             e->e_id = NOID;
380 		}
381 	}else{
382 		rc = wc->session->rollback_transaction(wc->session, NULL);
383 		snprintf( text->bv_val, text->bv_len,
384 				  "txn_aborted! %s (%d)",
385 				  rc == LDAP_OTHER ? "Internal error" :
386 				  wiredtiger_strerror(rc), rc );
387         Debug( LDAP_DEBUG_ANY,
388 			   "=> " LDAP_XSTRING(wt_tool_entry_put) ": %s\n",
389 			   text->bv_val );
390         e->e_id = NOID;
391 	}
392 
393 	return e->e_id;
394 }
395 
wt_tool_entry_reindex(BackendDB * be,ID id,AttributeDescription ** adv)396 int wt_tool_entry_reindex(
397 	BackendDB *be,
398 	ID id,
399 	AttributeDescription **adv )
400 {
401 	struct wt_info *wi = (struct wt_info *) be->be_private;
402 	int rc;
403 	Entry *e;
404 	Operation op = {0};
405 	Opheader ohdr = {0};
406 
407 	Debug( LDAP_DEBUG_ARGS,
408 		   "=> " LDAP_XSTRING(wt_tool_entry_reindex) "( %ld )\n",
409 		   (long) id );
410 	assert( tool_base == NULL );
411 	assert( tool_filter == NULL );
412 
413 	/* No indexes configured, nothing to do. Could return an
414      * error here to shortcut things.
415      */
416 	if (!wi->wi_attrs) {
417 		return 0;
418 	}
419 
420 	/* Check for explicit list of attrs to index */
421 	if ( adv ) {
422 		int i, j, n;
423 
424 		if ( wi->wi_attrs[0]->ai_desc != adv[0] ) {
425 			/* count */
426 			for ( n = 0; adv[n]; n++ ) ;
427 
428 			/* insertion sort */
429 			for ( i = 0; i < n; i++ ) {
430 				AttributeDescription *ad = adv[i];
431 				for ( j = i-1; j>=0; j--) {
432 					if ( SLAP_PTRCMP( adv[j], ad ) <= 0 ) break;
433 					adv[j+1] = adv[j];
434 				}
435 				adv[j+1] = ad;
436 			}
437 		}
438 
439 		for ( i = 0; adv[i]; i++ ) {
440 			if ( wi->wi_attrs[i]->ai_desc != adv[i] ) {
441 				for ( j = i+1; j < wi->wi_nattrs; j++ ) {
442 					if ( wi->wi_attrs[j]->ai_desc == adv[i] ) {
443 						AttrInfo *ai = wi->wi_attrs[i];
444 						wi->wi_attrs[i] = wi->wi_attrs[j];
445 						wi->wi_attrs[j] = ai;
446 						break;
447 					}
448 				}
449 				if ( j == wi->wi_nattrs ) {
450 					Debug( LDAP_DEBUG_ANY,
451 						   LDAP_XSTRING(wt_tool_entry_reindex)
452 						   ": no index configured for %s\n",
453 						   adv[i]->ad_cname.bv_val );
454 					return -1;
455 				}
456 			}
457 		}
458 		wi->wi_nattrs = i;
459 	}
460 
461 	e = wt_tool_entry_get( be, id );
462 
463 	if( e == NULL ) {
464 		Debug( LDAP_DEBUG_ANY,
465 			   LDAP_XSTRING(wt_tool_entry_reindex)
466 			   ": could not locate id=%ld\n",
467 			   (long) id );
468 		return -1;
469 	}
470 
471 	op.o_hdr = &ohdr;
472 	op.o_bd = be;
473 	op.o_tmpmemctx = NULL;
474 	op.o_tmpmfuncs = &ch_mfuncs;
475 
476 	rc = wc->session->begin_transaction(wc->session, NULL);
477 	if( rc ){
478 		Debug( LDAP_DEBUG_ANY,
479 			   LDAP_XSTRING(wt_dn2id_add)
480 			   ": begin_transaction failed: %s (%d)\n",
481 			   wiredtiger_strerror(rc), rc );
482 		goto done;
483 	}
484 	Debug( LDAP_DEBUG_TRACE,
485 		   "=> " LDAP_XSTRING(wt_tool_entry_reindex) "( %ld, \"%s\" )\n",
486 		   (long) id, e->e_dn );
487 
488 	rc = wt_tool_index_add( &op, wc, e );
489 
490 done:
491 	if ( rc == 0 ){
492 		rc = wc->session->commit_transaction(wc->session, NULL);
493 		if( rc ) {
494 			Debug( LDAP_DEBUG_ANY,
495 				   "=> " LDAP_XSTRING(wt_tool_entry_reindex)
496 				   "commit_transaction failed: %s (%d)\n",
497 				   wiredtiger_strerror(rc), rc );
498 		}
499 	}else{
500 		rc = wc->session->rollback_transaction(wc->session, NULL);
501 		Debug( LDAP_DEBUG_ANY,
502 			   "=> " LDAP_XSTRING(wt_tool_entry_reindex)
503 			   ": rollback transaction %s (%d)\n",
504 			   wiredtiger_strerror(rc), rc );
505 	}
506 
507 	wt_entry_release( &op, e, 0 );
508 
509 	return rc;
510 }
511 
512 /*
513  * Local variables:
514  * indent-tabs-mode: t
515  * tab-width: 4
516  * c-basic-offset: 4
517  * End:
518  */
519