Age precision rounding causes premature stale object

Reza Naghibi reza at
Fri Dec 9 21:37:09 CET 2016

So in light of the hit-for-pass vs. hit-for-miss change in 5.0 (which I
think is great), I have been researching 0s TTL objects coming into cache
(and generating the hit-for-XXX marker). In particular, even with grace
disabled, I have still seen valid objects from one Varnish come in as a
stale 0s TTL object in another Varnish. As in, an object comes into Varnish
with a max-age of X and an equal Age of X. Example:

Cache-Control: max-age=14
Age: 14

The effective TTL here is 0s, triggering the hit-for-XXX. Looking at the

http_PrintfHeader(req->resp, "Age: %.0f",
   fmax(0., req->t_prev - req->objcore->t_origin));

The issue here is that %.0f will do a standard IEEE floating point
numerical rounding to satisfy the precision. I am not sure if this is a C
standard, but in my tests, this holds true. In the context of our Age
calculation, this means that objects in their last 0.5s of TTL life will
get their Age rounded up to the max-age and then anything reading this
response will see a stale object.

Given that we are losing precision and accepting a 1s rounding error,
floor() is the best choice here as it doesn't have the side effect of this
premature Age == max-age scenario. So something as simple as:

http_PrintfHeader(req->resp, "Age: %.0f",
    floor(fmax(0., req->t_prev - req->objcore->t_origin)));

Will make sure we *always* get an Age < max-age, up until the actual Age >=
max-age and the object is infact stale.

Thoughts? I am not sure of the history here and if this has been previously
considered and there are valid reasons for this logic. If so, I apologize
in advance!

Reza Naghibi
Varnish Software
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <>

More information about the varnish-dev mailing list