()
| 130 | cacheEvictionReasonEntry cacheEvictionReason = "entry" |
| 131 | cacheEvictionReasonByte cacheEvictionReason = "byte" |
| 132 | ) |
| 133 | |
| 134 | // CacheKey computes a deterministic cache key from a tenant scope, a full |
| 135 | // URL, and a byte range. The URL includes scheme, host, path, and query — so |
| 136 | // different buckets, regions, or query-signed URLs naturally produce |
| 137 | // different keys. The scope is the SigV4 access key ID (see TenantScope), so |
| 138 | // two tenants reading the same object URL never share an entry. |
| 139 | // |
| 140 | // Hash input format: scope + "\x00" + url + "|" + range. The NUL separator |
| 141 | // makes the scope boundary unambiguous: no URL or range byte sequence can |
| 142 | // shift bytes into or out of the scope field. |
| 143 | func CacheKey(scope, url, rangeHeader string) string { |
| 144 | h := sha256.New() |
| 145 | _, _ = fmt.Fprintf(h, "%s\x00%s|%s", scope, url, rangeHeader) |
| 146 | return fmt.Sprintf("%x", h.Sum(nil)) |
| 147 | } |
| 148 | |
| 149 | // DiskCache manages cached S3 responses on local NVMe storage with LRU eviction. |
| 150 | // |
| 151 | // Every operation below holds the one mutex, and a production node tracks |
| 152 | // hundreds of thousands of entries — so each critical section must be O(1). |
| 153 | // The previous slice-based order ([]cacheEntry with linear scans and splices) |
| 154 | // put ~half the proxy's CPU into LRU bookkeeping under this lock, serializing |
| 155 | // all cache traffic behind it. |
| 156 | type DiskCache struct { |
| 157 | dir string |
| 158 | // maxBytes is the eviction threshold. The constructor sets it to |
| 159 | // maxPercent of the filesystem's TOTAL bytes, and the background refresh |
| 160 | // loop (refreshCapacity) lowers it whenever FREE space shrinks so the |
| 161 | // cache can never grow into disk it doesn't own. currentSize is the sum |
| 162 | // of tracked entry sizes. |
| 163 | maxBytes int64 |
| 164 | maxEntries int |
no test coverage detected