Back to index

openldap  2.4.31
init.c
Go to the documentation of this file.
00001 /* init.c - initialize mdb backend */
00002 /* $OpenLDAP$ */
00003 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
00004  *
00005  * Copyright 2000-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 
00017 #include "portable.h"
00018 
00019 #include <stdio.h>
00020 #include <ac/string.h>
00021 #include <ac/unistd.h>
00022 #include <ac/stdlib.h>
00023 #include <ac/errno.h>
00024 #include <sys/stat.h>
00025 #include "back-mdb.h"
00026 #include <lutil.h>
00027 #include <ldap_rq.h>
00028 #include "config.h"
00029 
00030 static const struct berval mdmi_databases[] = {
00031        BER_BVC("ad2i"),
00032        BER_BVC("dn2i"),
00033        BER_BVC("id2e"),
00034        BER_BVNULL
00035 };
00036 
00037 static int
00038 mdb_id_compare( const MDB_val *a, const MDB_val *b )
00039 {
00040        return *(ID *)a->mv_data < *(ID *)b->mv_data ? -1 : *(ID *)a->mv_data > *(ID *)b->mv_data;
00041 }
00042 
00043 static int
00044 mdb_db_init( BackendDB *be, ConfigReply *cr )
00045 {
00046        struct mdb_info      *mdb;
00047        int rc;
00048 
00049        Debug( LDAP_DEBUG_TRACE,
00050               LDAP_XSTRING(mdb_db_init) ": Initializing mdb database\n",
00051               0, 0, 0 );
00052 
00053        /* allocate backend-database-specific stuff */
00054        mdb = (struct mdb_info *) ch_calloc( 1, sizeof(struct mdb_info) );
00055 
00056        /* DBEnv parameters */
00057        mdb->mi_dbenv_home = ch_strdup( SLAPD_DEFAULT_DB_DIR );
00058        mdb->mi_dbenv_flags = 0;
00059        mdb->mi_dbenv_mode = SLAPD_DEFAULT_DB_MODE;
00060 
00061        mdb->mi_search_stack_depth = DEFAULT_SEARCH_STACK_DEPTH;
00062        mdb->mi_search_stack = NULL;
00063 
00064        mdb->mi_mapsize = DEFAULT_MAPSIZE;
00065 
00066        be->be_private = mdb;
00067        be->be_cf_ocs = be->bd_info->bi_cf_ocs;
00068 
00069 #ifndef MDB_MULTIPLE_SUFFIXES
00070        SLAP_DBFLAGS( be ) |= SLAP_DBFLAG_ONE_SUFFIX;
00071 #endif
00072 
00073        rc = mdb_monitor_db_init( be );
00074 
00075        return rc;
00076 }
00077 
00078 static int
00079 mdb_db_close( BackendDB *be, ConfigReply *cr );
00080 
00081 static int
00082 mdb_db_open( BackendDB *be, ConfigReply *cr )
00083 {
00084        int rc, i;
00085        struct mdb_info *mdb = (struct mdb_info *) be->be_private;
00086        struct stat stat1;
00087        uint32_t flags;
00088        char *dbhome;
00089        MDB_txn *txn;
00090 
00091        if ( be->be_suffix == NULL ) {
00092               Debug( LDAP_DEBUG_ANY,
00093                      LDAP_XSTRING(mdb_db_open) ": need suffix.\n",
00094                      1, 0, 0 );
00095               return -1;
00096        }
00097 
00098        Debug( LDAP_DEBUG_ARGS,
00099               LDAP_XSTRING(mdb_db_open) ": \"%s\"\n",
00100               be->be_suffix[0].bv_val, 0, 0 );
00101 
00102        /* Check existence of dbenv_home. Any error means trouble */
00103        rc = stat( mdb->mi_dbenv_home, &stat1 );
00104        if( rc != 0 ) {
00105               Debug( LDAP_DEBUG_ANY,
00106                      LDAP_XSTRING(mdb_db_open) ": database \"%s\": "
00107                      "cannot access database directory \"%s\" (%d).\n",
00108                      be->be_suffix[0].bv_val, mdb->mi_dbenv_home, errno );
00109               return -1;
00110        }
00111 
00112        /* mdb is always clean */
00113        be->be_flags |= SLAP_DBFLAG_CLEAN;
00114 
00115        rc = mdb_env_create( &mdb->mi_dbenv );
00116        if( rc != 0 ) {
00117               Debug( LDAP_DEBUG_ANY,
00118                      LDAP_XSTRING(mdb_db_open) ": database \"%s\": "
00119                      "mdb_env_create failed: %s (%d).\n",
00120                      be->be_suffix[0].bv_val, mdb_strerror(rc), rc );
00121               goto fail;
00122        }
00123 
00124        if ( mdb->mi_readers ) {
00125               rc = mdb_env_set_maxreaders( mdb->mi_dbenv, mdb->mi_readers );
00126               if( rc != 0 ) {
00127                      Debug( LDAP_DEBUG_ANY,
00128                             LDAP_XSTRING(mdb_db_open) ": database \"%s\": "
00129                             "mdb_env_set_maxreaders failed: %s (%d).\n",
00130                             be->be_suffix[0].bv_val, mdb_strerror(rc), rc );
00131                      goto fail;
00132               }
00133        }
00134 
00135        rc = mdb_env_set_mapsize( mdb->mi_dbenv, mdb->mi_mapsize );
00136        if( rc != 0 ) {
00137               Debug( LDAP_DEBUG_ANY,
00138                      LDAP_XSTRING(mdb_db_open) ": database \"%s\": "
00139                      "mdb_env_set_mapsize failed: %s (%d).\n",
00140                      be->be_suffix[0].bv_val, mdb_strerror(rc), rc );
00141               goto fail;
00142        }
00143 
00144        rc = mdb_env_set_maxdbs( mdb->mi_dbenv, MDB_INDICES );
00145        if( rc != 0 ) {
00146               Debug( LDAP_DEBUG_ANY,
00147                      LDAP_XSTRING(mdb_db_open) ": database \"%s\": "
00148                      "mdb_env_set_maxdbs failed: %s (%d).\n",
00149                      be->be_suffix[0].bv_val, mdb_strerror(rc), rc );
00150               goto fail;
00151        }
00152 
00153 #ifdef HAVE_EBCDIC
00154        strcpy( path, mdb->mi_dbenv_home );
00155        __atoe( path );
00156        dbhome = path;
00157 #else
00158        dbhome = mdb->mi_dbenv_home;
00159 #endif
00160 
00161        Debug( LDAP_DEBUG_TRACE,
00162               LDAP_XSTRING(mdb_db_open) ": database \"%s\": "
00163               "dbenv_open(%s).\n",
00164               be->be_suffix[0].bv_val, mdb->mi_dbenv_home, 0);
00165 
00166        flags = mdb->mi_dbenv_flags;
00167 
00168        if ( slapMode & SLAP_TOOL_QUICK )
00169               flags |= MDB_NOSYNC;
00170 
00171        if ( slapMode & SLAP_TOOL_READONLY)
00172               flags |= MDB_RDONLY;
00173 
00174        rc = mdb_env_open( mdb->mi_dbenv, dbhome,
00175                      flags, mdb->mi_dbenv_mode );
00176 
00177        if ( rc ) {
00178               Debug( LDAP_DEBUG_ANY,
00179                      LDAP_XSTRING(mdb_db_open) ": database \"%s\" cannot be opened, err %d. "
00180                      "Restore from backup!\n",
00181                      be->be_suffix[0].bv_val, rc, 0 );
00182               goto fail;
00183        }
00184 
00185        rc = mdb_txn_begin( mdb->mi_dbenv, NULL, 0, &txn );
00186        if ( rc ) {
00187               Debug( LDAP_DEBUG_ANY,
00188                      LDAP_XSTRING(mdb_db_open) ": database \"%s\" cannot be opened, err %d. "
00189                      "Restore from backup!\n",
00190                      be->be_suffix[0].bv_val, rc, 0 );
00191               goto fail;
00192        }
00193 
00194        /* open (and create) main databases */
00195        for( i = 0; mdmi_databases[i].bv_val; i++ ) {
00196               flags = MDB_INTEGERKEY;
00197               if( i == MDB_ID2ENTRY ) {
00198                      if ( !(slapMode & (SLAP_TOOL_READMAIN|SLAP_TOOL_READONLY) ))
00199                             flags |= MDB_CREATE;
00200               } else {
00201                      if ( i == MDB_DN2ID )
00202                             flags |= MDB_DUPSORT;
00203                      if ( !(slapMode & SLAP_TOOL_READONLY) )
00204                             flags |= MDB_CREATE;
00205               }
00206 
00207               rc = mdb_open( txn,
00208                      mdmi_databases[i].bv_val,
00209                      flags,
00210                      &mdb->mi_dbis[i] );
00211 
00212               if ( rc != 0 ) {
00213                      snprintf( cr->msg, sizeof(cr->msg), "database \"%s\": "
00214                             "mdb_open(%s/%s) failed: %s (%d).", 
00215                             be->be_suffix[0].bv_val, 
00216                             mdb->mi_dbenv_home, mdmi_databases[i].bv_val,
00217                             mdb_strerror(rc), rc );
00218                      Debug( LDAP_DEBUG_ANY,
00219                             LDAP_XSTRING(mdb_db_open) ": %s\n",
00220                             cr->msg, 0, 0 );
00221                      goto fail;
00222               }
00223 
00224               if ( i == MDB_ID2ENTRY )
00225                      mdb_set_compare( txn, mdb->mi_dbis[i], mdb_id_compare );
00226               else if ( i == MDB_DN2ID )
00227                      mdb_set_dupsort( txn, mdb->mi_dbis[i], mdb_dup_compare );
00228 
00229        }
00230 
00231        rc = mdb_ad_read( mdb, txn );
00232        if ( rc ) {
00233               mdb_txn_abort( txn );
00234               goto fail;
00235        }
00236 
00237        rc = mdb_attr_dbs_open( be, txn, cr );
00238        if ( rc ) {
00239               mdb_txn_abort( txn );
00240               goto fail;
00241        }
00242 
00243        rc = mdb_txn_commit(txn);
00244        if ( rc != 0 ) {
00245               goto fail;
00246        }
00247 
00248        /* monitor setup */
00249        rc = mdb_monitor_db_open( be );
00250        if ( rc != 0 ) {
00251               goto fail;
00252        }
00253 
00254        mdb->mi_flags |= MDB_IS_OPEN;
00255 
00256        return 0;
00257 
00258 fail:
00259        mdb_db_close( be, NULL );
00260        return rc;
00261 }
00262 
00263 static int
00264 mdb_db_close( BackendDB *be, ConfigReply *cr )
00265 {
00266        int rc;
00267        struct mdb_info *mdb = (struct mdb_info *) be->be_private;
00268 
00269        /* monitor handling */
00270        (void)mdb_monitor_db_close( be );
00271 
00272        mdb->mi_flags &= ~MDB_IS_OPEN;
00273 
00274        if( mdb->mi_dbenv ) {
00275               mdb_reader_flush( mdb->mi_dbenv );
00276        }
00277 
00278        if ( mdb->mi_dbenv ) {
00279               if ( mdb->mi_dbis[0] ) {
00280                      int i;
00281 
00282                      mdb_attr_dbs_close( mdb );
00283                      for ( i=0; i<MDB_NDB; i++ )
00284                             mdb_close( mdb->mi_dbenv, mdb->mi_dbis[i] );
00285 
00286                      /* force a sync, but not if we were ReadOnly,
00287                       * and not in Quick mode.
00288                       */
00289                      if (!(slapMode & (SLAP_TOOL_QUICK|SLAP_TOOL_READONLY))) {
00290                             rc = mdb_env_sync( mdb->mi_dbenv, 1 );
00291                             if( rc != 0 ) {
00292                                    Debug( LDAP_DEBUG_ANY,
00293                                           "mdb_db_close: database \"%s\": "
00294                                           "mdb_env_sync failed: %s (%d).\n",
00295                                           be->be_suffix[0].bv_val, mdb_strerror(rc), rc );
00296                             }
00297                      }
00298               }
00299 
00300               mdb_env_close( mdb->mi_dbenv );
00301               mdb->mi_dbenv = NULL;
00302        }
00303 
00304        return 0;
00305 }
00306 
00307 static int
00308 mdb_db_destroy( BackendDB *be, ConfigReply *cr )
00309 {
00310        struct mdb_info *mdb = (struct mdb_info *) be->be_private;
00311 
00312        /* stop and remove checkpoint task */
00313        if ( mdb->mi_txn_cp_task ) {
00314               struct re_s *re = mdb->mi_txn_cp_task;
00315               mdb->mi_txn_cp_task = NULL;
00316               ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
00317               if ( ldap_pvt_runqueue_isrunning( &slapd_rq, re ) )
00318                      ldap_pvt_runqueue_stoptask( &slapd_rq, re );
00319               ldap_pvt_runqueue_remove( &slapd_rq, re );
00320               ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
00321        }
00322 
00323        /* monitor handling */
00324        (void)mdb_monitor_db_destroy( be );
00325 
00326        if( mdb->mi_dbenv_home ) ch_free( mdb->mi_dbenv_home );
00327 
00328        mdb_attr_index_destroy( mdb );
00329 
00330        ch_free( mdb );
00331        be->be_private = NULL;
00332 
00333        return 0;
00334 }
00335 
00336 int
00337 mdb_back_initialize(
00338        BackendInfo   *bi )
00339 {
00340        int rc;
00341 
00342        static char *controls[] = {
00343               LDAP_CONTROL_ASSERT,
00344               LDAP_CONTROL_MANAGEDSAIT,
00345               LDAP_CONTROL_NOOP,
00346               LDAP_CONTROL_PAGEDRESULTS,
00347               LDAP_CONTROL_PRE_READ,
00348               LDAP_CONTROL_POST_READ,
00349               LDAP_CONTROL_SUBENTRIES,
00350               LDAP_CONTROL_X_PERMISSIVE_MODIFY,
00351 #ifdef LDAP_X_TXN
00352               LDAP_CONTROL_X_TXN_SPEC,
00353 #endif
00354               NULL
00355        };
00356 
00357        /* initialize the underlying database system */
00358        Debug( LDAP_DEBUG_TRACE,
00359               LDAP_XSTRING(mdb_back_initialize) ": initialize " 
00360               MDB_UCTYPE " backend\n", 0, 0, 0 );
00361 
00362        bi->bi_flags |=
00363               SLAP_BFLAG_INCREMENT |
00364               SLAP_BFLAG_SUBENTRIES |
00365               SLAP_BFLAG_ALIASES |
00366               SLAP_BFLAG_REFERRALS;
00367 
00368        bi->bi_controls = controls;
00369 
00370        {      /* version check */
00371               int major, minor, patch, ver;
00372               char *version = mdb_version( &major, &minor, &patch );
00373 #ifdef HAVE_EBCDIC
00374               char v2[1024];
00375 
00376               /* All our stdio does an ASCII to EBCDIC conversion on
00377                * the output. Strings from the MDB library are already
00378                * in EBCDIC; we have to go back and forth...
00379                */
00380               strcpy( v2, version );
00381               __etoa( v2 );
00382               version = v2;
00383 #endif
00384               ver = (major << 24) | (minor << 16) | patch;
00385               if( ver != MDB_VERSION_FULL ) {
00386                      /* fail if a versions don't match */
00387                      Debug( LDAP_DEBUG_ANY,
00388                             LDAP_XSTRING(mdb_back_initialize) ": "
00389                             "MDB library version mismatch:"
00390                             " expected " MDB_VERSION_STRING ","
00391                             " got %s\n", version, 0, 0 );
00392                      return -1;
00393               }
00394 
00395               Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(mdb_back_initialize)
00396                      ": %s\n", version, 0, 0 );
00397        }
00398 
00399        bi->bi_open = 0;
00400        bi->bi_close = 0;
00401        bi->bi_config = 0;
00402        bi->bi_destroy = 0;
00403 
00404        bi->bi_db_init = mdb_db_init;
00405        bi->bi_db_config = config_generic_wrapper;
00406        bi->bi_db_open = mdb_db_open;
00407        bi->bi_db_close = mdb_db_close;
00408        bi->bi_db_destroy = mdb_db_destroy;
00409 
00410        bi->bi_op_add = mdb_add;
00411        bi->bi_op_bind = mdb_bind;
00412        bi->bi_op_compare = mdb_compare;
00413        bi->bi_op_delete = mdb_delete;
00414        bi->bi_op_modify = mdb_modify;
00415        bi->bi_op_modrdn = mdb_modrdn;
00416        bi->bi_op_search = mdb_search;
00417 
00418        bi->bi_op_unbind = 0;
00419 
00420        bi->bi_extended = mdb_extended;
00421 
00422        bi->bi_chk_referrals = 0;
00423        bi->bi_operational = mdb_operational;
00424 
00425        bi->bi_has_subordinates = mdb_hasSubordinates;
00426        bi->bi_entry_release_rw = mdb_entry_release;
00427        bi->bi_entry_get_rw = mdb_entry_get;
00428 
00429        /*
00430         * hooks for slap tools
00431         */
00432        bi->bi_tool_entry_open = mdb_tool_entry_open;
00433        bi->bi_tool_entry_close = mdb_tool_entry_close;
00434        bi->bi_tool_entry_first = backend_tool_entry_first;
00435        bi->bi_tool_entry_first_x = mdb_tool_entry_first_x;
00436        bi->bi_tool_entry_next = mdb_tool_entry_next;
00437        bi->bi_tool_entry_get = mdb_tool_entry_get;
00438        bi->bi_tool_entry_put = mdb_tool_entry_put;
00439        bi->bi_tool_entry_reindex = mdb_tool_entry_reindex;
00440        bi->bi_tool_sync = 0;
00441        bi->bi_tool_dn2id_get = mdb_tool_dn2id_get;
00442        bi->bi_tool_entry_modify = mdb_tool_entry_modify;
00443 
00444        bi->bi_connection_init = 0;
00445        bi->bi_connection_destroy = 0;
00446 
00447        rc = mdb_back_init_cf( bi );
00448 
00449        return rc;
00450 }
00451 
00452 #if    (SLAPD_MDB == SLAPD_MOD_DYNAMIC)
00453 
00454 SLAP_BACKEND_INIT_MODULE( mdb )
00455 
00456 #endif /* SLAPD_MDB == SLAPD_MOD_DYNAMIC */
00457