Store exception caught during computation as a result and rethrow it
This commit is contained in:
+27
-15
@@ -29,7 +29,8 @@ import org.jetbrains.jet.lang.resolve.BindingContext;
|
|||||||
import org.jetbrains.jet.lang.resolve.BindingTrace;
|
import org.jetbrains.jet.lang.resolve.BindingTrace;
|
||||||
import org.jetbrains.jet.util.slicedmap.ReadOnlySlice;
|
import org.jetbrains.jet.util.slicedmap.ReadOnlySlice;
|
||||||
import org.jetbrains.jet.util.slicedmap.WritableSlice;
|
import org.jetbrains.jet.util.slicedmap.WritableSlice;
|
||||||
import org.jetbrains.jet.utils.Nulls;
|
import org.jetbrains.jet.utils.ExceptionUtils;
|
||||||
|
import org.jetbrains.jet.utils.WrappedValues;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
@@ -132,18 +133,22 @@ public class LockBasedStorageManager implements StorageManager {
|
|||||||
@Override
|
@Override
|
||||||
public T compute() {
|
public T compute() {
|
||||||
Object _value = value;
|
Object _value = value;
|
||||||
if (_value != null) return Nulls.unescape(_value);
|
if (_value != null) return WrappedValues.unescapeExceptionOrNull(_value);
|
||||||
|
|
||||||
synchronized (lock) {
|
synchronized (lock) {
|
||||||
_value = value;
|
_value = value;
|
||||||
if (_value != null) return Nulls.unescape(_value);
|
if (_value != null) return WrappedValues.unescapeExceptionOrNull(_value);
|
||||||
|
|
||||||
T typedValue = computable.compute();
|
try {
|
||||||
value = Nulls.escape(typedValue);
|
T typedValue = computable.compute();
|
||||||
|
value = WrappedValues.escapeNull(typedValue);
|
||||||
postCompute(typedValue);
|
postCompute(typedValue);
|
||||||
|
return typedValue;
|
||||||
return typedValue;
|
}
|
||||||
|
catch (Throwable throwable) {
|
||||||
|
value = WrappedValues.escapeThrowable(throwable);
|
||||||
|
throw ExceptionUtils.rethrow(throwable);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -182,18 +187,25 @@ public class LockBasedStorageManager implements StorageManager {
|
|||||||
@Nullable
|
@Nullable
|
||||||
public V fun(@NotNull K input) {
|
public V fun(@NotNull K input) {
|
||||||
Object value = cache.get(input);
|
Object value = cache.get(input);
|
||||||
if (value != null) return Nulls.unescape(value);
|
if (value != null) return WrappedValues.unescapeExceptionOrNull(value);
|
||||||
|
|
||||||
synchronized (lock) {
|
synchronized (lock) {
|
||||||
value = cache.get(input);
|
value = cache.get(input);
|
||||||
if (value != null) return Nulls.unescape(value);
|
if (value != null) return WrappedValues.unescapeExceptionOrNull(value);
|
||||||
|
|
||||||
V typedValue = compute.fun(input);
|
try {
|
||||||
|
V typedValue = compute.fun(input);
|
||||||
|
Object oldValue = cache.put(input, WrappedValues.escapeNull(typedValue));
|
||||||
|
assert oldValue == null : "Race condition detected";
|
||||||
|
|
||||||
Object oldValue = cache.put(input, Nulls.escape(typedValue));
|
return typedValue;
|
||||||
assert oldValue == null : "Race condition detected";
|
}
|
||||||
|
catch (Throwable throwable) {
|
||||||
|
Object oldValue = cache.put(input, WrappedValues.escapeThrowable(throwable));
|
||||||
|
assert oldValue == null : "Race condition detected";
|
||||||
|
|
||||||
return typedValue;
|
throw ExceptionUtils.rethrow(throwable);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,9 @@ import java.io.Closeable;
|
|||||||
|
|
||||||
public class ExceptionUtils {
|
public class ExceptionUtils {
|
||||||
|
|
||||||
|
private ExceptionUtils() {
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Translate exception to unchecked exception.
|
* Translate exception to unchecked exception.
|
||||||
*
|
*
|
||||||
@@ -43,7 +46,7 @@ public class ExceptionUtils {
|
|||||||
if (closeable != null) {
|
if (closeable != null) {
|
||||||
try {
|
try {
|
||||||
closeable.close();
|
closeable.close();
|
||||||
} catch (Throwable e) {
|
} catch (Throwable ignored) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,11 +50,11 @@ public abstract class NullableMemoizedFunction<K, V> implements NullableFunction
|
|||||||
@Nullable
|
@Nullable
|
||||||
public V fun(@NotNull K input) {
|
public V fun(@NotNull K input) {
|
||||||
Object value = cache.get(input);
|
Object value = cache.get(input);
|
||||||
if (value != null) return Nulls.unescape(value);
|
if (value != null) return WrappedValues.unescapeNull(value);
|
||||||
|
|
||||||
V typedValue = compute(input);
|
V typedValue = compute(input);
|
||||||
|
|
||||||
Object oldValue = cache.put(input, Nulls.escape(typedValue));
|
Object oldValue = cache.put(input, WrappedValues.escapeNull(typedValue));
|
||||||
assert oldValue == null : "Race condition detected";
|
assert oldValue == null : "Race condition detected";
|
||||||
|
|
||||||
return typedValue;
|
return typedValue;
|
||||||
|
|||||||
+33
-3
@@ -19,19 +19,49 @@ package org.jetbrains.jet.utils;
|
|||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
public class Nulls {
|
public class WrappedValues {
|
||||||
private static final Object NULL_VALUE = new Object();
|
private static final Object NULL_VALUE = new Object();
|
||||||
|
|
||||||
|
private final static class ThrowableWrapper {
|
||||||
|
private final Throwable throwable;
|
||||||
|
|
||||||
|
private ThrowableWrapper(@NotNull Throwable throwable) {
|
||||||
|
this.throwable = throwable;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public Throwable getThrowable() {
|
||||||
|
return throwable;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private WrappedValues() {
|
||||||
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public static <V> V unescape(@NotNull Object value) {
|
public static <V> V unescapeNull(@NotNull Object value) {
|
||||||
if (value == NULL_VALUE) return null;
|
if (value == NULL_VALUE) return null;
|
||||||
return (V) value;
|
return (V) value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public static <V> Object escape(@Nullable V value) {
|
public static <V> Object escapeNull(@Nullable V value) {
|
||||||
if (value == null) return NULL_VALUE;
|
if (value == null) return NULL_VALUE;
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public static Object escapeThrowable(@NotNull Throwable throwable) {
|
||||||
|
return new ThrowableWrapper(throwable);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public static <V> V unescapeExceptionOrNull(@NotNull Object value) {
|
||||||
|
if (value instanceof ThrowableWrapper) {
|
||||||
|
throw ExceptionUtils.rethrow(((ThrowableWrapper) value).getThrowable());
|
||||||
|
}
|
||||||
|
|
||||||
|
return unescapeNull(value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user