io.permazen.kv.caching.CachingKVTransaction Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of permazen-kv-caching Show documentation
Show all versions of permazen-kv-caching Show documentation
Permazen key/value store classes related to caching.
/*
* Copyright (C) 2015 Archie L. Cobbs. All rights reserved.
*/
package io.permazen.kv.caching;
import io.permazen.kv.CloseableKVStore;
import io.permazen.kv.KVPair;
import io.permazen.kv.KVTransaction;
import io.permazen.kv.mvcc.MutableView;
import io.permazen.kv.mvcc.Mutations;
import io.permazen.kv.mvcc.Writes;
import io.permazen.util.CloseableIterator;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
/**
* A transaction associated with a {@link CachingKVDatabase}.
*
*
* Instances create the following "stack":
*
* - A {@link MutableView} to collect any mutations
* - A {@link CachingKVStore} to cache transaction data
* - The underlying {@link KVTransaction}
*
*/
public class CachingKVTransaction extends AbstractCachingConfig implements KVTransaction, CloseableKVStore {
/**
* The associated database.
*/
protected final CachingKVDatabase kvdb;
/**
* The {@link MutableView} that accumulates any mutations.
*/
protected final MutableView view;
/**
* The caching layer for the transaction.
*/
protected final CachingKVStore cachingKV;
/**
* The underlying transaction.
*/
protected final KVTransaction inner;
CachingKVTransaction(CachingKVDatabase kvdb, KVTransaction inner, ExecutorService executor, long rttEstimate) {
this.kvdb = kvdb;
this.inner = inner;
this.cachingKV = new CachingKVStore(inner, executor, rttEstimate);
this.kvdb.copyCachingConfigTo(this.cachingKV);
this.view = new MutableView(this.cachingKV);
this.view.disableReadTracking();
}
/**
* Get the underlying {@link KVTransaction}.
*
* @return the wrapped {@link KVTransaction}
*/
public KVTransaction getInnerTransaction() {
return this.inner;
}
/**
* Get the underlying {@link CachingKVStore} utilized by this instance.
*
* @return the internal {@link CachingKVStore}
*/
public CachingKVStore getCachingKVStore() {
return this.cachingKV;
}
// Closeable
@Override
public void close() {
this.kvdb.updateRttEstimate(this.cachingKV.getRttEstimate());
this.cachingKV.close();
this.inner.rollback();
}
// KVStore
@Override
public byte[] get(byte[] key) {
return this.view.get(key);
}
@Override
public KVPair getAtLeast(byte[] minKey, byte[] maxKey) {
return this.view.getAtLeast(minKey, maxKey);
}
@Override
public KVPair getAtMost(byte[] maxKey, byte[] minKey) {
return this.view.getAtMost(maxKey, minKey);
}
@Override
public CloseableIterator getRange(byte[] minKey, byte[] maxKey, boolean reverse) {
return this.view.getRange(minKey, maxKey, reverse);
}
@Override
public void put(byte[] key, byte[] value) {
this.view.put(key, value);
}
@Override
public void remove(byte[] key) {
this.view.remove(key);
}
@Override
public void removeRange(byte[] minKey, byte[] maxKey) {
this.view.removeRange(minKey, maxKey);
}
@Override
public void adjustCounter(byte[] key, long amount) {
this.view.adjustCounter(key, amount);
}
@Override
public byte[] encodeCounter(long value) {
return this.view.encodeCounter(value);
}
@Override
public long decodeCounter(byte[] bytes) {
return this.view.decodeCounter(bytes);
}
@Override
public void apply(Mutations mutations) {
this.view.apply(mutations);
}
// KVTransaction
@Override
public CachingKVDatabase getKVDatabase() {
return this.kvdb;
}
@Override
public void setTimeout(long timeout) {
this.inner.setTimeout(timeout);
}
@Override
public boolean isReadOnly() {
return this.inner.isReadOnly();
}
@Override
public void setReadOnly(boolean readOnly) {
this.inner.setReadOnly(readOnly);
}
@Override
public Future watchKey(byte[] key) {
return this.inner.watchKey(key);
}
@Override
public void commit() {
// Grab transaction reads & writes, set to immutable
final Writes writes;
synchronized (this.view) {
writes = this.view.getWrites();
this.view.setReadOnly();
this.cachingKV.close(); // this tells background read-ahead threads to ignore subsequent exceptions
}
// Apply writes and commit tx
try {
this.applyWritesBeforeCommitIfNotReadOnly(writes);
this.inner.commit();
} finally {
this.close();
}
}
@Override
public void rollback() {
try {
this.inner.rollback();
} finally {
this.close();
}
}
@Override
public CloseableKVStore mutableSnapshot() {
return this.inner.mutableSnapshot();
}
// Other methods
/**
* Apply accumulated mutations just prior to {@link commit commit()}'ing the transaction.
*
*
* The implementation in {@link CachingKVTransaction} checks whether the inner transaction {@link #isReadOnly},
* and if so invokes {@link Writes#applyTo Writes.applyTo}.
*
* @param writes the mutations to apply
*/
protected void applyWritesBeforeCommitIfNotReadOnly(Writes writes) {
if (!this.inner.isReadOnly())
writes.applyTo(this.inner);
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy