001 /* 002 * CDDL HEADER START 003 * 004 * The contents of this file are subject to the terms of the 005 * Common Development and Distribution License, Version 1.0 only 006 * (the "License"). You may not use this file except in compliance 007 * with the License. 008 * 009 * You can obtain a copy of the license at 010 * trunk/opends/resource/legal-notices/OpenDS.LICENSE 011 * or https://OpenDS.dev.java.net/OpenDS.LICENSE. 012 * See the License for the specific language governing permissions 013 * and limitations under the License. 014 * 015 * When distributing Covered Code, include this CDDL HEADER in each 016 * file and include the License file at 017 * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, 018 * add the following below this CDDL HEADER, with the fields enclosed 019 * by brackets "[]" replaced with your own identifying information: 020 * Portions Copyright [yyyy] [name of copyright owner] 021 * 022 * CDDL HEADER END 023 * 024 * 025 * Copyright 2006-2008 Sun Microsystems, Inc. 026 */ 027 package org.opends.server.backends.jeb; 028 029 import com.sleepycat.je.*; 030 031 import static org.opends.server.loggers.debug.DebugLogger.*; 032 import org.opends.server.loggers.debug.DebugTracer; 033 import org.opends.server.types.DebugLogLevel; 034 035 /** 036 * This class is a wrapper around the JE database object and provides basic 037 * read and write methods for entries. 038 */ 039 public abstract class DatabaseContainer 040 { 041 /** 042 * The tracer object for the debug logger. 043 */ 044 private static final DebugTracer TRACER = getTracer(); 045 046 /** 047 * The database entryContainer. 048 */ 049 protected EntryContainer entryContainer; 050 051 /** 052 * The JE database configuration. 053 */ 054 protected DatabaseConfig dbConfig; 055 056 /** 057 * The name of the database within the entryContainer. 058 */ 059 protected String name; 060 061 /** 062 * The reference to the JE Environment. 063 */ 064 private Environment env; 065 066 /** 067 * A JE database handle opened through this database 068 * container. 069 */ 070 private Database database; 071 072 /** 073 * Create a new DatabaseContainer object. 074 * 075 * @param name The name of the entry database. 076 * @param env The JE Environment. 077 * @param entryContainer The entryContainer of the entry database. 078 * @throws DatabaseException if a JE database error occurs. 079 */ 080 protected DatabaseContainer(String name, Environment env, 081 EntryContainer entryContainer) 082 throws DatabaseException 083 { 084 this.env = env; 085 this.entryContainer = entryContainer; 086 this.name = name; 087 } 088 089 /** 090 * Opens a JE database in this database container. If the provided 091 * database configuration is transactional, a transaction will be 092 * created and used to perform the open. 093 * 094 * @throws DatabaseException if a JE database error occurs while 095 * openning the index. 096 */ 097 public void open() throws DatabaseException 098 { 099 if (dbConfig.getTransactional()) 100 { 101 // Open the database under a transaction. 102 Transaction txn = 103 entryContainer.beginTransaction(); 104 try 105 { 106 database = env.openDatabase(txn, name, dbConfig); 107 if (debugEnabled()) 108 { 109 TRACER.debugVerbose("JE database %s opened. txnid=%d", 110 database.getDatabaseName(), 111 txn.getId()); 112 } 113 entryContainer.transactionCommit(txn); 114 } 115 catch (DatabaseException e) 116 { 117 entryContainer.transactionAbort(txn); 118 throw e; 119 } 120 } 121 else 122 { 123 database = env.openDatabase(null, name, dbConfig); 124 if (debugEnabled()) 125 { 126 TRACER.debugVerbose("JE database %s opened. txnid=none", 127 database.getDatabaseName()); 128 } 129 } 130 } 131 132 /** 133 * Flush any cached database information to disk and close the 134 * database container. 135 * 136 * The database container should not be closed while other processes 137 * aquired the container. The container should not be closed 138 * while cursors handles into the database remain open, or 139 * transactions that include operations on the database have not yet 140 * been commited or aborted. 141 * 142 * The container may not be accessed again after this method is 143 * called, regardless of the method's success or failure. 144 * 145 * @throws DatabaseException if an error occurs. 146 */ 147 synchronized void close() throws DatabaseException 148 { 149 if(dbConfig.getDeferredWrite()) 150 { 151 database.sync(); 152 } 153 database.close(); 154 database = null; 155 156 if(debugEnabled()) 157 { 158 TRACER.debugInfo("Closed database %s", name); 159 } 160 } 161 162 /** 163 * Replace or insert a record into a JE database, with optional debug logging. 164 * This is a simple wrapper around the JE Database.put method. 165 * @param txn The JE transaction handle, or null if none. 166 * @param key The record key. 167 * @param data The record value. 168 * @return The operation status. 169 * @throws DatabaseException If an error occurs in the JE operation. 170 */ 171 protected OperationStatus put(Transaction txn, DatabaseEntry key, 172 DatabaseEntry data) 173 throws DatabaseException 174 { 175 OperationStatus status = database.put(txn, key, data); 176 if (debugEnabled()) 177 { 178 TRACER.debugJEAccess(DebugLogLevel.VERBOSE, status, database, 179 txn, key, data); 180 } 181 return status; 182 } 183 184 /** 185 * Read a record from a JE database, with optional debug logging. This is a 186 * simple wrapper around the JE Database.get method. 187 * @param txn The JE transaction handle, or null if none. 188 * @param key The key of the record to be read. 189 * @param data The record value returned as output. Its byte array does not 190 * need to be initialized by the caller. 191 * @param lockMode The JE locking mode to be used for the read. 192 * @return The operation status. 193 * @throws DatabaseException If an error occurs in the JE operation. 194 */ 195 protected OperationStatus read(Transaction txn, 196 DatabaseEntry key, DatabaseEntry data, 197 LockMode lockMode) 198 throws DatabaseException 199 { 200 OperationStatus status = database.get(txn, key, data, lockMode); 201 if (debugEnabled()) 202 { 203 TRACER.debugJEAccess(DebugLogLevel.VERBOSE, status, database, txn, key, 204 data); 205 } 206 return status; 207 } 208 209 /** 210 * Insert a record into a JE database, with optional debug logging. This is a 211 * simple wrapper around the JE Database.putNoOverwrite method. 212 * @param txn The JE transaction handle, or null if none. 213 * @param key The record key. 214 * @param data The record value. 215 * @return The operation status. 216 * @throws DatabaseException If an error occurs in the JE operation. 217 */ 218 protected OperationStatus insert(Transaction txn, 219 DatabaseEntry key, DatabaseEntry data) 220 throws DatabaseException 221 { 222 OperationStatus status = database.putNoOverwrite(txn, key, data); 223 if (debugEnabled()) 224 { 225 TRACER.debugJEAccess(DebugLogLevel.VERBOSE, status, database, txn, key, 226 data); 227 } 228 return status; 229 } 230 231 /** 232 * Delete a record from a JE database, with optional debug logging. This is a 233 * simple wrapper around the JE Database.delete method. 234 * @param txn The JE transaction handle, or null if none. 235 * @param key The key of the record to be read. 236 * @return The operation status. 237 * @throws DatabaseException If an error occurs in the JE operation. 238 */ 239 protected OperationStatus delete(Transaction txn, 240 DatabaseEntry key) 241 throws DatabaseException 242 { 243 OperationStatus status = database.delete(txn, key); 244 if (debugEnabled()) 245 { 246 TRACER.debugJEAccess(DebugLogLevel.VERBOSE, status, database, txn, 247 key, null); 248 } 249 return status; 250 } 251 252 /** 253 * Open a JE cursor on the DN database. 254 * @param txn A JE database transaction to be used by the cursor, 255 * or null if none. 256 * @param cursorConfig The JE cursor configuration. 257 * @return A JE cursor. 258 * @throws DatabaseException If an error occurs while attempting to open 259 * the cursor. 260 */ 261 public Cursor openCursor(Transaction txn, CursorConfig cursorConfig) 262 throws DatabaseException 263 { 264 return database.openCursor(txn, cursorConfig); 265 } 266 267 /** 268 * Get the count of key/data pairs in the database in a JE database. 269 * This is a simple wrapper around the JE Database.count method. 270 * @return The count of key/data pairs in the database. 271 * @throws DatabaseException If an error occurs in the JE operation. 272 */ 273 public long getRecordCount() throws DatabaseException 274 { 275 long count = database.count(); 276 if (debugEnabled()) 277 { 278 TRACER.debugJEAccess(DebugLogLevel.VERBOSE, OperationStatus.SUCCESS, 279 database, null, null, null); 280 } 281 return count; 282 } 283 284 /** 285 * Get a string representation of this object. 286 * @return return A string representation of this object. 287 */ 288 public String toString() 289 { 290 return name; 291 } 292 293 /** 294 * Get the JE database name for this database container. 295 * 296 * @return JE database name for this database container. 297 */ 298 public String getName() 299 { 300 return name; 301 } 302 303 /** 304 * Preload the database into cache. 305 * 306 * @param config The preload configuration. 307 * @return Statistics about the preload process. 308 * @throws DatabaseException If an JE database error occurs 309 * during the preload. 310 */ 311 public PreloadStats preload(PreloadConfig config) 312 throws DatabaseException 313 { 314 return database.preload(config); 315 } 316 317 /** 318 * Set the JE database name to use for this container. 319 * 320 * @param name The database name to use for this container. 321 */ 322 void setName(String name) 323 { 324 this.name = name; 325 } 326 }