-
Notifications
You must be signed in to change notification settings - Fork 11.2k
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
Fix Dynamic Field Cursor Index Bug #11789
Conversation
The latest updates on your projects. Learn more about Vercel for Git ↗︎ |
@oxade , thanks for the fix! Could you elaborate on what caused the bug and how this PR fixed it? |
For Dynamic Object Fields, there are 3 different IDs at play: The DB key is type There were two potential fixes:
For example the structure in the DB is: If the query is made with a limit of 3, the returned cursor will be The solution in this code changes the cursor to return the |
## Description Fixes dynamic field pagination/cursor issue: #7686 ## Test Plan Manual testing --- If your changes are not user-facing and not a breaking change, you can skip the following section. Otherwise, please indicate what changed, and then add to the Release Notes section as highlighted during the release process. ### Type of Change (Check all that apply) - [x] user-visible impact - [ ] breaking change for a client SDKs - [ ] breaking change for FNs (FN binary must upgrade) - [ ] breaking change for validators or node operators (must upgrade binaries) - [ ] breaking change for on-chain data layout - [ ] necessitate either a data wipe or data migration ### Release notes
## Description Cherrypick of #11789 Fixes dynamic field pagination/cursor issue: #7686 ## Test Plan Manual testing --- If your changes are not user-facing and not a breaking change, you can skip the following section. Otherwise, please indicate what changed, and then add to the Release Notes section as highlighted during the release process. ### Type of Change (Check all that apply) - [x] user-visible impact - [ ] breaking change for a client SDKs - [ ] breaking change for FNs (FN binary must upgrade) - [ ] breaking change for validators or node operators (must upgrade binaries) - [ ] breaking change for on-chain data layout - [ ] necessitate either a data wipe or data migration ### Release notes ## Description Describe the changes or additions included in this PR. ## Test Plan How did you test the new or updated feature? --- If your changes are not user-facing and not a breaking change, you can skip the following section. Otherwise, please indicate what changed, and then add to the Release Notes section as highlighted during the release process. ### Type of Change (Check all that apply) - [ ] user-visible impact - [ ] breaking change for a client SDKs - [ ] breaking change for FNs (FN binary must upgrade) - [ ] breaking change for validators or node operators (must upgrade binaries) - [ ] breaking change for on-chain data layout - [ ] necessitate either a data wipe or data migration ### Release notes
So this means that the cursors returned will no longer be the actual object ids, and we will have to keep this implementation detail in our code if we later need to continue retrieving from the last retrieved DF? 😢 malaise just to be sure, the ordering of the child objects (including dof_wrapper and child ids) can only ever increase right? Or can future dfs be inserted in between the ones we see here? (For eg where there is a gap between the wrapper_ids) |
Yes. Unfortunately its a choice between that, and having invalid data returned.
Since object ids are randomly generated, anything can be inserted anywhere as our DB only cares about lexicographic key ordering. So yes gaps can be filled at any point. |
Ah I see! Unfortunate that both behave differently, since this will definitely cause confusion to people using both. But it is what it is.
I see. This is the biggest point we would like to see improved.
|
If the cursor is used strictly as a cursor without assuming it holds any other meaning, there should be no confusion either way as it operates the same way in both cases. It just so happens to match the underlying object id for DF.
what is "ts"? |
timestamp sorry. Like "retrieve all DFs added some timestampMS=..." |
Description
Fixes: #7686
For Dynamic Object Fields, there are 3 different IDs at play:
parent_id
: the ID of the parent objectdof_wrapper_id
: the ID of the wrapper dynamic field which wraps the actual child object. This is an implementation detail of dynamic object fields.child_object_id
: the ID of the inner child object. This is the real object users are interested in.The DB key is type
DynamicFieldKey
which is setup as(parent_id, dof_wrapper_id)
, and valueDynamicFieldInfo
which containschild_object_id
But the old code was returning
child_object_id
as cursor instead ofdof_wrapper_id
, which means when you try to find the next page, the cursor does not exist in the DB keys so the search lands on the first entry closest to(parent_id, child_object_id)
.There were two potential fixes:
(parent_id, child_object_id)
. This is more user friendly as the cursor is the direct object people care about. However this would break existing DB entries.dof_wrapper_id
so that subsequent queries are keyed properly. Althoughdof_wrapper_id
is just an indirection on thechild_object_id
and does not show up in the response itself (only thechild_object_id
shows up), keeping this approach allows us to roll out this fix without breaking existing DB entries.For example the structure in the DB is:
1:
(parent_id: 3, dof_wrapper_id: 4)
->DynamicFieldInfo {child_object_id: 2}
2:
(parent_id: 3, dof_wrapper_id: 7)
->DynamicFieldInfo {child_object_id: 3}
3:
(parent_id: 3, dof_wrapper_id: 9)
->DynamicFieldInfo {child_object_id: 5}
4:
(parent_id: 3, dof_wrapper_id: 12)
->DynamicFieldInfo {child_object_id: 19}
If the query is made with a limit of 3, the returned cursor will be
5
which is fromchild_object_id
in the 3rd entry.But when this cursor is used the next time, it will match the 2nd entry
(parent_id: 3, dof_wrapper_id: 7)
->DynamicFieldInfo {child_object_id: 3}
because the the DB implementation of skip_to which is used in the dynamic field iterator seeks to the nearest highest key from 5 which is 7.This is an example of how one will see duplicates because the cursor can point backwards.
The solution in this code changes the cursor to return the
dof_wrapper_id
of 9 in this example, so the next query will return the 4th entry(parent_id: 3, dof_wrapper_id: 12)
->DynamicFieldInfo {child_object_id: 19}
as expected.Test Plan
Manual testing
If your changes are not user-facing and not a breaking change, you can skip the following section. Otherwise, please indicate what changed, and then add to the Release Notes section as highlighted during the release process.
Type of Change (Check all that apply)
Release notes