From 09d82c08155a11052446b4de419d249ab7e8b30c Mon Sep 17 00:00:00 2001 From: dodic Date: Fri, 24 Jun 2022 12:33:21 +0300 Subject: [PATCH 01/22] `update_links` + base for smart filter --- rust/src/main.rs | 1 + rust/src/model/object_type/mutation_root.rs | 43 ++++++++++++++++++-- rust/src/model/object_type/query_root.rs | 44 +++++++++++++-------- 3 files changed, 67 insertions(+), 21 deletions(-) diff --git a/rust/src/main.rs b/rust/src/main.rs index 55e38179..a864c06f 100644 --- a/rust/src/main.rs +++ b/rust/src/main.rs @@ -1,5 +1,6 @@ #![feature(never_type)] #![feature(result_flattening)] +#![feature(box_syntax)] mod model; diff --git a/rust/src/model/object_type/mutation_root.rs b/rust/src/model/object_type/mutation_root.rs index 4a6123a0..c69fe10f 100644 --- a/rust/src/model/object_type/mutation_root.rs +++ b/rust/src/model/object_type/mutation_root.rs @@ -1,4 +1,3 @@ -use crate::model::Links; use crate::model::LinksBoolExp; use crate::model::LinksIncInput; use crate::model::LinksInsertInput; @@ -44,7 +43,8 @@ use crate::model::StringsOnConflict; use crate::model::StringsPkColumnsInput; use crate::model::StringsSetInput; use crate::model::{Bigint, LinksResult}; -use crate::Store; +use crate::model::{LinkType, Links}; +use crate::{QueryRoot, Store}; use async_graphql::*; use doublets::data::{LinksError, Query}; use doublets::{Doublets, Link}; @@ -230,6 +230,7 @@ impl MutationRoot { ) -> Option { todo!() } + #[graphql(name = "update_links")] pub async fn update_links( &self, @@ -237,9 +238,43 @@ impl MutationRoot { #[graphql(name = "_inc")] inc: Option, #[graphql(name = "_set")] set: Option, _where: Box, - ) -> Option { - todo!() + ) -> Result> { + let mut store = ctx.data_unchecked::().write().await; + + let ids: Vec<_> = QueryRoot::filter_links(&*store, Some(_where)) + .await + .map(|link| link.index) + .collect(); + + let returning: LinksResult> = ids + .into_iter() + .map(move |id| -> LinksResult> { + let link = store.try_get_link(id)?; + let (from_id, to_id) = if let Some(inc) = &inc { + ( + link.source + inc.from_id.to_link(), + link.target + inc.from_id.to_link(), + ) + } else if let Some(set) = &set { + (set.from_id.to_link(), set.to_id.to_link()) + } else { + (link.source, link.target) + }; + + if (link.source, link.target) != (from_id, to_id) { + store.update(id, from_id, to_id)?; + Ok(Link::new(id, from_id, to_id)) + } else { + Ok(link) + } + }) + .map(|link| link.map(|link| Links(link))) + .collect(); + returning + .map(|s| Some(LinksMutationResponse(s))) + .map_err(|e| e.into()) } + #[graphql(name = "update_links_by_pk")] pub async fn update_links_by_pk( &self, diff --git a/rust/src/model/object_type/query_root.rs b/rust/src/model/object_type/query_root.rs index 0746d259..c391f8c7 100644 --- a/rust/src/model/object_type/query_root.rs +++ b/rust/src/model/object_type/query_root.rs @@ -37,9 +37,9 @@ use crate::model::StringsBoolExp; use crate::model::StringsOrderBy; use crate::model::StringsSelectColumn; use crate::model::{Bigint, BigintComparisonExp, LinkType}; -use crate::Store; +use crate::{RawStore, Store}; use async_graphql::*; -use doublets::Doublets; +use doublets::{Doublets, Link}; #[derive(Debug)] pub struct QueryRoot; @@ -76,17 +76,11 @@ impl QueryRoot { todo!() } - pub async fn links( - &self, - ctx: &Context<'_>, - #[graphql(name = "distinct_on")] distinct_on: Option>, - limit: Option, - offset: Option, - #[graphql(name = "order_by")] order_by: Option>, + #[graphql(skip)] + pub(crate) async fn filter_links( + store: &RawStore, _where: Option>, - ) -> Vec { - let store = ctx.data_unchecked::().read().await; - + ) -> Box> + '_> { let fast_param_impl = |param: Option<&BigintComparisonExp>| -> LinkType { let any = store.constants().any; if let Some(param) = param { @@ -104,16 +98,32 @@ impl QueryRoot { let from_id = fast_param_impl(r#where.from_id.as_deref()); let to_id = fast_param_impl(r#where.to_id.as_deref()); - store + box store .each_iter([id, from_id, to_id]) - .filter(|link| r#where.matches(&*store, link)) - .map(|link| Links(link)) - .collect() + .filter(move |link| r#where.matches(&*store, link)) } else { - store.iter().map(|link| Links(link)).collect() + // todo: come up with something smarter + // store.iter() + box store.iter() } } + pub async fn links( + &self, + ctx: &Context<'_>, + #[graphql(name = "distinct_on")] distinct_on: Option>, + limit: Option, + offset: Option, + #[graphql(name = "order_by")] order_by: Option>, + _where: Option>, + ) -> Vec { + let store = ctx.data_unchecked::().read().await; + Self::filter_links(&*store, _where) + .await + .map(|link| Links(link)) + .collect() + } + #[graphql(name = "links_aggregate")] pub async fn links_aggregate( &self, From 6cbd788a01b71e80bf2c7c9c3c0c1470396fd9eb Mon Sep 17 00:00:00 2001 From: dodic Date: Sat, 25 Jun 2022 21:35:37 +0300 Subject: [PATCH 02/22] Update + Delete + Some fixes --- rust/Cargo.toml | 4 +- rust/src/main.rs | 8 +- .../model/input_object_type/links_bool_exp.rs | 4 +- rust/src/model/object_type/mutation_root.rs | 29 +++- rust/src/model/object_type/query_root.rs | 4 +- rust/src/store.rs | 133 ++++++++++++++++++ 6 files changed, 170 insertions(+), 12 deletions(-) create mode 100644 rust/src/store.rs diff --git a/rust/Cargo.toml b/rust/Cargo.toml index b39ce67c..7e7a551e 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -10,4 +10,6 @@ async-graphql = "4.0" actix-web = "4.0" async-graphql-actix-web = "4.0" #doublets = { version = "0.1.0-alpha.20", features = ["full"] } -doublets = "0.1.0-beta.3" +doublets = "0.1.0-beta.4" +doublets-decorators = "0.1.0-alpha.3" +smallvec = "1.8.0" diff --git a/rust/src/main.rs b/rust/src/main.rs index a864c06f..0618fdbe 100644 --- a/rust/src/main.rs +++ b/rust/src/main.rs @@ -1,13 +1,16 @@ #![feature(never_type)] #![feature(result_flattening)] #![feature(box_syntax)] +#![feature(try_trait_v2)] mod model; +mod store; use crate::model::{ Links, LinksInsertInput, LinksMutationResponse, LinksOnConflict, LinksOptionExt, MutationRoot, QueryRoot, }; +use crate::store::RawStore; use actix_web::{guard, web, App, HttpResponse, HttpServer, Responder}; use async_graphql::{ http::{playground_source, GraphQLPlaygroundConfig}, @@ -17,11 +20,11 @@ use async_graphql_actix_web::{GraphQLRequest, GraphQLResponse}; use async_std::sync::RwLock; use doublets::mem::FileMappedMem; use doublets::{splited, Link}; +use doublets_decorators::{CascadeUniqueResolver, CascadeUsagesResolver}; use std::{error::Error, fs::File, io, path::Path}; // todo: wait for fix type infer -type RawStore = splited::Store; -type Store = RwLock; +type Store = RwLock; type Schema = async_graphql::Schema; async fn index(schema: web::Data, req: GraphQLRequest) -> GraphQLResponse { @@ -50,6 +53,7 @@ fn map_db_file>(path: P) -> io::Result { // todo: implement Into for LinksError async fn main() -> Result<(), Box> { let store = RawStore::new(map_db_file("db.links")?, map_db_file("index.links")?)?; + let store = store::Store::new(store); let schema = Schema::build(QueryRoot, MutationRoot, EmptySubscription) .data(Store::new(store)) .finish(); diff --git a/rust/src/model/input_object_type/links_bool_exp.rs b/rust/src/model/input_object_type/links_bool_exp.rs index 3dcbbacb..1f899b9b 100644 --- a/rust/src/model/input_object_type/links_bool_exp.rs +++ b/rust/src/model/input_object_type/links_bool_exp.rs @@ -7,7 +7,7 @@ use crate::model::ObjectsBoolExp; use crate::model::SelectorsBoolExp; use crate::model::StringsBoolExp; use crate::model::{BigintComparisonExp, LinkType}; -use crate::RawStore; +use crate::{store, RawStore}; use async_graphql::*; use doublets::{Doublets, Link}; @@ -58,7 +58,7 @@ pub struct LinksBoolExp { } impl LinksBoolExp { - pub fn matches(&self, store: &RawStore, link: &Link) -> bool { + pub fn matches(&self, store: &store::Store, link: &Link) -> bool { let mut exp = true; if let Some(id) = &self.id { diff --git a/rust/src/model/object_type/mutation_root.rs b/rust/src/model/object_type/mutation_root.rs index c69fe10f..99a3acff 100644 --- a/rust/src/model/object_type/mutation_root.rs +++ b/rust/src/model/object_type/mutation_root.rs @@ -48,6 +48,7 @@ use crate::{QueryRoot, Store}; use async_graphql::*; use doublets::data::{LinksError, Query}; use doublets::{Doublets, Link}; +use smallvec::{smallvec, SmallVec}; use std::io::{Read, Write}; pub use crate::model::LinksOptionExt; @@ -62,9 +63,27 @@ impl MutationRoot { &self, ctx: &Context<'_>, _where: Box, - ) -> Option { - todo!() + ) -> Result> { + let mut store = ctx.data_unchecked::().write().await; + + let ids: Vec<_> = QueryRoot::filter_links(&*store, Some(_where)) + .await + .map(|link| link.index) + .collect(); + + let returning: LinksResult> = ids + .into_iter() + .map(move |id| -> LinksResult<_> { + let link = store.try_get_link(id)?; + store.delete(id)?; + Ok(Links(link)) + }) + .collect(); + returning + .map(|s| Some(LinksMutationResponse(s))) + .map_err(|e| e.into()) } + #[graphql(name = "delete_links_by_pk")] pub async fn delete_links_by_pk(&self, ctx: &Context<'_>, id: Bigint) -> Option { todo!() @@ -248,7 +267,7 @@ impl MutationRoot { let returning: LinksResult> = ids .into_iter() - .map(move |id| -> LinksResult> { + .map(move |id| -> LinksResult<_> { let link = store.try_get_link(id)?; let (from_id, to_id) = if let Some(inc) = &inc { ( @@ -262,13 +281,13 @@ impl MutationRoot { }; if (link.source, link.target) != (from_id, to_id) { - store.update(id, from_id, to_id)?; + let id = store.update(id, from_id, to_id)?; Ok(Link::new(id, from_id, to_id)) } else { Ok(link) } }) - .map(|link| link.map(|link| Links(link))) + .map(|result| result.map(|link| Links(link))) .collect(); returning .map(|s| Some(LinksMutationResponse(s))) diff --git a/rust/src/model/object_type/query_root.rs b/rust/src/model/object_type/query_root.rs index c391f8c7..9d4f4f63 100644 --- a/rust/src/model/object_type/query_root.rs +++ b/rust/src/model/object_type/query_root.rs @@ -37,7 +37,7 @@ use crate::model::StringsBoolExp; use crate::model::StringsOrderBy; use crate::model::StringsSelectColumn; use crate::model::{Bigint, BigintComparisonExp, LinkType}; -use crate::{RawStore, Store}; +use crate::{store, RawStore, Store}; use async_graphql::*; use doublets::{Doublets, Link}; @@ -78,7 +78,7 @@ impl QueryRoot { #[graphql(skip)] pub(crate) async fn filter_links( - store: &RawStore, + store: &store::Store, _where: Option>, ) -> Box> + '_> { let fast_param_impl = |param: Option<&BigintComparisonExp>| -> LinkType { diff --git a/rust/src/store.rs b/rust/src/store.rs new file mode 100644 index 00000000..7f243ee0 --- /dev/null +++ b/rust/src/store.rs @@ -0,0 +1,133 @@ +use crate::model::{LinkType, LinksResult}; +use doublets::data::Flow::Continue; +use doublets::data::{LinksConstants, LinksError, ToQuery}; +use doublets::{mem::FileMappedMem, splited, Doublets, Link}; +use smallvec::SmallVec; +use std::ops::Try; + +pub type RawStore = splited::Store; +type Inner = splited::Store; + +pub struct Store(Inner); + +impl Store { + pub fn new(inner: Inner) -> Self { + Self(inner) + } + + pub fn iter(&self) -> impl Iterator> + '_ { + // todo: + // self.0.iter() + let mut vec = SmallVec::<[_; 2]>::new(); + + self.try_each(|link| { + vec.push(link); + Continue + }); + + vec.into_iter() + } + + pub fn each_iter<'a>( + &self, + query: impl ToQuery + 'a, + ) -> impl Iterator> + 'a { + self.0.each_iter(query) + } + + pub fn update_iter<'a>( + &mut self, + id: LinkType, + from_id: LinkType, + to_id: LinkType, + ) -> LinksResult> + 'a> { + let mut vec = SmallVec::<[_; 2]>::new(); + + self.update_with(id, from_id, to_id, |before, link| { + vec.push(link); + Continue + })?; + + Ok(vec.into_iter()) + } +} + +impl Doublets for Store { + fn constants(&self) -> LinksConstants { + self.0.constants() + } + + fn count_by(&self, query: impl ToQuery) -> LinkType { + self.0.count_by(query) + } + + fn create_by_with( + &mut self, + query: impl ToQuery, + handler: F, + ) -> Result> + where + F: FnMut(Link, Link) -> R, + R: Try, + { + self.0.create_by_with(query, handler) + } + + fn try_each_by(&self, restrictions: impl ToQuery, handler: F) -> R + where + F: FnMut(Link) -> R, + R: Try, + { + self.0.try_each_by(restrictions, handler) + } + + fn update_by_with( + &mut self, + query: impl ToQuery, + replacement: impl ToQuery, + mut handler: F, + ) -> Result> + where + F: FnMut(Link, Link) -> R, + R: Try, + { + let query = query.to_query(); + let replacement = replacement.to_query(); + + let constants = self.constants(); + let store = &mut self.0; + let (new, from_id, to_id) = ( + query[constants.index_part as usize], + replacement[constants.source_part as usize], + replacement[constants.target_part as usize], + ); + let id = if let Some(old) = store.search(from_id, to_id) { + store.rebase_with(old, new, &mut handler)?; + store.delete_with(old, &mut handler)?; + new + } else { + new + }; + + store.update_with(id, from_id, to_id, handler) + } + + fn delete_by_with( + &mut self, + query: impl ToQuery, + mut handler: F, + ) -> Result> + where + F: FnMut(Link, Link) -> R, + R: Try, + { + let index_part = self.constants().index_part; + let store = &mut self.0; + store.delete_usages_with(query.to_query()[index_part as usize], &mut handler)?; + store.delete_by_with(query, handler) + } + + fn get_link(&self, index: LinkType) -> Option> { + self.0.get_link(index) + } +} From 49376d1b3cd72708cdeba38ed0ce3b511be31513 Mon Sep 17 00:00:00 2001 From: dodic Date: Sat, 25 Jun 2022 21:53:04 +0300 Subject: [PATCH 03/22] Use old standard --- rust/src/store.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/rust/src/store.rs b/rust/src/store.rs index 7f243ee0..df91d892 100644 --- a/rust/src/store.rs +++ b/rust/src/store.rs @@ -102,9 +102,9 @@ impl Doublets for Store { replacement[constants.target_part as usize], ); let id = if let Some(old) = store.search(from_id, to_id) { - store.rebase_with(old, new, &mut handler)?; - store.delete_with(old, &mut handler)?; - new + store.rebase_with(new, old, &mut handler)?; + store.delete_with(new, &mut handler)?; + old } else { new }; From 6fa2b31555330a159ba5284d5c371a07f2648892 Mon Sep 17 00:00:00 2001 From: FreePhoenix888 Date: Tue, 28 Jun 2022 14:06:37 +0600 Subject: [PATCH 04/22] Remove extra collect and into_iter --- rust/src/model/object_type/mutation_root.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/rust/src/model/object_type/mutation_root.rs b/rust/src/model/object_type/mutation_root.rs index 99a3acff..88545a89 100644 --- a/rust/src/model/object_type/mutation_root.rs +++ b/rust/src/model/object_type/mutation_root.rs @@ -66,13 +66,11 @@ impl MutationRoot { ) -> Result> { let mut store = ctx.data_unchecked::().write().await; - let ids: Vec<_> = QueryRoot::filter_links(&*store, Some(_where)) + let ids = QueryRoot::filter_links(&*store, Some(_where)) .await - .map(|link| link.index) - .collect(); + .map(|link| link.index); let returning: LinksResult> = ids - .into_iter() .map(move |id| -> LinksResult<_> { let link = store.try_get_link(id)?; store.delete(id)?; From b0218f200259953caad3929acac0f19d05850dd3 Mon Sep 17 00:00:00 2001 From: dodic Date: Wed, 29 Jun 2022 08:30:08 +0300 Subject: [PATCH 05/22] Migrate to new doublets --- rust/Cargo.toml | 4 +--- rust/src/main.rs | 5 ++--- rust/src/store.rs | 43 ++++++++++++------------------------------- 3 files changed, 15 insertions(+), 37 deletions(-) diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 7e7a551e..708892a9 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -9,7 +9,5 @@ async-std = { version = "1.12", features = ["attributes"] } async-graphql = "4.0" actix-web = "4.0" async-graphql-actix-web = "4.0" -#doublets = { version = "0.1.0-alpha.20", features = ["full"] } -doublets = "0.1.0-beta.4" -doublets-decorators = "0.1.0-alpha.3" +doublets = "0.1.0-beta.6" smallvec = "1.8.0" diff --git a/rust/src/main.rs b/rust/src/main.rs index 0618fdbe..95c60dd3 100644 --- a/rust/src/main.rs +++ b/rust/src/main.rs @@ -19,8 +19,7 @@ use async_graphql::{ use async_graphql_actix_web::{GraphQLRequest, GraphQLResponse}; use async_std::sync::RwLock; use doublets::mem::FileMappedMem; -use doublets::{splited, Link}; -use doublets_decorators::{CascadeUniqueResolver, CascadeUsagesResolver}; +use doublets::{split, Link}; use std::{error::Error, fs::File, io, path::Path}; // todo: wait for fix type infer @@ -39,7 +38,7 @@ async fn index_playground() -> actix_web::Result { } // todo: may be add support async-std files to platform-mem -fn map_db_file>(path: P) -> io::Result { +fn map_db_file>(path: P) -> io::Result> { File::options() .create(true) .read(true) diff --git a/rust/src/store.rs b/rust/src/store.rs index df91d892..74333f1f 100644 --- a/rust/src/store.rs +++ b/rust/src/store.rs @@ -1,12 +1,18 @@ use crate::model::{LinkType, LinksResult}; -use doublets::data::Flow::Continue; -use doublets::data::{LinksConstants, LinksError, ToQuery}; -use doublets::{mem::FileMappedMem, splited, Doublets, Link}; +use doublets::{ + data::{Flow::Continue, LinksConstants, LinksError, ToQuery}, + mem::FileMappedMem, + parts, split, Doublets, Link, +}; use smallvec::SmallVec; use std::ops::Try; -pub type RawStore = splited::Store; -type Inner = splited::Store; +pub type RawStore = split::Store< + LinkType, + FileMappedMem>, + FileMappedMem>, +>; +type Inner = RawStore; pub struct Store(Inner); @@ -16,16 +22,7 @@ impl Store { } pub fn iter(&self) -> impl Iterator> + '_ { - // todo: - // self.0.iter() - let mut vec = SmallVec::<[_; 2]>::new(); - - self.try_each(|link| { - vec.push(link); - Continue - }); - - vec.into_iter() + self.0.iter() } pub fn each_iter<'a>( @@ -34,22 +31,6 @@ impl Store { ) -> impl Iterator> + 'a { self.0.each_iter(query) } - - pub fn update_iter<'a>( - &mut self, - id: LinkType, - from_id: LinkType, - to_id: LinkType, - ) -> LinksResult> + 'a> { - let mut vec = SmallVec::<[_; 2]>::new(); - - self.update_with(id, from_id, to_id, |before, link| { - vec.push(link); - Continue - })?; - - Ok(vec.into_iter()) - } } impl Doublets for Store { From 95ae7e043572770b1a6b3db336e87730fa9befb8 Mon Sep 17 00:00:00 2001 From: dodic Date: Wed, 29 Jun 2022 08:53:35 +0300 Subject: [PATCH 06/22] Fix borrowing error --- rust/src/model/object_type/mutation_root.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/rust/src/model/object_type/mutation_root.rs b/rust/src/model/object_type/mutation_root.rs index 88545a89..6996a1ef 100644 --- a/rust/src/model/object_type/mutation_root.rs +++ b/rust/src/model/object_type/mutation_root.rs @@ -66,11 +66,13 @@ impl MutationRoot { ) -> Result> { let mut store = ctx.data_unchecked::().write().await; - let ids = QueryRoot::filter_links(&*store, Some(_where)) + let ids: Vec<_> = QueryRoot::filter_links(&*store, Some(_where)) .await - .map(|link| link.index); + .map(|link| link.index) + .collect(); let returning: LinksResult> = ids + .into_iter() .map(move |id| -> LinksResult<_> { let link = store.try_get_link(id)?; store.delete(id)?; @@ -280,12 +282,11 @@ impl MutationRoot { if (link.source, link.target) != (from_id, to_id) { let id = store.update(id, from_id, to_id)?; - Ok(Link::new(id, from_id, to_id)) + Ok(Links(Link::new(id, from_id, to_id))) } else { - Ok(link) + Ok(Links(link)) } }) - .map(|result| result.map(|link| Links(link))) .collect(); returning .map(|s| Some(LinksMutationResponse(s))) From 63c17442e4aa78c565ef6beeb77597717c849880 Mon Sep 17 00:00:00 2001 From: FreePhoenix888 Date: Wed, 29 Jun 2022 14:43:30 +0600 Subject: [PATCH 07/22] Use self.0.iter() in iter() --- rust/src/store.rs | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/rust/src/store.rs b/rust/src/store.rs index df91d892..90e33a87 100644 --- a/rust/src/store.rs +++ b/rust/src/store.rs @@ -16,16 +16,15 @@ impl Store { } pub fn iter(&self) -> impl Iterator> + '_ { - // todo: - // self.0.iter() - let mut vec = SmallVec::<[_; 2]>::new(); - - self.try_each(|link| { - vec.push(link); - Continue - }); - - vec.into_iter() + self.0.iter() + // let mut vec = SmallVec::<[_; 2]>::new(); + // + // self.try_each(|link| { + // vec.push(link); + // Continue + // }); + // + // vec.into_iter() } pub fn each_iter<'a>( From d33e8485db0819b399e5f303a8ff1f3f9131b683 Mon Sep 17 00:00:00 2001 From: FreePhoenix888 Date: Wed, 29 Jun 2022 17:25:07 +0600 Subject: [PATCH 08/22] Implement distinct_on, limit, offset --- rust/src/model/object_type/query_root.rs | 35 ++++++++++++++++++++---- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/rust/src/model/object_type/query_root.rs b/rust/src/model/object_type/query_root.rs index 9d4f4f63..d9e89d5f 100644 --- a/rust/src/model/object_type/query_root.rs +++ b/rust/src/model/object_type/query_root.rs @@ -1,3 +1,4 @@ +use std::collections::HashMap; use crate::model::Can; use crate::model::CanAggregate; use crate::model::CanBoolExp; @@ -39,7 +40,7 @@ use crate::model::StringsSelectColumn; use crate::model::{Bigint, BigintComparisonExp, LinkType}; use crate::{store, RawStore, Store}; use async_graphql::*; -use doublets::{Doublets, Link}; +use doublets::{Doublet, Doublets, Link}; #[derive(Debug)] pub struct QueryRoot; @@ -118,10 +119,34 @@ impl QueryRoot { _where: Option>, ) -> Vec { let store = ctx.data_unchecked::().read().await; - Self::filter_links(&*store, _where) - .await - .map(|link| Links(link)) - .collect() + let mut links = Self::filter_links(&*store, _where) + .await; + if let Some(distinct_on) = distinct_on { + links = Box::new(links.map(|link| { + let mut distinct_fields = Vec::new(); + let mut distinct_fields_with_link = Vec::new(); + for link in links { + for distinct_on_item in distinct_on { + match distinct_on_item { + LinksSelectColumn::FromId => distinct_fields.push(link.source), + LinksSelectColumn::ToId => distinct_fields.push(link.target), + _ => {} + } + } + distinct_fields_with_link.push((&distinct_fields, link)) + } + distinct_fields_with_link.sort(); + distinct_fields_with_link.dedup_by(|(a, _), (b, _)| a.eq(b)); + distinct_fields_with_link.into_iter().map(|(_, link)| link) + })); + } + if let Some(offset) = offset { + links = Box::new(links.skip(offset as usize)); + } + if let Some(limit) = limit { + links = Box::new(links.take(limit as usize)); + } + links.map(|link| Links(link)).collect() } #[graphql(name = "links_aggregate")] From b4317329fa8845e174eed5cd1bb7e8fbe83b9c79 Mon Sep 17 00:00:00 2001 From: FreePhoenix888 Date: Wed, 29 Jun 2022 17:27:17 +0600 Subject: [PATCH 09/22] Dereference box --- rust/src/model/object_type/query_root.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/rust/src/model/object_type/query_root.rs b/rust/src/model/object_type/query_root.rs index d9e89d5f..bc39ffab 100644 --- a/rust/src/model/object_type/query_root.rs +++ b/rust/src/model/object_type/query_root.rs @@ -119,8 +119,8 @@ impl QueryRoot { _where: Option>, ) -> Vec { let store = ctx.data_unchecked::().read().await; - let mut links = Self::filter_links(&*store, _where) - .await; + let mut links = *(Self::filter_links(&*store, _where) + .await); if let Some(distinct_on) = distinct_on { links = Box::new(links.map(|link| { let mut distinct_fields = Vec::new(); @@ -141,10 +141,10 @@ impl QueryRoot { })); } if let Some(offset) = offset { - links = Box::new(links.skip(offset as usize)); + links = links.skip(offset as usize); } if let Some(limit) = limit { - links = Box::new(links.take(limit as usize)); + links = links.take(limit as usize); } links.map(|link| Links(link)).collect() } From 536a19d603cae70b244e8df67da88bf011f9fdc9 Mon Sep 17 00:00:00 2001 From: dodic Date: Wed, 29 Jun 2022 15:30:14 +0300 Subject: [PATCH 10/22] Implement `distinct_on` algorithm --- rust/Cargo.toml | 4 +- rust/src/model/distinct.rs | 32 ++++++++++++ .../model/enum_type/links_select_column.rs | 2 +- rust/src/model/mod.rs | 3 ++ rust/src/model/object_type/query_root.rs | 52 +++++++++---------- 5 files changed, 64 insertions(+), 29 deletions(-) create mode 100644 rust/src/model/distinct.rs diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 708892a9..425b4a3d 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -9,5 +9,5 @@ async-std = { version = "1.12", features = ["attributes"] } async-graphql = "4.0" actix-web = "4.0" async-graphql-actix-web = "4.0" -doublets = "0.1.0-beta.6" -smallvec = "1.8.0" +doublets = "0.1.0-beta.7" +smallvec = "1.8" diff --git a/rust/src/model/distinct.rs b/rust/src/model/distinct.rs new file mode 100644 index 00000000..b4ac380d --- /dev/null +++ b/rust/src/model/distinct.rs @@ -0,0 +1,32 @@ +use crate::model::LinkType; +use doublets::Link; +use std::hash::{Hash, Hasher}; + +pub struct DistinctWrapper { + matches: (LinkType, LinkType), + link: Link, +} + +impl DistinctWrapper { + pub fn from_match_link(matches: (LinkType, LinkType), link: Link) -> Self { + Self { matches, link } + } + + pub fn into_link(self) -> Link { + self.link + } +} + +impl Hash for DistinctWrapper { + fn hash(&self, state: &mut H) { + self.matches.hash(state) + } +} + +impl PartialEq for DistinctWrapper { + fn eq(&self, other: &Self) -> bool { + &self.matches == &other.matches + } +} + +impl Eq for DistinctWrapper {} diff --git a/rust/src/model/enum_type/links_select_column.rs b/rust/src/model/enum_type/links_select_column.rs index c4353b53..41e589ba 100644 --- a/rust/src/model/enum_type/links_select_column.rs +++ b/rust/src/model/enum_type/links_select_column.rs @@ -1,6 +1,6 @@ use async_graphql::*; -#[derive(Enum, Debug, Copy, Clone, Eq, PartialEq)] +#[derive(Enum, Debug, Copy, Clone, Eq, PartialEq, Hash)] #[graphql(name = "links_select_column")] pub enum LinksSelectColumn { #[graphql(name = "from_id")] diff --git a/rust/src/model/mod.rs b/rust/src/model/mod.rs index 5566f5db..013bc1ac 100644 --- a/rust/src/model/mod.rs +++ b/rust/src/model/mod.rs @@ -1,3 +1,4 @@ +mod distinct; mod enum_type; mod input_object_type; mod iterator; @@ -234,6 +235,8 @@ pub use scalar_type::Jsonb; pub use scalar_type::LinksOptionExt; use std::marker::PhantomData; +pub use distinct::DistinctWrapper; + pub type LinkType = u64; pub type LinksResult = Result>; diff --git a/rust/src/model/object_type/query_root.rs b/rust/src/model/object_type/query_root.rs index bc39ffab..f2c82c12 100644 --- a/rust/src/model/object_type/query_root.rs +++ b/rust/src/model/object_type/query_root.rs @@ -1,5 +1,3 @@ -use std::collections::HashMap; -use crate::model::Can; use crate::model::CanAggregate; use crate::model::CanBoolExp; use crate::model::CanOrderBy; @@ -38,9 +36,12 @@ use crate::model::StringsBoolExp; use crate::model::StringsOrderBy; use crate::model::StringsSelectColumn; use crate::model::{Bigint, BigintComparisonExp, LinkType}; +use crate::model::{Can, DistinctWrapper}; use crate::{store, RawStore, Store}; use async_graphql::*; use doublets::{Doublet, Doublets, Link}; +use itertools::Itertools; +use std::collections::{HashMap, HashSet}; #[derive(Debug)] pub struct QueryRoot; @@ -119,34 +120,33 @@ impl QueryRoot { _where: Option>, ) -> Vec { let store = ctx.data_unchecked::().read().await; - let mut links = *(Self::filter_links(&*store, _where) - .await); + let mut links = Self::filter_links(&*store, _where).await; if let Some(distinct_on) = distinct_on { - links = Box::new(links.map(|link| { - let mut distinct_fields = Vec::new(); - let mut distinct_fields_with_link = Vec::new(); - for link in links { - for distinct_on_item in distinct_on { - match distinct_on_item { - LinksSelectColumn::FromId => distinct_fields.push(link.source), - LinksSelectColumn::ToId => distinct_fields.push(link.target), - _ => {} + let distinct_on: HashSet<_> = distinct_on.into_iter().collect(); + links = box links + .map(move |link| { + let mut from_id = 0; + let mut to_id = 0; + for column in &distinct_on { + match column { + LinksSelectColumn::FromId => from_id = link.source, + LinksSelectColumn::ToId => to_id = link.target, + _ => { + todo!() + } } } - distinct_fields_with_link.push((&distinct_fields, link)) - } - distinct_fields_with_link.sort(); - distinct_fields_with_link.dedup_by(|(a, _), (b, _)| a.eq(b)); - distinct_fields_with_link.into_iter().map(|(_, link)| link) - })); - } - if let Some(offset) = offset { - links = links.skip(offset as usize); - } - if let Some(limit) = limit { - links = links.take(limit as usize); + DistinctWrapper::from_match_link((from_id, to_id), link) + }) + .collect::>() + .into_iter() + .map(DistinctWrapper::into_link) } - links.map(|link| Links(link)).collect() + links + .skip(offset.unwrap_or(0) as usize) + .take(limit.map(|x| x as usize).unwrap_or(usize::MAX)) + .map(|link| Links(link)) + .collect() } #[graphql(name = "links_aggregate")] From 588ab9233876115001069668f60c10553daa2b2f Mon Sep 17 00:00:00 2001 From: dodic Date: Tue, 5 Jul 2022 15:24:55 +0300 Subject: [PATCH 11/22] First steps in ordering --- rust/Cargo.toml | 1 + rust/src/main.rs | 1 + rust/src/model/enum_type/order_by.rs | 15 ++++++++++++ .../model/input_object_type/links_order_by.rs | 24 ++++++++++++++++++- rust/src/model/object_type/query_root.rs | 17 ++++++++++--- 5 files changed, 54 insertions(+), 4 deletions(-) diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 425b4a3d..945cdd78 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -11,3 +11,4 @@ actix-web = "4.0" async-graphql-actix-web = "4.0" doublets = "0.1.0-beta.7" smallvec = "1.8" +rayon = "1.5" \ No newline at end of file diff --git a/rust/src/main.rs b/rust/src/main.rs index 95c60dd3..e44229f2 100644 --- a/rust/src/main.rs +++ b/rust/src/main.rs @@ -2,6 +2,7 @@ #![feature(result_flattening)] #![feature(box_syntax)] #![feature(try_trait_v2)] +#![feature(iter_order_by)] mod model; mod store; diff --git a/rust/src/model/enum_type/order_by.rs b/rust/src/model/enum_type/order_by.rs index df413e74..cd05c935 100644 --- a/rust/src/model/enum_type/order_by.rs +++ b/rust/src/model/enum_type/order_by.rs @@ -1,4 +1,6 @@ +use crate::model::LinkType; use async_graphql::*; +use std::cmp::Ordering; #[derive(Enum, Debug, Copy, Clone, Eq, PartialEq)] #[graphql(name = "order_by")] @@ -16,3 +18,16 @@ pub enum OrderBy { #[graphql(name = "desc_nulls_last")] DescNullsLast, } + +impl OrderBy { + pub fn matches(&self, a: LinkType, b: LinkType) -> Ordering { + match self { + OrderBy::Asc => a.cmp(&b), + OrderBy::AscNullsFirst => a.cmp(&b), + OrderBy::AscNullsLast => b.cmp(&b), + OrderBy::Desc => b.cmp(&a), + OrderBy::DescNullsFirst => b.cmp(&a), + OrderBy::DescNullsLast => b.cmp(&a), + } + } +} diff --git a/rust/src/model/input_object_type/links_order_by.rs b/rust/src/model/input_object_type/links_order_by.rs index 6f921114..39e0a314 100644 --- a/rust/src/model/input_object_type/links_order_by.rs +++ b/rust/src/model/input_object_type/links_order_by.rs @@ -1,4 +1,3 @@ -use crate::model::CanAggregateOrderBy; use crate::model::LinksAggregateOrderBy; use crate::model::MpAggregateOrderBy; use crate::model::NumbersOrderBy; @@ -6,7 +5,10 @@ use crate::model::ObjectsOrderBy; use crate::model::OrderBy; use crate::model::SelectorsAggregateOrderBy; use crate::model::StringsOrderBy; +use crate::model::{CanAggregateOrderBy, LinkType}; use async_graphql::*; +use doublets::Link; +use std::cmp::Ordering; #[derive(InputObject, Debug)] #[graphql(name = "links_order_by")] @@ -52,3 +54,23 @@ pub struct LinksOrderBy { pub typed_aggregate: Option, pub value: Option, } + +impl LinksOrderBy { + pub fn matches(&self, a: &Link, b: &Link) -> Ordering { + let mut ord = Ordering::Equal; + + if let Some(id) = self.id { + ord = ord.then_with(|| id.matches(a.index, b.index)); + } + + if let Some(from_id) = self.from_id { + ord = ord.then_with(|| from_id.matches(a.source, b.source)); + } + + if let Some(to_id) = self.to_id { + ord = ord.then_with(|| to_id.matches(a.target, b.target)); + } + + ord + } +} diff --git a/rust/src/model/object_type/query_root.rs b/rust/src/model/object_type/query_root.rs index f2c82c12..0078af82 100644 --- a/rust/src/model/object_type/query_root.rs +++ b/rust/src/model/object_type/query_root.rs @@ -40,7 +40,8 @@ use crate::model::{Can, DistinctWrapper}; use crate::{store, RawStore, Store}; use async_graphql::*; use doublets::{Doublet, Doublets, Link}; -use itertools::Itertools; +use rayon::prelude::*; +use std::cmp::Ordering; use std::collections::{HashMap, HashSet}; #[derive(Debug)] @@ -142,11 +143,21 @@ impl QueryRoot { .into_iter() .map(DistinctWrapper::into_link) } - links + let mut links: Vec<_> = links .skip(offset.unwrap_or(0) as usize) .take(limit.map(|x| x as usize).unwrap_or(usize::MAX)) .map(|link| Links(link)) - .collect() + .collect(); + + if let Some(order_by) = order_by { + links.par_sort_unstable_by(|a, b| { + order_by.iter().fold(Ordering::Equal, |ord, order| { + ord.then_with(|| order.matches(&a.0, &b.0)) + }) + }) + } + + links } #[graphql(name = "links_aggregate")] From dd9c55ae1dfca8bceec1a3c84ae2d374f1ca866c Mon Sep 17 00:00:00 2001 From: dodic Date: Tue, 5 Jul 2022 15:25:21 +0300 Subject: [PATCH 12/22] Remove useless feature --- rust/src/main.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/rust/src/main.rs b/rust/src/main.rs index e44229f2..95c60dd3 100644 --- a/rust/src/main.rs +++ b/rust/src/main.rs @@ -2,7 +2,6 @@ #![feature(result_flattening)] #![feature(box_syntax)] #![feature(try_trait_v2)] -#![feature(iter_order_by)] mod model; mod store; From ecff7e980b2d5da3c594e590cff1389f18918061 Mon Sep 17 00:00:00 2001 From: dodic Date: Tue, 5 Jul 2022 15:29:32 +0300 Subject: [PATCH 13/22] Fix copilot typo --- rust/src/model/enum_type/order_by.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust/src/model/enum_type/order_by.rs b/rust/src/model/enum_type/order_by.rs index cd05c935..68b4e2cc 100644 --- a/rust/src/model/enum_type/order_by.rs +++ b/rust/src/model/enum_type/order_by.rs @@ -24,7 +24,7 @@ impl OrderBy { match self { OrderBy::Asc => a.cmp(&b), OrderBy::AscNullsFirst => a.cmp(&b), - OrderBy::AscNullsLast => b.cmp(&b), + OrderBy::AscNullsLast => a.cmp(&b), OrderBy::Desc => b.cmp(&a), OrderBy::DescNullsFirst => b.cmp(&a), OrderBy::DescNullsLast => b.cmp(&a), From 121dc9b56a7065b4cfd9092cbd78088cdb589c78 Mon Sep 17 00:00:00 2001 From: dodic Date: Tue, 5 Jul 2022 15:45:37 +0300 Subject: [PATCH 14/22] Use unsafe magic --- rust/src/model/object_type/links.rs | 1 + rust/src/model/object_type/query_root.rs | 13 ++++++------- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/rust/src/model/object_type/links.rs b/rust/src/model/object_type/links.rs index d4e17f90..4bd956b1 100644 --- a/rust/src/model/object_type/links.rs +++ b/rust/src/model/object_type/links.rs @@ -30,6 +30,7 @@ use async_graphql::*; use doublets::Doublets; #[derive(Debug, Clone)] +#[repr(transparent)] pub struct Links(pub doublets::Link); #[Object(name = "links")] diff --git a/rust/src/model/object_type/query_root.rs b/rust/src/model/object_type/query_root.rs index 0078af82..45d4c9d7 100644 --- a/rust/src/model/object_type/query_root.rs +++ b/rust/src/model/object_type/query_root.rs @@ -43,6 +43,7 @@ use doublets::{Doublet, Doublets, Link}; use rayon::prelude::*; use std::cmp::Ordering; use std::collections::{HashMap, HashSet}; +use std::mem::ManuallyDrop; #[derive(Debug)] pub struct QueryRoot; @@ -143,21 +144,19 @@ impl QueryRoot { .into_iter() .map(DistinctWrapper::into_link) } - let mut links: Vec<_> = links - .skip(offset.unwrap_or(0) as usize) - .take(limit.map(|x| x as usize).unwrap_or(usize::MAX)) - .map(|link| Links(link)) - .collect(); + let mut links: Vec<_> = links.collect(); if let Some(order_by) = order_by { links.par_sort_unstable_by(|a, b| { order_by.iter().fold(Ordering::Equal, |ord, order| { - ord.then_with(|| order.matches(&a.0, &b.0)) + ord.then_with(|| order.matches(a, b)) }) }) } - links + let mut vec = ManuallyDrop::new(links); + // SAFETY: `Links` is transparent to `Link` and old `vec` is forgot + unsafe { Vec::from_raw_parts(vec.as_mut_ptr().cast(), vec.len(), vec.capacity()) } } #[graphql(name = "links_aggregate")] From 3bedae999eb4986cbae02ebf1159f20b4febfc53 Mon Sep 17 00:00:00 2001 From: dodic Date: Tue, 5 Jul 2022 15:50:13 +0300 Subject: [PATCH 15/22] Fix `LinkType` mismatching --- rust/src/model/mod.rs | 2 +- rust/src/model/object_type/links.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rust/src/model/mod.rs b/rust/src/model/mod.rs index 013bc1ac..5d4bd3ba 100644 --- a/rust/src/model/mod.rs +++ b/rust/src/model/mod.rs @@ -238,7 +238,7 @@ use std::marker::PhantomData; pub use distinct::DistinctWrapper; pub type LinkType = u64; -pub type LinksResult = Result>; +pub type LinksResult = Result>; struct LinkTypeAssert(PhantomData); diff --git a/rust/src/model/object_type/links.rs b/rust/src/model/object_type/links.rs index 4bd956b1..4bf8794a 100644 --- a/rust/src/model/object_type/links.rs +++ b/rust/src/model/object_type/links.rs @@ -1,4 +1,3 @@ -use crate::model::Bigint; use crate::model::Can; use crate::model::CanAggregate; use crate::model::CanBoolExp; @@ -25,13 +24,14 @@ use crate::model::SelectorsOrderBy; use crate::model::SelectorsSelectColumn; use crate::model::Strings; use crate::model::UpLinksArgs; +use crate::model::{Bigint, LinkType}; use crate::Store; use async_graphql::*; use doublets::Doublets; #[derive(Debug, Clone)] #[repr(transparent)] -pub struct Links(pub doublets::Link); +pub struct Links(pub doublets::Link); #[Object(name = "links")] impl Links { From ff0e0eccfe4b592a17f3f64822a7a06cf2cfe72f Mon Sep 17 00:00:00 2001 From: dodic Date: Tue, 5 Jul 2022 20:33:16 +0300 Subject: [PATCH 16/22] Fix limit/offset mismatching --- rust/src/model/object_type/query_root.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/rust/src/model/object_type/query_root.rs b/rust/src/model/object_type/query_root.rs index 45d4c9d7..53779a88 100644 --- a/rust/src/model/object_type/query_root.rs +++ b/rust/src/model/object_type/query_root.rs @@ -116,11 +116,13 @@ impl QueryRoot { &self, ctx: &Context<'_>, #[graphql(name = "distinct_on")] distinct_on: Option>, - limit: Option, - offset: Option, + limit: Option, + offset: Option, #[graphql(name = "order_by")] order_by: Option>, _where: Option>, ) -> Vec { + let offset = offset.unwrap_or(0); + let limit = limit.unwrap_or(usize::MAX); let store = ctx.data_unchecked::().read().await; let mut links = Self::filter_links(&*store, _where).await; if let Some(distinct_on) = distinct_on { @@ -157,6 +159,10 @@ impl QueryRoot { let mut vec = ManuallyDrop::new(links); // SAFETY: `Links` is transparent to `Link` and old `vec` is forgot unsafe { Vec::from_raw_parts(vec.as_mut_ptr().cast(), vec.len(), vec.capacity()) } + .into_par_iter() + .skip(offset) + .take(limit) + .collect() } #[graphql(name = "links_aggregate")] From 82e616acdce8881723d0b25b06cd323d0d57c573 Mon Sep 17 00:00:00 2001 From: dodic Date: Wed, 6 Jul 2022 12:10:57 +0300 Subject: [PATCH 17/22] Remove unsafe magic --- rust/src/model/object_type/query_root.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/rust/src/model/object_type/query_root.rs b/rust/src/model/object_type/query_root.rs index 53779a88..556fef96 100644 --- a/rust/src/model/object_type/query_root.rs +++ b/rust/src/model/object_type/query_root.rs @@ -156,9 +156,9 @@ impl QueryRoot { }) } - let mut vec = ManuallyDrop::new(links); - // SAFETY: `Links` is transparent to `Link` and old `vec` is forgot - unsafe { Vec::from_raw_parts(vec.as_mut_ptr().cast(), vec.len(), vec.capacity()) } + links + .into_par_iter() + .map(Links) .into_par_iter() .skip(offset) .take(limit) From d8dbf92df9c27228443c58b334ee9ff0cb2d9dc3 Mon Sep 17 00:00:00 2001 From: dodic Date: Mon, 11 Jul 2022 11:06:56 +0300 Subject: [PATCH 18/22] Necessary `.into_par_iter` --- rust/src/model/object_type/query_root.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/rust/src/model/object_type/query_root.rs b/rust/src/model/object_type/query_root.rs index 556fef96..adeef970 100644 --- a/rust/src/model/object_type/query_root.rs +++ b/rust/src/model/object_type/query_root.rs @@ -159,7 +159,6 @@ impl QueryRoot { links .into_par_iter() .map(Links) - .into_par_iter() .skip(offset) .take(limit) .collect() From 73ba856d652994928911312ac2d002529229441e Mon Sep 17 00:00:00 2001 From: dodic Date: Thu, 14 Jul 2022 11:37:53 +0300 Subject: [PATCH 19/22] Update server to modern doublets api --- rust/Cargo.toml | 5 +- rust/src/main.rs | 16 ++--- .../bigint_comparison_exp.rs | 1 - .../model/input_object_type/links_bool_exp.rs | 4 +- rust/src/model/mod.rs | 4 +- rust/src/model/object_type/mutation_root.rs | 2 +- rust/src/model/object_type/query_root.rs | 2 +- rust/src/store.rs | 71 ++++++++++--------- 8 files changed, 55 insertions(+), 50 deletions(-) diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 945cdd78..b46a2294 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -9,6 +9,7 @@ async-std = { version = "1.12", features = ["attributes"] } async-graphql = "4.0" actix-web = "4.0" async-graphql-actix-web = "4.0" -doublets = "0.1.0-beta.7" +doublets = "0.1.0-beta.14" smallvec = "1.8" -rayon = "1.5" \ No newline at end of file +rayon = "1.5" +itertools = "0.10.3" diff --git a/rust/src/main.rs b/rust/src/main.rs index 95c60dd3..414261ab 100644 --- a/rust/src/main.rs +++ b/rust/src/main.rs @@ -7,10 +7,9 @@ mod model; mod store; use crate::model::{ - Links, LinksInsertInput, LinksMutationResponse, LinksOnConflict, LinksOptionExt, MutationRoot, - QueryRoot, + LinkType, Links, LinksInsertInput, LinksMutationResponse, LinksOnConflict, LinksOptionExt, + MutationRoot, QueryRoot, }; -use crate::store::RawStore; use actix_web::{guard, web, App, HttpResponse, HttpServer, Responder}; use async_graphql::{ http::{playground_source, GraphQLPlaygroundConfig}, @@ -19,11 +18,11 @@ use async_graphql::{ use async_graphql_actix_web::{GraphQLRequest, GraphQLResponse}; use async_std::sync::RwLock; use doublets::mem::FileMappedMem; -use doublets::{split, Link}; +use doublets::{split, Doublets, Link}; use std::{error::Error, fs::File, io, path::Path}; -// todo: wait for fix type infer -type Store = RwLock; +type RawStore = Box>; +type Store = RwLock; type Schema = async_graphql::Schema; async fn index(schema: web::Data, req: GraphQLRequest) -> GraphQLResponse { @@ -51,8 +50,9 @@ fn map_db_file>(path: P) -> io::Result for LinksError async fn main() -> Result<(), Box> { - let store = RawStore::new(map_db_file("db.links")?, map_db_file("index.links")?)?; - let store = store::Store::new(store); + let store = + split::Store::::new(map_db_file("db.links")?, map_db_file("index.links")?)?; + let store: Box> = box store::Store::new(store); let schema = Schema::build(QueryRoot, MutationRoot, EmptySubscription) .data(Store::new(store)) .finish(); diff --git a/rust/src/model/input_object_type/bigint_comparison_exp.rs b/rust/src/model/input_object_type/bigint_comparison_exp.rs index 3829a893..e2ebe7e3 100644 --- a/rust/src/model/input_object_type/bigint_comparison_exp.rs +++ b/rust/src/model/input_object_type/bigint_comparison_exp.rs @@ -1,5 +1,4 @@ use crate::model::{Bigint, LinkType}; -use crate::RawStore; use async_graphql::*; use doublets::Doublets; diff --git a/rust/src/model/input_object_type/links_bool_exp.rs b/rust/src/model/input_object_type/links_bool_exp.rs index 1f899b9b..3dcbbacb 100644 --- a/rust/src/model/input_object_type/links_bool_exp.rs +++ b/rust/src/model/input_object_type/links_bool_exp.rs @@ -7,7 +7,7 @@ use crate::model::ObjectsBoolExp; use crate::model::SelectorsBoolExp; use crate::model::StringsBoolExp; use crate::model::{BigintComparisonExp, LinkType}; -use crate::{store, RawStore}; +use crate::RawStore; use async_graphql::*; use doublets::{Doublets, Link}; @@ -58,7 +58,7 @@ pub struct LinksBoolExp { } impl LinksBoolExp { - pub fn matches(&self, store: &store::Store, link: &Link) -> bool { + pub fn matches(&self, store: &RawStore, link: &Link) -> bool { let mut exp = true; if let Some(id) = &self.id { diff --git a/rust/src/model/mod.rs b/rust/src/model/mod.rs index 5d4bd3ba..d1156493 100644 --- a/rust/src/model/mod.rs +++ b/rust/src/model/mod.rs @@ -5,7 +5,7 @@ mod iterator; mod object_type; mod scalar_type; -use doublets::data::LinksError; +use doublets::data::Error; pub use enum_type::CanSelectColumn; pub use enum_type::LinksConstraint; pub use enum_type::LinksSelectColumn; @@ -238,7 +238,7 @@ use std::marker::PhantomData; pub use distinct::DistinctWrapper; pub type LinkType = u64; -pub type LinksResult = Result>; +pub type LinksResult = Result>; struct LinkTypeAssert(PhantomData); diff --git a/rust/src/model/object_type/mutation_root.rs b/rust/src/model/object_type/mutation_root.rs index 6996a1ef..9082213f 100644 --- a/rust/src/model/object_type/mutation_root.rs +++ b/rust/src/model/object_type/mutation_root.rs @@ -46,7 +46,7 @@ use crate::model::{Bigint, LinksResult}; use crate::model::{LinkType, Links}; use crate::{QueryRoot, Store}; use async_graphql::*; -use doublets::data::{LinksError, Query}; +use doublets::data::{Error, Query}; use doublets::{Doublets, Link}; use smallvec::{smallvec, SmallVec}; use std::io::{Read, Write}; diff --git a/rust/src/model/object_type/query_root.rs b/rust/src/model/object_type/query_root.rs index adeef970..0cb778ca 100644 --- a/rust/src/model/object_type/query_root.rs +++ b/rust/src/model/object_type/query_root.rs @@ -82,7 +82,7 @@ impl QueryRoot { #[graphql(skip)] pub(crate) async fn filter_links( - store: &store::Store, + store: &RawStore, _where: Option>, ) -> Box> + '_> { let fast_param_impl = |param: Option<&BigintComparisonExp>| -> LinkType { diff --git a/rust/src/store.rs b/rust/src/store.rs index 74333f1f..02da09fe 100644 --- a/rust/src/store.rs +++ b/rust/src/store.rs @@ -1,22 +1,16 @@ use crate::model::{LinkType, LinksResult}; +use doublets::data::{Flow, ReadHandler, WriteHandler}; use doublets::{ - data::{Flow::Continue, LinksConstants, LinksError, ToQuery}, + data::{Flow::Continue, LinksConstants, ToQuery}, mem::FileMappedMem, - parts, split, Doublets, Link, + parts, split, Doublets, Error, Link, Links, }; use smallvec::SmallVec; use std::ops::Try; -pub type RawStore = split::Store< - LinkType, - FileMappedMem>, - FileMappedMem>, ->; -type Inner = RawStore; +pub struct Store(Inner); -pub struct Store(Inner); - -impl Store { +impl> Store { pub fn new(inner: Inner) -> Self { Self(inner) } @@ -33,41 +27,52 @@ impl Store { } } -impl Doublets for Store { - fn constants(&self) -> LinksConstants { +impl> Links for Store { + fn constants(&self) -> &LinksConstants { self.0.constants() } - fn count_by(&self, query: impl ToQuery) -> LinkType { - self.0.count_by(query) + fn count_links(&self, query: &[LinkType]) -> LinkType { + self.0.count_links(query) } - fn create_by_with( + fn create_links( &mut self, - query: impl ToQuery, - handler: F, - ) -> Result> - where - F: FnMut(Link, Link) -> R, - R: Try, - { - self.0.create_by_with(query, handler) + query: &[LinkType], + handler: WriteHandler, + ) -> Result> { + self.0.create_links(query, handler) } - fn try_each_by(&self, restrictions: impl ToQuery, handler: F) -> R - where - F: FnMut(Link) -> R, - R: Try, - { - self.0.try_each_by(restrictions, handler) + fn each_links(&self, query: &[LinkType], handler: ReadHandler) -> Flow { + self.0.each_links(query, handler) + } + + fn update_links( + &mut self, + query: &[LinkType], + change: &[LinkType], + handler: WriteHandler, + ) -> Result> { + self.0.update_links(query, change, handler) } + fn delete_links( + &mut self, + query: &[LinkType], + handler: WriteHandler, + ) -> Result> { + self.0.delete_links(query, handler) + } +} + +impl> Doublets for Store { fn update_by_with( &mut self, query: impl ToQuery, replacement: impl ToQuery, mut handler: F, - ) -> Result> + ) -> Result> where F: FnMut(Link, Link) -> R, R: Try, @@ -75,7 +80,7 @@ impl Doublets for Store { let query = query.to_query(); let replacement = replacement.to_query(); - let constants = self.constants(); + let constants = self.constants().clone(); let store = &mut self.0; let (new, from_id, to_id) = ( query[constants.index_part as usize], @@ -97,7 +102,7 @@ impl Doublets for Store { &mut self, query: impl ToQuery, mut handler: F, - ) -> Result> + ) -> Result> where F: FnMut(Link, Link) -> R, R: Try, From 5fb007c562fb6a915bcc50c353d2f99081e76779 Mon Sep 17 00:00:00 2001 From: dodic Date: Sat, 6 Aug 2022 19:43:51 +0300 Subject: [PATCH 20/22] Use `doublets` from git latest --- rust/Cargo.toml | 2 +- rust/src/main.rs | 12 +++--------- rust/src/model/mod.rs | 2 +- rust/src/store.rs | 2 +- 4 files changed, 6 insertions(+), 12 deletions(-) diff --git a/rust/Cargo.toml b/rust/Cargo.toml index b46a2294..55261ba3 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -9,7 +9,7 @@ async-std = { version = "1.12", features = ["attributes"] } async-graphql = "4.0" actix-web = "4.0" async-graphql-actix-web = "4.0" -doublets = "0.1.0-beta.14" +doublets = { git = "https://github.com/linksplatform/doublets-rs" } smallvec = "1.8" rayon = "1.5" itertools = "0.10.3" diff --git a/rust/src/main.rs b/rust/src/main.rs index 414261ab..324642a7 100644 --- a/rust/src/main.rs +++ b/rust/src/main.rs @@ -17,7 +17,7 @@ use async_graphql::{ }; use async_graphql_actix_web::{GraphQLRequest, GraphQLResponse}; use async_std::sync::RwLock; -use doublets::mem::FileMappedMem; +use doublets::mem::FileMapped; use doublets::{split, Doublets, Link}; use std::{error::Error, fs::File, io, path::Path}; @@ -37,14 +37,8 @@ async fn index_playground() -> actix_web::Result { } // todo: may be add support async-std files to platform-mem -fn map_db_file>(path: P) -> io::Result> { - File::options() - .create(true) - .read(true) - .write(true) - .open(path) - .map(FileMappedMem::new) - .flatten() +fn map_db_file>(path: P) -> io::Result> { + FileMapped::from_path(path) } #[tokio::main] diff --git a/rust/src/model/mod.rs b/rust/src/model/mod.rs index d1156493..01db9c8b 100644 --- a/rust/src/model/mod.rs +++ b/rust/src/model/mod.rs @@ -240,7 +240,7 @@ pub use distinct::DistinctWrapper; pub type LinkType = u64; pub type LinksResult = Result>; -struct LinkTypeAssert(PhantomData); +struct LinkTypeAssert(PhantomData); #[allow(dead_code)] #[allow(non_camel_case_types)] diff --git a/rust/src/store.rs b/rust/src/store.rs index 02da09fe..01912718 100644 --- a/rust/src/store.rs +++ b/rust/src/store.rs @@ -2,7 +2,7 @@ use crate::model::{LinkType, LinksResult}; use doublets::data::{Flow, ReadHandler, WriteHandler}; use doublets::{ data::{Flow::Continue, LinksConstants, ToQuery}, - mem::FileMappedMem, + mem::FileMapped, parts, split, Doublets, Error, Link, Links, }; use smallvec::SmallVec; From 5fa44d87cc5d4e826f5204e2d8d76c21bea375ed Mon Sep 17 00:00:00 2001 From: dodic Date: Sat, 6 Aug 2022 21:10:12 +0300 Subject: [PATCH 21/22] Add `mimalloc` as global allocator feature --- rust/Cargo.toml | 13 ++++++++++--- rust/src/main.rs | 4 ++++ 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 55261ba3..16f248bd 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -4,12 +4,19 @@ version = "0.1.0" edition = "2021" [dependencies] -tokio = { version = "1.19", features = ["full"] } -async-std = { version = "1.12", features = ["attributes"] } async-graphql = "4.0" actix-web = "4.0" async-graphql-actix-web = "4.0" -doublets = { git = "https://github.com/linksplatform/doublets-rs" } smallvec = "1.8" rayon = "1.5" itertools = "0.10.3" + +tokio = { version = "1.19", features = ["full"] } +async-std = { version = "1.12", features = ["attributes"] } + +doublets = { git = "https://github.com/linksplatform/doublets-rs" } + +mimalloc = { version = "0.1", default-features = false, optional = true } + +[features] +default = ["mimalloc"] \ No newline at end of file diff --git a/rust/src/main.rs b/rust/src/main.rs index 324642a7..c62ebcc1 100644 --- a/rust/src/main.rs +++ b/rust/src/main.rs @@ -64,3 +64,7 @@ async fn main() -> Result<(), Box> { .await .map_err(|e| e.into()) } + +#[cfg(feature = "mimalloc")] +#[global_allocator] +static MIMALLOC: mimalloc::MiMalloc = mimalloc::MiMalloc; From cd5f5c08f9b9b6a69375f742aecb797e53054e20 Mon Sep 17 00:00:00 2001 From: dodic Date: Sun, 7 Aug 2022 16:09:49 +0300 Subject: [PATCH 22/22] Add `jemalloc` feature for `linux-x86_64` --- rust/Cargo.toml | 20 +++++++++++--------- rust/src/main.rs | 3 +++ 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 16f248bd..bfa2451b 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -4,19 +4,21 @@ version = "0.1.0" edition = "2021" [dependencies] -async-graphql = "4.0" -actix-web = "4.0" -async-graphql-actix-web = "4.0" -smallvec = "1.8" -rayon = "1.5" -itertools = "0.10.3" +actix-web = { version = "4.1.0" } +async-graphql = { version = "4.0.6" } +async-graphql-actix-web = { version = "4.0.6" } +itertools = { version = "0.10.3" } +smallvec = { version = "1.9.0" } +rayon = { version = "1.5.3" } -tokio = { version = "1.19", features = ["full"] } -async-std = { version = "1.12", features = ["attributes"] } +tokio = { version = "1.19", features = ["macros", "rt-multi-thread"] } doublets = { git = "https://github.com/linksplatform/doublets-rs" } mimalloc = { version = "0.1", default-features = false, optional = true } +[target.'cfg(all(target_os = "linux", target_arch = "x86_64"))'.dependencies] +jemalloc = { package = "tikv-jemallocator", version = "0.5.0", optional = true } + [features] -default = ["mimalloc"] \ No newline at end of file +default = ["mimalloc"] diff --git a/rust/src/main.rs b/rust/src/main.rs index c62ebcc1..cdf3de52 100644 --- a/rust/src/main.rs +++ b/rust/src/main.rs @@ -68,3 +68,6 @@ async fn main() -> Result<(), Box> { #[cfg(feature = "mimalloc")] #[global_allocator] static MIMALLOC: mimalloc::MiMalloc = mimalloc::MiMalloc; + +#[cfg(feature = "jemalloc")] +static JEMALLOC: jemalloc::Jemalloc = jemalloc::Jemalloc;