e.lastref = basics.lastref;
e.timestamp = basics.timestamp;
e.expires = basics.expires;
- e.lastmod = basics.lastmod;
+ e.lastModified(basics.lastmod);
e.refcount = basics.refcount;
e.flags = basics.flags;
void delayAwareRead(const Comm::ConnectionPointer &conn, char *buf, int len, AsyncCall::Pointer callback);
void setNoDelay (bool const);
- bool modifiedSince(HttpRequest * request) const;
+ void lastModified(const time_t when) { lastModified_ = when; }
+ /// \returns entry's 'effective' modification time
+ time_t lastModified() const {
+ // may still return -1 if timestamp is not set
+ return lastModified_ < 0 ? timestamp : lastModified_;
+ }
+ /// \returns a formatted string with entry's timestamps
+ const char *describeTimestamps() const;
+ // TODO: consider removing currently unsupported imslen parameter
+ bool modifiedSince(const time_t ims, const int imslen = -1) const;
/// has ETag matching at least one of the If-Match etags
bool hasIfMatchEtag(const HttpRequest &request) const;
/// has ETag matching at least one of the If-None-Match etags
time_t timestamp;
time_t lastref;
time_t expires;
- time_t lastmod;
+private:
+ time_t lastModified_; ///< received Last-Modified value or -1; use lastModified()
+public:
uint64_t swap_file_sz;
uint16_t refcount;
uint16_t flags;
{
const char *url = storeId();
debugs(88, 3, "clientReplyContext::processExpired: '" << http->uri << "'");
- assert(http->storeEntry()->lastmod >= 0);
+ const time_t lastmod = http->storeEntry()->lastModified();
+ assert(lastmod >= 0);
/*
* check if we are allowed to contact other servers
* @?@: Instead of a 504 (Gateway Timeout) reply, we may want to return
sc->setDelayId(DelayId::DelayClient(http));
#endif
- http->request->lastmod = old_entry->lastmod;
+ http->request->lastmod = lastmod;
if (!http->request->header.has(Http::HdrType::IF_NONE_MATCH)) {
ETag etag = {NULL, -1}; // TODO: make that a default ETag constructor
http->request->etag = etag.str;
}
- debugs(88, 5, "clientReplyContext::processExpired : lastmod " << entry->lastmod );
+ debugs(88, 5, "lastmod " << entry->lastModified());
http->storeEntry(entry);
assert(http->out.offset == 0);
assert(http->request->clientConnectionManager == http->getConn());
// if client sent IMS
- if (http->request->flags.ims && !old_entry->modifiedSince(http->request)) {
+ if (http->request->flags.ims && !old_entry->modifiedSince(http->request->ims, http->request->imslen)) {
// forward the 304 from origin
debugs(88, 3, "handleIMSReply: origin replied 304, revalidating existing entry and forwarding 304 to client");
sendClientUpstreamResponse();
*/
r->flags.needValidation = true;
- if (e->lastmod < 0) {
- debugs(88, 3, "validate HIT object? NO. Missing Last-Modified header. Do MISS.");
+ if (e->lastModified() < 0) {
+ debugs(88, 3, "validate HIT object? NO. Can't calculate entry modification time. Do MISS.");
/*
- * Previous reply didn't have a Last-Modified header,
- * we cannot revalidate it.
+ * We cannot revalidate entries without knowing their
+ * modification time.
+ * XXX: BUG 1890 objects without Date do not get one added.
*/
http->logType = LOG_TCP_MISS;
processMiss();
if (r.flags.ims) {
// handle If-Modified-Since requests from the client
- if (e->modifiedSince(&r)) {
+ if (e->modifiedSince(r.ims, r.imslen)) {
http->logType = LOG_TCP_IMS_HIT;
sendMoreData(result);
return;
e.lastref = basics.lastref;
e.timestamp = basics.timestamp;
e.expires = basics.expires;
- e.lastmod = basics.lastmod;
+ e.lastModified(basics.lastmod);
e.refcount = basics.refcount;
e.flags = basics.flags;
tmpe.expires,
tmpe.timestamp,
tmpe.lastref,
- tmpe.lastmod,
+ tmpe.lastModified(),
tmpe.refcount, /* refcount */
tmpe.flags, /* flags */
(int) flags.clean));
currentEntry()->lastref = swapData.timestamp;
currentEntry()->timestamp = swapData.timestamp;
currentEntry()->expires = swapData.expires;
- currentEntry()->lastmod = swapData.lastmod;
+ currentEntry()->lastModified(swapData.lastmod);
currentEntry()->flags = swapData.flags;
currentEntry()->refcount += swapData.refcount;
sd->dereference(*currentEntry());
s.timestamp = e.timestamp;
s.lastref = e.lastref;
s.expires = e.expires;
- s.lastmod = e.lastmod;
+ s.lastmod = e.lastModified();
s.swap_file_sz = e.swap_file_sz;
s.refcount = e.refcount;
s.flags = e.flags;
e->lastref = lastref;
e->timestamp = timestamp;
e->expires = expires;
- e->lastmod = lastmod;
+ e->lastModified(lastmod);
e->refcount = refcount;
e->flags = newFlags;
EBIT_CLR(e->flags, RELEASE_REQUEST);
s->timestamp = e.timestamp;
s->lastref = e.lastref;
s->expires = e.expires;
- s->lastmod = e.lastmod;
+ s->lastmod = e.lastModified();
s->swap_file_sz = e.swap_file_sz;
s->refcount = e.refcount;
s->flags = e.flags;
if (e && e->expires > -1)
hdr.putTime(Http::HdrType::EXPIRES, e->expires);
- if (e && e->lastmod > -1)
- hdr.putTime(Http::HdrType::LAST_MODIFIED, e->lastmod);
+ if (e && e->lastModified() > -1)
+ hdr.putTime(Http::HdrType::LAST_MODIFIED, e->lastModified());
hdr.packInto(&mb);
/* got modification time? */
if (spec.time >= 0)
- return http->storeEntry()->lastmod <= spec.time;
+ return !http->storeEntry()->modifiedSince(spec.time);
assert(0); /* should not happen */
return false;
basics.timestamp = from.timestamp;
basics.lastref = from.lastref;
basics.expires = from.expires;
- basics.lastmod = from.lastmod;
+ basics.lastmod = from.lastModified();
basics.swap_file_sz = from.swap_file_sz;
basics.refcount = from.refcount;
basics.flags = from.flags;
/* set lastmod to trigger IMS request if possible */
if (old_e)
- e->lastmod = old_e->lastmod;
+ e->lastModified(old_e->lastModified());
/* push towards peer cache */
debugs(72, 3, "peerDigestRequest: forwarding to fwdStart...");
debugs(72, 3, "peerDigestFetchFinish: expires: " <<
(long int) fetch->expires << " (" << std::showpos <<
(int) (fetch->expires - squid_curtime) << "), lmt: " <<
- std::noshowpos << (long int) fetch->entry->lastmod << " (" <<
- std::showpos << (int) (fetch->entry->lastmod - squid_curtime) <<
+ std::noshowpos << (long int) fetch->entry->lastModified() << " (" <<
+ std::showpos << (int) (fetch->entry->lastModified() - squid_curtime) <<
")");
}
}
// 3. If there is a Last-Modified header, try the last-modified factor algorithm.
- if (entry->lastmod > -1 && entry->timestamp > entry->lastmod) {
-
- /* lastmod_delta is the difference between the last-modified date of the response
- * and the time we cached it. It's how "old" the response was when we got it.
- */
- time_t lastmod_delta = entry->timestamp - entry->lastmod;
-
+ const time_t lastmod_delta = entry->timestamp - entry->lastModified();
+ if (lastmod_delta > 0) {
/* stale_age is the age of the response when it became/becomes stale according to
* the last-modified factor algorithm. It's how long we can consider the response
* fresh from the time we cached it.
/* Does not need refresh. This is certainly cachable */
return true;
- if (entry->lastmod < 0)
- /* Last modified is needed to do a refresh */
+ if (entry->lastModified() < 0)
+ /* We should know entry's modification time to do a refresh */
return false;
if (entry->mem_obj == NULL)
/* LOCALS */
static const char *describeStatuses(const StoreEntry *);
-static const char *describeTimestamps(const StoreEntry *);
static void statAvgTick(void *notused);
static void statAvgDump(StoreEntry *, int minutes, int hours);
#if STAT_GRAPHS
return buf;
}
-static const char *
-describeTimestamps(const StoreEntry * entry)
-{
- LOCAL_ARRAY(char, buf, 256);
- snprintf(buf, 256, "LV:%-9d LU:%-9d LM:%-9d EX:%-9d",
- (int) entry->timestamp,
- (int) entry->lastref,
- (int) entry->lastmod,
- (int) entry->expires);
- return buf;
-}
-
static void
statStoreEntry(MemBuf * mb, StoreEntry * e)
{
mb->appendf("KEY %s\n", e->getMD5Text());
mb->appendf("\t%s\n", describeStatuses(e));
mb->appendf("\t%s\n", storeEntryFlags(e));
- mb->appendf("\t%s\n", describeTimestamps(e));
+ mb->appendf("\t%s\n", e->describeTimestamps());
mb->appendf("\t%d locks, %d clients, %d refs\n", (int) e->locks(), storePendingNClients(e), (int) e->refcount);
mb->appendf("\tSwap Dir %d, File %#08X\n", e->swap_dirn, e->swap_filen);
timestamp(-1),
lastref(-1),
expires(-1),
- lastmod(-1),
+ lastModified_(-1),
swap_file_sz(0),
refcount(0),
flags(0),
else
exp = reply->expires;
- if (lastmod == reply->last_modified && timestamp == served_date && expires == exp)
- return false;
+ if (timestamp == served_date && expires == exp) {
+ // if the reply lacks LMT, then we now know that our effective
+ // LMT (i.e., timestamp) will stay the same, otherwise, old and
+ // new modification times must match
+ if (reply->last_modified < 0 || reply->last_modified == lastModified())
+ return false; // nothing has changed
+ }
expires = exp;
- lastmod = reply->last_modified;
+ lastModified_ = reply->last_modified;
timestamp = served_date;
debugs(20, l, "StoreEntry->timestamp: " << timestamp);
debugs(20, l, "StoreEntry->lastref: " << lastref);
debugs(20, l, "StoreEntry->expires: " << expires);
- debugs(20, l, "StoreEntry->lastmod: " << lastmod);
+ debugs(20, l, "StoreEntry->lastModified_: " << lastModified_);
debugs(20, l, "StoreEntry->swap_file_sz: " << swap_file_sz);
debugs(20, l, "StoreEntry->refcount: " << refcount);
debugs(20, l, "StoreEntry->flags: " << storeEntryFlags(this));
mem_obj->reset();
HttpReply *rep = (HttpReply *) getReply(); // bypass const
rep->reset();
- expires = lastmod = timestamp = -1;
+ expires = lastModified_ = timestamp = -1;
}
/*
}
bool
-StoreEntry::modifiedSince(HttpRequest * request) const
+StoreEntry::modifiedSince(const time_t ims, const int imslen) const
{
int object_length;
- time_t mod_time = lastmod;
-
- if (mod_time < 0)
- mod_time = timestamp;
+ const time_t mod_time = lastModified();
debugs(88, 3, "modifiedSince: '" << url() << "'");
if (object_length < 0)
object_length = contentLen();
- if (mod_time > request->ims) {
+ if (mod_time > ims) {
debugs(88, 3, "--> YES: entry newer than client");
return true;
- } else if (mod_time < request->ims) {
+ } else if (mod_time < ims) {
debugs(88, 3, "--> NO: entry older than client");
return false;
- } else if (request->imslen < 0) {
+ } else if (imslen < 0) {
debugs(88, 3, "--> NO: same LMT, no client length");
return false;
- } else if (request->imslen == object_length) {
+ } else if (imslen == object_length) {
debugs(88, 3, "--> NO: same LMT, same length");
return false;
} else {
return true;
}
+const char *
+StoreEntry::describeTimestamps() const
+{
+ LOCAL_ARRAY(char, buf, 256);
+ snprintf(buf, 256, "LV:%-9d LU:%-9d LM:%-9d EX:%-9d",
+ static_cast<int>(timestamp),
+ static_cast<int>(lastref),
+ static_cast<int>(lastModified_),
+ static_cast<int>(expires));
+ return buf;
+}
+
std::ostream &operator <<(std::ostream &os, const StoreEntry &e)
{
os << "e:";
what->timestamp = tmp->timestamp;
what->lastref = tmp->lastref;
what->expires = tmp->expires;
- what->lastmod = tmp->lastmod;
+ what->lastModified(tmp->lastmod);
what->swap_file_sz = tmp->swap_file_sz;
what->refcount = tmp->refcount;
what->flags = tmp->flags;
int StoreEntry::checkTooSmall() STUB_RETVAL(0)
void StoreEntry::delayAwareRead(const Comm::ConnectionPointer&, char *buf, int len, AsyncCall::Pointer callback) STUB
void StoreEntry::setNoDelay (bool const) STUB
-bool StoreEntry::modifiedSince(HttpRequest * request) const STUB_RETVAL(false)
+bool StoreEntry::modifiedSince(const time_t, const int) const STUB_RETVAL(false)
bool StoreEntry::hasIfMatchEtag(const HttpRequest &request) const STUB_RETVAL(false)
bool StoreEntry::hasIfNoneMatchEtag(const HttpRequest &request) const STUB_RETVAL(false)
Store::Disk &StoreEntry::disk() const STUB_RETREF(Store::Disk)
e->lastref = squid_curtime;
e->timestamp = squid_curtime;
e->expires = squid_curtime;
- e->lastmod = squid_curtime;
+ e->lastModified(squid_curtime);
e->refcount = 1;
EBIT_CLR(e->flags, RELEASE_REQUEST);
EBIT_CLR(e->flags, KEY_PRIVATE);
e->lastref = squid_curtime;
e->timestamp = squid_curtime;
e->expires = squid_curtime;
- e->lastmod = squid_curtime;
+ e->lastModified(squid_curtime);
e->refcount = 1;
EBIT_CLR(e->flags, RELEASE_REQUEST);
EBIT_CLR(e->flags, KEY_PRIVATE);