1/* $NetBSD$ */ 2 3/* dbcache.c - manage cache of open databases */ 4/* OpenLDAP: pkg/ldap/servers/slapd/back-bdb/dbcache.c,v 1.43.2.9 2010/04/13 20:23:24 kurt Exp */ 5/* This work is part of OpenLDAP Software <http://www.openldap.org/>. 6 * 7 * Copyright 2000-2010 The OpenLDAP Foundation. 8 * All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted only as authorized by the OpenLDAP 12 * Public License. 13 * 14 * A copy of this license is available in the file LICENSE in the 15 * top-level directory of the distribution or, alternatively, at 16 * <http://www.OpenLDAP.org/license.html>. 17 */ 18 19#include "portable.h" 20 21#include <stdio.h> 22 23#include <ac/errno.h> 24#include <ac/socket.h> 25#include <ac/string.h> 26#include <ac/time.h> 27#include <sys/stat.h> 28 29#include "slap.h" 30#include "back-bdb.h" 31#include "lutil_hash.h" 32 33#ifdef BDB_INDEX_USE_HASH 34/* Pass-thru hash function. Since the indexer is already giving us hash 35 * values as keys, we don't need BDB to re-hash them. 36 */ 37static u_int32_t 38bdb_db_hash( 39 DB *db, 40 const void *bytes, 41 u_int32_t length 42) 43{ 44 u_int32_t ret = 0; 45 unsigned char *dst = (unsigned char *)&ret; 46 const unsigned char *src = (const unsigned char *)bytes; 47 48 if ( length > sizeof(u_int32_t) ) 49 length = sizeof(u_int32_t); 50 51 while ( length ) { 52 *dst++ = *src++; 53 length--; 54 } 55 return ret; 56} 57#define BDB_INDEXTYPE DB_HASH 58#else 59#define BDB_INDEXTYPE DB_BTREE 60#endif 61 62/* If a configured size is found, return it, otherwise return 0 */ 63int 64bdb_db_findsize( 65 struct bdb_info *bdb, 66 struct berval *name 67) 68{ 69 struct bdb_db_pgsize *bp; 70 int rc; 71 72 for ( bp = bdb->bi_pagesizes; bp; bp=bp->bdp_next ) { 73 rc = strncmp( name->bv_val, bp->bdp_name.bv_val, name->bv_len ); 74 if ( !rc ) { 75 if ( name->bv_len == bp->bdp_name.bv_len ) 76 return bp->bdp_size; 77 if ( name->bv_len < bp->bdp_name.bv_len && 78 bp->bdp_name.bv_val[name->bv_len] == '.' ) 79 return bp->bdp_size; 80 } 81 } 82 return 0; 83} 84 85int 86bdb_db_cache( 87 Backend *be, 88 struct berval *name, 89 DB **dbout ) 90{ 91 int i, flags; 92 int rc; 93 struct bdb_info *bdb = (struct bdb_info *) be->be_private; 94 struct bdb_db_info *db; 95 char *file; 96 97 *dbout = NULL; 98 99 for( i=BDB_NDB; i < bdb->bi_ndatabases; i++ ) { 100 if( !ber_bvcmp( &bdb->bi_databases[i]->bdi_name, name) ) { 101 *dbout = bdb->bi_databases[i]->bdi_db; 102 return 0; 103 } 104 } 105 106 ldap_pvt_thread_mutex_lock( &bdb->bi_database_mutex ); 107 108 /* check again! may have been added by another thread */ 109 for( i=BDB_NDB; i < bdb->bi_ndatabases; i++ ) { 110 if( !ber_bvcmp( &bdb->bi_databases[i]->bdi_name, name) ) { 111 *dbout = bdb->bi_databases[i]->bdi_db; 112 ldap_pvt_thread_mutex_unlock( &bdb->bi_database_mutex ); 113 return 0; 114 } 115 } 116 117 if( i >= BDB_INDICES ) { 118 ldap_pvt_thread_mutex_unlock( &bdb->bi_database_mutex ); 119 return -1; 120 } 121 122 db = (struct bdb_db_info *) ch_calloc(1, sizeof(struct bdb_db_info)); 123 124 ber_dupbv( &db->bdi_name, name ); 125 126 rc = db_create( &db->bdi_db, bdb->bi_dbenv, 0 ); 127 if( rc != 0 ) { 128 Debug( LDAP_DEBUG_ANY, 129 "bdb_db_cache: db_create(%s) failed: %s (%d)\n", 130 bdb->bi_dbenv_home, db_strerror(rc), rc ); 131 ldap_pvt_thread_mutex_unlock( &bdb->bi_database_mutex ); 132 ch_free( db ); 133 return rc; 134 } 135 136 if( !BER_BVISNULL( &bdb->bi_db_crypt_key )) { 137 rc = db->bdi_db->set_flags( db->bdi_db, DB_ENCRYPT ); 138 if ( rc ) { 139 Debug( LDAP_DEBUG_ANY, 140 "bdb_db_cache: db set_flags(DB_ENCRYPT)(%s) failed: %s (%d)\n", 141 bdb->bi_dbenv_home, db_strerror(rc), rc ); 142 ldap_pvt_thread_mutex_unlock( &bdb->bi_database_mutex ); 143 db->bdi_db->close( db->bdi_db, 0 ); 144 ch_free( db ); 145 return rc; 146 } 147 } 148 149 if( bdb->bi_flags & BDB_CHKSUM ) { 150 rc = db->bdi_db->set_flags( db->bdi_db, DB_CHKSUM ); 151 if ( rc ) { 152 Debug( LDAP_DEBUG_ANY, 153 "bdb_db_cache: db set_flags(DB_CHKSUM)(%s) failed: %s (%d)\n", 154 bdb->bi_dbenv_home, db_strerror(rc), rc ); 155 ldap_pvt_thread_mutex_unlock( &bdb->bi_database_mutex ); 156 db->bdi_db->close( db->bdi_db, 0 ); 157 ch_free( db ); 158 return rc; 159 } 160 } 161 162 /* If no explicit size set, use the FS default */ 163 flags = bdb_db_findsize( bdb, name ); 164 if ( flags ) 165 rc = db->bdi_db->set_pagesize( db->bdi_db, flags ); 166 167#ifdef BDB_INDEX_USE_HASH 168 rc = db->bdi_db->set_h_hash( db->bdi_db, bdb_db_hash ); 169#endif 170 rc = db->bdi_db->set_flags( db->bdi_db, DB_DUP | DB_DUPSORT ); 171 172 file = ch_malloc( db->bdi_name.bv_len + sizeof(BDB_SUFFIX) ); 173 strcpy( file, db->bdi_name.bv_val ); 174 strcpy( file+db->bdi_name.bv_len, BDB_SUFFIX ); 175 176#ifdef HAVE_EBCDIC 177 __atoe( file ); 178#endif 179 flags = DB_CREATE | DB_THREAD; 180#ifdef DB_AUTO_COMMIT 181 if ( !( slapMode & SLAP_TOOL_QUICK )) 182 flags |= DB_AUTO_COMMIT; 183#endif 184 /* Cannot Truncate when Transactions are in use */ 185 if ( (slapMode & (SLAP_TOOL_QUICK|SLAP_TRUNCATE_MODE)) == 186 (SLAP_TOOL_QUICK|SLAP_TRUNCATE_MODE)) 187 flags |= DB_TRUNCATE; 188 189 rc = DB_OPEN( db->bdi_db, 190 file, NULL /* name */, 191 BDB_INDEXTYPE, bdb->bi_db_opflags | flags, bdb->bi_dbenv_mode ); 192 193 ch_free( file ); 194 195 if( rc != 0 ) { 196 Debug( LDAP_DEBUG_ANY, 197 "bdb_db_cache: db_open(%s) failed: %s (%d)\n", 198 name->bv_val, db_strerror(rc), rc ); 199 ldap_pvt_thread_mutex_unlock( &bdb->bi_database_mutex ); 200 return rc; 201 } 202 203 bdb->bi_databases[i] = db; 204 bdb->bi_ndatabases = i+1; 205 206 *dbout = db->bdi_db; 207 208 ldap_pvt_thread_mutex_unlock( &bdb->bi_database_mutex ); 209 return 0; 210} 211