Arc instead of Box for better caching

This commit is contained in:
Bryan Stitt 2023-06-07 13:57:38 -07:00
parent c2a3a4a0a9
commit 4f7144abc6
3 changed files with 56 additions and 21 deletions

@ -1181,7 +1181,7 @@ impl Web3ProxyApp {
mut params: serde_json::Value,
head_block_num: Option<U64>,
request_metadata: &Arc<RequestMetadata>,
) -> Web3ProxyResult<JsonRpcResponseEnum<Box<RawValue>>> {
) -> Web3ProxyResult<JsonRpcResponseEnum<Arc<RawValue>>> {
// TODO: don't clone into a new string?
let request_method = method.to_string();
@ -1189,7 +1189,7 @@ impl Web3ProxyApp {
// TODO: serve net_version without querying the backend
// TODO: don't force RawValue
let response_data: JsonRpcResponseEnum<Box<RawValue>> = match request_method.as_ref() {
let response_data: JsonRpcResponseEnum<Arc<RawValue>> = match request_method.as_ref() {
// lots of commands are blocked
method @ ("db_getHex"
| "db_getString"
@ -1701,14 +1701,14 @@ impl Web3ProxyApp {
match self
.jsonrpc_response_cache
.get_value_or_guard_async(cache_key).await
.get_value_or_guard_async(cache_key.hash()).await
{
Ok(x) => x,
Err(x) => {
let response_data = timeout(
duration,
self.balanced_rpcs
.try_proxy_connection::<_, Box<RawValue>>(
.try_proxy_connection::<_, Arc<RawValue>>(
method,
&params,
Some(request_metadata),
@ -1718,7 +1718,7 @@ impl Web3ProxyApp {
)
.await?;
let response_data: JsonRpcResponseEnum<Box<RawValue>> = response_data.try_into()?;
let response_data: JsonRpcResponseEnum<Arc<RawValue>> = response_data.try_into()?;
if matches!(response_data, JsonRpcResponseEnum::Result { .. }) || cache_errors {
// TODO: convert the Box<RawValue> to an Arc<RawValue>?
@ -1732,7 +1732,7 @@ impl Web3ProxyApp {
let x = timeout(
duration,
self.balanced_rpcs
.try_proxy_connection::<_, Box<RawValue>>(
.try_proxy_connection::<_, Arc<RawValue>>(
method,
&params,
Some(request_metadata),

@ -8,6 +8,7 @@ use serde_json::json;
use serde_json::value::{to_raw_value, RawValue};
use std::borrow::Cow;
use std::fmt;
use std::sync::Arc;
pub trait JsonRpcParams = Clone + fmt::Debug + serde::Serialize + Send + Sync + 'static;
pub trait JsonRpcResultData = serde::Serialize + serde::de::DeserializeOwned + fmt::Debug + Send;
@ -234,7 +235,7 @@ pub struct JsonRpcForwardedResponse {
pub jsonrpc: &'static str,
pub id: Box<RawValue>,
#[serde(skip_serializing_if = "Option::is_none")]
pub result: Option<Box<RawValue>>,
pub result: Option<Arc<RawValue>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub error: Option<JsonRpcErrorData>,
}
@ -279,7 +280,7 @@ impl JsonRpcForwardedResponse {
}
}
pub fn from_raw_response(result: Box<RawValue>, id: Box<RawValue>) -> Self {
pub fn from_raw_response(result: Arc<RawValue>, id: Box<RawValue>) -> Self {
JsonRpcForwardedResponse {
jsonrpc: "2.0",
id,
@ -292,6 +293,9 @@ impl JsonRpcForwardedResponse {
pub fn from_value(result: serde_json::Value, id: Box<RawValue>) -> Self {
let partial_response = to_raw_value(&result).expect("Value to RawValue should always work");
// TODO: an Arc is a waste here. change JsonRpcForwardedResponse to take an enum?
let partial_response = partial_response.into();
JsonRpcForwardedResponse {
jsonrpc: "2.0",
id,
@ -339,7 +343,7 @@ impl JsonRpcForwardedResponse {
}
pub fn try_from_response_result(
result: Result<Box<RawValue>, ProviderError>,
result: Result<Arc<RawValue>, ProviderError>,
id: Box<RawValue>,
) -> Web3ProxyResult<Self> {
match result {
@ -348,7 +352,7 @@ impl JsonRpcForwardedResponse {
}
}
pub fn from_response_data(data: JsonRpcResponseEnum<Box<RawValue>>, id: Box<RawValue>) -> Self {
pub fn from_response_data(data: JsonRpcResponseEnum<Arc<RawValue>>, id: Box<RawValue>) -> Self {
match data {
JsonRpcResponseEnum::Result { value, .. } => Self::from_raw_response(value, id),
JsonRpcResponseEnum::RpcError {

@ -8,6 +8,7 @@ use std::{
borrow::Cow,
hash::{BuildHasher, Hash, Hasher},
num::NonZeroU32,
sync::Arc,
};
#[derive(Clone, Debug, Eq, From)]
@ -19,6 +20,9 @@ pub struct JsonRpcQueryCacheKey {
}
impl JsonRpcQueryCacheKey {
pub fn hash(&self) -> u64 {
self.hash
}
pub fn from_block_num(&self) -> Option<U64> {
self.from_block_num
}
@ -79,7 +83,7 @@ impl JsonRpcQueryCacheKey {
}
pub type JsonRpcResponseCache =
CacheWithTTL<JsonRpcQueryCacheKey, JsonRpcResponseEnum<Box<RawValue>>, JsonRpcResponseWeigher>;
CacheWithTTL<u64, JsonRpcResponseEnum<Arc<RawValue>>, JsonRpcResponseWeigher>;
#[derive(Clone)]
pub struct JsonRpcResponseWeigher;
@ -107,7 +111,7 @@ impl<R> JsonRpcResponseEnum<R> {
}
}
impl From<serde_json::Value> for JsonRpcResponseEnum<Box<RawValue>> {
impl From<serde_json::Value> for JsonRpcResponseEnum<Arc<RawValue>> {
fn from(value: serde_json::Value) -> Self {
let value = RawValue::from_string(value.to_string()).unwrap();
@ -115,12 +119,24 @@ impl From<serde_json::Value> for JsonRpcResponseEnum<Box<RawValue>> {
}
}
impl From<Box<RawValue>> for JsonRpcResponseEnum<Box<RawValue>> {
impl From<Arc<RawValue>> for JsonRpcResponseEnum<Arc<RawValue>> {
fn from(value: Arc<RawValue>) -> Self {
let num_bytes = value.get().len();
let num_bytes = NonZeroU32::try_from(num_bytes as u32).unwrap();
Self::Result { value, num_bytes }
}
}
impl From<Box<RawValue>> for JsonRpcResponseEnum<Arc<RawValue>> {
fn from(value: Box<RawValue>) -> Self {
let num_bytes = value.get().len();
let num_bytes = NonZeroU32::try_from(num_bytes as u32).unwrap();
let value = value.into();
Self::Result { value, num_bytes }
}
}
@ -140,7 +156,21 @@ impl<R> TryFrom<Web3ProxyError> for JsonRpcResponseEnum<R> {
}
}
impl TryFrom<Result<Box<RawValue>, Web3ProxyError>> for JsonRpcResponseEnum<Box<RawValue>> {
impl TryFrom<Result<Arc<RawValue>, Web3ProxyError>> for JsonRpcResponseEnum<Arc<RawValue>> {
type Error = Web3ProxyError;
fn try_from(value: Result<Arc<RawValue>, Web3ProxyError>) -> Result<Self, Self::Error> {
match value {
Ok(x) => Ok(x.into()),
Err(err) => {
let x: Self = err.try_into()?;
Ok(x)
}
}
}
}
impl TryFrom<Result<Box<RawValue>, Web3ProxyError>> for JsonRpcResponseEnum<Arc<RawValue>> {
type Error = Web3ProxyError;
fn try_from(value: Result<Box<RawValue>, Web3ProxyError>) -> Result<Self, Self::Error> {
@ -205,8 +235,9 @@ impl TryFrom<ProviderError> for JsonRpcErrorData {
}
}
impl<K, Q> Weighter<K, Q, JsonRpcResponseEnum<Box<RawValue>>> for JsonRpcResponseWeigher {
fn weight(&self, _key: &K, _qey: &Q, value: &JsonRpcResponseEnum<Box<RawValue>>) -> NonZeroU32 {
// TODO: instead of Arc<RawValue>, be generic
impl<K, Q> Weighter<K, Q, JsonRpcResponseEnum<Arc<RawValue>>> for JsonRpcResponseWeigher {
fn weight(&self, _key: &K, _qey: &Q, value: &JsonRpcResponseEnum<Arc<RawValue>>) -> NonZeroU32 {
value.num_bytes()
}
}
@ -216,7 +247,7 @@ mod tests {
use super::{JsonRpcResponseEnum, JsonRpcResponseWeigher};
use quick_cache_ttl::CacheWithTTL;
use serde_json::value::RawValue;
use std::{num::NonZeroU32, time::Duration};
use std::{num::NonZeroU32, sync::Arc, time::Duration};
#[tokio::test(start_paused = true)]
async fn test_json_rpc_query_weigher() {
@ -225,7 +256,7 @@ mod tests {
let test_cache: CacheWithTTL<
u32,
JsonRpcResponseEnum<Box<RawValue>>,
JsonRpcResponseEnum<Arc<RawValue>>,
JsonRpcResponseWeigher,
> = CacheWithTTL::new_with_weights(
"test",
@ -238,17 +269,17 @@ mod tests {
.await;
let small_data = JsonRpcResponseEnum::Result {
value: Default::default(),
value: Box::<RawValue>::default().into(),
num_bytes: NonZeroU32::try_from(max_item_weight / 2).unwrap(),
};
let max_sized_data = JsonRpcResponseEnum::Result {
value: Default::default(),
value: Box::<RawValue>::default().into(),
num_bytes: NonZeroU32::try_from(max_item_weight).unwrap(),
};
let oversized_data = JsonRpcResponseEnum::Result {
value: Default::default(),
value: Box::<RawValue>::default().into(),
num_bytes: NonZeroU32::try_from(max_item_weight * 2).unwrap(),
};