diff --git a/src/main/java/net/openhft/chronicle/map/ReplicatedChronicleMap.java b/src/main/java/net/openhft/chronicle/map/ReplicatedChronicleMap.java index d86a193eb..d4d54fc67 100644 --- a/src/main/java/net/openhft/chronicle/map/ReplicatedChronicleMap.java +++ b/src/main/java/net/openhft/chronicle/map/ReplicatedChronicleMap.java @@ -45,39 +45,36 @@ import static net.openhft.lang.MemoryUnit.*; import static net.openhft.lang.collection.DirectBitSet.NOT_FOUND; /** - *
Each remote hash map, mirrors its changes over to - * another remote hash map, neither hash map is considered the master store of data, each hash map - * uses timestamps to reconcile changes. We refer to an instance of a remote hash-map as a node. A - * node will be connected to any number of other nodes, for the first implementation the maximum - * number of nodes will be fixed. The data that is stored locally in each node will become - * eventually consistent. So changes made to one node, for example by calling put() will be - * replicated over to the other node. To achieve a high level of performance and throughput, the - * call to put() won’t block, with concurrentHashMap, It is typical to check the return code of some - * methods to obtain the old value for example remove(). Due to the loose coupling and lock free - * nature of this multi master implementation, this return value will only be the old value on the - * nodes local data store. In other words the nodes are only concurrent locally. Its worth realising - * that another node performing exactly the same operation may return a different value. However - * reconciliation will ensure the maps themselves become eventually consistent.
- *If two ( or more nodes ) were to receive a change to their maps for - * the same key but different values, say by a user of the maps, calling the put(key, value). Then, - * initially each node will update its local store and each local store will hold a different value, - * but the aim of multi master replication is to provide eventual consistency across the nodes. So, - * with multi master when ever a node is changed it will notify the other nodes of its change. We - * will refer to this notification as an event. The event will hold a timestamp indicating the time - * the change occurred, it will also hold the state transition, in this case it was a put with a key - * and value. Eventual consistency is achieved by looking at the timestamp from the remote node, if - * for a given key, the remote nodes timestamp is newer than the local nodes timestamp, then the - * event from the remote node will be applied to the local node, otherwise the event will be - * ignored.
However there is an edge case that we have to concern ourselves with, If two - * nodes update their map at the same time with different values, we have to deterministically - * resolve which update wins, because of eventual consistency both nodes should end up locally - * holding the same data. Although it is rare two remote nodes could receive an update to their maps - * at exactly the same time for the same key, we have to handle this edge case, its therefore - * important not to rely on timestamps alone to reconcile the updates. Typically the update with the - * newest timestamp should win, but in this example both timestamps are the same, and the decision - * made to one node should be identical to the decision made to the other. We resolve this simple - * dilemma by using a node identifier, each node will have a unique identifier, the update from the - * node with the smallest identifier wins.
+ *Each remote hash map, mirrors its changes over to another + * remote hash map, neither hash map is considered the master store of data, each hash map uses timestamps to + * reconcile changes. We refer to an instance of a remote hash-map as a node. A node will be connected to any + * number of other nodes, for the first implementation the maximum number of nodes will be fixed. The data + * that is stored locally in each node will become eventually consistent. So changes made to one node, for + * example by calling put() will be replicated over to the other node. To achieve a high level of performance + * and throughput, the call to put() won’t block, with concurrentHashMap, It is typical to check the return + * code of some methods to obtain the old value for example remove(). Due to the loose coupling and lock free + * nature of this multi master implementation, this return value will only be the old value on the nodes + * local data store. In other words the nodes are only concurrent locally. Its worth realising that another + * node performing exactly the same operation may return a different value. However reconciliation will ensure + * the maps themselves become eventually consistent.
If two ( or more nodes ) + * were to receive a change to their maps for the same key but different values, say by a user of the maps, + * calling the put(key, value). Then, initially each node will update its local store and each local store + * will hold a different value, but the aim of multi master replication is to provide eventual consistency + * across the nodes. So, with multi master when ever a node is changed it will notify the other nodes of its + * change. We will refer to this notification as an event. The event will hold a timestamp indicating the time + * the change occurred, it will also hold the state transition, in this case it was a put with a key and + * value. Eventual consistency is achieved by looking at the timestamp from the remote node, if for a given + * key, the remote nodes timestamp is newer than the local nodes timestamp, then the event from the remote + * node will be applied to the local node, otherwise the event will be ignored.
However there is an + * edge case that we have to concern ourselves with, If two nodes update their map at the same time with + * different values, we have to deterministically resolve which update wins, because of eventual consistency + * both nodes should end up locally holding the same data. Although it is rare two remote nodes could receive + * an update to their maps at exactly the same time for the same key, we have to handle this edge case, its + * therefore important not to rely on timestamps alone to reconcile the updates. Typically the update with the + * newest timestamp should win, but in this example both timestamps are the same, and the decision made to one + * node should be identical to the decision made to the other. We resolve this simple dilemma by using a node + * identifier, each node will have a unique identifier, the update from the node with the smallest identifier + * wins.
* * @paramWe can reject put() and removes() when comparing times stamps with remote systems + * Used only with replication, its sometimes possible to receive an old ( or stale update ) from a + * remote map. This method is used to determine if we should ignore such updates.
We can reject
+ * put() and removes() when comparing times stamps with remote systems
*
* @param entry the maps entry
* @param timestamp the time the entry was created or updated
@@ -906,16 +951,15 @@ class ReplicatedChronicleMap Once a change occurs to a map, map replication requires that these changes are picked up
- * by another thread, this class provides an iterator like interface to poll for such changes.
- * In most cases the thread that adds data to the node is unlikely to be the same thread
- * that replicates the data over to the other nodes, so data will have to be marshaled between
- * the main thread storing data to the map, and the thread running the replication. One
- * way to perform this marshalling, would be to pipe the data into a queue. However, This class
- * takes another approach. It uses a bit set, and marks bits which correspond to the indexes of
- * the entries that have changed. It then provides an iterator like interface to poll for such
- * changes. Once a change occurs to a map, map replication requires that these changes are picked up by another
+ * thread, this class provides an iterator like interface to poll for such changes. In most cases
+ * the thread that adds data to the node is unlikely to be the same thread that replicates the data over
+ * to the other nodes, so data will have to be marshaled between the main thread storing data to the map,
+ * and the thread running the replication. One way to perform this marshalling, would be to pipe
+ * the data into a queue. However, This class takes another approach. It uses a bit set, and marks bits
+ * which correspond to the indexes of the entries that have changed. It then provides an iterator like
+ * interface to poll for such changes. (this could be later if
- * it was a remote put) this method is called only from usual
- * put or acquire
+ * @param timestamp the timestamp when the entry was put (this could be later if it was a
+ * remote put) this method is called only from usual put or acquire
* @param searchedHashLookup the hash lookup that used to find the entry based on the key
* @return offset of the written entry in the Segment bytes
* @see VanillaChronicleMap.Segment#putEntry
@@ -1216,8 +1260,8 @@ class ReplicatedChronicleMap