mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-10-01 19:02:13 +07:00
IOException from get / put / append sets corrupted state for
PersistentHashMap (IDEA-173669)
This commit is contained in:
@@ -20,7 +20,10 @@ import com.intellij.testFramework.PlatformTestUtil;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import com.intellij.util.containers.IntObjectCache;
|
||||
import com.intellij.util.io.storage.AbstractStorage;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
@@ -344,4 +347,92 @@ public class PersistentMapTest extends PersistentMapTestBase {
|
||||
fail();
|
||||
} catch (IncorrectOperationException ignore) {}
|
||||
}
|
||||
|
||||
public void testFailedReadWriteSetsCorruptedFlag() throws IOException {
|
||||
EnumeratorStringDescriptor throwingException = new EnumeratorStringDescriptor() {
|
||||
@Override
|
||||
public void save(@NotNull DataOutput storage, @NotNull String value) throws IOException {
|
||||
throw new IOException("test");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String read(@NotNull DataInput storage) throws IOException {
|
||||
throw new IOException("test");
|
||||
}
|
||||
};
|
||||
|
||||
PersistentMapPerformanceTest.MapConstructor<String, String> mapConstructorWithBrokenKeyDescriptor =
|
||||
(file) -> IOUtil.openCleanOrResetBroken(
|
||||
() -> new PersistentHashMap<>(file, throwingException, EnumeratorStringDescriptor.INSTANCE), file);
|
||||
|
||||
PersistentMapPerformanceTest.MapConstructor<String, String> mapConstructorWithBrokenValueDescriptor =
|
||||
(file) -> IOUtil.openCleanOrResetBroken(
|
||||
() -> new PersistentHashMap<>(file, EnumeratorStringDescriptor.INSTANCE, throwingException), file);
|
||||
|
||||
runIteration(mapConstructorWithBrokenKeyDescriptor);
|
||||
runIteration(mapConstructorWithBrokenValueDescriptor);
|
||||
}
|
||||
|
||||
private void runIteration(PersistentMapPerformanceTest.MapConstructor<String, String> brokenMapDescritor) throws IOException {
|
||||
String key = "AAA";
|
||||
String value = "AAA_VALUE";
|
||||
|
||||
PersistentMapPerformanceTest.MapConstructor<String, String> defaultMapConstructor =
|
||||
(file) -> IOUtil.openCleanOrResetBroken(
|
||||
() -> new PersistentHashMap<>(file, EnumeratorStringDescriptor.INSTANCE, EnumeratorStringDescriptor.INSTANCE), file);
|
||||
|
||||
createInitializedMap(key, value, defaultMapConstructor);
|
||||
|
||||
myMap = brokenMapDescritor.createMap(myFile);
|
||||
|
||||
try {
|
||||
myMap.get(key);
|
||||
fail();
|
||||
} catch (IOException ignore) {
|
||||
assertTrue(myMap.isCorrupted());
|
||||
}
|
||||
|
||||
createInitializedMap(key, value, defaultMapConstructor);
|
||||
|
||||
myMap = brokenMapDescritor.createMap(myFile);
|
||||
|
||||
try {
|
||||
myMap.put(key, value + value);
|
||||
fail();
|
||||
} catch (IOException ignore) {
|
||||
assertTrue(myMap.isCorrupted());
|
||||
}
|
||||
|
||||
createInitializedMap(key, value, defaultMapConstructor);
|
||||
|
||||
myMap = brokenMapDescritor.createMap(myFile);
|
||||
|
||||
try {
|
||||
myMap.appendData(key, new PersistentHashMap.ValueDataAppender() {
|
||||
@Override
|
||||
public void append(DataOutput out) throws IOException {
|
||||
throw new IOException();
|
||||
}
|
||||
});
|
||||
fail();
|
||||
} catch (IOException ignore) {
|
||||
assertTrue(myMap.isCorrupted());
|
||||
}
|
||||
}
|
||||
|
||||
private void closeMapSilently() throws IOException {
|
||||
try {
|
||||
myMap.close();
|
||||
} catch (IOException ignore) {}
|
||||
}
|
||||
|
||||
private void createInitializedMap(String key,
|
||||
String value,
|
||||
PersistentMapPerformanceTest.MapConstructor<String, String> defaultMapConstructor)
|
||||
throws IOException {
|
||||
closeMapSilently();
|
||||
myMap = defaultMapConstructor.createMap(myFile);
|
||||
myMap.put(key, value);
|
||||
closeMapSilently();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,8 +129,21 @@ public class PersistentHashMap<Key, Value> extends PersistentEnumeratorDelegate<
|
||||
this(file, keyDescriptor, valueExternalizer, initialSize, 0);
|
||||
}
|
||||
|
||||
public PersistentHashMap(@NotNull final File file, @NotNull KeyDescriptor<Key> keyDescriptor, @NotNull DataExternalizer<Value> valueExternalizer, final int initialSize, int version) throws IOException {
|
||||
super(checkDataFiles(file), keyDescriptor, initialSize, null, version);
|
||||
public PersistentHashMap(@NotNull final File file,
|
||||
@NotNull KeyDescriptor<Key> keyDescriptor,
|
||||
@NotNull DataExternalizer<Value> valueExternalizer,
|
||||
final int initialSize,
|
||||
int version) throws IOException {
|
||||
this(file, keyDescriptor, valueExternalizer, initialSize, version, null);
|
||||
}
|
||||
|
||||
public PersistentHashMap(@NotNull final File file,
|
||||
@NotNull KeyDescriptor<Key> keyDescriptor,
|
||||
@NotNull DataExternalizer<Value> valueExternalizer,
|
||||
final int initialSize,
|
||||
int version,
|
||||
@Nullable PagedFileStorage.StorageLockContext lockContext) throws IOException {
|
||||
super(checkDataFiles(file), keyDescriptor, initialSize, lockContext, version);
|
||||
|
||||
myStorageFile = file;
|
||||
myKeyDescriptor = keyDescriptor;
|
||||
@@ -255,6 +268,7 @@ public class PersistentHashMap<Key, Value> extends PersistentEnumeratorDelegate<
|
||||
myStreamPool.recycle(bytes);
|
||||
}
|
||||
catch (IOException e) {
|
||||
markCorrupted();
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
finally {
|
||||
@@ -344,7 +358,12 @@ public class PersistentHashMap<Key, Value> extends PersistentEnumeratorDelegate<
|
||||
public final void put(Key key, Value value) throws IOException {
|
||||
if (myIsReadOnly) throw new IncorrectOperationException();
|
||||
synchronized (myEnumerator) {
|
||||
doPut(key, value);
|
||||
try {
|
||||
doPut(key, value);
|
||||
} catch (IOException ex) {
|
||||
myEnumerator.markCorrupted();
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -420,7 +439,12 @@ public class PersistentHashMap<Key, Value> extends PersistentEnumeratorDelegate<
|
||||
public final void appendData(Key key, @NotNull ValueDataAppender appender) throws IOException {
|
||||
if (myIsReadOnly) throw new IncorrectOperationException();
|
||||
synchronized (myEnumerator) {
|
||||
doAppendData(key, appender);
|
||||
try {
|
||||
doAppendData(key, appender);
|
||||
} catch (IOException ex) {
|
||||
myEnumerator.markCorrupted();
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -449,8 +473,14 @@ public class PersistentHashMap<Key, Value> extends PersistentEnumeratorDelegate<
|
||||
@Override
|
||||
public final boolean processKeys(Processor<Key> processor) throws IOException {
|
||||
synchronized (myEnumerator) {
|
||||
myAppendCache.clear();
|
||||
return myEnumerator.iterateData(processor);
|
||||
try {
|
||||
myAppendCache.clear();
|
||||
return myEnumerator.iterateData(processor);
|
||||
}
|
||||
catch (IOException e) {
|
||||
myEnumerator.markCorrupted();
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -463,13 +493,19 @@ public class PersistentHashMap<Key, Value> extends PersistentEnumeratorDelegate<
|
||||
|
||||
public final boolean processKeysWithExistingMapping(Processor<Key> processor) throws IOException {
|
||||
synchronized (myEnumerator) {
|
||||
myAppendCache.clear();
|
||||
return myEnumerator.processAllDataObject(processor, new PersistentEnumerator.DataFilter() {
|
||||
@Override
|
||||
public boolean accept(final int id) {
|
||||
return readValueId(id) != NULL_ADDR;
|
||||
}
|
||||
});
|
||||
try {
|
||||
myAppendCache.clear();
|
||||
return myEnumerator.processAllDataObject(processor, new PersistentEnumerator.DataFilter() {
|
||||
@Override
|
||||
public boolean accept(final int id) {
|
||||
return readValueId(id) != NULL_ADDR;
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (IOException e) {
|
||||
myEnumerator.markCorrupted();
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -479,6 +515,9 @@ public class PersistentHashMap<Key, Value> extends PersistentEnumeratorDelegate<
|
||||
myBusyReading = true;
|
||||
try {
|
||||
return doGet(key);
|
||||
} catch(IOException ex) {
|
||||
myEnumerator.markCorrupted();
|
||||
throw ex;
|
||||
} finally {
|
||||
myBusyReading = false;
|
||||
}
|
||||
@@ -669,7 +708,13 @@ public class PersistentHashMap<Key, Value> extends PersistentEnumeratorDelegate<
|
||||
try {
|
||||
try {
|
||||
myAppendCacheFlusher.stop();
|
||||
myAppendCache.clear();
|
||||
try {
|
||||
myAppendCache.clear();
|
||||
} catch (RuntimeException ex) {
|
||||
Throwable cause = ex.getCause();
|
||||
if (cause instanceof IOException) throw (IOException)cause;
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
finally {
|
||||
final PersistentHashMapValueStorage valueStorage = myValueStorage;
|
||||
|
||||
Reference in New Issue
Block a user