mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
PersistentEnumerator.ourLock monitor object is transformed to StorageLockContext.ReentrantLock
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user