Skip to content

Commit

Permalink
Fix deadlock releasing resources that recursively clear when evicted …
Browse files Browse the repository at this point in the history
…from cache.

PiperOrigin-RevId: 283380663
  • Loading branch information
sjudd authored and glide-copybara-robot committed Dec 2, 2019
1 parent f4da653 commit 100ac4a
Show file tree
Hide file tree
Showing 4 changed files with 22 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -384,7 +384,9 @@ public synchronized void onEngineJobCancelled(EngineJob<?> engineJob, Key key) {

@Override
public void onResourceRemoved(@NonNull final Resource<?> resource) {
resourceRecycler.recycle(resource);
// Avoid deadlock with RequestManagers when recycling triggers recursive clear() calls.
// See b/145519760.
resourceRecycler.recycle(resource, /*forceNextFrame=*/ true);
}

@Override
Expand All @@ -393,7 +395,7 @@ public void onResourceReleased(Key cacheKey, EngineResource<?> resource) {
if (resource.isMemoryCacheable()) {
cache.put(cacheKey, resource);
} else {
resourceRecycler.recycle(resource);
resourceRecycler.recycle(resource, /*forceNextFrame=*/ false);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ class ResourceRecycler {
private final Handler handler =
new Handler(Looper.getMainLooper(), new ResourceRecyclerCallback());

synchronized void recycle(Resource<?> resource) {
if (isRecycling) {
synchronized void recycle(Resource<?> resource, boolean forceNextFrame) {
if (isRecycling || forceNextFrame) {
// If a resource has sub-resources, releasing a sub resource can cause it's parent to be
// synchronously evicted which leads to a recycle loop when the parent releases it's children.
// Posting breaks this loop.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -351,7 +351,7 @@ public void testResourceIsNotAddedToCacheOnReleasedIfNotCacheable() {
public void testResourceIsRecycledIfNotCacheableWhenReleased() {
when(harness.resource.isMemoryCacheable()).thenReturn(false);
harness.getEngine().onResourceReleased(harness.cacheKey, harness.resource);
verify(harness.resourceRecycler).recycle(eq(harness.resource));
verify(harness.resourceRecycler).recycle(eq(harness.resource), eq(false));
}

@Test
Expand All @@ -372,7 +372,7 @@ public void testEngineAddedAsListenerToMemoryCache() {
@Test
public void testResourceIsRecycledWhenRemovedFromCache() {
harness.getEngine().onResourceRemoved(harness.resource);
verify(harness.resourceRecycler).recycle(eq(harness.resource));
verify(harness.resourceRecycler).recycle(eq(harness.resource), eq(true));
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,20 @@ public void setUp() {
}

@Test
public void testRecyclesResourceSynchronouslyIfNotAlreadyRecyclingResource() {
public void recycle_withoutForceNextFrame_recyclesResourceSynchronously() {
Resource<?> resource = mockResource();
Shadows.shadowOf(Looper.getMainLooper()).pause();
recycler.recycle(resource);
recycler.recycle(resource, /*forceNextFrame=*/ false);
verify(resource).recycle();
}

@Test
public void recycle_withForceNextFrame_postsRecycle() {
Resource<?> resource = mockResource();
Shadows.shadowOf(Looper.getMainLooper()).pause();
recycler.recycle(resource, /*forceNextFrame=*/ true);
verify(resource, never()).recycle();
Shadows.shadowOf(Looper.getMainLooper()).runToEndOfTasks();
verify(resource).recycle();
}

Expand All @@ -42,7 +52,7 @@ public void testDoesNotRecycleChildResourceSynchronously() {
new Answer<Void>() {
@Override
public Void answer(InvocationOnMock invocationOnMock) throws Throwable {
recycler.recycle(child);
recycler.recycle(child, /*forceNextFrame=*/ false);
return null;
}
})
Expand All @@ -51,7 +61,7 @@ public Void answer(InvocationOnMock invocationOnMock) throws Throwable {

Shadows.shadowOf(Looper.getMainLooper()).pause();

recycler.recycle(parent);
recycler.recycle(parent, /*forceNextFrame=*/ false);

verify(parent).recycle();
verify(child, never()).recycle();
Expand Down

0 comments on commit 100ac4a

Please sign in to comment.