Fix a bug in HashSegmentIteration.forEachTierWhile()

This commit is contained in:
leventov
2015-11-29 01:52:57 +03:00
parent 2d7e25985a
commit a0c982374d
4 changed files with 62 additions and 13 deletions
@@ -655,4 +655,28 @@ public abstract class SegmentStages implements SegmentLock, LocksInterface {
nextPosToSearchFrom = 0L;
nextPosToSearchFrom(nextPosToSearchFrom);
}
public void verifyTierCountersAreaData() {
goToFirstTier();
while (true) {
int tierSegmentIndex = TierCountersArea.segmentIndex(tierCountersAreaAddr());
if (tierSegmentIndex != segmentIndex) {
throw new AssertionError("segmentIndex: " + segmentIndex +
", tier: " + tier + ", tierIndex: " + tierIndex + ", tierBaseAddr: " +
tierBaseAddr + " reports it belongs to segmentIndex " + tierSegmentIndex);
}
if (hasNextTier()) {
long currentTierIndex = this.tierIndex;
nextTier();
if (prevTierIndex() != currentTierIndex) {
throw new AssertionError("segmentIndex: " + segmentIndex +
", tier: " + tier + ", tierIndex: " + tierIndex + ", tierBaseAddr: " +
tierBaseAddr + " reports the previous tierIndex is " + prevTierIndex() +
" while actually it is " + currentTierIndex);
}
} else {
break;
}
}
}
}
@@ -103,12 +103,14 @@ public abstract class HashSegmentIteration<K, E extends HashEntry<K>>
}
hlp.initHashLookupPos(startPos);
long currentHashLookupPos;
int steps = 0;
do {
// Step from hlp.hashLookupPos, not currentHashLookupPos (with additional initialization
// of this local variable to startPos outside the loop), because if e.remove() is
// called in the `action`, hlp.hashLookupPos is stepped back in doRemove(), and
// currentHashLookupPos become invalid
currentHashLookupPos = hashLookup.step(hlp.hashLookupPos);
steps++;
hlp.setHashLookupPos(currentHashLookupPos);
long entry = hashLookup.readEntry(currentTierBaseAddr, currentHashLookupPos);
initHashLookupEntry(entry);
@@ -135,12 +137,17 @@ public abstract class HashSegmentIteration<K, E extends HashEntry<K>>
// slot in _current_ tier's hash lookup is shift deleted, see
// relocation()
currentHashLookupPos = hashLookup.stepBack(currentHashLookupPos);
steps--;
hlp.initHashLookupPos(currentHashLookupPos);
}
}
}
}
} while (currentHashLookupPos != startPos);
// the `steps == 0` condition and this variable updates in the loop fix the bug, when
// shift deletion occurs on the first entry of the tier, and the currentHashLookupPos
// becomes equal to start pos without making the whole loop, but only visiting a single
// entry
} while (currentHashLookupPos != startPos || steps == 0);
return interrupted ? ~size : size;
}
@@ -38,6 +38,8 @@ import org.jetbrains.annotations.NotNull;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Set;
import java.util.function.BiFunction;
import java.util.function.Function;
@@ -464,4 +466,16 @@ public class VanillaChronicleMap<K, V, R>
return q.defaultReturnValue().returnValue();
}
}
public void verifyTierCountersAreaData() {
for (int i = 0; i < actualSegments; i++) {
try (MapSegmentContext<K, V, ?> c = segmentContext(i)) {
Method verifyTierCountersAreaData =
c.getClass().getMethod("verifyTierCountersAreaData");
verifyTierCountersAreaData.invoke(c);
} catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
throw new AssertionError(e);
}
}
}
}