Oracle NoSQL Database Examples
version 11gR2.2.0.26

schema
Class WriteOperations

java.lang.Object
  extended by schema.WriteOperations

 class WriteOperations
extends Object

Performs write operations and retries the operation when a FaultException occurs in order to handle transient network failures. While the KVStore read methods perform retries automatically when a network failure occurs, the KVStore write methods do not. Therefore, it is recommended that write operations are performed using the methods in this class, or using a similar retry mechanism in the application.

The KVStore write methods are not defined to be strictly idempotent which means if they are performed more than once, the outcome may be different than if they were performed a single time. Repeating an operation may occur when it is retried after a network failure, if in fact the operation was successful the first time. Because of the network failure, the client is unaware of whether the first operation failed or succeeded.

For example, if KVStore.delete throws a FaultException due to a network failure, it may or may not have succeeded. Imagine that it did succeed and the network failure occurred when receiving the operation reply message. When the KVStore.delete call is retried, it will return false because the previous attempt succeeded. Of course, this can also occur if another client deletes the record, even when no retries are necessary. Therefore, the semantics of the delete method in this class are slightly different than the semantics of KVStore.delete. The delete method here does not return an indication of whether it deleted the record. The record is guaranteed to be deleted when the delete method returns without an exception, but there is no way to know whether it was deleted by this method or another client. With this change in semantics, the delete method in this class is idempotent.

Several methods in this class fall into the same category as the delete method in that they are idempotent, as they are defined here. These are: put, delete and multiDelete. When these methods return without an exception, their outcome is always the same, whether or not retries were necessary. For that reason, retrying these methods at the application level is not needed when no exception is thrown.

Most of the other methods in this class -- putIfAbsent, putIfPresent, putIfVersion and deleteIfVersion -- fall into a different category. These methods are not idempotent, even as defined here, because the application needs to decide whether the operations need to be retried in the face of concurrent access.

For example, say the application performs a KVStore.get, examines the record value and determines that it qualifies for deletion, and then calls deleteIfVersion. Say the call to KVStore.deleteIfVersion succeeds (when first called by the deleteIfVersion method here), but throws a FaultException due to a network failure. When the KVStore.deleteIfVersion call is retried, it returns false because the previous attempt succeeded and the record was deleted as a result; the deleteIfVersion method in this class will return false as well. Of course, this can also occur if another client has deleted or modified the record, even when no retries are necessary. Therefore, the meaning of a false return value from the deleteIfVersion method in this class is slightly different than for KVStore.deleteIfVersion. When false is returned by the deleteIfVersion method here, it may be because another client deleted or modified the record, or because this method itself unknowingly deleted the record and then retried the operation. Either way, the application should normally retry the higher level operation: call KVStore.get again (or use the prevValue parameter of the deleteIfVersion method) to get the current record value, and examine it again to see if the record still qualifies for deletion. In the example described, the record will no longer exist and the application should assume that it was deleted by another client or by this method itself; these two cases cannot be distinguished.

As an illustration of the difference in semantics, imagine a store that is idle except for a single client thread that is performing KVStore.get and deleteIfVersion calls (the method in this class). We also guarantee that no data migration takes place in this test, since data migration changes record versions as if another client performed an update. In this test, one might assume that the deleteIfVersion method should always return true, since no other clients are accessing the store. However, this is an incorrect assumption. If the test is run for long enough, transient network failures will eventually occur, and deleteIfVersion will return false due to scenarios such as the one described above. This may be an unexpected outcome in such a test scenario, but should be expected in a real world application due to other client activity and data migration, as well as network failures.

The following example is also noteworthy. Imagine that putIfVersion is used to increment or decrement a bank balance, or make another sort of incremental or conditional update. If null is returned by the putIfVersion method in this class (or if KVStore.putIfVersion throws a FaultException), this means the operation may or may not have succeeded. If performing the change exactly once is critical, as it would be when incrementing or decrementing a bank balance, the application must build in some means of determining whether the change succeeded or not. This explains why putIfVersion and similar methods in this class cannot simply compare the currently stored value to the value requested, to determine whether the operation succeeded. The test for success or failure must be left to the application in such cases.

The execute method is a special case, since it doesn't fall neatly into one of the two categories defined: idempotent like delete, or non-idempotent like deleteIfVersion. This is because execute can be used to perform a combination of delete and deleteIfVersion, as well as other types of write operations. The execute method in this class will retry KVStore.execute when a FaultException is thrown, and the meaning of the individual operation results will depend on the type of operation, as defined by the other methods in this class.

Note that this class does not do any exception handling, other than to retry the operation after any kind of FaultException is thrown. Up to N_RETRIES (currently two) retries are performed, and a FaultException that occurs in the last attempt is propagated to the caller. The caller should handle the exception as described in the RunOperation class in this example. In this example, calls to methods in this class are always made within the context of a RunOperation execution, and exceptions are handled by RunOperation in all cases.

A known deficiency of this class is that a network failure is not distinguished from other types of FaultExceptions that might occur; a retry is performed when any type of FaultException is thrown. This is not considered a major problem for two reasons: a) other types of failures are likely to be persistent and will quickly occur again when retrying, and b) optimizing performance when handling FaultExceptions is not normally a concern.


Nested Class Summary
(package private)  class WriteOperations.WriteOp<R,E extends Exception>
          Internal class used to perform retries for a write operation.
 
Constructor Summary
WriteOperations(KVStore store, KVStoreConfig config)
          Creates a WriteOperations wrapper for a given KVStore.
 
Method Summary
 void delete(Key key)
          Calls KVStore.delete and performs retries if a FaultException is thrown.
 void delete(Key key, ReturnValueVersion prevValue, Durability durability, long timeout, TimeUnit timeoutUnit)
          Calls KVStore.delete and performs retries if a FaultException is thrown.
 boolean deleteIfVersion(Key key, Version matchVersion)
          Calls KVStore.deleteIfVersion and performs retries if a FaultException is thrown.
 boolean deleteIfVersion(Key key, Version matchVersion, ReturnValueVersion prevValue, Durability durability, long timeout, TimeUnit timeoutUnit)
          Calls KVStore.deleteIfVersion and performs retries if a FaultException is thrown.
 List<OperationResult> execute(List<Operation> operations)
          Calls KVStore.execute and performs retries if a FaultException is thrown.
 List<OperationResult> execute(List<Operation> operations, Durability durability, long timeout, TimeUnit timeoutUnit)
          Calls KVStore.execute and performs retries if a FaultException is thrown.
 void multiDelete(Key parentKey, KeyRange subRange, Depth depth)
          Calls KVStore.multiDelete and performs retries if a FaultException is thrown.
 void multiDelete(Key parentKey, KeyRange subRange, Depth depth, Durability durability, long timeout, TimeUnit timeoutUnit)
          Calls KVStore.multiDelete and performs retries if a FaultException is thrown.
 Version put(Key key, Value value)
          Calls KVStore.put and performs retries if a FaultException is thrown.
 Version put(Key key, Value value, ReturnValueVersion prevValue, Durability durability, long timeout, TimeUnit timeoutUnit)
          Calls KVStore.put and performs retries if a FaultException is thrown.
 Version putIfAbsent(Key key, Value value)
          Calls KVStore.putIfAbsent and performs retries if a FaultException is thrown.
 Version putIfAbsent(Key key, Value value, ReturnValueVersion prevValue, Durability durability, long timeout, TimeUnit timeoutUnit)
          Calls KVStore.putIfAbsent and performs retries if a FaultException is thrown.
 Version putIfPresent(Key key, Value value)
          Calls KVStore.putIfPresent and performs retries if a FaultException is thrown.
 Version putIfPresent(Key key, Value value, ReturnValueVersion prevValue, Durability durability, long timeout, TimeUnit timeoutUnit)
          Calls KVStore.putIfPresent and performs retries if a FaultException is thrown.
 Version putIfVersion(Key key, Value value, Version matchVersion)
          Calls KVStore.putIfVersion and performs retries if a FaultException is thrown.
 Version putIfVersion(Key key, Value value, Version matchVersion, ReturnValueVersion prevValue, Durability durability, long timeout, TimeUnit timeoutUnit)
          Calls KVStore.putIfVersion and performs retries if a FaultException is thrown.
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Constructor Detail

WriteOperations

WriteOperations(KVStore store,
                KVStoreConfig config)
Creates a WriteOperations wrapper for a given KVStore.

Method Detail

put

public Version put(Key key,
                   Value value)
            throws DurabilityException,
                   RequestTimeoutException,
                   FaultException
Calls KVStore.put and performs retries if a FaultException is thrown.

This method is equivalent to put(Key, Value, ReturnValueVersion, Durability, long, TimeUnit) except that the prevValue, durability, timeout and timeoutUnit parameters are not specified and take on default values.

Throws:
DurabilityException
RequestTimeoutException
FaultException

put

public Version put(Key key,
                   Value value,
                   ReturnValueVersion prevValue,
                   Durability durability,
                   long timeout,
                   TimeUnit timeoutUnit)
            throws DurabilityException,
                   RequestTimeoutException,
                   FaultException
Calls KVStore.put and performs retries if a FaultException is thrown.

This method is idempotent in the sense that if it is called multiple times and returns without throwing an exception, the outcome is always the same: the given Key/Value pair will have been stored.

Throws:
DurabilityException
RequestTimeoutException
FaultException

putIfAbsent

public Version putIfAbsent(Key key,
                           Value value)
                    throws DurabilityException,
                           RequestTimeoutException,
                           FaultException
Calls KVStore.putIfAbsent and performs retries if a FaultException is thrown.

This method is equivalent to putIfAbsent(Key, Value, ReturnValueVersion, Durability, long, TimeUnit) except that the prevValue, durability, timeout and timeoutUnit parameters are not specified and take on default values.

Throws:
DurabilityException
RequestTimeoutException
FaultException

putIfAbsent

public Version putIfAbsent(Key key,
                           Value value,
                           ReturnValueVersion prevValue,
                           Durability durability,
                           long timeout,
                           TimeUnit timeoutUnit)
                    throws DurabilityException,
                           RequestTimeoutException,
                           FaultException
Calls KVStore.putIfAbsent and performs retries if a FaultException is thrown.

This method is not idempotent since if it is called multiple times, the outcome may be different because the key may or may not exist. When null is returned, the application is expected to take action, such as performing retries, at a higher level.

When a retry is performed by this method and it returns null because the key is present, there is no returned indication of whether the key was inserted by an earlier attempt in the same method invocation, or by another client. The application must be prepared for either case.

Because of this ambiguity, it can be difficult to use this method (instead of put) as a self-check when the key is expected to be absent, or as a way to prevent two clients from writing the same key. To do this reliably, each client must include a unique identifier in the value and check for that identifier (call KVStore.get or use the prevValue parameter of this method) when null is returned.

Throws:
DurabilityException
RequestTimeoutException
FaultException

putIfPresent

public Version putIfPresent(Key key,
                            Value value)
                     throws DurabilityException,
                            RequestTimeoutException,
                            FaultException
Calls KVStore.putIfPresent and performs retries if a FaultException is thrown.

This method is equivalent to putIfPresent(Key, Value, ReturnValueVersion, Durability, long, TimeUnit) except that the prevValue, durability, timeout and timeoutUnit parameters are not specified and take on default values.

Throws:
DurabilityException
RequestTimeoutException
FaultException

putIfPresent

public Version putIfPresent(Key key,
                            Value value,
                            ReturnValueVersion prevValue,
                            Durability durability,
                            long timeout,
                            TimeUnit timeoutUnit)
                     throws DurabilityException,
                            RequestTimeoutException,
                            FaultException
Calls KVStore.putIfPresent and performs retries if a FaultException is thrown.

This method is not idempotent since if it is called multiple times, the outcome may be different because the key may or may not exist. When null is returned, the application is expected to take action, such as performing retries, at a higher level.

This method is commonly used (instead of put) as a self-check, when the key is expected to be present.

Throws:
DurabilityException
RequestTimeoutException
FaultException

putIfVersion

public Version putIfVersion(Key key,
                            Value value,
                            Version matchVersion)
                     throws DurabilityException,
                            RequestTimeoutException,
                            FaultException
Calls KVStore.putIfVersion and performs retries if a FaultException is thrown.

This method is equivalent to putIfVersion(Key, Value, Version, ReturnValueVersion, Durability, long, TimeUnit) except that the prevValue, durability, timeout and timeoutUnit parameters are not specified and take on default values.

Throws:
DurabilityException
RequestTimeoutException
FaultException

putIfVersion

public Version putIfVersion(Key key,
                            Value value,
                            Version matchVersion,
                            ReturnValueVersion prevValue,
                            Durability durability,
                            long timeout,
                            TimeUnit timeoutUnit)
                     throws DurabilityException,
                            RequestTimeoutException,
                            FaultException
Calls KVStore.putIfVersion and performs retries if a FaultException is thrown.

This method is not idempotent since if it is called multiple times, the outcome may be different because the version may or may not match. When null is returned, the application is expected to take action, such as performing retries, at a higher level.

When a retry is performed by this method and it returns null because the version does not match, there is no returned indication of whether the version was changed by an earlier attempt in the same method invocation, or by another client. The application must be prepared for either case.

This method is commonly used (instead of put) as a way to avoid lost updates.

WARNING: A putIfVersion operation should not be used to perform a self-check because the KVStore system may internally assign a new Version to a Key/Value pair when migrating data for better resource usage. One should never assume that only the application can change the Version of a Key/Value pair.

Throws:
DurabilityException
RequestTimeoutException
FaultException

delete

public void delete(Key key)
            throws DurabilityException,
                   RequestTimeoutException,
                   FaultException
Calls KVStore.delete and performs retries if a FaultException is thrown.

This method is equivalent to delete(Key, ReturnValueVersion, Durability, long, TimeUnit) except that the prevValue, durability, timeout and timeoutUnit parameters are not specified and take on default values.

Throws:
DurabilityException
RequestTimeoutException
FaultException

delete

public void delete(Key key,
                   ReturnValueVersion prevValue,
                   Durability durability,
                   long timeout,
                   TimeUnit timeoutUnit)
            throws DurabilityException,
                   RequestTimeoutException,
                   FaultException
Calls KVStore.delete and performs retries if a FaultException is thrown.

This method is idempotent in the sense that if it is called multiple times and returns without throwing an exception, the outcome is always the same: the given Key/Value pair will have been deleted.

Unlike KVStore.delete, this method does not return any indication of whether the Key/Value pair was deleted by this method or by another client.

Throws:
DurabilityException
RequestTimeoutException
FaultException

deleteIfVersion

public boolean deleteIfVersion(Key key,
                               Version matchVersion)
                        throws DurabilityException,
                               RequestTimeoutException,
                               FaultException
Calls KVStore.deleteIfVersion and performs retries if a FaultException is thrown.

This method is equivalent to deleteIfVersion(Key, Version, ReturnValueVersion, Durability, long, TimeUnit) except that the prevValue, durability, timeout and timeoutUnit parameters are not specified and take on default values.

Throws:
DurabilityException
RequestTimeoutException
FaultException

deleteIfVersion

public boolean deleteIfVersion(Key key,
                               Version matchVersion,
                               ReturnValueVersion prevValue,
                               Durability durability,
                               long timeout,
                               TimeUnit timeoutUnit)
                        throws DurabilityException,
                               RequestTimeoutException,
                               FaultException
Calls KVStore.deleteIfVersion and performs retries if a FaultException is thrown.

This method is not idempotent since if it is called multiple times, the outcome may be different because the version may or may not match. When false is returned, the application is expected to take action, such as performing retries, at a higher level.

When a retry is performed by this method and it returns false because the version does not match, there is no returned indication of whether the version was changed by an earlier attempt in the same method invocation, or by another client. The application must be prepared for either case.

This method is commonly used (instead of delete) as a way to avoid lost updates.

WARNING: A deleteIfVersion operation should not be used to perform a self-check because the KVStore system may internally assign a new Version to a Key/Value pair when migrating data for better resource usage. One should never assume that only the application can change the Version of a Key/Value pair.

Throws:
DurabilityException
RequestTimeoutException
FaultException

multiDelete

public void multiDelete(Key parentKey,
                        KeyRange subRange,
                        Depth depth)
                 throws DurabilityException,
                        RequestTimeoutException,
                        FaultException
Calls KVStore.multiDelete and performs retries if a FaultException is thrown.

This method is equivalent to multiDelete(Key, KeyRange, Depth, Durability, long, TimeUnit) except that the durability, timeout and timeoutUnit parameters are not specified and take on default values.

Throws:
DurabilityException
RequestTimeoutException
FaultException

multiDelete

public void multiDelete(Key parentKey,
                        KeyRange subRange,
                        Depth depth,
                        Durability durability,
                        long timeout,
                        TimeUnit timeoutUnit)
                 throws DurabilityException,
                        RequestTimeoutException,
                        FaultException
Calls KVStore.multiDelete and performs retries if a FaultException is thrown.

This method is idempotent in the sense that if it is called multiple times and returns without throwing an exception, the outcome is always the same: the specified Key/Value pairs will have been deleted.

Unlike KVStore.multiDelete, this method does not return any indication of how many Key/Value pairs were deleted by this method.

Throws:
DurabilityException
RequestTimeoutException
FaultException

execute

public List<OperationResult> execute(List<Operation> operations)
                              throws OperationExecutionException,
                                     DurabilityException,
                                     FaultException
Calls KVStore.execute and performs retries if a FaultException is thrown.

This method is equivalent to execute(List, Durability, long, TimeUnit) except that the durability, timeout and timeoutUnit parameters are not specified and take on default values.

Throws:
OperationExecutionException
DurabilityException
FaultException

execute

public List<OperationResult> execute(List<Operation> operations,
                                     Durability durability,
                                     long timeout,
                                     TimeUnit timeoutUnit)
                              throws OperationExecutionException,
                                     DurabilityException,
                                     FaultException
Calls KVStore.execute and performs retries if a FaultException is thrown.

This method may or may not be idempotent since the specified operations may or may not be idempotent. Care should be taken when multiple non-idempotent operations are included, because retries may cause some operations to fail.

When a retry is performed by this method and an OperationExecutionException is thrown, there is no returned indication of whether the operation(s) failed due to an operation that succeeded in an earlier attempt in the same method invocation, or due to an operation by another client. The application must be prepared for either case.

Throws:
OperationExecutionException
DurabilityException
FaultException

Oracle NoSQL Database Examples
version 11gR2.2.0.26

Copyright (c) 2011, 2013 Oracle and/or its affiliates. All rights reserved.