use ahash

this might actually be slower. do real benchmarks
This commit is contained in:
Bryan Stitt 2022-09-17 02:17:20 +00:00
parent 3d4bfbfde0
commit 05af0551c9
8 changed files with 46 additions and 30 deletions

1
Cargo.lock generated

@ -5544,6 +5544,7 @@ dependencies = [
name = "web3_proxy"
version = "0.1.0"
dependencies = [
"ahash 0.8.0",
"anyhow",
"arc-swap",
"argh",

@ -34,14 +34,12 @@ where
pub fn new(cache_size: u64, prefix: &str, rrl: RedisRateLimiter) -> Self {
let ttl = rrl.period as u64;
let hasher = ahash::RandomState::new();
// TODO: think more about this ttl. if
// TODO: time to live is not right. we want this ttl counter to start only after redis is down. this works for now
let local_cache = Cache::builder()
.time_to_live(Duration::from_secs(ttl))
.max_capacity(cache_size)
.name(prefix)
.build_with_hasher(hasher);
.build_with_hasher(ahash::RandomState::new());
Self {
local_cache,

@ -19,6 +19,7 @@ entities = { path = "../entities" }
migration = { path = "../migration" }
redis-rate-limiter = { path = "../redis-rate-limiter" }
ahash = "0.8.0"
anyhow = { version = "1.0.65", features = ["backtrace"] }
arc-swap = "1.5.1"
argh = "0.1.8"

@ -6,7 +6,7 @@ use crate::jsonrpc::JsonRpcForwardedResponse;
use crate::jsonrpc::JsonRpcForwardedResponseEnum;
use crate::jsonrpc::JsonRpcRequest;
use crate::jsonrpc::JsonRpcRequestEnum;
use crate::rpcs::blockchain::{ArcBlock, BlockHashesMap, BlockId};
use crate::rpcs::blockchain::{ArcBlock, BlockId};
use crate::rpcs::connections::Web3Connections;
use crate::rpcs::request::OpenRequestHandleMetrics;
use crate::rpcs::transactions::TxStatus;
@ -54,7 +54,7 @@ static APP_USER_AGENT: &str = concat!(
/// block hash, method, params
// TODO: better name
type ResponseCacheKey = (H256, String, Option<String>);
type ResponseCache = Cache<ResponseCacheKey, JsonRpcForwardedResponse>;
type ResponseCache = Cache<ResponseCacheKey, JsonRpcForwardedResponse, ahash::RandomState>;
pub type AnyhowJoinHandle<T> = JoinHandle<anyhow::Result<T>>;
@ -84,11 +84,11 @@ pub struct Web3ProxyApp {
app_metrics: Arc<Web3ProxyAppMetrics>,
open_request_handle_metrics: Arc<OpenRequestHandleMetrics>,
/// store pending transactions that we've seen so that we don't send duplicates to subscribers
pub pending_transactions: Cache<TxHash, TxStatus>,
pub pending_transactions: Cache<TxHash, TxStatus, ahash::RandomState>,
pub frontend_ip_rate_limiter: Option<DeferredRateLimiter<IpAddr>>,
pub frontend_key_rate_limiter: Option<DeferredRateLimiter<Uuid>>,
pub redis_pool: Option<RedisPool>,
pub user_cache: Cache<Uuid, UserCacheValue>,
pub user_cache: Cache<Uuid, UserCacheValue, ahash::RandomState>,
}
/// flatten a JoinError into an anyhow error
@ -232,7 +232,10 @@ impl Web3ProxyApp {
// test the pool
if let Err(err) = redis_pool.get().await {
error!("failed to connect to redis. some features will be disabled");
error!(
?err,
"failed to connect to redis. some features will be disabled"
);
};
Some(redis_pool)
@ -252,8 +255,9 @@ impl Web3ProxyApp {
drop(pending_tx_receiver);
// TODO: sized and timed expiration!
// TODO: put some in Redis, too?
let pending_transactions = Cache::new(10000);
let pending_transactions = Cache::builder()
.max_capacity(10_000)
.build_with_hasher(ahash::RandomState::new());
// TODO: don't drop the pending_tx_receiver. instead, read it to mark transactions as "seen". once seen, we won't re-send them
// TODO: once a transaction is "Confirmed" we remove it from the map. this should prevent major memory leaks.
@ -261,7 +265,9 @@ impl Web3ProxyApp {
// this block map is shared between balanced_rpcs and private_rpcs.
// TODO: what limits should we have for expiration?
let block_map = BlockHashesMap::new(10_000);
let block_map = Cache::builder()
.max_capacity(10_000)
.build_with_hasher(ahash::RandomState::new());
let (balanced_rpcs, balanced_handle) = Web3Connections::spawn(
top_config.app.chain_id,
@ -332,9 +338,13 @@ impl Web3ProxyApp {
}
// TODO: change this to a sized cache. theres some potentially giant responses that will break things
let response_cache = Cache::new(10_000);
let response_cache = Cache::builder()
.max_capacity(10_000)
.build_with_hasher(ahash::RandomState::new());
let user_cache = Cache::new(10_000);
let user_cache = Cache::builder()
.max_capacity(10_000)
.build_with_hasher(ahash::RandomState::new());
let app = Self {
config: top_config.app,

@ -1,4 +1,4 @@
use crate::rpcs::blockchain::BlockHashesMap;
use crate::rpcs::blockchain::BlockHashesCache;
use crate::rpcs::connection::Web3Connection;
use crate::rpcs::request::OpenRequestHandleMetrics;
use crate::{app::AnyhowJoinHandle, rpcs::blockchain::ArcBlock};
@ -120,7 +120,7 @@ impl Web3ConnectionConfig {
chain_id: u64,
http_client: Option<reqwest::Client>,
http_interval_sender: Option<Arc<broadcast::Sender<()>>>,
block_map: BlockHashesMap,
block_map: BlockHashesCache,
block_sender: Option<flume::Sender<BlockAndRpc>>,
tx_id_sender: Option<flume::Sender<TxHashAndRpc>>,
open_request_handle_metrics: Arc<OpenRequestHandleMetrics>,

@ -19,7 +19,7 @@ use tracing::{debug, trace, warn};
// TODO: type for Hydrated Blocks with their full transactions?
pub type ArcBlock = Arc<Block<TxHash>>;
pub type BlockHashesMap = Cache<H256, ArcBlock>;
pub type BlockHashesCache = Cache<H256, ArcBlock, ahash::RandomState>;
/// A block's hash and number.
#[derive(Clone, Debug, Default, From, Serialize)]

@ -1,5 +1,5 @@
///! Rate-limited communication with a web3 provider.
use super::blockchain::{ArcBlock, BlockHashesMap, BlockId};
use super::blockchain::{ArcBlock, BlockHashesCache, BlockId};
use super::provider::Web3Provider;
use super::request::{OpenRequestHandle, OpenRequestHandleMetrics, OpenRequestResult};
use crate::app::{flatten_handle, AnyhowJoinHandle};
@ -69,7 +69,7 @@ impl Web3Connection {
hard_limit: Option<(u64, RedisPool)>,
// TODO: think more about this type
soft_limit: u32,
block_map: BlockHashesMap,
block_map: BlockHashesCache,
block_sender: Option<flume::Sender<BlockAndRpc>>,
tx_id_sender: Option<flume::Sender<(TxHash, Arc<Self>)>>,
reconnect: bool,
@ -366,7 +366,7 @@ impl Web3Connection {
self: &Arc<Self>,
new_head_block: Result<Option<ArcBlock>, ProviderError>,
block_sender: &flume::Sender<BlockAndRpc>,
block_map: BlockHashesMap,
block_map: BlockHashesCache,
) -> anyhow::Result<()> {
match new_head_block {
Ok(None) => {
@ -428,7 +428,7 @@ impl Web3Connection {
async fn subscribe(
self: Arc<Self>,
http_interval_sender: Option<Arc<broadcast::Sender<()>>>,
block_map: BlockHashesMap,
block_map: BlockHashesCache,
block_sender: Option<flume::Sender<BlockAndRpc>>,
tx_id_sender: Option<flume::Sender<(TxHash, Arc<Self>)>>,
reconnect: bool,
@ -516,7 +516,7 @@ impl Web3Connection {
self: Arc<Self>,
http_interval_receiver: Option<broadcast::Receiver<()>>,
block_sender: flume::Sender<BlockAndRpc>,
block_map: BlockHashesMap,
block_map: BlockHashesCache,
) -> anyhow::Result<()> {
info!(%self, "watching new heads");

@ -1,5 +1,5 @@
///! Load balanced communication with a group of web3 providers
use super::blockchain::{ArcBlock, BlockHashesMap};
use super::blockchain::{ArcBlock, BlockHashesCache};
use super::connection::Web3Connection;
use super::request::{OpenRequestHandle, OpenRequestHandleMetrics, OpenRequestResult};
use super::synced_connections::SyncedConnections;
@ -36,12 +36,12 @@ pub struct Web3Connections {
pub(super) conns: HashMap<String, Arc<Web3Connection>>,
/// any requests will be forwarded to one (or more) of these connections
pub(super) synced_connections: ArcSwap<SyncedConnections>,
pub(super) pending_transactions: Cache<TxHash, TxStatus>,
pub(super) pending_transactions: Cache<TxHash, TxStatus, ahash::RandomState>,
/// TODO: this map is going to grow forever unless we do some sort of pruning. maybe store pruned in redis?
/// all blocks, including orphans
pub(super) block_hashes: BlockHashesMap,
pub(super) block_hashes: BlockHashesCache,
/// blocks on the heaviest chain
pub(super) block_numbers: Cache<U64, H256>,
pub(super) block_numbers: Cache<U64, H256, ahash::RandomState>,
/// TODO: this map is going to grow forever unless we do some sort of pruning. maybe store pruned in redis?
/// TODO: what should we use for edges?
pub(super) blockchain_graphmap: AsyncRwLock<DiGraphMap<H256, u32>>,
@ -57,12 +57,12 @@ impl Web3Connections {
server_configs: HashMap<String, Web3ConnectionConfig>,
http_client: Option<reqwest::Client>,
redis_pool: Option<redis_rate_limiter::RedisPool>,
block_map: BlockHashesMap,
block_map: BlockHashesCache,
head_block_sender: Option<watch::Sender<ArcBlock>>,
min_sum_soft_limit: u32,
min_synced_rpcs: usize,
pending_tx_sender: Option<broadcast::Sender<TxStatus>>,
pending_transactions: Cache<TxHash, TxStatus>,
pending_transactions: Cache<TxHash, TxStatus, ahash::RandomState>,
open_request_handle_metrics: Arc<OpenRequestHandleMetrics>,
) -> anyhow::Result<(Arc<Self>, AnyhowJoinHandle<()>)> {
let (pending_tx_id_sender, pending_tx_id_receiver) = flume::unbounded();
@ -176,8 +176,14 @@ impl Web3Connections {
let synced_connections = SyncedConnections::default();
// TODO: sizing and expiration on these caches!
let block_hashes = Cache::new(10000);
let block_numbers = Cache::new(10000);
let block_hashes = Cache::builder()
.time_to_idle(Duration::from_secs(600))
.max_capacity(10_000)
.build_with_hasher(ahash::RandomState::new());
let block_numbers = Cache::builder()
.time_to_idle(Duration::from_secs(600))
.max_capacity(10_000)
.build_with_hasher(ahash::RandomState::new());
let connections = Arc::new(Self {
conns: connections,