/*
* Copyright (C) 2012, 2016 higherfrequencytrading.com
* Copyright (C) 2016 Roman Leventov
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.chronicle.set.replication;
import net.openhft.chronicle.hash.replication.ReplicableEntry;
import net.openhft.chronicle.set.SetAbsentEntry;
import static net.openhft.chronicle.hash.replication.DefaultEventualConsistencyStrategy.AcceptanceDecision.ACCEPT;
import static net.openhft.chronicle.hash.replication.DefaultEventualConsistencyStrategy.AcceptanceDecision.DISCARD;
import static net.openhft.chronicle.hash.replication.DefaultEventualConsistencyStrategy.decideOnRemoteModification;
public interface SetRemoteOperations<K, R> {
default void remove(SetRemoteQueryContext<K, R> q) {
SetReplicableEntry<K> entry = q.entry();
if (entry != null) {
if (decideOnRemoteModification(entry, q) == ACCEPT) {
q.remove(entry);
ReplicableEntry replicableAbsentEntry = (ReplicableEntry) q.absentEntry();
assert replicableAbsentEntry != null;
replicableAbsentEntry.updateOrigin(q.remoteIdentifier(), q.remoteTimestamp());
// See MapRemoteOperations
if (q.remoteIdentifier() == q.currentNodeIdentifier()) {
replicableAbsentEntry.raiseChangedForAllExcept(q.remoteNodeIdentifier());
replicableAbsentEntry.dropChangedFor(q.remoteNodeIdentifier());
} else {
replicableAbsentEntry.dropChanged();
}
}
} else {
SetAbsentEntry<K> absentEntry = q.absentEntry();
assert absentEntry != null;
ReplicableEntry replicableAbsentEntry;
if (!(absentEntry instanceof ReplicableEntry)) {
// Note in the two following lines dummy entry is inserted and removed using direct
// entry.doXxx calls, not q.xxx(entry). The intention is to avoid calling possibly
// overridden SetEntryOperations, because this is technical procedure of making
// "truly absent" entry "deleted", not actual insertion and removal.
absentEntry.doInsert();
entry = q.entry();
assert entry != null;
entry.doRemove();
replicableAbsentEntry = (ReplicableEntry) q.absentEntry();
assert replicableAbsentEntry != null;
} else {
replicableAbsentEntry = (ReplicableEntry) absentEntry;
if (decideOnRemoteModification(replicableAbsentEntry, q) == DISCARD)
return;
}
replicableAbsentEntry.updateOrigin(q.remoteIdentifier(), q.remoteTimestamp());
// See MapRemoteOperations
if (q.remoteIdentifier() == q.currentNodeIdentifier()) {
replicableAbsentEntry.raiseChangedForAllExcept(q.remoteNodeIdentifier());
replicableAbsentEntry.dropChangedFor(q.remoteNodeIdentifier());
} else {
replicableAbsentEntry.dropChanged();
}
}
}
default void put(SetRemoteQueryContext<K, R> q) {
SetReplicableEntry<K> entry = q.entry();
if (entry != null) {
if (decideOnRemoteModification(entry, q) == ACCEPT) {
entry.updateOrigin(q.remoteIdentifier(), q.remoteTimestamp());
// See MapRemoteOperations
if (q.remoteIdentifier() == q.currentNodeIdentifier()) {
entry.raiseChanged();
} else {
entry.dropChanged();
}
}
} else {
SetAbsentEntry<K> absentEntry = q.absentEntry();
assert absentEntry != null;
if (!(absentEntry instanceof ReplicableEntry) ||
decideOnRemoteModification((ReplicableEntry) absentEntry, q) == ACCEPT) {
q.insert(absentEntry);
entry = q.entry(); // q.entry() is not null after insert
assert entry != null;
entry.updateOrigin(q.remoteIdentifier(), q.remoteTimestamp());
// See MapRemoteOperations
if (q.remoteIdentifier() == q.currentNodeIdentifier()) {
entry.raiseChanged();
} else {
entry.dropChanged();
}
} else {
// See MapRemoteOperations
if (((ReplicableEntry) absentEntry).originIdentifier() == q.remoteIdentifier() &&
q.remoteIdentifier() != q.currentNodeIdentifier()) {
((ReplicableEntry) absentEntry).raiseChangedFor(q.remoteIdentifier());
}
}
}
}
}