init.c revision 1.3 1 /* $NetBSD: init.c,v 1.3 2025/09/05 21:16:32 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-2024 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 (at) 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: init.c,v 1.3 2025/09/05 21:16:32 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 static int
35 wt_db_init( BackendDB *be, ConfigReply *cr )
36 {
37 struct wt_info *wi;
38
39 Debug( LDAP_DEBUG_TRACE, "wt_db_init: Initializing wt backend\n" );
40
41 /* allocate backend-database-specific stuff */
42 wi = ch_calloc( 1, sizeof(struct wt_info) );
43 wi->wi_home = ch_strdup( SLAPD_DEFAULT_DB_DIR );
44 wi->wi_config = ch_calloc( 1, WT_CONFIG_MAX + 1);
45 if ( slapMode & SLAP_TOOL_READONLY ) {
46 strcpy(wi->wi_config, "readonly");
47 } else {
48 strcpy(wi->wi_config, "create");
49 }
50 wi->wi_lastid = 0;
51 wi->wi_search_stack_depth = DEFAULT_SEARCH_STACK_DEPTH;
52 wi->wi_search_stack = NULL;
53 wi->wi_flags = WT_USE_IDLCACHE;
54
55 be->be_private = wi;
56 be->be_cf_ocs = be->bd_info->bi_cf_ocs;
57
58 return LDAP_SUCCESS;
59 }
60
61 static int
62 wt_db_open( BackendDB *be, ConfigReply *cr )
63 {
64 struct wt_info *wi = (struct wt_info *) be->be_private;
65 int rc;
66 struct stat st;
67 WT_SESSION *session = NULL;
68 WT_SESSION *cache_session = NULL;
69
70 if ( be->be_suffix == NULL ) {
71 Debug( LDAP_DEBUG_ANY, "wt_db_open: need suffix.\n" );
72 return -1;
73 }
74
75 Debug( LDAP_DEBUG_ARGS,
76 "wt_db_open: \"%s\", home=%s, config=%s\n",
77 be->be_suffix[0].bv_val, wi->wi_home, wi->wi_config );
78
79 /* Check existence of home. Any error means trouble */
80 rc = stat( wi->wi_home, &st );
81 if( rc ) {
82 int saved_errno = errno;
83 Debug( LDAP_DEBUG_ANY,
84 "wt_db_open: database \"%s\": "
85 "cannot access database directory \"%s\" (%d).\n",
86 be->be_suffix[0].bv_val, wi->wi_home, saved_errno );
87 return -1;
88 }
89
90 /* back-wt is always clean */
91 be->be_flags |= SLAP_DBFLAG_CLEAN;
92
93 /* Open and create database */
94 rc = wiredtiger_open(wi->wi_home, NULL,
95 wi->wi_config, &wi->wi_conn);
96 if( rc ) {
97 int saved_errno = errno;
98 Debug( LDAP_DEBUG_ANY,
99 "wt_db_open: database \"%s\": "
100 "cannot open database \"%s\" (%d).\n",
101 be->be_suffix[0].bv_val, wi->wi_home, saved_errno );
102 return -1;
103 }
104
105 rc = wi->wi_conn->open_session(wi->wi_conn, NULL, NULL, &session);
106 if( rc ) {
107 Debug( LDAP_DEBUG_ANY,
108 "wt_db_open: database \"%s\": "
109 "cannot open session: \"%s\"\n",
110 be->be_suffix[0].bv_val, wiredtiger_strerror(rc) );
111 return -1;
112 }
113
114 if ( slapMode & SLAP_TOOL_READONLY ) {
115 goto readonly;
116 }
117
118 /* checking for obsolete table */
119 rc = session->verify(session, WT_INDEX_REVDN, NULL);
120 if ( !rc ) {
121 Debug( LDAP_DEBUG_ANY,
122 "wt_db_open: database \"%s\": "
123 "incompatible wiredtiger table, please restore from LDIF.\n",
124 be->be_suffix[0].bv_val );
125 return -1;
126 }
127
128 /* create tables and indexes */
129 rc = session->create(session,
130 WT_TABLE_ID2ENTRY,
131 "key_format=Q,"
132 "value_format=Su,"
133 "columns=(id,dn,entry)");
134 if( rc ) {
135 Debug( LDAP_DEBUG_ANY,
136 "wt_db_open: database \"%s\": "
137 "cannot create entry table: \"%s\"\n",
138 be->be_suffix[0].bv_val, wiredtiger_strerror(rc) );
139 return -1;
140 }
141
142 rc = session->create(session,
143 WT_TABLE_DN2ID,
144 "key_format=S,"
145 "value_format=SQQ,"
146 "columns=(revdn,ndn,id,pid)");
147 if( rc ) {
148 Debug( LDAP_DEBUG_ANY,
149 "wt_db_open: database \"%s\": "
150 "cannot create entry table: \"%s\"\n",
151 be->be_suffix[0].bv_val, wiredtiger_strerror(rc) );
152 return -1;
153 }
154
155 /* not using dn2id index for id2entry table */
156 rc = session->create(session, WT_INDEX_DN, "columns=(dn)");
157 if( rc ) {
158 Debug( LDAP_DEBUG_ANY,
159 "wt_db_open: database \"%s\": "
160 "cannot create dn index: \"%s\"\n",
161 be->be_suffix[0].bv_val, wiredtiger_strerror(rc) );
162 return -1;
163 }
164
165 rc = session->create(session, WT_INDEX_PID, "columns=(pid)");
166 if( rc ) {
167 Debug( LDAP_DEBUG_ANY,
168 "wt_db_open: database \"%s\": "
169 "cannot create pid index: \"%s\"\n",
170 be->be_suffix[0].bv_val, wiredtiger_strerror(rc) );
171 return -1;
172 }
173
174 rc = session->create(session, WT_INDEX_NDN, "columns=(ndn)");
175 if( rc ) {
176 Debug( LDAP_DEBUG_ANY,
177 "wt_db_open: database \"%s\": "
178 "cannot create ndn index: \"%s\"\n",
179 be->be_suffix[0].bv_val, wiredtiger_strerror(rc) );
180 return -1;
181 }
182
183 /* open in-memory database for idlcache */
184 rc = wiredtiger_open(be->be_suffix[0].bv_val, NULL,
185 "in_memory=true", &wi->wi_cache);
186 if( rc ) {
187 Debug( LDAP_DEBUG_ANY,
188 "wt_db_open: database \"%s\": "
189 "cannot open database for cache (%s).\n",
190 be->be_suffix[0].bv_val, wiredtiger_strerror(rc) );
191 return -1;
192 }
193
194 rc = wi->wi_cache->open_session(wi->wi_cache, NULL, NULL, &cache_session);
195 if( rc ) {
196 Debug( LDAP_DEBUG_ANY,
197 "wt_db_open: database \"%s\": "
198 "cannot open session for cache: \"%s\"\n",
199 be->be_suffix[0].bv_val, wiredtiger_strerror(rc) );
200 return -1;
201 }
202
203 rc = cache_session->create(cache_session,
204 WT_TABLE_IDLCACHE,
205 "key_format=Sb,"
206 "value_format=u,"
207 "columns=(ndn,scope,idl)");
208 if( rc ) {
209 Debug( LDAP_DEBUG_ANY,
210 "wt_db_open: database \"%s\": "
211 "cannot create idlcache table: \"%s\"\n",
212 be->be_suffix[0].bv_val, wiredtiger_strerror(rc) );
213 return -1;
214 }
215
216 readonly:
217 rc = wt_last_id( be, session, &wi->wi_lastid);
218 if (rc) {
219 snprintf( cr->msg, sizeof(cr->msg), "database \"%s\": "
220 "last_id() failed: %s(%d).",
221 be->be_suffix[0].bv_val, wiredtiger_strerror(rc), rc );
222 Debug( LDAP_DEBUG_ANY, "wt_db_open: %s\n", cr->msg );
223 return rc;
224 }
225
226 if (session) {
227 session->close(session, NULL);
228 }
229 if (cache_session) {
230 cache_session->close(cache_session, NULL);
231 }
232
233 wi->wi_flags |= WT_IS_OPEN;
234 return LDAP_SUCCESS;
235 }
236
237 static int
238 wt_db_close( BackendDB *be, ConfigReply *cr )
239 {
240 struct wt_info *wi = (struct wt_info *) be->be_private;
241 int rc;
242
243 if ( wi->wi_cache ) {
244 rc = wi->wi_cache->close(wi->wi_cache, NULL);
245 if( rc ) {
246 Debug( LDAP_DEBUG_ANY,
247 "wt_db_close: cannot close cache database (%d).\n", rc );
248 return -1;
249 }
250 }
251
252 if ( wi->wi_conn ) {
253 rc = wi->wi_conn->close(wi->wi_conn, NULL);
254 if( rc ) {
255 Debug( LDAP_DEBUG_ANY,
256 "wt_db_close: cannot close database (%d).\n", rc );
257 return -1;
258 }
259 wi->wi_flags &= ~WT_IS_OPEN;
260 }
261
262 return LDAP_SUCCESS;
263 }
264
265 static int
266 wt_db_destroy( Backend *be, ConfigReply *cr )
267 {
268 struct wt_info *wi = (struct wt_info *) be->be_private;
269
270 if( wi->wi_home ) {
271 ch_free( wi->wi_home );
272 wi->wi_home = NULL;
273 }
274
275 if( wi->wi_config ) {
276 ch_free( wi->wi_config );
277 wi->wi_config = NULL;
278 }
279
280 wt_attr_index_destroy( wi );
281 ch_free( wi );
282 be->be_private = NULL;
283
284 return LDAP_SUCCESS;
285 }
286
287 int
288 wt_back_initialize( BackendInfo *bi )
289 {
290 static const char *controls[] = {
291 LDAP_CONTROL_ASSERT,
292 LDAP_CONTROL_MANAGEDSAIT,
293 LDAP_CONTROL_NOOP,
294 LDAP_CONTROL_PAGEDRESULTS,
295 LDAP_CONTROL_PRE_READ,
296 LDAP_CONTROL_POST_READ,
297 LDAP_CONTROL_SUBENTRIES,
298 LDAP_CONTROL_X_PERMISSIVE_MODIFY,
299 #ifdef LDAP_X_TXN
300 LDAP_CONTROL_X_TXN_SPEC,
301 #endif
302 NULL
303 };
304
305 /* initialize the database system */
306 Debug( LDAP_DEBUG_TRACE,
307 "wt_back_initialize: initialize WiredTiger backend\n" );
308
309 bi->bi_flags |=
310 SLAP_BFLAG_INCREMENT |
311 SLAP_BFLAG_SUBENTRIES |
312 SLAP_BFLAG_ALIASES |
313 SLAP_BFLAG_REFERRALS;
314
315 bi->bi_controls = (char **)controls;
316
317 /* version check */
318 Debug( LDAP_DEBUG_TRACE,
319 "wt_back_initialize: %s\n",
320 wiredtiger_version(NULL, NULL, NULL) );
321
322 bi->bi_open = 0;
323 bi->bi_close = 0;
324 bi->bi_config = 0;
325 bi->bi_destroy = 0;
326
327 bi->bi_db_init = wt_db_init;
328 bi->bi_db_config = config_generic_wrapper;
329 bi->bi_db_open = wt_db_open;
330 bi->bi_db_close = wt_db_close;
331 bi->bi_db_destroy = wt_db_destroy;
332
333 bi->bi_op_add = wt_add;
334 bi->bi_op_bind = wt_bind;
335 bi->bi_op_unbind = 0;
336 bi->bi_op_search = wt_search;
337 bi->bi_op_compare = wt_compare;
338 bi->bi_op_modify = wt_modify;
339 bi->bi_op_modrdn = wt_modrdn;
340 bi->bi_op_delete = wt_delete;
341 bi->bi_op_abandon = 0;
342
343 bi->bi_extended = wt_extended;
344 #ifdef LDAP_X_TXN
345 bi->bi_op_txn = 0;
346 #endif
347
348 bi->bi_chk_referrals = 0;
349 bi->bi_operational = wt_operational;
350
351 bi->bi_has_subordinates = wt_hasSubordinates;
352 bi->bi_entry_release_rw = wt_entry_release;
353 bi->bi_entry_get_rw = wt_entry_get;
354
355 bi->bi_tool_entry_open = wt_tool_entry_open;
356 bi->bi_tool_entry_close = wt_tool_entry_close;
357 bi->bi_tool_entry_first = backend_tool_entry_first;
358 bi->bi_tool_entry_first_x = wt_tool_entry_first_x;
359 bi->bi_tool_entry_next = wt_tool_entry_next;
360 bi->bi_tool_entry_get = wt_tool_entry_get;
361 bi->bi_tool_entry_put = wt_tool_entry_put;
362 bi->bi_tool_entry_reindex = wt_tool_entry_reindex;
363 bi->bi_tool_sync = 0;
364 bi->bi_tool_dn2id_get = wt_tool_dn2id_get;
365 bi->bi_tool_entry_modify = wt_tool_entry_modify;
366
367 #if LDAP_VENDOR_VERSION_MINOR == X || LDAP_VENDOR_VERSION_MINOR >= 5
368 bi->bi_tool_entry_delete = wt_tool_entry_delete;
369 #endif
370
371 bi->bi_connection_init = 0;
372 bi->bi_connection_destroy = 0;
373
374 return wt_back_init_cf( bi );
375 }
376
377 #if SLAPD_WT == SLAPD_MOD_DYNAMIC
378
379 /* conditionally define the init_module() function */
380 SLAP_BACKEND_INIT_MODULE( wt )
381
382 #endif /* SLAPD_WT == SLAPD_MOD_DYNAMIC */
383
384 /*
385 * Local variables:
386 * indent-tabs-mode: t
387 * tab-width: 4
388 * c-basic-offset: 4
389 * End:
390 */
391