#3 Fixed a number of issue related to bit sets and blocks allocation in VanillaChronicleMap

This commit is contained in:
leventov
2014-10-15 11:11:06 +04:00
parent 0d7704435b
commit 331bdf8328
2 changed files with 50 additions and 8 deletions
@@ -133,7 +133,8 @@ class VanillaChronicleMap<K, KI, MKI extends MetaBytesInterop<K, KI>,
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<K, KI, MKI extends MetaBytesInterop<K, KI>,
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<K, KI, MKI extends MetaBytesInterop<K, KI>,
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<K, KI, MKI extends MetaBytesInterop<K, KI>,
);
}
}
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<K, KI, MKI extends MetaBytesInterop<K, KI>,
try {
hashLookup.clear();
freeList.clear();
nextPosToSearchFrom = 0;
resetSize();
} finally {
unlock();
@@ -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<Long> 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();
}
}
}