PersistentEnumerator.ourLock monitor object is transformed to StorageLockContext.ReentrantLock

This commit is contained in:
Maxim.Mossienko
2012-05-19 01:52:11 +04:00
parent e59b335b41
commit 0556eb708c
7 changed files with 257 additions and 114 deletions
@@ -45,14 +45,14 @@ class IntToIntBtree {
private TIntIntHashMap myCachedMappings;
private final int myCachedMappingsSize;
public IntToIntBtree(int _pageSize, File file, boolean initial) throws IOException {
public IntToIntBtree(int _pageSize, File file, PagedFileStorage.StorageLockContext storageLockContext, boolean initial) throws IOException {
pageSize = _pageSize;
if (initial) {
FileUtil.delete(file);
}
storage = new ResizeableMappedFile(file, pageSize, PersistentEnumeratorBase.ourLock, 1024 * 1024, true);
storage = new ResizeableMappedFile(file, pageSize, storageLockContext, 1024 * 1024, true);
root = new BtreeIndexNodeView(this);
if (initial) {
@@ -34,6 +34,7 @@ import java.util.Comparator;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantLock;
/**
* @author max
@@ -69,7 +70,7 @@ public class PagedFileStorage implements Forceable {
"; mmap=" + (!ByteBufferWrapper.NO_MMAP));
}
private final StorageLock myLock;
private final StorageLockContext myStorageLockContext;
private int myLastPage = UNKNOWN_PAGE;
private int myLastPage2 = UNKNOWN_PAGE;
private ByteBufferWrapper myLastBuffer;
@@ -81,10 +82,23 @@ public class PagedFileStorage implements Forceable {
private static final int MAX_PAGES_COUNT = 0xFFFF;
private static final int MAX_LIVE_STORAGES_COUNT = 0xFFFF;
public void lock() {
myStorageLockContext.myReentrantLock.lock();
}
public void unlock() {
myStorageLockContext.myReentrantLock.unlock();
}
public StorageLockContext getStorageLockContext() {
return myStorageLockContext;
}
public static class StorageLock {
private static final int FILE_INDEX_MASK = 0xFFFF0000;
private static final int FILE_INDEX_SHIFT = 16;
private final boolean checkThreadAccess;
public final StorageLockContext myDefaultStorageLockContext;
public StorageLock() {
this(true);
@@ -92,11 +106,12 @@ public class PagedFileStorage implements Forceable {
public StorageLock(boolean checkThreadAccess) {
this.checkThreadAccess = checkThreadAccess;
myDefaultStorageLockContext = new StorageLockContext(this);
}
private final BuffersCache myBuffersCache = new BuffersCache();
private final ConcurrentHashMap<Integer, PagedFileStorage> myIndex2Storage = new ConcurrentHashMap<Integer, PagedFileStorage>();
private int registerPagedFileStorage(PagedFileStorage storage) {
int registered = myIndex2Storage.size();
assert registered <= MAX_LIVE_STORAGES_COUNT;
@@ -173,10 +188,10 @@ public class PagedFileStorage implements Forceable {
@NotNull
private ByteBufferWrapper createValue(Integer key) {
checkThreadAccess();
final int storageIndex = key & FILE_INDEX_MASK;
PagedFileStorage owner = getRegisteredPagedFileStorageByIndex(storageIndex);
assert owner != null: "No storage for index " + storageIndex;
checkThreadAccess(owner.myStorageLockContext);
int off = (key & MAX_PAGES_COUNT) * owner.myPageSize;
if (off > owner.length()) {
throw new IndexOutOfBoundsException("off=" + off + " key.owner.length()=" + owner.length());
@@ -218,14 +233,14 @@ public class PagedFileStorage implements Forceable {
}
}
private void checkThreadAccess() {
if (checkThreadAccess && !Thread.holdsLock(StorageLock.this)) {
private void checkThreadAccess(StorageLockContext storageLockContext) {
if (checkThreadAccess && !storageLockContext.myReentrantLock.isHeldByCurrentThread()) {
throw new IllegalStateException("Must hold StorageLock lock to access PagedFileStorage");
}
}
private @Nullable Map<Integer, ByteBufferWrapper> getBuffersOrderedForOwner(int index) {
checkThreadAccess();
private @Nullable Map<Integer, ByteBufferWrapper> getBuffersOrderedForOwner(int index, StorageLockContext storageLockContext) {
checkThreadAccess(storageLockContext);
Map<Integer, ByteBufferWrapper> mineBuffers = null;
for (Map.Entry<Integer, ByteBufferWrapper> entry : myMap.entrySet()) {
if ((entry.getKey() & FILE_INDEX_MASK) == index) {
@@ -243,8 +258,8 @@ public class PagedFileStorage implements Forceable {
return mineBuffers;
}
private void unmapBuffersForOwner(int index) {
final Map<Integer, ByteBufferWrapper> buffers = getBuffersOrderedForOwner(index);
private void unmapBuffersForOwner(int index, StorageLockContext storageLockContext) {
final Map<Integer, ByteBufferWrapper> buffers = getBuffersOrderedForOwner(index, storageLockContext);
if (buffers != null) {
for (Integer key : buffers.keySet()) {
@@ -253,8 +268,8 @@ public class PagedFileStorage implements Forceable {
}
}
private void flushBuffersForOwner(int index) {
Map<Integer, ByteBufferWrapper> buffers = getBuffersOrderedForOwner(index);
private void flushBuffersForOwner(int index, StorageLockContext storageLockContext) {
Map<Integer, ByteBufferWrapper> buffers = getBuffersOrderedForOwner(index, storageLockContext);
if (buffers != null) {
for(ByteBufferWrapper buffer:buffers.values()) {
@@ -274,14 +289,17 @@ public class PagedFileStorage implements Forceable {
@NonNls private static final String RW = "rw";
public PagedFileStorage(File file, StorageLock lock, int pageSize, boolean valuesAreBufferAligned) throws IOException {
myFile = file;
myLock = lock;
myPageSize = Math.max(pageSize > 0 ? pageSize : BUFFER_SIZE, Page.PAGE_SIZE);
myValuesAreBufferAligned = valuesAreBufferAligned;
myStorageIndex = lock.registerPagedFileStorage(this);
myTypedIOBuffer = valuesAreBufferAligned ? null:new byte[8];
this(file, lock.myDefaultStorageLockContext, pageSize, valuesAreBufferAligned);
}
public PagedFileStorage(File file, StorageLockContext storageLockContext, int pageSize, boolean valuesAreBufferAligned) throws IOException {
myFile = file;
myStorageLockContext = storageLockContext;
myPageSize = Math.max(pageSize > 0 ? pageSize : BUFFER_SIZE, Page.PAGE_SIZE);
myValuesAreBufferAligned = valuesAreBufferAligned;
myStorageIndex = storageLockContext.myLock.registerPagedFileStorage(this);
myTypedIOBuffer = valuesAreBufferAligned ? null:new byte[8];
}
public PagedFileStorage(File file, StorageLock lock) throws IOException {
this(file, lock, BUFFER_SIZE, false);
}
@@ -452,13 +470,13 @@ public class PagedFileStorage implements Forceable {
}
finally {
unmapAll();
myLock.myIndex2Storage.remove(myStorageIndex);
myStorageLockContext.myLock.myIndex2Storage.remove(myStorageIndex);
myStorageIndex = -1;
}
}
private void unmapAll() {
myLock.myBuffersCache.unmapBuffersForOwner(myStorageIndex);
myStorageLockContext.myLock.myBuffersCache.unmapBuffersForOwner(myStorageIndex, myStorageLockContext);
myLastPage = UNKNOWN_PAGE;
myLastPage2 = UNKNOWN_PAGE;
@@ -524,21 +542,21 @@ public class PagedFileStorage implements Forceable {
private ByteBuffer getBuffer(int page) {
if (myLastPage == page) {
ByteBuffer buf = myLastBuffer.getCachedBuffer();
if (buf != null && myLastChangeCount == myLock.myBuffersCache.changeCount) return buf;
if (buf != null && myLastChangeCount == myStorageLockContext.myLock.myBuffersCache.changeCount) return buf;
}
if (myLastPage2 == page) {
ByteBuffer buf = myLastBuffer2.getCachedBuffer();
if (buf != null && myLastChangeCount2 == myLock.myBuffersCache.changeCount) return buf;
if (buf != null && myLastChangeCount2 == myStorageLockContext.myLock.myBuffersCache.changeCount) return buf;
}
try {
assert page <= MAX_PAGES_COUNT;
if (myStorageIndex == -1) {
myStorageIndex = myLock.registerPagedFileStorage(this);
myStorageIndex = myStorageLockContext.myLock.registerPagedFileStorage(this);
}
ByteBufferWrapper byteBufferWrapper = myLock.myBuffersCache.get(myStorageIndex | page);
ByteBufferWrapper byteBufferWrapper = myStorageLockContext.myLock.myBuffersCache.get(myStorageIndex | page);
ByteBuffer buf = byteBufferWrapper.getBuffer();
if (myLastPage != page) {
@@ -551,7 +569,7 @@ public class PagedFileStorage implements Forceable {
myLastBuffer = byteBufferWrapper;
}
myLastChangeCount = myLock.myBuffersCache.changeCount;
myLastChangeCount = myStorageLockContext.myLock.myBuffersCache.changeCount;
return buf;
}
@@ -562,7 +580,7 @@ public class PagedFileStorage implements Forceable {
public void force() {
long started = IOStatistics.DEBUG ? System.currentTimeMillis():0;
myLock.myBuffersCache.flushBuffersForOwner(myStorageIndex);
myStorageLockContext.myLock.myBuffersCache.flushBuffersForOwner(myStorageIndex, myStorageLockContext);
isDirty = false;
if (IOStatistics.DEBUG) {
@@ -576,4 +594,14 @@ public class PagedFileStorage implements Forceable {
public boolean isDirty() {
return isDirty;
}
public static class StorageLockContext {
private final ReentrantLock myReentrantLock;
private final StorageLock myLock;
public StorageLockContext(StorageLock lock) {
myReentrantLock = new ReentrantLock();
myLock = lock;
}
}
}
@@ -65,18 +65,29 @@ public class PersistentBTreeEnumerator<Data> extends PersistentEnumeratorBase<Da
private static final int KEY_SHIFT = 1;
public PersistentBTreeEnumerator(@NotNull File file, @NotNull KeyDescriptor<Data> dataDescriptor, int initialSize) throws IOException {
super(file, new ResizeableMappedFile(file, initialSize, ourLock, VALUE_PAGE_SIZE, true), dataDescriptor, initialSize,
this(file, dataDescriptor, initialSize, ourLock.myDefaultStorageLockContext);
}
public PersistentBTreeEnumerator(@NotNull File file,
@NotNull KeyDescriptor<Data> dataDescriptor,
int initialSize,
PagedFileStorage.StorageLockContext lockContext) throws IOException {
super(file, new ResizeableMappedFile(file, initialSize, lockContext, VALUE_PAGE_SIZE, true), dataDescriptor, initialSize,
ourVersion, new RecordBufferHandler(), false);
myInlineKeysNoMapping = myDataDescriptor instanceof InlineKeyDescriptor && !wantKeyMapping();
myExternalKeysNoMapping = !(myDataDescriptor instanceof InlineKeyDescriptor) && !wantKeyMapping();
if (btree == null) {
synchronized (ourLock) {
try {
lockStorage();
storeVars(false);
initBtree(false);
storeBTreeVars(false);
}
finally {
unlockStorage();
}
}
}
@@ -90,7 +101,7 @@ public class PersistentBTreeEnumerator<Data> extends PersistentEnumeratorBase<Da
}
private void initBtree(boolean initial) throws IOException {
btree = new IntToIntBtree(PAGE_SIZE, indexFile(myFile), initial);
btree = new IntToIntBtree(PAGE_SIZE, indexFile(myFile), myStorage.getPagedFileStorage().getStorageLockContext(), initial);
}
private void storeVars(boolean toDisk) {
@@ -172,31 +183,32 @@ public class PersistentBTreeEnumerator<Data> extends PersistentEnumeratorBase<Da
@Override
public boolean traverseAllRecords(@NotNull final RecordsProcessor p) throws IOException {
try {
synchronized (ourLock) {
return btree.processMappings(new IntToIntBtree.KeyValueProcessor() {
public boolean process(int key, int value) throws IOException {
p.setCurrentKey(key);
lockStorage();
return btree.processMappings(new IntToIntBtree.KeyValueProcessor() {
public boolean process(int key, int value) throws IOException {
p.setCurrentKey(key);
if (value > 0) {
if (!p.process(value)) return false;
}
else {
int rec = -value;
while (rec != 0) {
int id = myStorage.getInt(rec);
if (!p.process(id)) return false;
rec = myStorage.getInt(rec + COLLISION_OFFSET);
}
}
return true;
if (value > 0) {
if (!p.process(value)) return false;
}
});
}
else {
int rec = -value;
while (rec != 0) {
int id = myStorage.getInt(rec);
if (!p.process(id)) return false;
rec = myStorage.getInt(rec + COLLISION_OFFSET);
}
}
return true;
}
});
}
catch (IllegalStateException e) {
CorruptedException corruptedException = new CorruptedException(myFile);
corruptedException.initCause(e);
throw corruptedException;
} finally {
unlockStorage();
}
}
@@ -244,9 +256,9 @@ public class PersistentBTreeEnumerator<Data> extends PersistentEnumeratorBase<Da
private final int[] myResultBuf = new int[1];
protected synchronized int enumerateImpl(final Data value, final boolean onlyCheckForExisting, boolean saveNewValue) throws IOException {
protected int enumerateImpl(final Data value, final boolean onlyCheckForExisting, boolean saveNewValue) throws IOException {
try {
synchronized (ourLock) {
lockStorage();
if (IntToIntBtree.doDump) System.out.println(value);
final int valueHC = myDataDescriptor.getHashCode(value);
@@ -348,12 +360,13 @@ public class PersistentBTreeEnumerator<Data> extends PersistentEnumeratorBase<Da
}
}
return newValueId;
}
}
catch (IllegalStateException e) {
CorruptedException exception = new CorruptedException(myFile);
exception.initCause(e);
throw exception;
} finally {
unlockStorage();
}
}
@@ -49,7 +49,14 @@ public class PersistentEnumerator<Data> extends PersistentEnumeratorBase<Data> {
private static final Version ourVersion = new Version(CORRECTLY_CLOSED_MAGIC, DIRTY_MAGIC);
public PersistentEnumerator(@NotNull File file, @NotNull KeyDescriptor<Data> dataDescriptor, int initialSize) throws IOException {
super(file, new ResizeableMappedFile(file, initialSize, ourLock), dataDescriptor, initialSize, ourVersion,
this(file, dataDescriptor, initialSize, ourLock.myDefaultStorageLockContext);
}
public PersistentEnumerator(@NotNull File file,
@NotNull KeyDescriptor<Data> dataDescriptor,
int initialSize,
PagedFileStorage.StorageLockContext storageLockContext) throws IOException {
super(file, new ResizeableMappedFile(file, initialSize, storageLockContext, -1, false), dataDescriptor, initialSize, ourVersion,
new RecordBufferHandler(), true);
}
@@ -62,7 +69,8 @@ public class PersistentEnumerator<Data> extends PersistentEnumeratorBase<Data> {
}
private boolean traverseRecords(int vectorStart, int slotsCount, @NotNull RecordsProcessor p) throws IOException {
synchronized (ourLock) {
lockStorage();
try {
for (int slotIdx = 0; slotIdx < slotsCount; slotIdx++) {
final int vector = myStorage.getInt(vectorStart + slotIdx * 4);
if (vector < 0) {
@@ -76,10 +84,14 @@ public class PersistentEnumerator<Data> extends PersistentEnumeratorBase<Data> {
}
return true;
}
finally {
unlockStorage();
}
}
protected synchronized int enumerateImpl(final Data value, final boolean onlyCheckForExisting, boolean saveNewValue) throws IOException {
synchronized (ourLock) {
lockStorage();
try {
int depth = 0;
final int valueHC = myDataDescriptor.getHashCode(value);
int hc = valueHC;
@@ -163,6 +175,9 @@ public class PersistentEnumerator<Data> extends PersistentEnumeratorBase<Data> {
return newId;
}
}
finally {
unlockStorage();
}
}
protected int writeData(final Data value, int hashCode) {
@@ -161,7 +161,8 @@ abstract class PersistentEnumeratorBase<Data> implements Forceable, Closeable {
myStorage = storage;
synchronized (ourLock) {
lockStorage();
try {
if (myStorage.length() == 0) {
try {
markDirty(true);
@@ -203,17 +204,28 @@ abstract class PersistentEnumeratorBase<Data> implements Forceable, Closeable {
}
}
}
finally {
unlockStorage();
}
if (myDataDescriptor instanceof InlineKeyDescriptor) {
myKeyStorage = null;
myKeyReadStream = null;
}
else {
myKeyStorage = new ResizeableMappedFile(keystreamFile(), initialSize, ourLock);
myKeyStorage = new ResizeableMappedFile(keystreamFile(), initialSize, myStorage.getPagedFileStorage().getStorageLockContext(), -1, false);
myKeyReadStream = new MyDataIS(myKeyStorage);
}
}
public void lockStorage() {
myStorage.getPagedFileStorage().lock();
}
public void unlockStorage() {
myStorage.getPagedFileStorage().unlock();
}
protected abstract void setupEmptyFile() throws IOException;
@NotNull
@@ -277,27 +289,43 @@ abstract class PersistentEnumeratorBase<Data> implements Forceable, Closeable {
}
protected void putMetaData(long data) throws IOException {
synchronized (ourLock) {
lockStorage();
try {
myStorage.putLong(META_DATA_OFFSET, data);
}
finally {
unlockStorage();
}
}
protected long getMetaData() throws IOException {
synchronized (ourLock) {
lockStorage();
try {
return myStorage.getLong(META_DATA_OFFSET);
}
finally {
unlockStorage();
}
}
protected void putMetaData2(long data) throws IOException {
synchronized (ourLock) {
lockStorage();
try {
myStorage.putLong(META_DATA_OFFSET + 8, data);
}
finally {
unlockStorage();
}
}
protected long getMetaData2() throws IOException {
synchronized (ourLock) {
lockStorage();
try {
return myStorage.getLong(META_DATA_OFFSET + 8);
}
finally {
unlockStorage();
}
}
public boolean processAllDataObject(final Processor<Data> processor, @Nullable final DataFilter filter) throws IOException {
@@ -365,7 +393,8 @@ abstract class PersistentEnumeratorBase<Data> implements Forceable, Closeable {
}
protected boolean iterateData(final Processor<Data> processor) throws IOException {
synchronized (ourLock) {
lockStorage();
try {
if (myKeyStorage == null) {
throw new UnsupportedOperationException("Iteration over InlineIntegerKeyDescriptors is not supported");
}
@@ -390,30 +419,35 @@ abstract class PersistentEnumeratorBase<Data> implements Forceable, Closeable {
keysStream.close();
}
}
finally {
unlockStorage();
}
}
private File keystreamFile() {
return new File(myFile.getPath() + ".keystream");
}
public synchronized Data valueOf(int idx) throws IOException {
synchronized (ourLock) {
try {
int addr = indexToAddr(idx);
public Data valueOf(int idx) throws IOException {
lockStorage();
try {
int addr = indexToAddr(idx);
if (myKeyReadStream == null) return ((InlineKeyDescriptor<Data>)myDataDescriptor).fromInt(addr);
if (myKeyReadStream == null) return ((InlineKeyDescriptor<Data>)myDataDescriptor).fromInt(addr);
myKeyReadStream.setup(addr, myKeyStorage.length());
return myDataDescriptor.read(myKeyReadStream);
}
catch (IOException io) {
markCorrupted();
throw io;
}
catch (Throwable e) {
markCorrupted();
throw new RuntimeException(e);
}
myKeyReadStream.setup(addr, myKeyStorage.length());
return myDataDescriptor.read(myKeyReadStream);
}
catch (IOException io) {
markCorrupted();
throw io;
}
catch (Throwable e) {
markCorrupted();
throw new RuntimeException(e);
}
finally {
unlockStorage();
}
}
@@ -452,12 +486,16 @@ abstract class PersistentEnumeratorBase<Data> implements Forceable, Closeable {
@Override
public synchronized void close() throws IOException {
synchronized (ourLock) {
lockStorage();
try {
if (!myClosed) {
myClosed = true;
doClose();
}
}
finally {
unlockStorage();
}
}
protected void doClose() throws IOException {
@@ -482,11 +520,15 @@ abstract class PersistentEnumeratorBase<Data> implements Forceable, Closeable {
}
private synchronized void flush() throws IOException {
synchronized (ourLock) {
lockStorage();
try {
if (myStorage.isDirty() || isDirty()) {
doFlush();
}
}
finally {
unlockStorage();
}
}
protected void doFlush() throws IOException {
@@ -496,23 +538,27 @@ abstract class PersistentEnumeratorBase<Data> implements Forceable, Closeable {
@Override
public synchronized void force() {
synchronized (ourLock) {
try {
if (myKeyStorage != null) {
myKeyStorage.force();
}
flush();
}
catch (IOException e) {
throw new RuntimeException(e);
lockStorage();
try {
if (myKeyStorage != null) {
myKeyStorage.force();
}
flush();
}
catch (IOException e) {
throw new RuntimeException(e);
}
finally {
unlockStorage();
}
}
protected final void markDirty(boolean dirty) throws IOException {
//assert Thread.holdsLock(this) || Thread.holdsLock(ourLock); // we hold one lock or another so can access myDirty
if (dirty && myDirty && !myDirtyStatusUpdateInProgress) return;
synchronized (ourLock) {
lockStorage();
try {
if (myDirty) {
if (!dirty) {
myDirtyStatusUpdateInProgress = true;
@@ -533,6 +579,9 @@ abstract class PersistentEnumeratorBase<Data> implements Forceable, Closeable {
}
}
}
finally {
unlockStorage();
}
}
protected synchronized void markCorrupted() {
@@ -100,24 +100,26 @@ public class PersistentHashMap<Key, Value> extends PersistentEnumeratorDelegate<
@Override
protected void onDropFromCache(final Key key, @NotNull final AppendStream value) {
synchronized (PersistentEnumerator.ourLock) {
try {
final BufferExposingByteArrayOutputStream bytes = value.getInternalBuffer();
final int id = enumerate(key);
long oldHeaderRecord = readValueId(id);
myEnumerator.lockStorage();
try {
final BufferExposingByteArrayOutputStream bytes = value.getInternalBuffer();
final int id = enumerate(key);
long oldHeaderRecord = readValueId(id);
long headerRecord = myValueStorage.appendBytes(bytes.getInternalBuffer(), 0, bytes.size(), oldHeaderRecord);
long headerRecord = myValueStorage.appendBytes(bytes.getInternalBuffer(), 0, bytes.size(), oldHeaderRecord);
updateValueId(id, headerRecord, oldHeaderRecord, key, 0);
if (oldHeaderRecord == NULL_ADDR) {
myLiveAndGarbageKeysCounter += LIVE_KEY_MASK;
}
myStreamPool.recycle(value);
}
catch (IOException e) {
throw new RuntimeException(e);
updateValueId(id, headerRecord, oldHeaderRecord, key, 0);
if (oldHeaderRecord == NULL_ADDR) {
myLiveAndGarbageKeysCounter += LIVE_KEY_MASK;
}
myStreamPool.recycle(value);
}
catch (IOException e) {
throw new RuntimeException(e);
}
finally {
myEnumerator.unlockStorage();
}
}
};
@@ -213,9 +215,13 @@ public class PersistentHashMap<Key, Value> extends PersistentEnumeratorDelegate<
public void dropMemoryCaches() {
synchronized (myEnumerator) {
synchronized (PersistentEnumerator.ourLock) {
myEnumerator.lockStorage();
try {
clearAppenderCaches();
}
finally {
myEnumerator.unlockStorage();
}
}
}
@@ -283,7 +289,8 @@ public class PersistentHashMap<Key, Value> extends PersistentEnumeratorDelegate<
}
protected void doPut(Key key, Value value) throws IOException {
synchronized (PersistentEnumerator.ourLock) {
myEnumerator.lockStorage();
try {
myEnumerator.markDirty(true);
myAppendCache.remove(key);
@@ -304,6 +311,9 @@ public class PersistentHashMap<Key, Value> extends PersistentEnumeratorDelegate<
updateValueId(id, header, oldheader, key, 0);
}
finally {
myEnumerator.unlockStorage();
}
}
@Override
@@ -371,7 +381,8 @@ public class PersistentHashMap<Key, Value> extends PersistentEnumeratorDelegate<
@Nullable
protected Value doGet(Key key) throws IOException {
synchronized (PersistentEnumerator.ourLock) {
myEnumerator.lockStorage();
try {
myAppendCache.remove(key);
final int id = tryEnumerate(key);
if (id == PersistentEnumerator.NULL_ID) {
@@ -399,6 +410,9 @@ public class PersistentHashMap<Key, Value> extends PersistentEnumeratorDelegate<
input.close();
}
}
finally {
myEnumerator.unlockStorage();
}
}
public final boolean containsMapping(Key key) throws IOException {
@@ -408,7 +422,8 @@ public class PersistentHashMap<Key, Value> extends PersistentEnumeratorDelegate<
}
protected boolean doContainsMapping(Key key) throws IOException {
synchronized (PersistentEnumerator.ourLock) {
myEnumerator.lockStorage();
try {
myAppendCache.remove(key);
final int id = tryEnumerate(key);
if (id == PersistentEnumerator.NULL_ID) {
@@ -416,6 +431,9 @@ public class PersistentHashMap<Key, Value> extends PersistentEnumeratorDelegate<
}
return readValueId(id) != NULL_ADDR;
}
finally {
myEnumerator.unlockStorage();
}
}
public final void remove(Key key) throws IOException {
@@ -425,7 +443,8 @@ public class PersistentHashMap<Key, Value> extends PersistentEnumeratorDelegate<
}
protected void doRemove(Key key) throws IOException {
synchronized (PersistentEnumerator.ourLock) {
myEnumerator.lockStorage();
try {
myAppendCache.remove(key);
final int id = tryEnumerate(key);
if (id == PersistentEnumerator.NULL_ID) {
@@ -440,6 +459,9 @@ public class PersistentHashMap<Key, Value> extends PersistentEnumeratorDelegate<
updateValueId(id, NULL_ADDR, record, key, 0);
}
finally {
myEnumerator.unlockStorage();
}
}
@Override
@@ -457,7 +479,8 @@ public class PersistentHashMap<Key, Value> extends PersistentEnumeratorDelegate<
}
protected void doForce() {
synchronized (PersistentEnumerator.ourLock) {
myEnumerator.lockStorage();
try {
try {
clearAppenderCaches();
}
@@ -465,6 +488,9 @@ public class PersistentHashMap<Key, Value> extends PersistentEnumeratorDelegate<
super.force();
}
}
finally {
myEnumerator.unlockStorage();
}
}
private void clearAppenderCaches() {
@@ -480,7 +506,8 @@ public class PersistentHashMap<Key, Value> extends PersistentEnumeratorDelegate<
}
protected void doClose() throws IOException {
synchronized (PersistentEnumerator.ourLock) {
myEnumerator.lockStorage();
try {
try {
myAppendCacheFlusher.stop();
myAppendCache.clear();
@@ -493,6 +520,9 @@ public class PersistentHashMap<Key, Value> extends PersistentEnumeratorDelegate<
super.close();
}
}
finally {
myEnumerator.unlockStorage();
}
}
// made public for tests
@@ -31,8 +31,8 @@ public class ResizeableMappedFile implements Forceable {
private long myLogicalSize;
private final PagedFileStorage myStorage;
public ResizeableMappedFile(final File file, int initialSize, PagedFileStorage.StorageLock lock, int pageSize, boolean valuesAreBufferAligned) throws IOException {
myStorage = new PagedFileStorage(file, lock, pageSize, valuesAreBufferAligned);
public ResizeableMappedFile(final File file, int initialSize, PagedFileStorage.StorageLockContext lockContext, int pageSize, boolean valuesAreBufferAligned) throws IOException {
myStorage = new PagedFileStorage(file, lockContext, pageSize, valuesAreBufferAligned);
boolean exists = file.exists();
if (!exists || file.length() == 0) {
if (!exists) FileUtil.createParentDirs(file);
@@ -41,12 +41,20 @@ public class ResizeableMappedFile implements Forceable {
myLogicalSize = readLength();
if (myLogicalSize == 0) {
synchronized (lock) {
try {
getPagedFileStorage().lock();
resize(initialSize);
}
finally {
getPagedFileStorage().unlock();
}
}
}
public ResizeableMappedFile(final File file, int initialSize, PagedFileStorage.StorageLock lock, int pageSize, boolean valuesAreBufferAligned) throws IOException {
this(file, initialSize, lock.myDefaultStorageLockContext, pageSize, valuesAreBufferAligned);
}
public ResizeableMappedFile(final File file, int initialSize, PagedFileStorage.StorageLock lock) throws IOException {
this(file, initialSize, lock, -1, false);
}