Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
95 commits
Select commit Hold shift + click to select a range
318a109
Add tiered storage component
jfantinhardesty May 27, 2026
0d5cbf3
Remove unused functions
jfantinhardesty May 27, 2026
7d93b2a
Initial structure setup(First commit)
Jun 2, 2026
f67f1d7
Initial attempt at openFile using design
Jun 3, 2026
0b27908
Rough Design of isOverLocalLimit and openFileHelper, logic added to O…
Jun 3, 2026
554a9b0
More structured design flow for OpenFile and setup of test file, firs…
Jun 4, 2026
d77b69f
Included function to make tests run, initial implementation of Create…
Jun 4, 2026
ddd1a1b
OpenFile now actually opens the file instead of just returning handle…
Jun 5, 2026
3218f91
Added WriteFile and dirty handle setters
Jun 5, 2026
de9b851
Added tests for open, write, create
Jun 5, 2026
598371b
Resolved most comments from initial PR, still have to work on error c…
Jun 5, 2026
3ed9612
Added OpenFile with O_create case
Jun 8, 2026
55f0dfa
Fixed O_Create and modified CreateFile (added unlocked internal funct…
Jun 8, 2026
ffc3909
Added initial ReleaseFile and uploadFile components
Jun 8, 2026
9cef74d
Implemented initial design of ReleaseFile and corresponding tests
Jun 9, 2026
6b919a0
Implemented initial design of ReleaseFile and corresponding tests
Jun 11, 2026
0b199fc
2nd PR Changes
Jun 11, 2026
d51bfe8
Initial ReadInBuffer component
Jun 11, 2026
d805f91
Added initial ReadInBuffer tests
Jun 15, 2026
432d54d
Initial implementation of DeleteFile, no tests yet
Jun 15, 2026
012bfc9
Resolved additional PR1 comments
Jun 24, 2026
2b914dd
Merge pull request #1 from HoJacob/feature/tiered_storage_setup
HoJacob Jun 25, 2026
2153f1e
Merge pull request #956 from HoJacob/feature/tiered_storage
jfantinhardesty Jun 25, 2026
628feaa
Initial LRU skeleton
Jun 25, 2026
2ccb80f
Initial LRU Functions
Jun 26, 2026
63b276c
LRU eviction initial implementation
Jun 29, 2026
ca744a6
LRU worker logic added
Jun 29, 2026
8e31b0c
Initial LRU Code w Workers/Eviction logic
Jun 29, 2026
ed56450
LRU capacity design fix
Jul 1, 2026
ea8b42a
Fixed deadlock bugs in channels
Jul 1, 2026
3ea1864
Initial test file setup
Jul 2, 2026
4b15841
Bug fixes and initial tests of lru eviction policy ready for pr draft
Jul 6, 2026
5e54e56
Feature/tiered storage/read in buffer (#959)
HoJacob Jul 6, 2026
449e766
Merge remote-tracking branch 'upstream/feature/tiered_storage' into f…
Jul 9, 2026
3f3a1b8
Handeled Dirty File State Scenario, ReleaseFile bugs, added Tests for…
Jul 13, 2026
74cce48
Changed all instances of normal map to sync.map
Jul 14, 2026
adef71e
Changed all instances of normal map to sync.map in TEST FILE NOW
Jul 14, 2026
e9dcb70
LRU Concurrency Design Implementation
Jul 17, 2026
13c608c
Fixed infinite loop logic and StopPolicy, old tests now work also tes…
Jul 20, 2026
8ac166b
Initial wiring of LRU Policy
Jul 20, 2026
d6c9a30
Wired LRU Policy with Tiered Storage, Implemented Tests against funct…
Jul 21, 2026
7a58ff6
Fixed DeleteFile and added in logic for edge case in LRU Policy
Jul 31, 2026
776d9b3
Tests for DeleteFile, still working on LRU Test
Aug 3, 2026
5a99492
Potential Fix for deadlock in Enqueue and Dequeue, manually unlocked …
Aug 4, 2026
37507f9
Something might be wrong with my vsCode that commit might not have wo…
Aug 4, 2026
ed6d5ed
Initial implementation of Sync and Flush, they are identical
Aug 4, 2026
880ab0e
WOW FINAL COMMIT MESSAGE SO COOL, added initial design of RenameFile,…
Aug 6, 2026
bb28d60
Merge pull request #960 from HoJacob/feature/tiered_storage-lru_policy
jfantinhardesty Aug 14, 2026
d34b4f4
Merge remote-tracking branch 'origin/main' into feature/tiered_storage
foodprocessor Aug 26, 2026
db88ac7
Add copyright notice
foodprocessor Aug 26, 2026
c741105
Make handleCount atomic
foodprocessor Aug 27, 2026
1b1631c
Opus 5: TS 5-10
foodprocessor Aug 27, 2026
403a1f6
Comments
foodprocessor Aug 31, 2026
6f04abc
Don't retry eviction
foodprocessor Aug 31, 2026
9f7825d
Cache used space
foodprocessor Aug 31, 2026
727fe53
Prevent path traversal exploits in local storage
foodprocessor Aug 31, 2026
6776993
Add local tier attribute lookup
foodprocessor Sep 1, 2026
299536c
Persist tiered storage state
foodprocessor Sep 1, 2026
ee89ba2
Honor file creation and open semantics
foodprocessor Sep 1, 2026
7b4bfc1
Merge local and cloud directory state
foodprocessor Sep 1, 2026
b883ff8
Normalize missing file delete errors
foodprocessor Sep 1, 2026
0a24d4a
Expand tiered storage coverage
foodprocessor Sep 1, 2026
fe54f7e
Don't buffer the upload channel
foodprocessor Sep 1, 2026
2d76d42
Remove resize (trivial wrapper for Add)
foodprocessor Sep 1, 2026
8713572
scrub reserveSpace
foodprocessor Sep 1, 2026
ec77960
Add comments
foodprocessor Sep 1, 2026
67de5b0
Simplify tiered storage LRU state
foodprocessor Sep 1, 2026
7a9a1ba
Trim tiered storage implementation
foodprocessor Sep 1, 2026
564cd8a
Stream tiered storage snapshots
foodprocessor Sep 1, 2026
c793782
Simplify tiered storage shutdown
foodprocessor Sep 1, 2026
ba0a0c2
Trim tiered storage LRU tests
foodprocessor Sep 1, 2026
bec401a
Combine tiered storage startup scans
foodprocessor Sep 1, 2026
2c2bc8b
Configure tiered storage eviction
foodprocessor Sep 1, 2026
51202ce
Validate tiered storage pipelines
foodprocessor Sep 1, 2026
6f34181
Document tiered storage configuration
foodprocessor Sep 1, 2026
41f6832
Implement tiered storage truncate
foodprocessor Sep 1, 2026
9dd752f
Delegate tiered storage symlinks
foodprocessor Sep 1, 2026
1d45ac9
Implement tiered storage metadata updates
foodprocessor Sep 1, 2026
ac933b0
Implement tiered storage directory rename
foodprocessor Sep 1, 2026
7f19ead
Report tiered storage capacity
foodprocessor Sep 1, 2026
c228602
Complete tiered storage interfaces
foodprocessor Sep 1, 2026
9c877b7
Test tiered storage recovery boundaries
foodprocessor Sep 1, 2026
acdfe8d
Add tiered storage mount smoke test
foodprocessor Sep 1, 2026
e5eed32
Address tiered storage lint
foodprocessor Sep 1, 2026
fc31563
Reword readme and change sample config to S3.
foodprocessor Sep 4, 2026
afe3922
Raise default thresholds to 80 90
foodprocessor Sep 8, 2026
6e8cebf
Update README
foodprocessor Sep 8, 2026
ab27843
Merge branch 'main' into feature/tiered_storage
foodprocessor Sep 10, 2026
88e9b92
Fix test lint
foodprocessor Sep 10, 2026
3815de0
Use subcomponent config pattern like file cache for the lru policy
foodprocessor Sep 10, 2026
b85b650
Use config struct in tests
foodprocessor Sep 10, 2026
224a187
Spelling
foodprocessor Sep 10, 2026
4f22b3e
Fix test to match new defaults
foodprocessor Sep 10, 2026
acb9dd6
Fix Windows error on absolute path
foodprocessor Sep 10, 2026
d221a90
Fix inexact eviction test
foodprocessor Sep 10, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 75 additions & 0 deletions .github/workflows/unit-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,81 @@ jobs:
go test -v -timeout=1h ./... --tags=unittest,azurite,fuse3
fi

- name: Tiered storage mount smoke test
if: matrix.job_name == 'linux-fuse3'
env:
S3_KEY_ID: ${{ env.AWS_ACCESS_KEY_ID }}
S3_SECRET_KEY: ${{ env.AWS_SECRET_ACCESS_KEY }}
S3_ENDPOINT: ${{ env.AWS_ENDPOINT }}
S3_REGION: ${{ env.AWS_REGION }}
S3_BUCKET_NAME: ${{ env.AWS_BUCKET_NAME }}
run: |
set -euo pipefail
MOUNT_DIR=/tmp/cloudfuse-tiered-mount
TIER_DIR=/tmp/cloudfuse-tiered-data
CONFIG=/tmp/cloudfuse-tiered.yaml
SOURCE=/tmp/cloudfuse-tiered-source
PERSISTENT=/tmp/cloudfuse-tiered-persistent
MOUNT_PID=

cleanup() {
if mountpoint -q "$MOUNT_DIR"; then
fusermount3 -u "$MOUNT_DIR" -z || true
fi
if [[ -n "$MOUNT_PID" ]]; then
kill "$MOUNT_PID" 2>/dev/null || true
fi
rm -rf "$MOUNT_DIR" "$TIER_DIR" "$CONFIG" "$SOURCE" "$PERSISTENT"
}
trap cleanup EXIT

mkdir -p "$MOUNT_DIR" "$TIER_DIR"
./cloudfuse gen-test-config \
--config-file=s3_key_tiered_storage.yaml \
--temp-path="$TIER_DIR" \
--output-file="$CONFIG"

mount_tiered() {
./cloudfuse mount "$MOUNT_DIR" --config-file="$CONFIG" --foreground=true &
MOUNT_PID=$!
for _ in {1..30}; do
mountpoint -q "$MOUNT_DIR" && return
sleep 1
done
return 1
}

unmount_tiered() {
fusermount3 -u "$MOUNT_DIR"
wait "$MOUNT_PID"
MOUNT_PID=
}

mount_tiered
head -c 900000 /dev/urandom > "$SOURCE"
cp "$SOURCE" "$MOUNT_DIR/evicted.bin"
for _ in {1..30}; do
aws --endpoint-url "$AWS_ENDPOINT" s3api head-object \
--bucket "$AWS_BUCKET_NAME" --key evicted.bin >/dev/null 2>&1 && break
sleep 1
done
aws --endpoint-url "$AWS_ENDPOINT" s3api head-object \
--bucket "$AWS_BUCKET_NAME" --key evicted.bin >/dev/null
test ! -e "$TIER_DIR/evicted.bin"
cmp "$SOURCE" "$MOUNT_DIR/evicted.bin"
test ! -e "$TIER_DIR/evicted.bin"

head -c 100000 /dev/urandom > "$PERSISTENT"
cp "$PERSISTENT" "$MOUNT_DIR/persistent.bin"
test -e "$TIER_DIR/persistent.bin"
unmount_tiered

mount_tiered
test -e "$TIER_DIR/persistent.bin"
cmp "$PERSISTENT" "$MOUNT_DIR/persistent.bin"
rm "$MOUNT_DIR/persistent.bin"
unmount_tiered

test:
name: Build and Test on Windows
environment: testing
Expand Down
21 changes: 18 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@

Cloudfuse provides the ability to mount a cloud bucket in your local filesystem on Linux and Windows.
With Cloudfuse you can easily read and write to the cloud, and connect programs on your computer to the cloud even if they're not cloud-aware.
Cloudfuse uses file caching to provide the performance of local storage, or you can use streaming mode to efficiently access small parts of large files (e.g. video playback).
Cloudfuse can run in two modes: caching, where the cloud is the source of truth and local disk holds a temporary copy for speed, or tiered storage, where local disk is the primary copy and the cloud is overflow for data that no longer fits locally.
Cloudfuse is a fork of [blobfuse2](https://github.com/Azure/azure-storage-fuse), and adds S3 support and Windows support.
Cloudfuse supports clouds with an S3 or Azure interface.

Expand Down Expand Up @@ -145,10 +145,10 @@ manually install Cloudfuse.

## Basic Use

The following describes how to use the Cloudfuse CLI. If you would like to use a GUI checkout the Cloudfuse GUI repo at <https://github.com/Seagate/cloudfuse-gui>.
The following describes how to use the Cloudfuse CLI.

1. Create a basic configuration file (TUI):
If you would like an easy way to get started with cloudfuse, run the following to launch a TUI to configure cloudfuse. If you prefer to configure manually, checkout how to write a config file: <https://github.com/Seagate/cloudfuse/wiki/Config-File>
If you would like an easy way to get started with cloudfuse, run the following to launch a TUI to configure cloudfuse. The TUI does not currently support tiering. If you prefer to configure manually, checkout how to write a config file: <https://github.com/Seagate/cloudfuse/wiki/Config-File>

```bash
cloudfuse config
Expand Down Expand Up @@ -314,6 +314,21 @@ Cloudfuse now supports offline access through the `file_cache` component. When c

> **Note:** Cloudfuse uses eventual consistency with last-writer-wins semantics. Offline access can extend the consistency window indefinitely and **increases the risk of data conflicts in multi-client setups!** See [component/file_cache/OfflineAccess.md](component/file_cache/OfflineAccess.md) for full details and configuration guidance.

## Tiered Storage

Use `tiered_storage` for on-prem-first configurations, when you want cloud storage to expand existing local storage. To minimize cloud storage costs, `tiered_storage` only maintains one copy of each file, moving old files to cloud storage once local storage fills up.

Note: Do not use `tiered_storage` if you use cloud storage to access your data remotely. Only overflow data will be present in the cloud.

See `sample_configs/sampleTieredStorageConfigS3.yaml` and `setup/baseConfig.yaml` for configuration.

### Expanding Existing Local Storage Using Tiered Storage

When using `tiered_storage` to add cloud capacity to an existing local storage location, please ensure all access is done through the Cloudfuse mount path / virtual drive. The `tiered_storage` `path` and all its existing contents will become *internal* local storage. Accessing the `tiered_storage` `path` directly may have unpredictable results.
For example, if you want expand the capacity of your existing local drive, `D:`, you could change that local drive's letter to `E:` first, then set `tiered_storage` `path` to `E:` and mount cloudfuse to `D:`. Then any existing applications or workflows that normally use `D:` would continue as normal, now pointed at the cloudfuse mount location.

**Cloudfuse may upload and delete local files under `path` as part of normal overflow eviction, so anything still reading or writing there directly can lose data or see missing files.**

## Limitations

### NOTICE
Expand Down
3 changes: 3 additions & 0 deletions cmd/imports.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,14 @@ import (
_ "github.com/Seagate/cloudfuse/component/attr_cache"
_ "github.com/Seagate/cloudfuse/component/azstorage"
_ "github.com/Seagate/cloudfuse/component/block_cache"
_ "github.com/Seagate/cloudfuse/component/custom"
_ "github.com/Seagate/cloudfuse/component/entry_cache"
_ "github.com/Seagate/cloudfuse/component/file_cache"
_ "github.com/Seagate/cloudfuse/component/libfuse"
_ "github.com/Seagate/cloudfuse/component/loopback"
_ "github.com/Seagate/cloudfuse/component/s3storage"
_ "github.com/Seagate/cloudfuse/component/size_tracker"
_ "github.com/Seagate/cloudfuse/component/stream"
_ "github.com/Seagate/cloudfuse/component/tiered_storage"
_ "github.com/Seagate/cloudfuse/component/xload"
)
11 changes: 11 additions & 0 deletions cmd/mount_linux_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -804,6 +804,17 @@ func (suite *mountTestSuite) TestCleanUpOnStartFlag() {
suite.assert.False(common.IsDirectoryEmpty(cachedirs[(i+1)%3]))
suite.assert.False(common.IsDirectoryEmpty(cachedirs[(i+2)%3]))
}

tieredPath := filepath.Join(testDir, "tiered")
err = os.MkdirAll(tieredPath, 0755)
suite.assert.NoError(err)
err = os.WriteFile(filepath.Join(tieredPath, "authoritative"), []byte("data"), 0644)
suite.assert.NoError(err)
config.Set("tiered_storage.path", tieredPath)
config.Set("cleanup-on-start", "true")
options.Components = []string{"tiered_storage"}
suite.assert.NoError(options.tempCacheCleanup())
suite.assert.False(common.IsDirectoryEmpty(tieredPath))
}

// TestValidateMountOptionsInvalidLogLevel tests validation with invalid log level
Expand Down
22 changes: 17 additions & 5 deletions common/lock_map.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ import (

// Lock item for each file
type LockMapItem struct {
handleCount uint32
handleCount atomic.Uint32
dirtyCount atomic.Uint32
mtx sync.RWMutex
downloadTime time.Time
Expand All @@ -54,7 +54,7 @@ func NewLockMap() *LockMap {

// Get the lock item based on file name, if item does not exists create it
func (l *LockMap) Get(name string) *LockMapItem {
lockIntf, _ := l.locks.LoadOrStore(name, &LockMapItem{handleCount: 0})
lockIntf, _ := l.locks.LoadOrStore(name, &LockMapItem{})
item := lockIntf.(*LockMapItem)
return item
}
Expand All @@ -75,6 +75,10 @@ func (l *LockMapItem) Unlock() {
l.mtx.Unlock()
}

func (l *LockMapItem) TryLock() bool {
return l.mtx.TryLock()
}

func (l *LockMapItem) RLock() {
l.mtx.RLock()
}
Expand All @@ -86,17 +90,25 @@ func (l *LockMapItem) RUnlock() {

// Increment the handle count
func (l *LockMapItem) Inc() {
l.handleCount++
l.handleCount.Add(1)
}

// Decrement the handle count
func (l *LockMapItem) Dec() {
l.handleCount--
for {
current := l.handleCount.Load()
if current == 0 {
return
}
if l.handleCount.CompareAndSwap(current, current-1) {
return
}
}
}

// Get the current handle count
func (l *LockMapItem) Count() uint32 {
return l.handleCount
return l.handleCount.Load()
}

// Increment dirty-handle count.
Expand Down
20 changes: 7 additions & 13 deletions common/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -618,20 +618,14 @@ func ComponentInPipeline(pipeline []string, component string) bool {
}

func ValidatePipeline(pipeline []string) error {
// file-cache, block-cache and xload are mutually exclusive
if ComponentInPipeline(pipeline, "file_cache") &&
ComponentInPipeline(pipeline, "block_cache") {
return fmt.Errorf("mount: file-cache and block-cache cannot be used together")
}

if ComponentInPipeline(pipeline, "file_cache") &&
ComponentInPipeline(pipeline, "xload") {
return fmt.Errorf("mount: file-cache and xload cannot be used together")
var selected []string
for _, component := range []string{"file_cache", "block_cache", "xload", "tiered_storage"} {
if ComponentInPipeline(pipeline, component) {
selected = append(selected, component)
}
}

if ComponentInPipeline(pipeline, "block_cache") &&
ComponentInPipeline(pipeline, "xload") {
return fmt.Errorf("mount: block-cache and xload cannot be used together")
if len(selected) > 1 {
return fmt.Errorf("mount: %s cannot be used together", strings.Join(selected, ", "))
}

return nil
Expand Down
12 changes: 12 additions & 0 deletions common/util_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -665,6 +665,15 @@ func (suite *utilTestSuite) TestValidatePipeline() {
err = ValidatePipeline([]string{"libfuse", "file_cache", "block_cache", "xload", "azstorage"})
suite.Error(err)

err = ValidatePipeline([]string{"libfuse", "file_cache", "tiered_storage", "azstorage"})
suite.Error(err)

err = ValidatePipeline([]string{"libfuse", "block_cache", "tiered_storage", "azstorage"})
suite.Error(err)

err = ValidatePipeline([]string{"libfuse", "xload", "tiered_storage", "azstorage"})
suite.Error(err)

err = ValidatePipeline([]string{"libfuse", "file_cache", "azstorage"})
suite.NoError(err)

Expand All @@ -673,6 +682,9 @@ func (suite *utilTestSuite) TestValidatePipeline() {

err = ValidatePipeline([]string{"libfuse", "xload", "attr_cache", "azstorage"})
suite.NoError(err)

err = ValidatePipeline([]string{"libfuse", "tiered_storage", "attr_cache", "azstorage"})
suite.NoError(err)
}

func (suite *utilTestSuite) TestUpdatePipeline() {
Expand Down
114 changes: 114 additions & 0 deletions component/tiered_storage/cache_size.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
/*
Licensed under the MIT License <http://opensource.org/licenses/MIT>.

Copyright © 2026 Seagate Technology LLC and/or its Affiliates

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE
*/

package tiered_storage

import (
"sync/atomic"
"time"

"github.com/Seagate/cloudfuse/common"
"github.com/Seagate/cloudfuse/common/log"
)

// driftWarnBytes is how far the running total may diverge from a measurement
// before the correction is worth a log line.
const driftWarnBytes = 16 * common.MbToBytes

// cacheSizeTracker tracks how many bytes of local storage the component is
// using.
//
// The total is maintained incrementally, because measuring it costs a du(1)
// subprocess on Linux and a full tree walk on Windows - far too expensive to do
// per write or per eviction tick. Incremental accounting drifts (directory
// entries, sparse files, anything that touches the cache directory behind our
// back), so Reconcile periodically replaces the total with a real measurement.
//
// Sizes are apparent bytes, matching `du -sb` on Linux. Windows measures
// allocated sectors instead, so the two platforms disagree slightly for small
// files; Reconcile is what keeps that from accumulating.
type cacheSizeTracker struct {
path string
used atomic.Int64
reconcileInterval time.Duration
lastReconcile atomic.Int64 // unix nanoseconds
}

func newCacheSizeTracker(path string, reconcileInterval time.Duration) *cacheSizeTracker {
t := &cacheSizeTracker{path: path, reconcileInterval: reconcileInterval}
t.lastReconcile.Store(time.Now().UnixNano())
return t
}

// Used returns the current cache usage in bytes.
func (t *cacheSizeTracker) Used() int64 {
return t.used.Load()
}

// Add applies a signed change in bytes. The total is clamped at zero: drift
// could otherwise drive it negative and hide a full cache.
func (t *cacheSizeTracker) Add(delta int64) {
if delta == 0 {
return
}
for {
current := t.used.Load()
next := max(current+delta, 0)
if t.used.CompareAndSwap(current, next) {
return
}
}
}

// Refresh measures the cache directory and replaces the running total.
// Changes made while the measurement is in flight are lost, which is inherent
// to reconciling against a moving target and is why it is not the hot path.
func (t *cacheSizeTracker) Refresh() {
t.lastReconcile.Store(time.Now().UnixNano())

usage, err := common.GetUsage(t.path)
if err != nil {
log.Err("cacheSizeTracker::Refresh : failed to measure %s [%v]", t.path, err)
return
}

measured := int64(usage)
previous := t.used.Swap(measured)
if drift := measured - previous; drift > driftWarnBytes || drift < -driftWarnBytes {
log.Info(
"cacheSizeTracker::Refresh : corrected usage by %d bytes (was %d, now %d)",
drift,
previous,
measured,
)
}
}

// Reconcile refreshes the running total, but no more often than reconcileInterval.
func (t *cacheSizeTracker) Reconcile() {
if time.Since(time.Unix(0, t.lastReconcile.Load())) < t.reconcileInterval {
return
}
t.Refresh()
}
Loading
Loading