From 331bdf832863531d749ea772cdc2039b54289036 Mon Sep 17 00:00:00 2001 From: leventov Date: Wed, 15 Oct 2014 11:10:23 +0400 Subject: [PATCH] #3 Fixed a number of issue related to bit sets and blocks allocation in VanillaChronicleMap --- .../chronicle/map/VanillaChronicleMap.java | 30 ++++++++++++++----- .../net/openhft/chronicle/map/Issue3.java | 28 +++++++++++++++++ 2 files changed, 50 insertions(+), 8 deletions(-) create mode 100644 src/test/java/net/openhft/chronicle/map/Issue3.java diff --git a/src/main/java/net/openhft/chronicle/map/VanillaChronicleMap.java b/src/main/java/net/openhft/chronicle/map/VanillaChronicleMap.java index 1a2189a09..d34852d43 100644 --- a/src/main/java/net/openhft/chronicle/map/VanillaChronicleMap.java +++ b/src/main/java/net/openhft/chronicle/map/VanillaChronicleMap.java @@ -133,7 +133,8 @@ class VanillaChronicleMap, this.removeReturnsNull = builder.removeReturnsNull(); this.actualSegments = builder.actualSegments(); - this.entriesPerSegment = builder.actualEntriesPerSegment(); + // align by 8 because otherwise sizeOfBitSets() might address less blocks than specified + this.entriesPerSegment = align8(builder.actualEntriesPerSegment()); this.metaDataBytes = builder.metaDataBytes(); this.eventListener = builder.eventListener(); @@ -158,6 +159,10 @@ class VanillaChronicleMap, return (l + 63) & ~63; } + static int align8(int n) { + return (n + 7) & ~7; + } + void initTransients() { keyReaderProvider = Provider.of((Class) originalKeyReader.getClass()); keyInteropProvider = Provider.of((Class) originalKeyInterop.getClass()); @@ -555,8 +560,8 @@ class VanillaChronicleMap, long start = bytes.startAddr() + SEGMENT_HEADER; createHashLookups(start); start += align64(sizeOfMultiMap() + sizeOfMultiMapBitSet()) * multiMapsPerSegment(); - final NativeBytes bsBytes = new NativeBytes( - tmpBytes.objectSerializer(), start, start + sizeOfBitSets(), null); + final NativeBytes bsBytes = new NativeBytes(tmpBytes.objectSerializer(), + start, start + ((entriesPerSegment + 7) / 8), null); freeList = new SingleThreadedDirectBitSet(bsBytes); start += numberOfBitSets() * sizeOfBitSets(); entriesOffset = start - bytes.startAddr(); @@ -914,15 +919,23 @@ class VanillaChronicleMap, ); } } + updateNextPosToSearchFrom(ret, blocks); + } else { + // if bit at nextPosToSearchFrom is clear, it was skipped because + // more than 1 block was requested. Don't move nextPosToSearchFrom + // in this case. blocks == 1 clause is just a fast path. + if (blocks == 1 || freeList.isSet(nextPosToSearchFrom)) { + updateNextPosToSearchFrom(ret, blocks); + } } - // if bit at nextPosToSearchFrom is clear, it was skipped because - // more than 1 block was requested. Don't move nextPosToSearchFrom - // in this case. blocks == 1 clause is just a fast path. - if (blocks == 1 || freeList.isSet(nextPosToSearchFrom)) - nextPosToSearchFrom = ret + blocks; return ret; } + private void updateNextPosToSearchFrom(int allocated, int blocks) { + if ((nextPosToSearchFrom = allocated + blocks) >= freeList.size()) + nextPosToSearchFrom = 0; + } + private boolean realloc(int fromPos, int oldBlocks, int newBlocks) { if (freeList.allClear(fromPos + oldBlocks, fromPos + newBlocks)) { freeList.set(fromPos + oldBlocks, fromPos + newBlocks); @@ -1188,6 +1201,7 @@ class VanillaChronicleMap, try { hashLookup.clear(); freeList.clear(); + nextPosToSearchFrom = 0; resetSize(); } finally { unlock(); diff --git a/src/test/java/net/openhft/chronicle/map/Issue3.java b/src/test/java/net/openhft/chronicle/map/Issue3.java new file mode 100644 index 000000000..faf02b435 --- /dev/null +++ b/src/test/java/net/openhft/chronicle/map/Issue3.java @@ -0,0 +1,28 @@ +package net.openhft.chronicle.map; + +import net.openhft.chronicle.set.ChronicleSet; +import net.openhft.chronicle.set.ChronicleSetBuilder; +import org.junit.Test; + +import java.io.IOException; +import java.util.Random; +import java.util.Set; + +public class Issue3 { + + @Test + public void test() throws IOException { + Set set = ChronicleSetBuilder.of(Long.class) + .actualSegments(1) + .actualEntriesPerSegment(1000) + .create(); + + Random r = new Random(); + for (int i = 0; i < 10; i++) { + for (int j = 0; j < 300; j++) { + set.add(r.nextLong()); + } + set.clear(); + } + } +}