1 /* init.cpp - initialize ndb backend */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 2008-2014 The OpenLDAP Foundation.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted only as authorized by the OpenLDAP
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>.
17 * This work was initially developed by Howard Chu for inclusion
18 * in OpenLDAP Software. This work was sponsored by MySQL.
24 #include <ac/string.h>
25 #include <ac/unistd.h>
26 #include <ac/stdlib.h>
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;
40 static struct berval ndb_optable = BER_BVC("OL_opattrs");
42 static struct berval ndb_opattrs[] = {
43 BER_BVC("structuralObjectClass"),
45 BER_BVC("creatorsName"),
46 BER_BVC("createTimestamp"),
48 BER_BVC("modifiersName"),
49 BER_BVC("modifyTimestamp"),
53 static int ndb_oplens[] = {
54 0, /* structuralOC, default */
56 0, /* creatorsName, default */
57 26, /* createTimestamp */
59 0, /* modifiersName, default */
60 26, /* modifyTimestamp */
64 static Uint32 ndb_lastrow[1];
65 NdbInterpretedCode *ndb_lastrow_code;
68 ndb_db_init( BackendDB *be, ConfigReply *cr )
73 Debug( LDAP_DEBUG_TRACE,
74 LDAP_XSTRING(ndb_db_init) ": Initializing ndb database\n",
77 /* allocate backend-database-specific stuff */
78 ni = (struct ndb_info *) ch_calloc( 1, sizeof(struct ndb_info) );
81 be->be_cf_ocs = be->bd_info->bi_cf_ocs;
83 ni->ni_search_stack_depth = DEFAULT_SEARCH_STACK_DEPTH;
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 );
90 rc = ndb_monitor_db_init( be );
97 ndb_db_close( BackendDB *be, ConfigReply *cr );
100 ndb_db_open( BackendDB *be, ConfigReply *cr )
102 struct ndb_info *ni = (struct ndb_info *) be->be_private;
103 char sqlbuf[BUFSIZ], *ptr;
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",
114 Debug( LDAP_DEBUG_ARGS,
115 LDAP_XSTRING(ndb_db_open) ": \"%s\"\n",
116 be->be_suffix[0].bv_val, 0, 0 );
118 if ( ni->ni_nconns < 1 )
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 );
126 snprintf( cr->msg, sizeof( cr->msg ),
127 "ndb_db_open: ni_cluster[%d]->connect failed (%d)",
132 for ( i=0; i<ni->ni_nconns; i++ ) {
133 rc = ni->ni_cluster[i]->wait_until_ready( 30, 30 );
135 snprintf( cr->msg, sizeof( cr->msg ),
136 "ndb_db_open: ni_cluster[%d]->wait failed (%d)",
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) );
152 sprintf( sqlbuf, "CREATE DATABASE IF NOT EXISTS %s", ni->ni_dbname );
153 rc = mysql_query( &ni->ni_sql, sqlbuf );
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) );
161 sprintf( sqlbuf, "USE %s", ni->ni_dbname );
162 rc = mysql_query( &ni->ni_sql, sqlbuf );
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) );
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 ) {
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 );
204 ptr = lutil_strcopy(ptr, "KEY " INDEX_NAME " (" );
206 for ( ln = ni->ni_attridxs; ln; ln=ln->ln_next ) {
207 NdbAttrInfo *ai = (NdbAttrInfo *)ln->ln_data;
208 if ( newcol ) *ptr++ = ',';
210 ptr = lutil_strcopy( ptr, ai->na_name.bv_val );
212 ai->na_ixcol = newcol + 18;
217 strcpy( ptr, ") ENGINE=ndb" );
218 rc = mysql_query( &ni->ni_sql, sqlbuf );
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) );
226 rc = mysql_query( &ni->ni_sql, "CREATE TABLE IF NOT EXISTS " NEXTID_TABLE " ("
227 "a bigint unsigned AUTO_INCREMENT PRIMARY KEY ) ENGINE=ndb" );
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) );
238 rc = ndb_aset_get( ni, &ndb_optable, ndb_opattrs, &oci );
240 snprintf( cr->msg, sizeof( cr->msg ),
241 "ndb_db_open: ndb_aset_get( %s ) failed (%d)",
242 ndb_optable.bv_val, rc );
245 for ( i=0; ndb_oplens[i] >= 0; i++ ) {
247 oci->no_attrs[i]->na_len = ndb_oplens[i];
249 rc = ndb_aset_create( ni, oci );
251 snprintf( cr->msg, sizeof( cr->msg ),
252 "ndb_db_open: ndb_aset_create( %s ) failed (%d)",
253 ndb_optable.bv_val, rc );
256 ni->ni_opattrs = oci;
258 /* Create attribute sets */
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 );
266 snprintf( cr->msg, sizeof( cr->msg ),
267 "ndb_db_open: ndb_aset_create( %s ) failed (%d)",
268 oci->no_name.bv_val, rc );
273 /* Initialize any currently used objectClasses */
276 const NdbDictionary::Dictionary *myDict;
278 ndb = new Ndb( ni->ni_cluster[0], ni->ni_dbname );
281 myDict = ndb->getDictionary();
282 ndb_oc_read( ni, myDict );
288 rc = ndb_monitor_db_open( be );
297 Debug( LDAP_DEBUG_ANY, "%s\n",
299 ndb_db_close( be, NULL );
304 ndb_db_close( BackendDB *be, ConfigReply *cr )
307 struct ndb_info *ni = (struct ndb_info *) be->be_private;
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;
317 ch_free( ni->ni_cluster );
318 ni->ni_cluster = NULL;
322 /* monitor handling */
323 (void)ndb_monitor_db_close( be );
330 ndb_db_destroy( BackendDB *be, ConfigReply *cr )
332 struct ndb_info *ni = (struct ndb_info *) be->be_private;
335 /* monitor handling */
336 (void)ndb_monitor_db_destroy( be );
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 );
344 be->be_private = NULL;
353 static char *controls[] = {
355 LDAP_CONTROL_MANAGEDSAIT,
357 LDAP_CONTROL_PAGEDRESULTS,
358 LDAP_CONTROL_PRE_READ,
359 LDAP_CONTROL_POST_READ,
360 LDAP_CONTROL_SUBENTRIES,
361 LDAP_CONTROL_X_PERMISSIVE_MODIFY,
363 LDAP_CONTROL_X_TXN_SPEC,
370 /* initialize the underlying database system */
371 Debug( LDAP_DEBUG_TRACE,
372 LDAP_XSTRING(ndb_back_initialize) ": initialize ndb backend\n", 0, 0, 0 );
376 ndb_lastrow_code = new NdbInterpretedCode( NULL, ndb_lastrow, 1 );
377 ndb_lastrow_code->interpret_exit_last_row();
378 ndb_lastrow_code->finalise();
381 SLAP_BFLAG_INCREMENT |
382 SLAP_BFLAG_SUBENTRIES |
384 SLAP_BFLAG_REFERRALS;
386 bi->bi_controls = controls;
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;
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;
407 bi->bi_op_unbind = 0;
410 bi->bi_extended = ndb_extended;
412 bi->bi_chk_referrals = ndb_referrals;
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;
420 * hooks for slap tools
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;
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;
435 bi->bi_connection_init = 0;
436 bi->bi_connection_destroy = 0;
438 rc = ndb_back_init_cf( bi );
443 #if SLAPD_NDB == SLAPD_MOD_DYNAMIC
445 /* conditionally define the init_module() function */
446 extern "C" { int init_module( int argc, char *argv[] ); }
448 SLAP_BACKEND_INIT_MODULE( ndb )
450 #endif /* SLAPD_NDB == SLAPD_MOD_DYNAMIC */