/*
* 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.map.impl.stage.iter;
import net.openhft.chronicle.hash.Data;
import net.openhft.chronicle.hash.ReplicatedHashSegmentContext;
import net.openhft.chronicle.hash.replication.ReplicableEntry;
import net.openhft.chronicle.map.MapEntry;
import net.openhft.chronicle.map.impl.ReplicatedIterationContext;
import net.openhft.chronicle.map.impl.VanillaChronicleMapHolder;
import net.openhft.chronicle.map.impl.stage.data.DummyValueZeroData;
import net.openhft.chronicle.map.impl.stage.entry.ReplicatedMapEntryStages;
import net.openhft.chronicle.map.impl.stage.replication.ReplicationUpdate;
import net.openhft.chronicle.set.DummyValueData;
import net.openhft.sg.StageRef;
import net.openhft.sg.Staged;
import java.util.function.Consumer;
import java.util.function.Predicate;
import static net.openhft.chronicle.map.impl.stage.iter.ReplicatedMapSegmentIteration.EntriesToTest.ALL;
import static net.openhft.chronicle.map.impl.stage.iter.ReplicatedMapSegmentIteration.EntriesToTest.PRESENT;
@Staged
public abstract class ReplicatedMapSegmentIteration<K, V, R> extends MapSegmentIteration<K, V, R>
implements ReplicatedIterationContext<K, V, R>, ReplicableEntry,
ReplicatedHashSegmentContext<K, MapEntry<K, V>> {
@StageRef VanillaChronicleMapHolder<K, V, R> mh;
@StageRef ReplicatedMapEntryStages<K, V> e;
@StageRef ReplicationUpdate<K> ru;
@StageRef DummyValueZeroData<V> dummyValue;
@StageRef ReplicatedMapAbsentDelegatingForIteration<K, V> absentEntryDelegating;
@StageRef ReplicatedMapEntryDelegating<K, V> entryDelegating;
enum EntriesToTest {PRESENT, ALL}
EntriesToTest entriesToTest = null;
void initEntriesToTest(EntriesToTest entriesToTest) {
this.entriesToTest = entriesToTest;
}
@Override
public boolean shouldTestEntry() {
return entriesToTest == ALL || !e.entryDeleted();
}
@Override
public Object entryForIteration() {
return !e.entryDeleted() ? entryDelegating : absentEntryDelegating;
}
@Override
public long tierEntriesForIteration() {
return entriesToTest == ALL ? s.tierEntries() : s.tierEntries() - s.tierDeleted();
}
@Override
public void doReplaceValue(Data<V> newValue) {
checkOnEachPublicOperation.checkOnEachPublicOperation();
try {
entry.innerDefaultReplaceValue(newValue);
e.updatedReplicationStateOnPresentEntry();
ru.updateChange();
} finally {
s.innerWriteLock.unlock();
}
}
@Override
public boolean forEachSegmentEntryWhile(Predicate<? super MapEntry<K, V>> predicate) {
checkOnEachPublicOperation.checkOnEachPublicOperation();
initEntriesToTest(PRESENT);
s.innerUpdateLock.lock();
return innerForEachSegmentEntryWhile(predicate);
}
@Override
public boolean forEachSegmentReplicableEntryWhile(
Predicate<? super ReplicableEntry> predicate) {
checkOnEachPublicOperation.checkOnEachPublicOperation();
initEntriesToTest(ALL);
s.innerUpdateLock.lock();
return innerForEachSegmentEntryWhile(predicate);
}
@Override
public void forEachSegmentReplicableEntry(Consumer<? super ReplicableEntry> action) {
forEachSegmentReplicableEntryWhile(e -> {
action.accept(e);
return true;
});
}
@Override
public void doRemove() {
checkOnEachPublicOperation.checkOnEachPublicOperation();
try {
if (e.valueSize > dummyValue.size())
e.innerDefaultReplaceValue(dummyValue);
e.updatedReplicationStateOnPresentEntry();
e.writeEntryDeleted();
ru.updateChange();
s.tierDeleted(s.tierDeleted() + 1);
} finally {
s.innerWriteLock.unlock();
}
initEntryRemovedOnThisIteration(true);
}
@Override
public void doRemoveCompletely() {
boolean wasDeleted = e.entryDeleted();
super.doRemove();
ru.dropChange();
if (wasDeleted)
s.tierDeleted(s.tierDeleted() - 1);
}
public void doInsert(Data<V> value) {
checkOnEachPublicOperation.checkOnEachPublicOperation();
if (e.entryDeleted()) {
try {
s.tierDeleted(s.tierDeleted() - 1);
e.innerDefaultReplaceValue(value);
s.incrementModCount();
e.writeEntryPresent();
e.updatedReplicationStateOnPresentEntry();
ru.updateChange();
} finally {
s.innerWriteLock.unlock();
}
} else {
throw new IllegalStateException(mh.h().toIdentityString() +
": Entry is present in the map when doInsert() is called");
}
}
public void doInsert() {
if (mh.set() == null)
throw new IllegalStateException(mh.h().toIdentityString() +
": Called SetAbsentEntry.doInsert() from Map context");
doInsert((Data<V>) DummyValueData.INSTANCE);
}
}