Skip to content

Commit

Permalink
Don't require connection to DB in token cache if not required
Browse files Browse the repository at this point in the history
  • Loading branch information
popzxc committed Mar 4, 2022
1 parent 8a06713 commit fd074d6
Show file tree
Hide file tree
Showing 5 changed files with 88 additions and 11 deletions.
11 changes: 11 additions & 0 deletions core/bin/zksync_api/src/api_server/rest/v02/token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,17 @@ impl ApiTokenData {
}

async fn token(&self, token_like: TokenLike) -> Result<Token, Error> {
// Try to find the token in the cache first.
if let Some(token) = self
.tokens
.try_get_token_from_cache(token_like.clone())
.await
{
return Ok(token);
}

// Establish db connection and repeat the query, so the token is loaded
// from the db.
let mut storage = self.pool.access_storage().await.map_err(Error::storage)?;

let token = self
Expand Down
8 changes: 8 additions & 0 deletions core/bin/zksync_api/src/api_server/tx_sender.rs
Original file line number Diff line number Diff line change
Expand Up @@ -992,6 +992,14 @@ impl TxSender {
&self,
token_id: impl Into<TokenLike>,
) -> Result<Token, SubmitError> {
let token_id = token_id.into();
// Try to find the token in the cache first.
if let Some(token) = self.tokens.try_get_token_from_cache(token_id.clone()).await {
return Ok(token);
}

// Establish db connection and repeat the query, so the token is loaded
// from the db.
let mut storage = self
.pool
.access_storage()
Expand Down
47 changes: 36 additions & 11 deletions core/bin/zksync_api/src/fee_ticker/ticker_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -192,19 +192,32 @@ impl FeeTickerInfo for TickerInfo {
/// Get last price from ticker
async fn get_last_token_price(&self, token: TokenLike) -> Result<TokenPrice, PriceError> {
let start = Instant::now();
let token = self
.token_db_cache
.get_token(
&mut self

let token = {
// Try to find the token in the cache first.
if let Some(token) = self
.token_db_cache
.try_get_token_from_cache(token.clone())
.await
{
token
} else {
// Establish db connection and repeat the query, so the token is loaded
// from the db.
let mut storage = self
.db
.access_storage()
.await
.map_err(PriceError::db_error)?,
token.clone(),
)
.await
.map_err(PriceError::db_error)?
.ok_or_else(|| PriceError::token_not_found(format!("Token not found: {:?}", token)))?;
.map_err(PriceError::db_error)?;
self.token_db_cache
.get_token(&mut storage, token.clone())
.await
.map_err(PriceError::db_error)?
.ok_or_else(|| {
PriceError::token_not_found(format!("Token not found: {:?}", token))
})?
}
};

// TODO: remove hardcode for Matter Labs Trial Token (ZKS-63).
if token.symbol == "MLTT" {
Expand Down Expand Up @@ -269,9 +282,21 @@ impl FeeTickerInfo for TickerInfo {

async fn get_token(&self, token: TokenLike) -> Result<Token, anyhow::Error> {
let start = Instant::now();
// Try to find the token in the cache first.
if let Some(token) = self
.token_db_cache
.try_get_token_from_cache(token.clone())
.await
{
return Ok(token);
}

// Establish db connection and repeat the query, so the token is loaded
// from the db.
let mut storage = self.db.access_storage().await?;
let result = self
.token_db_cache
.get_token(&mut self.db.access_storage().await?, token.clone())
.get_token(&mut storage, token.clone())
.await?
.ok_or_else(|| format_err!("Token not found: {:?}", token));
metrics::histogram!("ticker_info.get_token", start.elapsed());
Expand Down
11 changes: 11 additions & 0 deletions core/bin/zksync_api/src/fee_ticker/validator/cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,17 @@ impl TokenCacheWrapper {
pub async fn get_token(&self, token_like: TokenLike) -> anyhow::Result<Option<Token>> {
match self {
Self::DB(cache) => {
// Try to find the token in the cache first.
if let Some(token) = cache
.inner
.try_get_token_from_cache(token_like.clone())
.await
{
return Ok(Some(token));
}

// Establish db connection and repeat the query, so the token is loaded
// from the db.
cache
.inner
.get_token(&mut cache.pool.access_storage().await?, token_like)
Expand Down
22 changes: 22 additions & 0 deletions core/bin/zksync_api/src/utils/token_db_cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,28 @@ impl TokenDBCache {
Self::default()
}

/// Version of `get_token` that only attempts to find the token in the cache.
/// This method should be used in places that don't require the DB connection itself,
/// so taking a connection from the pool is avoided.
///
/// It is expected that if lookup fails, `get_token` will be called instead.
/// On such an event, we will try to get the token from cache twise, but this scenario
/// is unlikely, since most of the time tokens *are* in the cache.
pub async fn try_get_token_from_cache(
&self,
token_query: impl Into<TokenLike>,
) -> Option<Token> {
let token_query = token_query.into();
// Just return token from cache.
if let Some((token, update_time)) = self.cache.read().await.get(&token_query.to_lowercase())
{
if update_time.elapsed() < TOKEN_INVALIDATE_CACHE {
return Some(token.clone());
}
}
None
}

/// Performs case-insensitive token search.
pub async fn get_token(
&self,
Expand Down

0 comments on commit fd074d6

Please sign in to comment.