-
Notifications
You must be signed in to change notification settings - Fork 392
Fix cache_expiration_time #883
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
Changes from all commits
47d2cbc
0e8c32e
db0b3ca
ad2d027
3c44b27
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1900,7 +1900,7 @@ protected function fetch_data(&$cache) | |
| $this->data = []; | ||
| } | ||
| // Check if the cache has been updated | ||
| elseif (isset($this->data['cache_expiration_time']) && $this->data['cache_expiration_time'] > time()) { | ||
| elseif (!isset($this->data['cache_expiration_time']) || $this->data['cache_expiration_time'] < time()) { | ||
| // Want to know if we tried to send last-modified and/or etag headers | ||
| // when requesting this file. (Note that it's up to the file to | ||
| // support this, but we don't always send the headers either.) | ||
|
|
@@ -1924,6 +1924,7 @@ protected function fetch_data(&$cache) | |
| $this->status_code = 0; | ||
|
|
||
| if ($this->force_cache_fallback) { | ||
| $this->data['cache_expiration_time'] = $this->cache_duration + time(); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also probably want to do the same for 304 response.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The whole handling of cache + 304 is broken at the moment in my opinion. But yes, it would make sense in this PR to fix at least your suggestion (edit: done)
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh, I was wondering why does not the in-cache TTL remove the entry when it expires, which would break the 304 and it does, as you found out in https://github.com/FreshRSS/simplepie/blob/5e92ce767597aa9f5cbb00d88c7591b2e604dc5f/src/Cache/BaseDataCache.php#L58-L62
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I can happily send upstream more of the fixes / improvements, but best after some of the existing pending PRs are processed |
||
| $cache->set_data($cacheKey, $this->data, $this->cache_duration); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If I understand this correctly, this just extends the cache lifetime ( Probably should be a separate commit from the test fix, though.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The tests are still related to cache, and were preventing this PR from passing the tests, but can be put in another PR
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @jtojnar
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm, maybe we should just pass TTL as In the long term, we can probably come up with a nicer API though. For example, we could have a class /** @type CacheEntry array{mtime: int, extraKeys: array<string, mixed>, value: mixed} */and be used something like this: $cacheWrapper = new CacheWrapper(new Psr16($this->cache), $this->cache_duration);
$this->data = $cacheWrapper->get(
$key,
// Extra validation keys, since the allowed size of `$key` is limited.
// If value of any of the keys does not match the one in the `extraKeys` array,
// the value will be considered stale and one of the following actions will be performed.
[
// Different version of SimplePie might have unrecognizable structure of the cache data
// so pass `null` as `$staleData` to the callback.
['key' => 'build', 'expected' => Misc::get_build(), 'action' => CacheWrapper::INVALID_ACTION_DISCARD],
// A collision. Cause the value returned by the callback to be returned by `CacheWrapper::get()` but the cache would not be updated.
// I guess this could also be handled transparently by having the `CacheWrapper` store it in `CacheEntry`.
['key' => 'url', 'expected' => $this->feed_url, 'action' => CacheWrapper::INVALID_ACTION_COLLISION],
// …
],
// This callback will be executed when the cache lacks the key, or it is invalid.
// `$staleData` will be null if the key did not exist.
// The cache will be updated with the returned value and the mtime will be updated.
// Except maybe when exception occurs, then we might want to unset the cache and propagate the exception.
function(?array $staleData) use (&$obtainedFromCache): array {
$headers = [];
if ($staleData !== null && isset($staleData['headers']['etag'])) {
$headers['etag'] = $staleData['headers']['etag'];
}
$file = fetch($url, $headers);
if ($this->status_code === 304) {
$obtainedFromCache = true;
return $staleData;
}
// …
return [
'url' => $this->feed_url,
'feed_url' => $file->get_final_requested_uri(),
'build' => Misc::get_build(),
'cache_expiration_time' => $this->cache_duration + time(),
];
}
);
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would suggest to address this potential refactoring in another PR though :-)
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P.S. Regarding the tests, the change is due to the fix of the inequality higher up, so they are directly related |
||
|
|
||
| return true; | ||
|
|
@@ -1936,6 +1937,7 @@ protected function fetch_data(&$cache) | |
| // Set raw_data to false here too, to signify that the cache | ||
| // is still valid. | ||
| $this->raw_data = false; | ||
| $this->data['cache_expiration_time'] = $this->cache_duration + time(); | ||
| $cache->set_data($cacheKey, $this->data, $this->cache_duration); | ||
|
|
||
| return true; | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reading the explanations from both of you I think this PR is reasonable.
The last remaining thing not clear to me is how it can this patch fix anything without https://github.com/FreshRSS/simplepie/blob/5e92ce767597aa9f5cbb00d88c7591b2e604dc5f/src/Cache/BaseDataCache.php#L58-L62
If we use the same
$this->cache_durationas TTL passed to$cache->set_data()and to$this->data['cache_expiration_time'], I would expect that if the cache expires, the following would return the default empty array, and the above line would never be executed, as it is withinif (!empty($this->data)):simplepie/src/SimplePie.php
Line 1874 in 6b97dec
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This patch will fix some cases when the internal TTL has not expired yet. I think this is needed in any case.
But I completely agree that to have a working 304 cache, more fixes of the logic are needed. This PR focusses on the straightforward bugs in the current logic, which are needed no matter what, and should not be controversial (hopefully).
P.S.: In other words, to properly test the behaviour of the current logic, this PR is needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But how could the internal TTL not have expired when
$this->data['cache_expiration_time']did – are not they set to the same cache duration?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While the default cache implementation ("legacy file cache") is still broken, I believe passing another implementation might work (but I have not investigated in details)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, alright. We can set the TTL to
nullin allset_datacalls in a follow up PR to actually fix it then.