This repository has been archived by the owner on Dec 12, 2024. It is now read-only.
generated from TBD54566975/tbd-project-template
-
Notifications
You must be signed in to change notification settings - Fork 55
Fix Redis pagination issue in readAllKeys function #576
Open
radurobot
wants to merge
8
commits into
TBD54566975:main
Choose a base branch
from
radurobot:fix/redis-pagination-issue-538
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 5 commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
f39ac8e
Fix Redis pagination issue in readAllKeys function
c41318f
Merge branch 'main' into fix/redis-pagination-issue-538
decentralgabe fdf9390
Merge branch 'main' into fix/redis-pagination-issue-538
decentralgabe fc8e456
Merge branch 'main' into fix/redis-pagination-issue-538
andresuribe87 ff12b6e
Merge branch 'main' into fix/redis-pagination-issue-538
andresuribe87 0b28b1b
Refactor RedisDB's ReadPage function to use a PageToken struct for cu…
d88f9ea
Merge branch 'main' into fix/redis-pagination-issue-538
andresuribe87 2a49342
Merge branch 'main' into fix/redis-pagination-issue-538
andresuribe87 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
Could this be simplified by using
b.db.Scan(ctx, cursor, namespace+"*", int64(scanCount)).Iterator()
above?(as it happens, I also think there might be an implementation error right now, where only a subset of keys are returned)
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 @andresuribe87, it's possible, but ...
While the iterator provides a more convenient way to iterate over the keys returned by the Scan method, it does not provide a way to retrieve the current cursor value. As a result, a call to the Scan method is still necessary to retrieve the next cursor value. This allows us to keep the same function signature as the original implementation, which includes returning the next cursor value as a string.
I'm not sure if it's a good practice, calling the Scan method again after using the iterator to retrieve the next cursor value is redundant and inefficient. A more efficient approach would be to use only the Scan method without using an iterator. This avoids the need for an additional call to the Scan method to retrieve the next cursor value.
I see these options:
Scan
.Iterator
and then callScan
to get the cursor.If changing the function signature, we can support pagination without having a cursor by using an offset:
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.
Ah yes, excellent point.
Changing the function's signature seems like the best approach to me. I suggest keeping the
cursor
, and addingoffsetFromCursor int
. It's important to keep the cursor because it's propagated from the API.You'll likely also need to change the way in which the token is parsed in
ssi-service/pkg/storage/redis.go
Lines 37 to 43 in c8541a8
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.
Since it’s important to keep the cursor because it’s propagated from the API, using an approach that doesn’t support cursor-based pagination may not be suitable. It’s not possible to use the Iterator method to implement pagination in the same way as the original
readAllKeys
. As I said previously, one possible solution would be to modify the readAllKeys function to use a different approach for pagination, such as using an offset and limit instead of a cursor. However, this would require removing the cursor.I considered the possibility of manually calculating the cursor value inside the readAllKeys function while using the Iterator method. However, this is not possible because the cursor value is an internal implementation detail of the Redis
SCAN
command, and its value is determined by the Redis server based on the current state of the key space. The only way to retrieve the updated cursor value is to use theScan
method, which returns the next cursor value along with the keys.Hence, using
Iterator()
and keeping the cursor value updated it's not a possibility.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 agree. I don't think I was clear with my suggestion, my apologies. What I'm proposing is to keep cursor as a parameter, as well as adding an additional parameter called
offsetFromCursor
.Scan
would still be used, instead ofIterator
. Then, the function can start populating the result to return by making a Scan call from the given cursor, and only adding elements if they're greater than or equal to theoffsetFromCursor
. Does that make 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.
Okay, so we can have add a new type to the Redis struct:
This will be used as the new parameter.
In readAllKeys we'll read until
i >= int(b.offsetFromCursor)
.We can also have a new method to update the
offsetFromCursor
:However this change will impact all services that use this package. The
offsetFromCursor
needs to be updated but I'm not sure where.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.
The parameter
offsetFromCursor
is something that changes with every request, so I would expect it to be a parameter to thereadAllKeys
function. Can you elaborate on the advantages of putting in in the RedisDB struct? Keep in mind that the RedisDB struct is long lived.What I was imagining is something were the signature of the function becomes the following:
The implementation should add up to
pageSize
elements toallKeys
by:Scan
with the givencursor
valueoffsetFromCursor
index.When there are enough elements returned from
Scan
to be able to fill upallKeys
to the desiredpageSize
, thennextOffsetFromCursor
should increment bypageSize
. Otherwise, you should keep iterating over the results from the DB until the previous condition happens.As far as passing in the
offsetFromCursor
parameter from the callers, below is an example of what I was thinking:Does that all make 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.
Okay, so something like this should do the job:
@andresuribe87 what do you think?
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 think so, yes! This is awesome, thanks so much @radurobot
Just a note: I don't trust my eyes as much as I would trust tests :)