-
Notifications
You must be signed in to change notification settings - Fork 11.3k
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
jsonrpc: introduce coin_index_2 with coins sorted by balance #19822
Conversation
The latest updates on your projects. Learn more about Vercel for Git ↗︎
3 Skipped Deployments
|
37387e2
to
39459f1
Compare
39459f1
to
7743d1e
Compare
7743d1e
to
1e51100
Compare
fn make_live_object_indexer(&self) -> Self::ObjectIndexer; | ||
} | ||
|
||
/// Represents an instance of a indexer that operates on a subset of the live object set |
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.
/// Represents an instance of a indexer that operates on a subset of the live object set | |
/// Represents an instance of an indexer that operates on a subset of the live object set |
}); | ||
|
||
// 1. Remove old coins from the DB by looking at the set of input coin objects | ||
let coin_delete_keys = input_coins |
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.
@bmwill is there a motivation to change this piece (i.e. not using object_index_changes
but using input_coins
instead)? It's not immediately clear to me whether this change is correct or not, and we'd better not touch this piece unless absolutely needed
same for using written_coins
below
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 way it is written now is actually going to be more correct and less error prone and imo easier to reason about.
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 can't tell whether it's more correct or not with my current cooked weekend brain. Did you find errors in the old implementation which makes the new way "more correct"? If not, i'd vote for not touching this very brittle thing. If yes or you feel very confident about the correctness then i won't insist either.
either way i think @sadhansood may want to take a look at this piece as well
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.
Taking another look this seems like it can be simplified even more, and i should cleanup the comments on the written coins side
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.
Looking at the new logic, it seems reasonable. Although it is hard to be 100% sure and my hope is our tests will catch any bugs here. One way we could be absolutely sure is to compare end of epoch account balance of every account between old and new indexing logic on two FNs which are bootstrapped from db snapshots of the same epoch (obviously disconnect network or change sui config to prevent them from processing new checkpoints). This is subjective on how much confidence we have on our tests
Some(c) => { | ||
let obj = self.internal.get_object(&c).await?.ok_or_else(|| { | ||
SuiRpcInputError::GenericInvalid("cursor not found".to_string()) | ||
})?; | ||
let coin = obj.as_coin_maybe().ok_or_else(|| { | ||
SuiRpcInputError::GenericInvalid("cursor is not a coin".to_string()) | ||
})?; | ||
(coin_type_tag.to_string(), !coin.balance.value(), c) | ||
} |
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 has the risk of getting inconsistent results across pages, but honestly this is not the only api with this issue and i don't have a better idea how to deal with it
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.
Yeah :(
I had two options:
- break the cursor to now take the balance
- do this
This seemed the least bad option.
It does highlight that cursors like this should be less defined so that they can change if need be in the future
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.
Remark: Rocksdb actually has a way to support consistent cursor here which is called snapshot
(not to be confused with db checkpoint). It's a low overhead point in time view of the db (and millions of such snapshots could be simultaneously kept) which could be used to retrieve consistent data across pages (obviously we cannot hold a snapshot forever and it would need to be timed out)
1e51100
to
2009290
Compare
}); | ||
|
||
// 1. Remove old coins from the DB by looking at the set of input coin objects | ||
let coin_delete_keys = input_coins |
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.
Looking at the new logic, it seems reasonable. Although it is hard to be 100% sure and my hope is our tests will catch any bugs here. One way we could be absolutely sure is to compare end of epoch account balance of every account between old and new indexing logic on two FNs which are bootstrapped from db snapshots of the same epoch (obviously disconnect network or change sui config to prevent them from processing new checkpoints). This is subjective on how much confidence we have on our tests
Some(c) => { | ||
let obj = self.internal.get_object(&c).await?.ok_or_else(|| { | ||
SuiRpcInputError::GenericInvalid("cursor not found".to_string()) | ||
})?; | ||
let coin = obj.as_coin_maybe().ok_or_else(|| { | ||
SuiRpcInputError::GenericInvalid("cursor is not a coin".to_string()) | ||
})?; | ||
(coin_type_tag.to_string(), !coin.balance.value(), c) | ||
} |
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.
Remark: Rocksdb actually has a way to support consistent cursor here which is called snapshot
(not to be confused with db checkpoint). It's a low overhead point in time view of the db (and millions of such snapshots could be simultaneously kept) which could be used to retrieve consistent data across pages (obviously we cannot hold a snapshot forever and it would need to be timed out)
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.
code lgtm, and hopefully with some a/b testing of fetching coins/balance we can see if this works as expected
Factor out the parallel live object indexing, used for initializing the rest indexes, into more general purpose and reusable logic.
Introduce a new coin_index_2 index with coins sorted by balance in decreasing value (sorted high to low).
Initialize the new coin_index_2 index and clear the old coin_index column family.
Reduce the minimum batch size to write out during indexing the live object set from 256MB to 128MB, these smaller batch sizes resulted in a small improvement to index initialization.
…tion Introduce a meta column family that is used to track initialization of the Index DB itself as well as the status of the various column families themsevles.
e543142
to
a487e8c
Compare
Description
Introduce a new coin_index_2 index with coins sorted by balance in decreasing value (sorted high to low).
Test plan
How did you test the new or updated feature?
Release notes
Check each box that your changes affect. If none of the boxes relate to your changes, release notes aren't required.
For each box you select, include information after the relevant heading that describes the impact of your changes that a user might notice and any actions they must take to implement updates.
Introduces a new coin index used in returning paginated coins for the
sui_getCoins
JSON-RPC method. This changes the pagination order of coins to be returned in order of decreasing value (coins with a larger balance are returned first). In order to accomplish this a new column family (coin_index_2
) was added to the jsonrpcindexes
rocksdb database, deprecating and obsolescing the oldcoin_index
column family.Note
On startup a Fullnode will need to initialize this new index by iterating through, and processing the live
object set. This will result in a small period of downtime on node startup.
Once the new index has been initialized the old one will be removed in order to reclaim disk space.