-
Notifications
You must be signed in to change notification settings - Fork 232
refactor(lru): switch LRU implementation to golang-lru #3674
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 3 commits
ecb8eea
f68d61e
bfeda6c
3ad6be2
4354dd1
1d8d578
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -10,7 +10,8 @@ import ( | |
| "github.com/NethermindEth/juno/core/felt" | ||
| "github.com/NethermindEth/juno/core/pending" | ||
| "github.com/NethermindEth/juno/db" | ||
| "github.com/ethereum/go-ethereum/common/lru" | ||
| "github.com/NethermindEth/juno/utils" | ||
| "github.com/hashicorp/golang-lru/v2/simplelru" | ||
| "go.uber.org/zap" | ||
| ) | ||
|
|
||
|
|
@@ -130,7 +131,7 @@ func (s *Synchronizer) storeEmptyPreConfirmed( | |
| func (s *Synchronizer) handleTickerPreLatest( | ||
| ctx context.Context, | ||
| currentHead *core.Block, | ||
| seenByParent *lru.BasicLRU[felt.Felt, *pending.PreLatest], | ||
| seenByParent *simplelru.LRU[felt.Felt, *pending.PreLatest], | ||
| out chan<- *pending.PreLatest, | ||
| ) bool { | ||
| preLatest, err := s.dataSource.BlockPreLatest(ctx) | ||
|
|
@@ -168,7 +169,7 @@ func (s *Synchronizer) pollPreLatest(ctx context.Context, out chan<- *pending.Pr | |
|
|
||
| // Cache of pre-latest blocks keyed by the hash of their parent. | ||
| // When we receive the head with this parent hash, we emit the cached pre-latest. | ||
| seenByParent := lru.NewBasicLRU[felt.Felt, *pending.PreLatest](preLatestCacheSize) | ||
| seenByParent := utils.NewSimpleLRU[felt.Felt, *pending.PreLatest](preLatestCacheSize) | ||
|
|
||
| ticker := time.NewTicker(s.preLatestPollInterval) | ||
| defer ticker.Stop() | ||
|
|
@@ -219,7 +220,7 @@ func (s *Synchronizer) pollPreLatest(ctx context.Context, out chan<- *pending.Pr | |
| deliveredForHead = s.handleTickerPreLatest( | ||
| ctx, | ||
| currentHead, | ||
| &seenByParent, | ||
| seenByParent, | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It is great that you made |
||
| out, | ||
| ) | ||
| } | ||
|
|
||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am thinking it is better to create a package inside utils/lru/lru.go so that imports are called
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I see this comment was marked as resolved without being resolved, why?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it was updated in 3ad6be2. Let me know if that's not enough, or it's not what you meant.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe a git error, is not showing up in the diff
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @brbrr to clarify, we should have a |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| package utils | ||
|
|
||
| import ( | ||
| "fmt" | ||
|
|
||
| lru "github.com/hashicorp/golang-lru/v2" | ||
| "github.com/hashicorp/golang-lru/v2/simplelru" | ||
| ) | ||
|
|
||
| // NewLRU returns a new thread-safe LRU cache or panics if size <= 0. | ||
| // Use for caches sized by constants or validated config, where a zero size | ||
| // indicates a programmer error rather than a runtime condition. | ||
| func NewLRU[K comparable, V any](size int) *lru.Cache[K, V] { | ||
| c, err := lru.New[K, V](size) | ||
| if err != nil { | ||
| panic(fmt.Errorf("lru: %w (size=%d)", err, size)) | ||
| } | ||
| return c | ||
| } | ||
|
|
||
| // NewSimpleLRU returns a new non-thread-safe LRU cache or panics if size <= 0. | ||
| // Use the same way as NewLRU when external synchronization is provided | ||
| // (e.g. single-goroutine ownership). | ||
| func NewSimpleLRU[K comparable, V any](size int) *simplelru.LRU[K, V] { | ||
| c, err := simplelru.NewLRU[K, V](size, nil) | ||
| if err != nil { | ||
| panic(fmt.Errorf("simplelru: %w (size=%d)", err, size)) | ||
| } | ||
| return c | ||
|
brbrr marked this conversation as resolved.
Outdated
|
||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,66 @@ | ||
| package utils | ||
|
|
||
| import ( | ||
| "testing" | ||
|
|
||
| "github.com/stretchr/testify/assert" | ||
| "github.com/stretchr/testify/require" | ||
| ) | ||
|
|
||
| //nolint:dupl // duplicate tests as there's identical APIs | ||
| func TestNewLRU(t *testing.T) { | ||
| t.Run("returns usable cache for positive size", func(t *testing.T) { | ||
| c := NewLRU[string, int](2) | ||
| require.NotNil(t, c) | ||
| assert.Equal(t, 0, c.Len()) | ||
|
|
||
| c.Add("a", 1) | ||
| c.Add("b", 2) | ||
| assert.Equal(t, 2, c.Len()) | ||
|
|
||
| v, ok := c.Get("a") | ||
| assert.True(t, ok) | ||
| assert.Equal(t, 1, v) | ||
| }) | ||
|
|
||
| t.Run("panics on zero size", func(t *testing.T) { | ||
| assert.PanicsWithError(t, "lru: must provide a positive size (size=0)", func() { | ||
| NewLRU[string, int](0) | ||
| }) | ||
| }) | ||
|
|
||
| t.Run("panics on negative size", func(t *testing.T) { | ||
| assert.PanicsWithError(t, "lru: must provide a positive size (size=-1)", func() { | ||
| NewLRU[string, int](-1) | ||
| }) | ||
| }) | ||
| } | ||
|
|
||
| //nolint:dupl // duplicate tests as there's identical APIs | ||
| func TestNewSimpleLRU(t *testing.T) { | ||
| t.Run("returns usable cache for positive size", func(t *testing.T) { | ||
| c := NewSimpleLRU[string, int](2) | ||
| require.NotNil(t, c) | ||
| assert.Equal(t, 0, c.Len()) | ||
|
|
||
| c.Add("a", 1) | ||
| c.Add("b", 2) | ||
| assert.Equal(t, 2, c.Len()) | ||
|
|
||
| v, ok := c.Get("a") | ||
| assert.True(t, ok) | ||
| assert.Equal(t, 1, v) | ||
| }) | ||
|
|
||
| t.Run("panics on zero size", func(t *testing.T) { | ||
| assert.PanicsWithError(t, "simplelru: must provide a positive size (size=0)", func() { | ||
| NewSimpleLRU[string, int](0) | ||
| }) | ||
| }) | ||
|
|
||
| t.Run("panics on negative size", func(t *testing.T) { | ||
| assert.PanicsWithError(t, "simplelru: must provide a positive size (size=-1)", func() { | ||
| NewSimpleLRU[string, int](-1) | ||
| }) | ||
| }) | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know this is out of scope, but since we are touching it, could
NewAggregatedBloomCachereturn*AggregatedBloomFilterCache?Its methods are all pointer-receivers, so a pointer is more consistent and avoids copies diverging on
fallbackFuncin future uses.Also, it's only called in
blockchain.goand tests today, so the change stays small.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't make sense to me, can you explain what you mean? How having pointer receivers affects what the constructor should return?
This is a valid one.
Out of scope changes should be address in a different PR, let's try not squeeze them here