blob: 8cd20693e5eb74f6f6b7b3e86daf13c403ce7808 [file] [log] [blame]
/*
* Copyright 2004-2005 The Apache Software Foundation or its licensors,
* as applicable.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.jackrabbit.core.state.bdb;
import com.sleepycat.je.Database;
import com.sleepycat.je.DatabaseConfig;
import com.sleepycat.je.DatabaseEntry;
import com.sleepycat.je.Environment;
import com.sleepycat.je.EnvironmentConfig;
import com.sleepycat.je.LockMode;
import com.sleepycat.je.OperationStatus;
import com.sleepycat.je.Transaction;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.jackrabbit.core.NodeId;
import org.apache.jackrabbit.core.PropertyId;
import org.apache.jackrabbit.core.fs.FileSystem;
import org.apache.jackrabbit.core.fs.local.LocalFileSystem;
import org.apache.jackrabbit.core.state.AbstractPersistenceManager;
import org.apache.jackrabbit.core.state.ChangeLog;
import org.apache.jackrabbit.core.state.ItemStateException;
import org.apache.jackrabbit.core.state.NoSuchItemStateException;
import org.apache.jackrabbit.core.state.NodeReferences;
import org.apache.jackrabbit.core.state.NodeReferencesId;
import org.apache.jackrabbit.core.state.NodeState;
import org.apache.jackrabbit.core.state.PMContext;
import org.apache.jackrabbit.core.state.PropertyState;
import org.apache.jackrabbit.core.state.util.BLOBStore;
import org.apache.jackrabbit.core.state.util.FileSystemBLOBStore;
import java.io.File;
public class BerkeleyDBPersistenceManager extends AbstractPersistenceManager {
private static Log log = LogFactory.getLog(BerkeleyDBPersistenceManager.class);
protected static final String ENCODING = "UTF-8";
private boolean initialized = false;
private Environment environment;
private Database database;
// file system where BLOB data is stored
private FileSystem blobFS;
// BLOBStore that manages BLOB data in the file system
private BLOBStore blobStore;
private ThreadLocal localTransaction = new ThreadLocal(); // ?? are persistence managers thread-safes ???
//
public void init(PMContext context) throws Exception {
if (initialized) {
throw new IllegalStateException("already initialized");
}
// prepare the db directory
File envDir = new File(context.getHomeDir(), "db");
if (!envDir.exists()) {
envDir.mkdirs();
}
log.debug("init berkeleyDb environment at " + envDir.getAbsolutePath());
// create environnement
EnvironmentConfig config = new EnvironmentConfig();
config.setAllowCreate(true);
config.setTransactional(true);
environment = new Environment(envDir, config);
// open database
DatabaseConfig dbConfig = new DatabaseConfig();
dbConfig.setAllowCreate(true);
dbConfig.setSortedDuplicates(false);
dbConfig.setTransactional(true);
database = environment.openDatabase(null, "jcrStore", dbConfig);
/**
* store BLOB data in local file system in a sub directory
* of the workspace home directory
*/
LocalFileSystem blobFS = new LocalFileSystem();
blobFS.setRoot(new File(context.getHomeDir(), "blobs"));
blobFS.init();
this.blobFS = blobFS;
blobStore = new FileSystemBLOBStore(blobFS);
initialized = true;
}
public void close() throws Exception {
if (!initialized) {
throw new IllegalStateException("not initialized");
}
log.debug("close berkeleyDb environment");
// close database
database.close();
// close environnement
environment.close();
// close BLOB file system
blobFS.close();
blobFS = null;
blobStore = null;
initialized = false;
}
//
public NodeState load(NodeId id) throws NoSuchItemStateException, ItemStateException {
try {
DatabaseEntry key = new DatabaseEntry();
DatabaseEntry value = new DatabaseEntry();
NodeStateTupleBinding tupleBinding = new NodeStateTupleBinding(id);
key.setData(id.toString().getBytes(ENCODING));
OperationStatus operationStatus = database.get(null, key, value, LockMode.DEFAULT);
if (operationStatus.equals(OperationStatus.NOTFOUND)) {
throw new NoSuchItemStateException();
}
return (NodeState) tupleBinding.entryToObject(value);
} catch (NoSuchItemStateException e) {
throw e;
} catch (Exception e) {
log.error(e);
throw new ItemStateException(e);
}
}
public PropertyState load(PropertyId id) throws NoSuchItemStateException, ItemStateException {
try {
DatabaseEntry key = new DatabaseEntry();
DatabaseEntry value = new DatabaseEntry();
PropertyStateTupleBinding tupleBinding = new PropertyStateTupleBinding(id, blobStore);
key.setData(id.toString().getBytes(ENCODING));
OperationStatus operationStatus = database.get(null, key, value, LockMode.DEFAULT);
if (operationStatus.equals(OperationStatus.NOTFOUND)) {
throw new NoSuchItemStateException();
}
return (PropertyState) tupleBinding.entryToObject(value);
} catch (NoSuchItemStateException e) {
throw e;
} catch (Exception e) {
log.error(e);
throw new ItemStateException(e);
}
}
public NodeReferences load(NodeReferencesId id) throws NoSuchItemStateException, ItemStateException {
try {
DatabaseEntry key = new DatabaseEntry();
DatabaseEntry value = new DatabaseEntry();
NodeReferencesTupleBinding tupleBinding = new NodeReferencesTupleBinding(id);
key.setData((id.toString() + ".references").getBytes(ENCODING));
OperationStatus operationStatus = database.get(null, key, value, LockMode.DEFAULT);
if (operationStatus.equals(OperationStatus.NOTFOUND)) {
throw new NoSuchItemStateException();
}
return (NodeReferences) tupleBinding.entryToObject(value);
} catch (NoSuchItemStateException e) {
throw e;
} catch (Exception e) {
log.error(e);
throw new ItemStateException(e);
}
}
public boolean exists(NodeId id) throws ItemStateException {
try {
DatabaseEntry key = new DatabaseEntry();
DatabaseEntry value = new DatabaseEntry();
key.setData(id.toString().getBytes(ENCODING));
OperationStatus operationStatus = database.get(null, key, value, LockMode.DEFAULT);
return operationStatus.equals(OperationStatus.SUCCESS);
} catch (Exception e) {
log.error(e);
throw new ItemStateException(e);
}
}
public boolean exists(PropertyId id) throws ItemStateException {
try {
DatabaseEntry key = new DatabaseEntry();
DatabaseEntry value = new DatabaseEntry();
key.setData(id.toString().getBytes(ENCODING));
OperationStatus operationStatus = database.get(null, key, value, LockMode.DEFAULT);
return operationStatus.equals(OperationStatus.SUCCESS);
} catch (Exception e) {
log.error(e);
throw new ItemStateException(e);
}
}
public boolean exists(NodeReferencesId targetId) throws ItemStateException {
try {
DatabaseEntry key = new DatabaseEntry();
DatabaseEntry value = new DatabaseEntry();
key.setData((targetId.toString() + ".references").getBytes(ENCODING));
OperationStatus operationStatus = database.get(null, key, value, LockMode.DEFAULT);
return operationStatus.equals(OperationStatus.SUCCESS);
} catch (Exception e) {
log.error(e);
throw new ItemStateException(e);
}
}
//
public synchronized void store(ChangeLog changeLog) throws ItemStateException {
Transaction transaction = null;
try {
transaction = environment.beginTransaction(null, null);
localTransaction.set(transaction);
super.store(changeLog);
transaction.commit();
} catch (Exception e) {
try {
transaction.abort();
} catch (Exception fe) {
log.fatal(fe);
}
throw new ItemStateException(e);
} finally {
localTransaction.set(null);
}
}
//
protected void store(NodeState state) throws ItemStateException {
try {
Transaction transaction = (Transaction) localTransaction.get();
DatabaseEntry key = new DatabaseEntry();
DatabaseEntry value = new DatabaseEntry();
NodeStateTupleBinding tupleBinding = new NodeStateTupleBinding();
key.setData(state.getId().toString().getBytes(ENCODING));
tupleBinding.objectToEntry(state, value);
OperationStatus operationStatus = database.put(transaction, key, value);
if (!operationStatus.equals(OperationStatus.SUCCESS)) {
throw new ItemStateException(operationStatus.toString());
}
} catch (Exception e) {
log.error(e);
throw new ItemStateException(e);
}
}
protected void store(PropertyState state) throws ItemStateException {
try {
Transaction transaction = (Transaction) localTransaction.get();
DatabaseEntry key = new DatabaseEntry();
DatabaseEntry value = new DatabaseEntry();
PropertyStateTupleBinding tupleBinding = new PropertyStateTupleBinding(blobStore);
key.setData(state.getId().toString().getBytes(ENCODING));
tupleBinding.objectToEntry(state, value);
OperationStatus operationStatus = database.put(transaction, key, value);
if (!operationStatus.equals(OperationStatus.SUCCESS)) {
throw new ItemStateException(operationStatus.toString());
}
} catch (Exception e) {
log.error(e);
throw new ItemStateException(e);
}
}
protected void store(NodeReferences refs) throws ItemStateException {
try {
Transaction transaction = (Transaction) localTransaction.get();
DatabaseEntry key = new DatabaseEntry();
DatabaseEntry value = new DatabaseEntry();
NodeReferencesTupleBinding tupleBinding = new NodeReferencesTupleBinding();
key.setData((refs.getTargetId().toString() + ".references").getBytes(ENCODING));
tupleBinding.objectToEntry(refs, value);
OperationStatus operationStatus = database.put(transaction, key, value);
if (!operationStatus.equals(OperationStatus.SUCCESS)) {
throw new ItemStateException(operationStatus.toString());
}
} catch (Exception e) {
log.error(e);
throw new ItemStateException(e);
}
}
protected void destroy(NodeState state) throws ItemStateException {
try {
Transaction transaction = (Transaction) localTransaction.get();
DatabaseEntry key = new DatabaseEntry();
key.setData(state.getId().toString().getBytes(ENCODING));
OperationStatus operationStatus = database.delete(transaction, key);
if (!operationStatus.equals(OperationStatus.SUCCESS)) {
throw new ItemStateException(operationStatus.toString());
}
} catch (Exception e) {
log.error(e);
throw new ItemStateException(e);
}
}
protected void destroy(PropertyState state) throws ItemStateException {
try {
Transaction transaction = (Transaction) localTransaction.get();
DatabaseEntry key = new DatabaseEntry();
key.setData(state.getId().toString().getBytes(ENCODING));
OperationStatus operationStatus = database.delete(transaction, key);
if (!operationStatus.equals(OperationStatus.SUCCESS)) {
throw new ItemStateException(operationStatus.toString());
}
} catch (Exception e) {
log.error(e);
throw new ItemStateException(e);
}
}
protected void destroy(NodeReferences refs) throws ItemStateException {
try {
Transaction transaction = (Transaction) localTransaction.get();
DatabaseEntry key = new DatabaseEntry();
key.setData((refs.getTargetId().toString() + ".references").getBytes(ENCODING));
OperationStatus operationStatus = database.delete(transaction, key);
if (!operationStatus.equals(OperationStatus.SUCCESS)) {
throw new ItemStateException(operationStatus.toString());
}
} catch (Exception e) {
log.error(e);
throw new ItemStateException(e);
}
}
}