Add dataStoreSize field to Chronicle Map's global mutable state

This commit is contained in:
leventov
2016-02-13 21:27:30 +07:00
parent e5c37a1e8f
commit 05ccde9671
7 changed files with 87 additions and 43 deletions
@@ -18,6 +18,8 @@ package net.openhft.chronicle.hash;
import net.openhft.chronicle.bytes.Byteable;
import net.openhft.chronicle.values.Group;
import net.openhft.chronicle.values.Range;
import net.openhft.chronicle.values.Values;
/**
* <h1>This interface is a private API, don't use in client code</h1>
@@ -28,17 +30,27 @@ public interface VanillaGlobalMutableState extends Byteable {
@Group(1)
int getAllocatedExtraTierBulks();
void setAllocatedExtraTierBulks(int allocatedExtraTierBulks);
void setAllocatedExtraTierBulks(@Range(min = 0, max = 16777215) int allocatedExtraTierBulks);
@Group(2)
long getFirstFreeTierIndex();
void setFirstFreeTierIndex(long firstFreeTierIndex);
void setFirstFreeTierIndex(@Range(min = 0, max = 1099511627775L) long firstFreeTierIndex);
@Group(3)
long getExtraTiersInUse();
void setExtraTiersInUse(long extraTiersInUse);
void setExtraTiersInUse(@Range(min = 0, max = 1099511627775L) long extraTiersInUse);
@Group(4)
long getSegmentHeadersOffset();
void setSegmentHeadersOffset(long segmentHeadersOffset);
void setSegmentHeadersOffset(@Range(min = 0, max = 4294967295L) long segmentHeadersOffset);
@Group(5)
long getDataStoreSize();
void setDataStoreSize(@Range(min = 0, max = Long.MAX_VALUE) long dataStoreSize);
long addDataStoreSize(long addition);
public static void main(String[] args) {
System.setProperty("chronicle.values.dumpCode", "true");
Values.nativeClassFor(VanillaGlobalMutableState.class);
}
}
@@ -16,6 +16,7 @@
package net.openhft.chronicle.hash.impl;
import net.openhft.chronicle.algo.MemoryUnit;
import net.openhft.chronicle.algo.locks.*;
import net.openhft.chronicle.bytes.BytesStore;
import net.openhft.chronicle.bytes.MappedBytesStoreFactory;
@@ -434,6 +435,7 @@ public abstract class VanillaChronicleHash<K,
zeroOutNewlyMappedChronicleMapBytes();
// write the segment headers offset after zeroing out
globalMutableState.setSegmentHeadersOffset(segmentHeadersOffset);
globalMutableState.setDataStoreSize(sizeInBytesWithoutTiers());
} else {
initBulks();
}
@@ -481,24 +483,32 @@ public abstract class VanillaChronicleHash<K,
}
public final void createMappedStoreAndSegments() throws IOException {
// TODO this method had been moved -- not clear where
//OS.warnOnWindows(sizeInBytesWithoutTiers());
long mapSize = expectedFileSize();
createMappedStoreAndSegments(map(mapSize, 0));
createMappedStoreAndSegments(map(dataStoreSize(), 0));
}
public final void basicRecover() throws IOException {
long segmentHeadersOffset = computeSegmentHeadersOffset();
long segmentHeadersOffset = globalMutableState().getSegmentHeadersOffset();
if (segmentHeadersOffset <= 0 || segmentHeadersOffset % 4096 != 0 ||
segmentHeadersOffset > GIGABYTES.toBytes(1)) {
segmentHeadersOffset = computeSegmentHeadersOffset();
}
long sizeInBytesWithoutTiers = computeSizeInBytesWithoutTiers(segmentHeadersOffset);
long sizeBeyondSegments = Math.max(raf.length() - sizeInBytesWithoutTiers, 0);
int allocatedExtraTierBulks = (int) (sizeBeyondSegments / tierBulkSizeInBytes);
long mapSize = pageAlign(sizeInBytesWithoutTiers +
allocatedExtraTierBulks * tierBulkSizeInBytes);
initBytesStoreAndHeadersViews(map(mapSize, 0));
long dataStoreSize = globalMutableState().getDataStoreSize();
int allocatedExtraTierBulks = globalMutableState().getAllocatedExtraTierBulks();
if (dataStoreSize < sizeInBytesWithoutTiers ||
((dataStoreSize - sizeInBytesWithoutTiers) % tierBulkSizeInBytes != 0)) {
dataStoreSize = sizeInBytesWithoutTiers + allocatedExtraTierBulks * tierBulkSizeInBytes;
} else {
allocatedExtraTierBulks =
(int) ((dataStoreSize - sizeInBytesWithoutTiers) / tierBulkSizeInBytes);
}
initBytesStoreAndHeadersViews(map(dataStoreSize, 0));
resetGlobalMutableStateLock();
recoverAllocatedExtraTierBulks(allocatedExtraTierBulks);
recoverSegmentHeadersOffset(segmentHeadersOffset);
recoverDataStoreSize(dataStoreSize);
initOffsetsAndBulks();
}
@@ -530,6 +540,14 @@ public abstract class VanillaChronicleHash<K,
}
}
private void recoverDataStoreSize(long dataStoreSize) {
if (globalMutableState.getDataStoreSize() != dataStoreSize) {
LOG.error("data store size of map at {} corrupted. stored: {}, should be: {}",
file, globalMutableState.getDataStoreSize(), dataStoreSize);
globalMutableState.setDataStoreSize(dataStoreSize);
}
}
private boolean persisted() {
return file != null;
}
@@ -609,11 +627,11 @@ public abstract class VanillaChronicleHash<K,
return segmentHeadersOffset + actualSegments * (segmentHeaderSize + tierSize);
}
public final long expectedFileSize() {
public final long dataStoreSize() {
long sizeInBytesWithoutTiers = sizeInBytesWithoutTiers();
int allocatedExtraTierBulks = !createdOrInMemory ?
globalMutableState.getAllocatedExtraTierBulks() : 0;
return pageAlign(sizeInBytesWithoutTiers + allocatedExtraTierBulks * tierBulkSizeInBytes);
return sizeInBytesWithoutTiers + allocatedExtraTierBulks * tierBulkSizeInBytes;
}
@Override
@@ -800,6 +818,7 @@ public abstract class VanillaChronicleHash<K,
// after we are sure the new bulk is initialized, update the global mutable state
globalMutableState.setAllocatedExtraTierBulks(allocatedExtraTierBulks + 1);
globalMutableState.setFirstFreeTierIndex(firstTierIndex);
globalMutableState.addDataStoreSize(tierBulkSizeInBytes);
}
public void msync() throws IOException {
@@ -930,6 +949,7 @@ public abstract class VanillaChronicleHash<K,
* @see net.openhft.chronicle.bytes.MappedFile#acquireByteStore(long, MappedBytesStoreFactory)
*/
private NativeBytesStore map(long mapSize, long mappingOffsetInFile) throws IOException {
mapSize = pageAlign(mapSize);
long minFileSize = mappingOffsetInFile + mapSize;
FileChannel fileChannel = raf.getChannel();
if (fileChannel.size() < minFileSize) {
@@ -1593,11 +1593,11 @@ public final class ChronicleMapBuilder<K, V> implements
VanillaChronicleMap<K, V, ?> map = wire.getValueIn().typedMarshallable();
assert map != null;
map.initBeforeMapping(file, raf, headerBuffer.limit(), recover);
long expectedFileLength = map.expectedFileSize();
if (!recover && expectedFileLength != file.length()) {
long dataStoreSize = map.globalMutableState().getDataStoreSize();
if (!recover && dataStoreSize > file.length()) {
throw new IOException("The file " + file + " the map is serialized from " +
"has unexpected length " + file.length() + ", probably corrupted. " +
"Expected length is " + expectedFileLength);
"Data store size is " + dataStoreSize);
}
map.initTransientsFromBuilder(this);
if (!recover) {
@@ -1683,11 +1683,6 @@ public final class ChronicleMapBuilder<K, V> implements
try {
VanillaChronicleMap<K, V, ?> map = newMap();
// TODO this method had been moved
// if(OS.warnOnWindows(map.sizeInBytesWithoutTiers())){
// throw new IllegalStateException("Windows cannot support this configuration");
// }
BytesStore bytesStore =
lazyNativeBytesStoreWithFixedCapacity(map.sizeInBytesWithoutTiers());
map.createMappedStoreAndSegments(bytesStore);
@@ -17,21 +17,30 @@
package net.openhft.chronicle.map;
import net.openhft.chronicle.hash.VanillaGlobalMutableState;
import net.openhft.chronicle.values.Array;
import net.openhft.chronicle.values.Group;
import net.openhft.chronicle.values.*;
interface ReplicatedGlobalMutableState extends VanillaGlobalMutableState {
@Group(5)
int getCurrentCleanupSegmentIndex();
void setCurrentCleanupSegmentIndex(int currentCleanupSegmentIndex);
@Group(6)
int getCurrentCleanupSegmentIndex();
void setCurrentCleanupSegmentIndex(
@Range(min = 0, max = Integer.MAX_VALUE) int currentCleanupSegmentIndex);
@Group(7)
@Align(offset = 1)
int getModificationIteratorsCount();
int addModificationIteratorsCount(@Range(min = 0, max = 128) int addition);
@Group(8)
// Align to prohibit array filling the highest bit of the previous 2-byte block, that
// complicates generated code for all fields, defined in this interface.
@Align(offset = 2)
@Array(length = 128)
boolean getModificationIteratorInitAt(int index);
void setModificationIteratorInitAt(int index, boolean init);
@Group(7)
int getModificationIteratorsCount();
int addModificationIteratorsCount(int addition);
public static void main(String[] args) {
System.setProperty("chronicle.values.dumpCode", "true");
Values.nativeClassFor(ReplicatedGlobalMutableState.class);
}
}