1 /* init.cpp - initialize ndb backend */ 2 /* OpenLDAP: pkg/ldap/servers/slapd/back-ndb/init.cpp,v 1.4.2.4 2010/04/13 20:23:35 kurt Exp */ 3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 4 * 5 * Copyright 2008-2010 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 initially developed by Howard Chu for inclusion 18 * in OpenLDAP Software. This work was sponsored by MySQL. 19 */ 20 21 #include "portable.h" 22 23 #include <stdio.h> 24 #include <ac/string.h> 25 #include <ac/unistd.h> 26 #include <ac/stdlib.h> 27 #include <ac/errno.h> 28 #include <sys/stat.h> 29 #include "back-ndb.h" 30 #include <lutil.h> 31 #include "config.h" 32 33 extern "C" { 34 static BI_db_init ndb_db_init; 35 static BI_db_close ndb_db_close; 36 static BI_db_open ndb_db_open; 37 static BI_db_destroy ndb_db_destroy; 38 } 39 40 static struct berval ndb_optable = BER_BVC("OL_opattrs"); 41 42 static struct berval ndb_opattrs[] = { 43 BER_BVC("structuralObjectClass"), 44 BER_BVC("entryUUID"), 45 BER_BVC("creatorsName"), 46 BER_BVC("createTimestamp"), 47 BER_BVC("entryCSN"), 48 BER_BVC("modifiersName"), 49 BER_BVC("modifyTimestamp"), 50 BER_BVNULL 51 }; 52 53 static int ndb_oplens[] = { 54 0, /* structuralOC, default */ 55 36, /* entryUUID */ 56 0, /* creatorsName, default */ 57 26, /* createTimestamp */ 58 40, /* entryCSN */ 59 0, /* modifiersName, default */ 60 26, /* modifyTimestamp */ 61 -1 62 }; 63 64 static Uint32 ndb_lastrow[1]; 65 NdbInterpretedCode *ndb_lastrow_code; 66 67 static int 68 ndb_db_init( BackendDB *be, ConfigReply *cr ) 69 { 70 struct ndb_info *ni; 71 int rc = 0; 72 73 Debug( LDAP_DEBUG_TRACE, 74 LDAP_XSTRING(ndb_db_init) ": Initializing ndb database\n", 75 0, 0, 0 ); 76 77 /* allocate backend-database-specific stuff */ 78 ni = (struct ndb_info *) ch_calloc( 1, sizeof(struct ndb_info) ); 79 80 be->be_private = ni; 81 be->be_cf_ocs = be->bd_info->bi_cf_ocs; 82 83 ni->ni_search_stack_depth = DEFAULT_SEARCH_STACK_DEPTH; 84 85 ldap_pvt_thread_rdwr_init( &ni->ni_ai_rwlock ); 86 ldap_pvt_thread_rdwr_init( &ni->ni_oc_rwlock ); 87 ldap_pvt_thread_mutex_init( &ni->ni_conn_mutex ); 88 89 #ifdef DO_MONITORING 90 rc = ndb_monitor_db_init( be ); 91 #endif 92 93 return rc; 94 } 95 96 static int 97 ndb_db_close( BackendDB *be, ConfigReply *cr ); 98 99 static int 100 ndb_db_open( BackendDB *be, ConfigReply *cr ) 101 { 102 struct ndb_info *ni = (struct ndb_info *) be->be_private; 103 char sqlbuf[BUFSIZ], *ptr; 104 int rc, i; 105 106 if ( be->be_suffix == NULL ) { 107 snprintf( cr->msg, sizeof( cr->msg ), 108 "ndb_db_open: need suffix" ); 109 Debug( LDAP_DEBUG_ANY, "%s\n", 110 cr->msg, 0, 0 ); 111 return -1; 112 } 113 114 Debug( LDAP_DEBUG_ARGS, 115 LDAP_XSTRING(ndb_db_open) ": \"%s\"\n", 116 be->be_suffix[0].bv_val, 0, 0 ); 117 118 if ( ni->ni_nconns < 1 ) 119 ni->ni_nconns = 1; 120 121 ni->ni_cluster = (Ndb_cluster_connection **)ch_calloc( ni->ni_nconns, sizeof( Ndb_cluster_connection *)); 122 for ( i=0; i<ni->ni_nconns; i++ ) { 123 ni->ni_cluster[i] = new Ndb_cluster_connection( ni->ni_connectstr ); 124 rc = ni->ni_cluster[i]->connect( 20, 5, 1 ); 125 if ( rc ) { 126 snprintf( cr->msg, sizeof( cr->msg ), 127 "ndb_db_open: ni_cluster[%d]->connect failed (%d)", 128 i, rc ); 129 goto fail; 130 } 131 } 132 for ( i=0; i<ni->ni_nconns; i++ ) { 133 rc = ni->ni_cluster[i]->wait_until_ready( 30, 30 ); 134 if ( rc ) { 135 snprintf( cr->msg, sizeof( cr->msg ), 136 "ndb_db_open: ni_cluster[%d]->wait failed (%d)", 137 i, rc ); 138 goto fail; 139 } 140 } 141 142 mysql_init( &ni->ni_sql ); 143 if ( !mysql_real_connect( &ni->ni_sql, ni->ni_hostname, ni->ni_username, ni->ni_password, 144 "", ni->ni_port, ni->ni_socket, ni->ni_clflag )) { 145 snprintf( cr->msg, sizeof( cr->msg ), 146 "ndb_db_open: mysql_real_connect failed, %s (%d)", 147 mysql_error(&ni->ni_sql), mysql_errno(&ni->ni_sql) ); 148 rc = -1; 149 goto fail; 150 } 151 152 sprintf( sqlbuf, "CREATE DATABASE IF NOT EXISTS %s", ni->ni_dbname ); 153 rc = mysql_query( &ni->ni_sql, sqlbuf ); 154 if ( rc ) { 155 snprintf( cr->msg, sizeof( cr->msg ), 156 "ndb_db_open: CREATE DATABASE %s failed, %s (%d)", 157 ni->ni_dbname, mysql_error(&ni->ni_sql), mysql_errno(&ni->ni_sql) ); 158 goto fail; 159 } 160 161 sprintf( sqlbuf, "USE %s", ni->ni_dbname ); 162 rc = mysql_query( &ni->ni_sql, sqlbuf ); 163 if ( rc ) { 164 snprintf( cr->msg, sizeof( cr->msg ), 165 "ndb_db_open: USE DATABASE %s failed, %s (%d)", 166 ni->ni_dbname, mysql_error(&ni->ni_sql), mysql_errno(&ni->ni_sql) ); 167 goto fail; 168 } 169 170 ptr = sqlbuf; 171 ptr += sprintf( ptr, "CREATE TABLE IF NOT EXISTS " DN2ID_TABLE " (" 172 "eid bigint unsigned NOT NULL, " 173 "object_classes VARCHAR(1024) NOT NULL, " 174 "a0 VARCHAR(128) NOT NULL DEFAULT '', " 175 "a1 VARCHAR(128) NOT NULL DEFAULT '', " 176 "a2 VARCHAR(128) NOT NULL DEFAULT '', " 177 "a3 VARCHAR(128) NOT NULL DEFAULT '', " 178 "a4 VARCHAR(128) NOT NULL DEFAULT '', " 179 "a5 VARCHAR(128) NOT NULL DEFAULT '', " 180 "a6 VARCHAR(128) NOT NULL DEFAULT '', " 181 "a7 VARCHAR(128) NOT NULL DEFAULT '', " 182 "a8 VARCHAR(128) NOT NULL DEFAULT '', " 183 "a9 VARCHAR(128) NOT NULL DEFAULT '', " 184 "a10 VARCHAR(128) NOT NULL DEFAULT '', " 185 "a11 VARCHAR(128) NOT NULL DEFAULT '', " 186 "a12 VARCHAR(128) NOT NULL DEFAULT '', " 187 "a13 VARCHAR(128) NOT NULL DEFAULT '', " 188 "a14 VARCHAR(128) NOT NULL DEFAULT '', " 189 "a15 VARCHAR(128) NOT NULL DEFAULT '', " 190 "PRIMARY KEY (a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15), " 191 "UNIQUE KEY eid (eid) USING HASH" ); 192 /* Create index columns */ 193 if ( ni->ni_attridxs ) { 194 ListNode *ln; 195 int newcol = 0; 196 197 *ptr++ = ','; 198 *ptr++ = ' '; 199 for ( ln = ni->ni_attridxs; ln; ln=ln->ln_next ) { 200 NdbAttrInfo *ai = (NdbAttrInfo *)ln->ln_data; 201 ptr += sprintf( ptr, "`%s` VARCHAR(%d), ", 202 ai->na_name.bv_val, ai->na_len ); 203 } 204 ptr = lutil_strcopy(ptr, "KEY " INDEX_NAME " (" ); 205 206 for ( ln = ni->ni_attridxs; ln; ln=ln->ln_next ) { 207 NdbAttrInfo *ai = (NdbAttrInfo *)ln->ln_data; 208 if ( newcol ) *ptr++ = ','; 209 *ptr++ = '`'; 210 ptr = lutil_strcopy( ptr, ai->na_name.bv_val ); 211 *ptr++ = '`'; 212 ai->na_ixcol = newcol + 18; 213 newcol++; 214 } 215 *ptr++ = ')'; 216 } 217 strcpy( ptr, ") ENGINE=ndb" ); 218 rc = mysql_query( &ni->ni_sql, sqlbuf ); 219 if ( rc ) { 220 snprintf( cr->msg, sizeof( cr->msg ), 221 "ndb_db_open: CREATE TABLE " DN2ID_TABLE " failed, %s (%d)", 222 mysql_error(&ni->ni_sql), mysql_errno(&ni->ni_sql) ); 223 goto fail; 224 } 225 226 rc = mysql_query( &ni->ni_sql, "CREATE TABLE IF NOT EXISTS " NEXTID_TABLE " (" 227 "a bigint unsigned AUTO_INCREMENT PRIMARY KEY ) ENGINE=ndb" ); 228 if ( rc ) { 229 snprintf( cr->msg, sizeof( cr->msg ), 230 "ndb_db_open: CREATE TABLE " NEXTID_TABLE " failed, %s (%d)", 231 mysql_error(&ni->ni_sql), mysql_errno(&ni->ni_sql) ); 232 goto fail; 233 } 234 235 { 236 NdbOcInfo *oci; 237 238 rc = ndb_aset_get( ni, &ndb_optable, ndb_opattrs, &oci ); 239 if ( rc ) { 240 snprintf( cr->msg, sizeof( cr->msg ), 241 "ndb_db_open: ndb_aset_get( %s ) failed (%d)", 242 ndb_optable.bv_val, rc ); 243 goto fail; 244 } 245 for ( i=0; ndb_oplens[i] >= 0; i++ ) { 246 if ( ndb_oplens[i] ) 247 oci->no_attrs[i]->na_len = ndb_oplens[i]; 248 } 249 rc = ndb_aset_create( ni, oci ); 250 if ( rc ) { 251 snprintf( cr->msg, sizeof( cr->msg ), 252 "ndb_db_open: ndb_aset_create( %s ) failed (%d)", 253 ndb_optable.bv_val, rc ); 254 goto fail; 255 } 256 ni->ni_opattrs = oci; 257 } 258 /* Create attribute sets */ 259 { 260 ListNode *ln; 261 262 for ( ln = ni->ni_attrsets; ln; ln=ln->ln_next ) { 263 NdbOcInfo *oci = (NdbOcInfo *)ln->ln_data; 264 rc = ndb_aset_create( ni, oci ); 265 if ( rc ) { 266 snprintf( cr->msg, sizeof( cr->msg ), 267 "ndb_db_open: ndb_aset_create( %s ) failed (%d)", 268 oci->no_name.bv_val, rc ); 269 goto fail; 270 } 271 } 272 } 273 /* Initialize any currently used objectClasses */ 274 { 275 Ndb *ndb; 276 const NdbDictionary::Dictionary *myDict; 277 278 ndb = new Ndb( ni->ni_cluster[0], ni->ni_dbname ); 279 ndb->init(1024); 280 281 myDict = ndb->getDictionary(); 282 ndb_oc_read( ni, myDict ); 283 delete ndb; 284 } 285 286 #ifdef DO_MONITORING 287 /* monitor setup */ 288 rc = ndb_monitor_db_open( be ); 289 if ( rc != 0 ) { 290 goto fail; 291 } 292 #endif 293 294 return 0; 295 296 fail: 297 Debug( LDAP_DEBUG_ANY, "%s\n", 298 cr->msg, 0, 0 ); 299 ndb_db_close( be, NULL ); 300 return rc; 301 } 302 303 static int 304 ndb_db_close( BackendDB *be, ConfigReply *cr ) 305 { 306 int i; 307 struct ndb_info *ni = (struct ndb_info *) be->be_private; 308 309 mysql_close( &ni->ni_sql ); 310 if ( ni->ni_cluster ) { 311 for ( i=0; i<ni->ni_nconns; i++ ) { 312 if ( ni->ni_cluster[i] ) { 313 delete ni->ni_cluster[i]; 314 ni->ni_cluster[i] = NULL; 315 } 316 } 317 ch_free( ni->ni_cluster ); 318 ni->ni_cluster = NULL; 319 } 320 321 #ifdef DO_MONITORING 322 /* monitor handling */ 323 (void)ndb_monitor_db_close( be ); 324 #endif 325 326 return 0; 327 } 328 329 static int 330 ndb_db_destroy( BackendDB *be, ConfigReply *cr ) 331 { 332 struct ndb_info *ni = (struct ndb_info *) be->be_private; 333 334 #ifdef DO_MONITORING 335 /* monitor handling */ 336 (void)ndb_monitor_db_destroy( be ); 337 #endif 338 339 ldap_pvt_thread_mutex_destroy( &ni->ni_conn_mutex ); 340 ldap_pvt_thread_rdwr_destroy( &ni->ni_ai_rwlock ); 341 ldap_pvt_thread_rdwr_destroy( &ni->ni_oc_rwlock ); 342 343 ch_free( ni ); 344 be->be_private = NULL; 345 346 return 0; 347 } 348 349 extern "C" int 350 ndb_back_initialize( 351 BackendInfo *bi ) 352 { 353 static char *controls[] = { 354 LDAP_CONTROL_ASSERT, 355 LDAP_CONTROL_MANAGEDSAIT, 356 LDAP_CONTROL_NOOP, 357 LDAP_CONTROL_PAGEDRESULTS, 358 LDAP_CONTROL_PRE_READ, 359 LDAP_CONTROL_POST_READ, 360 LDAP_CONTROL_SUBENTRIES, 361 LDAP_CONTROL_X_PERMISSIVE_MODIFY, 362 #ifdef LDAP_X_TXN 363 LDAP_CONTROL_X_TXN_SPEC, 364 #endif 365 NULL 366 }; 367 368 int rc = 0; 369 370 /* initialize the underlying database system */ 371 Debug( LDAP_DEBUG_TRACE, 372 LDAP_XSTRING(ndb_back_initialize) ": initialize ndb backend\n", 0, 0, 0 ); 373 374 ndb_init(); 375 376 ndb_lastrow_code = new NdbInterpretedCode( NULL, ndb_lastrow, 1 ); 377 ndb_lastrow_code->interpret_exit_last_row(); 378 ndb_lastrow_code->finalise(); 379 380 bi->bi_flags |= 381 SLAP_BFLAG_INCREMENT | 382 SLAP_BFLAG_SUBENTRIES | 383 SLAP_BFLAG_ALIASES | 384 SLAP_BFLAG_REFERRALS; 385 386 bi->bi_controls = controls; 387 388 bi->bi_open = 0; 389 bi->bi_close = 0; 390 bi->bi_config = 0; 391 bi->bi_destroy = 0; 392 393 bi->bi_db_init = ndb_db_init; 394 bi->bi_db_config = config_generic_wrapper; 395 bi->bi_db_open = ndb_db_open; 396 bi->bi_db_close = ndb_db_close; 397 bi->bi_db_destroy = ndb_db_destroy; 398 399 bi->bi_op_add = ndb_back_add; 400 bi->bi_op_bind = ndb_back_bind; 401 bi->bi_op_compare = ndb_back_compare; 402 bi->bi_op_delete = ndb_back_delete; 403 bi->bi_op_modify = ndb_back_modify; 404 bi->bi_op_modrdn = ndb_back_modrdn; 405 bi->bi_op_search = ndb_back_search; 406 407 bi->bi_op_unbind = 0; 408 409 #if 0 410 bi->bi_extended = ndb_extended; 411 412 bi->bi_chk_referrals = ndb_referrals; 413 #endif 414 bi->bi_operational = ndb_operational; 415 bi->bi_has_subordinates = ndb_has_subordinates; 416 bi->bi_entry_release_rw = 0; 417 bi->bi_entry_get_rw = ndb_entry_get; 418 419 /* 420 * hooks for slap tools 421 */ 422 bi->bi_tool_entry_open = ndb_tool_entry_open; 423 bi->bi_tool_entry_close = ndb_tool_entry_close; 424 bi->bi_tool_entry_first = ndb_tool_entry_first; 425 bi->bi_tool_entry_next = ndb_tool_entry_next; 426 bi->bi_tool_entry_get = ndb_tool_entry_get; 427 bi->bi_tool_entry_put = ndb_tool_entry_put; 428 #if 0 429 bi->bi_tool_entry_reindex = ndb_tool_entry_reindex; 430 bi->bi_tool_sync = 0; 431 bi->bi_tool_dn2id_get = ndb_tool_dn2id_get; 432 bi->bi_tool_entry_modify = ndb_tool_entry_modify; 433 #endif 434 435 bi->bi_connection_init = 0; 436 bi->bi_connection_destroy = 0; 437 438 rc = ndb_back_init_cf( bi ); 439 440 return rc; 441 } 442 443 #if SLAPD_NDB == SLAPD_MOD_DYNAMIC 444 445 /* conditionally define the init_module() function */ 446 extern "C" { int init_module( int argc, char *argv[] ); } 447 448 SLAP_BACKEND_INIT_MODULE( ndb ) 449 450 #endif /* SLAPD_NDB == SLAPD_MOD_DYNAMIC */ 451 452