Back to index

openldap  2.4.31
dbcache.c
Go to the documentation of this file.
00001 /* dbcache.c - manage cache of open databases */
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 
00021 #include <ac/errno.h>
00022 #include <ac/socket.h>
00023 #include <ac/string.h>
00024 #include <ac/time.h>
00025 #include <sys/stat.h>
00026 
00027 #include "slap.h"
00028 #include "back-bdb.h"
00029 #include "lutil_hash.h"
00030 
00031 #ifdef BDB_INDEX_USE_HASH
00032 /* Pass-thru hash function. Since the indexer is already giving us hash
00033  * values as keys, we don't need BDB to re-hash them.
00034  */
00035 static u_int32_t
00036 bdb_db_hash(
00037        DB *db,
00038        const void *bytes,
00039        u_int32_t length
00040 )
00041 {
00042        u_int32_t ret = 0;
00043        unsigned char *dst = (unsigned char *)&ret;
00044        const unsigned char *src = (const unsigned char *)bytes;
00045 
00046        if ( length > sizeof(u_int32_t) )
00047               length = sizeof(u_int32_t);
00048 
00049        while ( length ) {
00050               *dst++ = *src++;
00051               length--;
00052        }
00053        return ret;
00054 }
00055 #define       BDB_INDEXTYPE DB_HASH
00056 #else
00057 #define       BDB_INDEXTYPE DB_BTREE
00058 #endif
00059 
00060 /* If a configured size is found, return it, otherwise return 0 */
00061 int
00062 bdb_db_findsize(
00063        struct bdb_info *bdb,
00064        struct berval *name
00065 )
00066 {
00067        struct bdb_db_pgsize *bp;
00068        int rc;
00069 
00070        for ( bp = bdb->bi_pagesizes; bp; bp=bp->bdp_next ) {
00071               rc = strncmp( name->bv_val, bp->bdp_name.bv_val, name->bv_len );
00072               if ( !rc ) {
00073                      if ( name->bv_len == bp->bdp_name.bv_len )
00074                             return bp->bdp_size;
00075                      if ( name->bv_len < bp->bdp_name.bv_len &&
00076                             bp->bdp_name.bv_val[name->bv_len] == '.' )
00077                             return bp->bdp_size;
00078               }
00079        }
00080        return 0;
00081 }
00082 
00083 int
00084 bdb_db_cache(
00085        Backend       *be,
00086        struct berval *name,
00087        DB **dbout )
00088 {
00089        int i, flags;
00090        int rc;
00091        struct bdb_info *bdb = (struct bdb_info *) be->be_private;
00092        struct bdb_db_info *db;
00093        char *file;
00094 
00095        *dbout = NULL;
00096 
00097        for( i=BDB_NDB; i < bdb->bi_ndatabases; i++ ) {
00098               if( !ber_bvcmp( &bdb->bi_databases[i]->bdi_name, name) ) {
00099                      *dbout = bdb->bi_databases[i]->bdi_db;
00100                      return 0;
00101               }
00102        }
00103 
00104        ldap_pvt_thread_mutex_lock( &bdb->bi_database_mutex );
00105 
00106        /* check again! may have been added by another thread */
00107        for( i=BDB_NDB; i < bdb->bi_ndatabases; i++ ) {
00108               if( !ber_bvcmp( &bdb->bi_databases[i]->bdi_name, name) ) {
00109                      *dbout = bdb->bi_databases[i]->bdi_db;
00110                      ldap_pvt_thread_mutex_unlock( &bdb->bi_database_mutex );
00111                      return 0;
00112               }
00113        }
00114 
00115        if( i >= BDB_INDICES ) {
00116               ldap_pvt_thread_mutex_unlock( &bdb->bi_database_mutex );
00117               return -1;
00118        }
00119 
00120        db = (struct bdb_db_info *) ch_calloc(1, sizeof(struct bdb_db_info));
00121 
00122        ber_dupbv( &db->bdi_name, name );
00123 
00124        rc = db_create( &db->bdi_db, bdb->bi_dbenv, 0 );
00125        if( rc != 0 ) {
00126               Debug( LDAP_DEBUG_ANY,
00127                      "bdb_db_cache: db_create(%s) failed: %s (%d)\n",
00128                      bdb->bi_dbenv_home, db_strerror(rc), rc );
00129               ldap_pvt_thread_mutex_unlock( &bdb->bi_database_mutex );
00130               ch_free( db );
00131               return rc;
00132        }
00133 
00134        if( !BER_BVISNULL( &bdb->bi_db_crypt_key )) {
00135               rc = db->bdi_db->set_flags( db->bdi_db, DB_ENCRYPT );
00136               if ( rc ) {
00137                      Debug( LDAP_DEBUG_ANY,
00138                             "bdb_db_cache: db set_flags(DB_ENCRYPT)(%s) failed: %s (%d)\n",
00139                             bdb->bi_dbenv_home, db_strerror(rc), rc );
00140                      ldap_pvt_thread_mutex_unlock( &bdb->bi_database_mutex );
00141                      db->bdi_db->close( db->bdi_db, 0 );
00142                      ch_free( db );
00143                      return rc;
00144               }
00145        }
00146 
00147        if( bdb->bi_flags & BDB_CHKSUM ) {
00148               rc = db->bdi_db->set_flags( db->bdi_db, DB_CHKSUM );
00149               if ( rc ) {
00150                      Debug( LDAP_DEBUG_ANY,
00151                             "bdb_db_cache: db set_flags(DB_CHKSUM)(%s) failed: %s (%d)\n",
00152                             bdb->bi_dbenv_home, db_strerror(rc), rc );
00153                      ldap_pvt_thread_mutex_unlock( &bdb->bi_database_mutex );
00154                      db->bdi_db->close( db->bdi_db, 0 );
00155                      ch_free( db );
00156                      return rc;
00157               }
00158        }
00159 
00160        /* If no explicit size set, use the FS default */
00161        flags = bdb_db_findsize( bdb, name );
00162        if ( flags )
00163               rc = db->bdi_db->set_pagesize( db->bdi_db, flags );
00164 
00165 #ifdef BDB_INDEX_USE_HASH
00166        rc = db->bdi_db->set_h_hash( db->bdi_db, bdb_db_hash );
00167 #endif
00168        rc = db->bdi_db->set_flags( db->bdi_db, DB_DUP | DB_DUPSORT );
00169 
00170        file = ch_malloc( db->bdi_name.bv_len + sizeof(BDB_SUFFIX) );
00171        strcpy( file, db->bdi_name.bv_val );
00172        strcpy( file+db->bdi_name.bv_len, BDB_SUFFIX );
00173 
00174 #ifdef HAVE_EBCDIC
00175        __atoe( file );
00176 #endif
00177        flags = DB_CREATE | DB_THREAD;
00178 #ifdef DB_AUTO_COMMIT
00179        if ( !( slapMode & SLAP_TOOL_QUICK ))
00180               flags |= DB_AUTO_COMMIT;
00181 #endif
00182        /* Cannot Truncate when Transactions are in use */
00183        if ( (slapMode & (SLAP_TOOL_QUICK|SLAP_TRUNCATE_MODE)) ==
00184               (SLAP_TOOL_QUICK|SLAP_TRUNCATE_MODE))
00185                      flags |= DB_TRUNCATE;
00186 
00187        rc = DB_OPEN( db->bdi_db,
00188               file, NULL /* name */,
00189               BDB_INDEXTYPE, bdb->bi_db_opflags | flags, bdb->bi_dbenv_mode );
00190 
00191        ch_free( file );
00192 
00193        if( rc != 0 ) {
00194               Debug( LDAP_DEBUG_ANY,
00195                      "bdb_db_cache: db_open(%s) failed: %s (%d)\n",
00196                      name->bv_val, db_strerror(rc), rc );
00197               ldap_pvt_thread_mutex_unlock( &bdb->bi_database_mutex );
00198               return rc;
00199        }
00200 
00201        bdb->bi_databases[i] = db;
00202        bdb->bi_ndatabases = i+1;
00203 
00204        *dbout = db->bdi_db;
00205 
00206        ldap_pvt_thread_mutex_unlock( &bdb->bi_database_mutex );
00207        return 0;
00208 }