Skip to content
This repository has been archived by the owner on Feb 3, 2023. It is now read-only.

Commit

Permalink
Merge pull request #226 from holochain/135-riker-one-sys
Browse files Browse the repository at this point in the history
riker for hash table
  • Loading branch information
thedavidmeister committed Aug 30, 2018
2 parents 93ac55c + d4dbbe7 commit d5e0c68
Show file tree
Hide file tree
Showing 23 changed files with 1,108 additions and 377 deletions.
6 changes: 6 additions & 0 deletions core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,15 @@ multihash = "0.8.0"
rust-base58 = "0.0.4"
bitflags = "1.0"
holochain_wasm_utils = { path = "../wasm_utils"}
riker = "0.1.7"
riker-default = "0.1.7"
riker-patterns = "0.1.7"
futures-preview = "0.2.2"
lazy_static = "1.1.0"
unwrap_to = "0.1.0"
num-traits = "0.2"
num-derive = "0.2"
config = "0.8"

[dev-dependencies]
wabt = "0.4"
Expand Down
98 changes: 98 additions & 0 deletions core/src/actor.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
use agent::keys::Keys;
use error::HolochainError;
use futures::executor::block_on;
use hash_table::{pair::Pair, pair_meta::PairMeta};
use riker::actors::*;
use riker_default::DefaultModel;
use riker_patterns::ask::ask;

#[derive(Clone, Debug)]
/// riker protocol for all our actors
/// currently this is flat but may be nested/namespaced in the future or multi-protocol riker
/// @see https://github.com/riker-rs/riker/issues/17
pub enum Protocol {
/// Chain::set_top_pair()
SetTopPair(Option<Pair>),
SetTopPairResult(Result<Option<Pair>, HolochainError>),

/// Chain::top_pair()
TopPair,
TopPairResult(Option<Pair>),

/// HashTable::setup()
Setup,
SetupResult(Result<(), HolochainError>),

/// HashTable::teardown()
Teardown,
TeardownResult(Result<(), HolochainError>),

/// HashTable::modify()
Modify {
keys: Keys,
old_pair: Pair,
new_pair: Pair,
},
ModifyResult(Result<(), HolochainError>),

/// HashTable::retract()
Retract {
keys: Keys,
pair: Pair,
},
RetractResult(Result<(), HolochainError>),

/// HashTable::assert_meta()
AssertMeta(PairMeta),
AssertMetaResult(Result<(), HolochainError>),

/// HashTable::get_meta()
Meta(String),
MetaResult(Result<Option<PairMeta>, HolochainError>),

/// HashTable::get_pair_meta()
PairMeta(Pair),
PairMetaResult(Result<Vec<PairMeta>, HolochainError>),

/// HashTable::pair()
Pair(String),
PairResult(Result<Option<Pair>, HolochainError>),

/// HashTable::commit()
Commit(Pair),
CommitResult(Result<(), HolochainError>),
}

/// this is the global state that manages every actor
/// to be thread/concurrency safe there must only ever be one actor system
/// @see https://github.com/riker-rs/riker/issues/17
/// @see http://riker.rs/actors/#creating-actors
lazy_static! {
pub static ref SYS: ActorSystem<Protocol> = {
let model: DefaultModel<Protocol> = DefaultModel::new();
ActorSystem::new(&model).unwrap()
};
}

/// required by riker
impl Into<ActorMsg<Protocol>> for Protocol {
fn into(self) -> ActorMsg<Protocol> {
ActorMsg::User(self)
}
}

/// convenience trait to build fake synchronous facades for actors
pub trait AskSelf {
/// adapter for synchronous code to interact with an actor
/// uses the ask() fn from riker patterns under the hood to create a future then block on it
/// handles passing the actor system through to ask() to hide that implementation detail
/// @see http://riker.rs/patterns/#ask
fn block_on_ask(&self, message: Protocol) -> Protocol;
}

impl AskSelf for ActorRef<Protocol> {
fn block_on_ask(&self, message: Protocol) -> Protocol {
let a = ask(&(*SYS), self, message);
block_on(a).unwrap()
}
}
102 changes: 49 additions & 53 deletions core/src/agent/state.rs
Original file line number Diff line number Diff line change
@@ -1,37 +1,33 @@
use action::{Action, ActionWrapper, AgentReduceFn};
use agent::keys::Keys;
use chain::Chain;
use chain::{Chain, SourceChain};
use context::Context;
use error::HolochainError;
use hash_table::{entry::Entry, memory::MemTable, pair::Pair};
use hash_table::pair::Pair;
use instance::Observer;
use std::{
collections::HashMap,
rc::Rc,
sync::{mpsc::Sender, Arc},
};

#[derive(Clone, Debug, PartialEq, Default)]
#[derive(Clone, Debug, PartialEq)]
/// struct to track the internal state of an agent exposed to reducers/observers
pub struct AgentState {
keys: Option<Keys>,
// @TODO how should this work with chains/HTs?
// @see https://github.com/holochain/holochain-rust/issues/137
// @see https://github.com/holochain/holochain-rust/issues/135
top_pair: Option<Pair>,
/// every action and the result of that action
// @TODO this will blow up memory, implement as some kind of dropping/FIFO with a limit?
// @see https://github.com/holochain/holochain-rust/issues/166
actions: HashMap<ActionWrapper, ActionResponse>,
chain: Chain,
}

impl AgentState {
/// builds a new, empty AgentState
pub fn new() -> AgentState {
pub fn new(chain: &Chain) -> AgentState {
AgentState {
keys: None,
top_pair: None,
actions: HashMap::new(),
chain: chain.clone(),
}
}

Expand All @@ -40,10 +36,9 @@ impl AgentState {
self.keys.clone()
}

/// getter for a copy of self.top_pair
/// should be used with a source chain for validation/safety
pub fn top_pair(&self) -> Option<Pair> {
self.top_pair.clone()
/// getter for the chain
pub fn chain(&self) -> &Chain {
&self.chain
}

/// getter for a copy of self.actions
Expand Down Expand Up @@ -98,17 +93,12 @@ fn reduce_commit(
let action = action_wrapper.action();
let entry = unwrap_to!(action => Action::Commit);

// add entry to source chain
// @TODO this does nothing!
// it needs to get something stateless from the agent state that points to
// something stateful that can handle an entire hash table (e.g. actor)
// @see https://github.com/holochain/holochain-rust/issues/135
// @see https://github.com/holochain/holochain-rust/issues/148
let mut chain = Chain::new(Rc::new(MemTable::new()));
// @TODO validation dispatch should go here rather than upstream in invoke_commit
// @see https://github.com/holochain/holochain-rust/issues/256

state.actions.insert(
action_wrapper.clone(),
ActionResponse::Commit(chain.push_entry(&entry)),
ActionResponse::Commit(state.chain.push_entry(&entry)),
);
}

Expand All @@ -124,27 +114,19 @@ fn reduce_get(
let action = action_wrapper.action();
let key = unwrap_to!(action => Action::Get);

// get pair from source chain
// @TODO this does nothing!
// it needs to get something stateless from the agent state that points to
// something stateful that can handle an entire hash table (e.g. actor)
// @see https://github.com/holochain/holochain-rust/issues/135
// @see https://github.com/holochain/holochain-rust/issues/148

// drop in a dummy entry for testing
let mut chain = Chain::new(Rc::new(MemTable::new()));
let e = Entry::new("testEntryType", "test entry content");
chain.push_entry(&e).expect("test entry should be valid");
let result = state.chain.entry(&key.clone());

// @TODO if the get fails local, do a network get
// @see https://github.com/holochain/holochain-rust/issues/167

let result = chain
.entry(&key)
.expect("should be able to get entry that we just added");
state
.actions
.insert(action_wrapper.clone(), ActionResponse::Get(result.clone()));
state.actions.insert(
action_wrapper.clone(),
ActionResponse::Get(
result
.clone()
.expect("should be able to get entry that we just added"),
),
);
}

/// maps incoming action to the correct handler
Expand Down Expand Up @@ -185,14 +167,15 @@ pub fn reduce(
pub mod tests {
use super::{reduce_commit, reduce_get, ActionResponse, AgentState};
use action::tests::{test_action_wrapper_commit, test_action_wrapper_get};
use chain::tests::test_chain;
use error::HolochainError;
use hash_table::pair::tests::test_pair;
use instance::tests::{test_context, test_instance_blank};
use std::collections::HashMap;
use std::{collections::HashMap, sync::Arc};

/// dummy agent state
pub fn test_agent_state() -> AgentState {
AgentState::new()
AgentState::new(&test_chain())
}

/// dummy action response for a successful commit as test_pair()
Expand All @@ -217,12 +200,6 @@ pub mod tests {
assert_eq!(None, test_agent_state().keys());
}

#[test]
/// test for the agent state top pair getter
fn agent_state_top_pair() {
assert_eq!(None, test_agent_state().top_pair());
}

#[test]
/// test for the agent state actions getter
fn agent_state_actions() {
Expand Down Expand Up @@ -255,22 +232,41 @@ pub mod tests {
/// test for reducing get
fn test_reduce_get() {
let mut state = test_agent_state();
let action_wrapper = test_action_wrapper_get();
let context = test_context("foo");

let instance = test_instance_blank();

let aw1 = test_action_wrapper_get();
reduce_get(
test_context("foo"),
Arc::clone(&context),
&mut state,
&action_wrapper,
&aw1,
&instance.action_channel().clone(),
&instance.observer_channel().clone(),
);

assert_eq!(
state.actions().get(&action_wrapper),
Some(&test_action_response_get()),
// nothing has been committed so the get must be None
assert_eq!(state.actions().get(&aw1), Some(&ActionResponse::Get(None)),);

// do a round trip
reduce_commit(
Arc::clone(&context),
&mut state,
&test_action_wrapper_commit(),
&instance.action_channel().clone(),
&instance.observer_channel().clone(),
);

let aw2 = test_action_wrapper_get();
reduce_get(
Arc::clone(&context),
&mut state,
&aw2,
&instance.action_channel().clone(),
&instance.observer_channel().clone(),
);

assert_eq!(state.actions().get(&aw2), Some(&test_action_response_get()),);
}

#[test]
Expand Down
Loading

0 comments on commit d5e0c68

Please sign in to comment.