mirror of
https://github.com/OpenHFT/Chronicle-Map.git
synced 2021-09-13 01:26:12 +00:00
Updated SPI model and added examples
This commit is contained in:
@@ -18,7 +18,6 @@
|
||||
|
||||
package net.openhft.chronicle.hash;
|
||||
|
||||
import net.openhft.chronicle.map.MapEntry;
|
||||
import net.openhft.chronicle.map.MapEntryOperations;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@@ -40,14 +39,10 @@ public interface HashEntry<K> {
|
||||
@NotNull Value<K, ?> key();
|
||||
|
||||
/**
|
||||
* Removes the entry from the {@code ChronicleHash}. Returns {@code true} if the remove was
|
||||
* successful, {@code false} if it failed for any reason.
|
||||
*
|
||||
* <p>This method if the default implementation for {@link MapEntryOperations#remove(MapEntry)},
|
||||
* which might be customized over the default.
|
||||
* Removes the entry from the {@code ChronicleHash}.
|
||||
*
|
||||
* @throws IllegalStateException if some locking/state conditions required to perform remove
|
||||
* operation are not met
|
||||
*/
|
||||
boolean defaultRemove();
|
||||
void doRemove();
|
||||
}
|
||||
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright 2015 Higher Frequency Trading
|
||||
*
|
||||
* http://www.higherfrequencytrading.com
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.openhft.chronicle.hash.replication;
|
||||
|
||||
public final class DefaultEventualConsistencyStrategy {
|
||||
|
||||
public static boolean shouldApplyRemoteModification(
|
||||
ReplicatedEntry entry, ReplicationContext context) {
|
||||
long remoteTimestamp = context.remoteTimestamp();
|
||||
long originTimestamp = entry.originTimestamp();
|
||||
return remoteTimestamp > originTimestamp || (remoteTimestamp == originTimestamp &&
|
||||
context.remoteIdentifier() <= entry.originIdentifier());
|
||||
}
|
||||
|
||||
private DefaultEventualConsistencyStrategy() {}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright 2015 Higher Frequency Trading
|
||||
*
|
||||
* http://www.higherfrequencytrading.com
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.openhft.chronicle.hash.replication;
|
||||
|
||||
public interface ReplicatedEntry {
|
||||
|
||||
byte originIdentifier();
|
||||
|
||||
long originTimestamp();
|
||||
}
|
||||
+8
-1
@@ -16,7 +16,10 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.openhft.chronicle.hash;
|
||||
package net.openhft.chronicle.hash.replication;
|
||||
|
||||
import net.openhft.chronicle.hash.ChronicleHash;
|
||||
import net.openhft.chronicle.hash.HashContext;
|
||||
|
||||
/**
|
||||
* Context of internal replication operation.
|
||||
@@ -24,4 +27,8 @@ package net.openhft.chronicle.hash;
|
||||
* @param <K> the key type of accessed {@link ChronicleHash}
|
||||
*/
|
||||
public interface ReplicationContext<K> extends HashContext<K> {
|
||||
|
||||
byte remoteIdentifier();
|
||||
|
||||
long remoteTimestamp();
|
||||
}
|
||||
@@ -45,16 +45,11 @@ public interface MapAbsentEntry<K, V> {
|
||||
|
||||
/**
|
||||
* Inserts the new entry into the map, of {@link #absentKey() the key} and the given value.
|
||||
* Returns {@code true} if the insertion was successful, {@code false} if it failed for
|
||||
* any reason.
|
||||
*
|
||||
* <p>This method if the default implementation for {@link MapAbsentEntryOperations#insert},
|
||||
* which might be customized over the default.
|
||||
*
|
||||
* @throws IllegalStateException if some locking/state conditions required to perform insertion
|
||||
* operation are not met
|
||||
*/
|
||||
boolean defaultInsert(Value<V, ?> value);
|
||||
void doInsert(Value<V, ?> value);
|
||||
|
||||
/**
|
||||
* Returns the "nil" value, which should be inserted into the map in this context. This
|
||||
|
||||
@@ -19,8 +19,12 @@
|
||||
package net.openhft.chronicle.map;
|
||||
|
||||
import net.openhft.chronicle.hash.Value;
|
||||
import net.openhft.chronicle.hash.replication.ReplicatedEntry;
|
||||
import net.openhft.chronicle.hash.replication.ReplicationContext;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import static net.openhft.chronicle.hash.replication.DefaultEventualConsistencyStrategy.shouldApplyRemoteModification;
|
||||
|
||||
/**
|
||||
* SPI interface for customizing "low-level" insertion of a new entry into {@link ChronicleMap}.
|
||||
*
|
||||
@@ -35,13 +39,21 @@ public interface MapAbsentEntryOperations<K, V> {
|
||||
* Returns {@code true} if the insertion was successful, {@code false} if it failed
|
||||
* for any reason.
|
||||
*
|
||||
* @implNote simply delegates to {@link MapAbsentEntry#defaultInsert(Value)}.
|
||||
*
|
||||
* @throws IllegalStateException if some locking/state conditions required to perform insertion
|
||||
* operation are not met
|
||||
*/
|
||||
default boolean insert(@NotNull MapAbsentEntry<K, V> absentEntry, Value<V, ?> value) {
|
||||
return absentEntry.defaultInsert(value);
|
||||
MapContext<K, V> context = absentEntry.context();
|
||||
boolean shouldInsert = !(context instanceof ReplicationContext) ||
|
||||
!(absentEntry instanceof ReplicatedEntry) ||
|
||||
shouldApplyRemoteModification((ReplicatedEntry) absentEntry,
|
||||
(ReplicationContext) context);
|
||||
if (shouldInsert) {
|
||||
absentEntry.doInsert(value);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -42,15 +42,10 @@ public interface MapEntry<K, V> extends HashEntry<K> {
|
||||
@NotNull Value<V, ?> value();
|
||||
|
||||
/**
|
||||
* Replaces the entry's value with the new one. Returns {@code true} if the replace operation
|
||||
* was successful, {@code false} if it failed for any reason.
|
||||
*
|
||||
* <p>This method if the default implementation for {@link MapEntryOperations#replaceValue},
|
||||
* which might be customized over the default.
|
||||
* Replaces the entry's value with the new one.
|
||||
*
|
||||
* @throws IllegalStateException if some locking/state conditions required to perform replace
|
||||
* operation are not met
|
||||
*/
|
||||
boolean defaultReplaceValue(Value<V, ?> newValue);
|
||||
void doReplaceValue(Value<V, ?> newValue);
|
||||
}
|
||||
|
||||
|
||||
@@ -19,8 +19,12 @@
|
||||
package net.openhft.chronicle.map;
|
||||
|
||||
import net.openhft.chronicle.hash.Value;
|
||||
import net.openhft.chronicle.hash.replication.ReplicatedEntry;
|
||||
import net.openhft.chronicle.hash.replication.ReplicationContext;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import static net.openhft.chronicle.hash.replication.DefaultEventualConsistencyStrategy.shouldApplyRemoteModification;
|
||||
|
||||
/**
|
||||
* SPI interface for customizing "low-level" modification operations on the <i>present</i>
|
||||
* {@link ChronicleMap} entry.
|
||||
@@ -29,33 +33,45 @@ import org.jetbrains.annotations.NotNull;
|
||||
* @param <V> type of the value in {@code ChronicleMap}
|
||||
*/
|
||||
public interface MapEntryOperations<K, V> {
|
||||
|
||||
static boolean shouldModify(@NotNull MapEntry<?, ?> entry) {
|
||||
MapContext<?, ?> context = entry.context();
|
||||
return !(context instanceof ReplicationContext) ||
|
||||
shouldApplyRemoteModification((ReplicatedEntry) entry,
|
||||
(ReplicationContext) context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the given entry from the {@code ChronicleHash}. Returns {@code true} if the remove
|
||||
* was successful, {@code false} if it failed for any reason.
|
||||
*
|
||||
* @implNote simply delegates to {@link MapEntry#defaultRemove()}.
|
||||
*
|
||||
* @param entry the entry to remove
|
||||
* @throws IllegalStateException if some locking/state conditions required to perform remove
|
||||
* operation are not met
|
||||
*/
|
||||
default boolean remove(@NotNull MapEntry<K, V> entry) {
|
||||
return entry.defaultRemove();
|
||||
if (shouldModify(entry)) {
|
||||
entry.doRemove();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Replaces the given entry's value with the new one. Returns {@code true} if the replace
|
||||
* operation was successful, {@code false} if it failed for any reason.
|
||||
*
|
||||
* @implNote simply delegates to {@link MapEntry#defaultReplaceValue(Value)
|
||||
* entry.defaultReplace(newValue)}.
|
||||
*
|
||||
* @param entry the entry to replace the value in
|
||||
* @throws IllegalStateException if some locking/state conditions required to perform replace
|
||||
* operation are not met
|
||||
*/
|
||||
default boolean replaceValue(@NotNull MapEntry<K, V> entry, Value<V, ?> newValue) {
|
||||
return entry.defaultReplaceValue(newValue);
|
||||
if (shouldModify(entry)) {
|
||||
entry.doReplaceValue(newValue);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user