Store exception caught during computation as a result and rethrow it

This commit is contained in:
Nikolay Krasko
2013-08-07 14:14:08 +04:00
parent ca675290a8
commit 8d06a72157
4 changed files with 66 additions and 21 deletions
@@ -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;
@@ -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);
}
} }