integrate cache in on-demand
This commit is contained in:
parent
3b9741e9d8
commit
48cf591e66
@ -156,7 +156,7 @@ impl Cache {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::Cache;
|
use super::Cache;
|
||||||
use time::{Duration, SteadyTime};
|
use time::Duration;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn corpus_inaccessible() {
|
fn corpus_inaccessible() {
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
//! will take the raw data received here and extract meaningful results from it.
|
//! will take the raw data received here and extract meaningful results from it.
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
use ethcore::basic_account::BasicAccount;
|
use ethcore::basic_account::BasicAccount;
|
||||||
use ethcore::encoded;
|
use ethcore::encoded;
|
||||||
@ -28,10 +29,11 @@ use futures::{Async, Poll, Future};
|
|||||||
use futures::sync::oneshot::{self, Sender, Receiver};
|
use futures::sync::oneshot::{self, Sender, Receiver};
|
||||||
use network::PeerId;
|
use network::PeerId;
|
||||||
use rlp::{RlpStream, Stream};
|
use rlp::{RlpStream, Stream};
|
||||||
use util::{Bytes, RwLock, U256};
|
use util::{Bytes, RwLock, Mutex, U256};
|
||||||
use util::sha3::{SHA3_NULL_RLP, SHA3_EMPTY_LIST_RLP};
|
use util::sha3::{SHA3_NULL_RLP, SHA3_EMPTY_LIST_RLP};
|
||||||
|
|
||||||
use net::{Handler, Status, Capabilities, Announcement, EventContext, BasicContext, ReqId};
|
use net::{Handler, Status, Capabilities, Announcement, EventContext, BasicContext, ReqId};
|
||||||
|
use cache::Cache;
|
||||||
use types::les_request::{self as les_request, Request as LesRequest};
|
use types::les_request::{self as les_request, Request as LesRequest};
|
||||||
|
|
||||||
pub mod request;
|
pub mod request;
|
||||||
@ -42,9 +44,16 @@ struct Peer {
|
|||||||
capabilities: Capabilities,
|
capabilities: Capabilities,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Which portions of a CHT proof should be sent.
|
||||||
|
enum ChtProofSender {
|
||||||
|
Both(Sender<(encoded::Header, U256)>),
|
||||||
|
Header(Sender<encoded::Header>),
|
||||||
|
ChainScore(Sender<U256>),
|
||||||
|
}
|
||||||
|
|
||||||
// Attempted request info and sender to put received value.
|
// Attempted request info and sender to put received value.
|
||||||
enum Pending {
|
enum Pending {
|
||||||
HeaderByNumber(request::HeaderByNumber, Sender<(encoded::Header, U256)>), // num + CHT root
|
HeaderByNumber(request::HeaderByNumber, ChtProofSender),
|
||||||
HeaderByHash(request::HeaderByHash, Sender<encoded::Header>),
|
HeaderByHash(request::HeaderByHash, Sender<encoded::Header>),
|
||||||
Block(request::Body, Sender<encoded::Block>),
|
Block(request::Body, Sender<encoded::Block>),
|
||||||
BlockReceipts(request::BlockReceipts, Sender<Vec<Receipt>>),
|
BlockReceipts(request::BlockReceipts, Sender<Vec<Receipt>>),
|
||||||
@ -58,30 +67,77 @@ enum Pending {
|
|||||||
pub struct OnDemand {
|
pub struct OnDemand {
|
||||||
peers: RwLock<HashMap<PeerId, Peer>>,
|
peers: RwLock<HashMap<PeerId, Peer>>,
|
||||||
pending_requests: RwLock<HashMap<ReqId, Pending>>,
|
pending_requests: RwLock<HashMap<ReqId, Pending>>,
|
||||||
|
cache: Arc<Mutex<Cache>>,
|
||||||
orphaned_requests: RwLock<Vec<Pending>>,
|
orphaned_requests: RwLock<Vec<Pending>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for OnDemand {
|
impl OnDemand {
|
||||||
fn default() -> Self {
|
/// Create a new `OnDemand` service with the given cache.
|
||||||
|
pub fn new(cache: Arc<Mutex<Cache>>) -> Self {
|
||||||
OnDemand {
|
OnDemand {
|
||||||
peers: RwLock::new(HashMap::new()),
|
peers: RwLock::new(HashMap::new()),
|
||||||
pending_requests: RwLock::new(HashMap::new()),
|
pending_requests: RwLock::new(HashMap::new()),
|
||||||
|
cache: cache,
|
||||||
orphaned_requests: RwLock::new(Vec::new()),
|
orphaned_requests: RwLock::new(Vec::new()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl OnDemand {
|
|
||||||
/// Request a header by block number and CHT root hash.
|
/// Request a header by block number and CHT root hash.
|
||||||
/// Returns the header and the total difficulty.
|
/// Returns the header.
|
||||||
pub fn header_by_number(&self, ctx: &BasicContext, req: request::HeaderByNumber) -> Receiver<(encoded::Header, U256)> {
|
pub fn header_by_number(&self, ctx: &BasicContext, req: request::HeaderByNumber) -> Receiver<encoded::Header> {
|
||||||
let (sender, receiver) = oneshot::channel();
|
let (sender, receiver) = oneshot::channel();
|
||||||
self.dispatch_header_by_number(ctx, req, sender);
|
let cached = {
|
||||||
|
let mut cache = self.cache.lock();
|
||||||
|
cache.block_hash(&req.num()).and_then(|hash| cache.block_header(&hash))
|
||||||
|
};
|
||||||
|
|
||||||
|
match cached {
|
||||||
|
Some(hdr) => sender.complete(hdr),
|
||||||
|
None => self.dispatch_header_by_number(ctx, req, ChtProofSender::Header(sender)),
|
||||||
|
}
|
||||||
|
receiver
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Request a canonical block's chain score.
|
||||||
|
/// Returns the chain score.
|
||||||
|
pub fn chain_score_by_number(&self, ctx: &BasicContext, req: request::HeaderByNumber) -> Receiver<U256> {
|
||||||
|
let (sender, receiver) = oneshot::channel();
|
||||||
|
let cached = {
|
||||||
|
let mut cache = self.cache.lock();
|
||||||
|
cache.block_hash(&req.num()).and_then(|hash| cache.chain_score(&hash))
|
||||||
|
};
|
||||||
|
|
||||||
|
match cached {
|
||||||
|
Some(score) => sender.complete(score),
|
||||||
|
None => self.dispatch_header_by_number(ctx, req, ChtProofSender::ChainScore(sender)),
|
||||||
|
}
|
||||||
|
|
||||||
|
receiver
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Request a canonical block's chain score.
|
||||||
|
/// Returns the header and chain score.
|
||||||
|
pub fn header_and_score_by_number(&self, ctx: &BasicContext, req: request::HeaderByNumber) -> Receiver<(encoded::Header, U256)> {
|
||||||
|
let (sender, receiver) = oneshot::channel();
|
||||||
|
let cached = {
|
||||||
|
let mut cache = self.cache.lock();
|
||||||
|
let hash = cache.block_hash(&req.num());
|
||||||
|
(
|
||||||
|
hash.clone().and_then(|hash| cache.block_header(&hash)),
|
||||||
|
hash.and_then(|hash| cache.chain_score(&hash)),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
match cached {
|
||||||
|
(Some(hdr), Some(score)) => sender.complete((hdr, score)),
|
||||||
|
_ => self.dispatch_header_by_number(ctx, req, ChtProofSender::Both(sender)),
|
||||||
|
}
|
||||||
|
|
||||||
receiver
|
receiver
|
||||||
}
|
}
|
||||||
|
|
||||||
// dispatch the request, completing the request if no peers available.
|
// dispatch the request, completing the request if no peers available.
|
||||||
fn dispatch_header_by_number(&self, ctx: &BasicContext, req: request::HeaderByNumber, sender: Sender<(encoded::Header, U256)>) {
|
fn dispatch_header_by_number(&self, ctx: &BasicContext, req: request::HeaderByNumber, sender: ChtProofSender) {
|
||||||
let num = req.num();
|
let num = req.num();
|
||||||
let cht_num = req.cht_num();
|
let cht_num = req.cht_num();
|
||||||
|
|
||||||
@ -123,7 +179,10 @@ impl OnDemand {
|
|||||||
/// it as easily.
|
/// it as easily.
|
||||||
pub fn header_by_hash(&self, ctx: &BasicContext, req: request::HeaderByHash) -> Receiver<encoded::Header> {
|
pub fn header_by_hash(&self, ctx: &BasicContext, req: request::HeaderByHash) -> Receiver<encoded::Header> {
|
||||||
let (sender, receiver) = oneshot::channel();
|
let (sender, receiver) = oneshot::channel();
|
||||||
self.dispatch_header_by_hash(ctx, req, sender);
|
match self.cache.lock().block_header(&req.0) {
|
||||||
|
Some(hdr) => sender.complete(hdr),
|
||||||
|
None => self.dispatch_header_by_hash(ctx, req, sender),
|
||||||
|
}
|
||||||
receiver
|
receiver
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -181,7 +240,16 @@ impl OnDemand {
|
|||||||
|
|
||||||
sender.complete(encoded::Block::new(stream.out()))
|
sender.complete(encoded::Block::new(stream.out()))
|
||||||
} else {
|
} else {
|
||||||
self.dispatch_block(ctx, req, sender);
|
match self.cache.lock().block_body(&req.hash) {
|
||||||
|
Some(body) => {
|
||||||
|
let mut stream = RlpStream::new_list(3);
|
||||||
|
stream.append_raw(&req.header.into_inner(), 1);
|
||||||
|
stream.append_raw(&body.into_inner(), 2);
|
||||||
|
|
||||||
|
sender.complete(encoded::Block::new(stream.out()));
|
||||||
|
}
|
||||||
|
None => self.dispatch_block(ctx, req, sender),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
receiver
|
receiver
|
||||||
}
|
}
|
||||||
@ -224,7 +292,10 @@ impl OnDemand {
|
|||||||
if req.0.receipts_root() == SHA3_NULL_RLP {
|
if req.0.receipts_root() == SHA3_NULL_RLP {
|
||||||
sender.complete(Vec::new())
|
sender.complete(Vec::new())
|
||||||
} else {
|
} else {
|
||||||
self.dispatch_block_receipts(ctx, req, sender);
|
match self.cache.lock().block_receipts(&req.0.hash()) {
|
||||||
|
Some(receipts) => sender.complete(receipts),
|
||||||
|
None => self.dispatch_block_receipts(ctx, req, sender),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
receiver
|
receiver
|
||||||
@ -378,8 +449,15 @@ impl OnDemand {
|
|||||||
|
|
||||||
for orphaned in to_dispatch {
|
for orphaned in to_dispatch {
|
||||||
match orphaned {
|
match orphaned {
|
||||||
Pending::HeaderByNumber(req, mut sender) =>
|
Pending::HeaderByNumber(req, mut sender) => {
|
||||||
if !check_hangup(&mut sender) { self.dispatch_header_by_number(ctx, req, sender) },
|
let hangup = match sender {
|
||||||
|
ChtProofSender::Both(ref mut s) => check_hangup(s),
|
||||||
|
ChtProofSender::Header(ref mut s) => check_hangup(s),
|
||||||
|
ChtProofSender::ChainScore(ref mut s) => check_hangup(s),
|
||||||
|
};
|
||||||
|
|
||||||
|
if !hangup { self.dispatch_header_by_number(ctx, req, sender) }
|
||||||
|
}
|
||||||
Pending::HeaderByHash(req, mut sender) =>
|
Pending::HeaderByHash(req, mut sender) =>
|
||||||
if !check_hangup(&mut sender) { self.dispatch_header_by_hash(ctx, req, sender) },
|
if !check_hangup(&mut sender) { self.dispatch_header_by_hash(ctx, req, sender) },
|
||||||
Pending::Block(req, mut sender) =>
|
Pending::Block(req, mut sender) =>
|
||||||
@ -439,8 +517,19 @@ impl Handler for OnDemand {
|
|||||||
Pending::HeaderByNumber(req, sender) => {
|
Pending::HeaderByNumber(req, sender) => {
|
||||||
if let Some(&(ref header, ref proof)) = proofs.get(0) {
|
if let Some(&(ref header, ref proof)) = proofs.get(0) {
|
||||||
match req.check_response(header, proof) {
|
match req.check_response(header, proof) {
|
||||||
Ok(header) => {
|
Ok((header, score)) => {
|
||||||
sender.complete(header);
|
let mut cache = self.cache.lock();
|
||||||
|
let hash = header.hash();
|
||||||
|
cache.insert_block_header(hash, header.clone());
|
||||||
|
cache.insert_block_hash(header.number(), hash);
|
||||||
|
cache.insert_chain_score(hash, score);
|
||||||
|
|
||||||
|
match sender {
|
||||||
|
ChtProofSender::Both(sender) => sender.complete((header, score)),
|
||||||
|
ChtProofSender::Header(sender) => sender.complete(header),
|
||||||
|
ChtProofSender::ChainScore(sender) => sender.complete(score),
|
||||||
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
@ -468,6 +557,7 @@ impl Handler for OnDemand {
|
|||||||
if let Some(ref header) = headers.get(0) {
|
if let Some(ref header) = headers.get(0) {
|
||||||
match req.check_response(header) {
|
match req.check_response(header) {
|
||||||
Ok(header) => {
|
Ok(header) => {
|
||||||
|
self.cache.lock().insert_block_header(req.0, header.clone());
|
||||||
sender.complete(header);
|
sender.complete(header);
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -493,9 +583,11 @@ impl Handler for OnDemand {
|
|||||||
|
|
||||||
match req {
|
match req {
|
||||||
Pending::Block(req, sender) => {
|
Pending::Block(req, sender) => {
|
||||||
if let Some(ref block) = bodies.get(0) {
|
if let Some(ref body) = bodies.get(0) {
|
||||||
match req.check_response(block) {
|
match req.check_response(body) {
|
||||||
Ok(block) => {
|
Ok(block) => {
|
||||||
|
let body = encoded::Body::new(body.to_vec());
|
||||||
|
self.cache.lock().insert_block_body(req.hash, body);
|
||||||
sender.complete(block);
|
sender.complete(block);
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -524,6 +616,8 @@ impl Handler for OnDemand {
|
|||||||
if let Some(ref receipts) = receipts.get(0) {
|
if let Some(ref receipts) = receipts.get(0) {
|
||||||
match req.check_response(receipts) {
|
match req.check_response(receipts) {
|
||||||
Ok(receipts) => {
|
Ok(receipts) => {
|
||||||
|
let hash = req.0.hash();
|
||||||
|
self.cache.lock().insert_block_receipts(hash, receipts.clone());
|
||||||
sender.complete(receipts);
|
sender.complete(receipts);
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -604,10 +698,16 @@ impl Handler for OnDemand {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use cache::Cache;
|
||||||
use net::{Announcement, BasicContext, ReqId, Error as LesError};
|
use net::{Announcement, BasicContext, ReqId, Error as LesError};
|
||||||
use request::{Request as LesRequest, Kind as LesRequestKind};
|
use request::{Request as LesRequest, Kind as LesRequestKind};
|
||||||
|
|
||||||
use network::{PeerId, NodeId};
|
use network::{PeerId, NodeId};
|
||||||
use util::H256;
|
use time::Duration;
|
||||||
|
use util::{H256, Mutex};
|
||||||
|
|
||||||
struct FakeContext;
|
struct FakeContext;
|
||||||
|
|
||||||
@ -624,7 +724,8 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn detects_hangup() {
|
fn detects_hangup() {
|
||||||
let on_demand = OnDemand::default();
|
let cache = Arc::new(Mutex::new(Cache::new(Default::default(), Duration::hours(6))));
|
||||||
|
let on_demand = OnDemand::new(cache);
|
||||||
let result = on_demand.header_by_hash(&FakeContext, request::HeaderByHash(H256::default()));
|
let result = on_demand.header_by_hash(&FakeContext, request::HeaderByHash(H256::default()));
|
||||||
|
|
||||||
assert!(on_demand.orphaned_requests.read().len() == 1);
|
assert!(on_demand.orphaned_requests.read().len() == 1);
|
||||||
|
@ -108,7 +108,7 @@ impl EthClient {
|
|||||||
|
|
||||||
self.sync.with_context(|ctx|
|
self.sync.with_context(|ctx|
|
||||||
self.on_demand.header_by_number(ctx, req)
|
self.on_demand.header_by_number(ctx, req)
|
||||||
.map(|(h, _)| Some(h))
|
.map(Some)
|
||||||
.map_err(err_premature_cancel)
|
.map_err(err_premature_cancel)
|
||||||
.boxed()
|
.boxed()
|
||||||
)
|
)
|
||||||
|
Loading…
Reference in New Issue
Block a user