|
Oracle NoSQL Database Examples version 11gR2.2.0.26 |
|||||||||
PREV CLASS NEXT CLASS | FRAMES NO FRAMES | |||||||||
SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD |
java.lang.Objectschema.WriteOperations
class WriteOperations
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(KVStore store, KVStoreConfig config)
Method Detail |
---|
public Version put(Key key, Value value) throws DurabilityException, RequestTimeoutException, FaultException
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.
DurabilityException
RequestTimeoutException
FaultException
public Version put(Key key, Value value, ReturnValueVersion prevValue, Durability durability, long timeout, TimeUnit timeoutUnit) throws DurabilityException, RequestTimeoutException, FaultException
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.
DurabilityException
RequestTimeoutException
FaultException
public Version putIfAbsent(Key key, Value value) throws DurabilityException, RequestTimeoutException, FaultException
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.
DurabilityException
RequestTimeoutException
FaultException
public Version putIfAbsent(Key key, Value value, ReturnValueVersion prevValue, Durability durability, long timeout, TimeUnit timeoutUnit) throws DurabilityException, RequestTimeoutException, FaultException
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.
DurabilityException
RequestTimeoutException
FaultException
public Version putIfPresent(Key key, Value value) throws DurabilityException, RequestTimeoutException, FaultException
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.
DurabilityException
RequestTimeoutException
FaultException
public Version putIfPresent(Key key, Value value, ReturnValueVersion prevValue, Durability durability, long timeout, TimeUnit timeoutUnit) throws DurabilityException, RequestTimeoutException, FaultException
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.
DurabilityException
RequestTimeoutException
FaultException
public Version putIfVersion(Key key, Value value, Version matchVersion) throws DurabilityException, RequestTimeoutException, FaultException
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.
DurabilityException
RequestTimeoutException
FaultException
public Version putIfVersion(Key key, Value value, Version matchVersion, ReturnValueVersion prevValue, Durability durability, long timeout, TimeUnit timeoutUnit) throws DurabilityException, RequestTimeoutException, FaultException
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.
DurabilityException
RequestTimeoutException
FaultException
public void delete(Key key) throws DurabilityException, RequestTimeoutException, FaultException
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.
DurabilityException
RequestTimeoutException
FaultException
public void delete(Key key, ReturnValueVersion prevValue, Durability durability, long timeout, TimeUnit timeoutUnit) throws DurabilityException, RequestTimeoutException, FaultException
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.
DurabilityException
RequestTimeoutException
FaultException
public boolean deleteIfVersion(Key key, Version matchVersion) throws DurabilityException, RequestTimeoutException, FaultException
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.
DurabilityException
RequestTimeoutException
FaultException
public boolean deleteIfVersion(Key key, Version matchVersion, ReturnValueVersion prevValue, Durability durability, long timeout, TimeUnit timeoutUnit) throws DurabilityException, RequestTimeoutException, FaultException
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.
DurabilityException
RequestTimeoutException
FaultException
public void multiDelete(Key parentKey, KeyRange subRange, Depth depth) throws DurabilityException, RequestTimeoutException, FaultException
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.
DurabilityException
RequestTimeoutException
FaultException
public void multiDelete(Key parentKey, KeyRange subRange, Depth depth, Durability durability, long timeout, TimeUnit timeoutUnit) throws DurabilityException, RequestTimeoutException, FaultException
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.
DurabilityException
RequestTimeoutException
FaultException
public List<OperationResult> execute(List<Operation> operations) throws OperationExecutionException, DurabilityException, FaultException
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.
OperationExecutionException
DurabilityException
FaultException
public List<OperationResult> execute(List<Operation> operations, Durability durability, long timeout, TimeUnit timeoutUnit) throws OperationExecutionException, DurabilityException, FaultException
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.
OperationExecutionException
DurabilityException
FaultException
|
Oracle NoSQL Database Examples version 11gR2.2.0.26 |
|||||||||
PREV CLASS NEXT CLASS | FRAMES NO FRAMES | |||||||||
SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD |