io.permazen.kv.lmdb.LMDBKVTransaction Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of permazen-kv-lmdb Show documentation
Show all versions of permazen-kv-lmdb Show documentation
Permazen key/value store implementation based on LMDB.
The newest version!
/*
* Copyright (C) 2015 Archie L. Cobbs. All rights reserved.
*/
package io.permazen.kv.lmdb;
import com.google.common.base.Preconditions;
import io.permazen.kv.CloseableKVStore;
import io.permazen.kv.KVStore;
import io.permazen.kv.KVTransaction;
import io.permazen.kv.StaleKVTransactionException;
import io.permazen.kv.mvcc.MutableView;
import io.permazen.kv.util.ForwardingKVStore;
import java.util.concurrent.Future;
import javax.annotation.concurrent.GuardedBy;
import javax.annotation.concurrent.ThreadSafe;
import org.lmdbjava.Dbi;
import org.lmdbjava.Env;
import org.lmdbjava.Txn;
/**
* LMDB transaction viewed as a {@link KVTransaction}.
*
* @param buffer type
*/
@ThreadSafe
public abstract class LMDBKVTransaction extends ForwardingKVStore implements KVTransaction {
// Lock order: (1) LMDBKVTransaction, (2) LMDBKVDatabase
private final LMDBKVDatabase kvdb;
private final Env env;
private final Dbi db;
@GuardedBy("this")
private Txn tx;
@GuardedBy("this")
private LMDBKVStore kv;
@GuardedBy("this")
private KVStore delegate;
@GuardedBy("this")
private boolean readOnly;
@GuardedBy("this")
private boolean closed;
/**
* Constructor.
*
* @param kvdb associated database
* @param env environment
* @param db database handle
*/
protected LMDBKVTransaction(LMDBKVDatabase kvdb, Env env, Dbi db) {
this.kvdb = kvdb;
this.env = env;
this.db = db;
}
// KVTransaction
@Override
public LMDBKVDatabase getKVDatabase() {
return this.kvdb;
}
@Override
public synchronized void commit() {
if (this.closed)
throw new StaleKVTransactionException(this, "transaction closed");
this.kvdb.transactionClosed(this);
this.closed = true;
if (this.kv != null) {
this.kv.close();
this.tx.commit();
this.tx = null;
}
}
@Override
public synchronized void rollback() {
if (this.closed)
return;
this.kvdb.transactionClosed(this);
this.closed = true;
if (this.kv != null) {
this.kv.close();
this.tx.abort();
this.tx = null;
}
}
@Override
public synchronized boolean isReadOnly() {
return this.readOnly;
}
@Override
public synchronized void setReadOnly(boolean readOnly) {
if (this.closed)
throw new StaleKVTransactionException(this, "transaction closed");
Preconditions.checkState(this.kv == null || readOnly == this.readOnly, "already accessed");
this.readOnly = readOnly;
}
@Override
public synchronized CloseableKVStore readOnlySnapshot() {
throw new UnsupportedOperationException();
}
@Override
public void setTimeout(long timeout) {
throw new UnsupportedOperationException("setTimeout() not supported");
}
@Override
public Future watchKey(byte[] key) {
throw new UnsupportedOperationException("watchKey() not supported");
}
// ForwardingKVStore
@Override
protected synchronized KVStore delegate() {
if (this.closed)
throw new StaleKVTransactionException(this, "transaction closed");
if (this.kv == null)
this.buildKV();
return this.delegate;
}
// Internal methods
protected abstract LMDBKVStore createKVStore(Dbi db, Txn tx);
private synchronized LMDBKVStore buildKV() {
if (this.closed)
throw new StaleKVTransactionException(this, "transaction closed");
if (this.kv == null) {
assert this.delegate == null;
this.tx = this.readOnly ? this.env.txnRead() : this.env.txnWrite();
this.kv = this.createKVStore(this.db, this.tx);
this.delegate = this.readOnly ? new MutableView(this.kv, false) : this.kv;
}
return this.kv;
}
}