IEP-12: updated javadoc with notes about data consistency in atomic caches in failure scenarios when entry processors and putIfAbsent/replace/remove operations are used.
Project: http://git-wip-us.apache.org/repos/asf/ignite/repo Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/d7987e6d Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/d7987e6d Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/d7987e6d Branch: refs/heads/ignite-zk Commit: d7987e6d5f633d6d0e4dc8816387efcba7bafbdd Parents: 0e8224f Author: yzhdanov <6ufalug04ap> Authored: Fri Dec 22 15:32:48 2017 +0300 Committer: yzhdanov <6ufalug04ap> Committed: Fri Dec 22 15:32:48 2017 +0300 ---------------------------------------------------------------------- .../java/org/apache/ignite/IgniteCache.java | 85 ++++++++++++++++++-- .../apache/ignite/cache/CacheAtomicityMode.java | 39 ++++++++- 2 files changed, 115 insertions(+), 9 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ignite/blob/d7987e6d/modules/core/src/main/java/org/apache/ignite/IgniteCache.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/IgniteCache.java b/modules/core/src/main/java/org/apache/ignite/IgniteCache.java index 6a0add9..cd8264b 100644 --- a/modules/core/src/main/java/org/apache/ignite/IgniteCache.java +++ b/modules/core/src/main/java/org/apache/ignite/IgniteCache.java @@ -37,6 +37,7 @@ import javax.cache.integration.CacheWriter; import javax.cache.processor.EntryProcessor; import javax.cache.processor.EntryProcessorException; import javax.cache.processor.EntryProcessorResult; +import org.apache.ignite.cache.CacheAtomicityMode; import org.apache.ignite.cache.CacheEntry; import org.apache.ignite.cache.CacheEntryProcessor; import org.apache.ignite.cache.CacheMetrics; @@ -556,12 +557,34 @@ public interface IgniteCache<K, V> extends javax.cache.Cache<K, V>, IgniteAsyncS public long localSizeLong(int partition, CachePeekMode... peekModes); /** + * Asynchronously invokes each {@link EntryProcessor} from map's values against the correspondent + * {@link javax.cache.Cache.Entry} specified by map's key set. + * <p> + * If an {@link javax.cache.Cache.Entry} does not exist for the specified key, an attempt is made + * to load it (if a loader is configured) or a surrogate {@link javax.cache.Cache.Entry}, + * consisting of the key and a value of null is provided. + * <p> + * The order that the entries for the keys are processed is undefined. + * Implementations may choose to process the entries in any order, including + * concurrently. Furthermore there is no guarantee implementations will + * use the same {@link EntryProcessor} instance to process each entry, as + * the case may be in a non-local cache topology. + * <p> + * The result of executing the {@link EntryProcessor} is returned in the future as a + * {@link Map} of {@link EntryProcessorResult}s, one result per key. Should the + * {@link EntryProcessor} or Caching implementation throw an exception, the + * exception is wrapped and re-thrown when a call to + * {@link javax.cache.processor.EntryProcessorResult#get()} is made. + * <p> + * Please refer to documentation for {@link CacheAtomicityMode#ATOMIC} for information on + * system behavior in crash scenarios for atomic caches. + * * @param map Map containing keys and entry processors to be applied to values. * @param args Additional arguments to pass to the {@link EntryProcessor}. * @return The map of {@link EntryProcessorResult}s of the processing per key, - * if any, defined by the {@link EntryProcessor} implementation. No mappings - * will be returned for {@link EntryProcessor}s that return a - * <code>null</code> value for a key. + * if any, defined by the {@link EntryProcessor} implementation. No mappings + * will be returned for {@link EntryProcessor}s that return a + * <code>null</code> value for a key. * @throws TransactionException If operation within transaction is failed. */ @IgniteAsyncSupported @@ -569,7 +592,7 @@ public interface IgniteCache<K, V> extends javax.cache.Cache<K, V>, IgniteAsyncS Object... args) throws TransactionException; /** - * Asynchronously version of the {@link #invokeAll(Set, EntryProcessor, Object...)} method. + * Asynchronously version of the {@link #invokeAll(Map, Object...)} method. * * @param map Map containing keys and entry processors to be applied to values. * @param args Additional arguments to pass to the {@link EntryProcessor}. @@ -844,6 +867,12 @@ public interface IgniteCache<K, V> extends javax.cache.Cache<K, V>, IgniteAsyncS /** * {@inheritDoc} + * <p> + * For {@link CacheAtomicityMode#ATOMIC} return + * value on primary node crash may be incorrect because of the automatic retries. It is recommended + * to disable retries with {@link #withNoRetries()} and manually restore primary-backup + * consistency in case of update failure. + * * @throws TransactionException If operation within transaction is failed. */ @IgniteAsyncSupported @@ -852,6 +881,11 @@ public interface IgniteCache<K, V> extends javax.cache.Cache<K, V>, IgniteAsyncS /** * Asynchronously associates the specified key with the given value if it is * not already associated with a value. + * <p> + * For {@link CacheAtomicityMode#ATOMIC} return + * value on primary node crash may be incorrect because of the automatic retries. It is recommended + * to disable retries with {@link #withNoRetries()} and manually restore primary-backup + * consistency in case of update failure. * * @param key Key. * @param val Value. @@ -891,6 +925,12 @@ public interface IgniteCache<K, V> extends javax.cache.Cache<K, V>, IgniteAsyncS /** * {@inheritDoc} + * <p> + * For {@link CacheAtomicityMode#ATOMIC} return + * value on primary node crash may be incorrect because of the automatic retries. It is recommended + * to disable retries with {@link #withNoRetries()} and manually restore primary-backup + * consistency in case of update failure. + * * @throws TransactionException If operation within transaction is failed. */ @IgniteAsyncSupported @@ -899,6 +939,11 @@ public interface IgniteCache<K, V> extends javax.cache.Cache<K, V>, IgniteAsyncS /** * Asynchronously removes the mapping for a key only if currently mapped to the * given value. + * <p> + * For {@link CacheAtomicityMode#ATOMIC} return + * value on primary node crash may be incorrect because of the automatic retries. It is recommended + * to disable retries with {@link #withNoRetries()} and manually restore primary-backup + * consistency in case of update failure. * * @param key Key. * @param oldVal Old value. @@ -926,6 +971,12 @@ public interface IgniteCache<K, V> extends javax.cache.Cache<K, V>, IgniteAsyncS /** * {@inheritDoc} + * <p> + * For {@link CacheAtomicityMode#ATOMIC} return + * value on primary node crash may be incorrect because of the automatic retries. It is recommended + * to disable retries with {@link #withNoRetries()} and manually restore primary-backup + * consistency in case of update failure. + * * @throws TransactionException If operation within transaction is failed. */ @IgniteAsyncSupported @@ -933,6 +984,11 @@ public interface IgniteCache<K, V> extends javax.cache.Cache<K, V>, IgniteAsyncS /** * Asynchronous version of the {@link #replace(Object, Object, Object)}. + * <p> + * For {@link CacheAtomicityMode#ATOMIC} return + * value on primary node crash may be incorrect because of the automatic retries. It is recommended + * to disable retries with {@link #withNoRetries()} and manually restore primary-backup + * consistency in case of update failure. * * @param key Key. * @param oldVal Old value. @@ -1142,16 +1198,24 @@ public interface IgniteCache<K, V> extends javax.cache.Cache<K, V>, IgniteAsyncS /** * {@inheritDoc} + * <p> + * Please refer to documentation for {@link CacheAtomicityMode#ATOMIC} for information on + * system behavior in crash scenarios for atomic caches. + * * @throws TransactionException If operation within transaction is failed. */ @IgniteAsyncSupported - @Override public <T> T invoke(K key, EntryProcessor<K, V, T> entryProcessor, Object... arguments) throws TransactionException; + @Override public <T> T invoke(K key, EntryProcessor<K, V, T> entryProcessor, Object... arguments) + throws TransactionException; /** * Asynchronously invokes an {@link EntryProcessor} against the {@link javax.cache.Cache.Entry} specified by * the provided key. If an {@link javax.cache.Cache.Entry} does not exist for the specified key, * an attempt is made to load it (if a loader is configured) or a surrogate * {@link javax.cache.Cache.Entry}, consisting of the key with a null value is used instead. + * <p> + * Please refer to documentation for {@link CacheAtomicityMode#ATOMIC} for information on + * system behavior in crash scenarios for atomic caches. * * @param key The key to the entry. * @param entryProcessor The {@link EntryProcessor} to invoke. @@ -1171,6 +1235,9 @@ public interface IgniteCache<K, V> extends javax.cache.Cache<K, V>, IgniteAsyncS * An instance of entry processor must be stateless as it may be invoked multiple times on primary and * backup nodes in the cache. It is guaranteed that the value passed to the entry processor will be always * the same. + * <p> + * Please refer to documentation for {@link CacheAtomicityMode#ATOMIC} for information on + * system behavior in crash scenarios for atomic caches. * * @param key The key to the entry. * @param entryProcessor The {@link CacheEntryProcessor} to invoke. @@ -1225,6 +1292,10 @@ public interface IgniteCache<K, V> extends javax.cache.Cache<K, V>, IgniteAsyncS /** * {@inheritDoc} + * <p> + * Please refer to documentation for {@link CacheAtomicityMode#ATOMIC} for information on + * system behavior in crash scenarios for atomic caches. + * * @throws TransactionException If operation within transaction is failed. */ @IgniteAsyncSupported @@ -1250,7 +1321,9 @@ public interface IgniteCache<K, V> extends javax.cache.Cache<K, V>, IgniteAsyncS * {@link EntryProcessor} or Caching implementation throw an exception, the * exception is wrapped and re-thrown when a call to * {@link javax.cache.processor.EntryProcessorResult#get()} is made. - + * <p> + * Please refer to documentation for {@link CacheAtomicityMode#ATOMIC} for information on + * system behavior in crash scenarios for atomic caches. * * @param keys The set of keys. * @param entryProcessor The {@link EntryProcessor} to invoke. http://git-wip-us.apache.org/repos/asf/ignite/blob/d7987e6d/modules/core/src/main/java/org/apache/ignite/cache/CacheAtomicityMode.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/cache/CacheAtomicityMode.java b/modules/core/src/main/java/org/apache/ignite/cache/CacheAtomicityMode.java index 92b5aa1..79a8e5f 100644 --- a/modules/core/src/main/java/org/apache/ignite/cache/CacheAtomicityMode.java +++ b/modules/core/src/main/java/org/apache/ignite/cache/CacheAtomicityMode.java @@ -17,6 +17,8 @@ package org.apache.ignite.cache; +import javax.cache.processor.EntryProcessor; +import org.apache.ignite.IgniteCache; import org.apache.ignite.transactions.Transaction; import org.jetbrains.annotations.Nullable; @@ -44,16 +46,47 @@ public enum CacheAtomicityMode { * In addition to transactions and locking, one of the main differences in {@code ATOMIC} mode * is that bulk writes, such as {@code putAll(...)}, {@code removeAll(...)}, and {@code transformAll(...)} * methods, become simple batch operations which can partially fail. In case of partial - * failure {@link org.apache.ignite.internal.processors.cache.CachePartialUpdateCheckedException} will be thrown + * failure {@link CachePartialUpdateException} will be thrown * which will contain a list of keys for which the update failed. It is recommended that bulk writes are used * whenever multiple keys need to be inserted or updated in cache, as they reduce number of network trips and * provide better performance. * <p> - * Note that even without locking and transactions, {@code ATOMIC} mode still provides - * full consistency guarantees across all cache nodes. + * Note that even without locking and transactions, {@code ATOMIC} mode makes best effort to provide + * full consistency guarantees across all cache nodes. However, in following scenarios (but not limited to) + * full consistency is not possible and {@link #TRANSACTIONAL} mode should be used or custom defined recovery + * logic should be applied to restore data consistency: + * <ul> + * <li> + * Node that originated update has left together with at least one primary node + * for this update operation, and left primary node has not finished update propagation + * to all nodes holding backup partitions. This way backup copies may differ. And also if + * persistent store is configured it may come to an inconsistent state as well. + * </li> + * <li> + * If update originating node is alive then update is retried by default and for operations + * {@code put(...)}, {@code putAll(...)}, {@code remove(K, V)} and {@code removeAll(Set<K>)} + * all copies of partitions will come to a consistent state. + * </li> + * <li> + * If {@link EntryProcessor} is used and processor is not idempotent then failure of primary node + * may result in applying the same processor on next chosen primary which may have already been + * updated within current operation. If processor is not idempotent it is recommended to disable + * automatic retries and manually restore consistency between key-value copies in case of update failure. + * </li> + * <li> + * For operations {@code putIfAbsent(K, V)}, {@code replace(K, V, V)} and {@code remove(K, V)} return + * value on primary node crash may be incorrect because of the automatic retries. It is recommended + * to disable retries with {@link IgniteCache#withNoRetries()} and manually restore primary-backup + * consistency in case of update failure. + * </li> + * </ul> * <p> * Also note that all data modifications in {@code ATOMIC} mode are guaranteed to be atomic * and consistent with writes to the underlying persistent store, if one is configured. + * <p> + * Note! Consistency behavior of atomic cache will be improved in future releases. + * + * @see IgniteCache#withNoRetries() */ ATOMIC;
