|
|
@ -170,12 +170,18 @@ func getMetadata(objInfo ObjectInfo) map[string]string { |
|
|
|
return metadata |
|
|
|
return metadata |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// marks cache hit
|
|
|
|
|
|
|
|
func (c *cacheObjects) incCacheStats(size int64) { |
|
|
|
|
|
|
|
c.cacheStats.incHit() |
|
|
|
|
|
|
|
c.cacheStats.incBytesServed(size) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func (c *cacheObjects) GetObjectNInfo(ctx context.Context, bucket, object string, rs *HTTPRangeSpec, h http.Header, lockType LockType, opts ObjectOptions) (gr *GetObjectReader, err error) { |
|
|
|
func (c *cacheObjects) GetObjectNInfo(ctx context.Context, bucket, object string, rs *HTTPRangeSpec, h http.Header, lockType LockType, opts ObjectOptions) (gr *GetObjectReader, err error) { |
|
|
|
if c.isCacheExclude(bucket, object) || c.skipCache() { |
|
|
|
if c.isCacheExclude(bucket, object) || c.skipCache() { |
|
|
|
return c.GetObjectNInfoFn(ctx, bucket, object, rs, h, lockType, opts) |
|
|
|
return c.GetObjectNInfoFn(ctx, bucket, object, rs, h, lockType, opts) |
|
|
|
} |
|
|
|
} |
|
|
|
var cc cacheControl |
|
|
|
var cc cacheControl |
|
|
|
|
|
|
|
var cacheObjSize int64 |
|
|
|
// fetch diskCache if object is currently cached or nearest available cache drive
|
|
|
|
// fetch diskCache if object is currently cached or nearest available cache drive
|
|
|
|
dcache, err := c.getCacheToLoc(ctx, bucket, object) |
|
|
|
dcache, err := c.getCacheToLoc(ctx, bucket, object) |
|
|
|
if err != nil { |
|
|
|
if err != nil { |
|
|
@ -184,12 +190,17 @@ func (c *cacheObjects) GetObjectNInfo(ctx context.Context, bucket, object string |
|
|
|
|
|
|
|
|
|
|
|
cacheReader, cacheErr := c.get(ctx, dcache, bucket, object, rs, h, opts) |
|
|
|
cacheReader, cacheErr := c.get(ctx, dcache, bucket, object, rs, h, opts) |
|
|
|
if cacheErr == nil { |
|
|
|
if cacheErr == nil { |
|
|
|
|
|
|
|
cacheObjSize = cacheReader.ObjInfo.Size |
|
|
|
|
|
|
|
if rs != nil { |
|
|
|
|
|
|
|
if _, len, err := rs.GetOffsetLength(cacheObjSize); err == nil { |
|
|
|
|
|
|
|
cacheObjSize = len |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
cc = cacheControlOpts(cacheReader.ObjInfo) |
|
|
|
cc = cacheControlOpts(cacheReader.ObjInfo) |
|
|
|
if (!cc.isEmpty() && !cc.isStale(cacheReader.ObjInfo.ModTime)) || |
|
|
|
if (!cc.isEmpty() && !cc.isStale(cacheReader.ObjInfo.ModTime)) || |
|
|
|
cc.onlyIfCached { |
|
|
|
cc.onlyIfCached { |
|
|
|
// This is a cache hit, mark it so
|
|
|
|
// This is a cache hit, mark it so
|
|
|
|
c.cacheStats.incHit() |
|
|
|
c.incCacheStats(cacheObjSize) |
|
|
|
c.cacheStats.incBytesServed(cacheReader.ObjInfo.Size) |
|
|
|
|
|
|
|
return cacheReader, nil |
|
|
|
return cacheReader, nil |
|
|
|
} |
|
|
|
} |
|
|
|
if cc.noStore { |
|
|
|
if cc.noStore { |
|
|
@ -198,11 +209,9 @@ func (c *cacheObjects) GetObjectNInfo(ctx context.Context, bucket, object string |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Reaching here implies cache miss
|
|
|
|
|
|
|
|
c.cacheStats.incMiss() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
objInfo, err := c.GetObjectInfoFn(ctx, bucket, object, opts) |
|
|
|
objInfo, err := c.GetObjectInfoFn(ctx, bucket, object, opts) |
|
|
|
if backendDownError(err) && cacheErr == nil { |
|
|
|
if backendDownError(err) && cacheErr == nil { |
|
|
|
|
|
|
|
c.incCacheStats(cacheObjSize) |
|
|
|
return cacheReader, nil |
|
|
|
return cacheReader, nil |
|
|
|
} else if err != nil { |
|
|
|
} else if err != nil { |
|
|
|
if _, ok := err.(ObjectNotFound); ok { |
|
|
|
if _, ok := err.(ObjectNotFound); ok { |
|
|
@ -213,10 +222,12 @@ func (c *cacheObjects) GetObjectNInfo(ctx context.Context, bucket, object string |
|
|
|
dcache.Delete(ctx, bucket, object) |
|
|
|
dcache.Delete(ctx, bucket, object) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
c.cacheStats.incMiss() |
|
|
|
return nil, err |
|
|
|
return nil, err |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if !objInfo.IsCacheable() { |
|
|
|
if !objInfo.IsCacheable() { |
|
|
|
|
|
|
|
c.cacheStats.incMiss() |
|
|
|
return c.GetObjectNInfoFn(ctx, bucket, object, rs, h, lockType, opts) |
|
|
|
return c.GetObjectNInfoFn(ctx, bucket, object, rs, h, lockType, opts) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -225,6 +236,7 @@ func (c *cacheObjects) GetObjectNInfo(ctx context.Context, bucket, object string |
|
|
|
if cacheReader.ObjInfo.ETag == objInfo.ETag { |
|
|
|
if cacheReader.ObjInfo.ETag == objInfo.ETag { |
|
|
|
// Update metadata in case server-side copy might have changed object metadata
|
|
|
|
// Update metadata in case server-side copy might have changed object metadata
|
|
|
|
dcache.updateMetadataIfChanged(ctx, bucket, object, objInfo, cacheReader.ObjInfo) |
|
|
|
dcache.updateMetadataIfChanged(ctx, bucket, object, objInfo, cacheReader.ObjInfo) |
|
|
|
|
|
|
|
c.incCacheStats(cacheObjSize) |
|
|
|
return cacheReader, nil |
|
|
|
return cacheReader, nil |
|
|
|
} |
|
|
|
} |
|
|
|
cacheReader.Close() |
|
|
|
cacheReader.Close() |
|
|
@ -232,6 +244,8 @@ func (c *cacheObjects) GetObjectNInfo(ctx context.Context, bucket, object string |
|
|
|
c.delete(ctx, dcache, bucket, object) |
|
|
|
c.delete(ctx, dcache, bucket, object) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Reaching here implies cache miss
|
|
|
|
|
|
|
|
c.cacheStats.incMiss() |
|
|
|
// Since we got here, we are serving the request from backend,
|
|
|
|
// Since we got here, we are serving the request from backend,
|
|
|
|
// and also adding the object to the cache.
|
|
|
|
// and also adding the object to the cache.
|
|
|
|
if !dcache.diskUsageLow() { |
|
|
|
if !dcache.diskUsageLow() { |
|
|
@ -304,25 +318,28 @@ func (c *cacheObjects) GetObjectInfo(ctx context.Context, bucket, object string, |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Reaching here implies cache miss
|
|
|
|
|
|
|
|
c.cacheStats.incMiss() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
objInfo, err := getObjectInfoFn(ctx, bucket, object, opts) |
|
|
|
objInfo, err := getObjectInfoFn(ctx, bucket, object, opts) |
|
|
|
if err != nil { |
|
|
|
if err != nil { |
|
|
|
if _, ok := err.(ObjectNotFound); ok { |
|
|
|
if _, ok := err.(ObjectNotFound); ok { |
|
|
|
// Delete the cached entry if backend object was deleted.
|
|
|
|
// Delete the cached entry if backend object was deleted.
|
|
|
|
c.delete(ctx, dcache, bucket, object) |
|
|
|
c.delete(ctx, dcache, bucket, object) |
|
|
|
|
|
|
|
c.cacheStats.incMiss() |
|
|
|
return ObjectInfo{}, err |
|
|
|
return ObjectInfo{}, err |
|
|
|
} |
|
|
|
} |
|
|
|
if !backendDownError(err) { |
|
|
|
if !backendDownError(err) { |
|
|
|
|
|
|
|
c.cacheStats.incMiss() |
|
|
|
return ObjectInfo{}, err |
|
|
|
return ObjectInfo{}, err |
|
|
|
} |
|
|
|
} |
|
|
|
if cerr == nil { |
|
|
|
if cerr == nil { |
|
|
|
|
|
|
|
// This is a cache hit, mark it so
|
|
|
|
|
|
|
|
c.cacheStats.incHit() |
|
|
|
return cachedObjInfo, nil |
|
|
|
return cachedObjInfo, nil |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
c.cacheStats.incMiss() |
|
|
|
return ObjectInfo{}, BackendDown{} |
|
|
|
return ObjectInfo{}, BackendDown{} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// Reaching here implies cache miss
|
|
|
|
|
|
|
|
c.cacheStats.incMiss() |
|
|
|
// when backend is up, do a sanity check on cached object
|
|
|
|
// when backend is up, do a sanity check on cached object
|
|
|
|
if cerr != nil { |
|
|
|
if cerr != nil { |
|
|
|
return objInfo, nil |
|
|
|
return objInfo, nil |
|
|
|