From 9199033db7bd1cd4de6dee7e38ab7c4d4e7e41aa Mon Sep 17 00:00:00 2001 From: poornas Date: Fri, 10 Jan 2020 20:21:13 -0800 Subject: [PATCH] Set X-Cache and X-Cache-Lookup headers for cache (#8794) X-Cache sets cache status of HIT if object is served from the disk cache, or MISS otherwise. X-Cache-Lookup is set to HIT if object was found in the cache even if not served (for e.g. if cache entry was invalidated by ETag verification) --- cmd/api-headers.go | 5 ++++- cmd/disk-cache-backend.go | 6 ++++-- cmd/disk-cache-utils.go | 18 ++++++++++++++++++ cmd/disk-cache.go | 20 +++++++++++++------- cmd/http/headers.go | 6 ++++++ cmd/object-api-datatypes.go | 5 +++++ 6 files changed, 50 insertions(+), 10 deletions(-) diff --git a/cmd/api-headers.go b/cmd/api-headers.go index 19e8f178e..5f47d562e 100644 --- a/cmd/api-headers.go +++ b/cmd/api-headers.go @@ -91,7 +91,10 @@ func setObjectHeaders(w http.ResponseWriter, objInfo ObjectInfo, rs *HTTPRangeSp if !objInfo.Expires.IsZero() { w.Header().Set(xhttp.Expires, objInfo.Expires.UTC().Format(http.TimeFormat)) } - + if globalCacheConfig.Enabled { + w.Header().Set(xhttp.XCache, objInfo.CacheStatus.String()) + w.Header().Set(xhttp.XCacheLookup, objInfo.CacheLookupStatus.String()) + } // Set all other user defined metadata. for k, v := range objInfo.UserDefined { if HasPrefix(k, ReservedMetadataPrefix) { diff --git a/cmd/disk-cache-backend.go b/cmd/disk-cache-backend.go index 2f94d94c4..aaa4fa8bc 100644 --- a/cmd/disk-cache-backend.go +++ b/cmd/disk-cache-backend.go @@ -89,8 +89,10 @@ func (m *cacheMeta) ToObjectInfo(bucket, object string) (o ObjectInfo) { } o = ObjectInfo{ - Bucket: bucket, - Name: object, + Bucket: bucket, + Name: object, + CacheStatus: CacheHit, + CacheLookupStatus: CacheHit, } // We set file info only if its valid. diff --git a/cmd/disk-cache-utils.go b/cmd/disk-cache-utils.go index 5f03c52a4..9c97df74c 100644 --- a/cmd/disk-cache-utils.go +++ b/cmd/disk-cache-utils.go @@ -28,6 +28,24 @@ import ( "github.com/minio/minio/cmd/crypto" ) +// CacheStatusType - whether the request was served from cache. +type CacheStatusType string + +const ( + // CacheHit - whether object was served from cache. + CacheHit CacheStatusType = "HIT" + + // CacheMiss - object served from backend. + CacheMiss CacheStatusType = "MISS" +) + +func (c CacheStatusType) String() string { + if c != "" { + return string(c) + } + return string(CacheMiss) +} + type cacheControl struct { expiry time.Time maxAge int diff --git a/cmd/disk-cache.go b/cmd/disk-cache.go index be69a999f..e61c6ce4f 100644 --- a/cmd/disk-cache.go +++ b/cmd/disk-cache.go @@ -223,7 +223,10 @@ func (c *cacheObjects) GetObjectNInfo(ctx context.Context, bucket, object string } if cc.noStore { c.cacheStats.incMiss() - return c.GetObjectNInfo(ctx, bucket, object, rs, h, lockType, opts) + bReader, err := c.GetObjectNInfo(ctx, bucket, object, rs, h, lockType, opts) + bReader.ObjInfo.CacheLookupStatus = CacheHit + bReader.ObjInfo.CacheStatus = CacheMiss + return bReader, err } } @@ -272,8 +275,14 @@ func (c *cacheObjects) GetObjectNInfo(ctx context.Context, bucket, object string default: } } + + bkReader, bkErr := c.GetObjectNInfoFn(ctx, bucket, object, rs, h, lockType, opts) + // Record if cache has a hit that was invalidated by ETag verification + if cacheErr == nil { + bkReader.ObjInfo.CacheLookupStatus = CacheHit + } if !dcache.diskAvailable(objInfo.Size) { - return c.GetObjectNInfoFn(ctx, bucket, object, rs, h, lockType, opts) + return bkReader, bkErr } if rs != nil { @@ -290,12 +299,9 @@ func (c *cacheObjects) GetObjectNInfo(ctx context.Context, bucket, object string c.put(ctx, dcache, bucket, object, bReader, bReader.ObjInfo.Size, rs, ObjectOptions{UserDefined: getMetadata(bReader.ObjInfo)}) } }() - return c.GetObjectNInfoFn(ctx, bucket, object, rs, h, lockType, opts) - } - bkReader, bkErr := c.GetObjectNInfoFn(ctx, bucket, object, rs, h, lockType, opts) - if bkErr != nil { - return nil, bkErr + return bkReader, bkErr } + // Initialize pipe. pipeReader, pipeWriter := io.Pipe() teeReader := io.TeeReader(bkReader, pipeWriter) diff --git a/cmd/http/headers.go b/cmd/http/headers.go index 14c26e794..86326f8c8 100644 --- a/cmd/http/headers.go +++ b/cmd/http/headers.go @@ -40,6 +40,12 @@ const ( Action = "Action" ) +// Non standard S3 HTTP response constants +const ( + XCache = "X-Cache" + XCacheLookup = "X-Cache-Lookup" +) + // Standard S3 HTTP request constants const ( IfModifiedSince = "If-Modified-Since" diff --git a/cmd/object-api-datatypes.go b/cmd/object-api-datatypes.go index b38367e2a..0a40f7aef 100644 --- a/cmd/object-api-datatypes.go +++ b/cmd/object-api-datatypes.go @@ -143,6 +143,11 @@ type ObjectInfo struct { // Date and time at which the object is no longer able to be cached Expires time.Time + // CacheStatus sets status of whether this is a cache hit/miss + CacheStatus CacheStatusType + // CacheLookupStatus sets whether a cacheable response is present in the cache + CacheLookupStatus CacheStatusType + // Specify object storage class StorageClass string