├── arthas ├── src │ ├── utils │ │ ├── mod.rs │ │ ├── hash_map │ │ │ └── mod.rs │ │ └── file │ │ │ └── mod.rs │ ├── prelude │ │ └── mod.rs │ ├── tree │ │ ├── cmp │ │ │ └── mod.rs │ │ ├── rc │ │ │ ├── mod.rs │ │ │ ├── _type │ │ │ │ └── mod.rs │ │ │ ├── node │ │ │ │ └── mod.rs │ │ │ ├── data │ │ │ │ └── mod.rs │ │ │ ├── child │ │ │ │ └── mod.rs │ │ │ └── item │ │ │ │ └── mod.rs │ │ ├── searcher │ │ │ ├── meet │ │ │ │ └── mod.rs │ │ │ ├── entrance_type │ │ │ │ └── mod.rs │ │ │ ├── mod.rs │ │ │ ├── task │ │ │ │ └── mod.rs │ │ │ └── executor │ │ │ │ └── mod.rs │ │ ├── len │ │ │ └── mod.rs │ │ ├── deleter │ │ │ └── mod.rs │ │ ├── action │ │ │ └── mod.rs │ │ ├── mod.rs │ │ ├── inserter │ │ │ └── mod.rs │ │ ├── comparision │ │ │ └── mod.rs │ │ ├── math │ │ │ └── mod.rs │ │ └── node │ │ │ └── mod.rs │ ├── types │ │ ├── mod.rs │ │ ├── utc_date │ │ │ └── mod.rs │ │ └── utc_date_time │ │ │ └── mod.rs │ ├── query │ │ ├── order │ │ │ └── mod.rs │ │ ├── query_type │ │ │ └── mod.rs │ │ ├── action │ │ │ └── mod.rs │ │ └── mod.rs │ ├── macros │ │ └── mod.rs │ ├── config │ │ └── mod.rs │ ├── store │ │ ├── config │ │ │ └── mod.rs │ │ └── mod.rs │ ├── item │ │ ├── convertor │ │ │ └── mod.rs │ │ └── mod.rs │ ├── error │ │ └── mod.rs │ ├── persistence │ │ ├── operation │ │ │ └── mod.rs │ │ ├── meta │ │ │ └── mod.rs │ │ ├── service │ │ │ └── mod.rs │ │ ├── logger │ │ │ └── mod.rs │ │ └── mod.rs │ ├── traits │ │ └── mod.rs │ ├── lib.rs │ ├── memory │ │ └── mod.rs │ ├── encoder │ │ └── mod.rs │ └── loader │ │ └── mod.rs ├── tests │ ├── persistence.rs │ ├── error.rs │ ├── leaks.rs │ ├── common │ │ └── mod.rs │ ├── model │ │ └── mod.rs │ ├── concurrency.rs │ ├── crud.rs │ └── encoder.rs ├── benches │ ├── crud.rs │ └── memory.rs └── Cargo.toml ├── .gitignore ├── .travis.yml ├── arthas_derive ├── Cargo.toml └── src │ └── lib.rs ├── LICENSE └── README.md /arthas/src/utils/mod.rs: -------------------------------------------------------------------------------- 1 | 2 | pub mod file; 3 | pub mod hash_map; 4 | -------------------------------------------------------------------------------- /arthas/src/prelude/mod.rs: -------------------------------------------------------------------------------- 1 | //! The Arthas Prelude. 2 | 3 | pub use traits::Arthas; 4 | -------------------------------------------------------------------------------- /arthas/src/tree/cmp/mod.rs: -------------------------------------------------------------------------------- 1 | 2 | #[derive(Debug, PartialEq, Clone)] 3 | pub enum Cmp { 4 | Eq, 5 | Ne, 6 | Gt, 7 | Lt, 8 | Ge, 9 | Le, 10 | } 11 | -------------------------------------------------------------------------------- /arthas/src/types/mod.rs: -------------------------------------------------------------------------------- 1 | //! Additional types for daily use. 2 | 3 | mod utc_date; 4 | mod utc_date_time; 5 | 6 | pub use self::utc_date::UtcDate; 7 | pub use self::utc_date_time::UtcDateTime; 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *~ 3 | *# 4 | *.o 5 | *.so 6 | *.swp 7 | *.dylib 8 | *.dSYM 9 | *.dll 10 | *.rlib 11 | *.dummy 12 | *.exe 13 | *-test 14 | target/ 15 | Cargo.lock 16 | arthas.ar/ 17 | *.ar 18 | *.arx 19 | *.saving 20 | -------------------------------------------------------------------------------- /arthas/src/query/order/mod.rs: -------------------------------------------------------------------------------- 1 | 2 | #[derive(PartialEq, Debug, Clone)] 3 | pub enum Order { 4 | Asc, 5 | Desc, 6 | } 7 | 8 | impl Default for Order { 9 | fn default() -> Order { 10 | Order::Asc 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /arthas/src/query/query_type/mod.rs: -------------------------------------------------------------------------------- 1 | 2 | #[derive(PartialEq, Debug, Clone)] 3 | pub enum QueryType { 4 | Find, 5 | Count, 6 | } 7 | 8 | impl Default for QueryType { 9 | fn default() -> QueryType { 10 | QueryType::Find 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /arthas/src/types/utc_date/mod.rs: -------------------------------------------------------------------------------- 1 | 2 | use chrono::*; 3 | 4 | 5 | /// UTC Date. 6 | pub struct UtcDate(Date); 7 | 8 | impl UtcDate { 9 | /// Create UTC Date from now. 10 | pub fn new() -> UtcDate { 11 | UtcDate(UTC::today()) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /arthas/src/tree/rc/mod.rs: -------------------------------------------------------------------------------- 1 | 2 | mod data; 3 | mod item; 4 | mod child; 5 | mod _type; 6 | mod node; 7 | 8 | pub use self::data::RcData; 9 | pub use self::item::RcItem; 10 | pub use self::child::RcChild; 11 | pub use self::_type::DataType; 12 | pub use self::node::RcNode; 13 | -------------------------------------------------------------------------------- /arthas/src/macros/mod.rs: -------------------------------------------------------------------------------- 1 | 2 | #[doc(hidden)] 3 | #[macro_export] 4 | macro_rules! thread_trace { 5 | ($fmt:tt) => (trace!("{}", format!("{}: {}", ::thread_id::get(), $fmt))); 6 | ($fmt:tt, $($arg:tt)+) => (trace!("{}", format!("{}: {}", ::thread_id::get(), format!($fmt, $($arg)+)))) 7 | } 8 | -------------------------------------------------------------------------------- /arthas/src/types/utc_date_time/mod.rs: -------------------------------------------------------------------------------- 1 | 2 | use chrono::*; 3 | 4 | 5 | /// UTC Date Time. 6 | pub struct UtcDateTime(DateTime); 7 | 8 | impl UtcDateTime { 9 | /// Create UTC DateTime from now. 10 | pub fn new() -> UtcDateTime { 11 | UtcDateTime(UTC::now()) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /arthas/src/query/action/mod.rs: -------------------------------------------------------------------------------- 1 | 2 | #[derive(Debug)] 3 | pub enum Action { 4 | Insert, 5 | Find, 6 | FindOne, 7 | Count, 8 | Replace, 9 | Update, 10 | Remove, 11 | } 12 | 13 | impl Default for Action { 14 | fn default() -> Action { 15 | Action::Find 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: rust 2 | rust: 3 | - stable 4 | - beta 5 | os: 6 | - linux 7 | - osx 8 | cache: cargo 9 | script: 10 | - (cd arthas && cargo build) 11 | - (cd arthas && cargo test) 12 | - (cd arthas && cargo doc) 13 | - (cd arthas_derive && cargo build) 14 | - (cd arthas_derive && cargo doc) 15 | -------------------------------------------------------------------------------- /arthas/src/config/mod.rs: -------------------------------------------------------------------------------- 1 | //! Config Arthas. 2 | 3 | use std::path::Path; 4 | use store::config; 5 | 6 | 7 | /// Set `false` to disable persistence. Defaults to `true`. 8 | pub fn persistence(persistence: bool) { 9 | config().write().unwrap().persistence = persistence; 10 | } 11 | 12 | /// Set arthas root path. Defaults to `arthas.ar`. 13 | pub fn path>(path: P) { 14 | config().write().unwrap().path = path.as_ref().to_owned(); 15 | } 16 | -------------------------------------------------------------------------------- /arthas/src/store/config/mod.rs: -------------------------------------------------------------------------------- 1 | 2 | use std::path::PathBuf; 3 | use std::env; 4 | use DATA_DIR; 5 | 6 | 7 | pub struct Config { 8 | pub persistence: bool, 9 | pub path: PathBuf, 10 | } 11 | 12 | impl Config { 13 | pub fn new() -> Config { 14 | Config { 15 | persistence: true, 16 | path: get_path(), 17 | } 18 | } 19 | } 20 | 21 | fn get_path() -> PathBuf { 22 | env::current_dir().unwrap().join(DATA_DIR) 23 | } 24 | -------------------------------------------------------------------------------- /arthas/src/utils/hash_map/mod.rs: -------------------------------------------------------------------------------- 1 | 2 | use std::collections::HashMap; 3 | use std::iter::IntoIterator; 4 | use std::cmp::Eq; 5 | use std::hash::Hash; 6 | 7 | 8 | pub fn revert(hash_map: HashMap) -> HashMap 9 | where HashMap: IntoIterator, 10 | V: Eq + Hash 11 | { 12 | let mut reverted_map = HashMap::new(); 13 | 14 | for (k, v) in hash_map { 15 | reverted_map.insert(v, k); 16 | } 17 | 18 | reverted_map 19 | } 20 | -------------------------------------------------------------------------------- /arthas/tests/persistence.rs: -------------------------------------------------------------------------------- 1 | 2 | #[macro_use] 3 | extern crate serde_derive; 4 | #[macro_use] 5 | extern crate arthas_derive; 6 | extern crate rand; 7 | extern crate arthas; 8 | extern crate env_logger; 9 | 10 | pub mod common; 11 | pub mod model; 12 | 13 | use model::*; 14 | use common::setup; 15 | 16 | 17 | #[test] 18 | fn test_persistence_insert() { 19 | setup(); 20 | 21 | for i in 0..10 { 22 | Article::session() 23 | .insert(Article::new("Foobar!").views(i)) 24 | .unwrap(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /arthas_derive/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "arthas_derive" 3 | version = "0.1.0" 4 | description = "Macros 1.1 implementation of #[derive(Arthas)]" 5 | keywords = ["database", "in-memory", "structure", "db", "embedded"] 6 | authors = ["fengcen "] 7 | repository = "https://github.com/fengcen/arthas.git" 8 | homepage = "https://github.com/fengcen/arthas" 9 | documentation = "https://github.com/fengcen/arthas" 10 | license = "MIT" 11 | 12 | [lib] 13 | name = "arthas_derive" 14 | plugin = true 15 | path = "src/lib.rs" 16 | crate-type = ["proc-macro"] 17 | 18 | [dependencies] 19 | syn = "^0.11" 20 | quote = "^0.3" 21 | regex = "^0.2" 22 | -------------------------------------------------------------------------------- /arthas/src/tree/searcher/meet/mod.rs: -------------------------------------------------------------------------------- 1 | 2 | use super::super::cmp::Cmp; 3 | use super::super::math::Math; 4 | use serde_json::Value; 5 | 6 | 7 | pub trait Meet { 8 | fn meet(&self, cmp: &Cmp, other: &Value) -> bool; 9 | } 10 | 11 | impl Meet for Value { 12 | fn meet(&self, cmp: &Cmp, other: &Value) -> bool { 13 | match *cmp { 14 | Cmp::Eq => Math::eq(self, other), 15 | Cmp::Gt => Math::gt(self, other), 16 | Cmp::Lt => Math::lt(self, other), 17 | Cmp::Ge => Math::ge(self, other), 18 | Cmp::Le => Math::le(self, other), 19 | Cmp::Ne => Math::ne(self, other), 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /arthas/src/tree/rc/_type/mod.rs: -------------------------------------------------------------------------------- 1 | 2 | use serde_json::Value; 3 | 4 | 5 | #[derive(Clone, Debug)] 6 | pub enum DataType { 7 | String, 8 | Number, 9 | Bool, 10 | Array, 11 | Object, 12 | Null, 13 | } 14 | 15 | impl<'a> From<&'a Value> for DataType { 16 | fn from(value: &Value) -> DataType { 17 | match *value { 18 | Value::String(_) => DataType::String, 19 | Value::Number(_) => DataType::Number, 20 | Value::Bool(_) => DataType::Bool, 21 | Value::Null => DataType::Null, 22 | Value::Array(_) => DataType::Array, 23 | Value::Object(_) => DataType::Object, 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /arthas/src/item/convertor/mod.rs: -------------------------------------------------------------------------------- 1 | 2 | use super::ItemWrapper; 3 | use serde_json::{self, Value}; 4 | use traits::{Structure, FieldIntMap}; 5 | use error::Error; 6 | use encoder; 7 | 8 | 9 | pub trait Convertor { 10 | fn to_wrapper(&self, 11 | field_int_map: &FieldIntMap) 12 | -> Result, Error>; 13 | } 14 | 15 | impl Convertor for Value { 16 | fn to_wrapper(&self, 17 | field_int_map: &FieldIntMap) 18 | -> Result, Error> { 19 | Ok(serde_json::from_value::>(encoder::decode_wrapper(self, field_int_map))?) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /arthas/tests/error.rs: -------------------------------------------------------------------------------- 1 | 2 | #[macro_use] 3 | extern crate serde_derive; 4 | #[macro_use] 5 | extern crate arthas_derive; 6 | extern crate rand; 7 | extern crate arthas; 8 | extern crate env_logger; 9 | 10 | pub mod common; 11 | pub mod model; 12 | 13 | use model::*; 14 | use arthas::Error; 15 | use common::setup; 16 | 17 | #[test] 18 | fn test_can_not_replace() { 19 | setup(); 20 | 21 | assert_eq!(Comment::session().replace(Comment { ..Default::default() }), 22 | Err(Error::CanNotReplace)); 23 | } 24 | 25 | #[test] 26 | fn test_field_not_found() { 27 | setup(); 28 | 29 | assert_eq!(Article::session().field("bad field").eq("bad value").find(), 30 | Err(Error::FieldNotFound)); 31 | } 32 | -------------------------------------------------------------------------------- /arthas/tests/leaks.rs: -------------------------------------------------------------------------------- 1 | 2 | #[macro_use] 3 | extern crate serde_derive; 4 | #[macro_use] 5 | extern crate arthas_derive; 6 | extern crate rand; 7 | extern crate arthas; 8 | extern crate env_logger; 9 | 10 | pub mod common; 11 | pub mod model; 12 | 13 | use std::time::Duration; 14 | use std::thread::sleep; 15 | use model::*; 16 | use common::memory_setup; 17 | 18 | 19 | #[test] 20 | #[ignore] 21 | fn test_memory_leaks() { 22 | memory_setup(); 23 | 24 | for _ in 0..10000 { 25 | let id = Article::session() 26 | .insert(Article::new("Hello world!")) 27 | .unwrap(); 28 | 29 | Article::session().id(&id).remove().unwrap(); 30 | } 31 | 32 | sleep(Duration::from_secs(3)); 33 | } 34 | -------------------------------------------------------------------------------- /arthas/src/error/mod.rs: -------------------------------------------------------------------------------- 1 | 2 | quick_error! { 3 | #[derive(Debug, PartialEq)] 4 | /// Arthas error. 5 | pub enum Error { 6 | /// Only struct which has field `_id` can use `replace` method. 7 | CanNotReplace { 8 | display("Only struct which has field `_id` can use replace method") 9 | } 10 | /// Serialize error. 11 | Serialize { 12 | from(::serde_json::error::Error) 13 | } 14 | /// Requires id. 15 | RequiresId { 16 | display("Requires id.") 17 | } 18 | /// No field in the struct. 19 | FieldNotFound { 20 | display("Query field can not be not found in the struct.") 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /arthas/src/persistence/operation/mod.rs: -------------------------------------------------------------------------------- 1 | 2 | use serde_json::Value; 3 | use item::Id; 4 | 5 | 6 | #[derive(Default)] 7 | pub struct Operation { 8 | pub value: Option, 9 | pub id: Option, 10 | pub insert: bool, 11 | pub delete: bool, 12 | } 13 | 14 | impl Operation { 15 | pub fn new() -> Operation { 16 | Operation { ..Default::default() } 17 | } 18 | 19 | pub fn id(mut self, id: Id) -> Operation { 20 | self.id = Some(id); 21 | self 22 | } 23 | 24 | pub fn value(mut self, value: Value) -> Operation { 25 | self.value = Some(value); 26 | self 27 | } 28 | 29 | pub fn insert(mut self) -> Operation { 30 | self.insert = true; 31 | self 32 | } 33 | 34 | pub fn delete(mut self) -> Operation { 35 | self.delete = true; 36 | self 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /arthas/src/tree/len/mod.rs: -------------------------------------------------------------------------------- 1 | 2 | use serde_json::{self, Value}; 3 | use super::rc::RcData; 4 | 5 | 6 | pub trait Len { 7 | fn can_len(&self) -> bool; 8 | fn create_len_rc_data(&self) -> Option; 9 | } 10 | 11 | impl Len for Value { 12 | fn can_len(&self) -> bool { 13 | match *self { 14 | Value::Array(_) | Value::Object(_) | Value::String(_) => true, 15 | _ => false, 16 | } 17 | } 18 | 19 | fn create_len_rc_data(&self) -> Option { 20 | match *self { 21 | Value::Array(ref array) => create_rc_data_by_usize(array.len()), 22 | Value::Object(ref map) => create_rc_data_by_usize(map.len()), 23 | Value::String(ref string) => create_rc_data_by_usize(string.len()), 24 | _ => None, 25 | } 26 | } 27 | } 28 | 29 | #[inline] 30 | fn create_rc_data_by_usize(len: usize) -> Option { 31 | Some(RcData::new(Box::into_raw(Box::new(Value::Number(serde_json::Number::from(len)))))) 32 | } 33 | -------------------------------------------------------------------------------- /arthas/src/persistence/meta/mod.rs: -------------------------------------------------------------------------------- 1 | 2 | pub struct Meta { 3 | pub offset: usize, 4 | pub real: usize, 5 | pub size: usize, 6 | } 7 | 8 | impl Meta { 9 | pub fn new(bytes: &[u8]) -> Meta { 10 | let size = bytes.len(); 11 | Meta { 12 | offset: 0, 13 | real: size, 14 | size: size, 15 | } 16 | } 17 | 18 | pub fn to_simple(&self) -> SimpleMeta { 19 | SimpleMeta(self.offset, self.real, self.size) 20 | } 21 | } 22 | 23 | 24 | #[derive(Default, Debug, Clone, Serialize, Deserialize)] 25 | pub struct SimpleMeta(usize, usize, usize); 26 | 27 | impl SimpleMeta { 28 | pub fn set_offset(&mut self, v: usize) { 29 | self.0 = v; 30 | } 31 | 32 | pub fn set_real(&mut self, v: usize) { 33 | self.1 = v; 34 | } 35 | 36 | pub fn offset(&self) -> usize { 37 | self.0 38 | } 39 | 40 | pub fn real(&self) -> usize { 41 | self.1 42 | } 43 | 44 | pub fn size(&self) -> usize { 45 | self.2 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /arthas/src/item/mod.rs: -------------------------------------------------------------------------------- 1 | 2 | pub mod convertor; 3 | 4 | use objectid::ObjectId; 5 | use traits::Structure; 6 | 7 | 8 | /// Item id 9 | pub type Id = String; 10 | pub type StructName = String; 11 | pub type FieldInt = String; 12 | 13 | 14 | #[derive(Debug, Serialize, Deserialize, Clone)] 15 | pub struct ItemWrapper { 16 | pub item: T, 17 | pub id: Id, 18 | } 19 | 20 | impl ItemWrapper { 21 | pub fn new(mut item: T) -> ItemWrapper { 22 | let id = if T::has_id() { 23 | let mut id = item.get_id(); 24 | if id.is_empty() { 25 | id = create_id(); 26 | item.set_id(id.clone()); 27 | } 28 | id 29 | } else { 30 | create_id() 31 | }; 32 | 33 | ItemWrapper { 34 | item: item, 35 | id: id, 36 | } 37 | } 38 | } 39 | 40 | #[inline] 41 | fn create_id() -> String { 42 | ObjectId::new().unwrap().to_string() 43 | } 44 | 45 | #[inline] 46 | pub fn get_len_field_int(field_int: &str) -> String { 47 | format!("len({})", field_int) 48 | } 49 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 fengcen 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /arthas/benches/crud.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(all(feature = "unstable", test), feature(test))] 2 | 3 | #[macro_use] 4 | extern crate serde_derive; 5 | #[macro_use] 6 | extern crate arthas_derive; 7 | extern crate rand; 8 | extern crate arthas; 9 | extern crate env_logger; 10 | 11 | #[path = "../tests/common/mod.rs"] 12 | pub mod common; 13 | #[path = "../tests/model/mod.rs"] 14 | pub mod model; 15 | 16 | #[cfg(all(feature = "unstable", test))] 17 | mod benches { 18 | extern crate test; 19 | 20 | use model::*; 21 | use super::common::setup; 22 | 23 | #[bench] 24 | fn bench_a_insert(b: &mut test::Bencher) { 25 | setup(); 26 | 27 | b.iter(|| { 28 | Article::session() 29 | .insert(Article::new("Hello world!")) 30 | .unwrap() 31 | }) 32 | } 33 | 34 | #[bench] 35 | fn bench_find(b: &mut test::Bencher) { 36 | setup(); 37 | 38 | b.iter(|| { 39 | Article::session() 40 | .field("title") 41 | .eq("Hello world!") 42 | .limit(100) 43 | .find() 44 | .unwrap() 45 | }) 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /arthas/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "arthas" 3 | version = "0.3.0" 4 | description = "Arthas is an in-memory structure database." 5 | keywords = ["database", "in-memory", "structure", "db", "embedded"] 6 | authors = ["fengcen "] 7 | repository = "https://github.com/fengcen/arthas.git" 8 | homepage = "https://github.com/fengcen/arthas" 9 | documentation = "https://github.com/fengcen/arthas" 10 | license = "MIT" 11 | 12 | [lib] 13 | name = "arthas" 14 | path = "src/lib.rs" 15 | 16 | [features] 17 | unstable = [] 18 | 19 | [dependencies] 20 | quick-error = "^1.1" 21 | glob = "^0.2" 22 | memmap = "^0.5" 23 | bincode = "^0.6" 24 | serde = "^1.0" 25 | serde_json = "^1.0" 26 | serde_derive = "^1.0" 27 | libc = "^0.2" 28 | num_cpus = "^1.2" 29 | scoped-pool = "^1.0" 30 | lazy_static = "^0.2" 31 | quickersort = "^2.1" 32 | log = "^0.3" 33 | thread-id = "^3.0" 34 | vec_map = "^0.6" 35 | chrono = { version = "^0.2", features = ["serde"] } 36 | objectid = { version = "^0.1", features = ["serde"] } 37 | 38 | [dev-dependencies] 39 | arthas_derive = { version = "^0.1", path = "../arthas_derive" } 40 | maplit = "^0.1" 41 | mktemp = "^0.3" 42 | rand = "^0.3" 43 | env_logger = "^0.3" 44 | -------------------------------------------------------------------------------- /arthas/src/tree/deleter/mod.rs: -------------------------------------------------------------------------------- 1 | 2 | use super::Tree; 3 | 4 | 5 | pub struct Deleter {} 6 | 7 | impl Deleter { 8 | pub fn delete(tree: &mut Tree, id: &str) { 9 | thread_trace!("delete id: {}", id); 10 | let rc_item = tree.id_map.remove(id); 11 | if rc_item.is_none() { 12 | return; 13 | } 14 | 15 | let rc_item = rc_item.unwrap(); 16 | 17 | for (field_int, rc_node) in &rc_item.read().unwrap().nodes { 18 | let (clear, deleted_rc_node, root) = rc_node.write().unwrap().delete(id); 19 | if clear { 20 | let rc_node = tree.root.remove(field_int); 21 | if rc_node.is_some() { 22 | rc_node.unwrap().destroy(); 23 | } 24 | } else if deleted_rc_node.is_some() { 25 | deleted_rc_node.unwrap().destroy(); 26 | } 27 | 28 | if root.is_some() { 29 | tree.root.insert(field_int.clone(), root.unwrap()); 30 | } 31 | } 32 | 33 | rc_item.destroy(); 34 | } 35 | 36 | pub fn clear(tree: &mut Tree) { 37 | tree.id_map.clear(); 38 | tree.root.clear(); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /arthas/src/tree/rc/node/mod.rs: -------------------------------------------------------------------------------- 1 | 2 | use std::sync::RwLock; 3 | use std::ops::Deref; 4 | use std::ops::DerefMut; 5 | use item::Id; 6 | use super::RcChild; 7 | use super::super::node::Node; 8 | 9 | 10 | #[derive(Clone, Debug)] 11 | pub struct RcNode(*mut RwLock); 12 | 13 | impl RcNode { 14 | pub fn new(id: Id, rc_child: RcChild) -> RcNode { 15 | RcNode(Box::into_raw(Box::new(RwLock::new(Node::new(id, rc_child))))) 16 | } 17 | 18 | pub fn destroy(self) { 19 | let rc_node = unsafe { Box::from_raw(self.0) }; 20 | let node = rc_node.write().unwrap(); 21 | let mut group = node.group.write().unwrap(); 22 | 23 | for (_, rc_child) in group.drain() { 24 | rc_child.destroy(); 25 | } 26 | } 27 | } 28 | 29 | unsafe impl Send for RcNode {} 30 | unsafe impl Sync for RcNode {} 31 | 32 | impl Deref for RcNode { 33 | type Target = RwLock; 34 | fn deref(&self) -> &Self::Target { 35 | unsafe { &*self.0 } 36 | } 37 | } 38 | 39 | impl DerefMut for RcNode { 40 | fn deref_mut(&mut self) -> &mut Self::Target { 41 | unsafe { &mut *self.0 } 42 | } 43 | } 44 | 45 | impl PartialEq for RcNode { 46 | fn eq(&self, other: &RcNode) -> bool { 47 | self.0 == other.0 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /arthas/src/persistence/service/mod.rs: -------------------------------------------------------------------------------- 1 | 2 | use item::Id; 3 | use serde_json::Value; 4 | use error::Error; 5 | use super::logger::Logger; 6 | use store::is_persistence; 7 | use traits::Structure; 8 | use loader::{persistence_exits, create_persistence}; 9 | 10 | 11 | pub struct PersistenceService { 12 | pub logger: Option, 13 | } 14 | 15 | impl PersistenceService { 16 | pub fn new() -> PersistenceService { 17 | let struct_name = T::get_struct_name(); 18 | 19 | if is_persistence() && !persistence_exits(&struct_name) { 20 | create_persistence(&struct_name, &T::get_field_int_map()); 21 | } 22 | 23 | PersistenceService { 24 | logger: if is_persistence() { 25 | Some(Logger::new(&struct_name)) 26 | } else { 27 | None 28 | }, 29 | } 30 | } 31 | 32 | pub fn insert(&mut self, id: Id, value: Value) -> Result<(), Error> { 33 | self.logger.as_mut().unwrap().insert(id, value); 34 | Ok(()) 35 | } 36 | 37 | pub fn delete(&mut self, id: Id) -> Result<(), Error> { 38 | self.logger.as_mut().unwrap().delete(id); 39 | Ok(()) 40 | } 41 | 42 | pub fn clear(&mut self) -> Result<(), Error> { 43 | self.logger.as_mut().unwrap().clear(); 44 | Ok(()) 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /arthas/src/traits/mod.rs: -------------------------------------------------------------------------------- 1 | 2 | use std::collections::HashMap; 3 | use item::Id; 4 | use query::Query; 5 | 6 | pub trait Arthas: Sized { 7 | fn get_struct_name() -> String; 8 | fn session<'a>() -> Query<'a, Self>; 9 | fn get_field_type_map() -> FieldTypeMap; 10 | fn get_field_int_map() -> FieldIntMap; 11 | fn is_one() -> bool; 12 | fn new_empty() -> Self; 13 | fn new_deep_empty() -> Self; 14 | fn has_id() -> bool; 15 | fn set_id(&mut self, id: Id); 16 | fn get_id(&self) -> Id; 17 | fn get_rename_map() -> HashMap; 18 | } 19 | 20 | pub type FieldTypeMap = HashMap; 21 | pub type FieldIntMap = HashMap; 22 | pub type RenameMap = HashMap; 23 | 24 | #[derive(Debug, Clone)] 25 | pub enum FieldType { 26 | Atomic(String), 27 | Array(FieldTypeMap), 28 | Object(FieldTypeMap), 29 | Struct(FieldTypeMap), 30 | } 31 | 32 | use serde::Serialize; 33 | use serde::de::DeserializeOwned; 34 | use std::fmt::Debug; 35 | 36 | pub trait Structure 37 | : 'static + Serialize + DeserializeOwned + Default + Clone + Debug + PartialEq + Send + Sync + Arthas 38 | { 39 | } 40 | impl Structure for T {} 41 | 42 | pub fn get_unique_int_str(field: &str) -> String { 43 | let mut integer = 0; 44 | 45 | for (index, ch) in field.chars().enumerate() { 46 | integer += index * (ch as usize); 47 | } 48 | 49 | integer.to_string() 50 | } 51 | -------------------------------------------------------------------------------- /arthas/src/tree/rc/data/mod.rs: -------------------------------------------------------------------------------- 1 | 2 | use std::sync::RwLock; 3 | use std::ops::Deref; 4 | use std::ops::DerefMut; 5 | use serde_json::Value; 6 | use super::DataType; 7 | 8 | 9 | #[derive(Clone, Debug)] 10 | pub struct RcData(*mut RwLock); 11 | 12 | impl RcData { 13 | pub fn new(value: *const Value) -> RcData { 14 | RcData(Box::into_raw(Box::new(RwLock::new(Data::new(value))))) 15 | } 16 | 17 | pub fn destroy(self) { 18 | unsafe { 19 | Box::from_raw(self.0); 20 | } 21 | } 22 | } 23 | 24 | unsafe impl Send for RcData {} 25 | unsafe impl Sync for RcData {} 26 | 27 | impl Deref for RcData { 28 | type Target = RwLock; 29 | fn deref(&self) -> &Self::Target { 30 | unsafe { &*self.0 } 31 | } 32 | } 33 | 34 | impl DerefMut for RcData { 35 | fn deref_mut(&mut self) -> &mut Self::Target { 36 | unsafe { &mut *self.0 } 37 | } 38 | } 39 | 40 | 41 | #[derive(Clone, Debug)] 42 | pub struct Data { 43 | pub value: *const Value, 44 | pub _type: DataType, 45 | } 46 | 47 | impl Data { 48 | pub fn new(value: *const Value) -> Data { 49 | let _type = DataType::from(unsafe { &*value }); 50 | 51 | Data { 52 | value: value, 53 | _type: _type, 54 | } 55 | } 56 | 57 | pub fn can_index(&self) -> bool { 58 | match self._type { 59 | DataType::Number | DataType::String => true, 60 | _ => false, 61 | } 62 | } 63 | 64 | pub fn get_value(&self) -> &Value { 65 | unsafe { &*self.value } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /arthas/src/persistence/logger/mod.rs: -------------------------------------------------------------------------------- 1 | 2 | use std::fs::File; 3 | use utils::file::open_log_file; 4 | use serde_json::Value; 5 | use to_value; 6 | use item::Id; 7 | use std::io::Write; 8 | 9 | 10 | #[derive(Serialize, Deserialize, Debug, Clone)] 11 | pub enum Action { 12 | Insert, 13 | Delete, 14 | Clear, 15 | } 16 | 17 | #[derive(Serialize, Deserialize, Debug, Clone)] 18 | pub struct Line { 19 | pub action: Action, 20 | pub id: Option, 21 | pub value: Option, 22 | } 23 | 24 | impl Line { 25 | pub fn new(action: Action) -> Line { 26 | Line { 27 | action: action, 28 | id: None, 29 | value: None, 30 | } 31 | } 32 | 33 | pub fn id(mut self, id: Id) -> Line { 34 | self.id = Some(id); 35 | self 36 | } 37 | 38 | pub fn value(mut self, value: Value) -> Line { 39 | self.value = Some(value); 40 | self 41 | } 42 | } 43 | 44 | pub struct Logger { 45 | file: File, 46 | } 47 | 48 | impl Logger { 49 | pub fn new(struct_name: &str) -> Logger { 50 | Logger { file: open_log_file(struct_name) } 51 | } 52 | 53 | pub fn insert(&mut self, id: Id, value: Value) { 54 | writeln!(self.file, 55 | "{}", 56 | to_value(Line::new(Action::Insert).id(id).value(value))) 57 | .unwrap(); 58 | } 59 | 60 | pub fn delete(&mut self, id: Id) { 61 | writeln!(self.file, "{}", to_value(Line::new(Action::Delete).id(id))).unwrap(); 62 | } 63 | 64 | pub fn clear(&mut self) { 65 | writeln!(self.file, "{}", to_value(Line::new(Action::Clear))).unwrap(); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /arthas/tests/common/mod.rs: -------------------------------------------------------------------------------- 1 | 2 | extern crate arthas; 3 | extern crate mktemp; 4 | extern crate rand; 5 | extern crate env_logger; 6 | 7 | use self::mktemp::Temp; 8 | use std::sync::{Once, ONCE_INIT}; 9 | use rand::random; 10 | use rand::distributions::{IndependentSample, Range}; 11 | use rand::Rng; 12 | 13 | use std::collections::HashMap; 14 | use std::iter::IntoIterator; 15 | use std::cmp::Eq; 16 | use std::hash::Hash; 17 | 18 | 19 | pub fn setup() { 20 | static ONCE: Once = ONCE_INIT; 21 | 22 | ONCE.call_once(|| { 23 | config_env_logger(); 24 | let temp_dir = Temp::new_dir().unwrap().to_path_buf(); 25 | arthas::config::path(temp_dir); 26 | }); 27 | } 28 | 29 | 30 | pub fn memory_setup() { 31 | static ONCE: Once = ONCE_INIT; 32 | 33 | ONCE.call_once(|| { 34 | config_env_logger(); 35 | arthas::config::persistence(false); 36 | }); 37 | } 38 | 39 | pub fn random_usize() -> usize { 40 | random::() 41 | } 42 | 43 | pub fn random_string() -> String { 44 | let len = random_usize_max(15); 45 | rand::thread_rng() 46 | .gen_iter::() 47 | .take(len) 48 | .collect() 49 | } 50 | 51 | fn random_usize_max(max: usize) -> usize { 52 | let between = Range::new(0, max); 53 | let mut rng = rand::thread_rng(); 54 | between.ind_sample(&mut rng) 55 | } 56 | 57 | fn config_env_logger() { 58 | env_logger::init().unwrap(); 59 | } 60 | 61 | pub fn revert(hash_map: HashMap) -> HashMap 62 | where HashMap: IntoIterator, 63 | V: Eq + Hash 64 | { 65 | let mut reverted_map = HashMap::new(); 66 | 67 | for (k, v) in hash_map { 68 | reverted_map.insert(v, k); 69 | } 70 | 71 | reverted_map 72 | } 73 | -------------------------------------------------------------------------------- /arthas/src/tree/action/mod.rs: -------------------------------------------------------------------------------- 1 | 2 | 3 | #[derive(Default, Debug)] 4 | pub struct SearchAction { 5 | pub take: bool, 6 | pub fold_left: bool, 7 | pub fold_right: bool, 8 | pub go_left: bool, 9 | pub go_right: bool, 10 | } 11 | 12 | impl SearchAction { 13 | pub fn new() -> SearchAction { 14 | SearchAction { ..Default::default() } 15 | } 16 | 17 | pub fn merge(&self, other: &SearchAction) -> Option { 18 | if self.go_left != other.go_left || self.go_right != other.go_right { 19 | return None; 20 | } 21 | 22 | let mut new_action = SearchAction::new(); 23 | 24 | if self.take && other.take { 25 | new_action.take = true; 26 | } 27 | 28 | if self.fold_left && other.fold_left { 29 | new_action.fold_left = true; 30 | } 31 | 32 | if self.fold_right && other.fold_right { 33 | new_action.fold_right = true; 34 | } 35 | 36 | new_action.go_left = self.go_left; 37 | new_action.go_right = self.go_right; 38 | 39 | Some(new_action) 40 | } 41 | 42 | pub fn is_stopped(&self) -> bool { 43 | !self.go_left && !self.go_right 44 | } 45 | 46 | pub fn take(mut self) -> SearchAction { 47 | self.take = true; 48 | self 49 | } 50 | 51 | pub fn go_right(mut self) -> SearchAction { 52 | self.go_right = true; 53 | self 54 | } 55 | 56 | pub fn go_left(mut self) -> SearchAction { 57 | self.go_left = true; 58 | self 59 | } 60 | 61 | pub fn fold_right(mut self) -> SearchAction { 62 | self.fold_right = true; 63 | self 64 | } 65 | 66 | pub fn fold_left(mut self) -> SearchAction { 67 | self.fold_left = true; 68 | self 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /arthas/tests/model/mod.rs: -------------------------------------------------------------------------------- 1 | 2 | extern crate serde_json; 3 | extern crate arthas; 4 | 5 | pub use arthas::traits::Arthas; 6 | use std::collections::HashMap; 7 | 8 | 9 | #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Arthas)] 10 | #[arthas(is_one, rename="string_one=one")] 11 | pub struct Atomic { 12 | pub string_one: String, 13 | pub string_two: String, 14 | pub hash_map: HashMap, 15 | } 16 | 17 | #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Arthas)] 18 | pub struct Comment { 19 | pub title: String, 20 | pub content: String, 21 | } 22 | 23 | #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Arthas)] 24 | pub struct Article { 25 | pub _id: String, 26 | pub title: String, 27 | pub content: String, 28 | pub day_to_views: HashMap, 29 | pub views: usize, 30 | pub comments: Vec, 31 | } 32 | 33 | impl Article { 34 | pub fn new>(title: T) -> Article { 35 | Article { title: title.into(), ..Default::default() } 36 | } 37 | 38 | pub fn views(mut self, views: usize) -> Article { 39 | self.views = views; 40 | self 41 | } 42 | 43 | pub fn content>(mut self, content: T) -> Article { 44 | self.content = content.into(); 45 | self 46 | } 47 | } 48 | 49 | #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Arthas)] 50 | pub struct Comments { 51 | pub day_to_comments: HashMap, 52 | } 53 | 54 | #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Arthas)] 55 | pub struct Articles { 56 | pub day_to_articles: HashMap, 57 | } 58 | 59 | #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Arthas)] 60 | pub struct Blog { 61 | pub articles: Articles, 62 | pub comments: Comments, 63 | } 64 | -------------------------------------------------------------------------------- /arthas/tests/concurrency.rs: -------------------------------------------------------------------------------- 1 | 2 | #[macro_use] 3 | extern crate serde_derive; 4 | #[macro_use] 5 | extern crate arthas_derive; 6 | extern crate rand; 7 | extern crate arthas; 8 | extern crate env_logger; 9 | 10 | pub mod common; 11 | pub mod model; 12 | 13 | use model::*; 14 | use std::thread::spawn; 15 | use common::setup; 16 | 17 | 18 | #[test] 19 | fn test_concurrent() { 20 | setup(); 21 | 22 | let mut threads = Vec::new(); 23 | 24 | for _ in 0..10 { 25 | threads.push(spawn(|| for _ in 0..5 { 26 | insert(); 27 | remove(); 28 | find(); 29 | replace(); 30 | })); 31 | } 32 | 33 | for thread in threads { 34 | thread.join().unwrap(); 35 | } 36 | } 37 | 38 | fn insert() { 39 | let id = Article::session().insert(Article::new("Hello world!")).unwrap(); 40 | let item = Article::session().id(&id).find_one().unwrap(); 41 | assert!(item.is_some()); 42 | assert_eq!(item.unwrap().title, "Hello world!"); 43 | } 44 | 45 | fn remove() { 46 | let id = Article::session().insert(Article::new("Hello world!")).unwrap(); 47 | let items = Article::session().id(&id).remove().unwrap(); 48 | assert_eq!(items.len(), 1); 49 | assert_eq!(items.first().unwrap().title, "Hello world!"); 50 | } 51 | 52 | fn replace() { 53 | let id = Article::session().insert(Article::new("Hello world!")).unwrap(); 54 | Article::session().id(&id).replace(Article::new("Foobar Replace!")).unwrap(); 55 | let item = Article::session().id(&id).find_one().unwrap(); 56 | assert_eq!(item.unwrap().title, "Foobar Replace!"); 57 | } 58 | 59 | fn find() { 60 | for i in 0..10 { 61 | Article::session() 62 | .insert(Article::new("Foobar!").views(i)) 63 | .unwrap(); 64 | } 65 | 66 | Article::session() 67 | .field("title") 68 | .eq("Foobar!") 69 | .find() 70 | .unwrap(); 71 | } 72 | -------------------------------------------------------------------------------- /arthas/src/tree/mod.rs: -------------------------------------------------------------------------------- 1 | 2 | pub mod node; 3 | pub mod rc; 4 | pub mod inserter; 5 | pub mod searcher; 6 | pub mod deleter; 7 | pub mod math; 8 | pub mod comparision; 9 | pub mod cmp; 10 | pub mod action; 11 | pub mod len; 12 | 13 | use std::collections::HashMap; 14 | use serde_json::Value; 15 | use traits::{Structure, FieldIntMap}; 16 | use query::{Query, QueryType}; 17 | use error::Error; 18 | use item::{Id, FieldInt}; 19 | use self::rc::{RcNode, RcItem}; 20 | use self::inserter::Inserter; 21 | use self::searcher::Searcher; 22 | use self::deleter::Deleter; 23 | use utils::hash_map::revert; 24 | use scoped_pool::Pool; 25 | 26 | 27 | pub struct Tree { 28 | pub int_field_map: FieldIntMap, 29 | pub id_map: HashMap, 30 | pub root: HashMap, 31 | pub min: HashMap, 32 | pub max: HashMap, 33 | pub searcher: Searcher, 34 | } 35 | 36 | impl Tree { 37 | pub fn new() -> Tree { 38 | Tree { 39 | int_field_map: revert(T::get_field_int_map()), 40 | id_map: HashMap::new(), 41 | root: HashMap::new(), 42 | min: HashMap::new(), 43 | max: HashMap::new(), 44 | searcher: Searcher::new(), 45 | } 46 | } 47 | 48 | pub fn insert(&mut self, id: Id, value: Value) { 49 | Inserter::insert(self, id, value); 50 | } 51 | 52 | pub fn delete(&mut self, id: &str) { 53 | Deleter::delete(self, id); 54 | } 55 | 56 | pub fn clear(&mut self) { 57 | Deleter::clear(self); 58 | } 59 | 60 | pub fn search(&self, 61 | pool: &Pool, 62 | query: &Query, 63 | query_type: &QueryType) 64 | -> Result<(usize, Vec<*const Value>), Error> { 65 | self.searcher.search(pool, self, query, query_type) 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /arthas/src/tree/rc/child/mod.rs: -------------------------------------------------------------------------------- 1 | 2 | use std::sync::RwLock; 3 | use std::ops::{Deref, DerefMut}; 4 | use std::fmt; 5 | use serde_json::Value; 6 | use super::{RcData, RcItem, DataType}; 7 | 8 | 9 | #[derive(Clone)] 10 | pub struct RcChild(*mut RwLock); 11 | 12 | impl RcChild { 13 | pub fn new(data: RcData, item: RcItem) -> RcChild { 14 | RcChild(Box::into_raw(Box::new(RwLock::new(Child::new(data, item))))) 15 | } 16 | 17 | pub fn destroy(self) { 18 | unsafe { 19 | Box::from_raw(self.0); 20 | } 21 | } 22 | } 23 | 24 | unsafe impl Send for RcChild {} 25 | unsafe impl Sync for RcChild {} 26 | 27 | impl fmt::Debug for RcChild { 28 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 29 | write!(f, "{:?}", self.read().unwrap().get_item_value()) 30 | } 31 | } 32 | 33 | impl Deref for RcChild { 34 | type Target = RwLock; 35 | fn deref(&self) -> &Self::Target { 36 | unsafe { &*self.0 } 37 | } 38 | } 39 | 40 | impl DerefMut for RcChild { 41 | fn deref_mut(&mut self) -> &mut Self::Target { 42 | unsafe { &mut *self.0 } 43 | } 44 | } 45 | 46 | 47 | #[derive(Clone)] 48 | pub struct Child { 49 | pub data: RcData, 50 | pub item: RcItem, 51 | } 52 | 53 | impl Child { 54 | pub fn new(data: RcData, item: RcItem) -> Child { 55 | Child { 56 | data: data, 57 | item: item, 58 | } 59 | } 60 | 61 | pub fn get_item_pointer(&self) -> *const Value { 62 | self.item.read().unwrap().get_pointer() 63 | } 64 | 65 | pub fn get_item_value(&self) -> &Value { 66 | unsafe { &*self.get_item_pointer() } 67 | } 68 | 69 | pub fn get_value(&self) -> Value { 70 | self.data.read().unwrap().get_value().clone() 71 | } 72 | 73 | pub fn get_type(&self) -> DataType { 74 | self.data.read().unwrap()._type.clone() 75 | } 76 | } 77 | 78 | impl fmt::Debug for Child { 79 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 80 | write!(f, "{:?}", self.data) 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /arthas/src/store/mod.rs: -------------------------------------------------------------------------------- 1 | 2 | mod config; 3 | 4 | use std::sync::{RwLock, Once, ONCE_INIT}; 5 | use std::mem; 6 | use std::collections::HashMap; 7 | use std::path::PathBuf; 8 | use self::config::Config; 9 | use memory::Memory; 10 | use persistence::Persistence; 11 | use traits::Structure; 12 | 13 | 14 | pub type MemoryStore = HashMap>; 15 | pub type PersistenceStore = HashMap>; 16 | 17 | pub trait MemoryGetter { 18 | fn get_memory(&self) -> &RwLock; 19 | } 20 | 21 | impl MemoryGetter for MemoryStore { 22 | fn get_memory(&self) -> &RwLock { 23 | self.get(&T::get_struct_name()).unwrap() 24 | } 25 | } 26 | 27 | 28 | pub fn memories<'a>() -> &'a RwLock { 29 | static mut MEMORIES: *const RwLock = 0 as *const RwLock; 30 | static ONCE: Once = ONCE_INIT; 31 | 32 | unsafe { 33 | ONCE.call_once(|| MEMORIES = mem::transmute(Box::new(RwLock::new(MemoryStore::new())))); 34 | &*MEMORIES 35 | } 36 | } 37 | 38 | pub fn persistences<'a>() -> &'a RwLock { 39 | static mut PERSISTENCES: *const RwLock = 0 as *const RwLock; 40 | static ONCE: Once = ONCE_INIT; 41 | 42 | unsafe { 43 | ONCE.call_once(|| { 44 | PERSISTENCES = mem::transmute(Box::new(RwLock::new(PersistenceStore::new()))) 45 | }); 46 | &*PERSISTENCES 47 | } 48 | } 49 | 50 | pub fn config<'a>() -> &'a RwLock { 51 | static mut CONFIG: *const RwLock = 0 as *const RwLock; 52 | static ONCE: Once = ONCE_INIT; 53 | 54 | unsafe { 55 | ONCE.call_once(|| CONFIG = mem::transmute(Box::new(RwLock::new(Config::new())))); 56 | &*CONFIG 57 | } 58 | } 59 | 60 | #[inline] 61 | pub fn is_persistence() -> bool { 62 | config().read().unwrap().persistence 63 | } 64 | 65 | #[inline] 66 | pub fn get_path() -> PathBuf { 67 | config().read().unwrap().path.clone() 68 | } 69 | 70 | #[inline] 71 | pub fn get_extension_path(struct_name: &str, ext: &'static str) -> PathBuf { 72 | PathBuf::from(format!("{}/{}.{}", get_path().display(), struct_name, ext)) 73 | } 74 | -------------------------------------------------------------------------------- /arthas/src/tree/searcher/entrance_type/mod.rs: -------------------------------------------------------------------------------- 1 | 2 | use serde_json::Value; 3 | use super::super::rc::RcNode; 4 | use super::super::math::Math; 5 | use super::super::Tree; 6 | 7 | 8 | pub enum EntranceType { 9 | Root, 10 | Min, 11 | Max, 12 | None, 13 | } 14 | 15 | impl EntranceType { 16 | pub fn new(tree: &Tree, field_int: &str, value: &Value) -> EntranceType { 17 | let root = tree.root.get(field_int); 18 | let min = tree.min.get(field_int); 19 | let max = tree.max.get(field_int); 20 | 21 | if root.is_none() { 22 | EntranceType::None 23 | } else if min.is_some() && max.is_none() { 24 | let root_rate = get_rate(root.unwrap(), value); 25 | let min_rate = get_rate(min.unwrap(), value); 26 | if root_rate > min_rate { 27 | EntranceType::Root 28 | } else { 29 | EntranceType::Min 30 | } 31 | } else if min.is_none() && max.is_some() { 32 | let max_rate = get_rate(max.unwrap(), value); 33 | let root_rate = get_rate(root.unwrap(), value); 34 | if root_rate > max_rate { 35 | EntranceType::Root 36 | } else { 37 | EntranceType::Max 38 | } 39 | } else if min.is_some() && max.is_some() { 40 | let root_rate = get_rate(root.unwrap(), value); 41 | let min_rate = get_rate(min.unwrap(), value); 42 | let max_rate = get_rate(max.unwrap(), value); 43 | 44 | thread_trace!("entrance type, root rate: {:?}, min rate: {:?}, max rate: {:?}", 45 | root_rate, 46 | min_rate, 47 | max_rate); 48 | 49 | let maximum = vec![root_rate, min_rate, max_rate] 50 | .into_iter() 51 | .fold(0.0, |a, b| if a > b { a } else { b }); 52 | 53 | if maximum == min_rate { 54 | EntranceType::Min 55 | } else if maximum == max_rate { 56 | EntranceType::Max 57 | } else { 58 | EntranceType::Root 59 | } 60 | } else { 61 | EntranceType::Root 62 | } 63 | } 64 | } 65 | 66 | fn get_rate(rc_node: &RcNode, value: &Value) -> f64 { 67 | rc_node.read().unwrap().get_value().get_rate(value) 68 | } 69 | -------------------------------------------------------------------------------- /arthas/src/tree/rc/item/mod.rs: -------------------------------------------------------------------------------- 1 | 2 | use std::sync::RwLock; 3 | use std::ops::Deref; 4 | use std::ops::DerefMut; 5 | use item::{Id, FieldInt, get_len_field_int}; 6 | use serde_json::Value; 7 | use std::collections::HashMap; 8 | use super::RcData; 9 | use super::RcNode; 10 | use traits::get_unique_int_str; 11 | use super::super::len::Len; 12 | 13 | 14 | lazy_static! { 15 | static ref _ID_INT_STR: String = get_unique_int_str("_id"); 16 | } 17 | 18 | 19 | #[derive(Clone, Debug)] 20 | pub struct RcItem(*mut RwLock); 21 | 22 | impl RcItem { 23 | pub fn new(id: Id, value: Value) -> RcItem { 24 | RcItem(Box::into_raw(Box::new(RwLock::new(Item::new(id, value))))) 25 | } 26 | 27 | pub fn destroy(self) { 28 | let rc_item = unsafe { Box::from_raw(self.0) }; 29 | let mut item = rc_item.write().unwrap(); 30 | item.nodes.clear(); 31 | 32 | for (_, rc_data) in item.datas.drain() { 33 | rc_data.destroy(); 34 | } 35 | } 36 | } 37 | 38 | unsafe impl Send for RcItem {} 39 | unsafe impl Sync for RcItem {} 40 | 41 | impl Deref for RcItem { 42 | type Target = RwLock; 43 | fn deref(&self) -> &Self::Target { 44 | unsafe { &*self.0 } 45 | } 46 | } 47 | 48 | impl DerefMut for RcItem { 49 | fn deref_mut(&mut self) -> &mut Self::Target { 50 | unsafe { &mut *self.0 } 51 | } 52 | } 53 | 54 | 55 | #[derive(Clone, Debug)] 56 | pub struct Item { 57 | pub id: Id, 58 | pub nodes: HashMap, 59 | pub datas: HashMap, 60 | pub value: Value, 61 | } 62 | 63 | impl Item { 64 | pub fn new(id: Id, value: Value) -> Item { 65 | if value.is_object() { 66 | let mut datas = HashMap::new(); 67 | 68 | for (field_int, value) in value.get("item").unwrap().as_object().unwrap() { 69 | if field_int != &*_ID_INT_STR { 70 | datas.insert(field_int.to_owned(), RcData::new(value as *const Value)); 71 | 72 | if value.can_len() { 73 | datas.insert(get_len_field_int(field_int), 74 | value.create_len_rc_data().unwrap()); 75 | } 76 | } 77 | } 78 | 79 | Item { 80 | id: id, 81 | nodes: HashMap::new(), 82 | datas: datas, 83 | value: value, 84 | } 85 | } else { 86 | unreachable!() 87 | } 88 | } 89 | 90 | pub fn get_pointer(&self) -> *const Value { 91 | &self.value as *const Value 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /arthas/src/tree/inserter/mod.rs: -------------------------------------------------------------------------------- 1 | 2 | use item::Id; 3 | use serde_json::Value; 4 | use super::rc::{RcItem, RcChild, RcNode}; 5 | use super::Tree; 6 | 7 | pub struct Inserter {} 8 | 9 | impl Inserter { 10 | pub fn insert(tree: &mut Tree, id: Id, value: Value) { 11 | thread_trace!("insert id: {}", id); 12 | let rc_item = RcItem::new(id.clone(), value); 13 | tree.id_map.insert(id.clone(), rc_item.clone()); 14 | let datas = rc_item.read().unwrap().datas.clone(); 15 | 16 | for (field_int, rc_data) in datas { 17 | if rc_data.read().unwrap().can_index() { 18 | let mut is_min = true; 19 | let mut is_max = true; 20 | 21 | thread_trace!("current insert field data: {:?}", 22 | rc_data.read().unwrap().get_value()); 23 | 24 | let rc_child = RcChild::new(rc_data, rc_item.clone()); 25 | let root_exists = tree.root.contains_key(&field_int); 26 | 27 | if root_exists { 28 | let node_option = tree.root 29 | .get(&field_int) 30 | .unwrap() 31 | .write() 32 | .unwrap() 33 | .insert(field_int.clone(), 34 | id.clone(), 35 | rc_child, 36 | &mut is_min, 37 | &mut is_max); 38 | 39 | if node_option.is_some() { 40 | let rc_node = node_option.unwrap(); 41 | if is_min { 42 | thread_trace!("found min node: {:?}", 43 | rc_node.read().unwrap().get_value()); 44 | tree.min.insert(field_int, rc_node); 45 | } else if is_max { 46 | thread_trace!("found max node: {:?}", 47 | rc_node.read().unwrap().get_value()); 48 | tree.max.insert(field_int, rc_node); 49 | } else { 50 | unreachable!() 51 | } 52 | } 53 | } else { 54 | let rc_node = RcNode::new(id.clone(), rc_child); 55 | rc_node.write().unwrap().self_rc = Some(rc_node.clone()); 56 | rc_item.write().unwrap().nodes.insert(field_int.clone(), rc_node.clone()); 57 | tree.root.insert(field_int, rc_node); 58 | } 59 | } 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Arthas 2 | ====== 3 | 4 | [![Project Status: Abandoned – Initial development has started, but there has not yet been a stable, usable release; the project has been abandoned and the author(s) do not intend on continuing development.](https://www.repostatus.org/badges/latest/abandoned.svg)](https://www.repostatus.org/#abandoned) 5 | 6 | [![Build Status](https://travis-ci.org/fengcen/arthas.svg?branch=master)](https://travis-ci.org/fengcen/arthas) 7 | [![docs](https://docs.rs/arthas/badge.svg)](https://docs.rs/arthas) 8 | 9 | Arthas is an in-memory structure database. 10 | 11 | [Document](https://docs.rs/arthas) 12 | ---------------------------------- 13 | 14 | Prerequisites 15 | ------------- 16 | 17 | Arthas requires Rust 1.15 or above. 18 | 19 | Features 20 | -------- 21 | 22 | * Support persistence. 23 | * Automatically update fields. 24 | * Automatic indexing. 25 | * Use structure without ORM. 26 | * Embedded. 27 | 28 | Usage 29 | ----- 30 | 31 | Add dependencies to Cargo.toml 32 | 33 | ```toml 34 | [dependencies] 35 | arthas = "^0.3" 36 | arthas_derive = "^0.1" 37 | serde = "^0.9" 38 | serde_derive = "^0.9" 39 | ``` 40 | 41 | In your `main.rs` or `lib.rs`: 42 | 43 | ```rust 44 | extern crate arthas; 45 | #[macro_use] 46 | extern crate arthas_derive; 47 | #[macro_use] 48 | extern crate serde_derive; 49 | ``` 50 | 51 | CRUD Methods 52 | ------------ 53 | 54 | - [x] insert() 55 | - [x] remove() 56 | - [x] replace() 57 | - [x] find() 58 | - [x] find_one() 59 | - [x] count() 60 | 61 | Query Methods 62 | ------------- 63 | 64 | - [x] id() 65 | - [x] limit() 66 | - [x] offset() 67 | - [x] field() 68 | - [x] len() 69 | - [x] eq() 70 | - [x] ne() 71 | - [x] gt() 72 | - [x] lt() 73 | - [x] ge() 74 | - [x] le() 75 | - [x] desc() 76 | - [x] asc() 77 | 78 | Examples 79 | -------- 80 | 81 | Examples can be found in the [Documentation](https://docs.rs/arthas). 82 | 83 | Upgrade to arthas 0.3 and arthas_derive 84 | --------------------------------------- 85 | 86 | 1. Rename all your data files to only contains struct name. For example, rename "model.user.User" to "User". 87 | 2. Replace attribute `#[arthas]` with `#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Arthas)]` 88 | 3. If you use attribute value like `#[arthas(one)]`, replace with the attribute `#[arthas(is_one)]` 89 | 4. If you use the rename attribute like `#[arthas_rename("from = to")]`, replace with the attribute `#[arthas(rename = "from = to")]` 90 | 5. If you use both `#[arthas(one)]` and `#[arthas_rename("from = to")]`, replace with `#[arthas(is_one, rename = "from = to")]` 91 | 92 | License 93 | ------- 94 | 95 | arthas is primarily distributed under the terms of the MIT license. 96 | See [LICENSE](LICENSE) for details. 97 | -------------------------------------------------------------------------------- /arthas/src/tree/comparision/mod.rs: -------------------------------------------------------------------------------- 1 | 2 | use super::cmp::Cmp; 3 | use serde_json::Value; 4 | use super::math::Math; 5 | use item::FieldInt; 6 | use super::action::SearchAction; 7 | use super::searcher::meet::Meet; 8 | 9 | 10 | #[derive(Debug, Clone)] 11 | pub struct Comparision { 12 | pub field_int: FieldInt, 13 | pub cmp: Cmp, 14 | pub other: Value, 15 | } 16 | 17 | impl Comparision { 18 | pub fn new(field_int: FieldInt, cmp: Cmp, other: Value) -> Comparision { 19 | Comparision { 20 | field_int: field_int, 21 | cmp: cmp, 22 | other: other, 23 | } 24 | } 25 | 26 | pub fn _match(&self, value: &Value) -> bool { 27 | value.meet(&self.cmp, &self.other) 28 | } 29 | 30 | pub fn compare(&self, current: &Value) -> Option { 31 | match self.cmp { 32 | Cmp::Eq => { 33 | if Math::eq(current, &self.other) { 34 | Some(SearchAction::new().take()) 35 | } else if Math::lt(current, &self.other) { 36 | Some(SearchAction::new().go_right()) 37 | } else { 38 | Some(SearchAction::new().go_left()) 39 | } 40 | } 41 | Cmp::Ne => { 42 | if Math::eq(current, &self.other) { 43 | Some(SearchAction::new().fold_left().fold_right()) 44 | } else if Math::lt(current, &self.other) { 45 | Some(SearchAction::new().take().fold_left().go_right()) 46 | } else { 47 | Some(SearchAction::new().take().fold_right().go_left()) 48 | } 49 | } 50 | Cmp::Gt => { 51 | if Math::gt(current, &self.other) { 52 | Some(SearchAction::new().take().fold_right().go_left()) 53 | } else if Math::lt(current, &self.other) { 54 | Some(SearchAction::new().go_right()) 55 | } else { 56 | Some(SearchAction::new().fold_right()) 57 | } 58 | } 59 | Cmp::Lt => { 60 | if Math::lt(current, &self.other) { 61 | Some(SearchAction::new().take().fold_left().go_right()) 62 | } else if Math::gt(current, &self.other) { 63 | Some(SearchAction::new().go_left()) 64 | } else { 65 | Some(SearchAction::new().fold_left()) 66 | } 67 | } 68 | Cmp::Ge => { 69 | if Math::eq(current, &self.other) || Math::gt(current, &self.other) { 70 | Some(SearchAction::new().take().fold_right()) 71 | } else { 72 | Some(SearchAction::new().go_right()) 73 | } 74 | } 75 | Cmp::Le => { 76 | if Math::eq(current, &self.other) || Math::lt(current, &self.other) { 77 | Some(SearchAction::new().take().fold_left()) 78 | } else { 79 | Some(SearchAction::new().go_left()) 80 | } 81 | } 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /arthas/src/utils/file/mod.rs: -------------------------------------------------------------------------------- 1 | 2 | use std::path::{Path, PathBuf}; 3 | use std::fs::{File, create_dir_all, OpenOptions}; 4 | use store::{get_path, get_extension_path}; 5 | use {DATA_EXTENSION, PERSISTENCE_EXTENSION, LOG_EXTENSION, SAVING_EXTENSION}; 6 | 7 | 8 | pub fn exists>(file_path: P) -> bool { 9 | file_path.as_ref().is_file() 10 | } 11 | 12 | pub fn open_log_file(struct_name: &str) -> File { 13 | ensure_data_file_exists(struct_name, LOG_EXTENSION); 14 | OpenOptions::new() 15 | .read(true) 16 | .write(true) 17 | .append(true) 18 | .open(get_extension_path(struct_name, LOG_EXTENSION)) 19 | .unwrap() 20 | } 21 | 22 | pub fn open_index_with_read(struct_name: &str) -> Option { 23 | let path = get_extension_path(struct_name, PERSISTENCE_EXTENSION); 24 | if !path.is_file() { 25 | return None; 26 | } 27 | 28 | Some(OpenOptions::new() 29 | .read(true) 30 | .open(path) 31 | .unwrap()) 32 | } 33 | 34 | pub fn open_data_with_read(struct_name: &str) -> File { 35 | OpenOptions::new() 36 | .read(true) 37 | .open(get_extension_path(struct_name, DATA_EXTENSION)) 38 | .unwrap() 39 | } 40 | 41 | pub fn open_data_or_create(struct_name: &str) -> File { 42 | ensure_data_file_exists(struct_name, DATA_EXTENSION); 43 | OpenOptions::new() 44 | .read(true) 45 | .write(true) 46 | .open(get_extension_path(struct_name, DATA_EXTENSION)) 47 | .unwrap() 48 | } 49 | 50 | pub fn open_data_with_append(struct_name: &str) -> File { 51 | ensure_data_file_exists(struct_name, DATA_EXTENSION); 52 | OpenOptions::new() 53 | .read(true) 54 | .write(true) 55 | .append(true) 56 | .open(get_extension_path(struct_name, DATA_EXTENSION)) 57 | .unwrap() 58 | } 59 | 60 | pub fn open_with_write>(path: P) -> File { 61 | ensure_file_exists(path.as_ref()); 62 | OpenOptions::new() 63 | .read(true) 64 | .write(true) 65 | .create(true) 66 | .truncate(true) 67 | .open(path) 68 | .unwrap() 69 | } 70 | 71 | pub fn open_with_read>(path: P) -> File { 72 | OpenOptions::new() 73 | .read(true) 74 | .open(path) 75 | .unwrap() 76 | } 77 | 78 | pub fn get_log_path(struct_name: &str) -> PathBuf { 79 | get_extension_path(struct_name, LOG_EXTENSION) 80 | } 81 | 82 | pub fn get_persistence_path(struct_name: &str) -> PathBuf { 83 | get_extension_path(struct_name, PERSISTENCE_EXTENSION) 84 | } 85 | 86 | pub fn get_data_path(struct_name: &str) -> PathBuf { 87 | get_extension_path(struct_name, DATA_EXTENSION) 88 | } 89 | 90 | pub fn get_saving_path(struct_name: &str) -> PathBuf { 91 | get_extension_path(struct_name, SAVING_EXTENSION) 92 | } 93 | 94 | fn ensure_data_file_exists(struct_name: &str, ext: &'static str) { 95 | create_data_dir(); 96 | OpenOptions::new() 97 | .read(true) 98 | .write(true) 99 | .create(true) 100 | .open(get_extension_path(struct_name, ext)) 101 | .unwrap(); 102 | } 103 | 104 | fn ensure_file_exists>(path: P) { 105 | create_data_dir(); 106 | OpenOptions::new() 107 | .read(true) 108 | .write(true) 109 | .create(true) 110 | .open(path) 111 | .unwrap(); 112 | } 113 | 114 | fn create_data_dir() { 115 | create_dir_all(get_path()).unwrap(); 116 | } 117 | -------------------------------------------------------------------------------- /arthas/src/tree/searcher/mod.rs: -------------------------------------------------------------------------------- 1 | 2 | pub mod task; 3 | pub mod executor; 4 | pub mod meet; 5 | pub mod entrance_type; 6 | 7 | use super::Tree; 8 | use query::{Query, QueryType}; 9 | use error::Error; 10 | use serde_json::Value; 11 | use traits::Structure; 12 | use self::task::Task; 13 | use self::executor::Exectuor; 14 | use scoped_pool::Pool; 15 | 16 | 17 | pub struct Searcher {} 18 | 19 | impl Searcher { 20 | pub fn new() -> Searcher { 21 | Searcher {} 22 | } 23 | 24 | pub fn search(&self, 25 | pool: &Pool, 26 | tree: &Tree, 27 | query: &Query, 28 | query_type: &QueryType) 29 | -> Result<(usize, Vec<*const Value>), Error> { 30 | if query.id.is_some() { 31 | thread_trace!("search by id: {:?}", query.id); 32 | self.search_by_id(tree, query, query_type) 33 | } else if !query.conditions.is_empty() { 34 | thread_trace!("search by conditions."); 35 | self.search_by_query(pool, tree, query, query_type) 36 | } else { 37 | thread_trace!("search all."); 38 | self.search_all(tree, query, query_type) 39 | } 40 | } 41 | 42 | fn search_by_id(&self, 43 | tree: &Tree, 44 | query: &Query, 45 | query_type: &QueryType) 46 | -> Result<(usize, Vec<*const Value>), Error> { 47 | let mut values = Vec::new(); 48 | let mut count = 0; 49 | 50 | if let Some(rc_item) = tree.id_map.get(query.id.as_ref().unwrap()) { 51 | if query.offset.is_none() || *query.offset.as_ref().unwrap() == 0 { 52 | count += 1; 53 | 54 | if query_type == &QueryType::Find { 55 | values.push(rc_item.read().unwrap().get_pointer()); 56 | } 57 | } 58 | } 59 | 60 | Ok((count, values)) 61 | } 62 | 63 | fn search_by_query(&self, 64 | pool: &Pool, 65 | tree: &Tree, 66 | query: &Query, 67 | query_type: &QueryType) 68 | -> Result<(usize, Vec<*const Value>), Error> { 69 | Exectuor::exec(pool, tree, Task::new(query, query_type)) 70 | } 71 | 72 | fn search_all(&self, 73 | tree: &Tree, 74 | query: &Query, 75 | query_type: &QueryType) 76 | -> Result<(usize, Vec<*const Value>), Error> { 77 | let mut values = Vec::new(); 78 | let mut count = 0; 79 | 80 | thread_trace!("current id map length: {}", tree.id_map.len()); 81 | 82 | for (index, rc_item) in tree.id_map.values().enumerate() { 83 | if query.offset.is_some() && index + 1 < *query.offset.as_ref().unwrap() { 84 | continue; 85 | } 86 | 87 | count += 1; 88 | 89 | if query_type == &QueryType::Find { 90 | values.push(rc_item.read().unwrap().get_pointer()); 91 | } 92 | 93 | if query.limit.is_some() && count >= *query.limit.as_ref().unwrap() { 94 | break; 95 | } 96 | } 97 | 98 | Ok((count, values)) 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /arthas/benches/memory.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(all(feature = "unstable", test), feature(test))] 2 | 3 | #[macro_use] 4 | extern crate serde_derive; 5 | #[macro_use] 6 | extern crate arthas_derive; 7 | extern crate rand; 8 | extern crate arthas; 9 | extern crate env_logger; 10 | 11 | #[path = "../tests/common/mod.rs"] 12 | pub mod common; 13 | #[path = "../tests/model/mod.rs"] 14 | pub mod model; 15 | 16 | #[cfg(all(feature = "unstable", test))] 17 | mod benches { 18 | extern crate test; 19 | 20 | use model::*; 21 | use super::common; 22 | use super::common::memory_setup; 23 | 24 | 25 | #[bench] 26 | fn bench_a_insert_random(b: &mut test::Bencher) { 27 | memory_setup(); 28 | 29 | b.iter(|| { 30 | Article::session() 31 | .insert(Article::new(common::random_string()).views(common::random_usize())) 32 | .unwrap() 33 | }) 34 | } 35 | 36 | #[bench] 37 | fn bench_b_insert_hello(b: &mut test::Bencher) { 38 | memory_setup(); 39 | 40 | b.iter(|| { 41 | Article::session() 42 | .insert(Article::new("Hello world!")) 43 | .unwrap() 44 | }) 45 | } 46 | 47 | #[bench] 48 | fn bench_find(b: &mut test::Bencher) { 49 | memory_setup(); 50 | 51 | b.iter(|| { 52 | Article::session() 53 | .field("title") 54 | .eq("Hello world!") 55 | .limit(100) 56 | .find() 57 | .unwrap() 58 | }) 59 | } 60 | 61 | #[bench] 62 | fn bench_lt_100(b: &mut test::Bencher) { 63 | memory_setup(); 64 | 65 | b.iter(|| { 66 | Article::session() 67 | .field("views") 68 | .lt(100) 69 | .limit(100) 70 | .find() 71 | .unwrap() 72 | }) 73 | } 74 | 75 | #[bench] 76 | fn bench_gt_100(b: &mut test::Bencher) { 77 | memory_setup(); 78 | 79 | b.iter(|| { 80 | Article::session() 81 | .field("views") 82 | .gt(100) 83 | .limit(100) 84 | .find() 85 | .unwrap() 86 | }) 87 | } 88 | 89 | #[bench] 90 | fn bench_multiple_conditions_find(b: &mut test::Bencher) { 91 | memory_setup(); 92 | 93 | b.iter(|| { 94 | Article::session() 95 | .field("title") 96 | .eq("Hello world!") 97 | .field("views") 98 | .lt(100) 99 | .limit(100) 100 | .find() 101 | .unwrap() 102 | }) 103 | } 104 | 105 | #[bench] 106 | fn bench_count(b: &mut test::Bencher) { 107 | b.iter(|| { 108 | Article::session() 109 | .field("title") 110 | .eq("Hello world!") 111 | .count() 112 | .unwrap() 113 | }) 114 | } 115 | 116 | #[bench] 117 | fn bench_find_one(b: &mut test::Bencher) { 118 | b.iter(|| { 119 | Article::session() 120 | .field("title") 121 | .eq("Hello world!") 122 | .find_one() 123 | .unwrap() 124 | }) 125 | } 126 | 127 | #[bench] 128 | fn bench_limit_one(b: &mut test::Bencher) { 129 | b.iter(|| { 130 | Article::session() 131 | .field("title") 132 | .eq("Hello world!") 133 | .limit(1) 134 | .find() 135 | .unwrap() 136 | }) 137 | } 138 | 139 | } 140 | -------------------------------------------------------------------------------- /arthas/src/tree/searcher/task/mod.rs: -------------------------------------------------------------------------------- 1 | 2 | use std::collections::HashSet; 3 | use super::super::comparision::Comparision; 4 | use item::FieldInt; 5 | use query::{Query, Order, QueryType}; 6 | use super::super::rc::RcChild; 7 | 8 | pub type Subs = Vec; 9 | pub type Orders = Vec<(String, Order)>; 10 | 11 | #[derive(Debug)] 12 | pub struct Sub { 13 | pub field_int: FieldInt, 14 | pub comparisions: Vec, 15 | pub order: Option, 16 | pub stopped: bool, 17 | } 18 | 19 | impl Sub { 20 | pub fn _match(&self, rc_child: &RcChild) -> bool { 21 | let child = rc_child.read().unwrap(); 22 | let item = child.item.read().unwrap(); 23 | let rc_data = item.datas.get(&self.field_int).unwrap(); 24 | let data = rc_data.read().unwrap(); 25 | let value = data.get_value(); 26 | 27 | for comparision in &self.comparisions { 28 | if !comparision._match(value) { 29 | return false; 30 | } 31 | } 32 | true 33 | } 34 | } 35 | 36 | 37 | #[derive(Default, Debug)] 38 | pub struct Task { 39 | pub subs: Subs, 40 | pub orders: Orders, 41 | pub order_field: Option, 42 | pub order: Option, 43 | pub offset: usize, 44 | pub limit: Option, 45 | pub query_type: QueryType, 46 | pub subs_length: usize, 47 | pub current: usize, 48 | } 49 | 50 | impl Task { 51 | pub fn new(query: &Query, query_type: &QueryType) -> Task { 52 | let (subs_length, subs) = Self::create_subs(query); 53 | let orders = Self::create_orders(query); 54 | let order_field = if let Some(order) = orders.first() { 55 | Some(order.0.to_owned()) 56 | } else { 57 | None 58 | }; 59 | let order = if let Some(order) = orders.first() { 60 | Some(order.1.clone()) 61 | } else { 62 | None 63 | }; 64 | 65 | Task { 66 | subs: subs, 67 | orders: orders, 68 | order: order, 69 | offset: query.offset.unwrap_or(0), 70 | limit: query.limit.clone(), 71 | query_type: query_type.clone(), 72 | subs_length: subs_length, 73 | order_field: order_field, 74 | current: 0, 75 | } 76 | } 77 | 78 | fn create_orders(query: &Query) -> Orders { 79 | let mut fields = HashSet::new(); 80 | let mut orders = Vec::new(); 81 | 82 | for tup in &query.orders { 83 | if fields.contains(&tup.0) { 84 | continue; 85 | } else { 86 | orders.push(tup.clone()); 87 | fields.insert(tup.0.clone()); 88 | } 89 | } 90 | 91 | orders 92 | } 93 | 94 | fn create_subs(query: &Query) -> (usize, Subs) { 95 | let mut subs_length = 0; 96 | let mut subs = Vec::new(); 97 | 98 | for (field_int, comparisions) in &query.conditions { 99 | subs_length += 1; 100 | let mut sub_order = None; 101 | 102 | if !query.orders.is_empty() { 103 | let order = query.orders.first().unwrap(); 104 | if field_int == &order.0 { 105 | sub_order = Some(order.1.clone()); 106 | } 107 | } 108 | 109 | subs.push(Sub { 110 | field_int: field_int.to_owned(), 111 | comparisions: comparisions.clone(), 112 | order: sub_order, 113 | stopped: false, 114 | }); 115 | } 116 | 117 | (subs_length, subs) 118 | } 119 | 120 | pub fn get_order_field(&self) -> &str { 121 | self.order_field.as_ref().unwrap() 122 | } 123 | 124 | pub fn has_order(&self) -> bool { 125 | self.order_field.is_some() 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /arthas/src/persistence/mod.rs: -------------------------------------------------------------------------------- 1 | 2 | pub mod operation; 3 | pub mod meta; 4 | pub mod service; 5 | pub mod logger; 6 | 7 | 8 | use std::str; 9 | use std::collections::HashMap; 10 | use item::StructName; 11 | use persistence::operation::Operation; 12 | use traits::FieldIntMap; 13 | use encoder::bin_encode; 14 | use item::Id; 15 | use self::meta::{Meta, SimpleMeta}; 16 | use self::logger::{Line, Action}; 17 | use serde_json; 18 | use BINENCODE; 19 | 20 | 21 | #[derive(Default, Serialize, Deserialize, Debug, Clone)] 22 | pub struct Persistence { 23 | pub struct_name: StructName, 24 | pub field_int_map: FieldIntMap, 25 | pub metas: HashMap, 26 | pub deleted: Vec, 27 | pub size: usize, 28 | } 29 | 30 | impl Persistence { 31 | pub fn new(struct_name: StructName, field_int_map: FieldIntMap) -> Persistence { 32 | Persistence { 33 | struct_name: struct_name, 34 | field_int_map: field_int_map, 35 | ..Default::default() 36 | } 37 | } 38 | 39 | pub fn insert(&mut self, operation: Operation) -> (bool, SimpleMeta, Vec) { 40 | let bytes = self.get_bytes(&operation).unwrap(); 41 | let meta = Meta::new(&bytes).to_simple(); 42 | let (append, meta) = self.insert_meta(operation.id.unwrap(), meta); 43 | (append, meta, bytes) 44 | } 45 | 46 | pub fn delete(&mut self, operation: Operation) { 47 | let removed = self.metas.remove(&operation.id.unwrap()); 48 | if removed.is_some() { 49 | let meta = removed.unwrap(); 50 | self.deleted.push(meta); 51 | } 52 | } 53 | 54 | pub fn clear(&mut self) { 55 | for (_, meta) in self.metas.drain() { 56 | self.deleted.push(meta); 57 | } 58 | 59 | self.size = 0; 60 | } 61 | 62 | pub fn write_log(&mut self, log: String) -> Option<(bool, SimpleMeta, Vec)> { 63 | let line = serde_json::from_str::(&log).unwrap(); 64 | match line.action { 65 | Action::Insert => { 66 | Some(self.insert(Operation::new().id(line.id.unwrap()).value(line.value.unwrap()))) 67 | } 68 | Action::Delete => { 69 | self.delete(Operation::new().id(line.id.unwrap()).delete()); 70 | None 71 | } 72 | Action::Clear => { 73 | self.clear(); 74 | None 75 | } 76 | } 77 | } 78 | 79 | fn insert_meta(&mut self, id: Id, mut meta: SimpleMeta) -> (bool, SimpleMeta) { 80 | let mut append = false; 81 | let return_meta; 82 | 83 | if let Some(mut old_meta) = self.find_in_deleted(meta.size()) { 84 | old_meta.set_real(meta.real()); 85 | return_meta = old_meta.clone(); 86 | self.metas.insert(id, old_meta); 87 | } else if self.size > 0 { 88 | meta.set_offset(self.size); 89 | return_meta = meta.clone(); 90 | self.metas.insert(id, meta); 91 | append = true; 92 | } else { 93 | return_meta = meta.clone(); 94 | self.metas.insert(id, meta); 95 | append = true; 96 | } 97 | 98 | self.size += return_meta.size(); 99 | 100 | (append, return_meta) 101 | } 102 | 103 | fn get_bytes(&self, operation: &Operation) -> Option> { 104 | if operation.value.is_some() { 105 | let data = operation.value.as_ref().unwrap().to_string(); 106 | 107 | Some(if BINENCODE { 108 | bin_encode(data) 109 | } else { 110 | data.as_bytes().to_owned() 111 | }) 112 | } else { 113 | None 114 | } 115 | } 116 | 117 | fn find_in_deleted(&mut self, size: usize) -> Option { 118 | let mut index_option = None; 119 | 120 | for (index, meta) in self.deleted.iter().enumerate() { 121 | if meta.size() >= size { 122 | index_option = Some(index); 123 | break; 124 | } 125 | } 126 | 127 | if index_option.is_some() { 128 | Some(self.deleted.swap_remove(index_option.unwrap())) 129 | } else { 130 | None 131 | } 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /arthas/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Arthas is an in-memory structure database. 2 | //! 3 | //! # Usage 4 | //! 5 | //! 1. Add dependencies to `Cargo.toml`. 6 | //! 7 | //! ```html 8 | //! [dependencies] 9 | //! arthas = "^0.3" 10 | //! arthas_derive = "^0.1" 11 | //! serde = "^0.9" 12 | //! serde_derive = "^0.9" 13 | //! ``` 14 | //! 15 | //! 2. In your `main.rs` or `lib.rs`: 16 | //! 17 | //! ```html 18 | //! extern crate arthas; 19 | //! #[macro_use] 20 | //! extern crate arthas_derive; 21 | //! #[macro_use] 22 | //! extern crate serde_derive; 23 | //! ``` 24 | //! 25 | //! 3. Add "#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Arthas)]" attribute to your struct. 26 | //! 27 | //! ```html 28 | //! #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Arthas)] 29 | //! pub struct Article { 30 | //! pub _id: String, // If you want to use id. add a field named `_id`. 31 | //! pub title: String, 32 | //! pub content: String, 33 | //! pub views: usize, 34 | //! } 35 | //! ``` 36 | //! 37 | //! 38 | //! # CRUD Examples 39 | //! All struct can use the static method `session()`. `session()` will return a [`Query`](struct.Query.html). 40 | //! 41 | //! ``` 42 | //! extern crate arthas; 43 | //! #[macro_use] 44 | //! extern crate arthas_derive; 45 | //! #[macro_use] 46 | //! extern crate serde_derive; 47 | //! 48 | //! use arthas::prelude::*; 49 | //! 50 | //! #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Arthas)] 51 | //! pub struct Article { 52 | //! pub _id: String, 53 | //! pub title: String, 54 | //! pub content: String, 55 | //! pub views: usize, 56 | //! } 57 | //! 58 | //! impl Article { 59 | //! pub fn new>(title: T) -> Article { 60 | //! Article { title: title.into(), ..Default::default() } 61 | //! } 62 | //! } 63 | //! 64 | //! fn main() { 65 | //! // Disable persistence for the tests. 66 | //! arthas::config::persistence(false); 67 | //! 68 | //! // Insert 69 | //! let id = Article::session().insert(Article::new("Hello world!")).unwrap(); 70 | //! 71 | //! // Update 72 | //! Article::session().id(&id).update(|article| article.views = 10).unwrap(); 73 | //! 74 | //! // Find 75 | //! let items = Article::session().find().unwrap(); 76 | //! assert!(items.len() > 0); 77 | //! 78 | //! // Find One 79 | //! let item = Article::session().id(&id).find_one().unwrap(); 80 | //! assert!(item.is_some()); 81 | //! assert_eq!(item.unwrap().title, "Hello world!"); 82 | //! 83 | //! // Remove 84 | //! Article::session().id(&id).remove().unwrap(); 85 | //! } 86 | //! ``` 87 | //! 88 | //! # Load Persistence 89 | //! Arthas will not automatically load persistence from disk, you have to load persistence yourself. 90 | //! 91 | //! ```html 92 | //! arthas::load::
(); // Load `Article`'s persistence. 93 | //! ``` 94 | //! 95 | //! # Update Structure 96 | //! Sometimes you want to update your structure. Like renaming or removing fields. Arthas will automatically remove and add fields, but you have to tell Arthas if you want to **rename** fields. 97 | //! 98 | //! ```html 99 | //! #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Arthas)] 100 | //! #[arthas(rename = "content = body, views = visit")] // Use `#[arthas]` attribute. 101 | //! pub struct Article { 102 | //! pub _id: String, 103 | //! pub title: String, 104 | //! pub body: String, // This is the field renamed from `content` 105 | //! pub visit: usize, // This is the field renamed from `views` 106 | //! } 107 | //! ``` 108 | //! 109 | #![deny(missing_docs)] 110 | 111 | #[cfg(test)] 112 | extern crate env_logger; 113 | 114 | #[macro_use] 115 | extern crate quick_error; 116 | #[macro_use] 117 | extern crate serde_derive; 118 | #[macro_use] 119 | extern crate lazy_static; 120 | #[macro_use] 121 | extern crate log; 122 | extern crate serde_json; 123 | extern crate memmap; 124 | extern crate bincode; 125 | extern crate serde; 126 | extern crate glob; 127 | extern crate num_cpus; 128 | extern crate scoped_pool; 129 | extern crate quickersort; 130 | extern crate objectid; 131 | extern crate thread_id; 132 | extern crate chrono; 133 | extern crate vec_map; 134 | 135 | 136 | #[macro_use] 137 | mod macros; 138 | #[doc(hidden)] 139 | pub mod encoder; 140 | mod memory; 141 | mod persistence; 142 | mod store; 143 | mod utils; 144 | mod loader; 145 | mod query; 146 | mod error; 147 | mod tree; 148 | mod item; 149 | 150 | #[doc(hidden)] 151 | pub mod traits; 152 | pub mod prelude; 153 | 154 | pub use query::Query; 155 | pub use error::Error; 156 | pub use item::Id; 157 | 158 | #[doc(hidden)] 159 | pub mod types; 160 | pub mod config; 161 | 162 | 163 | /// Load persistence. 164 | pub fn load() { 165 | loader::load::(); 166 | } 167 | 168 | /// Convert variable to `serde_json::Value`. 169 | pub fn to_value(value: S) -> serde_json::Value { 170 | serde_json::to_value(value).unwrap() 171 | } 172 | 173 | 174 | const DATA_EXTENSION: &'static str = "ar"; 175 | const PERSISTENCE_EXTENSION: &'static str = "arx"; 176 | const LOG_EXTENSION: &'static str = "arl"; 177 | const SAVING_EXTENSION: &'static str = "saving"; 178 | const DATA_DIR: &'static str = "arthas.ar"; 179 | const BINENCODE: bool = true; 180 | -------------------------------------------------------------------------------- /arthas/src/tree/math/mod.rs: -------------------------------------------------------------------------------- 1 | 2 | use std::cmp::Ordering; 3 | use serde_json::Value; 4 | use query::Order; 5 | 6 | 7 | pub trait Math { 8 | fn eq(&self, &Value) -> bool; 9 | fn ne(&self, &Value) -> bool; 10 | fn gt(&self, &Value) -> bool; 11 | fn lt(&self, &Value) -> bool; 12 | fn ge(&self, &Value) -> bool; 13 | fn le(&self, &Value) -> bool; 14 | fn cmp(&self, &Value, order: &Order) -> Ordering; 15 | fn get_rate(&self, &Value) -> f64; 16 | } 17 | 18 | impl Math for Value { 19 | fn eq(&self, value: &Value) -> bool { 20 | thread_trace!("math eq, current: {:?}, find: {:?}", self, value); 21 | 22 | if self.is_number() && value.is_number() { 23 | self.get_f64() == value.get_f64() 24 | } else { 25 | self == value 26 | } 27 | } 28 | 29 | fn ne(&self, value: &Value) -> bool { 30 | thread_trace!("math ne, current: {:?}, find: {:?}", self, value); 31 | 32 | if self.is_number() && value.is_number() { 33 | self.get_f64() != value.get_f64() 34 | } else { 35 | self != value 36 | } 37 | } 38 | 39 | fn gt(&self, value: &Value) -> bool { 40 | thread_trace!("math gt, current: {:?}, find: {:?}", self, value); 41 | 42 | if self.is_number() && value.is_number() { 43 | self.get_f64() > value.get_f64() 44 | } else if self.is_string() && value.is_string() { 45 | self.get_str() > value.get_str() 46 | } else { 47 | panic!("Unsupported math type"); 48 | } 49 | } 50 | 51 | fn lt(&self, value: &Value) -> bool { 52 | thread_trace!("math lt, current: {:?}, find: {:?}", self, value); 53 | 54 | if self.is_number() && value.is_number() { 55 | self.get_f64() < value.get_f64() 56 | } else if self.is_string() && value.is_string() { 57 | self.get_str() < value.get_str() 58 | } else { 59 | panic!("Unsupported math type"); 60 | } 61 | } 62 | 63 | fn ge(&self, value: &Value) -> bool { 64 | thread_trace!("math ge, current: {:?}, find: {:?}", self, value); 65 | 66 | if self.is_number() && value.is_number() { 67 | self.get_f64() >= value.get_f64() 68 | } else if self.is_string() && value.is_string() { 69 | self.get_str() >= value.get_str() 70 | } else { 71 | panic!("Unsupported math type"); 72 | } 73 | } 74 | 75 | fn le(&self, value: &Value) -> bool { 76 | thread_trace!("math le, current: {:?}, find: {:?}", self, value); 77 | 78 | if self.is_number() && value.is_number() { 79 | self.get_f64() <= value.get_f64() 80 | } else if self.is_string() && value.is_string() { 81 | self.get_str() <= value.get_str() 82 | } else { 83 | panic!("Unsupported math type"); 84 | } 85 | } 86 | 87 | fn cmp(&self, value: &Value, order: &Order) -> Ordering { 88 | thread_trace!("math cmp, current: {:?}, find: {:?}", self, value); 89 | 90 | if let Order::Desc = *order { 91 | if Math::eq(self, value) { 92 | Ordering::Equal 93 | } else if Math::lt(self, value) { 94 | Ordering::Greater 95 | } else if Math::gt(self, value) { 96 | Ordering::Less 97 | } else { 98 | panic!("Unsupported math type"); 99 | } 100 | } else if Math::eq(self, value) { 101 | Ordering::Equal 102 | } else if Math::lt(self, value) { 103 | Ordering::Less 104 | } else if Math::gt(self, value) { 105 | Ordering::Greater 106 | } else { 107 | panic!("Unsupported math type"); 108 | } 109 | } 110 | 111 | fn get_rate(&self, other: &Value) -> f64 { 112 | if self.is_number() && other.is_number() { 113 | let n1 = self.get_f64(); 114 | let n2 = other.get_f64(); 115 | n2 / n1 116 | } else if self.is_string() && other.is_string() { 117 | let n1 = self.get_str().chars().map(|c| c as usize).fold(0, |a, b| a + b); 118 | let n2 = other.get_str().chars().map(|c| c as usize).fold(0, |a, b| a + b); 119 | n2 as f64 / n1 as f64 120 | } else { 121 | panic!("Unsupported math type"); 122 | } 123 | } 124 | } 125 | 126 | 127 | trait Type { 128 | fn get_f64(&self) -> f64; 129 | fn get_string(&self) -> String; 130 | fn get_str(&self) -> &str; 131 | fn get_u64(&self) -> u64; 132 | fn get_i64(&self) -> i64; 133 | fn get_boolean(&self) -> bool; 134 | fn format(&self) -> String; 135 | } 136 | 137 | impl Type for Value { 138 | fn get_f64(&self) -> f64 { 139 | match *self { 140 | Value::Number(ref n) => n.as_f64().unwrap(), 141 | _ => panic!("not a number"), 142 | } 143 | } 144 | 145 | fn get_string(&self) -> String { 146 | self.as_str().unwrap().to_owned() 147 | } 148 | 149 | fn get_str(&self) -> &str { 150 | self.as_str().unwrap() 151 | } 152 | 153 | fn get_u64(&self) -> u64 { 154 | self.as_u64().unwrap() 155 | } 156 | 157 | fn get_i64(&self) -> i64 { 158 | self.as_i64().unwrap() 159 | } 160 | 161 | fn get_boolean(&self) -> bool { 162 | self.as_bool().unwrap() 163 | } 164 | 165 | fn format(&self) -> String { 166 | format!("{:?}", self) 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /arthas/tests/crud.rs: -------------------------------------------------------------------------------- 1 | 2 | extern crate rand; 3 | extern crate arthas; 4 | #[macro_use] 5 | extern crate serde_derive; 6 | #[macro_use] 7 | extern crate arthas_derive; 8 | extern crate env_logger; 9 | 10 | pub mod common; 11 | pub mod model; 12 | 13 | use model::*; 14 | use common::setup; 15 | 16 | 17 | #[test] 18 | fn test_a_insert() { 19 | setup(); 20 | 21 | let id = Article::session().insert(Article::new("Hello world!")).unwrap(); 22 | let item = Article::session().id(&id).find_one().unwrap(); 23 | assert!(item.is_some()); 24 | assert_eq!(item.unwrap().title, "Hello world!"); 25 | } 26 | 27 | #[test] 28 | fn test_a_insert_random() { 29 | setup(); 30 | 31 | Article::session() 32 | .insert(Article::new("Hello world!").views(common::random_usize())) 33 | .unwrap(); 34 | } 35 | 36 | #[test] 37 | fn test_remove() { 38 | setup(); 39 | 40 | let id = Article::session().insert(Article::new("Hello world!")).unwrap(); 41 | let items = Article::session().id(&id).remove().unwrap(); 42 | assert_eq!(items.len(), 1); 43 | assert_eq!(items.first().unwrap().title, "Hello world!"); 44 | } 45 | 46 | #[test] 47 | fn test_update() { 48 | setup(); 49 | 50 | let id = Article::session().insert(Article::new("Hello world!")).unwrap(); 51 | Article::session().id(&id).update(|item| item.title = "Hello".to_owned()).unwrap(); 52 | let item = Article::session().id(&id).find_one().unwrap(); 53 | assert!(item.is_some()); 54 | assert_eq!(item.unwrap().title, "Hello"); 55 | } 56 | 57 | #[test] 58 | fn test_replace() { 59 | setup(); 60 | 61 | let id = Article::session().insert(Article::new("Hello world!")).unwrap(); 62 | Article::session().id(&id).replace(Article::new("Foobar Replace!")).unwrap(); 63 | let item = Article::session().id(&id).find_one().unwrap(); 64 | assert_eq!(item.unwrap().title, "Foobar Replace!"); 65 | } 66 | 67 | #[test] 68 | fn test_find() { 69 | setup(); 70 | 71 | for i in 0..10 { 72 | Article::session() 73 | .insert(Article::new("Foobar!").views(i)) 74 | .unwrap(); 75 | } 76 | 77 | let all_items = Article::session() 78 | .field("title") 79 | .eq("Foobar!") 80 | .find() 81 | .unwrap(); 82 | 83 | assert_eq!(all_items.len(), 10); 84 | 85 | let less_five_items = Article::session() 86 | .field("title") 87 | .eq("Foobar!") 88 | .field("views") 89 | .lt(5) 90 | .find() 91 | .unwrap(); 92 | 93 | assert_eq!(less_five_items.len(), 5); 94 | } 95 | 96 | #[test] 97 | fn test_count() { 98 | setup(); 99 | 100 | for i in 0..10 { 101 | Article::session() 102 | .insert(Article::new("Count!").views(i)) 103 | .unwrap(); 104 | } 105 | 106 | let count = Article::session() 107 | .field("title") 108 | .eq("Count!") 109 | .count() 110 | .unwrap(); 111 | 112 | assert_eq!(count, 10); 113 | } 114 | 115 | #[test] 116 | fn test_offset() { 117 | setup(); 118 | 119 | for i in 0..10 { 120 | Article::session() 121 | .insert(Article::new("Offset!").views(i)) 122 | .unwrap(); 123 | } 124 | 125 | let count = Article::session() 126 | .field("title") 127 | .eq("Offset!") 128 | .offset(5) 129 | .count() 130 | .unwrap(); 131 | 132 | assert_eq!(count, 5); 133 | } 134 | 135 | #[test] 136 | fn test_lt_100() { 137 | setup(); 138 | 139 | Article::session() 140 | .field("views") 141 | .lt(100) 142 | .find() 143 | .unwrap(); 144 | } 145 | 146 | #[test] 147 | fn test_gt_100() { 148 | setup(); 149 | 150 | Article::session() 151 | .field("views") 152 | .gt(100) 153 | .find() 154 | .unwrap(); 155 | } 156 | 157 | #[test] 158 | fn test_desc() { 159 | setup(); 160 | 161 | for i in 0..5 { 162 | Article::session() 163 | .insert(Article::new("Desc!").views(i)) 164 | .unwrap(); 165 | } 166 | 167 | let items = Article::session() 168 | .field("title") 169 | .eq("Desc!") 170 | .field("views") 171 | .lt(3) 172 | .desc("views") 173 | .find() 174 | .unwrap(); 175 | assert_eq!(items.len(), 3); 176 | assert_eq!(items[0].views, 2); 177 | assert_eq!(items[1].views, 1); 178 | assert_eq!(items[2].views, 0); 179 | } 180 | 181 | #[test] 182 | fn test_asc() { 183 | setup(); 184 | 185 | for i in 0..5 { 186 | Article::session() 187 | .insert(Article::new("Asc!").views(i)) 188 | .unwrap(); 189 | } 190 | 191 | let items = Article::session() 192 | .field("title") 193 | .eq("Asc!") 194 | .field("views") 195 | .lt(3) 196 | .asc("views") 197 | .find() 198 | .unwrap(); 199 | 200 | assert_eq!(items.len(), 3); 201 | assert_eq!(items[0].views, 0); 202 | assert_eq!(items[1].views, 1); 203 | assert_eq!(items[2].views, 2); 204 | } 205 | 206 | #[test] 207 | fn test_multiple_order() { 208 | setup(); 209 | 210 | for i in 0..5 { 211 | let content = if i < 3 { "a" } else { "b" }; 212 | Article::session() 213 | .insert(Article::new("Multiple Order!").views(i).content(content)) 214 | .unwrap(); 215 | } 216 | 217 | let items = Article::session() 218 | .field("title") 219 | .eq("Multiple Order!") 220 | .desc("content") 221 | .asc("views") 222 | .find() 223 | .unwrap(); 224 | 225 | assert_eq!(items.len(), 5); 226 | assert_eq!(items[0].content, "b"); 227 | assert_eq!(items[1].content, "b"); 228 | assert_eq!(items[2].content, "a"); 229 | assert_eq!(items[3].content, "a"); 230 | assert_eq!(items[4].content, "a"); 231 | 232 | assert_eq!(items[0].views, 3); 233 | assert_eq!(items[1].views, 4); 234 | assert_eq!(items[2].views, 0); 235 | assert_eq!(items[3].views, 1); 236 | assert_eq!(items[4].views, 2); 237 | 238 | let items = Article::session() 239 | .field("title") 240 | .eq("Multiple Order!") 241 | .desc("content") 242 | .desc("views") 243 | .find() 244 | .unwrap(); 245 | 246 | assert_eq!(items[0].views, 4); 247 | assert_eq!(items[1].views, 3); 248 | assert_eq!(items[2].views, 2); 249 | assert_eq!(items[3].views, 1); 250 | assert_eq!(items[4].views, 0); 251 | } 252 | 253 | #[test] 254 | fn test_len() { 255 | setup(); 256 | 257 | for i in 0..5 { 258 | Article::session() 259 | .insert(Article::new("qwertyuiopasdfghjklzxcvbnm").views(i)) 260 | .unwrap(); 261 | } 262 | 263 | let items = Article::session() 264 | .len("title") 265 | .eq(26) 266 | .find() 267 | .unwrap(); 268 | 269 | assert_eq!(items.len(), 5); 270 | } 271 | 272 | #[test] 273 | fn test_empty_query_all() { 274 | setup(); 275 | 276 | Article::session().insert(Article::new("Empty Query All!")).unwrap(); 277 | 278 | let items = Article::session() 279 | .limit(100) 280 | .find() 281 | .unwrap(); 282 | 283 | assert!(items.len() > 0); 284 | } 285 | -------------------------------------------------------------------------------- /arthas/src/memory/mod.rs: -------------------------------------------------------------------------------- 1 | 2 | use std::sync::Mutex; 3 | use std::sync::atomic::{AtomicPtr, Ordering}; 4 | use std::sync::Arc; 5 | use query::Query; 6 | use item::{ItemWrapper, Id, get_len_field_int}; 7 | use serde_json::Value; 8 | use to_value; 9 | use store; 10 | use traits::{Structure, FieldIntMap}; 11 | use persistence::service::PersistenceService; 12 | use error::Error; 13 | use item::convertor::Convertor; 14 | use encoder; 15 | use tree::Tree; 16 | use query::QueryType; 17 | use num_cpus; 18 | use utils::hash_map::revert; 19 | use scoped_pool::Pool; 20 | use vec_map::VecMap; 21 | 22 | 23 | pub struct Memory { 24 | pub field_int_map: Arc, 25 | pub int_field_map: Arc, 26 | pub service: PersistenceService, 27 | pub tree: Tree, 28 | pub is_one: bool, 29 | pub pool: Pool, 30 | } 31 | 32 | impl Memory { 33 | pub fn new() -> Memory { 34 | Memory { 35 | field_int_map: Arc::new(T::get_field_int_map()), 36 | int_field_map: Arc::new(revert(T::get_field_int_map())), 37 | service: PersistenceService::new::(), 38 | tree: Tree::new::(), 39 | is_one: T::is_one(), 40 | pool: Pool::new(num_cpus::get()), 41 | } 42 | } 43 | 44 | pub fn insert(&mut self, query: &mut Query) -> Result { 45 | self.check_query_field(query)?; 46 | 47 | let wrapper = ItemWrapper::new(query.item.take().unwrap()); 48 | let id = wrapper.id.clone(); 49 | let encoded = encoder::encode_wrapper(&to_value(wrapper), &self.field_int_map); 50 | self.insert_encoded_value(id.clone(), encoded)?; 51 | Ok(id) 52 | } 53 | 54 | pub fn find(&self, query: &mut Query) -> Result, Error> { 55 | self.check_query_field(query)?; 56 | 57 | Ok(self.search(&query, &QueryType::Find)? 58 | .1 59 | .into_iter() 60 | .map(|wrapper| wrapper.item) 61 | .collect::>()) 62 | } 63 | 64 | pub fn count(&self, query: &mut Query) -> Result { 65 | self.check_query_field(query)?; 66 | 67 | Ok(self.search(&query, &QueryType::Count)?.0) 68 | } 69 | 70 | pub fn find_one(&self, query: &mut Query) -> Result, Error> { 71 | self.check_query_field(query)?; 72 | 73 | query.limit = Some(1); 74 | let mut items = self.find(query)?; 75 | 76 | if !items.is_empty() { 77 | Ok(Some(items.remove(0))) 78 | } else if T::is_one() { 79 | Ok(Some(T::new_empty())) 80 | } else { 81 | Ok(None) 82 | } 83 | } 84 | 85 | pub fn update(&mut self, query: &mut Query) -> Result { 86 | self.check_query_field(query)?; 87 | 88 | let updater = query.updater.take().unwrap(); 89 | let mut wrappers = self.delete_to_wrapper(query)?; 90 | let count = wrappers.len(); 91 | 92 | for wrapper in &mut wrappers { 93 | updater(&mut wrapper.item); 94 | } 95 | 96 | for wrapper in &wrappers { 97 | let encoded = encoder::encode_wrapper(&to_value(wrapper), &self.field_int_map); 98 | self.tree.insert(wrapper.id.clone(), encoded); 99 | } 100 | 101 | if store::is_persistence() { 102 | for wrapper in wrappers { 103 | self.service.insert(wrapper.id.clone(), to_value(&wrapper))?; 104 | } 105 | } 106 | 107 | Ok(count) 108 | } 109 | 110 | pub fn replace(&mut self, query: &mut Query) -> Result<(), Error> { 111 | self.check_query_field(query)?; 112 | 113 | if query.id.is_some() { 114 | query.item.as_mut().unwrap().set_id(query.id.clone().unwrap()); 115 | } 116 | 117 | let wrapper = ItemWrapper::new(query.item.clone().unwrap()); 118 | self.delete_to_wrapper::(&mut Query::new().id(wrapper.id.clone()))?; 119 | self.insert(query)?; 120 | 121 | Ok(()) 122 | } 123 | 124 | pub fn delete(&mut self, query: &mut Query) -> Result, Error> { 125 | self.check_query_field(query)?; 126 | 127 | Ok(self.delete_to_wrapper(query)? 128 | .into_iter() 129 | .map(|wrapper| wrapper.item) 130 | .collect::>()) 131 | } 132 | 133 | pub fn insert_encoded_value(&mut self, id: Id, value: Value) -> Result<(), Error> { 134 | if self.is_one { 135 | self.clear()?; 136 | self.tree.insert(id.clone(), value.clone()); 137 | 138 | if store::is_persistence() { 139 | self.service.clear()?; 140 | self.service.insert(id.clone(), value.clone())?; 141 | } 142 | } else { 143 | self.tree.insert(id.clone(), value.clone()); 144 | 145 | if store::is_persistence() { 146 | self.service.insert(id.clone(), value.clone())?; 147 | } 148 | } 149 | 150 | Ok(()) 151 | } 152 | 153 | fn clear(&mut self) -> Result<(), Error> { 154 | self.tree.clear(); 155 | 156 | if store::is_persistence() { 157 | self.service.clear()?; 158 | } 159 | 160 | Ok(()) 161 | } 162 | 163 | fn delete_to_wrapper(&mut self, 164 | query: &mut Query) 165 | -> Result>, Error> { 166 | let wrappers = self.search::(&query, &QueryType::Find)?.1; 167 | 168 | for wrapper in &wrappers { 169 | self.tree.delete(&wrapper.id); 170 | 171 | if store::is_persistence() { 172 | self.service.delete(wrapper.id.clone())?; 173 | } 174 | } 175 | 176 | Ok(wrappers) 177 | } 178 | 179 | fn search(&self, 180 | query: &&mut Query, 181 | query_type: &QueryType) 182 | -> Result<(usize, Vec>), Error> { 183 | let (count, values) = self.tree.search(&self.pool, query, query_type)?; 184 | let wrappers = if query_type == &QueryType::Find && count > 0 { 185 | let wrapper_map = Mutex::new(VecMap::new()); 186 | self.pool.scoped(|scope| { 187 | let wrapper_map = &wrapper_map; 188 | let int_field_map = &self.int_field_map; 189 | 190 | for (i, value) in values.into_iter().enumerate() { 191 | let ptr = AtomicPtr::new(value as *mut Value); 192 | 193 | scope.execute(move || { 194 | let wrapper = unsafe { &*ptr.load(Ordering::SeqCst) } 195 | .to_wrapper::(&*int_field_map) 196 | .unwrap(); 197 | wrapper_map.lock().unwrap().insert(i, wrapper); 198 | }) 199 | } 200 | }); 201 | 202 | let mut wrappers = Vec::new(); 203 | let mut wrapper_map = wrapper_map.into_inner().unwrap(); 204 | 205 | for i in 0..count { 206 | wrappers.push(wrapper_map.remove(i).unwrap()); 207 | } 208 | 209 | wrappers 210 | 211 | } else { 212 | Vec::new() 213 | }; 214 | 215 | Ok((count, wrappers)) 216 | } 217 | 218 | #[inline] 219 | fn check_query_field(&self, query: &Query) -> Result<(), Error> { 220 | for field in &query.conditions { 221 | if !self.int_field_map.contains_key(field.0) { 222 | let mut found = false; 223 | 224 | for field_int in self.int_field_map.keys() { 225 | if get_len_field_int(field_int) == *field.0 { 226 | found = true; 227 | break; 228 | } 229 | } 230 | 231 | if !found { 232 | return Err(Error::FieldNotFound); 233 | } 234 | } 235 | } 236 | 237 | Ok(()) 238 | } 239 | } 240 | -------------------------------------------------------------------------------- /arthas/src/encoder/mod.rs: -------------------------------------------------------------------------------- 1 | 2 | use serde_json::{self, Value}; 3 | use traits::FieldIntMap; 4 | use std::iter::IntoIterator; 5 | use bincode::SizeLimit; 6 | use bincode::serde::{deserialize, serialize}; 7 | 8 | 9 | pub fn encode_wrapper(value: &Value, field_int_map: &FieldIntMap) -> Value { 10 | handle_wrapper(Action::Encode, value, field_int_map) 11 | } 12 | 13 | pub fn decode_wrapper(value: &Value, field_int_map: &FieldIntMap) -> Value { 14 | handle_wrapper(Action::Decode, value, field_int_map) 15 | } 16 | 17 | enum Action { 18 | Encode, 19 | Decode, 20 | } 21 | 22 | fn handle_wrapper(action: Action, value: &Value, field_int_map: &FieldIntMap) -> Value { 23 | if value.is_object() { 24 | let handled = match action { 25 | Action::Encode => encode(value.get("item").unwrap(), field_int_map), 26 | Action::Decode => decode(value.get("item").unwrap(), field_int_map), 27 | }; 28 | 29 | let mut map = serde_json::Map::new(); 30 | map.insert("id".to_owned(), value.get("id").unwrap().to_owned()); 31 | map.insert("item".to_owned(), handled); 32 | Value::Object(map) 33 | } else { 34 | unreachable!() 35 | } 36 | } 37 | 38 | pub fn encode(value: &Value, field_int_map: &FieldIntMap) -> Value { 39 | let mut output = Value::Object(serde_json::Map::new()); 40 | 41 | for (path, integer) in field_int_map { 42 | encode_segments(path, 43 | &mut get_path_segments(path), 44 | &mut Vec::new(), 45 | value, 46 | object_entry(&mut output, integer)); 47 | } 48 | 49 | output 50 | } 51 | 52 | fn encode_segments<'a>(path: &str, 53 | segments: &mut Vec<&'a str>, 54 | current_path: &mut Vec<&'a str>, 55 | current_input: &Value, 56 | current_output: &mut Value) { 57 | let segment = segments.remove(0); 58 | current_path.push(segment); 59 | 60 | if segment == "[]" { 61 | if current_input.as_array().is_some() { 62 | for (index, input) in current_input.as_array().unwrap().into_iter().enumerate() { 63 | encode_segments(path, 64 | segments, 65 | current_path, 66 | input, 67 | array_get_value_mut(current_output, index)); 68 | } 69 | } 70 | } else if segment == "{}" { 71 | if current_input.as_object().is_some() { 72 | for (field, input) in current_input.as_object().unwrap() { 73 | encode_segments(path, 74 | segments, 75 | current_path, 76 | input, 77 | object_entry_value_mut(current_output, field)); 78 | } 79 | } 80 | } else if current_path.join(".") == path { 81 | *current_output = current_input.get(segment).unwrap().clone(); 82 | } else { 83 | encode_segments(path, 84 | segments, 85 | current_path, 86 | current_input.get(segment).unwrap(), 87 | current_output); 88 | } 89 | 90 | segments.insert(0, segment); 91 | current_path.pop(); 92 | } 93 | 94 | pub fn decode(value: &Value, int_field_map: &FieldIntMap) -> Value { 95 | let mut output = Value::Object(serde_json::Map::new()); 96 | let path_value = replace_integer(value, int_field_map); 97 | 98 | for (path, input) in path_value.as_object().unwrap() { 99 | decode_segments(path, 100 | &mut get_path_segments(path), 101 | &mut Vec::new(), 102 | input, 103 | &mut output); 104 | } 105 | 106 | output 107 | } 108 | 109 | fn decode_segments<'a>(path: &str, 110 | segments: &mut Vec<&'a str>, 111 | current_path: &mut Vec<&'a str>, 112 | current_input: &Value, 113 | current_output: &mut Value) { 114 | let segment = segments.remove(0); 115 | current_path.push(segment); 116 | 117 | if segment == "[]" { 118 | if current_input.as_array().is_some() { 119 | for (index, input) in current_input.as_array().unwrap().into_iter().enumerate() { 120 | decode_segments(path, 121 | segments, 122 | current_path, 123 | input, 124 | array_get_value_mut(current_output, index)); 125 | } 126 | } else { 127 | *current_output = Value::Array(Vec::new()); 128 | } 129 | } else if segment == "{}" { 130 | if current_input.as_object().is_some() { 131 | for (field, input) in current_input.as_object().unwrap() { 132 | decode_segments(path, 133 | segments, 134 | current_path, 135 | input, 136 | object_entry_value_mut(current_output, field)); 137 | } 138 | } else { 139 | *current_output = Value::Object(serde_json::Map::new()); 140 | } 141 | } else if current_path.join(".") == path { 142 | object_insert(current_output, segment, current_input); 143 | } else { 144 | decode_segments(path, 145 | segments, 146 | current_path, 147 | current_input, 148 | object_entry_value_mut(current_output, segment)); 149 | } 150 | 151 | segments.insert(0, segment); 152 | current_path.pop(); 153 | } 154 | 155 | #[inline] 156 | pub fn bin_encode>(input: T) -> Vec { 157 | serialize(&input.into(), SizeLimit::Infinite).unwrap() 158 | } 159 | 160 | #[inline] 161 | pub fn bin_decode>(input: T) -> String { 162 | deserialize(input.as_ref()).unwrap() 163 | } 164 | 165 | #[inline] 166 | fn replace_integer(value: &Value, int_field_map: &FieldIntMap) -> Value { 167 | let mut map = serde_json::Map::new(); 168 | 169 | for (integer, value) in value.as_object().unwrap() { 170 | map.insert(int_field_map.get(integer).cloned().unwrap(), value.clone()); 171 | } 172 | 173 | Value::Object(map) 174 | 175 | } 176 | 177 | #[inline] 178 | fn get_path_segments(path: &str) -> Vec<&str> { 179 | path.split('.').collect::>() 180 | } 181 | 182 | #[inline] 183 | fn object_entry<'a>(object: &'a mut Value, field: &str) -> &'a mut Value { 184 | if let Value::Object(ref mut map) = *object { 185 | if !map.contains_key(field) { 186 | map.insert(field.to_owned(), Value::Null); 187 | } 188 | 189 | map.get_mut(field).unwrap() 190 | } else { 191 | unreachable!() 192 | } 193 | } 194 | 195 | #[inline] 196 | fn object_insert(object: &mut Value, field: &str, input: &Value) { 197 | if let Value::Object(ref mut map) = *object { 198 | map.insert(field.to_owned(), input.clone()); 199 | } else { 200 | unreachable!() 201 | } 202 | } 203 | 204 | #[inline] 205 | fn array_get_value_mut(array: &mut Value, index: usize) -> &mut Value { 206 | if array.as_array().is_none() { 207 | *array = Value::Array(Vec::new()); 208 | } 209 | 210 | if let Value::Array(ref mut vec) = *array { 211 | if vec.get(index).is_none() { 212 | vec.push(Value::Object(serde_json::Map::new())); 213 | } 214 | 215 | &mut vec[index] 216 | } else { 217 | unreachable!() 218 | } 219 | } 220 | 221 | #[inline] 222 | fn object_entry_value_mut<'a>(object: &'a mut Value, field: &str) -> &'a mut Value { 223 | if object.as_object().is_none() { 224 | *object = Value::Object(serde_json::Map::new()); 225 | } 226 | 227 | if let Value::Object(ref mut map) = *object { 228 | if !map.contains_key(field) { 229 | map.insert(field.to_owned(), Value::Object(serde_json::Map::new())); 230 | } 231 | 232 | map.get_mut(field).unwrap() 233 | } else { 234 | unreachable!() 235 | } 236 | } 237 | -------------------------------------------------------------------------------- /arthas/src/query/mod.rs: -------------------------------------------------------------------------------- 1 | 2 | mod order; 3 | mod query_type; 4 | mod action; 5 | 6 | #[macro_use] 7 | mod macros { 8 | macro_rules! exec_query { 9 | ($store:ident, $access:ident, $action:ident, $query: ident) => { 10 | { 11 | check_query(&$query)?; 12 | 13 | thread_trace!("{:?}: {}, lock done", $query.action, $query.struct_name); 14 | 15 | let result = $store.get_memory::() 16 | .$access() 17 | .unwrap().$action(&mut $query); 18 | 19 | thread_trace!("{:?}: {}, query time: {} ms, result: {:?}", 20 | $query.action, 21 | $query.struct_name, 22 | $query.get_query_time(), 23 | result); 24 | 25 | result 26 | } 27 | } 28 | } 29 | } 30 | 31 | pub use self::order::Order; 32 | pub use self::query_type::QueryType; 33 | 34 | use std::sync::RwLockReadGuard; 35 | use std::collections::HashMap; 36 | use std::time::Instant; 37 | use item::{Id, StructName, get_len_field_int}; 38 | use memory::Memory; 39 | use traits::Structure; 40 | use store::{MemoryStore, memories, persistences, is_persistence, MemoryGetter}; 41 | use std::sync::RwLock; 42 | use persistence::Persistence; 43 | use error::Error; 44 | use std::fmt; 45 | use tree::comparision::Comparision; 46 | use tree::cmp::Cmp; 47 | use to_value; 48 | use serde::Serialize; 49 | use traits::get_unique_int_str; 50 | use self::action::Action; 51 | 52 | 53 | pub type Updater<'a, T> = Box; 54 | 55 | /// Query. 56 | #[derive(Default)] 57 | pub struct Query<'a, T> { 58 | #[doc(hidden)] 59 | pub updater: Option>, 60 | #[doc(hidden)] 61 | pub item: Option, 62 | #[doc(hidden)] 63 | pub id: Option, 64 | #[doc(hidden)] 65 | pub limit: Option, 66 | #[doc(hidden)] 67 | pub offset: Option, 68 | #[doc(hidden)] 69 | pub field: Option, 70 | #[doc(hidden)] 71 | pub len: Option, 72 | #[doc(hidden)] 73 | pub conditions: HashMap>, 74 | #[doc(hidden)] 75 | pub orders: Vec<(String, Order)>, 76 | struct_name: StructName, 77 | action: Action, 78 | start_time: Option, 79 | } 80 | 81 | impl<'a, T: Structure> Query<'a, T> { 82 | /// Create new query. 83 | pub fn new() -> Query<'a, T> { 84 | Query { struct_name: T::get_struct_name(), ..Default::default() } 85 | } 86 | 87 | /// Query with id. 88 | pub fn id>(mut self, id: I) -> Query<'a, T> { 89 | self.id = Some(id.as_ref().into()); 90 | self 91 | } 92 | 93 | /// Limit like sql. 94 | pub fn limit(mut self, limit: usize) -> Query<'a, T> { 95 | self.limit = Some(limit); 96 | self 97 | } 98 | 99 | /// Offset like sql. 100 | pub fn offset(mut self, offset: usize) -> Query<'a, T> { 101 | self.offset = Some(offset); 102 | self 103 | } 104 | 105 | /// Set field for later comparision. 106 | pub fn field>(mut self, field: I) -> Query<'a, T> { 107 | self.field = Some(field.as_ref().into()); 108 | self 109 | } 110 | 111 | /// This method tests for `self` and `other` values to be equal, and is used by `==`. 112 | pub fn eq(mut self, other: V) -> Query<'a, T> { 113 | self.compare(Cmp::Eq, other); 114 | self 115 | } 116 | 117 | /// This method tests for `!=`. 118 | pub fn ne(mut self, other: V) -> Query<'a, T> { 119 | self.compare(Cmp::Ne, other); 120 | self 121 | } 122 | 123 | /// This method tests greater than (for `self` and `other`) and is used by the `>` operator. 124 | pub fn gt(mut self, other: V) -> Query<'a, T> { 125 | self.compare(Cmp::Gt, other); 126 | self 127 | } 128 | 129 | /// This method tests less than (for `self` and `other`) and is used by the `<` operator. 130 | pub fn lt(mut self, other: V) -> Query<'a, T> { 131 | self.compare(Cmp::Lt, other); 132 | self 133 | } 134 | 135 | /// This method tests greater than or equal to (for `self` and `other`) and is used by the `>=` operator. 136 | pub fn ge(mut self, other: V) -> Query<'a, T> { 137 | self.compare(Cmp::Ge, other); 138 | self 139 | } 140 | 141 | /// This method tests less than or equal to (for `self` and `other`) and is used by the `<=` operator. 142 | pub fn le(mut self, other: V) -> Query<'a, T> { 143 | self.compare(Cmp::Le, other); 144 | self 145 | } 146 | 147 | /// Query the field's length. 148 | pub fn len>(mut self, field: I) -> Query<'a, T> { 149 | self.len = Some(field.as_ref().into()); 150 | self 151 | } 152 | 153 | /// Query order desc field. 154 | pub fn desc>(mut self, field: I) -> Query<'a, T> { 155 | self.orders.push((get_unique_int_str(field.as_ref()), Order::Desc)); 156 | self 157 | } 158 | 159 | /// Query order asc field. 160 | pub fn asc>(mut self, field: I) -> Query<'a, T> { 161 | self.orders.push((get_unique_int_str(field.as_ref()), Order::Asc)); 162 | self 163 | } 164 | 165 | /// Insert an item. 166 | pub fn insert(mut self, item: T) -> Result { 167 | self.item = Some(item); 168 | let store = self.prepare(Action::Insert)?; 169 | exec_query!(store, write, insert, self) 170 | } 171 | 172 | /// Remove item. 173 | pub fn remove(mut self) -> Result, Error> { 174 | let store = self.prepare(Action::Remove)?; 175 | exec_query!(store, write, delete, self) 176 | } 177 | 178 | /// Update items. 179 | pub fn update(mut self, updater: F) -> Result 180 | where F: Fn(&mut T) + 'a 181 | { 182 | self.updater = Some(Box::new(updater)); 183 | let store = self.prepare(Action::Update)?; 184 | exec_query!(store, write, update, self) 185 | } 186 | 187 | /// Replace an item. 188 | pub fn replace(mut self, item: T) -> Result<(), Error> { 189 | self.item = Some(item); 190 | let store = self.prepare(Action::Replace)?; 191 | exec_query!(store, write, replace, self) 192 | } 193 | 194 | /// Find items. 195 | pub fn find(mut self) -> Result, Error> { 196 | let store = self.prepare(Action::Find)?; 197 | exec_query!(store, read, find, self) 198 | } 199 | 200 | /// Find only one item. 201 | pub fn find_one(mut self) -> Result, Error> { 202 | let store = self.prepare(Action::FindOne)?; 203 | exec_query!(store, read, find_one, self) 204 | } 205 | 206 | /// Count items. 207 | pub fn count(mut self) -> Result { 208 | let store = self.prepare(Action::Count)?; 209 | self.orders.clear(); 210 | exec_query!(store, read, count, self) 211 | } 212 | 213 | #[inline] 214 | fn prepare<'b>(&mut self, action: Action) -> Result, Error> { 215 | self.action = action; 216 | self.start_time = Some(Instant::now()); 217 | thread_trace!("{:?}: {}, query: {:?}, wait for lock.", 218 | self.action, 219 | self.struct_name, 220 | self); 221 | self.get_memory() 222 | } 223 | 224 | fn get_memory<'b>(&self) -> Result, Error> { 225 | let struct_name = T::get_struct_name(); 226 | let store_lock = memories(); 227 | 228 | if !store_lock.read().unwrap().contains_key(&struct_name) { 229 | if is_persistence() { 230 | let persistence_lock = persistences(); 231 | persistence_lock.write() 232 | .unwrap() 233 | .entry(struct_name.clone()) 234 | .or_insert_with(|| { 235 | RwLock::new(Persistence::new(struct_name.clone(), T::get_field_int_map())) 236 | }); 237 | } 238 | 239 | store_lock.write() 240 | .unwrap() 241 | .entry(struct_name.clone()) 242 | .or_insert_with(|| RwLock::new(Memory::new::())); 243 | } 244 | 245 | Ok(store_lock.read().unwrap()) 246 | } 247 | 248 | #[inline] 249 | fn get_query_time(&self) -> f64 { 250 | ((self.start_time.as_ref().unwrap().elapsed().subsec_nanos()) as f64 / 1000.0).round() / 251 | 1000.0 252 | } 253 | 254 | fn compare(&mut self, cmp: Cmp, value: V) { 255 | let field_int = if self.field.is_some() { 256 | get_unique_int_str(&self.field.take().unwrap()) 257 | } else if self.len.is_some() { 258 | get_len_field_int(&get_unique_int_str(&self.len.take().unwrap())) 259 | } else { 260 | unreachable!() 261 | }; 262 | 263 | self.conditions 264 | .entry(field_int.clone()) 265 | .or_insert_with(Vec::new) 266 | .push(Comparision::new(field_int, cmp, to_value(value))); 267 | } 268 | } 269 | 270 | impl<'a, T: Structure> fmt::Debug for Query<'a, T> { 271 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 272 | write!(f, 273 | "{{ item: {:?}, id: {:?}, limit: {:?}, field: {:?}, conditions: {:?}, orders: {:?} \ 274 | }}", 275 | self.item, 276 | self.id, 277 | self.limit, 278 | self.field, 279 | self.conditions, 280 | self.orders) 281 | } 282 | } 283 | 284 | 285 | #[inline] 286 | fn check_query(query: &Query) -> Result<(), Error> { 287 | match query.action { 288 | Action::Replace => check_replace_query(query), 289 | _ => Ok(()), 290 | } 291 | } 292 | 293 | #[inline] 294 | fn check_replace_query(query: &Query) -> Result<(), Error> { 295 | if !T::has_id() { 296 | return Err(Error::CanNotReplace); 297 | } 298 | 299 | if query.item.as_ref().unwrap().get_id().is_empty() && query.id.is_none() { 300 | return Err(Error::RequiresId); 301 | } 302 | 303 | Ok(()) 304 | } 305 | -------------------------------------------------------------------------------- /arthas/tests/encoder.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(all(feature = "unstable", test), feature(test))] 2 | 3 | #[macro_use] 4 | extern crate serde_derive; 5 | #[macro_use] 6 | extern crate arthas_derive; 7 | extern crate rand; 8 | extern crate arthas; 9 | #[macro_use] 10 | extern crate maplit; 11 | extern crate env_logger; 12 | extern crate serde_json; 13 | 14 | pub mod model; 15 | pub mod common; 16 | 17 | use std::collections::HashMap; 18 | use arthas::to_value; 19 | use arthas::encoder::{encode, decode}; 20 | use arthas::traits::get_unique_int_str; 21 | use common::revert; 22 | use model::*; 23 | 24 | 25 | #[test] 26 | fn test_atomic() { 27 | let string_one = "This is string one".to_owned(); 28 | let string_two = "This is string two".to_owned(); 29 | 30 | let decoded = to_value(Atomic { 31 | string_one: string_one.clone(), 32 | string_two: string_two.clone(), 33 | hash_map: HashMap::new(), 34 | }); 35 | 36 | let encoded = to_value(hashmap!{ 37 | get_unique_int_str("string_one") => to_value(string_one.clone()), 38 | get_unique_int_str("string_two") => to_value(string_two.clone()), 39 | get_unique_int_str("hash_map") => to_value(HashMap::::new()) 40 | }); 41 | 42 | assert_eq!(encode(&decoded, &Atomic::get_field_int_map()), encoded); 43 | assert_eq!(decode(&encoded, &revert(Atomic::get_field_int_map())), 44 | decoded); 45 | } 46 | 47 | #[test] 48 | fn test_vec() { 49 | let title = "This is title".to_owned(); 50 | let content = "This is content".to_owned(); 51 | let comment_title = "This is comment title".to_owned(); 52 | let comment_content = "This is comment content".to_owned(); 53 | 54 | let decoded = to_value(Article { 55 | _id: String::new(), 56 | title: title.clone(), 57 | content: content.clone(), 58 | day_to_views: HashMap::new(), 59 | views: 0, 60 | comments: vec![Comment { 61 | title: comment_title.clone(), 62 | content: comment_content.clone(), 63 | }], 64 | }); 65 | 66 | let encoded = to_value(hashmap!{ 67 | get_unique_int_str("_id") => to_value(""), 68 | get_unique_int_str("title") => to_value(title.clone()), 69 | get_unique_int_str("content") => to_value(content.clone()), 70 | get_unique_int_str("day_to_views") => to_value(HashMap::::new()), 71 | get_unique_int_str("views") => to_value(0), 72 | get_unique_int_str("comments.[].title") => to_value(vec![comment_title.clone()]), 73 | get_unique_int_str("comments.[].content") => to_value(vec![comment_content.clone()]) 74 | }); 75 | 76 | assert_eq!(encode(&decoded, &Article::get_field_int_map()), encoded); 77 | assert_eq!(decode(&encoded, &revert(Article::get_field_int_map())), 78 | decoded); 79 | } 80 | 81 | #[test] 82 | fn test_hashmap() { 83 | let day_26 = "2016-10-26".to_owned(); 84 | let day_27 = "2016-10-27".to_owned(); 85 | let title_26 = "This is day 26 title".to_owned(); 86 | let title_27 = "This is day 27 title".to_owned(); 87 | let content_26 = "This is day 26 content".to_owned(); 88 | let content_27 = "This is day 27 content".to_owned(); 89 | 90 | let decoded = to_value(Comments { 91 | day_to_comments: hashmap!{ 92 | day_26.clone() => Comment { 93 | title: title_26.clone(), 94 | content: content_26.clone() 95 | }, 96 | day_27.clone() => Comment { 97 | title: title_27.clone(), 98 | content: content_27.clone() 99 | } 100 | }, 101 | }); 102 | 103 | let encoded = to_value(hashmap!{ 104 | get_unique_int_str("day_to_comments.{}.title") => to_value(hashmap!{ 105 | day_26.clone() => title_26.clone(), 106 | day_27.clone() => title_27.clone() 107 | }), 108 | get_unique_int_str("day_to_comments.{}.content") => to_value(hashmap!{ 109 | day_26.clone() => content_26.clone(), 110 | day_27.clone() => content_27.clone() 111 | }) 112 | }); 113 | 114 | assert_eq!(encode(&decoded, &Comments::get_field_int_map()), encoded); 115 | assert_eq!(decode(&encoded, &revert(Comments::get_field_int_map())), 116 | decoded); 117 | } 118 | 119 | #[test] 120 | fn test_blog() { 121 | let comment_title = "This is comment title".to_owned(); 122 | let comment_content = "This is comment content".to_owned(); 123 | let day_26 = "2016-10-26".to_owned(); 124 | let day_27 = "2016-10-27".to_owned(); 125 | let title_26 = "This is day 26 title".to_owned(); 126 | let title_27 = "This is day 27 title".to_owned(); 127 | let content_26 = "This is day 26 content".to_owned(); 128 | let content_27 = "This is day 27 content".to_owned(); 129 | let comment_title_26 = "This is day 26 comment title".to_owned(); 130 | let comment_title_27 = "This is day 27 comment title".to_owned(); 131 | let comment_content_26 = "This is day 26 comment content".to_owned(); 132 | let comment_content_27 = "This is day 27 comment content".to_owned(); 133 | 134 | let decoded = to_value(Blog { 135 | articles: Articles { 136 | day_to_articles: hashmap!{ 137 | day_26.clone() => Article { 138 | _id: String::new(), 139 | title: title_26.clone(), 140 | content: content_26.clone(), 141 | day_to_views: HashMap::new(), 142 | views: 0, 143 | comments: vec![Comment { 144 | title: comment_title.clone(), 145 | content: comment_content.clone() 146 | }] 147 | }, 148 | day_27.clone() => Article { 149 | _id: String::new(), 150 | title: title_27.clone(), 151 | content: content_27.clone(), 152 | day_to_views: HashMap::new(), 153 | views: 0, 154 | comments: vec![Comment { 155 | title: comment_title.clone(), 156 | content: comment_content.clone() 157 | }] 158 | } 159 | }, 160 | }, 161 | comments: Comments { 162 | day_to_comments: hashmap!{ 163 | day_26.clone() => Comment { 164 | title: comment_title_26.clone(), 165 | content: comment_content_26.clone() 166 | }, 167 | day_27.clone() => Comment { 168 | title: comment_title_27.clone(), 169 | content: comment_content_27.clone() 170 | } 171 | }, 172 | }, 173 | }); 174 | 175 | let encoded = to_value(hashmap!{ 176 | get_unique_int_str("articles.day_to_articles.{}._id") => to_value(hashmap!{ 177 | day_26.clone() => String::new(), 178 | day_27.clone() => String::new() 179 | }), 180 | get_unique_int_str("articles.day_to_articles.{}.title") => to_value(hashmap!{ 181 | day_26.clone() => title_26.clone(), 182 | day_27.clone() => title_27.clone() 183 | }), 184 | get_unique_int_str("articles.day_to_articles.{}.content") => to_value(hashmap!{ 185 | day_26.clone() => content_26.clone(), 186 | day_27.clone() => content_27.clone() 187 | }), 188 | get_unique_int_str("articles.day_to_articles.{}.day_to_views") => to_value(hashmap!{ 189 | day_26.clone() => HashMap::::new(), 190 | day_27.clone() => HashMap::::new() 191 | }), 192 | get_unique_int_str("articles.day_to_articles.{}.views") => to_value(hashmap!{ 193 | day_26.clone() => 0, 194 | day_27.clone() => 0 195 | }), 196 | get_unique_int_str("articles.day_to_articles.{}.comments.[].title") => to_value(hashmap!{ 197 | day_26.clone() => vec![comment_title.clone()], 198 | day_27.clone() => vec![comment_title.clone()] 199 | }), 200 | get_unique_int_str("articles.day_to_articles.{}.comments.[].content") => to_value(hashmap!{ 201 | day_26.clone() => vec![comment_content.clone()], 202 | day_27.clone() => vec![comment_content.clone()] 203 | }), 204 | get_unique_int_str("comments.day_to_comments.{}.title") =>to_value(hashmap!{ 205 | day_26.clone() => comment_title_26.clone(), 206 | day_27.clone() => comment_title_27.clone() 207 | }), 208 | get_unique_int_str("comments.day_to_comments.{}.content") =>to_value(hashmap!{ 209 | day_26.clone() => comment_content_26.clone(), 210 | day_27.clone() => comment_content_27.clone() 211 | }) 212 | }); 213 | 214 | assert_eq!(encode(&decoded, &Blog::get_field_int_map()), encoded); 215 | assert_eq!(decode(&encoded, &revert(Blog::get_field_int_map())), 216 | decoded); 217 | } 218 | 219 | 220 | #[cfg(all(feature = "unstable", test))] 221 | mod benches { 222 | extern crate test; 223 | use arthas::to_value; 224 | use arthas::traits::get_unique_int_str; 225 | use arthas::encoder::{encode, decode}; 226 | use model::*; 227 | use std::collections::HashMap; 228 | use common::revert; 229 | 230 | 231 | #[bench] 232 | fn bench_encode(b: &mut test::Bencher) { 233 | let title = "This is title".to_owned(); 234 | let content = "This is content".to_owned(); 235 | let comment_title = "This is comment title".to_owned(); 236 | let comment_content = "This is comment content".to_owned(); 237 | let field_int_map = Article::get_field_int_map(); 238 | 239 | let value = to_value(Article { 240 | _id: String::new(), 241 | title: title.clone(), 242 | content: content.clone(), 243 | day_to_views: HashMap::new(), 244 | views: 0, 245 | comments: vec![Comment { 246 | title: comment_title.clone(), 247 | content: comment_content.clone(), 248 | }], 249 | }); 250 | 251 | b.iter(|| encode(&value, &field_int_map)) 252 | } 253 | 254 | #[bench] 255 | fn bench_decode(b: &mut test::Bencher) { 256 | let title = "This is title".to_owned(); 257 | let content = "This is content".to_owned(); 258 | let comment_title = "This is comment title".to_owned(); 259 | let comment_content = "This is comment content".to_owned(); 260 | let int_field_map = revert(Article::get_field_int_map()); 261 | 262 | let value = to_value(hashmap!{ 263 | get_unique_int_str("_id") => to_value(""), 264 | get_unique_int_str("title") => to_value(title.clone()), 265 | get_unique_int_str("content") => to_value(content.clone()), 266 | get_unique_int_str("day_to_views") => to_value(HashMap::::new()), 267 | get_unique_int_str("views") => to_value(0), 268 | get_unique_int_str("comments.[].title") => to_value(vec![comment_title.clone()]), 269 | get_unique_int_str("comments.[].content") => to_value(vec![comment_content.clone()]) 270 | }); 271 | 272 | b.iter(|| decode(&value, &int_field_map)) 273 | } 274 | } 275 | -------------------------------------------------------------------------------- /arthas/src/tree/searcher/executor/mod.rs: -------------------------------------------------------------------------------- 1 | 2 | use std::cmp::Ordering; 3 | use std::sync::Mutex; 4 | use std::sync::atomic::AtomicBool; 5 | use std::collections::HashMap; 6 | use super::task::Task; 7 | use error::Error; 8 | use super::Tree; 9 | use super::super::rc::RcChild; 10 | use item::FieldInt; 11 | use serde_json::Value; 12 | use query::QueryType; 13 | use super::super::node::{Group, Groups}; 14 | use quickersort::sort_by; 15 | use super::super::math::Math; 16 | use super::task::{Sub, Orders}; 17 | use scoped_pool::Pool; 18 | use super::entrance_type::EntranceType; 19 | 20 | 21 | pub struct Exectuor {} 22 | 23 | impl Exectuor { 24 | pub fn exec(pool: &Pool, 25 | tree: &Tree, 26 | mut task: Task) 27 | -> Result<(usize, Vec<*const Value>), Error> { 28 | if tree.id_map.is_empty() { 29 | thread_trace!("tree is empty"); 30 | return Ok(Default::default()); 31 | } 32 | 33 | let field_groups = Mutex::new(HashMap::new()); 34 | let field_sub = Mutex::new(HashMap::new()); 35 | let stopped = AtomicBool::new(false); 36 | 37 | pool.scoped(|scope| { 38 | let field_groups = &field_groups; 39 | let field_sub = &field_sub; 40 | let stopped = &stopped; 41 | 42 | for mut sub in task.subs.drain(..) { 43 | let entrance_type = EntranceType::new(tree, 44 | &sub.field_int, 45 | &sub.comparisions.first().unwrap().other); 46 | 47 | match entrance_type { 48 | EntranceType::Root => { 49 | scope.execute(move || { 50 | let mut groups = Groups::new(); 51 | let rc_node = tree.root 52 | .get(&sub.field_int) 53 | .unwrap(); 54 | thread_trace!("search root, root is {:?}", 55 | rc_node.read().unwrap().get_value()); 56 | 57 | rc_node.read() 58 | .unwrap() 59 | .search_root(stopped, &mut groups, &mut sub); 60 | 61 | field_groups.lock().unwrap().insert(sub.field_int.clone(), groups); 62 | field_sub.lock().unwrap().insert(sub.field_int.clone(), sub); 63 | }); 64 | } 65 | EntranceType::Min => { 66 | scope.execute(move || { 67 | let mut groups = Groups::new(); 68 | let rc_node = tree.min 69 | .get(&sub.field_int) 70 | .unwrap(); 71 | 72 | thread_trace!("search min, min is {:?}", 73 | rc_node.read().unwrap().get_value()); 74 | 75 | rc_node.read() 76 | .unwrap() 77 | .search_min(stopped, &mut groups, &mut sub); 78 | 79 | field_groups.lock().unwrap().insert(sub.field_int.clone(), groups); 80 | field_sub.lock().unwrap().insert(sub.field_int.clone(), sub); 81 | }) 82 | } 83 | EntranceType::Max => { 84 | scope.execute(move || { 85 | let mut groups = Groups::new(); 86 | let rc_node = tree.max 87 | .get(&sub.field_int) 88 | .unwrap(); 89 | 90 | thread_trace!("search max, max is {:?}", 91 | rc_node.read().unwrap().get_value()); 92 | 93 | rc_node.read() 94 | .unwrap() 95 | .search_max(stopped, &mut groups, &mut sub); 96 | 97 | field_groups.lock().unwrap().insert(sub.field_int.clone(), groups); 98 | field_sub.lock().unwrap().insert(sub.field_int.clone(), sub); 99 | }) 100 | } 101 | EntranceType::None => { 102 | thread_trace!("no root found!"); 103 | } 104 | } 105 | } 106 | }); 107 | 108 | let mut field_groups = field_groups.into_inner().unwrap(); 109 | let mut field_sub = field_sub.into_inner().unwrap(); 110 | let need_sort = task.has_order(); 111 | let stopped_field = get_stopped_field(&field_sub, &task); 112 | 113 | thread_trace!("stopped field: {:?}", stopped_field); 114 | 115 | if field_groups.contains_key(&stopped_field) { 116 | field_sub.remove(&stopped_field); 117 | let groups = field_groups.remove(&stopped_field).unwrap(); 118 | 119 | thread_trace!("wait for filter, groups len: {:?}", groups.len()); 120 | 121 | if need_sort { 122 | let mut children = groups_to_children(groups); 123 | thread_trace!("children: {:?}", children); 124 | sort_children(&mut children[..], &task.orders); 125 | thread_trace!("sorted children: {:?}", children); 126 | Ok(filter_children(children, &task, &field_sub)) 127 | } else { 128 | Ok(filter_groups(groups, &task, &field_sub)) 129 | } 130 | } else { 131 | unreachable!() 132 | } 133 | } 134 | } 135 | 136 | #[inline] 137 | fn filter_groups(groups: Groups, 138 | task: &Task, 139 | field_sub: &HashMap) 140 | -> (usize, Vec<*const Value>) { 141 | let mut found = 0; 142 | let mut count = 0; 143 | let mut values = Vec::new(); 144 | let other_conditions_exists = !field_sub.is_empty(); 145 | let is_count = task.query_type == QueryType::Count; 146 | 147 | 'outer: for group in groups { 148 | thread_trace!("filter groups, current group: {:?}", 149 | &*group.read().unwrap()); 150 | 151 | if other_conditions_exists { 152 | thread_trace!("other conditions exists"); 153 | for rc_child in group.read().unwrap().values() { 154 | if filter_child(rc_child, 155 | &mut found, 156 | &mut count, 157 | &mut values, 158 | task, 159 | field_sub) { 160 | break 'outer; 161 | } 162 | } 163 | } else if is_count { 164 | thread_trace!("only count"); 165 | count += group.read().unwrap().len(); 166 | found = count; 167 | } else { 168 | thread_trace!("no other conditions exists"); 169 | if collect_child(&mut found, &mut count, task, &group, &mut values) { 170 | break; 171 | } 172 | } 173 | } 174 | 175 | if is_count { 176 | if count > task.offset { 177 | count -= task.offset; 178 | } else { 179 | count = 0; 180 | } 181 | } 182 | 183 | (count, values) 184 | } 185 | 186 | #[inline] 187 | fn collect_child(found: &mut usize, 188 | count: &mut usize, 189 | task: &Task, 190 | group: &Group, 191 | values: &mut Vec<*const Value>) 192 | -> bool { 193 | for rc_child in group.read().unwrap().values() { 194 | *found += 1; 195 | 196 | if *found > task.offset { 197 | *count += 1; 198 | values.push(rc_child.read().unwrap().get_item_pointer()); 199 | 200 | if task.limit.is_some() && *count >= *task.limit.as_ref().unwrap() { 201 | return true; 202 | } 203 | } 204 | } 205 | 206 | false 207 | } 208 | 209 | #[inline] 210 | fn filter_children(children: Vec, 211 | task: &Task, 212 | field_sub: &HashMap) 213 | -> (usize, Vec<*const Value>) { 214 | let mut found = 0; 215 | let mut count = 0; 216 | let mut values = Vec::new(); 217 | 218 | for rc_child in children { 219 | if filter_child(&rc_child, 220 | &mut found, 221 | &mut count, 222 | &mut values, 223 | task, 224 | field_sub) { 225 | break; 226 | } 227 | } 228 | 229 | (count, values) 230 | } 231 | 232 | #[inline] 233 | fn filter_child(rc_child: &RcChild, 234 | found: &mut usize, 235 | count: &mut usize, 236 | values: &mut Vec<*const Value>, 237 | task: &Task, 238 | field_sub: &HashMap) 239 | -> bool { 240 | let mut pass = true; 241 | 242 | for sub in field_sub.values() { 243 | if !sub._match(&rc_child) { 244 | thread_trace!("not match, left: {:?}, right: {:?}", 245 | rc_child, 246 | sub.comparisions); 247 | 248 | pass = false; 249 | break; 250 | } 251 | } 252 | 253 | if pass { 254 | thread_trace!("filter child pass, take: {:?}", 255 | rc_child.read().unwrap().get_value()); 256 | 257 | *found += 1; 258 | 259 | if *found > task.offset { 260 | *count += 1; 261 | values.push(rc_child.read().unwrap().get_item_pointer()); 262 | } 263 | 264 | if task.limit.is_some() && *count >= *task.limit.as_ref().unwrap() { 265 | return true; 266 | } 267 | } 268 | 269 | false 270 | } 271 | 272 | #[inline] 273 | fn sort_children(children: &mut [RcChild], orders: &Orders) { 274 | sort_by(children, 275 | &|a, b| { 276 | let a_rc_item = a.read().unwrap(); 277 | let a_item = a_rc_item.item.read().unwrap(); 278 | 279 | let b_rc_item = b.read().unwrap(); 280 | let b_item = b_rc_item.item.read().unwrap(); 281 | 282 | let mut ordering = Ordering::Equal; 283 | 284 | for &(ref field, ref order) in orders { 285 | let a_rc_data = &a_item.datas[field]; 286 | let a_data = a_rc_data.read().unwrap(); 287 | let a_value = a_data.get_value(); 288 | 289 | 290 | let b_rc_data = &b_item.datas[field]; 291 | let b_data = b_rc_data.read().unwrap(); 292 | let b_value = b_data.get_value(); 293 | 294 | ordering = a_value.cmp(b_value, order); 295 | 296 | if ordering != Ordering::Equal { 297 | break; 298 | } 299 | } 300 | 301 | ordering 302 | }); 303 | } 304 | 305 | #[inline] 306 | fn groups_to_children(groups: Vec) -> Vec { 307 | let mut children = Vec::new(); 308 | for group in groups { 309 | for rc_child in group.read().unwrap().values() { 310 | children.push(rc_child.clone()); 311 | } 312 | } 313 | children 314 | } 315 | 316 | #[inline] 317 | fn get_stopped_field(field_sub: &HashMap, task: &Task) -> String { 318 | if task.has_order() && field_sub.contains_key(task.get_order_field()) && 319 | field_sub.get(task.get_order_field()).unwrap().stopped { 320 | return task.get_order_field().to_owned(); 321 | } 322 | 323 | for (field, sub) in field_sub { 324 | if sub.stopped { 325 | return field.to_owned(); 326 | } 327 | } 328 | 329 | unreachable!() 330 | } 331 | -------------------------------------------------------------------------------- /arthas/src/loader/mod.rs: -------------------------------------------------------------------------------- 1 | 2 | use std::io::prelude::*; 3 | use std::str::from_utf8; 4 | use std::str; 5 | use std::sync::{RwLock, RwLockWriteGuard}; 6 | use std::io::BufReader; 7 | use std::io::BufRead; 8 | use std::fs::{self, File}; 9 | use memmap::{Mmap, Protection}; 10 | use serde_json::{self, Value}; 11 | use to_value; 12 | use persistence::operation::Operation; 13 | use traits::{FieldIntMap, RenameMap}; 14 | use encoder::{bin_encode, bin_decode}; 15 | use traits::get_unique_int_str; 16 | use {utils, encoder}; 17 | use memory::Memory; 18 | use traits::Structure; 19 | use persistence::Persistence; 20 | use config; 21 | use utils::file::{get_log_path, get_data_path, get_persistence_path, get_saving_path}; 22 | use persistence::meta::SimpleMeta; 23 | use BINENCODE; 24 | use store::{is_persistence, persistences, memories, config}; 25 | 26 | 27 | pub fn load() { 28 | let struct_name = T::get_struct_name(); 29 | 30 | fix_persistence_name(&struct_name); 31 | check_log_and_persistence(&struct_name); 32 | 33 | if utils::file::exists(get_log_path(&struct_name)) { 34 | write_log(&struct_name); 35 | } 36 | 37 | let field_int_map = T::get_field_int_map(); 38 | let rename_map = T::get_rename_map(); 39 | let persistence_store_lock = persistences(); 40 | let mut persistence_store = persistence_store_lock.write().unwrap(); 41 | let mut persistence = 42 | persistence_store.entry(struct_name.clone()) 43 | .or_insert_with(|| { 44 | RwLock::new(Persistence::new(struct_name.clone(), field_int_map.clone())) 45 | }) 46 | .write() 47 | .unwrap(); 48 | 49 | let memory_store_lock = memories(); 50 | let mut memory_store = memory_store_lock.write().unwrap(); 51 | let memory = memory_store.entry(struct_name.clone()) 52 | .or_insert_with(|| RwLock::new(Memory::new::())) 53 | .write() 54 | .unwrap(); 55 | 56 | let persistence_option = load_persistence(&struct_name, 57 | &field_int_map, 58 | &rename_map, 59 | &to_value(T::new_deep_empty())); 60 | 61 | if persistence_option.is_some() { 62 | *persistence = persistence_option.unwrap(); 63 | load_data(memory, &persistence, &struct_name, &T::get_field_int_map()); 64 | } else { 65 | create_persistence(&struct_name, &field_int_map); 66 | } 67 | 68 | config(); 69 | } 70 | 71 | pub fn persistence_exits(struct_name: &str) -> bool { 72 | get_persistence_path(struct_name).is_file() 73 | } 74 | 75 | pub fn create_persistence(struct_name: &str, field_int_map: &FieldIntMap) { 76 | save_persistence(Persistence::new(struct_name.to_owned(), field_int_map.clone())); 77 | fix_persistence_name(struct_name); 78 | } 79 | 80 | pub fn load_persistence(struct_name: &str, 81 | field_int_map: &FieldIntMap, 82 | rename_map: &RenameMap, 83 | empty_value: &Value) 84 | -> Option { 85 | let persistence_path = get_persistence_path(struct_name); 86 | if !utils::file::exists(&persistence_path) { 87 | return None; 88 | } 89 | 90 | let persistence_option = read_persistence(struct_name); 91 | if persistence_option.is_none() { 92 | return None; 93 | } 94 | 95 | let mut persistence = persistence_option.unwrap(); 96 | 97 | if to_value(&persistence.field_int_map).to_string() != to_value(field_int_map).to_string() { 98 | update_schema(&persistence, 99 | struct_name, 100 | field_int_map, 101 | rename_map, 102 | empty_value); 103 | persistence = read_persistence(struct_name).unwrap(); 104 | } 105 | 106 | Some(persistence) 107 | 108 | 109 | } 110 | 111 | fn read_persistence(struct_name: &str) -> Option { 112 | let file = utils::file::open_index_with_read(struct_name); 113 | let mut buf = Vec::new(); 114 | 115 | if file.is_some() { 116 | file.unwrap().read_to_end(&mut buf).unwrap(); 117 | } 118 | 119 | if buf.is_empty() { 120 | None 121 | } else { 122 | match serde_json::from_str::(&if BINENCODE { 123 | bin_decode(&buf) 124 | } else { 125 | from_utf8(&buf).unwrap().to_owned() 126 | }) { 127 | Ok(persistence) => Some(persistence), 128 | Err(err) => panic!("Invalid persistence index: {:?}", err), 129 | } 130 | } 131 | } 132 | 133 | pub fn load_data(mut memory: RwLockWriteGuard, 134 | persistence: &Persistence, 135 | struct_name: &str, 136 | field_int_map: &FieldIntMap) { 137 | let path = get_data_path(struct_name); 138 | let enable_backup = is_persistence(); 139 | config::persistence(false); 140 | 141 | if utils::file::exists(&path) { 142 | let file = utils::file::open_data_with_read(struct_name); 143 | if to_value(&persistence.field_int_map).to_string() != to_value(field_int_map).to_string() { 144 | panic!("Incompatible schema!"); 145 | } 146 | 147 | for (id, meta) in &persistence.metas { 148 | let mmap = Mmap::open_with_offset(&file, Protection::Read, meta.offset(), meta.real()) 149 | .unwrap(); 150 | 151 | let bytes: &[u8] = unsafe { mmap.as_slice() }; 152 | let value = serde_json::from_str::(&if BINENCODE { 153 | bin_decode(bytes) 154 | } else { 155 | from_utf8(bytes).unwrap().to_owned() 156 | }) 157 | .unwrap(); 158 | 159 | memory.insert_encoded_value(id.to_owned(), value).unwrap(); 160 | } 161 | } 162 | 163 | config::persistence(enable_backup); 164 | } 165 | 166 | 167 | fn update_schema(persistence: &Persistence, 168 | struct_name: &str, 169 | field_int_map: &FieldIntMap, 170 | rename_map: &RenameMap, 171 | empty_value: &Value) { 172 | let old_data_path = get_data_path(struct_name); 173 | let old_data_index_path = get_persistence_path(struct_name); 174 | let backup_data_path = format!("{}.backup", old_data_path.display()); 175 | let backup_data_index_path = format!("{}.backup", old_data_index_path.display()); 176 | fs::rename(&old_data_path, &backup_data_path).unwrap(); 177 | fs::rename(&old_data_index_path, &backup_data_index_path).unwrap(); 178 | 179 | let old_file = utils::file::open_with_read(backup_data_path); 180 | let mut new_persistence = Persistence::new(struct_name.to_owned(), field_int_map.clone()); 181 | 182 | for meta in persistence.metas.values() { 183 | let mmap = Mmap::open_with_offset(&old_file, Protection::Read, meta.offset(), meta.real()) 184 | .unwrap(); 185 | let bytes: &[u8] = unsafe { mmap.as_slice() }; 186 | let mut value = serde_json::from_str::(&if BINENCODE { 187 | bin_decode(bytes) 188 | } else { 189 | from_utf8(bytes).unwrap().to_owned() 190 | }) 191 | .unwrap(); 192 | 193 | fix_value(&mut value, rename_map, empty_value, field_int_map); 194 | 195 | new_persistence.insert(Operation::new() 196 | .value(value) 197 | .insert()); 198 | } 199 | } 200 | 201 | fn fix_value(value: &mut Value, 202 | rename_map: &RenameMap, 203 | empty_value: &Value, 204 | field_int_map: &FieldIntMap) { 205 | let integer_map = utils::hash_map::revert(field_int_map.clone()); 206 | let object = value.as_object_mut().unwrap().get_mut("item").unwrap().as_object_mut().unwrap(); 207 | let empty_value = encoder::encode(empty_value, field_int_map); 208 | let empty_object = empty_value.as_object().unwrap(); 209 | let integers = object.keys().map(|v| v.to_owned()).collect::>(); 210 | let new_integers = integer_map.keys().collect::>(); 211 | 212 | for (from, to) in rename_map { 213 | let from_integer = get_unique_int_str(from); 214 | let to_integer = get_unique_int_str(to); 215 | let remove_value = object.remove(&from_integer); 216 | 217 | if remove_value.is_some() { 218 | object.insert(to_integer, remove_value.unwrap()); 219 | } 220 | } 221 | 222 | for integer in integers { 223 | if !integer_map.contains_key(&integer) { 224 | object.remove(&integer); 225 | } 226 | } 227 | 228 | for integer in new_integers { 229 | if !object.contains_key(integer) { 230 | object.insert(integer.to_owned(), 231 | empty_object.get(integer).cloned().unwrap()); 232 | } 233 | } 234 | } 235 | 236 | fn fix_persistence_name(struct_name: &str) { 237 | let persistence_path = get_persistence_path(struct_name); 238 | let saving_path = get_saving_path(struct_name); 239 | if utils::file::exists(&persistence_path) && utils::file::exists(&saving_path) { 240 | fs::remove_file(saving_path).unwrap(); 241 | } else if utils::file::exists(&saving_path) { 242 | fs::rename(saving_path, persistence_path).unwrap(); 243 | } 244 | } 245 | 246 | fn check_log_and_persistence(struct_name: &str) { 247 | if utils::file::exists(get_log_path(struct_name)) && 248 | !utils::file::exists(get_persistence_path(struct_name)) { 249 | panic!("log exists but index not found!"); 250 | } 251 | } 252 | 253 | fn fix_file_length(struct_name: &str, size: usize) { 254 | utils::file::open_data_or_create(struct_name).set_len(size as u64).unwrap(); 255 | } 256 | 257 | fn write_log(struct_name: &str) { 258 | let mut persistence = read_persistence(struct_name).unwrap(); 259 | fix_file_length(struct_name, persistence.size); 260 | 261 | let log_file = utils::file::open_log_file(struct_name); 262 | let file = BufReader::new(&log_file); 263 | let mut append_file = utils::file::open_data_with_append(struct_name); 264 | let mmap_file = utils::file::open_data_or_create(struct_name); 265 | 266 | for line_result in file.lines() { 267 | let line = line_result.unwrap(); 268 | let info = persistence.write_log(line); 269 | if info.is_some() { 270 | let (append, meta, bytes) = info.unwrap(); 271 | save_bytes(&mut append_file, &mmap_file, append, meta, bytes); 272 | } 273 | } 274 | 275 | save_persistence(persistence); 276 | remove_old_persistence(struct_name); 277 | fix_persistence_name(struct_name); 278 | remove_log_file(struct_name); 279 | } 280 | 281 | fn remove_log_file(struct_name: &str) { 282 | fs::remove_file(get_log_path(struct_name)).unwrap(); 283 | } 284 | 285 | fn save_persistence(persistence: Persistence) { 286 | utils::file::open_with_write(get_saving_path(&persistence.struct_name)) 287 | .write_all(&if BINENCODE { 288 | bin_encode(to_value(persistence).to_string()) 289 | } else { 290 | to_value(persistence).to_string().as_bytes().to_owned() 291 | }) 292 | .unwrap(); 293 | } 294 | 295 | fn remove_old_persistence(struct_name: &str) { 296 | fs::remove_file(get_persistence_path(struct_name)).unwrap(); 297 | } 298 | 299 | fn save_bytes(append_file: &mut File, 300 | mmap_file: &File, 301 | append: bool, 302 | meta: SimpleMeta, 303 | data: Vec) { 304 | if append { 305 | append_file.write_all(&data).unwrap(); 306 | } else { 307 | let mut mmap = 308 | Mmap::open_with_offset(mmap_file, Protection::ReadWrite, meta.offset(), meta.real()) 309 | .unwrap(); 310 | { 311 | let old_bytes: &mut [u8] = unsafe { mmap.as_mut_slice() }; 312 | for (index, byte) in old_bytes.iter_mut().enumerate() { 313 | *byte = data[index]; 314 | } 315 | } 316 | } 317 | } 318 | -------------------------------------------------------------------------------- /arthas_derive/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Macros 1.1 implementation of #[derive(Arthas)] 2 | //! 3 | //! See [Arthas](https://github.com/fengcen/arthas) for more information. 4 | //! 5 | #![recursion_limit = "1000"] 6 | 7 | extern crate proc_macro; 8 | extern crate syn; 9 | #[macro_use] 10 | extern crate quote; 11 | extern crate regex; 12 | 13 | use proc_macro::TokenStream; 14 | use syn::DeriveInput; 15 | use syn::Ident; 16 | use syn::Field; 17 | use quote::ToTokens; 18 | use regex::Regex; 19 | 20 | 21 | #[proc_macro_derive(Arthas, attributes(arthas))] 22 | #[doc(hidden)] 23 | pub fn arthas(input: TokenStream) -> TokenStream { 24 | let s = input.to_string(); 25 | let ast = syn::parse_macro_input(&s).unwrap(); 26 | let gen = impl_arthas(&ast); 27 | gen.parse().unwrap() 28 | } 29 | 30 | fn impl_arthas(ast: &DeriveInput) -> quote::Tokens { 31 | check_is_struct(ast); 32 | 33 | let name = &ast.ident; 34 | let name_string = name.to_string(); 35 | let is_one = check_is_one(ast); 36 | let has_id = check_has_id(ast); 37 | 38 | let set_id_block = if has_id { 39 | quote! {self._id = id;} 40 | } else { 41 | quote! {{}} 42 | }; 43 | 44 | let get_id_expr = if has_id { 45 | quote! {return self._id.clone();} 46 | } else { 47 | quote! {return String::new();} 48 | }; 49 | 50 | let field_int_map_block = generate_field_int_map_block(ast); 51 | let deep_struct = generate_deep_struct(ast); 52 | let rename_map_block = generate_rename_map_block(ast); 53 | 54 | let set_id_ident = if has_id { 55 | quote! {id} 56 | } else { 57 | quote! {_} 58 | }; 59 | 60 | quote! { 61 | impl ::arthas::traits::Arthas for #name { 62 | fn get_struct_name() -> String { 63 | #name_string.to_owned() 64 | } 65 | 66 | fn session<'a>() -> ::arthas::Query<'a, Self> { 67 | ::arthas::Query::new() 68 | } 69 | 70 | fn is_one() -> bool { 71 | #is_one 72 | } 73 | 74 | fn new_empty() -> Self { 75 | #name { 76 | ..Default::default() 77 | } 78 | } 79 | 80 | fn new_deep_empty() -> Self { 81 | #deep_struct 82 | } 83 | 84 | fn has_id() -> bool { 85 | #has_id 86 | } 87 | 88 | fn set_id(&mut self, #set_id_ident: String) { 89 | #set_id_block 90 | } 91 | 92 | fn get_id(&self) -> String { 93 | #get_id_expr 94 | } 95 | 96 | fn get_field_type_map() -> ::arthas::traits::FieldTypeMap { 97 | #field_int_map_block 98 | } 99 | 100 | fn get_rename_map() -> ::std::collections::HashMap { 101 | #rename_map_block 102 | } 103 | 104 | fn get_field_int_map() -> ::arthas::traits::FieldIntMap { 105 | let mut field_int_map = ::std::collections::HashMap::new(); 106 | let field_type_map = Self::get_field_type_map(); 107 | let mut paths = Vec::new(); 108 | scan_inner_type(&mut field_int_map, &field_type_map, &mut paths); 109 | return field_int_map; 110 | 111 | fn scan_inner_type(field_int_map: &mut ::arthas::traits::FieldIntMap, field_type_map: &::arthas::traits::FieldTypeMap, paths: &mut Vec) { 112 | for (field, field_type) in field_type_map { 113 | match *field_type { 114 | ::arthas::traits::FieldType::Atomic(_) => { 115 | paths.push(field.to_owned().to_owned()); 116 | let path = join(paths, "."); 117 | field_int_map.insert(path.clone(), ::arthas::traits::get_unique_int_str(&path)); 118 | paths.pop(); 119 | }, 120 | ::arthas::traits::FieldType::Array(ref type_map) => { 121 | paths.push(field.to_owned().to_owned()); 122 | paths.push("[]".to_owned()); 123 | scan_inner_type(field_int_map, type_map, paths); 124 | paths.pop(); 125 | paths.pop(); 126 | }, 127 | ::arthas::traits::FieldType::Object(ref type_map) => { 128 | paths.push(field.to_owned().to_owned()); 129 | paths.push("{}".to_owned()); 130 | scan_inner_type(field_int_map, type_map, paths); 131 | paths.pop(); 132 | paths.pop(); 133 | }, 134 | ::arthas::traits::FieldType::Struct(ref type_map) => { 135 | paths.push(field.to_owned().to_owned()); 136 | scan_inner_type(field_int_map, type_map, paths); 137 | paths.pop(); 138 | } 139 | } 140 | } 141 | } 142 | 143 | fn join, I: AsRef>(vec: &[T], separator: I) -> String { 144 | let mut buffer = String::new(); 145 | for (count, item) in vec.iter().enumerate() { 146 | if count == 0 { 147 | buffer += item.as_ref(); 148 | } else { 149 | buffer += separator.as_ref(); 150 | buffer += item.as_ref(); 151 | } 152 | } 153 | 154 | buffer 155 | } 156 | } 157 | } 158 | } 159 | } 160 | 161 | fn get_ast_struct_fields(ast: &DeriveInput) -> &[Field] { 162 | if let syn::Body::Struct(ref variant_data) = ast.body { 163 | if let syn::VariantData::Struct(ref fields) = *variant_data { 164 | return fields; 165 | } 166 | } 167 | 168 | panic!("No fields in struct! Arthas does not support empty struct!"); 169 | } 170 | 171 | fn generate_deep_struct(ast: &DeriveInput) -> quote::Tokens { 172 | let mut tokens = quote::Tokens::new(); 173 | 174 | tokens.append(&format!("{} {{", ast.ident.to_string())); 175 | 176 | for field in get_ast_struct_fields(ast) { 177 | let field_ident = field.ident.clone().unwrap(); 178 | let field_type = type_to_string(&field.ty); 179 | 180 | if is_vec(&field_type) && vec_is_struct_type(&field_type) { 181 | let generic_type = get_vec_generic_type(&field_type); 182 | tokens.append(&format!("{}:", field_ident.to_string())); 183 | tokens.append("e!{ 184 | { 185 | let mut vec = Vec::new(); 186 | vec.push(#generic_type::new_deep_empty()); 187 | vec 188 | } 189 | } 190 | .to_string()); 191 | tokens.append(","); 192 | } else if is_hashmap(&field_type) && hashmap_is_struct_type(&field_type) { 193 | let generic_type = get_hashmap_generic_type(&field_type); 194 | tokens.append(&format!("{}:", field_ident.to_string())); 195 | tokens.append("e!{ 196 | { 197 | let mut map = ::std::collections::HashMap::new(); 198 | map.insert(String::new(), #generic_type::new_deep_empty()); 199 | map 200 | } 201 | } 202 | .to_string()); 203 | tokens.append(","); 204 | } else if is_option(&field_type) && option_is_struct_type(&field_type) { 205 | let generic_type = get_option_generic_type(&field_type); 206 | tokens.append(&format!("{}:", field_ident.to_string())); 207 | tokens.append("e!{ 208 | { 209 | Some(#generic_type::new_deep_empty()) 210 | } 211 | } 212 | .to_string()); 213 | tokens.append(","); 214 | } 215 | } 216 | 217 | tokens.append("..Default::default()"); 218 | tokens.append("}"); 219 | tokens 220 | } 221 | 222 | fn get_rename_value(ast: &DeriveInput) -> String { 223 | for attr in &ast.attrs { 224 | if let syn::MetaItem::List(ref ident, ref meta_items) = attr.value { 225 | if ident.to_string() == "arthas" { 226 | for item in meta_items { 227 | if let syn::NestedMetaItem::MetaItem(ref meta_item) = *item { 228 | if let syn::MetaItem::NameValue(ref ident, ref lit) = *meta_item { 229 | if ident.to_string() == "rename" { 230 | if let syn::Lit::Str(ref value, _) = *lit { 231 | return value.to_owned(); 232 | } 233 | } 234 | } 235 | } 236 | } 237 | } 238 | } 239 | } 240 | 241 | String::new() 242 | } 243 | 244 | fn generate_rename_map_block(ast: &DeriveInput) -> quote::Tokens { 245 | let rename_value = get_rename_value(ast); 246 | let mut rename_map_block = quote::Tokens::new(); 247 | let mut rename_map_exists = false; 248 | rename_map_block.append("{let mut rename_map = ::std::collections::HashMap::new();"); 249 | 250 | for name_value in rename_value.split(',') { 251 | if name_value.is_empty() { 252 | continue; 253 | } 254 | 255 | let segments = name_value.trim().split('=').collect::>(); 256 | if segments.len() != 2 { 257 | panic!("invalid rename value"); 258 | } 259 | 260 | rename_map_exists = true; 261 | 262 | let name = segments[0]; 263 | let value = segments[1]; 264 | 265 | rename_map_block.append("e!{ 266 | rename_map.insert(#name.to_owned(), #value.to_owned()); 267 | } 268 | .to_string()); 269 | } 270 | rename_map_block.append("rename_map}"); 271 | 272 | if rename_map_exists { 273 | rename_map_block 274 | } else { 275 | quote!{::std::collections::HashMap::new()} 276 | } 277 | } 278 | 279 | fn generate_field_int_map_block(ast: &DeriveInput) -> quote::Tokens { 280 | let mut field_type_map_block = quote::Tokens::new(); 281 | field_type_map_block.append("{"); 282 | field_type_map_block.append("let mut field_type_map = ::std::collections::HashMap::new();"); 283 | 284 | for field in get_ast_struct_fields(ast) { 285 | let field_ident_string = field.ident.clone().unwrap().to_string(); 286 | let field_type = type_to_string(&field.ty); 287 | 288 | if is_vec(&field_type) && vec_is_struct_type(&field_type) { 289 | let generic_type = get_vec_generic_type(&field_type); 290 | field_type_map_block.append("e!{ 291 | field_type_map.insert(#field_ident_string.to_owned(), 292 | ::arthas::traits::FieldType::Array(#generic_type::get_field_type_map())); 293 | } 294 | .to_string()); 295 | } else if is_hashmap(&field_type) && hashmap_is_struct_type(&field_type) { 296 | let generic_type = get_hashmap_generic_type(&field_type); 297 | field_type_map_block.append("e!{ 298 | field_type_map.insert(#field_ident_string.to_owned(), 299 | ::arthas::traits::FieldType::Object(#generic_type::get_field_type_map()));} 300 | .to_string()); 301 | } else if is_option(&field_type) && option_is_struct_type(&field_type) { 302 | let generic_type = get_option_generic_type(&field_type); 303 | field_type_map_block.append("e!{ 304 | field_type_map.insert(#field_ident_string.to_owned(), 305 | ::arthas::traits::FieldType::Object(#generic_type::get_field_type_map()));} 306 | .to_string()); 307 | } else if is_struct_type(&field_type) { 308 | let generic_type = to_ident(field_type); 309 | field_type_map_block.append("e!{ 310 | field_type_map.insert(#field_ident_string.to_owned(), 311 | ::arthas::traits::FieldType::Struct(#generic_type::get_field_type_map()));} 312 | .to_string()); 313 | } else { 314 | field_type_map_block.append("e!{ 315 | field_type_map.insert(#field_ident_string.to_owned(), 316 | ::arthas::traits::FieldType::Atomic(#field_type.to_owned()));} 317 | .to_string()); 318 | } 319 | } 320 | 321 | field_type_map_block.append("return field_type_map;"); 322 | field_type_map_block.append("}"); 323 | field_type_map_block 324 | } 325 | 326 | fn to_ident>(ident_str: I) -> Ident { 327 | Ident::from(ident_str.as_ref()) 328 | } 329 | 330 | fn type_to_string(ty: &syn::Ty) -> String { 331 | let mut ty_tokens = quote::Tokens::new(); 332 | ty.to_tokens(&mut ty_tokens); 333 | ty_tokens.to_string() 334 | } 335 | 336 | fn check_is_struct(ast: &DeriveInput) { 337 | if let syn::Body::Struct(_) = ast.body { 338 | } else { 339 | panic!("#[derive(Arthas)] is only defined for structs, not for enums or other!"); 340 | } 341 | } 342 | 343 | fn check_has_id(ast: &DeriveInput) -> bool { 344 | for field in get_ast_struct_fields(ast) { 345 | if let Some(ref ident) = field.ident { 346 | if ident.to_string() == "_id" { 347 | return true; 348 | } 349 | } 350 | } 351 | 352 | false 353 | } 354 | 355 | fn check_is_one(ast: &DeriveInput) -> bool { 356 | for attr in &ast.attrs { 357 | if let syn::MetaItem::List(ref ident, ref meta_items) = attr.value { 358 | if ident.to_string() == "arthas" { 359 | for item in meta_items { 360 | if let syn::NestedMetaItem::MetaItem(ref meta_item) = *item { 361 | if let syn::MetaItem::Word(ref ident) = *meta_item { 362 | if ident.to_string() == "is_one" { 363 | return true; 364 | } 365 | } 366 | } 367 | } 368 | } 369 | } 370 | } 371 | 372 | false 373 | } 374 | 375 | fn is_vec(type_: &str) -> bool { 376 | type_.starts_with("Vec<") || type_.starts_with("Vec <") 377 | } 378 | 379 | fn is_option(type_: &str) -> bool { 380 | type_.starts_with("Option<") || type_.starts_with("Option <") 381 | } 382 | 383 | fn is_hashmap(type_: &str) -> bool { 384 | type_.starts_with("HashMap<") || type_.starts_with("HashMap <") 385 | } 386 | 387 | fn get_vec_generic_type(type_: &str) -> Ident { 388 | let reg = Regex::new("Vec *< *(.*) *>").unwrap(); 389 | let cap = reg.captures(type_).unwrap(); 390 | to_ident(cap[1].trim()) 391 | } 392 | 393 | fn get_option_generic_type(type_: &str) -> Ident { 394 | let reg = Regex::new(r"Option *< *(.*) *>").unwrap(); 395 | let cap = reg.captures(type_).unwrap(); 396 | to_ident(cap[1].trim()) 397 | } 398 | 399 | fn get_hashmap_generic_type(type_: &str) -> Ident { 400 | let reg = Regex::new(r"HashMap *< *[a-z0-9A-Z]+ *, *(.*) *>").unwrap(); 401 | let cap = reg.captures(type_).unwrap(); 402 | to_ident(cap[1].trim()) 403 | } 404 | 405 | fn hashmap_is_struct_type(type_: &str) -> bool { 406 | is_struct_type(&get_hashmap_generic_type(type_).to_string()) 407 | } 408 | 409 | fn vec_is_struct_type(type_: &str) -> bool { 410 | is_struct_type(&get_vec_generic_type(type_).to_string()) 411 | } 412 | 413 | fn option_is_struct_type(type_: &str) -> bool { 414 | is_struct_type(&get_option_generic_type(type_).to_string()) 415 | } 416 | 417 | fn is_struct_type(generic_type: &str) -> bool { 418 | if is_option(generic_type) && !option_is_struct_type(generic_type) { 419 | false 420 | } else if is_vec(generic_type) && !vec_is_struct_type(generic_type) { 421 | false 422 | } else if is_hashmap(generic_type) && !hashmap_is_struct_type(generic_type) { 423 | false 424 | } else { 425 | match generic_type { 426 | "String" | "&'static str" | "usize" | "u8" | "u16" | "u32" | "u64" | "i8" | "i16" | 427 | "i32" | "i64" | "bool" => false, 428 | _ => true, 429 | } 430 | } 431 | } 432 | -------------------------------------------------------------------------------- /arthas/src/tree/node/mod.rs: -------------------------------------------------------------------------------- 1 | 2 | use std::sync::atomic::Ordering; 3 | use std::sync::atomic::AtomicBool; 4 | use std::collections::HashMap; 5 | use std::sync::Arc; 6 | use std::sync::RwLock; 7 | use std::fmt; 8 | use serde_json::Value; 9 | use item::{Id, FieldInt}; 10 | use super::comparision::Comparision; 11 | use super::action::SearchAction; 12 | use super::rc::RcChild; 13 | use super::math::Math; 14 | use super::rc::DataType; 15 | use super::rc::RcNode; 16 | use super::searcher::task::Sub; 17 | 18 | 19 | pub type Group = Arc>>; 20 | pub type Groups = Vec; 21 | 22 | 23 | #[derive(Clone)] 24 | pub struct Node { 25 | pub _type: DataType, 26 | pub self_rc: Option, 27 | pub group: Group, 28 | pub parent: Option, 29 | pub left: Option, 30 | pub right: Option, 31 | } 32 | 33 | impl Node { 34 | pub fn new(id: Id, rc_child: RcChild) -> Node { 35 | let _type = rc_child.read().unwrap().get_type(); 36 | 37 | let mut map = HashMap::new(); 38 | map.insert(id, rc_child); 39 | 40 | Node { 41 | _type: _type, 42 | self_rc: None, 43 | group: Arc::new(RwLock::new(map)), 44 | parent: None, 45 | left: None, 46 | right: None, 47 | } 48 | } 49 | 50 | pub fn insert(&mut self, 51 | field_int: FieldInt, 52 | id: Id, 53 | rc_child: RcChild, 54 | is_min: &mut bool, 55 | is_max: &mut bool) 56 | -> Option { 57 | match self._type { 58 | DataType::Number | DataType::String => { 59 | if Math::gt(&rc_child.read().unwrap().get_value(), &self.get_value()) { 60 | if *is_min { 61 | thread_trace!("found gt, cancel min"); 62 | *is_min = false; 63 | } 64 | 65 | if self.right.is_some() { 66 | thread_trace!("continue insert right"); 67 | self.insert_continue_right(field_int, id, rc_child, is_min, is_max) 68 | } else { 69 | thread_trace!("set right node"); 70 | self.set_right(field_int, id, rc_child, is_max) 71 | } 72 | } else if Math::lt(&rc_child.read().unwrap().get_value(), &self.get_value()) { 73 | if *is_max { 74 | thread_trace!("found lt, cancel max"); 75 | *is_max = false; 76 | } 77 | 78 | if self.left.is_some() { 79 | thread_trace!("continue insert left"); 80 | self.insert_continue_left(field_int, id, rc_child, is_min, is_max) 81 | } else { 82 | thread_trace!("set left node"); 83 | self.set_left(field_int, id, rc_child, is_min) 84 | } 85 | } else { 86 | thread_trace!("found group, insert to current"); 87 | self.insert_to_current(field_int, id, rc_child); 88 | *is_min = false; 89 | *is_max = false; 90 | None 91 | } 92 | } 93 | _ => unreachable!(), 94 | } 95 | } 96 | 97 | fn insert_to_current(&mut self, field_int: FieldInt, id: Id, rc_child: RcChild) { 98 | { 99 | let child = rc_child.read().unwrap(); 100 | child.item 101 | .write() 102 | .unwrap() 103 | .nodes 104 | .insert(field_int, self.self_rc.clone().unwrap()); 105 | } 106 | 107 | self.group.write().unwrap().insert(id, rc_child); 108 | } 109 | 110 | fn insert_continue_right(&mut self, 111 | field_int: FieldInt, 112 | id: Id, 113 | rc_child: RcChild, 114 | is_min: &mut bool, 115 | is_max: &mut bool) 116 | -> Option { 117 | self.right 118 | .as_mut() 119 | .unwrap() 120 | .write() 121 | .unwrap() 122 | .insert(field_int, id, rc_child, is_min, is_max) 123 | } 124 | 125 | fn insert_continue_left(&mut self, 126 | field_int: FieldInt, 127 | id: Id, 128 | rc_child: RcChild, 129 | is_min: &mut bool, 130 | is_max: &mut bool) 131 | -> Option { 132 | self.left 133 | .as_mut() 134 | .unwrap() 135 | .write() 136 | .unwrap() 137 | .insert(field_int, id, rc_child, is_min, is_max) 138 | } 139 | 140 | fn set_left(&mut self, 141 | field_int: FieldInt, 142 | id: Id, 143 | rc_child: RcChild, 144 | is_min: &mut bool) 145 | -> Option { 146 | let rc_node = RcNode::new(id, rc_child.clone()); 147 | let child = rc_child.read() 148 | .unwrap(); 149 | child.item 150 | .write() 151 | .unwrap() 152 | .nodes 153 | .insert(field_int, rc_node.clone()); 154 | 155 | { 156 | let mut node = rc_node.write().unwrap(); 157 | node.parent = self.self_rc.clone(); 158 | node.self_rc = Some(rc_node.clone()); 159 | } 160 | 161 | self.left = Some(rc_node.clone()); 162 | 163 | if *is_min { Some(rc_node) } else { None } 164 | } 165 | 166 | fn set_right(&mut self, 167 | field_int: FieldInt, 168 | id: Id, 169 | rc_child: RcChild, 170 | is_max: &mut bool) 171 | -> Option { 172 | let rc_node = RcNode::new(id, rc_child.clone()); 173 | let child = rc_child.read().unwrap(); 174 | child.item 175 | .write() 176 | .unwrap() 177 | .nodes 178 | .insert(field_int, rc_node.clone()); 179 | 180 | { 181 | let mut node = rc_node.write().unwrap(); 182 | node.parent = self.self_rc.clone(); 183 | node.self_rc = Some(rc_node.clone()); 184 | } 185 | 186 | self.right = Some(rc_node.clone()); 187 | 188 | if *is_max { Some(rc_node) } else { None } 189 | } 190 | 191 | pub fn search_root(&self, stopped: &AtomicBool, groups: &mut Groups, sub: &mut Sub) { 192 | let action_option = self.search_current(stopped, groups, sub); 193 | if action_option.is_some() { 194 | self.go_right_or_go_left(action_option.unwrap(), stopped, groups, sub); 195 | } 196 | } 197 | 198 | fn search_max_root(&self, stopped: &AtomicBool, groups: &mut Groups, sub: &mut Sub) { 199 | let action_option = self.search_max_current(stopped, groups, sub); 200 | if action_option.is_some() { 201 | self.search_min_or_max_go_right_or_go_left(action_option.unwrap(), 202 | stopped, 203 | groups, 204 | sub); 205 | } 206 | } 207 | 208 | fn search_min_root(&self, stopped: &AtomicBool, groups: &mut Groups, sub: &mut Sub) { 209 | let action_option = self.search_min_current(stopped, groups, sub); 210 | if action_option.is_some() { 211 | self.search_min_or_max_go_right_or_go_left(action_option.unwrap(), 212 | stopped, 213 | groups, 214 | sub); 215 | } 216 | } 217 | 218 | pub fn search_max(&self, stopped: &AtomicBool, groups: &mut Groups, sub: &mut Sub) { 219 | let action_option = self.search_max_current(stopped, groups, sub); 220 | if action_option.is_some() { 221 | let action = action_option.unwrap(); 222 | 223 | let mut should_stop = true; 224 | 225 | if !action.fold_left && action.go_left { 226 | if self.left.is_some() { 227 | self.go_left(stopped, groups, sub); 228 | } 229 | 230 | if self.parent.is_some() { 231 | should_stop = false; 232 | self.go_top_max(stopped, groups, sub); 233 | } 234 | } 235 | 236 | if should_stop { 237 | return stop(stopped, sub); 238 | } 239 | } else if !stopped.load(Ordering::SeqCst) { 240 | return stop(stopped, sub); 241 | } 242 | } 243 | 244 | pub fn search_min(&self, stopped: &AtomicBool, groups: &mut Groups, sub: &mut Sub) { 245 | let action_option = self.search_min_current(stopped, groups, sub); 246 | if action_option.is_some() { 247 | let action = action_option.unwrap(); 248 | 249 | let mut should_stop = true; 250 | 251 | if !action.fold_right && action.go_right { 252 | if self.right.is_some() { 253 | self.go_right(stopped, groups, sub); 254 | } 255 | 256 | if self.parent.is_some() { 257 | should_stop = false; 258 | self.go_top_min(stopped, groups, sub); 259 | } 260 | } 261 | 262 | if should_stop && !stopped.load(Ordering::SeqCst) { 263 | return stop(stopped, sub); 264 | } 265 | } else if !stopped.load(Ordering::SeqCst) { 266 | return stop(stopped, sub); 267 | } 268 | } 269 | 270 | fn go_right(&self, stopped: &AtomicBool, groups: &mut Groups, sub: &mut Sub) { 271 | thread_trace!("search min, go right"); 272 | self.right.as_ref().unwrap().read().unwrap().search_min_root(stopped, groups, sub); 273 | } 274 | 275 | fn go_left(&self, stopped: &AtomicBool, groups: &mut Groups, sub: &mut Sub) { 276 | thread_trace!("search max, go left"); 277 | self.left.as_ref().unwrap().read().unwrap().search_max_root(stopped, groups, sub); 278 | } 279 | 280 | fn go_top_max(&self, stopped: &AtomicBool, groups: &mut Groups, sub: &mut Sub) { 281 | thread_trace!("search max, go top"); 282 | self.parent.as_ref().unwrap().read().unwrap().search_max(stopped, groups, sub); 283 | } 284 | 285 | fn go_top_min(&self, stopped: &AtomicBool, groups: &mut Groups, sub: &mut Sub) { 286 | thread_trace!("search min, go top"); 287 | self.parent.as_ref().unwrap().read().unwrap().search_min(stopped, groups, sub); 288 | } 289 | 290 | fn search_min_current(&self, 291 | stopped: &AtomicBool, 292 | groups: &mut Groups, 293 | sub: &mut Sub) 294 | -> Option { 295 | if stopped.load(Ordering::SeqCst) { 296 | thread_trace!("search min current, other threads had stopped, return none"); 297 | return None; 298 | } 299 | 300 | let action_option = self.compare_self(&sub.comparisions); 301 | if action_option.is_none() { 302 | thread_trace!("search min current, action is none, return none"); 303 | return None; 304 | } 305 | 306 | let action = action_option.unwrap(); 307 | self.fold_min_action(&action, groups); 308 | 309 | if action.is_stopped() { 310 | thread_trace!("search min current, action is stopped, return none"); 311 | return None; 312 | } 313 | 314 | thread_trace!("search min current, found some action: {:?}", action); 315 | Some(action) 316 | } 317 | 318 | fn search_max_current(&self, 319 | stopped: &AtomicBool, 320 | groups: &mut Groups, 321 | sub: &mut Sub) 322 | -> Option { 323 | if stopped.load(Ordering::SeqCst) { 324 | thread_trace!("search min current, other threads had stopped, return none"); 325 | return None; 326 | } 327 | 328 | let action_option = self.compare_self(&sub.comparisions); 329 | if action_option.is_none() { 330 | thread_trace!("search min current, action is none, return none"); 331 | return None; 332 | } 333 | 334 | let action = action_option.unwrap(); 335 | self.fold_max_action(&action, groups); 336 | 337 | if action.is_stopped() { 338 | thread_trace!("search min current, action is stopped, return none"); 339 | return None; 340 | } 341 | 342 | thread_trace!("search min current, found some action: {:?}", action); 343 | Some(action) 344 | } 345 | 346 | fn search_current(&self, 347 | stopped: &AtomicBool, 348 | groups: &mut Groups, 349 | sub: &mut Sub) 350 | -> Option { 351 | if stopped.load(Ordering::SeqCst) { 352 | thread_trace!("other threads had stopped, stopping current."); 353 | return None; 354 | } 355 | 356 | let action_option = self.compare_self(&sub.comparisions); 357 | if action_option.is_none() { 358 | stop(stopped, sub); 359 | thread_trace!("action is none, stopping sub."); 360 | return None; 361 | } 362 | 363 | let action = action_option.unwrap(); 364 | self.fold_action(&action, groups); 365 | 366 | if action.is_stopped() { 367 | stop(stopped, sub); 368 | thread_trace!("action is stopped, stopping sub."); 369 | return None; 370 | } 371 | 372 | thread_trace!("found some action: {:?}", action); 373 | Some(action) 374 | } 375 | 376 | fn search_min_or_max_go_right_or_go_left(&self, 377 | action: SearchAction, 378 | stopped: &AtomicBool, 379 | groups: &mut Groups, 380 | sub: &mut Sub) { 381 | if action.go_right && self.right.is_some() { 382 | self.right 383 | .as_ref() 384 | .unwrap() 385 | .read() 386 | .unwrap() 387 | .search_min_root(stopped, groups, sub); 388 | } 389 | 390 | if action.go_left && self.left.is_some() { 391 | self.left 392 | .as_ref() 393 | .unwrap() 394 | .read() 395 | .unwrap() 396 | .search_min_root(stopped, groups, sub); 397 | 398 | } 399 | } 400 | 401 | fn go_right_or_go_left(&self, 402 | action: SearchAction, 403 | stopped: &AtomicBool, 404 | groups: &mut Groups, 405 | sub: &mut Sub) { 406 | let mut no_right_go = true; 407 | let mut no_left_go = true; 408 | 409 | if action.go_right && self.right.is_some() { 410 | no_right_go = false; 411 | self.right 412 | .as_ref() 413 | .unwrap() 414 | .read() 415 | .unwrap() 416 | .search_root(stopped, groups, sub); 417 | } 418 | 419 | if action.go_left && self.left.is_some() { 420 | no_left_go = false; 421 | self.left 422 | .as_ref() 423 | .unwrap() 424 | .read() 425 | .unwrap() 426 | .search_root(stopped, groups, sub); 427 | 428 | } 429 | 430 | if no_left_go && no_right_go { 431 | return stop(stopped, sub); 432 | } 433 | } 434 | 435 | fn fold_min_action(&self, action: &SearchAction, groups: &mut Groups) { 436 | if action.take { 437 | thread_trace!("fold min action, take current childs: {:?}", 438 | &*self.group.read().unwrap()); 439 | 440 | self.append_to(groups); 441 | } 442 | 443 | if action.fold_right { 444 | thread_trace!("fold min action, fold right"); 445 | self.fold_right_top(groups); 446 | } 447 | } 448 | 449 | fn fold_max_action(&self, action: &SearchAction, groups: &mut Groups) { 450 | if action.take { 451 | thread_trace!("fold max action, take current childs: {:?}", 452 | &*self.group.read().unwrap()); 453 | 454 | self.append_to(groups); 455 | } 456 | 457 | if action.fold_left { 458 | thread_trace!("fold max action, fold left"); 459 | self.fold_left_top(groups); 460 | } 461 | } 462 | 463 | fn fold_action(&self, action: &SearchAction, groups: &mut Groups) { 464 | if action.take { 465 | thread_trace!("fold action, take current childs: {:?}", 466 | &*self.group.read().unwrap()); 467 | 468 | self.append_to(groups); 469 | } 470 | 471 | if action.fold_right { 472 | thread_trace!("fold right"); 473 | self.fold_right_to(groups); 474 | } 475 | 476 | if action.fold_left { 477 | thread_trace!("fold left"); 478 | self.fold_left_to(groups); 479 | } 480 | } 481 | 482 | fn fold_left_top(&self, groups: &mut Groups) { 483 | self.fold_left_to(groups); 484 | 485 | if self.parent.is_some() { 486 | self.parent.as_ref().unwrap().read().unwrap().fold_current_left(groups); 487 | } 488 | } 489 | 490 | fn fold_right_top(&self, groups: &mut Groups) { 491 | self.fold_right_to(groups); 492 | 493 | if self.parent.is_some() { 494 | self.parent.as_ref().unwrap().read().unwrap().fold_current_right(groups); 495 | } 496 | } 497 | 498 | fn fold_current_left(&self, groups: &mut Groups) { 499 | self.append_to(groups); 500 | self.fold_left_to(groups); 501 | } 502 | 503 | fn fold_current_right(&self, groups: &mut Groups) { 504 | self.append_to(groups); 505 | self.fold_right_to(groups); 506 | } 507 | 508 | fn fold_left_to(&self, groups: &mut Groups) { 509 | if self.left.is_some() { 510 | self.left.as_ref().unwrap().read().unwrap().fold_to(groups); 511 | } 512 | } 513 | 514 | fn fold_right_to(&self, groups: &mut Groups) { 515 | if self.right.is_some() { 516 | self.right.as_ref().unwrap().read().unwrap().fold_to(groups); 517 | } 518 | } 519 | 520 | fn fold_to(&self, groups: &mut Groups) { 521 | self.append_to(groups); 522 | self.fold_right_to(groups); 523 | self.fold_left_to(groups); 524 | } 525 | 526 | fn append_to(&self, groups: &mut Groups) { 527 | groups.push(self.group.clone()); 528 | } 529 | 530 | fn compare_self(&self, comparisions: &[Comparision]) -> Option { 531 | let mut prev_action = None; 532 | 533 | for comparision in comparisions { 534 | let compared_action = comparision.compare(&self.get_value()); 535 | if compared_action.is_none() { 536 | return None; 537 | } 538 | 539 | if prev_action.is_none() { 540 | prev_action = compared_action; 541 | } else { 542 | let merged_action = prev_action.as_ref().unwrap().merge(&compared_action.unwrap()); 543 | if merged_action.is_none() { 544 | return None; 545 | } else { 546 | prev_action = merged_action; 547 | } 548 | } 549 | } 550 | 551 | prev_action 552 | } 553 | 554 | pub fn delete(&mut self, id: &str) -> (bool, Option, Option) { 555 | if self.group.read().unwrap().len() == 1 { 556 | let (clear, root) = self.delete_self(); 557 | (clear, self.self_rc.take(), root) 558 | } else { 559 | let rc_child = self.group.write().unwrap().remove(id); 560 | if rc_child.is_some() { 561 | rc_child.unwrap().destroy(); 562 | } 563 | 564 | (false, None, None) 565 | } 566 | } 567 | 568 | fn is_root(&self) -> bool { 569 | self.parent.is_none() 570 | } 571 | 572 | fn delete_self(&mut self) -> (bool, Option) { 573 | let mut clear = false; 574 | let mut root = None; 575 | 576 | if self.has_no_child_node() { 577 | if self.is_root() { 578 | clear = true; 579 | } else { 580 | self.parent.as_ref().unwrap().write().unwrap().delete_child_node(&self.self_rc); 581 | } 582 | } else if self.has_two_child_node() { 583 | let is_root = self.is_root(); 584 | let need_link_rc_node = self.take_right_min_node(); 585 | 586 | { 587 | let mut need_link_node = need_link_rc_node.write().unwrap(); 588 | 589 | self.replace_parent_child_node(need_link_rc_node.clone()); 590 | 591 | if is_root { 592 | need_link_node.parent = None; 593 | } else { 594 | need_link_node.parent = Some(self.parent.take().unwrap()); 595 | } 596 | 597 | let left_rc_node = self.left.take().unwrap(); 598 | left_rc_node.write().unwrap().parent = Some(need_link_rc_node.clone()); 599 | need_link_node.left = Some(left_rc_node); 600 | 601 | if self.right.is_some() { 602 | let right_rc_node = self.right.take().unwrap(); 603 | right_rc_node.write().unwrap().parent = Some(need_link_rc_node.clone()); 604 | need_link_node.right = Some(right_rc_node); 605 | } 606 | } 607 | 608 | if is_root { 609 | clear = true; 610 | root = Some(need_link_rc_node); 611 | } 612 | } else if self.left.is_some() { 613 | let rc_node = self.left.take().unwrap(); 614 | 615 | if self.is_root() { 616 | rc_node.write().unwrap().parent = None; 617 | clear = true; 618 | root = Some(rc_node); 619 | } else { 620 | rc_node.write().unwrap().parent = self.parent.clone(); 621 | self.replace_parent_child_node(rc_node); 622 | } 623 | } else if self.right.is_some() { 624 | let rc_node = self.right.take().unwrap(); 625 | 626 | if self.is_root() { 627 | rc_node.write().unwrap().parent = None; 628 | clear = true; 629 | root = Some(rc_node); 630 | } else { 631 | rc_node.write().unwrap().parent = self.parent.clone(); 632 | self.replace_parent_child_node(rc_node); 633 | } 634 | } else { 635 | unreachable!() 636 | } 637 | 638 | (clear, root) 639 | } 640 | 641 | fn right_child_no_left(&self) -> bool { 642 | self.right.as_ref().unwrap().read().unwrap().left.is_none() 643 | } 644 | 645 | fn left_child_no_left(&self) -> bool { 646 | self.left.as_ref().unwrap().read().unwrap().left.is_none() 647 | } 648 | 649 | fn take_left_min_node(&mut self) -> RcNode { 650 | if self.left_child_no_left() { 651 | self.left.take().unwrap() 652 | } else { 653 | self.left.as_ref().unwrap().write().unwrap().take_left_min_node() 654 | } 655 | } 656 | 657 | fn take_right_min_node(&mut self) -> RcNode { 658 | if self.right_child_no_left() { 659 | self.right.take().unwrap() 660 | } else { 661 | self.right.as_ref().unwrap().write().unwrap().take_left_min_node() 662 | } 663 | } 664 | 665 | fn replace_parent_child_node(&self, rc_node: RcNode) { 666 | let mut parent = self.parent.as_ref().unwrap().write().unwrap(); 667 | parent.replace_child_node(&self.self_rc, rc_node); 668 | } 669 | 670 | fn replace_child_node(&mut self, from: &Option, to: RcNode) { 671 | if self.left == *from { 672 | self.left = Some(to); 673 | } else { 674 | self.right = Some(to); 675 | } 676 | } 677 | 678 | fn delete_child_node(&mut self, self_rc: &Option) { 679 | if self.left == *self_rc { 680 | self.left = None; 681 | } else { 682 | self.right = None; 683 | } 684 | } 685 | 686 | fn has_no_child_node(&self) -> bool { 687 | self.left.is_none() && self.right.is_none() 688 | } 689 | 690 | fn has_two_child_node(&self) -> bool { 691 | self.left.is_some() && self.right.is_some() 692 | } 693 | 694 | pub fn get_value(&self) -> Value { 695 | for child in self.group.read().unwrap().values() { 696 | return child.read().unwrap().get_value(); 697 | } 698 | 699 | unreachable!() 700 | } 701 | } 702 | 703 | impl fmt::Debug for Node { 704 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 705 | write!(f, "{:?}", self.group) 706 | } 707 | } 708 | 709 | #[inline] 710 | fn stop(stopped: &AtomicBool, sub: &mut Sub) { 711 | sub.stopped = true; 712 | stopped.store(true, Ordering::SeqCst); 713 | } 714 | --------------------------------------------------------------------------------