init.cpp revision 1.1.1.2
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
33extern "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
40static struct berval ndb_optable = BER_BVC("OL_opattrs");
41
42static 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
53static 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
64static Uint32 ndb_lastrow[1];
65NdbInterpretedCode *ndb_lastrow_code;
66
67static int
68ndb_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
96static int
97ndb_db_close( BackendDB *be, ConfigReply *cr );
98
99static int
100ndb_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
296fail:
297	Debug( LDAP_DEBUG_ANY, "%s\n",
298		cr->msg, 0, 0 );
299	ndb_db_close( be, NULL );
300	return rc;
301}
302
303static int
304ndb_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
329static int
330ndb_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
349extern "C" int
350ndb_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 */
446extern "C" { int init_module( int argc, char *argv[] ); }
447
448SLAP_BACKEND_INIT_MODULE( ndb )
449
450#endif /* SLAPD_NDB == SLAPD_MOD_DYNAMIC */
451
452