/*
* 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.algo.bitset.ReusableBitSet;
import net.openhft.chronicle.hash.ChronicleHashCorruption;
import net.openhft.chronicle.hash.impl.CompactOffHeapLinearHashTable;
import net.openhft.chronicle.hash.impl.VanillaChronicleHash;
import net.openhft.chronicle.hash.impl.stage.entry.SegmentStages;
import net.openhft.chronicle.hash.impl.stage.iter.TierRecovery;
import net.openhft.chronicle.map.ChronicleHashCorruptionImpl;
import net.openhft.chronicle.map.ReplicatedChronicleMap;
import net.openhft.chronicle.map.impl.ReplicatedChronicleMapHolder;
import net.openhft.chronicle.map.impl.stage.entry.ReplicatedMapEntryStages;
import net.openhft.sg.StageRef;
import net.openhft.sg.Staged;
import static net.openhft.chronicle.map.ChronicleHashCorruptionImpl.format;
import static net.openhft.chronicle.map.ChronicleHashCorruptionImpl.report;
@Staged
public class ReplicatedTierRecovery extends TierRecovery {
@StageRef ReplicatedChronicleMapHolder<?, ?, ?> rh;
@StageRef SegmentStages s;
@StageRef ReplicatedMapEntryStages<?, ?> e;
@Override
public void removeDuplicatesInSegment(
ChronicleHashCorruption.Listener corruptionListener,
ChronicleHashCorruptionImpl corruption) {
super.removeDuplicatesInSegment(corruptionListener, corruption);
recoverTierDeleted(corruptionListener, corruption);
cleanupModificationIterationBits();
}
private void recoverTierDeleted(
ChronicleHashCorruption.Listener corruptionListener,
ChronicleHashCorruptionImpl corruption) {
VanillaChronicleHash<?, ?, ?, ?> h = rh.h();
CompactOffHeapLinearHashTable hl = h.hashLookup;
long hlAddr = s.tierBaseAddr;
long deleted = 0;
long hlPos = 0;
do {
long hlEntry = hl.readEntry(hlAddr, hlPos);
if (!hl.empty(hlEntry)) {
e.readExistingEntry(hl.value(hlEntry));
if (e.entryDeleted()) {
deleted++;
}
}
hlPos = hl.step(hlPos);
} while (hlPos != 0);
if (s.tierDeleted() != deleted) {
long finalDeleted = deleted;
report(corruptionListener, corruption, s.segmentIndex, () ->
format("wrong deleted counter for tier with index {}, stored: {}, should be: {}",
s.tierIndex, s.tierDeleted(), finalDeleted)
);
s.tierDeleted(deleted);
}
}
private void cleanupModificationIterationBits() {
ReplicatedChronicleMap<?, ?, ?> m = rh.m();
ReplicatedChronicleMap<?, ?, ?>.ModificationIterator[] its =
m.acquireAllModificationIterators();
ReusableBitSet freeList = s.freeList;
for (long pos = 0; pos < m.actualChunksPerSegmentTier;) {
long nextPos = freeList.nextSetBit(pos);
if (nextPos > pos) {
for (ReplicatedChronicleMap<?, ?, ?>.ModificationIterator it : its) {
it.clearRange0(s.tierIndex, pos, nextPos);
}
}
if (nextPos > 0) {
e.readExistingEntry(nextPos);
if (e.entrySizeInChunks > 1) {
for (ReplicatedChronicleMap<?, ?, ?>.ModificationIterator it : its) {
it.clearRange0(s.tierIndex, nextPos + 1, nextPos + e.entrySizeInChunks);
}
}
pos = nextPos + e.entrySizeInChunks;
} else {
for (ReplicatedChronicleMap<?, ?, ?>.ModificationIterator it : its) {
it.clearRange0(s.tierIndex, pos, m.actualChunksPerSegmentTier);
}
break;
}
}
}
}