]> git.sur5r.net Git - openldap/blob - servers/slapd/back-ndb/init.cpp
MySQL NDB Cluster backend (experimental)
[openldap] / servers / slapd / back-ndb / init.cpp
1 /* init.cpp - initialize ndb backend */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 2008 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 int
65 ndb_db_init( BackendDB *be, ConfigReply *cr )
66 {
67         struct ndb_info *ni;
68         int rc = 0;
69
70         Debug( LDAP_DEBUG_TRACE,
71                 LDAP_XSTRING(ndb_db_init) ": Initializing ndb database\n",
72                 0, 0, 0 );
73
74         /* allocate backend-database-specific stuff */
75         ni = (struct ndb_info *) ch_calloc( 1, sizeof(struct ndb_info) );
76
77         be->be_private = ni;
78         be->be_cf_ocs = be->bd_info->bi_cf_ocs;
79
80         ni->ni_search_stack_depth = DEFAULT_SEARCH_STACK_DEPTH;
81
82         ldap_pvt_thread_rdwr_init( &ni->ni_ai_rwlock );
83         ldap_pvt_thread_rdwr_init( &ni->ni_oc_rwlock );
84         ldap_pvt_thread_mutex_init( &ni->ni_conn_mutex );
85
86 #ifdef DO_MONITORING
87         rc = ndb_monitor_db_init( be );
88 #endif
89
90         return rc;
91 }
92
93 static int
94 ndb_db_close( BackendDB *be, ConfigReply *cr );
95
96 static int
97 ndb_db_open( BackendDB *be, ConfigReply *cr )
98 {
99         struct ndb_info *ni = (struct ndb_info *) be->be_private;
100         char sqlbuf[BUFSIZ], *ptr;
101         int rc, i;
102
103         if ( be->be_suffix == NULL ) {
104                 snprintf( cr->msg, sizeof( cr->msg ),
105                         "ndb_db_open: need suffix" );
106                 Debug( LDAP_DEBUG_ANY, "%s\n",
107                         cr->msg, 0, 0 );
108                 return -1;
109         }
110
111         Debug( LDAP_DEBUG_ARGS,
112                 LDAP_XSTRING(ndb_db_open) ": \"%s\"\n",
113                 be->be_suffix[0].bv_val, 0, 0 );
114
115         if ( ni->ni_nconns < 1 )
116                 ni->ni_nconns = 1;
117
118         ni->ni_cluster = (Ndb_cluster_connection **)ch_malloc( ni->ni_nconns * sizeof( Ndb_cluster_connection *));
119         for ( i=0; i<ni->ni_nconns; i++ ) {
120                 ni->ni_cluster[i] = new Ndb_cluster_connection( ni->ni_connectstr );
121                 rc = ni->ni_cluster[i]->connect( 4, 5, 1 );
122         }
123         for ( i=0; i<ni->ni_nconns; i++ ) {
124                 rc = ni->ni_cluster[i]->wait_until_ready( 30, 0 );
125         }
126
127         mysql_init( &ni->ni_sql );
128         if ( !mysql_real_connect( &ni->ni_sql, ni->ni_hostname, ni->ni_username, ni->ni_password,
129                 "", ni->ni_port, ni->ni_socket, ni->ni_clflag )) {
130                 snprintf( cr->msg, sizeof( cr->msg ),
131                         "ndb_db_open: mysql_real_connect failed, %s (%d)",
132                         mysql_error(&ni->ni_sql), mysql_errno(&ni->ni_sql) );
133                 rc = -1;
134                 goto fail;
135         }
136
137         sprintf( sqlbuf, "CREATE DATABASE IF NOT EXISTS %s", ni->ni_dbname );
138         rc = mysql_query( &ni->ni_sql, sqlbuf );
139         if ( rc ) {
140                 snprintf( cr->msg, sizeof( cr->msg ),
141                         "ndb_db_open: CREATE DATABASE %s failed, %s (%d)",
142                         ni->ni_dbname, mysql_error(&ni->ni_sql), mysql_errno(&ni->ni_sql) );
143                 goto fail;
144         }
145
146         sprintf( sqlbuf, "USE %s", ni->ni_dbname );
147         rc = mysql_query( &ni->ni_sql, sqlbuf );
148         if ( rc ) {
149                 snprintf( cr->msg, sizeof( cr->msg ),
150                         "ndb_db_open: USE DATABASE %s failed, %s (%d)",
151                         ni->ni_dbname, mysql_error(&ni->ni_sql), mysql_errno(&ni->ni_sql) );
152                 goto fail;
153         }
154
155         ptr = sqlbuf;
156         ptr += sprintf( ptr, "CREATE TABLE IF NOT EXISTS " DN2ID_TABLE " ("
157                 "eid bigint unsigned NOT NULL, "
158                 "object_classes VARCHAR(1024) NOT NULL, "
159                 "a0 VARCHAR(128) NOT NULL DEFAULT '', "
160                 "a1 VARCHAR(128) NOT NULL DEFAULT '', "
161                 "a2 VARCHAR(128) NOT NULL DEFAULT '', "
162                 "a3 VARCHAR(128) NOT NULL DEFAULT '', "
163                 "a4 VARCHAR(128) NOT NULL DEFAULT '', "
164                 "a5 VARCHAR(128) NOT NULL DEFAULT '', "
165                 "a6 VARCHAR(128) NOT NULL DEFAULT '', "
166                 "a7 VARCHAR(128) NOT NULL DEFAULT '', "
167                 "a8 VARCHAR(128) NOT NULL DEFAULT '', "
168                 "a9 VARCHAR(128) NOT NULL DEFAULT '', "
169                 "a10 VARCHAR(128) NOT NULL DEFAULT '', "
170                 "a11 VARCHAR(128) NOT NULL DEFAULT '', "
171                 "a12 VARCHAR(128) NOT NULL DEFAULT '', "
172                 "a13 VARCHAR(128) NOT NULL DEFAULT '', "
173                 "a14 VARCHAR(128) NOT NULL DEFAULT '', "
174                 "a15 VARCHAR(128) NOT NULL DEFAULT '', "
175                 "PRIMARY KEY (a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15), "
176                 "UNIQUE KEY eid (eid) USING HASH" );
177         /* Create index columns */
178         if ( ni->ni_attridxs ) {
179                 ListNode *ln;
180                 int newcol = 0;
181
182                 *ptr++ = ',';
183                 *ptr++ = ' ';
184                 for ( ln = ni->ni_attridxs; ln; ln=ln->ln_next ) {
185                         NdbAttrInfo *ai = (NdbAttrInfo *)ln->ln_data;
186                         ptr += sprintf( ptr, "`%s` VARCHAR(%d), ",
187                                 ai->na_name.bv_val, ai->na_len );
188                 }
189                 ptr = lutil_strcopy(ptr, "KEY " INDEX_NAME " (" );
190
191                 for ( ln = ni->ni_attridxs; ln; ln=ln->ln_next ) {
192                         NdbAttrInfo *ai = (NdbAttrInfo *)ln->ln_data;
193                         if ( newcol ) *ptr++ = ',';
194                         *ptr++ = '`';
195                         ptr = lutil_strcopy( ptr, ai->na_name.bv_val );
196                         *ptr++ = '`';
197                         ai->na_ixcol = newcol + 18;
198                         newcol++;
199                 }
200                 *ptr++ = ')';
201         }
202         strcpy( ptr, ") ENGINE=ndb" );
203         rc = mysql_query( &ni->ni_sql, sqlbuf );
204         if ( rc ) {
205                 snprintf( cr->msg, sizeof( cr->msg ),
206                         "ndb_db_open: CREATE TABLE " DN2ID_TABLE " failed, %s (%d)",
207                         mysql_error(&ni->ni_sql), mysql_errno(&ni->ni_sql) );
208                 goto fail;
209         }
210
211         rc = mysql_query( &ni->ni_sql, "CREATE TABLE IF NOT EXISTS " NEXTID_TABLE " ("
212                 "a bigint unsigned AUTO_INCREMENT PRIMARY KEY ) ENGINE=ndb" );
213         if ( rc ) {
214                 snprintf( cr->msg, sizeof( cr->msg ),
215                         "ndb_db_open: CREATE TABLE " NEXTID_TABLE " failed, %s (%d)",
216                         mysql_error(&ni->ni_sql), mysql_errno(&ni->ni_sql) );
217                 goto fail;
218         }
219
220         {
221                 NdbOcInfo *oci;
222
223                 rc = ndb_aset_get( ni, &ndb_optable, ndb_opattrs, &oci );
224                 if ( rc ) {
225                         snprintf( cr->msg, sizeof( cr->msg ),
226                                 "ndb_db_open: ndb_aset_get( %s ) failed (%d)",
227                                 ndb_optable.bv_val, rc );
228                         goto fail;
229                 }
230                 for ( i=0; ndb_oplens[i] >= 0; i++ ) {
231                         if ( ndb_oplens[i] )
232                                 oci->no_attrs[i]->na_len = ndb_oplens[i];
233                 }
234                 rc = ndb_aset_create( ni, oci );
235                 if ( rc ) {
236                         snprintf( cr->msg, sizeof( cr->msg ),
237                                 "ndb_db_open: ndb_aset_create( %s ) failed (%d)",
238                                 ndb_optable.bv_val, rc );
239                         goto fail;
240                 }
241                 ni->ni_opattrs = oci;
242         }
243         /* Create attribute sets */
244         {
245                 ListNode *ln;
246
247                 for ( ln = ni->ni_attrsets; ln; ln=ln->ln_next ) {
248                         NdbOcInfo *oci = (NdbOcInfo *)ln->ln_data;
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                                         oci->no_name.bv_val, rc );
254                                 goto fail;
255                         }
256                 }
257         }
258         /* Initialize any currently used objectClasses */
259         {
260                 Ndb *ndb;
261                 const NdbDictionary::Dictionary *myDict;
262
263                 ndb = new Ndb( ni->ni_cluster[0], ni->ni_dbname );
264                 ndb->init(1024);
265
266                 myDict = ndb->getDictionary();
267                 ndb_oc_read( ni, myDict );
268                 delete ndb;
269         }
270
271 #ifdef DO_MONITORING
272         /* monitor setup */
273         rc = ndb_monitor_db_open( be );
274         if ( rc != 0 ) {
275                 goto fail;
276         }
277 #endif
278
279         return 0;
280
281 fail:
282         Debug( LDAP_DEBUG_ANY, "%s\n",
283                 cr->msg, 0, 0 );
284         ndb_db_close( be, NULL );
285         return rc;
286 }
287
288 static int
289 ndb_db_close( BackendDB *be, ConfigReply *cr )
290 {
291         int i, rc;
292         struct ndb_info *ni = (struct ndb_info *) be->be_private;
293
294         mysql_close( &ni->ni_sql );
295         for ( i=0; i<ni->ni_nconns; i++ ) {
296                 delete ni->ni_cluster[i];
297                 ni->ni_cluster[i] = NULL;
298         }
299         ch_free( ni->ni_cluster );
300         ni->ni_cluster = NULL;
301
302 #ifdef DO_MONITORING
303         /* monitor handling */
304         (void)ndb_monitor_db_close( be );
305 #endif
306
307         return 0;
308 }
309
310 static int
311 ndb_db_destroy( BackendDB *be, ConfigReply *cr )
312 {
313         struct ndb_info *ni = (struct ndb_info *) be->be_private;
314
315 #ifdef DO_MONITORING
316         /* monitor handling */
317         (void)ndb_monitor_db_destroy( be );
318 #endif
319
320         ldap_pvt_thread_mutex_destroy( &ni->ni_conn_mutex );
321         ldap_pvt_thread_rdwr_destroy( &ni->ni_ai_rwlock );
322         ldap_pvt_thread_rdwr_destroy( &ni->ni_oc_rwlock );
323
324         ch_free( ni );
325         be->be_private = NULL;
326
327         return 0;
328 }
329
330 extern "C" int
331 ndb_back_initialize(
332         BackendInfo     *bi )
333 {
334         int rc = 0;
335
336         /* initialize the underlying database system */
337         Debug( LDAP_DEBUG_TRACE,
338                 LDAP_XSTRING(ndb_back_initialize) ": initialize ndb backend\n", 0, 0, 0 );
339
340         ndb_init();
341
342         bi->bi_open = 0;
343         bi->bi_close = 0;
344         bi->bi_config = 0;
345         bi->bi_destroy = 0;
346
347         bi->bi_db_init = ndb_db_init;
348         bi->bi_db_config = config_generic_wrapper;
349         bi->bi_db_open = ndb_db_open;
350         bi->bi_db_close = ndb_db_close;
351         bi->bi_db_destroy = ndb_db_destroy;
352
353         bi->bi_op_add = ndb_back_add;
354         bi->bi_op_bind = ndb_back_bind;
355         bi->bi_op_compare = ndb_back_compare;
356         bi->bi_op_delete = ndb_back_delete;
357         bi->bi_op_modify = ndb_back_modify;
358         bi->bi_op_modrdn = ndb_back_modrdn;
359         bi->bi_op_search = ndb_back_search;
360
361         bi->bi_op_unbind = 0;
362
363 #if 0
364         bi->bi_extended = ndb_extended;
365
366         bi->bi_chk_referrals = ndb_referrals;
367 #endif
368         bi->bi_operational = ndb_operational;
369         bi->bi_has_subordinates = ndb_has_subordinates;
370         bi->bi_entry_release_rw = 0;
371         bi->bi_entry_get_rw = ndb_entry_get;
372
373         /*
374          * hooks for slap tools
375          */
376         bi->bi_tool_entry_open = ndb_tool_entry_open;
377         bi->bi_tool_entry_close = ndb_tool_entry_close;
378         bi->bi_tool_entry_first = ndb_tool_entry_first;
379         bi->bi_tool_entry_next = ndb_tool_entry_next;
380         bi->bi_tool_entry_get = ndb_tool_entry_get;
381         bi->bi_tool_entry_put = ndb_tool_entry_put;
382 #if 0
383         bi->bi_tool_entry_reindex = ndb_tool_entry_reindex;
384         bi->bi_tool_sync = 0;
385         bi->bi_tool_dn2id_get = ndb_tool_dn2id_get;
386         bi->bi_tool_entry_modify = ndb_tool_entry_modify;
387 #endif
388
389         bi->bi_connection_init = 0;
390         bi->bi_connection_destroy = 0;
391
392         rc = ndb_back_init_cf( bi );
393
394         return rc;
395 }
396
397 #if     SLAPD_NDB == SLAPD_MOD_DYNAMIC
398
399 /* conditionally define the init_module() function */
400 SLAP_BACKEND_INIT_MODULE( ndb )
401
402 #endif /* SLAPD_NDB == SLAPD_MOD_DYNAMIC */
403