From 0383af0f15eb9a04855ecec2bfefe2c58278b86a Mon Sep 17 00:00:00 2001 From: s-brian Date: Thu, 27 Aug 2015 22:35:54 +0100 Subject: [PATCH 1/5] Add a DataCache object for Data caching. --- src/cache.rs | 144 ++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 1 + src/routing.rs | 4 +- src/routing_client.rs | 2 + src/routing_node.rs | 37 +++-------- 5 files changed, 159 insertions(+), 29 deletions(-) create mode 100644 src/cache.rs diff --git a/src/cache.rs b/src/cache.rs new file mode 100644 index 0000000000..1b8ff4995a --- /dev/null +++ b/src/cache.rs @@ -0,0 +1,144 @@ +// Copyright 2015 MaidSafe.net limited. +// +// This SAFE Network Software is licensed to you under (1) the MaidSafe.net Commercial License, +// version 1.0 or later, or (2) The General Public License (GPL), version 3, depending on which +// licence you accepted on initial access to the Software (the "Licences"). +// +// By contributing code to the SAFE Network Software, or to this project generally, you agree to be +// bound by the terms of the MaidSafe Contributor Agreement, version 1.0. This, along with the +// Licenses can be found in the root directory of this project at LICENSE, COPYING and CONTRIBUTOR. +// +// Unless required by applicable law or agreed to in writing, the SAFE Network Software distributed +// under the GPL Licence is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. +// +// Please review the Licences for the specific language governing permissions and limitations +// relating to use of the SAFE Network Software. + +use lru_time_cache::LruCache; +use messages::{ExternalRequest, ExternalResponse}; +use data::{Data, DataRequest}; +use NameType; +use time::Duration; + +pub struct CacheOptions { + cache_plain_data: bool, + cache_structured_data: bool, + cache_immutable_data: bool, + duration: Option, + capacity: Option, +} + +impl CacheOptions { + + /// Construct with caching off. + pub fn new() -> CacheOptions { + CacheOptions { + cache_plain_data: false, + cache_structured_data: false, + cache_immutable_data: false, + duration: None, + capacity: None, + } + } +} + +pub struct DataCache { + cache: LruCache, + cache_options: CacheOptions, +} + +impl DataCache { + + /// Constructor accepting CacheOptions for the cache type and data types that are cacheable. + pub fn new(cache_options: CacheOptions) -> DataCache { + DataCache { + cache: DataCache::init_cache( + cache_options.duration.clone(), cache_options.capacity.clone()), + cache_options: cache_options, + } + } + + /// Insert a NameType/Data pair into the cache if cache_options accepts caching for the Data + /// type. Ignores optional return from LruCache insert. + pub fn insert(&mut self, response: ExternalResponse) { + match response { + ExternalResponse::Get(data, _, _) => { + match data { + Data::PlainData(ref plain_data) => { + if self.cache_options.cache_plain_data { + self.cache.insert(data.name(), data.clone()); + } + } + Data::StructuredData(ref structured_data) => { + if self.cache_options.cache_structured_data { + self.cache.insert(data.name(), data.clone()); + } + } + Data::ImmutableData(ref immutable_data) => { + if self.cache_options.cache_immutable_data { + self.cache.insert(data.name(), data.clone()); + } + } + } + } + _ => {} + }; + } + + /// Optionally retrieve a Data value from cache. + pub fn get(&mut self, request: ExternalRequest) -> Option<&Data> { + match request { + ExternalRequest::Get(data_request, _) => { + match data_request { + DataRequest::PlainData(data_name) => { + if self.cache_options.cache_plain_data { + return self.cache.get(&data_name) + } + return None; + } + DataRequest::StructuredData(data_name, _) => { + if self.cache_options.cache_structured_data { + return self.cache.get(&data_name); + } + return None; + } + DataRequest::ImmutableData(data_name, _) => { + if self.cache_options.cache_immutable_data { + return self.cache.get(&data_name); + } + return None; + } + } + } + _ => None, + } + } + + /// Returns true if a Data entry exists for the specified name. + pub fn contains_key(&self, name: &NameType) -> bool { + self.cache.contains_key(name) + } + + fn init_cache(time_to_live: Option, capacity: Option) + -> LruCache { + match (time_to_live, capacity) { + (Some(time_to_live), Some(capacity)) => { + LruCache::::with_expiry_duration_and_capacity(time_to_live, capacity) + } + (Some(time_to_live), None) => { + LruCache::::with_expiry_duration(time_to_live) + } + (None, Some(capacity)) => { + LruCache::::with_capacity(capacity) + } + (None, None) => { + LruCache::::with_capacity(0usize) + } + } + } +} + +#[cfg(test)] +mod test { +} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 0e1c2fdb5f..9b2747910b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -67,6 +67,7 @@ mod wake_up; mod peer; mod refresh_accumulator; mod message_accumulator; +mod cache; /// Routing provides an actionable interface to routing. pub mod routing; diff --git a/src/routing.rs b/src/routing.rs index 32ef234d53..47067be6d4 100644 --- a/src/routing.rs +++ b/src/routing.rs @@ -32,6 +32,7 @@ use error::{RoutingError, ResponseError}; use authority::Authority; use sodiumoxide::crypto; use messages::{ExternalRequest, ExternalResponse, InternalRequest, Content}; +use cache::CacheOptions; type RoutingResult = Result<(), RoutingError>; @@ -48,7 +49,7 @@ impl Routing { /// Starts a new RoutingIdentity, which will also start a new RoutingNode. /// The RoutingNode will attempt to achieve full routing node status. /// The intial Routing object will have newly generated keys - pub fn new(event_sender: mpsc::Sender) -> Routing { + pub fn new(event_sender: mpsc::Sender, cache_options: CacheOptions) -> Routing { sodiumoxide::init(); // enable shared global (i.e. safe to multithread now) let (action_sender, action_receiver) = mpsc::channel::(); @@ -58,6 +59,7 @@ impl Routing { action_receiver, event_sender, false, + cache_options, None); spawn(move || { diff --git a/src/routing_client.rs b/src/routing_client.rs index e17be4b9bf..ee7f51be38 100644 --- a/src/routing_client.rs +++ b/src/routing_client.rs @@ -32,6 +32,7 @@ use error::{RoutingError, ResponseError}; use authority::Authority; use sodiumoxide::crypto; use messages::{ExternalRequest, ExternalResponse, InternalRequest, Content}; +use cache::CacheOptions; type RoutingResult = Result<(), RoutingError>; @@ -60,6 +61,7 @@ impl RoutingClient { action_receiver, event_sender, true, + CacheOptions::new(), keys); spawn(move || { diff --git a/src/routing_node.rs b/src/routing_node.rs index f3224fad4a..9fb74da3df 100644 --- a/src/routing_node.rs +++ b/src/routing_node.rs @@ -47,6 +47,7 @@ use utils; use data::{Data, DataRequest}; use authority::{Authority, our_authority}; use wake_up::WakeUpCaller; +use cache::{CacheOptions, DataCache}; use messages::{RoutingMessage, SignedMessage, SignedToken, ConnectRequest, ConnectResponse, Content, ExternalRequest, ExternalResponse, InternalRequest, InternalResponse}; @@ -79,7 +80,7 @@ pub struct RoutingNode { public_id_cache: LruCache, accumulator: MessageAccumulator, refresh_accumulator: RefreshAccumulator, - data_cache: LruCache, + data_cache: DataCache, } impl RoutingNode { @@ -87,6 +88,7 @@ impl RoutingNode { action_receiver: mpsc::Receiver, event_sender: mpsc::Sender, client_restriction: bool, + cache_options: CacheOptions, keys: Option) -> RoutingNode { @@ -114,7 +116,7 @@ impl RoutingNode { public_id_cache: LruCache::with_expiry_duration(Duration::minutes(10)), accumulator: MessageAccumulator::new(), refresh_accumulator: RefreshAccumulator::new(), - data_cache: LruCache::with_expiry_duration(Duration::minutes(10)), + data_cache: DataCache::new(cache_options), } } @@ -1097,6 +1099,8 @@ impl RoutingNode { }; }; + // cache here !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + self.send_to_user(Event::Response { response : response, our_authority : to_authority, @@ -1147,35 +1151,12 @@ impl RoutingNode { } } - fn handle_cache_get(&mut self, request: ExternalRequest) -> Option { - match request { - ExternalRequest::Get(data_request, _) => { - match data_request { - DataRequest::ImmutableData(data_name, _) => { - match self.data_cache.get(&data_name) { - Some(data) => Some(data.clone()), - None => None, - } - } - _ => None - } - } - _ => None, - } + fn handle_cache_get(&mut self, request: ExternalRequest) -> Option<&Data> { + self.data_cache.get(request) } fn handle_cache_put(&mut self, response: ExternalResponse) { - match response { - ExternalResponse::Get(data, _, _) => { - match data { - Data::ImmutableData(ref immutable_data) => { - self.data_cache.insert(immutable_data.name(), data.clone()); - } - _ => {} - } - } - _ => {} - }; + self.data_cache.insert(response) } } From 8cdbe4f5dfc4adbc571fafae7bb0af0a9239e0df Mon Sep 17 00:00:00 2001 From: BSMaidSafe Date: Mon, 31 Aug 2015 17:37:02 +0100 Subject: [PATCH 2/5] Add caching to RoutingNode, remove cache.rs. --- src/action.rs | 2 + src/cache.rs | 144 ------------------------------ src/lib.rs | 1 - src/routing.rs | 12 ++- src/routing_client.rs | 2 - src/routing_node.rs | 202 +++++++++++++++++++++++++++++++++++++----- src/types.rs | 59 ++++++++++++ 7 files changed, 248 insertions(+), 174 deletions(-) delete mode 100644 src/cache.rs diff --git a/src/action.rs b/src/action.rs index 63b3cf6cc6..d75ce4ab75 100644 --- a/src/action.rs +++ b/src/action.rs @@ -17,6 +17,7 @@ use messages::{SignedMessage, Content}; use authority::Authority; +use types::CacheOptions; /// An Action initiates a message flow < A | B > where we are (a part of) A. /// 1. Action::SendMessage hands a fully formed SignedMessage over to RoutingNode @@ -36,6 +37,7 @@ pub enum Action { // | the destination authority // RoutingNode will form the RoutingMessage and sign it as its own identity Churn(::direct_messages::Churn, Vec<::crust::Endpoint>), + SetCacheOptions(CacheOptions), WakeUp, Terminate, } diff --git a/src/cache.rs b/src/cache.rs deleted file mode 100644 index 1b8ff4995a..0000000000 --- a/src/cache.rs +++ /dev/null @@ -1,144 +0,0 @@ -// Copyright 2015 MaidSafe.net limited. -// -// This SAFE Network Software is licensed to you under (1) the MaidSafe.net Commercial License, -// version 1.0 or later, or (2) The General Public License (GPL), version 3, depending on which -// licence you accepted on initial access to the Software (the "Licences"). -// -// By contributing code to the SAFE Network Software, or to this project generally, you agree to be -// bound by the terms of the MaidSafe Contributor Agreement, version 1.0. This, along with the -// Licenses can be found in the root directory of this project at LICENSE, COPYING and CONTRIBUTOR. -// -// Unless required by applicable law or agreed to in writing, the SAFE Network Software distributed -// under the GPL Licence is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. -// -// Please review the Licences for the specific language governing permissions and limitations -// relating to use of the SAFE Network Software. - -use lru_time_cache::LruCache; -use messages::{ExternalRequest, ExternalResponse}; -use data::{Data, DataRequest}; -use NameType; -use time::Duration; - -pub struct CacheOptions { - cache_plain_data: bool, - cache_structured_data: bool, - cache_immutable_data: bool, - duration: Option, - capacity: Option, -} - -impl CacheOptions { - - /// Construct with caching off. - pub fn new() -> CacheOptions { - CacheOptions { - cache_plain_data: false, - cache_structured_data: false, - cache_immutable_data: false, - duration: None, - capacity: None, - } - } -} - -pub struct DataCache { - cache: LruCache, - cache_options: CacheOptions, -} - -impl DataCache { - - /// Constructor accepting CacheOptions for the cache type and data types that are cacheable. - pub fn new(cache_options: CacheOptions) -> DataCache { - DataCache { - cache: DataCache::init_cache( - cache_options.duration.clone(), cache_options.capacity.clone()), - cache_options: cache_options, - } - } - - /// Insert a NameType/Data pair into the cache if cache_options accepts caching for the Data - /// type. Ignores optional return from LruCache insert. - pub fn insert(&mut self, response: ExternalResponse) { - match response { - ExternalResponse::Get(data, _, _) => { - match data { - Data::PlainData(ref plain_data) => { - if self.cache_options.cache_plain_data { - self.cache.insert(data.name(), data.clone()); - } - } - Data::StructuredData(ref structured_data) => { - if self.cache_options.cache_structured_data { - self.cache.insert(data.name(), data.clone()); - } - } - Data::ImmutableData(ref immutable_data) => { - if self.cache_options.cache_immutable_data { - self.cache.insert(data.name(), data.clone()); - } - } - } - } - _ => {} - }; - } - - /// Optionally retrieve a Data value from cache. - pub fn get(&mut self, request: ExternalRequest) -> Option<&Data> { - match request { - ExternalRequest::Get(data_request, _) => { - match data_request { - DataRequest::PlainData(data_name) => { - if self.cache_options.cache_plain_data { - return self.cache.get(&data_name) - } - return None; - } - DataRequest::StructuredData(data_name, _) => { - if self.cache_options.cache_structured_data { - return self.cache.get(&data_name); - } - return None; - } - DataRequest::ImmutableData(data_name, _) => { - if self.cache_options.cache_immutable_data { - return self.cache.get(&data_name); - } - return None; - } - } - } - _ => None, - } - } - - /// Returns true if a Data entry exists for the specified name. - pub fn contains_key(&self, name: &NameType) -> bool { - self.cache.contains_key(name) - } - - fn init_cache(time_to_live: Option, capacity: Option) - -> LruCache { - match (time_to_live, capacity) { - (Some(time_to_live), Some(capacity)) => { - LruCache::::with_expiry_duration_and_capacity(time_to_live, capacity) - } - (Some(time_to_live), None) => { - LruCache::::with_expiry_duration(time_to_live) - } - (None, Some(capacity)) => { - LruCache::::with_capacity(capacity) - } - (None, None) => { - LruCache::::with_capacity(0usize) - } - } - } -} - -#[cfg(test)] -mod test { -} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 9b2747910b..0e1c2fdb5f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -67,7 +67,6 @@ mod wake_up; mod peer; mod refresh_accumulator; mod message_accumulator; -mod cache; /// Routing provides an actionable interface to routing. pub mod routing; diff --git a/src/routing.rs b/src/routing.rs index 47067be6d4..1cd650d5b9 100644 --- a/src/routing.rs +++ b/src/routing.rs @@ -27,12 +27,11 @@ use messages::SignedToken; use routing_node::RoutingNode; use NameType; use data::{Data, DataRequest}; -use types::Bytes; +use types::{Bytes, CacheOptions}; use error::{RoutingError, ResponseError}; use authority::Authority; use sodiumoxide::crypto; use messages::{ExternalRequest, ExternalResponse, InternalRequest, Content}; -use cache::CacheOptions; type RoutingResult = Result<(), RoutingError>; @@ -49,7 +48,7 @@ impl Routing { /// Starts a new RoutingIdentity, which will also start a new RoutingNode. /// The RoutingNode will attempt to achieve full routing node status. /// The intial Routing object will have newly generated keys - pub fn new(event_sender: mpsc::Sender, cache_options: CacheOptions) -> Routing { + pub fn new(event_sender: mpsc::Sender) -> Routing { sodiumoxide::init(); // enable shared global (i.e. safe to multithread now) let (action_sender, action_receiver) = mpsc::channel::(); @@ -59,7 +58,6 @@ impl Routing { action_receiver, event_sender, false, - cache_options, None); spawn(move || { @@ -157,6 +155,12 @@ impl Routing { } + /// Dynamically enable/disable caching for Data types. + pub fn set_cache_options(&self, cache_options: CacheOptions) { + let _ = self.action_sender.send(Action::SetCacheOptions(cache_options)); + + } + /// Signal to RoutingNode that it needs to refuse new messages and handle all outstanding /// messages. After handling all messages it will send an Event::Terminated to the user. pub fn stop(&mut self) { diff --git a/src/routing_client.rs b/src/routing_client.rs index ee7f51be38..e17be4b9bf 100644 --- a/src/routing_client.rs +++ b/src/routing_client.rs @@ -32,7 +32,6 @@ use error::{RoutingError, ResponseError}; use authority::Authority; use sodiumoxide::crypto; use messages::{ExternalRequest, ExternalResponse, InternalRequest, Content}; -use cache::CacheOptions; type RoutingResult = Result<(), RoutingError>; @@ -61,7 +60,6 @@ impl RoutingClient { action_receiver, event_sender, true, - CacheOptions::new(), keys); spawn(move || { diff --git a/src/routing_node.rs b/src/routing_node.rs index 9fb74da3df..fd6fd9afd1 100644 --- a/src/routing_node.rs +++ b/src/routing_node.rs @@ -41,13 +41,12 @@ use id::Id; use public_id::PublicId; use hello::Hello; use types; -use types::{MessageId, Bytes, Address}; +use types::{MessageId, Bytes, Address, CacheOptions}; use utils::{encode, decode}; use utils; use data::{Data, DataRequest}; use authority::{Authority, our_authority}; use wake_up::WakeUpCaller; -use cache::{CacheOptions, DataCache}; use messages::{RoutingMessage, SignedMessage, SignedToken, ConnectRequest, ConnectResponse, Content, ExternalRequest, ExternalResponse, InternalRequest, InternalResponse}; @@ -80,7 +79,8 @@ pub struct RoutingNode { public_id_cache: LruCache, accumulator: MessageAccumulator, refresh_accumulator: RefreshAccumulator, - data_cache: DataCache, + cache_options: CacheOptions, + data_cache: Option>, } impl RoutingNode { @@ -88,7 +88,6 @@ impl RoutingNode { action_receiver: mpsc::Receiver, event_sender: mpsc::Sender, client_restriction: bool, - cache_options: CacheOptions, keys: Option) -> RoutingNode { @@ -116,7 +115,8 @@ impl RoutingNode { public_id_cache: LruCache::with_expiry_duration(Duration::minutes(10)), accumulator: MessageAccumulator::new(), refresh_accumulator: RefreshAccumulator::new(), - data_cache: DataCache::new(cache_options), + cache_options: CacheOptions::no_caching(), + data_cache: None, } } @@ -140,6 +140,9 @@ impl RoutingNode { Ok(Action::Churn(our_close_group, targets)) => { let _ = self.generate_churn(our_close_group, targets); }, + Ok(Action::SetCacheOptions(cache_options)) => { + self.set_cache_options(cache_options); + }, Ok(Action::WakeUp) => { // ensure that the loop is blocked for maximally 10ms }, @@ -413,6 +416,19 @@ impl RoutingNode { return Err(RoutingError::FilterCheckFailed); } + let message = signed_message.get_routing_message().clone(); + + // Cache a response if from a GetRequest and caching is enabled for the Data type. + self.handle_cache_put(&message); + // Get from cache if it's there. + match self.handle_cache_get(&message) { + Some(content) => { + return self.send_content( + Authority::ManagedNode(self.core.id().name()), message.source(), content); + }, + None => {} + } + // scan for remote names if self.core.is_connected_node() { match signed_message.claimant() { @@ -426,8 +442,6 @@ impl RoutingNode { ignore(self.send(signed_message.clone())); } - let message = signed_message.get_routing_message().clone(); - // check if our calculated authority matches the destination authority of the message let our_authority = self.core.our_authority(&message); if our_authority.clone().map(|our_auth| &message.to_authority != &our_auth).unwrap_or(true) { @@ -1081,7 +1095,7 @@ impl RoutingNode { // ----- Message Handlers that return to the event channel ------------------------------------ - fn handle_external_response(&self, + fn handle_external_response(&mut self, response: ExternalResponse, to_authority: Authority, from_authority: Authority) @@ -1099,8 +1113,6 @@ impl RoutingNode { }; }; - // cache here !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - self.send_to_user(Event::Response { response : response, our_authority : to_authority, @@ -1110,10 +1122,10 @@ impl RoutingNode { Ok(()) } - fn handle_refresh(&mut self, type_tag : u64, - sender : NameType, - payload : Bytes, - our_authority : Authority) -> RoutingResult { + fn handle_refresh(&mut self, type_tag: u64, + sender: NameType, + payload: Bytes, + our_authority: Authority) -> RoutingResult { debug_assert!(our_authority.is_group()); let threshold = self.group_threshold(); let group_name = our_authority.get_location().clone(); @@ -1151,12 +1163,139 @@ impl RoutingNode { } } - fn handle_cache_get(&mut self, request: ExternalRequest) -> Option<&Data> { - self.data_cache.get(request) + // ------ Cache handling ---------------------------------------------------------------------- + + fn set_cache_options(&mut self, cache_options: CacheOptions) { + self.cache_options.set_cache_options(cache_options); + if self.cache_options.caching_enabled() { + match self.data_cache { + None => self.data_cache = + Some(LruCache::::with_expiry_duration(Duration::minutes(10))), + Some(_) => {}, + } + } else { + self.data_cache = None; + } + } + + fn handle_cache_put(&mut self, message: &RoutingMessage) { + match self.data_cache { + Some(ref mut data_cache) => { + match message.content.clone() { + Content::ExternalResponse(response) => { + match response { + ExternalResponse::Get(data, _, _) => { + match data { + Data::PlainData(ref plain_data) => { + if self.cache_options.plain_data_caching_enabled() { + debug!("Caching PlainData {:?}", data.name()); + data_cache.insert(data.name(), data.clone()); + } + } + Data::StructuredData(ref structured_data) => { + if self.cache_options.structured_data_caching_enabled() { + debug!("Caching StructuredData {:?}", data.name()); + data_cache.insert(data.name(), data.clone()); + } + } + Data::ImmutableData(ref immutable_data) => { + if self.cache_options.immutable_data_caching_enabled() { + debug!("Caching ImmutableData {:?}", data.name()); + // TODO verify data + data_cache.insert(data.name(), data.clone()); + } + } + } + } + _ => {} + } + + }, + _ => {} + } + }, + None => {} + } + } - fn handle_cache_put(&mut self, response: ExternalResponse) { - self.data_cache.insert(response) + fn handle_cache_get(&mut self, message: &RoutingMessage) -> Option { + match self.data_cache { + Some(ref mut data_cache) => { + match message.content.clone() { + Content::ExternalRequest(request) => { + match request { + ExternalRequest::Get(data_request, _) => { + match data_request { + DataRequest::PlainData(data_name) => { + if self.cache_options.plain_data_caching_enabled() { + match data_cache.get(&data_name) { + Some(data) => { + let response = + ExternalResponse::Get( + data.clone(), + data_request, + None); + return Some(Content::ExternalResponse(response)); + }, + None => return None + } + } + return None; + } + DataRequest::StructuredData(data_name, version) => { + if self.cache_options.structured_data_caching_enabled() { + match data_cache.get(&data_name) { + Some(data) => { + match *data { + Data::StructuredData(ref structured_data) => { + if structured_data.get_version() == version { + let response = + ExternalResponse::Get( + data.clone(), + data_request, + None); + return Some(Content::ExternalResponse(response)); + } else { + return None + } + }, + _ => return None + } + }, + None => return None + } + } + return None; + } + DataRequest::ImmutableData(data_name, _) => { + if self.cache_options.immutable_data_caching_enabled() { + match data_cache.get(&data_name) { + Some(data) => { + let response = + ExternalResponse::Get( + data.clone(), + data_request, + None); + return Some(Content::ExternalResponse(response)); + }, + None => return None + } + } + return None; + } + } + } + _ => None, + } + + }, + _ => None, + } + + }, + None => None, + } } } @@ -1171,16 +1310,21 @@ mod test { use data::{Data, DataRequest}; use event::Event; use immutable_data::{ImmutableData, ImmutableDataType}; - use messages::{ExternalRequest, ExternalResponse, SignedToken}; + use messages::{ExternalRequest, ExternalResponse, SignedToken, RoutingMessage, Content}; use rand::{thread_rng, Rng}; use std::sync::mpsc; use super::RoutingNode; + use NameType; + use authority::Authority; + use types::CacheOptions; #[test] fn cache() { let (action_sender, action_receiver) = mpsc::channel::(); let (event_sender, _) = mpsc::channel::(); - let mut node = RoutingNode::new(action_sender, action_receiver, event_sender, false, None); + let mut node = RoutingNode::new(action_sender.clone(), action_receiver, event_sender, false, None); + let cache_options = CacheOptions::with_caching(false, false, true); + let _ = node.set_cache_options(cache_options); let mut data = [0u8; 64]; thread_rng().fill_bytes(&mut data); let immutable = ImmutableData::new(ImmutableDataType::Normal, @@ -1199,8 +1343,20 @@ mod test { let response = ExternalResponse::Get(immutable_data, data_request.clone(), Some(sign_token)); let request = ExternalRequest::Get(data_request, 0u8); - assert!(node.handle_cache_get(request.clone()).is_none()); - node.handle_cache_put(response); - assert!(node.handle_cache_get(request).is_some()); + let routing_message_request = RoutingMessage { + from_authority: Authority::ClientManager(NameType::new([1u8; 64])), + to_authority: Authority::NaeManager(NameType::new(data)), + content: Content::ExternalRequest(request) + }; + + let routing_message_response = RoutingMessage { + from_authority: Authority::NaeManager(NameType::new(data)), + to_authority: Authority::ClientManager(NameType::new([1u8; 64])), + content: Content::ExternalResponse(response) + }; + + assert!(node.handle_cache_get(&routing_message_request).is_none()); + node.handle_cache_put(&routing_message_response); + assert!(node.handle_cache_get(&routing_message_request).is_some()); } } diff --git a/src/types.rs b/src/types.rs index 0a4a437f85..66ba7d3a0b 100644 --- a/src/types.rs +++ b/src/types.rs @@ -96,6 +96,65 @@ impl Debug for Address { } } +#[derive(PartialEq, Eq, Clone, Debug)] +pub struct CacheOptions { + cache_plain_data: bool, + cache_structured_data: bool, + cache_immutable_data: bool, +} + +impl CacheOptions { + + /// Construct with caching off. + pub fn no_caching() -> CacheOptions { + CacheOptions { + cache_plain_data: false, + cache_structured_data: false, + cache_immutable_data: false, + } + } + + /// Construct with caching optionally set. + pub fn with_caching(cache_plain_data: bool, cache_structured_data: bool, cache_immutable_data: bool) + -> CacheOptions { + CacheOptions { + cache_plain_data: cache_plain_data, + cache_structured_data: cache_structured_data, + cache_immutable_data: cache_immutable_data, + } + } + + /// Enable or disable Data caching. + pub fn set_cache_options(&mut self, cache_options: CacheOptions) { + self.cache_plain_data = cache_options.cache_plain_data; + self.cache_structured_data = cache_options.cache_structured_data; + self.cache_immutable_data = cache_options.cache_immutable_data; + } + + /// Return true if any caching option is set otherwise false. + pub fn caching_enabled(& self) -> bool { + if self.cache_plain_data || self.cache_structured_data || self.cache_immutable_data { + return true; + } + false + } + + /// Return PlainData caching option. + pub fn plain_data_caching_enabled(& self) -> bool { + self.cache_plain_data + } + + /// Return StructuredData caching option. + pub fn structured_data_caching_enabled(& self) -> bool { + self.cache_structured_data + } + + /// Return ImmutableData caching option. + pub fn immutable_data_caching_enabled(& self) -> bool { + self.cache_immutable_data + } +} + // #[cfg(test)] // #[allow(deprecated)] // mod test { From c3007f709dd7823b47ddad375c07f955c065ea52 Mon Sep 17 00:00:00 2001 From: BSMaidSafe Date: Tue, 1 Sep 2015 11:33:04 +0100 Subject: [PATCH 3/5] Addresses issue raised in PR, additional tests. --- src/data.rs | 1 + src/routing_node.rs | 114 ++++++++++++++++++++++++++++++++++++-------- 2 files changed, 95 insertions(+), 20 deletions(-) diff --git a/src/data.rs b/src/data.rs index 30ae7ff3ed..c0d5a751c5 100644 --- a/src/data.rs +++ b/src/data.rs @@ -49,6 +49,7 @@ impl Data { #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, RustcEncodable, RustcDecodable)] pub enum DataRequest { + // (Identifier, TypeTag) pair for name resolution. StructuredData(NameType, u64), ImmutableData(NameType, ImmutableDataType), PlainData(NameType), diff --git a/src/routing_node.rs b/src/routing_node.rs index fa47ca598b..c551734b24 100644 --- a/src/routing_node.rs +++ b/src/routing_node.rs @@ -1234,25 +1234,17 @@ impl RoutingNode { } return None; } - DataRequest::StructuredData(data_name, version) => { + DataRequest::StructuredData(data_name, tag) => { if self.cache_options.structured_data_caching_enabled() { - match data_cache.get(&data_name) { + let name = StructuredData::compute_name(tag, &data_name); + match data_cache.get(&name) { Some(data) => { - match *data { - Data::StructuredData(ref structured_data) => { - if structured_data.get_version() == version { - let response = - ExternalResponse::Get( - data.clone(), - data_request, - None); - return Some(Content::ExternalResponse(response)); - } else { - return None - } - }, - _ => return None - } + let response = + ExternalResponse::Get( + data.clone(), + data_request, + None); + return Some(Content::ExternalResponse(response)); }, None => return None } @@ -1309,11 +1301,53 @@ mod test { use authority::Authority; use types::CacheOptions; - #[test] - fn cache() { + fn create_node() -> RoutingNode { let (action_sender, action_receiver) = mpsc::channel::(); let (event_sender, _) = mpsc::channel::(); - let mut node = RoutingNode::new(action_sender.clone(), action_receiver, event_sender, false, None); + RoutingNode::new(action_sender.clone(), action_receiver, event_sender, false, None) + } + + #[test] + fn no_caching() { + let mut node = create_node(); + let mut data = [0u8; 64]; + thread_rng().fill_bytes(&mut data); + let immutable = ImmutableData::new(ImmutableDataType::Normal, + data.iter().map(|&x|x).collect::>()); + let immutable_data = Data::ImmutableData(immutable.clone()); + let key_pair = crypto::sign::gen_keypair(); + let sig = crypto::sign::sign_detached(&data, &key_pair.1); + let sign_token = SignedToken { + serialised_request: data.iter().map(|&x|x).collect::>(), + signature: sig, + }; + + let data_request = DataRequest::ImmutableData(immutable.name().clone(), + immutable.get_type_tag().clone()); + + let response = ExternalResponse::Get(immutable_data, data_request.clone(), Some(sign_token)); + let request = ExternalRequest::Get(data_request, 0u8); + + let routing_message_request = RoutingMessage { + from_authority: Authority::ClientManager(NameType::new([1u8; 64])), + to_authority: Authority::NaeManager(NameType::new(data)), + content: Content::ExternalRequest(request) + }; + + let routing_message_response = RoutingMessage { + from_authority: Authority::NaeManager(NameType::new(data)), + to_authority: Authority::ClientManager(NameType::new([1u8; 64])), + content: Content::ExternalResponse(response) + }; + + assert!(node.handle_cache_get(&routing_message_request).is_none()); + node.handle_cache_put(&routing_message_response); + assert!(node.handle_cache_get(&routing_message_request).is_none()); + } + + #[test] + fn cache_for_type() { + let mut node = create_node(); let cache_options = CacheOptions::with_caching(false, false, true); let _ = node.set_cache_options(cache_options); let mut data = [0u8; 64]; @@ -1350,4 +1384,44 @@ mod test { node.handle_cache_put(&routing_message_response); assert!(node.handle_cache_get(&routing_message_request).is_some()); } + + #[test] + fn no_cache_for_type() { + let mut node = create_node(); + let cache_options = CacheOptions::with_caching(true, true, false); + let _ = node.set_cache_options(cache_options); + let mut data = [0u8; 64]; + thread_rng().fill_bytes(&mut data); + let immutable = ImmutableData::new(ImmutableDataType::Normal, + data.iter().map(|&x|x).collect::>()); + let immutable_data = Data::ImmutableData(immutable.clone()); + let key_pair = crypto::sign::gen_keypair(); + let sig = crypto::sign::sign_detached(&data, &key_pair.1); + let sign_token = SignedToken { + serialised_request: data.iter().map(|&x|x).collect::>(), + signature: sig, + }; + + let data_request = DataRequest::ImmutableData(immutable.name().clone(), + immutable.get_type_tag().clone()); + + let response = ExternalResponse::Get(immutable_data, data_request.clone(), Some(sign_token)); + let request = ExternalRequest::Get(data_request, 0u8); + + let routing_message_request = RoutingMessage { + from_authority: Authority::ClientManager(NameType::new([1u8; 64])), + to_authority: Authority::NaeManager(NameType::new(data)), + content: Content::ExternalRequest(request) + }; + + let routing_message_response = RoutingMessage { + from_authority: Authority::NaeManager(NameType::new(data)), + to_authority: Authority::ClientManager(NameType::new([1u8; 64])), + content: Content::ExternalResponse(response) + }; + + assert!(node.handle_cache_get(&routing_message_request).is_none()); + node.handle_cache_put(&routing_message_response); + assert!(node.handle_cache_get(&routing_message_request).is_none()); + } } From 938c1fdb0a48dfaa290cf568fc844403d1de45aa Mon Sep 17 00:00:00 2001 From: BSMaidSafe Date: Wed, 2 Sep 2015 12:55:37 +0100 Subject: [PATCH 4/5] Restructure cache tests. --- src/routing_node.rs | 119 +++++++++++++++----------------------------- 1 file changed, 39 insertions(+), 80 deletions(-) diff --git a/src/routing_node.rs b/src/routing_node.rs index c551734b24..1f767a3293 100644 --- a/src/routing_node.rs +++ b/src/routing_node.rs @@ -1222,6 +1222,7 @@ impl RoutingNode { if self.cache_options.plain_data_caching_enabled() { match data_cache.get(&data_name) { Some(data) => { + debug!("Got PlainData {:?} from cache", data_name); let response = ExternalResponse::Get( data.clone(), @@ -1239,6 +1240,7 @@ impl RoutingNode { let name = StructuredData::compute_name(tag, &data_name); match data_cache.get(&name) { Some(data) => { + debug!("Got StructuredData {:?} from cache", name); let response = ExternalResponse::Get( data.clone(), @@ -1255,6 +1257,7 @@ impl RoutingNode { if self.cache_options.immutable_data_caching_enabled() { match data_cache.get(&data_name) { Some(data) => { + debug!("Got ImmutableData {:?} from cache", data_name); let response = ExternalResponse::Get( data.clone(), @@ -1301,32 +1304,31 @@ mod test { use authority::Authority; use types::CacheOptions; - fn create_node() -> RoutingNode { + fn create_routing_node() -> RoutingNode { let (action_sender, action_receiver) = mpsc::channel::(); let (event_sender, _) = mpsc::channel::(); RoutingNode::new(action_sender.clone(), action_receiver, event_sender, false, None) } - #[test] - fn no_caching() { - let mut node = create_node(); + // RoutingMessage's for ImmutableData Get request/response. + fn generate_routing_messages() -> (RoutingMessage, RoutingMessage) { let mut data = [0u8; 64]; thread_rng().fill_bytes(&mut data); + let immutable = ImmutableData::new(ImmutableDataType::Normal, data.iter().map(|&x|x).collect::>()); let immutable_data = Data::ImmutableData(immutable.clone()); let key_pair = crypto::sign::gen_keypair(); - let sig = crypto::sign::sign_detached(&data, &key_pair.1); + let signature = crypto::sign::sign_detached(&data, &key_pair.1); let sign_token = SignedToken { serialised_request: data.iter().map(|&x|x).collect::>(), - signature: sig, + signature: signature, }; let data_request = DataRequest::ImmutableData(immutable.name().clone(), immutable.get_type_tag().clone()); - - let response = ExternalResponse::Get(immutable_data, data_request.clone(), Some(sign_token)); - let request = ExternalRequest::Get(data_request, 0u8); + let request = ExternalRequest::Get(data_request.clone(), 0u8); + let response = ExternalResponse::Get(immutable_data, data_request, Some(sign_token)); let routing_message_request = RoutingMessage { from_authority: Authority::ClientManager(NameType::new([1u8; 64])), @@ -1340,88 +1342,45 @@ mod test { content: Content::ExternalResponse(response) }; - assert!(node.handle_cache_get(&routing_message_request).is_none()); - node.handle_cache_put(&routing_message_response); - assert!(node.handle_cache_get(&routing_message_request).is_none()); + (routing_message_request, routing_message_response) } #[test] - fn cache_for_type() { - let mut node = create_node(); - let cache_options = CacheOptions::with_caching(false, false, true); - let _ = node.set_cache_options(cache_options); - let mut data = [0u8; 64]; - thread_rng().fill_bytes(&mut data); - let immutable = ImmutableData::new(ImmutableDataType::Normal, - data.iter().map(|&x|x).collect::>()); - let immutable_data = Data::ImmutableData(immutable.clone()); - let key_pair = crypto::sign::gen_keypair(); - let sig = crypto::sign::sign_detached(&data, &key_pair.1); - let sign_token = SignedToken { - serialised_request: data.iter().map(|&x|x).collect::>(), - signature: sig, - }; - - let data_request = DataRequest::ImmutableData(immutable.name().clone(), - immutable.get_type_tag().clone()); - - let response = ExternalResponse::Get(immutable_data, data_request.clone(), Some(sign_token)); - let request = ExternalRequest::Get(data_request, 0u8); + fn no_caching() { + let mut node = create_routing_node(); + // Get request/response RoutingMessage's for ImmutableData. + let (message_request, message_response) = generate_routing_messages(); - let routing_message_request = RoutingMessage { - from_authority: Authority::ClientManager(NameType::new([1u8; 64])), - to_authority: Authority::NaeManager(NameType::new(data)), - content: Content::ExternalRequest(request) - }; + assert!(node.handle_cache_get(&message_request).is_none()); + node.handle_cache_put(&message_response); + assert!(node.handle_cache_get(&message_request).is_none()); + } - let routing_message_response = RoutingMessage { - from_authority: Authority::NaeManager(NameType::new(data)), - to_authority: Authority::ClientManager(NameType::new([1u8; 64])), - content: Content::ExternalResponse(response) - }; + #[test] + fn enable_immutable_data_caching() { + let mut node = create_routing_node(); + // Enable caching for ImmutableData, disable for other Data types. + let cache_options = CacheOptions::with_caching(false, false, true); + let _ = node.set_cache_options(cache_options); + // Get request/response RoutingMessage's for ImmutableData. + let (message_request, message_response) = generate_routing_messages(); - assert!(node.handle_cache_get(&routing_message_request).is_none()); - node.handle_cache_put(&routing_message_response); - assert!(node.handle_cache_get(&routing_message_request).is_some()); + assert!(node.handle_cache_get(&message_request).is_none()); + node.handle_cache_put(&message_response); + assert!(node.handle_cache_get(&message_request).is_some()); } #[test] - fn no_cache_for_type() { - let mut node = create_node(); + fn disable_immutable_data_caching() { + let mut node = create_routing_node(); + // Disable caching for ImmutableData, enable for other Data types. let cache_options = CacheOptions::with_caching(true, true, false); let _ = node.set_cache_options(cache_options); - let mut data = [0u8; 64]; - thread_rng().fill_bytes(&mut data); - let immutable = ImmutableData::new(ImmutableDataType::Normal, - data.iter().map(|&x|x).collect::>()); - let immutable_data = Data::ImmutableData(immutable.clone()); - let key_pair = crypto::sign::gen_keypair(); - let sig = crypto::sign::sign_detached(&data, &key_pair.1); - let sign_token = SignedToken { - serialised_request: data.iter().map(|&x|x).collect::>(), - signature: sig, - }; - - let data_request = DataRequest::ImmutableData(immutable.name().clone(), - immutable.get_type_tag().clone()); - - let response = ExternalResponse::Get(immutable_data, data_request.clone(), Some(sign_token)); - let request = ExternalRequest::Get(data_request, 0u8); - - let routing_message_request = RoutingMessage { - from_authority: Authority::ClientManager(NameType::new([1u8; 64])), - to_authority: Authority::NaeManager(NameType::new(data)), - content: Content::ExternalRequest(request) - }; - - let routing_message_response = RoutingMessage { - from_authority: Authority::NaeManager(NameType::new(data)), - to_authority: Authority::ClientManager(NameType::new([1u8; 64])), - content: Content::ExternalResponse(response) - }; + // Get request/response RoutingMessage's for ImmutableData. + let (message_request, message_response) = generate_routing_messages(); - assert!(node.handle_cache_get(&routing_message_request).is_none()); - node.handle_cache_put(&routing_message_response); - assert!(node.handle_cache_get(&routing_message_request).is_none()); + assert!(node.handle_cache_get(&message_request).is_none()); + node.handle_cache_put(&message_response); + assert!(node.handle_cache_get(&message_request).is_none()); } } From bdd573477c2d5fbc28ef39690690d032ee040108 Mon Sep 17 00:00:00 2001 From: BSMaidSafe Date: Thu, 3 Sep 2015 13:17:49 +0100 Subject: [PATCH 5/5] Use DataRequest name function. --- src/routing_node.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/routing_node.rs b/src/routing_node.rs index ddeac66681..71ea3ba742 100644 --- a/src/routing_node.rs +++ b/src/routing_node.rs @@ -1221,7 +1221,8 @@ impl RoutingNode { if self.cache_options.plain_data_caching_enabled() { match data_cache.get(&data_name) { Some(data) => { - debug!("Got PlainData {:?} from cache", data_name); + debug!("Got PlainData {:?} from cache", + data_name); let response = ExternalResponse::Get( data.clone(), @@ -1236,10 +1237,10 @@ impl RoutingNode { } DataRequest::StructuredData(data_name, tag) => { if self.cache_options.structured_data_caching_enabled() { - let name = StructuredData::compute_name(tag, &data_name); - match data_cache.get(&name) { + match data_cache.get(&data_request.name()) { Some(data) => { - debug!("Got StructuredData {:?} from cache", name); + debug!("Got StructuredData {:?} from cache", + data_request.name()); let response = ExternalResponse::Get( data.clone(), @@ -1256,7 +1257,8 @@ impl RoutingNode { if self.cache_options.immutable_data_caching_enabled() { match data_cache.get(&data_name) { Some(data) => { - debug!("Got ImmutableData {:?} from cache", data_name); + debug!("Got ImmutableData {:?} from cache", + data_name); let response = ExternalResponse::Get( data.clone(),