Check queue to determine major importing (#2763)

* simplify major sync detection

* fix typos

* fix merge

* more realistic EthTester

* add new synced state

* remove Blocks synced state

* move is_major_importing to rpc crate and check queue

* add tests
This commit is contained in:
keorn 2016-10-20 22:36:18 +01:00 committed by Gav Wood
parent 236fb82886
commit 866ab9c7a3
13 changed files with 87 additions and 29 deletions

View File

@ -85,7 +85,7 @@ impl<R: URLHint> ContentFetcher<R> {
// fallback to resolver
if let Ok(content_id) = content_id.from_hex() {
// if app_id is valid, but we are syncing always return true.
if self.sync.is_major_syncing() {
if self.sync.is_major_importing() {
return true;
}
// else try to resolve the app_id
@ -99,7 +99,7 @@ impl<R: URLHint> ContentFetcher<R> {
let mut cache = self.cache.lock();
let content_id = path.app_id.clone();
if self.sync.is_major_syncing() {
if self.sync.is_major_importing() {
return Box::new(ContentHandler::error(
StatusCode::ServiceUnavailable,
"Sync In Progress",

View File

@ -95,11 +95,11 @@ static DAPPS_DOMAIN : &'static str = ".parity";
/// Indicates sync status
pub trait SyncStatus: Send + Sync {
/// Returns true if there is a major sync happening.
fn is_major_syncing(&self) -> bool;
fn is_major_importing(&self) -> bool;
}
impl<F> SyncStatus for F where F: Fn() -> bool + Send + Sync {
fn is_major_syncing(&self) -> bool { self() }
fn is_major_importing(&self) -> bool { self() }
}
/// Webapps HTTP+RPC server build.

View File

@ -46,7 +46,7 @@ use transaction::{LocalizedTransaction, SignedTransaction, Action};
use blockchain::extras::TransactionAddress;
use types::filter::Filter;
use log_entry::LocalizedLogEntry;
use verification::queue::{BlockQueue, QueueInfo as BlockQueueInfo};
use verification::queue::BlockQueue;
use blockchain::{BlockChain, BlockProvider, TreeRoute, ImportRoute};
use client::{
BlockID, TransactionID, UncleID, TraceId, ClientConfig, BlockChainClient,
@ -71,6 +71,7 @@ use state_db::StateDB;
pub use types::blockchain_info::BlockChainInfo;
pub use types::block_status::BlockStatus;
pub use blockchain::CacheSize as BlockChainCacheSize;
pub use verification::queue::QueueInfo as BlockQueueInfo;
const MAX_TX_QUEUE_SIZE: usize = 4096;
const MAX_QUEUE_SIZE_TO_SLEEP_ON: usize = 2;

View File

@ -30,7 +30,7 @@ use std::sync::Arc;
trait Oracle: Send + Sync {
fn to_number(&self, hash: H256) -> Option<u64>;
fn is_major_syncing(&self) -> bool;
fn is_major_importing(&self) -> bool;
}
struct StandardOracle<F> where F: 'static + Send + Sync + Fn() -> bool {
@ -45,7 +45,7 @@ impl<F> Oracle for StandardOracle<F>
self.client.block_header(BlockID::Hash(hash)).map(|h| HeaderView::new(&h).number())
}
fn is_major_syncing(&self) -> bool {
fn is_major_importing(&self) -> bool {
(self.sync_status)()
}
}
@ -108,7 +108,7 @@ impl ChainNotify for Watcher {
_: Vec<H256>,
_duration: u64)
{
if self.oracle.is_major_syncing() { return }
if self.oracle.is_major_importing() { return }
trace!(target: "snapshot_watcher", "{} imported", imported.len());
@ -143,7 +143,7 @@ mod tests {
self.0.get(&hash).cloned()
}
fn is_major_syncing(&self) -> bool { false }
fn is_major_importing(&self) -> bool { false }
}
struct TestBroadcast(Option<u64>);

View File

@ -108,6 +108,7 @@ mod server {
use ethcore::client::{Client, BlockChainClient, BlockID};
use rpc_apis;
use ethcore_rpc::is_major_importing;
use ethcore_dapps::ContractClient;
pub use ethcore_dapps::Server as WebappServer;
@ -127,7 +128,8 @@ mod server {
Arc::new(Registrar { client: deps.client.clone() })
);
let sync = deps.sync.clone();
server.with_sync_status(Arc::new(move || sync.status().is_major_syncing()));
let client = deps.client.clone();
server.with_sync_status(Arc::new(move || is_major_importing(Some(sync.status().state), client.queue_info())));
server.with_signer_port(signer_port);
let server = rpc_apis::setup_rpc(server, deps.apis.clone(), rpc_apis::ApiSet::UnsafeContext);

View File

@ -29,6 +29,7 @@ use ethcore::views::BlockView;
use ethcore::snapshot::service::Service as SnapshotService;
use ethcore::snapshot::{RestorationStatus, SnapshotService as SS};
use number_prefix::{binary_prefix, Standalone, Prefixed};
use ethcore_rpc::is_major_importing;
pub struct Informant {
chain_info: RwLock<Option<BlockChainInfo>>,
@ -95,7 +96,7 @@ impl Informant {
let network_config = self.net.as_ref().map(|n| n.network_config());
let sync_status = self.sync.as_ref().map(|s| s.status());
let importing = self.sync.as_ref().map_or(false, |s| s.status().is_major_syncing());
let importing = is_major_importing(sync_status.map(|s| s.state), self.client.queue_info());
let (snapshot_sync, snapshot_current, snapshot_total) = self.snapshot.as_ref().map_or((false, 0, 0), |s|
match s.status() {
RestorationStatus::Ongoing { state_chunks, block_chunks, state_chunks_done, block_chunks_done } =>
@ -174,7 +175,8 @@ impl Informant {
impl ChainNotify for Informant {
fn new_blocks(&self, imported: Vec<H256>, _invalid: Vec<H256>, _enacted: Vec<H256>, _retracted: Vec<H256>, _sealed: Vec<H256>, duration: u64) {
let mut last_import = self.last_import.lock();
let importing = self.sync.as_ref().map_or(false, |s| s.status().is_major_syncing());
let sync_state = self.sync.as_ref().map(|s| s.status().state);
let importing = is_major_importing(sync_state, self.client.queue_info());
if Instant::now() > *last_import + Duration::from_secs(1) && !importing {
if let Some(block) = imported.last().and_then(|h| self.client.block(BlockID::Hash(*h))) {
let view = BlockView::new(&block);

View File

@ -18,11 +18,11 @@ use std::sync::{Arc, Mutex, Condvar};
use ctrlc::CtrlC;
use fdlimit::raise_fd_limit;
use ethcore_logger::{Config as LogConfig, setup_log};
use ethcore_rpc::NetworkSettings;
use ethcore_rpc::{NetworkSettings, is_major_importing};
use ethsync::NetworkConfiguration;
use util::{Colour, version, U256};
use io::{MayPanic, ForwardPanic, PanicHandler};
use ethcore::client::{Mode, DatabaseCompactionProfile, VMType, ChainNotify};
use ethcore::client::{Mode, DatabaseCompactionProfile, VMType, ChainNotify, BlockChainClient};
use ethcore::service::ClientService;
use ethcore::account_provider::AccountProvider;
use ethcore::miner::{Miner, MinerService, ExternalMiner, MinerOptions};
@ -315,7 +315,7 @@ pub fn execute(cmd: RunCmd) -> Result<(), String> {
let sync = sync_provider.clone();
let watcher = Arc::new(snapshot::Watcher::new(
service.client(),
move || ::ethsync::SyncProvider::status(&*sync).is_major_syncing(),
move || is_major_importing(Some(sync.status().state), client.queue_info()),
service.io().channel(),
SNAPSHOT_PERIOD,
SNAPSHOT_HISTORY,

View File

@ -56,6 +56,7 @@ use self::jsonrpc_core::{IoHandler, IoDelegate};
pub use jsonrpc_http_server::{ServerBuilder, Server, RpcServerError};
pub mod v1;
pub use v1::{SigningQueue, SignerService, ConfirmationsQueue, NetworkSettings};
pub use v1::block_import::is_major_importing;
/// An object that can be extended with `IoDelegates`
pub trait Extendable {

View File

@ -0,0 +1,60 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
//! Block import analysis functions.
use ethcore::client::BlockQueueInfo;
use ethsync::SyncState;
/// Check if client is during major sync or during block import.
pub fn is_major_importing(sync_state: Option<SyncState>, queue_info: BlockQueueInfo) -> bool {
let is_syncing_state = sync_state.map_or(false, |s|
s != SyncState::Idle && s != SyncState::NewBlocks
);
let is_verifying = queue_info.unverified_queue_size + queue_info.verified_queue_size > 3;
is_verifying || is_syncing_state
}
#[cfg(test)]
mod tests {
use ethcore::client::BlockQueueInfo;
use ethsync::SyncState;
use super::is_major_importing;
fn queue_info(unverified: usize, verified: usize) -> BlockQueueInfo {
BlockQueueInfo {
unverified_queue_size: unverified,
verified_queue_size: verified,
verifying_queue_size: 0,
max_queue_size: 1000,
max_mem_use: 1000,
mem_used: 500
}
}
#[test]
fn is_still_verifying() {
assert!(!is_major_importing(None, queue_info(2, 1)));
assert!(is_major_importing(None, queue_info(2, 2)));
}
#[test]
fn is_synced_state() {
assert!(is_major_importing(Some(SyncState::Blocks), queue_info(0, 0)));
assert!(!is_major_importing(Some(SyncState::Idle), queue_info(0, 0)));
}
}

View File

@ -22,6 +22,7 @@ pub mod errors;
pub mod dispatch;
pub mod params;
pub mod block_import;
mod poll_manager;
mod poll_filter;

View File

@ -49,6 +49,7 @@ use v1::types::{
};
use v1::helpers::{CallRequest as CRequest, errors, limit_logs};
use v1::helpers::dispatch::{default_gas_price, dispatch_transaction};
use v1::helpers::block_import::is_major_importing;
use v1::helpers::auto_args::Trailing;
/// Eth RPC options
@ -254,8 +255,9 @@ impl<C, S: ?Sized, M, EM> Eth for EthClient<C, S, M, EM> where
fn syncing(&self) -> Result<SyncStatus, Error> {
try!(self.active());
let status = take_weak!(self.sync).status();
if status.is_major_syncing() {
let current_block = U256::from(take_weak!(self.client).chain_info().best_block_number);
let client = take_weak!(self.client);
if is_major_importing(Some(status.state), client.queue_info()) {
let current_block = U256::from(client.chain_info().best_block_number);
let highest_block = U256::from(status.highest_block_number.unwrap_or(status.start_block_number));
let info = SyncInfo {
starting_block: status.start_block_number.into(),

View File

@ -28,4 +28,4 @@ pub mod types;
pub use self::traits::{Web3, Eth, EthFilter, EthSigning, Personal, PersonalSigner, Net, Ethcore, EthcoreSet, Traces, Rpc};
pub use self::impls::*;
pub use self::helpers::{SigningQueue, SignerService, ConfirmationsQueue, NetworkSettings};
pub use self::helpers::{SigningQueue, SignerService, ConfirmationsQueue, NetworkSettings, block_import};

View File

@ -202,17 +202,6 @@ pub struct SyncStatus {
}
impl SyncStatus {
/// Indicates if initial sync is still in progress.
pub fn is_major_syncing(&self) -> bool {
let is_synced_state = match self.state {
SyncState::Idle | SyncState::NewBlocks | SyncState::Blocks => true,
_ => false,
};
let is_current_block = self.highest_block_number.unwrap_or(self.start_block_number) < self.last_imported_block_number.unwrap_or(0) + BlockNumber::from(4u64);
// If not synced then is major syncing.
!(is_synced_state && is_current_block)
}
/// Indicates if snapshot download is in progress
pub fn is_snapshot_syncing(&self) -> bool {
self.state == SyncState::SnapshotManifest