/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2000, 2015 Oracle and/or its affiliates. All rights reserved.
*
* $Id$
*/
package com.sleepycat.compat;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Comparator;
import java.util.regex.Pattern;
import com.sleepycat.db.Cursor;
import com.sleepycat.db.CursorConfig;
import com.sleepycat.db.Database;
import com.sleepycat.db.DatabaseConfig;
import com.sleepycat.db.DatabaseEntry;
import com.sleepycat.db.DatabaseException;
import com.sleepycat.db.DatabaseType;
import com.sleepycat.db.Environment;
import com.sleepycat.db.EnvironmentConfig;
import com.sleepycat.db.ErrorHandler;
import com.sleepycat.db.LockDetectMode;
import com.sleepycat.db.LockMode;
import com.sleepycat.db.OperationStatus;
import com.sleepycat.db.SecondaryConfig;
import com.sleepycat.db.SecondaryCursor;
import com.sleepycat.db.SecondaryDatabase;
import com.sleepycat.db.Transaction;
import com.sleepycat.db.TransactionConfig;
/**
* A minimal set of DB-JE compatibility methods for internal use only.
* Two versions are maintained in parallel in the DB and JE source trees.
* Used by the collections package.
*/
public class DbCompat {
/* Capabilities */
public static final boolean CDB = true;
public static final boolean JOIN = true;
public static final boolean NESTED_TRANSACTIONS = true;
public static final boolean INSERTION_ORDERED_DUPLICATES = true;
public static final boolean SEPARATE_DATABASE_FILES = true;
public static final boolean MEMORY_SUBSYSTEM = true;
public static final boolean LOCK_SUBSYSTEM = true;
public static final boolean HASH_METHOD = true;
public static final boolean RECNO_METHOD = true;
public static final boolean QUEUE_METHOD = true;
public static final boolean BTREE_RECNUM_METHOD = true;
public static final boolean OPTIONAL_READ_UNCOMMITTED = true;
public static final boolean SECONDARIES = true;
public static boolean TRANSACTION_RUNNER_PRINT_STACK_TRACES = true;
public static final boolean DATABASE_COUNT = false;
public static final boolean NEW_JE_EXCEPTIONS = false;
public static final boolean POPULATE_ENFORCES_CONSTRAINTS = false;
private static boolean fSystemCaseSensitive = true;
/* Check if the underlying file system is case sensitive */
static {
File file1 = new File("no_such_file");
File file2 = new File("NO_SUCH_FILE");
fSystemCaseSensitive = !file1.equals(file2);
}
/* Methods used by the collections package. */
public static ClassLoader getClassLoader(Environment env) {
return null;
}
public static boolean getInitializeCache(EnvironmentConfig config) {
return config.getInitializeCache();
}
public static boolean getInitializeLocking(EnvironmentConfig config) {
return config.getInitializeLocking();
}
public static boolean getInitializeCDB(EnvironmentConfig config) {
return config.getInitializeCDB();
}
public static boolean isTypeBtree(DatabaseConfig dbConfig) {
return dbConfig.getType() == DatabaseType.BTREE;
}
public static boolean isTypeHash(DatabaseConfig dbConfig) {
return dbConfig.getType() == DatabaseType.HASH;
}
public static boolean isTypeQueue(DatabaseConfig dbConfig) {
return dbConfig.getType() == DatabaseType.QUEUE;
}
public static boolean isTypeRecno(DatabaseConfig dbConfig) {
return dbConfig.getType() == DatabaseType.RECNO;
}
public static boolean getBtreeRecordNumbers(DatabaseConfig dbConfig) {
return dbConfig.getBtreeRecordNumbers();
}
public static boolean getReadUncommitted(DatabaseConfig dbConfig) {
return dbConfig.getReadUncommitted();
}
public static boolean getRenumbering(DatabaseConfig dbConfig) {
return dbConfig.getRenumbering();
}
public static boolean getSortedDuplicates(DatabaseConfig dbConfig) {
return dbConfig.getSortedDuplicates();
}
public static boolean getUnsortedDuplicates(DatabaseConfig dbConfig) {
return dbConfig.getUnsortedDuplicates();
}
public static boolean getDeferredWrite(DatabaseConfig dbConfig) {
return false;
}
// XXX Remove this when DB and JE support CursorConfig.cloneConfig
public static CursorConfig cloneCursorConfig(CursorConfig config) {
CursorConfig newConfig = new CursorConfig();
newConfig.setReadCommitted(config.getReadCommitted());
newConfig.setReadUncommitted(config.getReadUncommitted());
newConfig.setWriteCursor(config.getWriteCursor());
return newConfig;
}
public static boolean getWriteCursor(CursorConfig config) {
return config.getWriteCursor();
}
public static void setWriteCursor(CursorConfig config, boolean val) {
config.setWriteCursor(val);
}
public static void setRecordNumber(DatabaseEntry entry, int recNum) {
entry.setRecordNumber(recNum);
}
public static int getRecordNumber(DatabaseEntry entry) {
return entry.getRecordNumber();
}
public static String getDatabaseFile(Database db)
throws DatabaseException {
return db.getDatabaseFile();
}
public static long getDatabaseCount(Database db)
throws DatabaseException {
throw new UnsupportedOperationException();
}
public static void syncDeferredWrite(Database db, boolean flushLog)
throws DatabaseException {
}
public static OperationStatus getCurrentRecordNumber(Cursor cursor,
DatabaseEntry key,
LockMode lockMode)
throws DatabaseException {
return cursor.getRecordNumber(key, lockMode);
}
public static OperationStatus getSearchRecordNumber(Cursor cursor,
DatabaseEntry key,
DatabaseEntry data,
LockMode lockMode)
throws DatabaseException {
return cursor.getSearchRecordNumber(key, data, lockMode);
}
public static OperationStatus getSearchRecordNumber(SecondaryCursor cursor,
DatabaseEntry key,
DatabaseEntry pKey,
DatabaseEntry data,
LockMode lockMode)
throws DatabaseException {
return cursor.getSearchRecordNumber(key, pKey, data, lockMode);
}
public static OperationStatus putAfter(Cursor cursor,
DatabaseEntry key,
DatabaseEntry data)
throws DatabaseException {
return cursor.putAfter(key, data);
}
public static OperationStatus putBefore(Cursor cursor,
DatabaseEntry key,
DatabaseEntry data)
throws DatabaseException {
return cursor.putBefore(key, data);
}
public static OperationStatus append(Database db,
Transaction txn,
DatabaseEntry key,
DatabaseEntry data)
throws DatabaseException {
return db.append(txn, key, data);
}
public static Transaction getThreadTransaction(Environment env)
throws DatabaseException {
return null;
}
/* Methods used by the collections tests. */
public static void setInitializeCache(EnvironmentConfig config,
boolean val) {
config.setInitializeCache(val);
}
public static void setInitializeLocking(EnvironmentConfig config,
boolean val) {
config.setInitializeLocking(val);
}
public static void setInitializeCDB(EnvironmentConfig config,
boolean val) {
config.setInitializeCDB(val);
}
public static void setLockDetectModeOldest(EnvironmentConfig config) {
config.setLockDetectMode(LockDetectMode.OLDEST);
}
public static void setBtreeComparator(DatabaseConfig dbConfig,
Comparator comparator) {
dbConfig.setBtreeComparator(comparator);
}
public static void setTypeBtree(DatabaseConfig dbConfig) {
dbConfig.setType(DatabaseType.BTREE);
}
public static void setTypeHash(DatabaseConfig dbConfig) {
dbConfig.setType(DatabaseType.HASH);
}
public static void setTypeRecno(DatabaseConfig dbConfig) {
dbConfig.setType(DatabaseType.RECNO);
}
public static void setTypeQueue(DatabaseConfig dbConfig) {
dbConfig.setType(DatabaseType.QUEUE);
}
public static void setBtreeRecordNumbers(DatabaseConfig dbConfig,
boolean val) {
dbConfig.setBtreeRecordNumbers(val);
}
public static void setReadUncommitted(DatabaseConfig dbConfig,
boolean val) {
dbConfig.setReadUncommitted(val);
}
public static void setRenumbering(DatabaseConfig dbConfig,
boolean val) {
dbConfig.setRenumbering(val);
}
public static void setSortedDuplicates(DatabaseConfig dbConfig,
boolean val) {
dbConfig.setSortedDuplicates(val);
}
public static void setUnsortedDuplicates(DatabaseConfig dbConfig,
boolean val) {
dbConfig.setUnsortedDuplicates(val);
}
public static void setDeferredWrite(DatabaseConfig dbConfig, boolean val) {
}
public static void setRecordLength(DatabaseConfig dbConfig, int val) {
dbConfig.setRecordLength(val);
}
public static void setRecordPad(DatabaseConfig dbConfig, int val) {
dbConfig.setRecordPad(val);
}
public static boolean databaseExists(Environment env,
String fileName,
String dbName) {
/* Currently we only support file names. */
assert fileName != null;
assert dbName == null;
try {
Database db = env.openDatabase(null, fileName, dbName, null);
db.close();
return true;
} catch (DatabaseException e) {
throw new RuntimeException(e);
} catch (FileNotFoundException e) {
return false;
}
}
public static Database openDatabase(Environment env,
Transaction txn,
String fileName,
String dbName,
DatabaseConfig config)
throws DatabaseException {
/* Currently we only support file names. */
assert fileName != null;
assert dbName == null;
try {
return env.openDatabase(txn, fileName, dbName, config);
} catch (DatabaseException e) {
if (isFileExistsError(e)) {
return null;
}
throw e;
} catch (FileNotFoundException e) {
return null;
}
}
public static SecondaryDatabase openSecondaryDatabase(
Environment env,
Transaction txn,
String fileName,
String dbName,
Database primaryDatabase,
SecondaryConfig config)
throws DatabaseException {
/* Currently we only support file names. */
assert fileName != null;
assert dbName == null;
try {
return env.openSecondaryDatabase
(txn, fileName, dbName, primaryDatabase, config);
} catch (DatabaseException e) {
if (isFileExistsError(e)) {
return null;
}
throw e;
} catch (FileNotFoundException e) {
return null;
}
}
public static boolean truncateDatabase(Environment env,
Transaction txn,
String fileName,
String dbName)
throws DatabaseException {
/* Currently we only support file names. */
assert fileName != null;
assert dbName == null;
Database db;
try {
db = env.openDatabase(txn, fileName, dbName, null);
} catch (FileNotFoundException e) {
return false;
}
try {
db.truncate(txn, false /*returnCount*/);
return true;
} finally {
db.close();
}
}
public static boolean removeDatabase(Environment env,
Transaction txn,
String fileName,
String dbName)
throws DatabaseException {
/* Currently we only support file names. */
assert fileName != null;
assert dbName == null;
try {
env.removeDatabase(txn, fileName, dbName);
return true;
} catch (FileNotFoundException e) {
return false;
}
}
public static boolean renameDatabase(Environment env,
Transaction txn,
String oldFileName,
String oldDbName,
String newFileName,
String newDbName)
throws DatabaseException {
/* Currently we only support file names. */
assert oldFileName != null;
assert newFileName != null;
assert oldDbName == null;
assert newDbName == null;
try {
File oldFile = new File(oldFileName);
File newFile = new File(newFileName);
if(!oldFile.equals(newFile)) {
env.renameDatabase(txn, oldFileName, null, newFileName);
}
if (oldDbName != null && !oldDbName.equals(newDbName)) {
env.renameDatabase(txn, newFileName, oldDbName, newDbName);
}
return true;
} catch (FileNotFoundException e) {
return false;
}
}
public static Database testOpenDatabase(Environment env,
Transaction txn,
String file,
String name,
DatabaseConfig config)
throws DatabaseException {
/* Currently we only support file names. */
assert file != null;
assert name == null;
try {
return env.openDatabase(txn, file, name, config);
} catch (DatabaseException e) {
if (isFileExistsError(e)) {
assert false;
return null;
}
throw e;
} catch (FileNotFoundException e) {
assert false;
return null;
}
}
public static SecondaryDatabase
testOpenSecondaryDatabase(Environment env,
Transaction txn,
String file,
String name,
Database primary,
SecondaryConfig config)
throws DatabaseException {
/* Currently we only support file names. */
assert file != null;
assert name == null;
try {
return env.openSecondaryDatabase(txn, file, name, primary, config);
} catch (DatabaseException e) {
if (isFileExistsError(e)) {
assert false;
return null;
}
throw e;
} catch (FileNotFoundException e) {
assert false;
return null;
}
}
/**
* Would like to check for errno 17 (EEXIST) but the value may not be
* standard on all platforms.
*/
private static boolean isFileExistsError(DatabaseException e) {
return (e.getMessage().contains("File exists") ||
e.getMessage().contains("Do not specify an existing file"));
}
public static boolean isDalvik(){
return false;
}
public static boolean setImportunate(final Transaction txn,
final boolean importunate) {
return false;
}
public static RuntimeException unexpectedException(Exception cause) {
if (!(cause instanceof DatabaseException)) {
cause = new DatabaseException(cause);
}
throw new RuntimeException(new DatabaseException(cause));
}
public static RuntimeException unexpectedException(String msg,
Exception cause) {
if (!(cause instanceof DatabaseException)) {
cause = new DatabaseException(cause);
}
throw new RuntimeException(new DatabaseException(cause));
}
public static RuntimeException unexpectedState(String msg) {
throw new RuntimeException(new DatabaseException(msg));
}
public static RuntimeException unexpectedState() {
throw new RuntimeException();
}
public static boolean hasCaseInsensitiveOnDiskDbFile(){
return !fSystemCaseSensitive;
}
public static void enableDeadlockDetection(EnvironmentConfig envConfig,
boolean isCDB) {
if (isCDB) {
envConfig.setCDBLockAllDatabases(true);
} else {
envConfig.setLockDetectMode(LockDetectMode.MAXWRITE);
}
}
public static Object getErrorHandler(Environment env)
throws DatabaseException {
return env.getConfig().getErrorHandler();
}
public static void setErrorHandler(Environment env, Object errHandler)
throws DatabaseException {
EnvironmentConfig config = env.getConfig();
config.setErrorHandler((ErrorHandler) errHandler);
env.setConfig(config);
}
public static void suppressError(Environment env, final Pattern errPattern)
throws DatabaseException{
if (errPattern != null) {
final EnvironmentConfig config = env.getConfig();
ErrorHandler handler = new ErrorHandler() {
public void error(Environment environment, String errpfx, String msg) {
if (!errPattern.matcher(msg).matches()) {
try {
config.getErrorStream().write(msg.getBytes());
config.getErrorStream().write("\n".getBytes());
} catch (IOException e) {
e.printStackTrace();
}
}
}
};
config.setErrorHandler(handler);
env.setConfig(config);
}
}
}