Back to index

openldap  2.4.31
init.cpp
Go to the documentation of this file.
00001 /* init.cpp - initialize ndb backend */
00002 /* $OpenLDAP$ */
00003 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
00004  *
00005  * Copyright 2008-2012 The OpenLDAP Foundation.
00006  * All rights reserved.
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted only as authorized by the OpenLDAP
00010  * Public License.
00011  *
00012  * A copy of this license is available in the file LICENSE in the
00013  * top-level directory of the distribution or, alternatively, at
00014  * <http://www.OpenLDAP.org/license.html>.
00015  */
00016 /* ACKNOWLEDGEMENTS:
00017  * This work was initially developed by Howard Chu for inclusion
00018  * in OpenLDAP Software. This work was sponsored by MySQL.
00019  */
00020 
00021 #include "portable.h"
00022 
00023 #include <stdio.h>
00024 #include <ac/string.h>
00025 #include <ac/unistd.h>
00026 #include <ac/stdlib.h>
00027 #include <ac/errno.h>
00028 #include <sys/stat.h>
00029 #include "back-ndb.h"
00030 #include <lutil.h>
00031 #include "config.h"
00032 
00033 extern "C" {
00034        static BI_db_init ndb_db_init;
00035        static BI_db_close ndb_db_close;
00036        static BI_db_open ndb_db_open;
00037        static BI_db_destroy ndb_db_destroy;
00038 }
00039 
00040 static struct berval ndb_optable = BER_BVC("OL_opattrs");
00041 
00042 static struct berval ndb_opattrs[] = {
00043        BER_BVC("structuralObjectClass"),
00044        BER_BVC("entryUUID"),
00045        BER_BVC("creatorsName"),
00046        BER_BVC("createTimestamp"),
00047        BER_BVC("entryCSN"),
00048        BER_BVC("modifiersName"),
00049        BER_BVC("modifyTimestamp"),
00050        BER_BVNULL
00051 };
00052 
00053 static int ndb_oplens[] = {
00054        0,     /* structuralOC, default */
00055        36,    /* entryUUID */
00056        0,     /* creatorsName, default */
00057        26,    /* createTimestamp */
00058        40,    /* entryCSN */
00059        0,     /* modifiersName, default */
00060        26,    /* modifyTimestamp */
00061        -1
00062 };
00063 
00064 static Uint32 ndb_lastrow[1];
00065 NdbInterpretedCode *ndb_lastrow_code;
00066 
00067 static int
00068 ndb_db_init( BackendDB *be, ConfigReply *cr )
00069 {
00070        struct ndb_info      *ni;
00071        int rc = 0;
00072 
00073        Debug( LDAP_DEBUG_TRACE,
00074               LDAP_XSTRING(ndb_db_init) ": Initializing ndb database\n",
00075               0, 0, 0 );
00076 
00077        /* allocate backend-database-specific stuff */
00078        ni = (struct ndb_info *) ch_calloc( 1, sizeof(struct ndb_info) );
00079 
00080        be->be_private = ni;
00081        be->be_cf_ocs = be->bd_info->bi_cf_ocs;
00082 
00083        ni->ni_search_stack_depth = DEFAULT_SEARCH_STACK_DEPTH;
00084 
00085        ldap_pvt_thread_rdwr_init( &ni->ni_ai_rwlock );
00086        ldap_pvt_thread_rdwr_init( &ni->ni_oc_rwlock );
00087        ldap_pvt_thread_mutex_init( &ni->ni_conn_mutex );
00088 
00089 #ifdef DO_MONITORING
00090        rc = ndb_monitor_db_init( be );
00091 #endif
00092 
00093        return rc;
00094 }
00095 
00096 static int
00097 ndb_db_close( BackendDB *be, ConfigReply *cr );
00098 
00099 static int
00100 ndb_db_open( BackendDB *be, ConfigReply *cr )
00101 {
00102        struct ndb_info *ni = (struct ndb_info *) be->be_private;
00103        char sqlbuf[BUFSIZ], *ptr;
00104        int rc, i;
00105 
00106        if ( be->be_suffix == NULL ) {
00107               snprintf( cr->msg, sizeof( cr->msg ),
00108                      "ndb_db_open: need suffix" );
00109               Debug( LDAP_DEBUG_ANY, "%s\n",
00110                      cr->msg, 0, 0 );
00111               return -1;
00112        }
00113 
00114        Debug( LDAP_DEBUG_ARGS,
00115               LDAP_XSTRING(ndb_db_open) ": \"%s\"\n",
00116               be->be_suffix[0].bv_val, 0, 0 );
00117 
00118        if ( ni->ni_nconns < 1 )
00119               ni->ni_nconns = 1;
00120 
00121        ni->ni_cluster = (Ndb_cluster_connection **)ch_calloc( ni->ni_nconns, sizeof( Ndb_cluster_connection *));
00122        for ( i=0; i<ni->ni_nconns; i++ ) {
00123               ni->ni_cluster[i] = new Ndb_cluster_connection( ni->ni_connectstr );
00124               rc = ni->ni_cluster[i]->connect( 20, 5, 1 );
00125               if ( rc ) {
00126                      snprintf( cr->msg, sizeof( cr->msg ),
00127                             "ndb_db_open: ni_cluster[%d]->connect failed (%d)",
00128                             i, rc );
00129                      goto fail;
00130               }
00131        }
00132        for ( i=0; i<ni->ni_nconns; i++ ) {
00133               rc = ni->ni_cluster[i]->wait_until_ready( 30, 30 );
00134               if ( rc ) {
00135                      snprintf( cr->msg, sizeof( cr->msg ),
00136                             "ndb_db_open: ni_cluster[%d]->wait failed (%d)",
00137                             i, rc );
00138                      goto fail;
00139               }
00140        }
00141 
00142        mysql_init( &ni->ni_sql );
00143        if ( !mysql_real_connect( &ni->ni_sql, ni->ni_hostname, ni->ni_username, ni->ni_password,
00144               "", ni->ni_port, ni->ni_socket, ni->ni_clflag )) {
00145               snprintf( cr->msg, sizeof( cr->msg ),
00146                      "ndb_db_open: mysql_real_connect failed, %s (%d)",
00147                      mysql_error(&ni->ni_sql), mysql_errno(&ni->ni_sql) );
00148               rc = -1;
00149               goto fail;
00150        }
00151 
00152        sprintf( sqlbuf, "CREATE DATABASE IF NOT EXISTS %s", ni->ni_dbname );
00153        rc = mysql_query( &ni->ni_sql, sqlbuf );
00154        if ( rc ) {
00155               snprintf( cr->msg, sizeof( cr->msg ),
00156                      "ndb_db_open: CREATE DATABASE %s failed, %s (%d)",
00157                      ni->ni_dbname, mysql_error(&ni->ni_sql), mysql_errno(&ni->ni_sql) );
00158               goto fail;
00159        }
00160 
00161        sprintf( sqlbuf, "USE %s", ni->ni_dbname );
00162        rc = mysql_query( &ni->ni_sql, sqlbuf );
00163        if ( rc ) {
00164               snprintf( cr->msg, sizeof( cr->msg ),
00165                      "ndb_db_open: USE DATABASE %s failed, %s (%d)",
00166                      ni->ni_dbname, mysql_error(&ni->ni_sql), mysql_errno(&ni->ni_sql) );
00167               goto fail;
00168        }
00169 
00170        ptr = sqlbuf;
00171        ptr += sprintf( ptr, "CREATE TABLE IF NOT EXISTS " DN2ID_TABLE " ("
00172               "eid bigint unsigned NOT NULL, "
00173               "object_classes VARCHAR(1024) NOT NULL, "
00174               "a0 VARCHAR(128) NOT NULL DEFAULT '', "
00175               "a1 VARCHAR(128) NOT NULL DEFAULT '', "
00176               "a2 VARCHAR(128) NOT NULL DEFAULT '', "
00177               "a3 VARCHAR(128) NOT NULL DEFAULT '', "
00178               "a4 VARCHAR(128) NOT NULL DEFAULT '', "
00179               "a5 VARCHAR(128) NOT NULL DEFAULT '', "
00180               "a6 VARCHAR(128) NOT NULL DEFAULT '', "
00181               "a7 VARCHAR(128) NOT NULL DEFAULT '', "
00182               "a8 VARCHAR(128) NOT NULL DEFAULT '', "
00183               "a9 VARCHAR(128) NOT NULL DEFAULT '', "
00184               "a10 VARCHAR(128) NOT NULL DEFAULT '', "
00185               "a11 VARCHAR(128) NOT NULL DEFAULT '', "
00186               "a12 VARCHAR(128) NOT NULL DEFAULT '', "
00187               "a13 VARCHAR(128) NOT NULL DEFAULT '', "
00188               "a14 VARCHAR(128) NOT NULL DEFAULT '', "
00189               "a15 VARCHAR(128) NOT NULL DEFAULT '', "
00190               "PRIMARY KEY (a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15), "
00191               "UNIQUE KEY eid (eid) USING HASH" );
00192        /* Create index columns */
00193        if ( ni->ni_attridxs ) {
00194               ListNode *ln;
00195               int newcol = 0;
00196 
00197               *ptr++ = ',';
00198               *ptr++ = ' ';
00199               for ( ln = ni->ni_attridxs; ln; ln=ln->ln_next ) {
00200                      NdbAttrInfo *ai = (NdbAttrInfo *)ln->ln_data;
00201                      ptr += sprintf( ptr, "`%s` VARCHAR(%d), ",
00202                             ai->na_name.bv_val, ai->na_len );
00203               }
00204               ptr = lutil_strcopy(ptr, "KEY " INDEX_NAME " (" );
00205 
00206               for ( ln = ni->ni_attridxs; ln; ln=ln->ln_next ) {
00207                      NdbAttrInfo *ai = (NdbAttrInfo *)ln->ln_data;
00208                      if ( newcol ) *ptr++ = ',';
00209                      *ptr++ = '`';
00210                      ptr = lutil_strcopy( ptr, ai->na_name.bv_val );
00211                      *ptr++ = '`';
00212                      ai->na_ixcol = newcol + 18;
00213                      newcol++;
00214               }
00215               *ptr++ = ')';
00216        }
00217        strcpy( ptr, ") ENGINE=ndb" );
00218        rc = mysql_query( &ni->ni_sql, sqlbuf );
00219        if ( rc ) {
00220               snprintf( cr->msg, sizeof( cr->msg ),
00221                      "ndb_db_open: CREATE TABLE " DN2ID_TABLE " failed, %s (%d)",
00222                      mysql_error(&ni->ni_sql), mysql_errno(&ni->ni_sql) );
00223               goto fail;
00224        }
00225 
00226        rc = mysql_query( &ni->ni_sql, "CREATE TABLE IF NOT EXISTS " NEXTID_TABLE " ("
00227               "a bigint unsigned AUTO_INCREMENT PRIMARY KEY ) ENGINE=ndb" );
00228        if ( rc ) {
00229               snprintf( cr->msg, sizeof( cr->msg ),
00230                      "ndb_db_open: CREATE TABLE " NEXTID_TABLE " failed, %s (%d)",
00231                      mysql_error(&ni->ni_sql), mysql_errno(&ni->ni_sql) );
00232               goto fail;
00233        }
00234 
00235        {
00236               NdbOcInfo *oci;
00237 
00238               rc = ndb_aset_get( ni, &ndb_optable, ndb_opattrs, &oci );
00239               if ( rc ) {
00240                      snprintf( cr->msg, sizeof( cr->msg ),
00241                             "ndb_db_open: ndb_aset_get( %s ) failed (%d)",
00242                             ndb_optable.bv_val, rc );
00243                      goto fail;
00244               }
00245               for ( i=0; ndb_oplens[i] >= 0; i++ ) {
00246                      if ( ndb_oplens[i] )
00247                             oci->no_attrs[i]->na_len = ndb_oplens[i];
00248               }
00249               rc = ndb_aset_create( ni, oci );
00250               if ( rc ) {
00251                      snprintf( cr->msg, sizeof( cr->msg ),
00252                             "ndb_db_open: ndb_aset_create( %s ) failed (%d)",
00253                             ndb_optable.bv_val, rc );
00254                      goto fail;
00255               }
00256               ni->ni_opattrs = oci;
00257        }
00258        /* Create attribute sets */
00259        {
00260               ListNode *ln;
00261 
00262               for ( ln = ni->ni_attrsets; ln; ln=ln->ln_next ) {
00263                      NdbOcInfo *oci = (NdbOcInfo *)ln->ln_data;
00264                      rc = ndb_aset_create( ni, oci );
00265                      if ( rc ) {
00266                             snprintf( cr->msg, sizeof( cr->msg ),
00267                                    "ndb_db_open: ndb_aset_create( %s ) failed (%d)",
00268                                    oci->no_name.bv_val, rc );
00269                             goto fail;
00270                      }
00271               }
00272        }
00273        /* Initialize any currently used objectClasses */
00274        {
00275               Ndb *ndb;
00276               const NdbDictionary::Dictionary *myDict;
00277 
00278               ndb = new Ndb( ni->ni_cluster[0], ni->ni_dbname );
00279               ndb->init(1024);
00280 
00281               myDict = ndb->getDictionary();
00282               ndb_oc_read( ni, myDict );
00283               delete ndb;
00284        }
00285 
00286 #ifdef DO_MONITORING
00287        /* monitor setup */
00288        rc = ndb_monitor_db_open( be );
00289        if ( rc != 0 ) {
00290               goto fail;
00291        }
00292 #endif
00293 
00294        return 0;
00295 
00296 fail:
00297        Debug( LDAP_DEBUG_ANY, "%s\n",
00298               cr->msg, 0, 0 );
00299        ndb_db_close( be, NULL );
00300        return rc;
00301 }
00302 
00303 static int
00304 ndb_db_close( BackendDB *be, ConfigReply *cr )
00305 {
00306        int i;
00307        struct ndb_info *ni = (struct ndb_info *) be->be_private;
00308 
00309        mysql_close( &ni->ni_sql );
00310        if ( ni->ni_cluster ) {
00311               for ( i=0; i<ni->ni_nconns; i++ ) {
00312                      if ( ni->ni_cluster[i] ) {
00313                             delete ni->ni_cluster[i];
00314                             ni->ni_cluster[i] = NULL;
00315                      }
00316               }
00317               ch_free( ni->ni_cluster );
00318               ni->ni_cluster = NULL;
00319        }
00320 
00321 #ifdef DO_MONITORING
00322        /* monitor handling */
00323        (void)ndb_monitor_db_close( be );
00324 #endif
00325 
00326        return 0;
00327 }
00328 
00329 static int
00330 ndb_db_destroy( BackendDB *be, ConfigReply *cr )
00331 {
00332        struct ndb_info *ni = (struct ndb_info *) be->be_private;
00333 
00334 #ifdef DO_MONITORING
00335        /* monitor handling */
00336        (void)ndb_monitor_db_destroy( be );
00337 #endif
00338 
00339        ldap_pvt_thread_mutex_destroy( &ni->ni_conn_mutex );
00340        ldap_pvt_thread_rdwr_destroy( &ni->ni_ai_rwlock );
00341        ldap_pvt_thread_rdwr_destroy( &ni->ni_oc_rwlock );
00342 
00343        ch_free( ni );
00344        be->be_private = NULL;
00345 
00346        return 0;
00347 }
00348 
00349 extern "C" int
00350 ndb_back_initialize(
00351        BackendInfo   *bi )
00352 {
00353        static char *controls[] = {
00354               LDAP_CONTROL_ASSERT,
00355               LDAP_CONTROL_MANAGEDSAIT,
00356               LDAP_CONTROL_NOOP,
00357               LDAP_CONTROL_PAGEDRESULTS,
00358               LDAP_CONTROL_PRE_READ,
00359               LDAP_CONTROL_POST_READ,
00360               LDAP_CONTROL_SUBENTRIES,
00361               LDAP_CONTROL_X_PERMISSIVE_MODIFY,
00362 #ifdef LDAP_X_TXN
00363               LDAP_CONTROL_X_TXN_SPEC,
00364 #endif
00365               NULL
00366        };
00367 
00368        int rc = 0;
00369 
00370        /* initialize the underlying database system */
00371        Debug( LDAP_DEBUG_TRACE,
00372               LDAP_XSTRING(ndb_back_initialize) ": initialize ndb backend\n", 0, 0, 0 );
00373 
00374        ndb_init();
00375 
00376        ndb_lastrow_code = new NdbInterpretedCode( NULL, ndb_lastrow, 1 );
00377        ndb_lastrow_code->interpret_exit_last_row();
00378        ndb_lastrow_code->finalise();
00379 
00380        bi->bi_flags |=
00381               SLAP_BFLAG_INCREMENT |
00382               SLAP_BFLAG_SUBENTRIES |
00383               SLAP_BFLAG_ALIASES |
00384               SLAP_BFLAG_REFERRALS;
00385 
00386        bi->bi_controls = controls;
00387 
00388        bi->bi_open = 0;
00389        bi->bi_close = 0;
00390        bi->bi_config = 0;
00391        bi->bi_destroy = 0;
00392 
00393        bi->bi_db_init = ndb_db_init;
00394        bi->bi_db_config = config_generic_wrapper;
00395        bi->bi_db_open = ndb_db_open;
00396        bi->bi_db_close = ndb_db_close;
00397        bi->bi_db_destroy = ndb_db_destroy;
00398 
00399        bi->bi_op_add = ndb_back_add;
00400        bi->bi_op_bind = ndb_back_bind;
00401        bi->bi_op_compare = ndb_back_compare;
00402        bi->bi_op_delete = ndb_back_delete;
00403        bi->bi_op_modify = ndb_back_modify;
00404        bi->bi_op_modrdn = ndb_back_modrdn;
00405        bi->bi_op_search = ndb_back_search;
00406 
00407        bi->bi_op_unbind = 0;
00408 
00409 #if 0
00410        bi->bi_extended = ndb_extended;
00411 
00412        bi->bi_chk_referrals = ndb_referrals;
00413 #endif
00414        bi->bi_operational = ndb_operational;
00415        bi->bi_has_subordinates = ndb_has_subordinates;
00416        bi->bi_entry_release_rw = 0;
00417        bi->bi_entry_get_rw = ndb_entry_get;
00418 
00419        /*
00420         * hooks for slap tools
00421         */
00422        bi->bi_tool_entry_open = ndb_tool_entry_open;
00423        bi->bi_tool_entry_close = ndb_tool_entry_close;
00424        bi->bi_tool_entry_first = ndb_tool_entry_first;
00425        bi->bi_tool_entry_next = ndb_tool_entry_next;
00426        bi->bi_tool_entry_get = ndb_tool_entry_get;
00427        bi->bi_tool_entry_put = ndb_tool_entry_put;
00428 #if 0
00429        bi->bi_tool_entry_reindex = ndb_tool_entry_reindex;
00430        bi->bi_tool_sync = 0;
00431        bi->bi_tool_dn2id_get = ndb_tool_dn2id_get;
00432        bi->bi_tool_entry_modify = ndb_tool_entry_modify;
00433 #endif
00434 
00435        bi->bi_connection_init = 0;
00436        bi->bi_connection_destroy = 0;
00437 
00438        rc = ndb_back_init_cf( bi );
00439 
00440        return rc;
00441 }
00442 
00443 #if    SLAPD_NDB == SLAPD_MOD_DYNAMIC
00444 
00445 /* conditionally define the init_module() function */
00446 extern "C" { int init_module( int argc, char *argv[] ); }
00447 
00448 SLAP_BACKEND_INIT_MODULE( ndb )
00449 
00450 #endif /* SLAPD_NDB == SLAPD_MOD_DYNAMIC */
00451