All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jsimpledb.kv.KVTransaction Maven / Gradle / Ivy

The newest version!

/*
 * Copyright (C) 2015 Archie L. Cobbs. All rights reserved.
 */

package org.jsimpledb.kv;

import java.util.concurrent.Future;

/**
 * {@link KVDatabase} transaction API.
 *
 * 

* Provides a transactional view of a {@link KVStore}. * *

* Instances may throw {@link KVTransactionException} during any operation if the transaction cannot be continued. * In particular, {@link StaleTransactionException} is thrown by a transaction that is no longer open, and * {@link RetryTransactionException} is thrown when the transaction should be retried due to a transient * problem (such as a write conflict with another transaction). * *

* When {@link RetryTransactionException} is thrown by {@link #commit}, the transaction may have actually been committed. * Therefore, transactions should be written to be idempotent. * *

* No matter what state it is in, instances must support invoking {@link #rollback} at any time. * *

* If an instance throws a {@link KVTransactionException}, the transaction should be implicitly rolled back. * Any subsequent operation other than {@link #rollback} should throw {@link StaleTransactionException}. * *

* Except for {@link #rollback} and methods that just query status, implementations must throw {@link StaleTransactionException} * if {@link #commit} or {@link #rollback} has already been invoked, or if the {@link KVTransaction} instance is no longer usable * for some other reason. In particular, implementations should throw {@link TransactionTimeoutException} if an operation * is attempted on a transaction that has been held open past some maximum allowed time limit. * *

* Implementations are responsible for ensuring modifications to {@code byte[]} arrays after method * invocations do no harm. This usually means {@code byte[]} array parameters and return values must be copied. * *

* Implementations are not required to support accessing keys that start with {@code 0xff}, * and if not may throw {@link IllegalArgumentException} if such keys are accessed. * *

* Note: for some implementations, the data read from a transaction that is never {@link #commit}'ed is * not guaranteed to be up to date. */ public interface KVTransaction extends KVStore { /** * Get the {@link KVDatabase} with which this instance is associated. * * @return associated database */ KVDatabase getKVDatabase(); /** * Change the timeout for this transaction from its default value (optional operation). * * @param timeout transaction timeout in milliseconds, or zero for unlimited * @throws UnsupportedOperationException if this transaction does not support timeouts * @throws IllegalArgumentException if {@code timeout} is negative * @throws StaleTransactionException if this transaction is no longer usable */ void setTimeout(long timeout); /** * Determine whether this transaction is read-only. * *

* Default is false. * * @return true if this instance is read-only * @throws StaleTransactionException if this transaction is no longer usable */ boolean isReadOnly(); /** * Enable or disable read-only mode. * *

* Read-only transactions allow mutations, but all changes are discarded on {@link #commit}. * *

* Some implementations may impose one or more of the following restrictions on this method: *

    *
  • {@link #setReadOnly setReadOnly()} may only be invoked prior to accessing data;
  • *
  • {@link #setReadOnly setReadOnly()} may only be invoked prior to mutating data; and/or
  • *
  • Once set to read-only, a transaction may not be set back to read-write
  • *
* *

* Note: for some implementations, the data read from a transaction that is never {@link #commit}'ed is * not guaranteed to be up to date, even if that transaction is read-only. * *

* Default is false. * * @param readOnly read-only setting * @throws IllegalStateException if the implementation doesn't support changing read-only status at this time * @throws StaleTransactionException if this transaction is no longer usable */ void setReadOnly(boolean readOnly); /** * Watch a key to monitor for changes in its value. * *

* When this method is invoked, {@code key}'s current value (if any) as read by this transaction is remembered. The returned * {@link Future} completes if and when a different value for {@code key} is subsequently committed by some transaction, * including possibly this one. This includes creation or deletion of the key. * *

* Key watches outlive the transaction in which they are created, persisting until they complete or are * {@link Future#cancel cancel()}'ed. When a {@link KVDatabase} is {@link KVDatabase#stop}'ed, all outstanding * key watches are implicitly {@link Future#cancel cancel()}'ed. * *

Caveats

* *

* Key watches are not without overhead; applications should avoid overuse. For example, consider creating a * single key that is used to consolidate modifications to some set of keys; at the JSimpleDB layer, modification * to multiple objects and/or fields can detected and consolidated using an * {@link org.jsimpledb.annotation.OnChange @OnChange} method that increments a single {@link org.jsimpledb.Counter} * field, whose key is then watched (to determine the key corresponding to a Java model object field, use * {@link org.jsimpledb.JTransaction#getKey(org.jsimpledb.JObject, String) JTransaction.getKey()}). * *

* Conceptually, detection of changes behaves as if by a background thread that periodically creates a new transaction * and reads the key's value (the actual implementation will likely be more efficient). This means a change that is * quickly reverted could be missed, and that multiple changes could occur before notification. In addition, spurious * notifications may occur, where the key's value has not changed. * *

* A key watch is only guaranteed to be valid if the transaction in which it was created successfully commits. * In particular, nothing is specified about how or whether {@link Future}s associated with failed transactions complete, * so the {@link Future}s returned by this method should not be relied on until after a successful commit (perhaps with * the help of a {@linkplain org.jsimpledb.core.Transaction#addCallback transaction callback}). * *

* Key watch support is optional; instances that don't support key watches throw {@link UnsupportedOperationException}. * Some implementations may only support watching a key that already exists. * *

* Note: many {@link KVDatabase} implementations actually return a * {@link com.google.common.util.concurrent.ListenableFuture}. However, listeners must not perform any * long running or blocking operations. Also, because the semantics of {@link RetryTransactionException} allow for * the possibility that the transaction actually did commit, "duplicate" listener notifications could occur. * *

* Key watch {@link Future}s that have not completed yet, but are no longer needed, must be {@link Future#cancel cancel()}'ed * to avoid memory leaks. * * @param key the key to watch * @return a {@link Future} that returns {@code key} when the value associated with {@code key} is modified * @throws StaleTransactionException if this transaction is no longer usable * @throws RetryTransactionException if this transaction must be retried and is no longer usable * @throws KVDatabaseException if an unexpected error occurs * @throws UnsupportedOperationException if this instance does not support key watches * @throws IllegalArgumentException if {@code key} starts with {@code 0xff} and such keys are not supported * @throws IllegalArgumentException if {@code key} is null * @see org.jsimpledb.JTransaction#getKey(org.jsimpledb.JObject, String) JTransaction.getKey() */ Future watchKey(byte[] key); /** * Commit this transaction. * *

* Note that if this method throws a {@link RetryTransactionException}, * the transaction was either successfully committed or rolled back. In either case, * this instance is no longer usable. * *

* Note also for some implementations, even read-only transactions must be {@link #commit}'ed in order for the * data accessed during the transaction to be guaranteed to be up to date. * * @throws StaleTransactionException if this transaction is no longer usable * @throws RetryTransactionException if this transaction must be retried and is no longer usable */ void commit(); /** * Cancel this transaction, if not already canceled. * *

* After this method returns, this instance is no longer usable. * *

* Note: for some implementations, rolling back a transaction invalidates guarantees about the the data read * during the transaction being up to date, even if the transaction was {@link #setReadOnly setReadOnly()}. * *

* This method may be invoked at any time, even after a previous invocation of * {@link #commit} or {@link #rollback}, in which case the invocation will be ignored. * In particular, this method should not throw {@link StaleTransactionException}. */ void rollback(); /** * Create a mutable copy of the database content represented by this transaction. * *

* The returned {@link CloseableKVStore} should be mutable, but all changes should remain private until * {@link CloseableKVStore#close close()} is invoked, at which time they should be discarded. * That is, the {@link CloseableKVStore} it is completely independent from this transaction * (subsequent changes to either one do not affect the other). * *

* Note that as with any other information extracted from a {@link KVTransaction}, the returned content * should not be considered valid until this transaction has been successfully committed. * *

* The returned {@link CloseableKVStore} should be promply {@link CloseableKVStore#close close()}'d when no longer * needed to release any underlying resources. In particular, the caller must ensure that the {@link CloseableKVStore} * is {@link CloseableKVStore#close close()}'d even if this transaction's commit fails. This may require * adding a transaction synchronization callback, etc. * *

* This is an optional method; only some underlying key/value store technologies can efficiently support it. * Implementations should throw {@link UnsupportedOperationException} if not supported. * * @return independent, mutable copy of this transaction's entire database content * @throws UnsupportedOperationException if this method is not supported * @throws StaleTransactionException if this transaction is no longer usable * @throws RetryTransactionException if this transaction must be retried and is no longer usable */ CloseableKVStore mutableSnapshot(); }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy