Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions codegen/src/name_generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@ impl WorktableNameGenerator {
Ident::new(format!("{}Wrapper", self.name).as_str(), Span::mixed_site())
}

pub fn get_lock_type_ident(&self) -> Ident {
Ident::new(format!("{}Lock", self.name).as_str(), Span::mixed_site())
}

pub fn get_index_type_ident(&self) -> Ident {
Ident::new(format!("{}Index", self.name).as_str(), Span::mixed_site())
}
Expand Down
157 changes: 157 additions & 0 deletions codegen/src/worktable/generator/locks.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
use crate::name_generator::WorktableNameGenerator;
use crate::worktable::generator::Generator;
use proc_macro2::{Ident, Span, TokenStream};
use quote::quote;

impl Generator {
pub fn gen_locks_def(&self) -> TokenStream {
let type_ = self.gen_locks_type();
let impl_ = self.gen_locks_impl();

quote! {
#type_
#impl_

}
}

fn gen_locks_type(&self) -> TokenStream {
let name_generator = WorktableNameGenerator::from_table_name(self.name.to_string());
let lock_ident = name_generator.get_lock_type_ident();

let rows: Vec<_> = self
.columns
.columns_map
.keys()
.map(|i| {
let name = Ident::new(format!("{i}_lock").as_str(), Span::mixed_site());
quote! { #name: Option<std::sync::Arc<Lock>>, }
})
.collect();

quote! {
#[derive(Debug, Clone)]
pub struct #lock_ident {
id: u16,
lock: Option<std::sync::Arc<Lock>>,
#(#rows)*
}
}
}

fn gen_locks_impl(&self) -> TokenStream {
let name_generator = WorktableNameGenerator::from_table_name(self.name.to_string());
let lock_ident = name_generator.get_lock_type_ident();

let new_fn = self.gen_new_fn();
let with_lock_fn = self.gen_with_lock_fn();
let lock_await_fn = self.gen_lock_await_fn();
let unlock_fn = self.gen_unlock_fn();

quote! {
impl #lock_ident {
#new_fn
#with_lock_fn
#lock_await_fn
#unlock_fn
}
}
}

fn gen_new_fn(&self) -> TokenStream {
let rows: Vec<_> = self
.columns
.columns_map
.keys()
.map(|i| {
let col = Ident::new(format!("{i}_lock").as_str(), Span::mixed_site());
quote! { #col: None }
})
.collect();

quote! {
pub fn new(lock_id: u16) -> Self {
Self {
id: lock_id,
lock: None,
#(#rows),*
}
}
}
}

fn gen_with_lock_fn(&self) -> TokenStream {
let rows: Vec<_> = self
.columns
.columns_map
.keys()
.map(|i| {
let col = Ident::new(format!("{i}_lock").as_str(), Span::mixed_site());
quote! { #col: Some(std::sync::Arc::new(Lock::new())) }
})
.collect();

quote! {
pub fn with_lock(lock_id: u16) -> Self {
Self {
id: lock_id,
lock: Some(std::sync::Arc::new(Lock::new())),
#(#rows),*
}
}
}
}

fn gen_lock_await_fn(&self) -> TokenStream {
let rows: Vec<_> = self
.columns
.columns_map
.keys()
.map(|col| {
let col = Ident::new(format!("{}_lock", col).as_str(), Span::mixed_site());
quote! {
if let Some(lock) = &self.#col {
futures.push(lock.as_ref());
}
}
})
.collect();
quote! {
pub async fn lock_await(&self) {
let mut futures = Vec::new();

if let Some(lock) = &self.lock {
futures.push(lock.as_ref());
}
#(#rows)*
futures::future::join_all(futures).await;
}
}
}

fn gen_unlock_fn(&self) -> TokenStream {
let rows: Vec<_> = self
.columns
.columns_map
.keys()
.map(|col| {
let col = Ident::new(format!("{}_lock", col).as_str(), Span::mixed_site());
quote! {
if let Some(#col) = &self.#col {
#col.unlock();
}
}
})
.collect();

quote! {
pub fn unlock(&self) {
if let Some(lock) = &self.lock {
lock.unlock();
}
#(#rows)*
}

}
}
}
1 change: 1 addition & 0 deletions codegen/src/worktable/generator/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
mod index;
mod locks;
mod primary_key;
mod queries;
mod row;
Expand Down
3 changes: 2 additions & 1 deletion codegen/src/worktable/generator/primary_key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,8 @@ impl Generator {
Into,
PartialEq,
PartialOrd,
Ord
Hash,
Ord,
)]
pub struct #ident(#(#types),*);
}
Expand Down
23 changes: 15 additions & 8 deletions codegen/src/worktable/generator/queries/delete.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,27 +34,34 @@ impl Generator {
fn gen_full_row_delete(&mut self) -> TokenStream {
let pk_ident = &self.pk.as_ref().unwrap().ident;

let name_generator = WorktableNameGenerator::from_table_name(self.name.to_string());
let lock_ident = name_generator.get_lock_type_ident();

quote! {
pub async fn delete(&self, pk: #pk_ident) -> core::result::Result<(), WorkTableError> {

if let Some(lock) = self.0.lock_map.get(&pk) {
lock.lock_await().await; // Waiting for all locks released
}

let lock_id = self.0.lock_map.next_id();
let lock = std::sync::Arc::new(#lock_ident::with_lock(lock_id.into())); //Creates new LockType with None
self.0.lock_map.insert(pk.clone(), lock.clone()); // adds LockType to LockMap

let link = self.0
.pk_map
.get(&pk)
.map(|v| v.get().value)
.ok_or(WorkTableError::NotFound)?;

let id = self.0.data.with_ref(link, |archived| {
archived.is_locked()
}).map_err(WorkTableError::PagesError)?;
if let Some(id) = id {
if let Some(lock) = self.0.lock_map.get(&(id.into())) {
lock.as_ref().await
}
}
let row = self.select(pk.clone()).unwrap();
self.0.indexes.delete_row(row, link)?;
self.0.pk_map.remove(&pk);
self.0.data.delete(link).map_err(WorkTableError::PagesError)?;

lock.unlock(); // Releases locks
self.0.lock_map.remove(&pk); // Removes locks

core::result::Result::Ok(())
}
}
Expand Down
83 changes: 30 additions & 53 deletions codegen/src/worktable/generator/queries/locks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,7 @@ impl Generator {
pub fn gen_query_locks_impl(&mut self) -> syn::Result<TokenStream> {
if let Some(q) = &self.queries {
let name_generator = WorktableNameGenerator::from_table_name(self.name.to_string());
let wrapper_name = name_generator.get_wrapper_type_ident();
let archived_wrapper = Ident::new(
format!("Archived{}", &wrapper_name).as_str(),
Span::mixed_site(),
);
let lock_type_ident = name_generator.get_lock_type_ident();

let fns = q
.updates
Expand All @@ -23,32 +19,22 @@ impl Generator {
.from_case(Case::Pascal)
.to_case(Case::Snake);

let check_ident = Ident::new(
format!("check_{snake_case_name}_lock").as_str(),
let lock_await_ident = Ident::new(
format!("lock_await_{snake_case_name}").as_str(),
Span::mixed_site(),
);
let checks = q
.updates
.get(name)
.expect("exists")
.columns
.iter()
.map(|col| {
let col =
Ident::new(format!("{}_lock", col).as_str(), Span::mixed_site());
quote! {
if self.#col != 0 {
return Some(self.#col.into());
}
}
})
.collect::<Vec<_>>();

let lock_ident = Ident::new(
format!("lock_{snake_case_name}").as_str(),
Span::mixed_site(),
);
let locks = q

let unlock_ident = Ident::new(
format!("unlock_{snake_case_name}").as_str(),
Span::mixed_site(),
);

let rows_lock_await = q
.updates
.get(name)
.expect("exists")
Expand All @@ -58,16 +44,14 @@ impl Generator {
let col =
Ident::new(format!("{}_lock", col).as_str(), Span::mixed_site());
quote! {
self.#col = id.into();
if let Some(lock) = &self.#col {
futures.push(lock.as_ref());
}
}
})
.collect::<Vec<_>>();

let unlock_ident = Ident::new(
format!("unlock_{snake_case_name}").as_str(),
Span::mixed_site(),
);
let unlocks = q
let rows_lock = q
.updates
.get(name)
.expect("exists")
Expand All @@ -77,16 +61,14 @@ impl Generator {
let col =
Ident::new(format!("{}_lock", col).as_str(), Span::mixed_site());
quote! {
self.#col = 0u16.into();
if self.#col.is_none() {
self.#col = Some(std::sync::Arc::new(Lock::new()));
}
}
})
.collect::<Vec<_>>();

let verify_ident = Ident::new(
format!("verify_{snake_case_name}_lock").as_str(),
Span::mixed_site(),
);
let verify = q
let rows_unlock = q
.updates
.get(name)
.expect("exists")
Expand All @@ -96,40 +78,35 @@ impl Generator {
let col =
Ident::new(format!("{}_lock", col).as_str(), Span::mixed_site());
quote! {
if self.#col != id {
return false;
if let Some(#col) = &self.#col {
#col.unlock();
}
}
})
.collect::<Vec<_>>();

quote! {
pub fn #check_ident(&self) -> Option<u16> {
if self.lock != 0 {
return Some(self.lock.into());
}
#(#checks)*
None
}

pub unsafe fn #lock_ident(&mut self, id: u16) {
#(#locks)*
pub fn #lock_ident(&mut self) {
#(#rows_lock)*
}

pub unsafe fn #unlock_ident(&mut self) {
#(#unlocks)*
pub fn #unlock_ident(&self) {
#(#rows_unlock)*
}

pub fn #verify_ident(&self, id: u16) -> bool {
#(#verify)*
true
pub async fn #lock_await_ident(&self) {
let mut futures = Vec::new();

#(#rows_lock_await)*
futures::future::join_all(futures).await;
}
}
})
.collect::<Vec<_>>();

Ok(quote! {
impl #archived_wrapper {
impl #lock_type_ident {
#(#fns)*
}
})
Expand Down
Loading