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