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