Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix cache check race condition #255

Merged
merged 5 commits into from Jun 18, 2018
Merged

Conversation

pcantrell
Copy link
Member

@pcantrell pcantrell commented Jun 18, 2018

This fixes #237.

@pcantrell pcantrell self-assigned this Jun 18, 2018
@pcantrell pcantrell force-pushed the fix-cache-check-race-condition branch from 777b21a to 8e7d99a Compare June 18, 2018 16:21
@pcantrell pcantrell added this to To do in 1.4 via automation Jun 18, 2018
@pcantrell pcantrell merged commit 8b275b0 into master Jun 18, 2018
1.4 automation moved this from To do to Done Jun 18, 2018
@pcantrell pcantrell deleted the fix-cache-check-race-condition branch June 18, 2018 16:36
@pcantrell pcantrell moved this from Done to Logged in 1.4 Jun 26, 2018
@@ -513,7 +538,7 @@ public final class Resource: NSObject

private func receiveDataNotModified()

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hello @pcantrell may I ask the real purpose of receiveDataNotModified().
I'm currently using Siesta 1.4.0 and reached this point as possible bug. The same will apply also on the latest 1.4.3 code.

receiveDataNotModified() as I understood is responsible to notify the observers that the resource data is still valid and will not be downloaded from the network. I'm totally ok with it but few line before the latestData?.touch() will actually change the local data and will update then the cache as well using a new timestamp.

The touch() will update the timestamp and the new timestamp will be cached despite no new data comes in from the backend. As a result the local cached data may never expire.

It's a real corner case but I was able to reproduce it just running again the killed application right before the resource expirations time.
As example, if a resource expires in 5 days and the user get back to the application after 4 days, the app may have been killed by the OS because of memory pressure, the cached resource get a new timestamp, invalidating the 5 days expiration planned for the day after. As result loadIfNeeded() will not result in a network call for a total of 9 days, unless the occurrence repeat all over again.

Looks like that lines 543-546 are not necessary at all.
Am I wrong? Maybe I misunderstood the .notChanged use case?

I'm just able to fix it in my code replacing the default EntityCache func updateEntityTimestamp(_ timestamp: TimeInterval, forKey key: CacheKey) implementation with an empty implementation. Probably all of this is not necessary at all.

Thank you in advance

Copy link
Member Author

@pcantrell pcantrell Apr 9, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

receiveDataNotModified() is supposed to mean that the server sent a 304, which means “we just checked and yes, this data is still valid.” If the server keeps sending 304s, then yes, the data in the cache should never expire. That’s what lines 543-546 are for.

I believe that you've flagged a real problem, and the mistake is here: my little hack to complete a cache-backed initial request shouldn’t update the timestamp. Would you mind filing an issue for this, so I don’t lose track of it?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok thanks for the explanation. It makes sense. I was confused because receiveDataNotModified() got called only in the pointed case. At least i didn't found any other call in the Siesta codebase.
Probably something still planned to be introduced?

Anyway i will file the bug so you can keep track of it.
Thanks

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh nice, I missed it because I was searching for receiveDataNotModified()
Thanks for pointing it out.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
No open projects
1.4
In release notes
Development

Successfully merging this pull request may close these issues.

Race condition between cache check and loadIfNeeded()
2 participants