Skip to content

Feature/tiered storage lru policy#960

Draft
HoJacob wants to merge 17 commits into
Seagate:feature/tiered_storagefrom
HoJacob:feature/tiered_storage-lru_policy
Draft

Feature/tiered storage lru policy#960
HoJacob wants to merge 17 commits into
Seagate:feature/tiered_storagefrom
HoJacob:feature/tiered_storage-lru_policy

Conversation

@HoJacob

@HoJacob HoJacob commented Jul 6, 2026

Copy link
Copy Markdown

What type of Pull Request is this? (check all applicable)

  • Refactor
  • Feature
  • Bug Fix
  • Optimization
  • Documentation Update

Describe your changes in brief

LRU initial implementation

Checklist

  • Tested locally
  • Added new dependencies
  • Updated documentation
  • Added tests

Related Issues

  • Related Issue #
  • Closes #

@foodprocessor foodprocessor left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very good work! Good design, solid choices.
The function pointers are a very clever way to maintain modularity. Nice touch!

Comment thread component/tiered_storage/lru_policy.go
Comment on lines +175 to +200
// eviction

//check du , do stat file before, based on difference between DU and

//1. check if we need eviction
curSize, err := common.GetUsage(q.cachePath)
if err != nil {
log.Err("lruPolicy::capacityChecker : failed to get usage: %v", err)
continue
}
if curSize/q.maxCacheSize <= q.threshold {
break
}

//targetRatio should always be less than thresholdRatio

//find difference to evict down to 60%
difference := curSize - q.maxCacheSize*q.targetRatio
curEvictedSpace := 0
for curEvictedSpace < int(difference) {
nodeSize, evicted := q.eviction()
if !evicted {
break
}
curEvictedSpace += int(nodeSize)
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good!
Later on, when we're looking at concurrency, let's make sure this code can't run more than once at a time (if the ticker is faster than eviction, we don't begin another eviction loop in parallel).

Comment on lines +243 to +244
q.extractNode(nodeToEvict)
q.nodeMap.Delete(nodeToEvict.name)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a rule we want to follow, for what node membership in the map and the linked list mean? In other words, should we update our records and then execute the action (upload & delete), or visa versa? Which is better for error handling?

Comment on lines +100 to +114
//create node
newNode := &lruNode{name: name}
val, found := q.nodeMap.LoadOrStore(name, newNode)
node := val.(*lruNode)

if found {
// touch
q.extractNode(node)
} else {
// brand new node — update tail if list was empty
if q.tail == nil {
q.tail = node
}
}
q.setHead(node)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This creates a new node before searching for an existing one. It still does what we expect in the end, but it smells off.

//create node
newNode := &lruNode{name: name}
val, found := q.nodeMap.LoadOrStore(name, newNode)
node := val.(*lruNode)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, dereferencing / type asserting val before we know if val was found makes me nervous. I figure it's probably fine and just returns nil in practice, but from my experience with C, I see echoes of "nil pointer dereference" here.

@jfantinhardesty jfantinhardesty left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work! This is a strong start to the LRU policy. Just have a few comments.

}
nodeSize := fileInfo.Size()

//remove node from queue and map

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the eviction code here, you delete from the LRU, but the file will still remain in the local cache? Do we want the file to stay in the cache or should we delete it when we evict?

}

// 6. Eviction, file with open handle, file with no open handle,
func (suite *lruPolicyTestSuite) TestCapacityCheckerEvictionOpenHandle() {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test is a bit flaky. The sleep could probably be a bit longer. Here is how you can replicate it.

go test -run TestLRUPolicyTestSuite ./component/tiered_storage --tags=unittest,fuse3 -count=50

You should see by running the unit tests 50 times that this test and a few others may fail.

}

//find the first applicable node
for nodeToEvict != nil && q.FileHasOpenFileHandle(nodeToEvict.name) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there could be a race condition here. After this check, it is possible that a new request comes in that opens the file before it gets uploaded.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants