提交 74fcad13 编写于 作者: S Sam Judd

Avoid blocking Futures forever on unexpected load failures.

上级 d447e582
...@@ -50,10 +50,10 @@ public class Registry { ...@@ -50,10 +50,10 @@ public class Registry {
private final ModelToResourceClassCache modelToResourceClassCache = private final ModelToResourceClassCache modelToResourceClassCache =
new ModelToResourceClassCache(); new ModelToResourceClassCache();
private final LoadPathCache loadPathCache = new LoadPathCache(); private final LoadPathCache loadPathCache = new LoadPathCache();
private final Pool<List<Exception>> exceptionListPool = FactoryPools.threadSafeList(); private final Pool<List<Throwable>> throwableListPool = FactoryPools.threadSafeList();
public Registry() { public Registry() {
this.modelLoaderRegistry = new ModelLoaderRegistry(exceptionListPool); this.modelLoaderRegistry = new ModelLoaderRegistry(throwableListPool);
this.encoderRegistry = new EncoderRegistry(); this.encoderRegistry = new EncoderRegistry();
this.decoderRegistry = new ResourceDecoderRegistry(); this.decoderRegistry = new ResourceDecoderRegistry();
this.resourceEncoderRegistry = new ResourceEncoderRegistry(); this.resourceEncoderRegistry = new ResourceEncoderRegistry();
...@@ -454,8 +454,9 @@ public class Registry { ...@@ -454,8 +454,9 @@ public class Registry {
if (decodePaths.isEmpty()) { if (decodePaths.isEmpty()) {
result = null; result = null;
} else { } else {
result = new LoadPath<>(dataClass, resourceClass, transcodeClass, decodePaths, result =
exceptionListPool); new LoadPath<>(
dataClass, resourceClass, transcodeClass, decodePaths, throwableListPool);
} }
loadPathCache.put(dataClass, resourceClass, transcodeClass, result); loadPathCache.put(dataClass, resourceClass, transcodeClass, result);
} }
...@@ -480,7 +481,7 @@ public class Registry { ...@@ -480,7 +481,7 @@ public class Registry {
ResourceTranscoder<TResource, Transcode> transcoder = ResourceTranscoder<TResource, Transcode> transcoder =
transcoderRegistry.get(registeredResourceClass, registeredTranscodeClass); transcoderRegistry.get(registeredResourceClass, registeredTranscodeClass);
decodePaths.add(new DecodePath<>(dataClass, registeredResourceClass, decodePaths.add(new DecodePath<>(dataClass, registeredResourceClass,
registeredTranscodeClass, decoders, transcoder, exceptionListPool)); registeredTranscodeClass, decoders, transcoder, throwableListPool));
} }
} }
return decodePaths; return decodePaths;
......
...@@ -41,7 +41,7 @@ class DecodeJob<R> implements DataFetcherGenerator.FetcherReadyCallback, ...@@ -41,7 +41,7 @@ class DecodeJob<R> implements DataFetcherGenerator.FetcherReadyCallback,
private static final String TAG = "DecodeJob"; private static final String TAG = "DecodeJob";
@Synthetic final DecodeHelper<R> decodeHelper = new DecodeHelper<>(); @Synthetic final DecodeHelper<R> decodeHelper = new DecodeHelper<>();
private final List<Exception> exceptions = new ArrayList<>(); private final List<Throwable> throwables = new ArrayList<>();
private final StateVerifier stateVerifier = StateVerifier.newInstance(); private final StateVerifier stateVerifier = StateVerifier.newInstance();
private final DiskCacheProvider diskCacheProvider; private final DiskCacheProvider diskCacheProvider;
private final Pools.Pool<DecodeJob<?>> pool; private final Pools.Pool<DecodeJob<?>> pool;
...@@ -187,7 +187,7 @@ class DecodeJob<R> implements DataFetcherGenerator.FetcherReadyCallback, ...@@ -187,7 +187,7 @@ class DecodeJob<R> implements DataFetcherGenerator.FetcherReadyCallback,
currentFetcher = null; currentFetcher = null;
startFetchTime = 0L; startFetchTime = 0L;
isCancelled = false; isCancelled = false;
exceptions.clear(); throwables.clear();
pool.release(this); pool.release(this);
} }
...@@ -227,19 +227,25 @@ class DecodeJob<R> implements DataFetcherGenerator.FetcherReadyCallback, ...@@ -227,19 +227,25 @@ class DecodeJob<R> implements DataFetcherGenerator.FetcherReadyCallback,
return; return;
} }
runWrapped(); runWrapped();
} catch (RuntimeException e) { } catch (Throwable t) {
// Catch Throwable and not Exception to handle OOMs. Throwables are swallowed by our
// usage of .submit() in GlideExecutor so we're not silently hiding crashes by doing this. We
// are however ensuring that our callbacks are always notified when a load fails. Without this
// notification, uncaught throwables never notify the corresponding callbacks, which can cause
// loads to silently hang forever, a case that's especially bad for users using Futures on
// background threads.
if (Log.isLoggable(TAG, Log.DEBUG)) { if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "DecodeJob threw unexpectedly" Log.d(TAG, "DecodeJob threw unexpectedly"
+ ", isCancelled: " + isCancelled + ", isCancelled: " + isCancelled
+ ", stage: " + stage, e); + ", stage: " + stage, t);
} }
// When we're encoding we've already notified our callback and it isn't safe to do so again. // When we're encoding we've already notified our callback and it isn't safe to do so again.
if (stage != Stage.ENCODE) { if (stage != Stage.ENCODE) {
exceptions.add(e); throwables.add(t);
notifyFailed(); notifyFailed();
} }
if (!isCancelled) { if (!isCancelled) {
throw e; throw t;
} }
} finally { } finally {
// Keeping track of the fetcher here and calling cleanup is excessively paranoid, we call // Keeping track of the fetcher here and calling cleanup is excessively paranoid, we call
...@@ -309,7 +315,7 @@ class DecodeJob<R> implements DataFetcherGenerator.FetcherReadyCallback, ...@@ -309,7 +315,7 @@ class DecodeJob<R> implements DataFetcherGenerator.FetcherReadyCallback,
private void notifyFailed() { private void notifyFailed() {
setNotifiedOrThrow(); setNotifiedOrThrow();
GlideException e = new GlideException("Failed to load resource", new ArrayList<>(exceptions)); GlideException e = new GlideException("Failed to load resource", new ArrayList<>(throwables));
callback.onLoadFailed(e); callback.onLoadFailed(e);
onLoadFailed(); onLoadFailed();
} }
...@@ -379,7 +385,7 @@ class DecodeJob<R> implements DataFetcherGenerator.FetcherReadyCallback, ...@@ -379,7 +385,7 @@ class DecodeJob<R> implements DataFetcherGenerator.FetcherReadyCallback,
fetcher.cleanup(); fetcher.cleanup();
GlideException exception = new GlideException("Fetching data failed", e); GlideException exception = new GlideException("Fetching data failed", e);
exception.setLoggingDetails(attemptedKey, dataSource, fetcher.getDataClass()); exception.setLoggingDetails(attemptedKey, dataSource, fetcher.getDataClass());
exceptions.add(exception); throwables.add(exception);
if (Thread.currentThread() != currentThread) { if (Thread.currentThread() != currentThread) {
runReason = RunReason.SWITCH_TO_SOURCE_SERVICE; runReason = RunReason.SWITCH_TO_SOURCE_SERVICE;
callback.reschedule(this); callback.reschedule(this);
...@@ -400,7 +406,7 @@ class DecodeJob<R> implements DataFetcherGenerator.FetcherReadyCallback, ...@@ -400,7 +406,7 @@ class DecodeJob<R> implements DataFetcherGenerator.FetcherReadyCallback,
resource = decodeFromData(currentFetcher, currentData, currentDataSource); resource = decodeFromData(currentFetcher, currentData, currentDataSource);
} catch (GlideException e) { } catch (GlideException e) {
e.setLoggingDetails(currentAttemptingKey, currentDataSource); e.setLoggingDetails(currentAttemptingKey, currentDataSource);
exceptions.add(e); throwables.add(e);
} }
if (resource != null) { if (resource != null) {
notifyEncodeAndRelease(resource, currentDataSource); notifyEncodeAndRelease(resource, currentDataSource);
......
...@@ -23,13 +23,13 @@ public class DecodePath<DataType, ResourceType, Transcode> { ...@@ -23,13 +23,13 @@ public class DecodePath<DataType, ResourceType, Transcode> {
private final Class<DataType> dataClass; private final Class<DataType> dataClass;
private final List<? extends ResourceDecoder<DataType, ResourceType>> decoders; private final List<? extends ResourceDecoder<DataType, ResourceType>> decoders;
private final ResourceTranscoder<ResourceType, Transcode> transcoder; private final ResourceTranscoder<ResourceType, Transcode> transcoder;
private final Pool<List<Exception>> listPool; private final Pool<List<Throwable>> listPool;
private final String failureMessage; private final String failureMessage;
public DecodePath(Class<DataType> dataClass, Class<ResourceType> resourceClass, public DecodePath(Class<DataType> dataClass, Class<ResourceType> resourceClass,
Class<Transcode> transcodeClass, Class<Transcode> transcodeClass,
List<? extends ResourceDecoder<DataType, ResourceType>> decoders, List<? extends ResourceDecoder<DataType, ResourceType>> decoders,
ResourceTranscoder<ResourceType, Transcode> transcoder, Pool<List<Exception>> listPool) { ResourceTranscoder<ResourceType, Transcode> transcoder, Pool<List<Throwable>> listPool) {
this.dataClass = dataClass; this.dataClass = dataClass;
this.decoders = decoders; this.decoders = decoders;
this.transcoder = transcoder; this.transcoder = transcoder;
...@@ -47,7 +47,7 @@ public class DecodePath<DataType, ResourceType, Transcode> { ...@@ -47,7 +47,7 @@ public class DecodePath<DataType, ResourceType, Transcode> {
private Resource<ResourceType> decodeResource(DataRewinder<DataType> rewinder, int width, private Resource<ResourceType> decodeResource(DataRewinder<DataType> rewinder, int width,
int height, Options options) throws GlideException { int height, Options options) throws GlideException {
List<Exception> exceptions = listPool.acquire(); List<Throwable> exceptions = listPool.acquire();
try { try {
return decodeResourceWithList(rewinder, width, height, options, exceptions); return decodeResourceWithList(rewinder, width, height, options, exceptions);
} finally { } finally {
...@@ -56,7 +56,7 @@ public class DecodePath<DataType, ResourceType, Transcode> { ...@@ -56,7 +56,7 @@ public class DecodePath<DataType, ResourceType, Transcode> {
} }
private Resource<ResourceType> decodeResourceWithList(DataRewinder<DataType> rewinder, int width, private Resource<ResourceType> decodeResourceWithList(DataRewinder<DataType> rewinder, int width,
int height, Options options, List<Exception> exceptions) throws GlideException { int height, Options options, List<Throwable> exceptions) throws GlideException {
Resource<ResourceType> result = null; Resource<ResourceType> result = null;
for (int i = 0, size = decoders.size(); i < size; i++) { for (int i = 0, size = decoders.size(); i < size; i++) {
ResourceDecoder<DataType, ResourceType> decoder = decoders.get(i); ResourceDecoder<DataType, ResourceType> decoder = decoders.get(i);
...@@ -68,7 +68,7 @@ public class DecodePath<DataType, ResourceType, Transcode> { ...@@ -68,7 +68,7 @@ public class DecodePath<DataType, ResourceType, Transcode> {
} }
// Some decoders throw unexpectedly. If they do, we shouldn't fail the entire load path, but // Some decoders throw unexpectedly. If they do, we shouldn't fail the entire load path, but
// instead log and continue. See #2406 for an example. // instead log and continue. See #2406 for an example.
} catch (IOException | RuntimeException e) { } catch (IOException | RuntimeException | OutOfMemoryError e) {
if (Log.isLoggable(TAG, Log.VERBOSE)) { if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Failed to decode data for " + decoder, e); Log.v(TAG, "Failed to decode data for " + decoder, e);
} }
......
...@@ -18,20 +18,20 @@ import java.util.List; ...@@ -18,20 +18,20 @@ import java.util.List;
public final class GlideException extends Exception { public final class GlideException extends Exception {
private static final StackTraceElement[] EMPTY_ELEMENTS = new StackTraceElement[0]; private static final StackTraceElement[] EMPTY_ELEMENTS = new StackTraceElement[0];
private final List<Exception> causes; private final List<Throwable> causes;
private Key key; private Key key;
private DataSource dataSource; private DataSource dataSource;
private Class<?> dataClass; private Class<?> dataClass;
public GlideException(String message) { public GlideException(String message) {
this(message, Collections.<Exception>emptyList()); this(message, Collections.<Throwable>emptyList());
} }
public GlideException(String detailMessage, Exception cause) { public GlideException(String detailMessage, Throwable cause) {
this(detailMessage, Collections.singletonList(cause)); this(detailMessage, Collections.singletonList(cause));
} }
public GlideException(String detailMessage, List<Exception> causes) { public GlideException(String detailMessage, List<Throwable> causes) {
super(detailMessage); super(detailMessage);
setStackTrace(EMPTY_ELEMENTS); setStackTrace(EMPTY_ELEMENTS);
this.causes = causes; this.causes = causes;
...@@ -62,7 +62,7 @@ public final class GlideException extends Exception { ...@@ -62,7 +62,7 @@ public final class GlideException extends Exception {
* *
* @see #getRootCauses() * @see #getRootCauses()
*/ */
public List<Exception> getCauses() { public List<Throwable> getCauses() {
return causes; return causes;
} }
...@@ -74,8 +74,8 @@ public final class GlideException extends Exception { ...@@ -74,8 +74,8 @@ public final class GlideException extends Exception {
* a given model using multiple different pathways, there may be multiple related or unrelated * a given model using multiple different pathways, there may be multiple related or unrelated
* reasons for a load to fail. * reasons for a load to fail.
*/ */
public List<Exception> getRootCauses() { public List<Throwable> getRootCauses() {
List<Exception> rootCauses = new ArrayList<>(); List<Throwable> rootCauses = new ArrayList<>();
addRootCauses(this, rootCauses); addRootCauses(this, rootCauses);
return rootCauses; return rootCauses;
} }
...@@ -88,20 +88,20 @@ public final class GlideException extends Exception { ...@@ -88,20 +88,20 @@ public final class GlideException extends Exception {
* complete stack traces. * complete stack traces.
*/ */
public void logRootCauses(String tag) { public void logRootCauses(String tag) {
List<Exception> causes = getRootCauses(); List<Throwable> causes = getRootCauses();
for (int i = 0, size = causes.size(); i < size; i++) { for (int i = 0, size = causes.size(); i < size; i++) {
Log.i(tag, "Root cause (" + (i + 1) + " of " + size + ")", causes.get(i)); Log.i(tag, "Root cause (" + (i + 1) + " of " + size + ")", causes.get(i));
} }
} }
private void addRootCauses(Exception exception, List<Exception> rootCauses) { private void addRootCauses(Throwable throwable, List<Throwable> rootCauses) {
if (exception instanceof GlideException) { if (throwable instanceof GlideException) {
GlideException glideException = (GlideException) exception; GlideException glideException = (GlideException) throwable;
for (Exception e : glideException.getCauses()) { for (Throwable t : glideException.getCauses()) {
addRootCauses(e, rootCauses); addRootCauses(t, rootCauses);
} }
} else { } else {
rootCauses.add(exception); rootCauses.add(throwable);
} }
} }
...@@ -136,18 +136,18 @@ public final class GlideException extends Exception { ...@@ -136,18 +136,18 @@ public final class GlideException extends Exception {
// Appendable throws, PrintWriter, PrintStream, and IndentedAppendable do not, so this should // Appendable throws, PrintWriter, PrintStream, and IndentedAppendable do not, so this should
// never happen. // never happen.
@SuppressWarnings("PMD.PreserveStackTrace") @SuppressWarnings("PMD.PreserveStackTrace")
private static void appendExceptionMessage(Exception e, Appendable appendable) { private static void appendExceptionMessage(Throwable t, Appendable appendable) {
try { try {
appendable.append(e.getClass().toString()).append(": ").append(e.getMessage()).append('\n'); appendable.append(t.getClass().toString()).append(": ").append(t.getMessage()).append('\n');
} catch (IOException e1) { } catch (IOException e1) {
throw new RuntimeException(e); throw new RuntimeException(t);
} }
} }
// Appendable throws, PrintWriter, PrintStream, and IndentedAppendable do not, so this should // Appendable throws, PrintWriter, PrintStream, and IndentedAppendable do not, so this should
// never happen. // never happen.
@SuppressWarnings("PMD.PreserveStackTrace") @SuppressWarnings("PMD.PreserveStackTrace")
private static void appendCauses(List<Exception> causes, Appendable appendable) { private static void appendCauses(List<Throwable> causes, Appendable appendable) {
try { try {
appendCausesWrapped(causes, appendable); appendCausesWrapped(causes, appendable);
} catch (IOException e) { } catch (IOException e) {
...@@ -156,7 +156,7 @@ public final class GlideException extends Exception { ...@@ -156,7 +156,7 @@ public final class GlideException extends Exception {
} }
@SuppressWarnings("ThrowableResultOfMethodCallIgnored") @SuppressWarnings("ThrowableResultOfMethodCallIgnored")
private static void appendCausesWrapped(List<Exception> causes, Appendable appendable) private static void appendCausesWrapped(List<Throwable> causes, Appendable appendable)
throws IOException { throws IOException {
int size = causes.size(); int size = causes.size();
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {
...@@ -166,7 +166,7 @@ public final class GlideException extends Exception { ...@@ -166,7 +166,7 @@ public final class GlideException extends Exception {
.append(String.valueOf(size)) .append(String.valueOf(size))
.append("): "); .append("): ");
Exception cause = causes.get(i); Throwable cause = causes.get(i);
if (cause instanceof GlideException) { if (cause instanceof GlideException) {
GlideException glideCause = (GlideException) cause; GlideException glideCause = (GlideException) cause;
glideCause.printStackTrace(appendable); glideCause.printStackTrace(appendable);
......
...@@ -21,13 +21,13 @@ import java.util.List; ...@@ -21,13 +21,13 @@ import java.util.List;
*/ */
public class LoadPath<Data, ResourceType, Transcode> { public class LoadPath<Data, ResourceType, Transcode> {
private final Class<Data> dataClass; private final Class<Data> dataClass;
private final Pool<List<Exception>> listPool; private final Pool<List<Throwable>> listPool;
private final List<? extends DecodePath<Data, ResourceType, Transcode>> decodePaths; private final List<? extends DecodePath<Data, ResourceType, Transcode>> decodePaths;
private final String failureMessage; private final String failureMessage;
public LoadPath(Class<Data> dataClass, Class<ResourceType> resourceClass, public LoadPath(Class<Data> dataClass, Class<ResourceType> resourceClass,
Class<Transcode> transcodeClass, Class<Transcode> transcodeClass,
List<DecodePath<Data, ResourceType, Transcode>> decodePaths, Pool<List<Exception>> listPool) { List<DecodePath<Data, ResourceType, Transcode>> decodePaths, Pool<List<Throwable>> listPool) {
this.dataClass = dataClass; this.dataClass = dataClass;
this.listPool = listPool; this.listPool = listPool;
this.decodePaths = Preconditions.checkNotEmpty(decodePaths); this.decodePaths = Preconditions.checkNotEmpty(decodePaths);
...@@ -37,17 +37,17 @@ public class LoadPath<Data, ResourceType, Transcode> { ...@@ -37,17 +37,17 @@ public class LoadPath<Data, ResourceType, Transcode> {
public Resource<Transcode> load(DataRewinder<Data> rewinder, Options options, int width, public Resource<Transcode> load(DataRewinder<Data> rewinder, Options options, int width,
int height, DecodePath.DecodeCallback<ResourceType> decodeCallback) throws GlideException { int height, DecodePath.DecodeCallback<ResourceType> decodeCallback) throws GlideException {
List<Exception> exceptions = listPool.acquire(); List<Throwable> throwables = listPool.acquire();
try { try {
return loadWithExceptionList(rewinder, options, width, height, decodeCallback, exceptions); return loadWithExceptionList(rewinder, options, width, height, decodeCallback, throwables);
} finally { } finally {
listPool.release(exceptions); listPool.release(throwables);
} }
} }
private Resource<Transcode> loadWithExceptionList(DataRewinder<Data> rewinder, Options options, private Resource<Transcode> loadWithExceptionList(DataRewinder<Data> rewinder, Options options,
int width, int height, DecodePath.DecodeCallback<ResourceType> decodeCallback, int width, int height, DecodePath.DecodeCallback<ResourceType> decodeCallback,
List<Exception> exceptions) throws GlideException { List<Throwable> exceptions) throws GlideException {
int size = decodePaths.size(); int size = decodePaths.size();
Resource<Transcode> result = null; Resource<Transcode> result = null;
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {
......
...@@ -17,8 +17,8 @@ public class ModelLoaderRegistry { ...@@ -17,8 +17,8 @@ public class ModelLoaderRegistry {
private final MultiModelLoaderFactory multiModelLoaderFactory; private final MultiModelLoaderFactory multiModelLoaderFactory;
private final ModelLoaderCache cache = new ModelLoaderCache(); private final ModelLoaderCache cache = new ModelLoaderCache();
public ModelLoaderRegistry(Pool<List<Exception>> exceptionListPool) { public ModelLoaderRegistry(Pool<List<Throwable>> throwableListPool) {
this(new MultiModelLoaderFactory(exceptionListPool)); this(new MultiModelLoaderFactory(throwableListPool));
} }
// Visible for testing. // Visible for testing.
......
...@@ -27,10 +27,10 @@ import java.util.List; ...@@ -27,10 +27,10 @@ import java.util.List;
class MultiModelLoader<Model, Data> implements ModelLoader<Model, Data> { class MultiModelLoader<Model, Data> implements ModelLoader<Model, Data> {
private final List<ModelLoader<Model, Data>> modelLoaders; private final List<ModelLoader<Model, Data>> modelLoaders;
private final Pool<List<Exception>> exceptionListPool; private final Pool<List<Throwable>> exceptionListPool;
MultiModelLoader(List<ModelLoader<Model, Data>> modelLoaders, MultiModelLoader(List<ModelLoader<Model, Data>> modelLoaders,
Pool<List<Exception>> exceptionListPool) { Pool<List<Throwable>> exceptionListPool) {
this.modelLoaders = modelLoaders; this.modelLoaders = modelLoaders;
this.exceptionListPool = exceptionListPool; this.exceptionListPool = exceptionListPool;
} }
...@@ -74,15 +74,15 @@ class MultiModelLoader<Model, Data> implements ModelLoader<Model, Data> { ...@@ -74,15 +74,15 @@ class MultiModelLoader<Model, Data> implements ModelLoader<Model, Data> {
static class MultiFetcher<Data> implements DataFetcher<Data>, DataCallback<Data> { static class MultiFetcher<Data> implements DataFetcher<Data>, DataCallback<Data> {
private final List<DataFetcher<Data>> fetchers; private final List<DataFetcher<Data>> fetchers;
private final Pool<List<Exception>> exceptionListPool; private final Pool<List<Throwable>> throwableListPool;
private int currentIndex; private int currentIndex;
private Priority priority; private Priority priority;
private DataCallback<? super Data> callback; private DataCallback<? super Data> callback;
@Nullable @Nullable
private List<Exception> exceptions; private List<Throwable> exceptions;
MultiFetcher(List<DataFetcher<Data>> fetchers, Pool<List<Exception>> exceptionListPool) { MultiFetcher(List<DataFetcher<Data>> fetchers, Pool<List<Throwable>> throwableListPool) {
this.exceptionListPool = exceptionListPool; this.throwableListPool = throwableListPool;
Preconditions.checkNotEmpty(fetchers); Preconditions.checkNotEmpty(fetchers);
this.fetchers = fetchers; this.fetchers = fetchers;
currentIndex = 0; currentIndex = 0;
...@@ -92,14 +92,14 @@ class MultiModelLoader<Model, Data> implements ModelLoader<Model, Data> { ...@@ -92,14 +92,14 @@ class MultiModelLoader<Model, Data> implements ModelLoader<Model, Data> {
public void loadData(Priority priority, DataCallback<? super Data> callback) { public void loadData(Priority priority, DataCallback<? super Data> callback) {
this.priority = priority; this.priority = priority;
this.callback = callback; this.callback = callback;
exceptions = exceptionListPool.acquire(); exceptions = throwableListPool.acquire();
fetchers.get(currentIndex).loadData(priority, this); fetchers.get(currentIndex).loadData(priority, this);
} }
@Override @Override
public void cleanup() { public void cleanup() {
if (exceptions != null) { if (exceptions != null) {
exceptionListPool.release(exceptions); throwableListPool.release(exceptions);
} }
exceptions = null; exceptions = null;
for (DataFetcher<Data> fetcher : fetchers) { for (DataFetcher<Data> fetcher : fetchers) {
......
...@@ -22,16 +22,16 @@ public class MultiModelLoaderFactory { ...@@ -22,16 +22,16 @@ public class MultiModelLoaderFactory {
private final List<Entry<?, ?>> entries = new ArrayList<>(); private final List<Entry<?, ?>> entries = new ArrayList<>();
private final Factory factory; private final Factory factory;
private final Set<Entry<?, ?>> alreadyUsedEntries = new HashSet<>(); private final Set<Entry<?, ?>> alreadyUsedEntries = new HashSet<>();
private final Pool<List<Exception>> exceptionListPool; private final Pool<List<Throwable>> throwableListPool;
public MultiModelLoaderFactory(Pool<List<Exception>> exceptionListPool) { public MultiModelLoaderFactory(Pool<List<Throwable>> throwableListPool) {
this(exceptionListPool, DEFAULT_FACTORY); this(throwableListPool, DEFAULT_FACTORY);
} }
// Visible for testing. // Visible for testing.
MultiModelLoaderFactory(Pool<List<Exception>> exceptionListPool, MultiModelLoaderFactory(Pool<List<Throwable>> throwableListPool,
Factory factory) { Factory factory) {
this.exceptionListPool = exceptionListPool; this.throwableListPool = throwableListPool;
this.factory = factory; this.factory = factory;
} }
...@@ -128,7 +128,7 @@ public class MultiModelLoaderFactory { ...@@ -128,7 +128,7 @@ public class MultiModelLoaderFactory {
} }
} }
if (loaders.size() > 1) { if (loaders.size() > 1) {
return factory.build(loaders, exceptionListPool); return factory.build(loaders, throwableListPool);
} else if (loaders.size() == 1) { } else if (loaders.size() == 1) {
return loaders.get(0); return loaders.get(0);
} else { } else {
...@@ -185,8 +185,8 @@ public class MultiModelLoaderFactory { ...@@ -185,8 +185,8 @@ public class MultiModelLoaderFactory {
static class Factory { static class Factory {
public <Model, Data> MultiModelLoader<Model, Data> build( public <Model, Data> MultiModelLoader<Model, Data> build(
List<ModelLoader<Model, Data>> modelLoaders, Pool<List<Exception>> exceptionListPool) { List<ModelLoader<Model, Data>> modelLoaders, Pool<List<Throwable>> throwableListPool) {
return new MultiModelLoader<>(modelLoaders, exceptionListPool); return new MultiModelLoader<>(modelLoaders, throwableListPool);
} }
} }
......
...@@ -35,16 +35,16 @@ public class MultiModelLoaderFactoryTest { ...@@ -35,16 +35,16 @@ public class MultiModelLoaderFactoryTest {
@Rule public ExpectedException exception = ExpectedException.none(); @Rule public ExpectedException exception = ExpectedException.none();
private Pool<List<Exception>> exceptionListPool; private Pool<List<Throwable>> throwableListPool;
private MultiModelLoaderFactory multiFactory; private MultiModelLoaderFactory multiFactory;
@Before @Before
public void setUp() { public void setUp() {
MockitoAnnotations.initMocks(this); MockitoAnnotations.initMocks(this);
exceptionListPool = FactoryPools.threadSafeList(); throwableListPool = FactoryPools.threadSafeList();
multiFactory = new MultiModelLoaderFactory(exceptionListPool, multiFactory =
multiModelLoaderFactory); new MultiModelLoaderFactory(throwableListPool, multiModelLoaderFactory);
when(firstFactory.build(eq(multiFactory))).thenReturn(firstModelLoader); when(firstFactory.build(eq(multiFactory))).thenReturn(firstModelLoader);
when(secondFactory.build(eq(multiFactory))).thenReturn(secondModelLoader); when(secondFactory.build(eq(multiFactory))).thenReturn(secondModelLoader);
} }
...@@ -268,7 +268,7 @@ public class MultiModelLoaderFactoryTest { ...@@ -268,7 +268,7 @@ public class MultiModelLoaderFactoryTest {
Class<Y> dataClass) { Class<Y> dataClass) {
ArgumentCaptor<List<ModelLoader<X, Y>>> captor = Util.cast(ArgumentCaptor.forClass(List.class)); ArgumentCaptor<List<ModelLoader<X, Y>>> captor = Util.cast(ArgumentCaptor.forClass(List.class));
multiFactory.build(modelClass, dataClass); multiFactory.build(modelClass, dataClass);
verify(multiModelLoaderFactory).build(captor.capture(), eq(exceptionListPool)); verify(multiModelLoaderFactory).build(captor.capture(), eq(throwableListPool));
List<ModelLoader<X, Y>> captured = captor.getValue(); List<ModelLoader<X, Y>> captured = captor.getValue();
List<ModelLoader<X, Y>> result = new ArrayList<>(captured.size()); List<ModelLoader<X, Y>> result = new ArrayList<>(captured.size());
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册