Skip to content

Deterministic time in cache items for reproducible builds #26127

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

Merged
merged 1 commit into from
Feb 11, 2018
Merged

Deterministic time in cache items for reproducible builds #26127

merged 1 commit into from
Feb 11, 2018

Conversation

lstrojny
Copy link
Contributor

@lstrojny lstrojny commented Feb 9, 2018

Q A
Branch? 3.4
Bug fix? no
New feature? yes
BC breaks? no
Deprecations? no
Tests pass? yes
Fixed tickets -
License MIT
Doc PR -

Allows setting a deterministic time for cache entries. This can be used to seed builds with a deterministic timestamp for reproducibility.

Parent issue is #25958

@@ -108,6 +110,11 @@ private function getFile($id, $mkdir = false)
return $dir.substr($hash, 2, 20);
}

private function getTime()
{
return $this->deterministicTime !== null ? $this->deterministicTime : time();
Copy link
Member

Choose a reason for hiding this comment

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

Thanks @lstrojny for this PR. I think this is going too far :)
This completely breaks the expiration mechanism of cache pools.
It cannot pass PSR-6 when this flag is on anymore.
Instead, I'd suggest to use a time-less value for non-expirable items.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

On breaking expiration mechanism: doesn't that depend on what I configure as a timestamp. Since I am touching the clock, I might invalidate it too early or too late, but that's my choice as a user.
On PSR-6: can you elaborate where the PSR-6 breakage comes from?

@nicolas-grekas
Copy link
Member

nicolas-grekas commented Feb 10, 2018

I might invalidate it too early or too late, but that's my choice as a user.
On PSR-6: can you elaborate where the PSR-6 breakage comes from?

The breakage comes from the first sentence, which is breaking basic expectations from the consumer pov (the instantiation is not the responsibility of the consumer, so it doesn't know that this pool is behaving specially - and doesn't expect it more importantly.)

As noted before, I'd suggest to use a time-less value for non-expirable items.
Reproducible builds just need this.
Generating expirable items at build time should never be part of a "reproducible build" anyway (just split them out if you want to warm-up such items - but they cannot be considered part of the build artifact.)

@lstrojny
Copy link
Contributor Author

@nicolas-grekas I don't think I agree that this would be so bad but I like your suggestion more, simply because it is way less code and we can live without adding any extra parameter to the classes.

@nicolas-grekas nicolas-grekas added this to the 3.4 milestone Feb 10, 2018
@robfrawley
Copy link
Contributor

robfrawley commented Feb 10, 2018

It seems really odd to change public methods by adding parameters whose sole purpose are to make testing easier but provide little (or no?) benefit to consumers (developers) themselves. Looks like you settled on a different implementation.

@lstrojny lstrojny changed the title Allow setting deterministic time for reproducible builds Deterministic time in cache items for reproducible builds Feb 10, 2018
Copy link
Member

@nicolas-grekas nicolas-grekas left a comment

Choose a reason for hiding this comment

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

small comments

@@ -36,7 +36,7 @@ public function prune()
continue;
}

if ($time >= (int) $expiresAt = fgets($h)) {
if (0 < ($expiresAt = fgets($h)) && $time >= $expiresAt) {
Copy link
Member

Choose a reason for hiding this comment

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

if (($expiresAt = (int) fgets($h)) && $time >= $expiresAt) {
the isset($expiresAt[0]) below looks unneeded now, it's always true now
(same comments on the second change)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done …

@@ -94,7 +94,7 @@ protected function doHave($id)
protected function doSave(array $values, $lifetime)
{
$ok = true;
$expiresAt = time() + ($lifetime ?: 31557600); // 31557600s = 1 year
$expiresAt = $lifetime > 0 ? (time() + $lifetime) : 0;
Copy link
Member

Choose a reason for hiding this comment

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

I'd suggest to write this as $lifetime ? time() + $lifetime : 0;

Copy link
Contributor Author

Choose a reason for hiding this comment

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

… and done

@nicolas-grekas
Copy link
Member

Thank you @lstrojny.

@nicolas-grekas nicolas-grekas merged commit b4259a6 into symfony:3.4 Feb 11, 2018
nicolas-grekas added a commit that referenced this pull request Feb 11, 2018
…(lstrojny)

This PR was merged into the 3.4 branch.

Discussion
----------

Deterministic time in cache items for reproducible builds

| Q             | A
| ------------- | ---
| Branch?       | 3.4
| Bug fix?      | no
| New feature?  | yes
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | -
| License       | MIT
| Doc PR        | -

Allows setting a deterministic time for cache entries. This can be used to seed builds with a deterministic timestamp for reproducibility.

Parent issue is #25958

Commits
-------

b4259a6 Use 0 for unlimited expiry
@lstrojny lstrojny deleted the dev/deterministic-cache-time branch February 13, 2018 16:41
This was referenced Mar 1, 2018
@Blacksmoke16
Copy link
Contributor

Blacksmoke16 commented Jan 14, 2022

Is it expected that when 0 is the expiresAt value, the file's created/modified timestamp on the filesystem is set to 0 which maps to start of unix epoch? This is causing some issues with tar for example as if the machine is an earlier timezone, such as EST, the timestamp is being parsed as something before the start of epoch time, which is invalid.

From what i can tell the expiration timestamp is being read from the file itself, so probably just need to add && 0 !== $expiresAt to https://github.com/symfony/symfony/blob/4.4/src/Symfony/Component/Cache/Traits/FilesystemCommonTrait.php#L111? Or is this working by design?

@nicolas-grekas
Copy link
Member

nicolas-grekas commented Jan 14, 2022

Please don't comment on old PRs/issues if you want any follow up.

@nicolas-grekas
Copy link
Member

Open an issue or better: a PR instead.

nicolas-grekas added a commit that referenced this pull request Jan 18, 2022
…y do not expire (Blacksmoke16)

This PR was squashed before being merged into the 4.4 branch.

Discussion
----------

[Cache] Set mtime of cache files 1 year into future if they do not expire

| Q             | A
| ------------- | ---
| Branch?       | 4.4
| Bug fix?      | yes
| New feature?  |no
| Deprecations? | no
| Tickets       | -
| License       | MIT
| Doc PR        | -

#26127 made is so that `0` is used to represent cache files that do not expire. However this was causing `touch` to be called with `0`, which was setting the create/modification time of the file to start of epoch time, which doesn't really make sense. It can cause some issues with `tar` for example as when timezones are taken into consideration you end up with warnings like:

> tar: app/cache/prod/annotations/@/+/3/cdcAWwqaPORAi0TfsO5Q: implausibly old time stamp 1969-12-31 19:00:00

Given the expiration of the files is stored within the file itself, it's probably safe to not `touch` it if that value is `0`. However is there actually a reason to touch it at all as a file that expires in 6 hours would show as created 6 hours into the future.

I also wasn't sure how to test this, so open to suggestions on that/if we need the `touch` at all.

Commits
-------

57cad6f [Cache] Set mtime of cache files 1 year into future if they do not expire
symfony-splitter pushed a commit to symfony/cache that referenced this pull request Jan 18, 2022
…y do not expire (Blacksmoke16)

This PR was squashed before being merged into the 4.4 branch.

Discussion
----------

[Cache] Set mtime of cache files 1 year into future if they do not expire

| Q             | A
| ------------- | ---
| Branch?       | 4.4
| Bug fix?      | yes
| New feature?  |no
| Deprecations? | no
| Tickets       | -
| License       | MIT
| Doc PR        | -

symfony/symfony#26127 made is so that `0` is used to represent cache files that do not expire. However this was causing `touch` to be called with `0`, which was setting the create/modification time of the file to start of epoch time, which doesn't really make sense. It can cause some issues with `tar` for example as when timezones are taken into consideration you end up with warnings like:

> tar: app/cache/prod/annotations/@/+/3/cdcAWwqaPORAi0TfsO5Q: implausibly old time stamp 1969-12-31 19:00:00

Given the expiration of the files is stored within the file itself, it's probably safe to not `touch` it if that value is `0`. However is there actually a reason to touch it at all as a file that expires in 6 hours would show as created 6 hours into the future.

I also wasn't sure how to test this, so open to suggestions on that/if we need the `touch` at all.

Commits
-------

57cad6f9a4 [Cache] Set mtime of cache files 1 year into future if they do not expire
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants