diff --git a/platform/util/src/com/intellij/util/io/PersistentHashMap.java b/platform/util/src/com/intellij/util/io/PersistentHashMap.java index 27d826e91f63..9b72914b65ed 100644 --- a/platform/util/src/com/intellij/util/io/PersistentHashMap.java +++ b/platform/util/src/com/intellij/util/io/PersistentHashMap.java @@ -764,7 +764,8 @@ public class PersistentHashMap extends PersistentEnumeratorDelegate< final File[] oldFiles = getFilesInDirectoryWithNameStartingWith(oldDataFile, oldDataFileBaseName); final String newPath = getDataFile(myEnumerator.myFile).getPath() + ".new"; - final PersistentHashMapValueStorage newStorage = PersistentHashMapValueStorage.create(newPath, myIsReadOnly); + PersistentHashMapValueStorage.CreationTimeOptions options = myValueStorage.getOptions(); + final PersistentHashMapValueStorage newStorage = PersistentHashMapValueStorage.create(newPath, options); myValueStorage.switchToCompactionMode(); myEnumerator.markDirty(true); long sizeBefore = myValueStorage.getSize(); @@ -819,7 +820,7 @@ public class PersistentHashMap extends PersistentEnumeratorDelegate< } } - myValueStorage = PersistentHashMapValueStorage.create(oldDataFile.getPath(), myIsReadOnly); + myValueStorage = PersistentHashMapValueStorage.create(oldDataFile.getPath(), options); LOG.info("Compacted " + myEnumerator.myFile.getPath() + ":" + sizeBefore + " bytes into " + newSize + " bytes in " + (System.currentTimeMillis() - now) + "ms."); myEnumerator.putMetaData(myLiveAndGarbageKeysCounter); myEnumerator.putMetaData2( myLargeIndexWatermarkId ); diff --git a/platform/util/src/com/intellij/util/io/PersistentHashMapValueStorage.java b/platform/util/src/com/intellij/util/io/PersistentHashMapValueStorage.java index 235b4174ad8a..71849c626bbc 100644 --- a/platform/util/src/com/intellij/util/io/PersistentHashMapValueStorage.java +++ b/platform/util/src/com/intellij/util/io/PersistentHashMapValueStorage.java @@ -41,9 +41,9 @@ public class PersistentHashMapValueStorage { private volatile long mySize; private final File myFile; private final String myPath; - private final boolean myReadOnly; - private final boolean myCompactChunksWithValueDeserialization; - private final ExceptionalIOCancellationCallback myExceptionalIOCancellationCallback; + + private final CreationTimeOptions myOptions; + private boolean myCompactionMode = false; private static final int CACHE_PROTECTED_QUEUE_SIZE = 10; @@ -53,19 +53,47 @@ public class PersistentHashMapValueStorage { public static final ThreadLocal EXCEPTIONAL_IO_CANCELLATION = new ThreadLocal(); public static final ThreadLocal READONLY = new ThreadLocal(); public static final ThreadLocal COMPACT_CHUNKS_WITH_VALUE_DESERIALIZATION = new ThreadLocal(); - + public static final ThreadLocal DO_COMPRESSION = new ThreadLocal() { @Override protected Boolean initialValue() { - return COMPRESSION_ENABLED; + return Boolean.valueOf(COMPRESSION_ENABLED); } }; - } + private final ExceptionalIOCancellationCallback myExceptionalIOCancellationCallback; + private final boolean myReadOnly; + private final boolean myCompactChunksWithValueDeserialization; + private final boolean myDoCompression; + + private CreationTimeOptions(ExceptionalIOCancellationCallback callback, + boolean readOnly, + boolean compactChunksWithValueDeserialization, + boolean doCompression) { + myExceptionalIOCancellationCallback = callback; + myReadOnly = readOnly; + myCompactChunksWithValueDeserialization = compactChunksWithValueDeserialization; + myDoCompression = doCompression; + } + + static CreationTimeOptions threadLocalOptions() { + return new CreationTimeOptions( + EXCEPTIONAL_IO_CANCELLATION.get(), + READONLY.get() == Boolean.TRUE, + COMPACT_CHUNKS_WITH_VALUE_DESERIALIZATION.get() == Boolean.TRUE, + DO_COMPRESSION.get() == Boolean.TRUE); + } + + } + public interface ExceptionalIOCancellationCallback { void checkCancellation(); } + CreationTimeOptions getOptions() { + return myOptions; + } + // cache size is twice larger than constants because (when used) it replaces two caches private static final FileAccessorCache ourRandomAccessFileCache = new FileAccessorCache( 2*CACHE_PROTECTED_QUEUE_SIZE, 2*CACHE_PROBATIONAL_QUEUE_SIZE) { @@ -112,21 +140,23 @@ public class PersistentHashMapValueStorage { public static final boolean COMPRESSION_ENABLED = SystemProperties.getBooleanProperty("idea.compression.enabled", true); - public PersistentHashMapValueStorage(String path) throws IOException { - myExceptionalIOCancellationCallback = CreationTimeOptions.EXCEPTIONAL_IO_CANCELLATION.get(); - myReadOnly = CreationTimeOptions.READONLY.get() == Boolean.TRUE; - myCompactChunksWithValueDeserialization = CreationTimeOptions.COMPACT_CHUNKS_WITH_VALUE_DESERIALIZATION.get() == Boolean.TRUE; + PersistentHashMapValueStorage(String path) throws IOException { + this(path, CreationTimeOptions.threadLocalOptions()); + } + + PersistentHashMapValueStorage(String path, CreationTimeOptions options) throws IOException { myPath = path; myFile = new File(path); + myOptions = options; - myCompressedAppendableFile = CreationTimeOptions.DO_COMPRESSION.get() != Boolean.FALSE ? new MyCompressedAppendableFile() : null; + myCompressedAppendableFile = myOptions.myDoCompression ? new MyCompressedAppendableFile() : null; if (myCompressedAppendableFile != null) { mySize = myCompressedAppendableFile.length(); // volatile write } else { mySize = myFile.length(); // volatile write } - if (mySize == 0 && !myReadOnly) { + if (mySize == 0 && !myOptions.myReadOnly) { appendBytes(new ByteSequence("Header Record For PersistentHashMapValueStorage".getBytes()), 0); // avoid corruption issue when disk fails to write first record synchronously or unexpected first write file increase (IDEA-106306), @@ -146,7 +176,7 @@ public class PersistentHashMapValueStorage { long currentLength = myFile.length(); if (currentLength > mySize) { // if real file length (unexpectedly) increases - Logger.getInstance(getClass().getName()).info("Avoided PSHM corruption due to write failure"); + Logger.getInstance(getClass().getName()).info("Avoided PSHM corruption due to write failure:" + myPath); mySize = currentLength; // volatile write } } @@ -460,7 +490,7 @@ public class PersistentHashMapValueStorage { } private boolean allowedToCompactChunks() { - return !myCompactionMode && !myReadOnly; + return !myCompactionMode && !myOptions.myReadOnly; } boolean performChunksCompaction(int chunksCount, int chunksBytesSize) { @@ -472,7 +502,7 @@ public class PersistentHashMapValueStorage { long startedTime = ourDumpChunkRemovalTime ? System.nanoTime() : 0; long newValueOffset; - if (myCompactChunksWithValueDeserialization) { + if (myOptions.myCompactChunksWithValueDeserialization) { final BufferExposingByteArrayOutputStream stream = new BufferExposingByteArrayOutputStream(result.buffer.length); DataOutputStream testStream = new DataOutputStream(stream); appender.append(testStream); @@ -503,7 +533,7 @@ public class PersistentHashMapValueStorage { // hook for exceptional termination of long io operation protected void checkCancellation() { - if (myExceptionalIOCancellationCallback != null) myExceptionalIOCancellationCallback.checkCancellation(); + if (myOptions.myExceptionalIOCancellationCallback != null) myOptions.myExceptionalIOCancellationCallback.checkCancellation(); } private long readPrevChunkAddress(long chunk) throws IOException { @@ -539,7 +569,7 @@ public class PersistentHashMapValueStorage { } public void force() { - if (myReadOnly) return; + if (myOptions.myReadOnly) return; if (myCompressedAppendableFile != null) { myCompressedAppendableFile.force(); } @@ -613,6 +643,10 @@ public class PersistentHashMapValueStorage { } } + public static PersistentHashMapValueStorage create(final String path, CreationTimeOptions options) throws IOException { + return new PersistentHashMapValueStorage(path, options); + } + private interface RAReader { void get(long addr, byte[] dst, int off, int len) throws IOException; void dispose(); @@ -766,6 +800,6 @@ public class PersistentHashMapValueStorage { @TestOnly public boolean isReadOnly() { - return myReadOnly; + return myOptions.myReadOnly; } }