-
Notifications
You must be signed in to change notification settings - Fork 1.7k
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
[FUN-973] s4 snapshot caching #12275
Conversation
8d415c1
to
4ca8dd6
Compare
I see that you haven't updated any CHANGELOG files. Would it make sense to do so? |
4ca8dd6
to
051cd9e
Compare
051cd9e
to
1652ecd
Compare
1652ecd
to
a025fbc
Compare
a025fbc
to
7af9645
Compare
7af9645
to
d0fe543
Compare
d0fe543
to
3beb238
Compare
3beb238
to
29a1558
Compare
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.
looks reasonable!
return c.underlayingORM.GetUnconfirmedRows(limit, qopts...) | ||
} | ||
|
||
func (c CachedORM) clearCache(row *Row) error { |
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'm not sure if returning an error from this method has any value. If any of the three error cases below happen, we should simply delete the key and continue iterating in the loop.
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.
makes sense! added the changes 👍🏼
} | ||
|
||
func (c CachedORM) DeleteExpired(limit uint, utcNow time.Time, qopts ...pg.QOpt) (int64, error) { | ||
return c.underlayingORM.DeleteExpired(limit, utcNow, qopts...) |
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 wonder if we should clear the cache here if DeleteExpired removed any entries.
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.
💡 good idea, I'll flush the cache to start fresh given there is no way of knowing what was deleted
for key := range c.cache.Items() { | ||
keyParts := strings.Split(key, "_") | ||
if len(keyParts) != 3 { | ||
c.lggr.Errorf("invalid cache key: %s", key) |
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.
Still delete the key on every error? We don't want any invalid keys in the cache anyway.
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.
got it, I've addressed it on this commit.
I changed it slightly to delete only if the key is a GetSnapshot key and it fails to parse the addresses.
I think this is safer, because if at some point we decide to add a cache layer to the eg the Get(address *ubig.Big, slotId uint, qopts ...pg.QOpt) (*Row, error)
this will wrongly delete records and it will be painful to find why.
Worst case scenario if the key is wrong it will die because of the TTL, wdyt?
"strings" | ||
"time" | ||
|
||
"github.com/patrickmn/go-cache" |
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 dependency must already exist I suppose since I don't see any changes to the go.mod file
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.
yes! the evmregistry is already using it
) | ||
|
||
// CachedORM is a cached orm wrapper that implements the ORM interface. | ||
// It adds a cache layer in order to remove unnecessary preassure to the underlaying implementation |
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.
nit: spelling of pressure
continue | ||
} | ||
|
||
if row.Address.ToInt().Cmp(minAddress) >= 0 && row.Address.ToInt().Cmp(maxAddress) <= 0 { |
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 am trying to understand a case where this would not be true...
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.
S4 supports snapshot sharding.
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.
Gotcha. I re-read the CLIP and this now makes sense.
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.
yes, we want to only delete the cached snapshots that its addressRange contain a specific row. Just to avoid deleting snapshots that are not affected
return cached.([]*SnapshotRow), nil | ||
} | ||
|
||
c.lggr.Info("Snapshot not found in cache, fetching it from underlaying implementation") |
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.
Nit: this could probably be debug level
} | ||
|
||
if deletedRows > 0 { | ||
c.cache.Flush() |
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.
Why do we need to flush the entire cache every time a single row is expired?
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.
more ctx here but basically its because we know some rows where deleted, but we don't know which ones, so the best effort on keeping the cache sync is to flush it
Quality Gate passedIssues Measures |
* feat: s4 get snapshot cached * chore: log and continue in case of error cleaning the cache * feat: flush cache in case of deleting expired from underlaying orm * feat: delete invalid keys * chore: typo + log level
Description
This pr introduces a s4 orm cache wrapper that accepts a ORM interface and wraps it with a in memory cache layer.
At the moment we are only focusing on caching the retrieve of
Snapshots
but the rest of the methods can also be cached if needed.the
Update
method will invalidate the cache only if the given address is within the range of address cached.