summaryrefslogtreecommitdiff
path: root/platform/util/src/com/intellij/util/io
diff options
context:
space:
mode:
Diffstat (limited to 'platform/util/src/com/intellij/util/io')
-rw-r--r--platform/util/src/com/intellij/util/io/AbstractStringEnumerator.java8
-rw-r--r--platform/util/src/com/intellij/util/io/AppendableStorageBackedByResizableMappedFile.java4
-rw-r--r--platform/util/src/com/intellij/util/io/CachingEnumerator.java149
-rw-r--r--platform/util/src/com/intellij/util/io/DataEnumerator.java30
-rw-r--r--platform/util/src/com/intellij/util/io/EnumeratorStringDescriptor.java1
-rw-r--r--platform/util/src/com/intellij/util/io/IntToIntBtree.java10
-rw-r--r--platform/util/src/com/intellij/util/io/PagedFileStorage.java30
-rw-r--r--platform/util/src/com/intellij/util/io/PersistentHashMap.java2
-rw-r--r--platform/util/src/com/intellij/util/io/PersistentStringEnumerator.java131
9 files changed, 224 insertions, 141 deletions
diff --git a/platform/util/src/com/intellij/util/io/AbstractStringEnumerator.java b/platform/util/src/com/intellij/util/io/AbstractStringEnumerator.java
index 589fa0add6fe..a8145d5351dd 100644
--- a/platform/util/src/com/intellij/util/io/AbstractStringEnumerator.java
+++ b/platform/util/src/com/intellij/util/io/AbstractStringEnumerator.java
@@ -16,19 +16,13 @@
package com.intellij.util.io;
import com.intellij.openapi.Forceable;
-import org.jetbrains.annotations.Nullable;
import java.io.Closeable;
-import java.io.IOException;
/**
* Author: dmitrylomov
*/
-public interface AbstractStringEnumerator extends Closeable, Forceable {
- int enumerate(@Nullable String value) throws IOException;
-
- @Nullable
- String valueOf(int idx) throws IOException;
+public interface AbstractStringEnumerator extends Closeable, Forceable, DataEnumerator<String> {
void markCorrupted();
}
diff --git a/platform/util/src/com/intellij/util/io/AppendableStorageBackedByResizableMappedFile.java b/platform/util/src/com/intellij/util/io/AppendableStorageBackedByResizableMappedFile.java
index 6f936d75849a..c4381da1a406 100644
--- a/platform/util/src/com/intellij/util/io/AppendableStorageBackedByResizableMappedFile.java
+++ b/platform/util/src/com/intellij/util/io/AppendableStorageBackedByResizableMappedFile.java
@@ -158,7 +158,7 @@ public class AppendableStorageBackedByResizableMappedFile extends ResizeableMapp
int base = addr;
int address = storage.getOffsetInPage(addr);
boolean same = true;
- ByteBuffer buffer = storage.getByteBuffer(addr, false);
+ ByteBuffer buffer = storage.getByteBuffer(addr, false).getCachedBuffer();
final int myPageSize = storage.myPageSize;
@Override
@@ -166,7 +166,7 @@ public class AppendableStorageBackedByResizableMappedFile extends ResizeableMapp
if (same) {
if (myPageSize == address && address < myFileLength) { // reached end of current byte buffer
base += address;
- buffer = storage.getByteBuffer(base, false);
+ buffer = storage.getByteBuffer(base, false).getCachedBuffer();
address = 0;
}
same = address < myFileLength && buffer.get(address++) == (byte)b;
diff --git a/platform/util/src/com/intellij/util/io/CachingEnumerator.java b/platform/util/src/com/intellij/util/io/CachingEnumerator.java
new file mode 100644
index 000000000000..94ce68c981ca
--- /dev/null
+++ b/platform/util/src/com/intellij/util/io/CachingEnumerator.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.util.io;
+
+import com.intellij.util.containers.SLRUMap;
+import jsr166e.extra.SequenceLock;
+import org.jetbrains.annotations.Nullable;
+
+import java.io.IOException;
+import java.util.concurrent.locks.Lock;
+
+/**
+ * @author peter
+ */
+public class CachingEnumerator<Data> implements DataEnumerator<Data> {
+ private static final int STRIPE_POWER = 4;
+ private static final int STRIPE_COUNT = 1 << STRIPE_POWER;
+ private static final int STRIPE_MASK = STRIPE_COUNT - 1;
+ @SuppressWarnings("unchecked") private final SLRUMap<Integer, Integer>[] myHashcodeToIdCache = new SLRUMap[STRIPE_COUNT];
+ @SuppressWarnings("unchecked") private final SLRUMap<Integer, Data>[] myIdToStringCache = new SLRUMap[STRIPE_COUNT];
+ private final Lock[] myStripeLocks = new Lock[STRIPE_COUNT];
+ private final DataEnumerator<Data> myBase;
+ private final KeyDescriptor<Data> myDataDescriptor;
+
+ public CachingEnumerator(DataEnumerator<Data> base, KeyDescriptor<Data> dataDescriptor) {
+ myBase = base;
+ myDataDescriptor = dataDescriptor;
+ int protectedSize = 8192;
+ int probationalSize = 8192;
+
+ for(int i = 0; i < STRIPE_COUNT; ++i) {
+ myHashcodeToIdCache[i] = new SLRUMap<Integer, Integer>(protectedSize / STRIPE_COUNT, probationalSize / STRIPE_COUNT);
+ myIdToStringCache[i] = new SLRUMap<Integer, Data>(protectedSize / STRIPE_COUNT, probationalSize / STRIPE_COUNT);
+ myStripeLocks[i] = new SequenceLock();
+ }
+
+ }
+
+ public int enumerate(@Nullable Data value) throws IOException {
+ int valueHashCode =-1;
+ int stripe = -1;
+
+ if (myHashcodeToIdCache != null && value != null) {
+ valueHashCode = myDataDescriptor.getHashCode(value);
+ stripe = Math.abs(valueHashCode) & STRIPE_MASK;
+
+ Integer cachedId;
+
+ myStripeLocks[stripe].lock();
+ try {
+ cachedId = myHashcodeToIdCache[stripe].get(valueHashCode);
+ }
+ finally {
+ myStripeLocks[stripe].unlock();
+ }
+
+ if (cachedId != null) {
+ int stripe2 = idStripe(cachedId.intValue());
+ myStripeLocks[stripe2].lock();
+ try {
+ Data s = myIdToStringCache[stripe2].get(cachedId);
+ if (s != null && myDataDescriptor.isEqual(value, s)) return cachedId.intValue();
+ }
+ finally {
+ myStripeLocks[stripe2].unlock();
+ }
+ }
+ }
+
+ int enumerate = myBase.enumerate(value);
+
+ if (stripe != -1) {
+ Integer enumeratedInteger;
+
+ myStripeLocks[stripe].lock();
+ try {
+ enumeratedInteger = enumerate;
+ myHashcodeToIdCache[stripe].put(valueHashCode, enumeratedInteger);
+ } finally {
+ myStripeLocks[stripe].unlock();
+ }
+
+ int stripe2 = idStripe(enumerate);
+ myStripeLocks[stripe2].lock();
+ try {
+ myIdToStringCache[stripe2].put(enumeratedInteger, value);
+ } finally {
+ myStripeLocks[stripe2].unlock();
+ }
+ }
+
+ return enumerate;
+ }
+
+ private static int idStripe(int h) {
+ h ^= (h >>> 20) ^ (h >>> 12);
+ return Math.abs(h ^ (h >>> 7) ^ (h >>> 4)) & STRIPE_MASK;
+ }
+
+ @Nullable
+ public Data valueOf(int idx) throws IOException {
+ int stripe = -1;
+ if (myIdToStringCache != null) {
+ stripe = idStripe(idx);
+ myStripeLocks[stripe].lock();
+ try {
+ Data s = myIdToStringCache[stripe].get(idx);
+ if (s != null) return s;
+ }
+ finally {
+ myStripeLocks[stripe].unlock();
+ }
+ }
+ Data s = myBase.valueOf(idx);
+
+ if (stripe != -1 && s != null) {
+ myStripeLocks[stripe].lock();
+ try {
+ myIdToStringCache[stripe].put(idx, s);
+ }
+ finally {
+ myStripeLocks[stripe].unlock();
+ }
+ }
+ return s;
+ }
+
+ public void close() throws IOException {
+ for(int i = 0; i < myIdToStringCache.length; ++i) {
+ myStripeLocks[i].lock();
+ myIdToStringCache[i].clear();
+ myHashcodeToIdCache[i].clear();
+ myStripeLocks[i].unlock();
+ }
+ }
+}
diff --git a/platform/util/src/com/intellij/util/io/DataEnumerator.java b/platform/util/src/com/intellij/util/io/DataEnumerator.java
new file mode 100644
index 000000000000..3a7a1131b638
--- /dev/null
+++ b/platform/util/src/com/intellij/util/io/DataEnumerator.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.util.io;
+
+import org.jetbrains.annotations.Nullable;
+
+import java.io.IOException;
+
+/**
+ * @author peter
+ */
+public interface DataEnumerator<Data> {
+ int enumerate(@Nullable Data value) throws IOException;
+
+ @Nullable
+ Data valueOf(int idx) throws IOException;
+}
diff --git a/platform/util/src/com/intellij/util/io/EnumeratorStringDescriptor.java b/platform/util/src/com/intellij/util/io/EnumeratorStringDescriptor.java
index dce1d4990623..922701542394 100644
--- a/platform/util/src/com/intellij/util/io/EnumeratorStringDescriptor.java
+++ b/platform/util/src/com/intellij/util/io/EnumeratorStringDescriptor.java
@@ -26,6 +26,7 @@ import java.io.IOException;
* Date: Dec 18, 2007
*/
public class EnumeratorStringDescriptor implements KeyDescriptor<String> {
+ public static final EnumeratorStringDescriptor INSTANCE = new EnumeratorStringDescriptor();
@Override
public int getHashCode(final String value) {
return value.hashCode();
diff --git a/platform/util/src/com/intellij/util/io/IntToIntBtree.java b/platform/util/src/com/intellij/util/io/IntToIntBtree.java
index 8cddbcee32c8..b17fc6cc5c6c 100644
--- a/platform/util/src/com/intellij/util/io/IntToIntBtree.java
+++ b/platform/util/src/com/intellij/util/io/IntToIntBtree.java
@@ -203,7 +203,7 @@ class IntToIntBtree {
boolean canUseLastKey = myCanUseLastKey;
if (canUseLastKey) {
myCanUseLastKey = false;
- if (key == myLastGetKey && !myAccessNodeView.myHasFullPagesAlongPath) {
+ if (key == myLastGetKey && !myAccessNodeView.myHasFullPagesAlongPath && myAccessNodeView.isValid()) {
++myOptimizedInserts;
++count;
myAccessNodeView.insert(key, value);
@@ -284,6 +284,7 @@ class IntToIntBtree {
private short myChildrenCount;
protected int myAddressInBuffer;
protected ByteBuffer myBuffer;
+ protected ByteBufferWrapper myBufferWrapper;
protected boolean myHasFullPagesAlongPath;
protected boolean myIsDirty;
@@ -302,7 +303,8 @@ class IntToIntBtree {
protected void syncWithStore() {
PagedFileStorage pagedFileStorage = btree.storage.getPagedFileStorage();
myAddressInBuffer = pagedFileStorage.getOffsetInPage(address);
- myBuffer = pagedFileStorage.getByteBuffer(address, false);
+ myBufferWrapper = pagedFileStorage.getByteBuffer(address, false);
+ myBuffer = myBufferWrapper.getCachedBuffer();
myIsDirty = false; // we will mark dirty on child count change, attrs change or existing key put
doInitFlags(myBuffer.getInt(myAddressInBuffer));
}
@@ -541,6 +543,10 @@ class IntToIntBtree {
setAddress(address);
}
+ public boolean isValid() {
+ return myBufferWrapper.getCachedBuffer() == myBuffer;
+ }
+
private static class HashLeafData {
final BtreeIndexNodeView nodeView;
final int[] keys;
diff --git a/platform/util/src/com/intellij/util/io/PagedFileStorage.java b/platform/util/src/com/intellij/util/io/PagedFileStorage.java
index 1d5e9d76d04e..69315f1b3764 100644
--- a/platform/util/src/com/intellij/util/io/PagedFileStorage.java
+++ b/platform/util/src/com/intellij/util/io/PagedFileStorage.java
@@ -151,7 +151,7 @@ public class PagedFileStorage implements Forceable {
if (myValuesAreBufferAligned) {
long page = addr / myPageSize;
int page_offset = (int) (addr % myPageSize);
- return getBuffer(page, false).getInt(page_offset);
+ return getReadOnlyBuffer(page).getInt(page_offset);
} else {
get(addr, myTypedIOBuffer, 0, 4);
return Bits.getInt(myTypedIOBuffer, 0);
@@ -173,15 +173,15 @@ public class PagedFileStorage implements Forceable {
return (int)(addr % myPageSize);
}
- ByteBuffer getByteBuffer(long address, boolean modify) {
- return getBuffer(address / myPageSize, modify);
+ ByteBufferWrapper getByteBuffer(long address, boolean modify) {
+ return getBufferWrapper(address / myPageSize, modify);
}
public final short getShort(long addr) {
if (myValuesAreBufferAligned) {
long page = addr / myPageSize;
int page_offset = (int)(addr % myPageSize);
- return getBuffer(page, false).getShort(page_offset);
+ return getReadOnlyBuffer(page).getShort(page_offset);
} else {
get(addr, myTypedIOBuffer, 0, 2);
return Bits.getShort(myTypedIOBuffer, 0);
@@ -212,7 +212,7 @@ public class PagedFileStorage implements Forceable {
if (myValuesAreBufferAligned) {
long page = addr / myPageSize;
int page_offset = (int)(addr % myPageSize);
- return getBuffer(page, false).getLong(page_offset);
+ return getReadOnlyBuffer(page).getLong(page_offset);
} else {
get(addr, myTypedIOBuffer, 0, 8);
return Bits.getLong(myTypedIOBuffer, 0);
@@ -223,7 +223,7 @@ public class PagedFileStorage implements Forceable {
long page = index / myPageSize;
int offset = (int)(index % myPageSize);
- return getBuffer(page, false).get(offset);
+ return getReadOnlyBuffer(page).get(offset);
}
public void put(long index, byte value) {
@@ -243,7 +243,7 @@ public class PagedFileStorage implements Forceable {
int page_offset = (int) (i % myPageSize);
int page_len = Math.min(l, myPageSize - page_offset);
- final ByteBuffer buffer = getBuffer(page, false);
+ final ByteBuffer buffer = getReadOnlyBuffer(page);
try {
buffer.position(page_offset);
}
@@ -369,28 +369,32 @@ public class PagedFileStorage implements Forceable {
}
private ByteBuffer getBuffer(long page) {
- return getBuffer(page, true);
+ return getBufferWrapper(page, true).getCachedBuffer();
}
- private ByteBuffer getBuffer(long page, boolean modify) {
+ private ByteBuffer getReadOnlyBuffer(long page) {
+ return getBufferWrapper(page, false).getCachedBuffer();
+ }
+
+ private ByteBufferWrapper getBufferWrapper(long page, boolean modify) {
synchronized (myLastAccessedBufferCacheLock) {
if (myLastPage == page) {
ByteBuffer buf = myLastBuffer.getCachedBuffer();
if (buf != null && myLastChangeCount == myStorageLockContext.myStorageLock.myMappingChangeCount) {
if (modify) markDirty(myLastBuffer);
- return buf;
+ return myLastBuffer;
}
} else if (myLastPage2 == page) {
ByteBuffer buf = myLastBuffer2.getCachedBuffer();
if (buf != null && myLastChangeCount2 == myStorageLockContext.myStorageLock.myMappingChangeCount) {
if (modify) markDirty(myLastBuffer2);
- return buf;
+ return myLastBuffer2;
}
} else if (myLastPage3 == page) {
ByteBuffer buf = myLastBuffer3.getCachedBuffer();
if (buf != null && myLastChangeCount3 == myStorageLockContext.myStorageLock.myMappingChangeCount) {
if (modify) markDirty(myLastBuffer3);
- return buf;
+ return myLastBuffer3;
}
}
}
@@ -427,7 +431,7 @@ public class PagedFileStorage implements Forceable {
myLastChangeCount = myStorageLockContext.myStorageLock.myMappingChangeCount;
}
- return buf;
+ return byteBufferWrapper;
}
catch (IOException e) {
throw new MappingFailedException("Cannot map buffer", e);
diff --git a/platform/util/src/com/intellij/util/io/PersistentHashMap.java b/platform/util/src/com/intellij/util/io/PersistentHashMap.java
index de43fbd11b1b..dde187d804b5 100644
--- a/platform/util/src/com/intellij/util/io/PersistentHashMap.java
+++ b/platform/util/src/com/intellij/util/io/PersistentHashMap.java
@@ -80,7 +80,7 @@ public class PersistentHashMap<Key, Value> extends PersistentEnumeratorDelegate<
private final boolean myCanReEnumerate;
private int myLargeIndexWatermarkId; // starting with this id we store offset in adjacent file in long format
private boolean myIntAddressForNewRecord;
- private static final boolean doHardConsistencyChecks = true;
+ private static final boolean doHardConsistencyChecks = false;
private volatile boolean myBusyReading;
private static class AppendStream extends DataOutputStream {
diff --git a/platform/util/src/com/intellij/util/io/PersistentStringEnumerator.java b/platform/util/src/com/intellij/util/io/PersistentStringEnumerator.java
index 19755778f2ec..996798734253 100644
--- a/platform/util/src/com/intellij/util/io/PersistentStringEnumerator.java
+++ b/platform/util/src/com/intellij/util/io/PersistentStringEnumerator.java
@@ -15,22 +15,14 @@
*/
package com.intellij.util.io;
-import com.intellij.util.containers.SLRUMap;
-import jsr166e.extra.SequenceLock;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.io.IOException;
-import java.util.concurrent.locks.Lock;
public class PersistentStringEnumerator extends PersistentEnumeratorDelegate<String> implements AbstractStringEnumerator {
- private static final int STRIPE_POWER = 4;
- private static final int STRIPE_COUNT = 1 << STRIPE_POWER;
- private static final int STRIPE_MASK = STRIPE_COUNT - 1;
- @Nullable private final SLRUMap<Integer, Integer>[] myHashcodeToIdCache;
- @Nullable private final SLRUMap<Integer, String>[] myIdToStringCache;
- @Nullable private final Lock[] myStripeLocks;
+ @Nullable private final CachingEnumerator<String> myCache;
public PersistentStringEnumerator(@NotNull final File file) throws IOException {
this(file, null);
@@ -58,129 +50,36 @@ public class PersistentStringEnumerator extends PersistentEnumeratorDelegate<Str
final int initialSize,
boolean cacheLastMappings,
@Nullable PagedFileStorage.StorageLockContext lockContext) throws IOException {
- super(file, new EnumeratorStringDescriptor(), initialSize, lockContext);
- if (cacheLastMappings) {
- myIdToStringCache = new SLRUMap[STRIPE_COUNT];
- myHashcodeToIdCache = new SLRUMap[STRIPE_COUNT];
- myStripeLocks = new Lock[STRIPE_COUNT];
- int protectedSize = 8192;
- int probationalSize = 8192;
+ super(file, EnumeratorStringDescriptor.INSTANCE, initialSize, lockContext);
+ myCache = cacheLastMappings ? new CachingEnumerator<String>(new DataEnumerator<String>() {
+ @Override
+ public int enumerate(@Nullable String value) throws IOException {
+ return PersistentStringEnumerator.super.enumerate(value);
+ }
- for(int i = 0; i < STRIPE_COUNT; ++i) {
- myHashcodeToIdCache[i] = new SLRUMap<Integer, Integer>(protectedSize / STRIPE_COUNT, probationalSize / STRIPE_COUNT);
- myIdToStringCache[i] = new SLRUMap<Integer, String>(protectedSize / STRIPE_COUNT, probationalSize / STRIPE_COUNT);
- myStripeLocks[i] = new SequenceLock();
+ @Nullable
+ @Override
+ public String valueOf(int idx) throws IOException {
+ return PersistentStringEnumerator.super.valueOf(idx);
}
- } else {
- myIdToStringCache = null;
- myHashcodeToIdCache = null;
- myStripeLocks = null;
- }
+ }, EnumeratorStringDescriptor.INSTANCE) : null;
}
@Override
public int enumerate(@Nullable String value) throws IOException {
- int valueHashCode =-1;
- int stripe = -1;
-
- if (myHashcodeToIdCache != null && value != null) {
- valueHashCode = value.hashCode();
- stripe = Math.abs(valueHashCode) & STRIPE_MASK;
-
- Integer cachedId;
-
- myStripeLocks[stripe].lock();
- try {
- cachedId = myHashcodeToIdCache[stripe].get(valueHashCode);
- }
- finally {
- myStripeLocks[stripe].unlock();
- }
-
- if (cachedId != null) {
- int stripe2 = idStripe(cachedId.intValue());
- myStripeLocks[stripe2].lock();
- try {
- String s = myIdToStringCache[stripe2].get(cachedId);
- if (s != null && value.equals(s)) return cachedId.intValue();
- }
- finally {
- myStripeLocks[stripe2].unlock();
- }
- }
- }
-
- int enumerate = super.enumerate(value);
-
- if (stripe != -1) {
- Integer enumeratedInteger;
-
- myStripeLocks[stripe].lock();
- try {
- enumeratedInteger = enumerate;
- myHashcodeToIdCache[stripe].put(valueHashCode, enumeratedInteger);
- } finally {
- myStripeLocks[stripe].unlock();
- }
-
- int stripe2 = idStripe(enumerate);
- myStripeLocks[stripe2].lock();
- try {
- myIdToStringCache[stripe2].put(enumeratedInteger, value);
- } finally {
- myStripeLocks[stripe2].unlock();
- }
- }
-
- return enumerate;
- }
-
- private int idStripe(int h) {
- h ^= (h >>> 20) ^ (h >>> 12);
- return Math.abs(h ^ (h >>> 7) ^ (h >>> 4)) & STRIPE_MASK;
+ return myCache != null ? myCache.enumerate(value) : super.enumerate(value);
}
@Nullable
@Override
public String valueOf(int idx) throws IOException {
- int stripe = -1;
- if (myIdToStringCache != null) {
- stripe = idStripe(idx);
- myStripeLocks[stripe].lock();
- try {
- String s = myIdToStringCache[stripe].get(idx);
- if (s != null) return s;
- }
- finally {
- myStripeLocks[stripe].unlock();
- }
- }
- String s = super.valueOf(idx);
-
- if (stripe != -1 && s != null) {
- myStripeLocks[stripe].lock();
- try {
- myIdToStringCache[stripe].put(idx, s);
- }
- finally {
- myStripeLocks[stripe].unlock();
- }
- }
- return s;
+ return myCache != null ? myCache.valueOf(idx) : super.valueOf(idx);
}
@Override
public void close() throws IOException {
super.close();
-
- if (myIdToStringCache != null) {
- for(int i = 0; i < myIdToStringCache.length; ++i) {
- myStripeLocks[i].lock();
- myIdToStringCache[i].clear();
- myHashcodeToIdCache[i].clear();
- myStripeLocks[i].unlock();
- }
- }
+ if (myCache != null) myCache.close();
}
@Override