Skip to content

Commit

Permalink
Implement pre_load/ post_loadfor the views. (linera-io#2213)
Browse files Browse the repository at this point in the history
* Implement the pre_load / post_load for the views.
* Rename the `from_bytes_opt` into `from_bytes_option`.
* Introduce the `from_bytes_option_or_default`.
  • Loading branch information
MathieuDutSik authored Jul 15, 2024
1 parent f59ad4d commit 51daaf4
Show file tree
Hide file tree
Showing 29 changed files with 1,379 additions and 256 deletions.
87 changes: 52 additions & 35 deletions linera-views-derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,6 @@ fn get_seq_parameter(generics: syn::Generics) -> Vec<syn::Ident> {
generic_vect
}

fn get_type_field(field: syn::Field) -> Option<syn::Ident> {
match field.ty {
syn::Type::Path(typepath) => {
if let Some(x) = typepath.path.segments.into_iter().next() {
return Some(x.ident);
}
None
}
_ => None,
}
}

fn custom_attribute(attributes: &[Attribute], key: &str) -> Option<LitStr> {
attributes
.iter()
Expand Down Expand Up @@ -92,6 +80,16 @@ fn empty_where_clause() -> WhereClause {
}
}

fn get_extended_entry(e: Type) -> TokenStream2 {
let syn::Type::Path(typepath) = e else {
panic!("The type should be a path");
};
let path_segment = typepath.path.segments.into_iter().next().unwrap();
let ident = path_segment.ident;
let arguments = path_segment.arguments;
quote! { #ident :: #arguments }
}

fn generate_view_code(input: ItemStruct, root: bool) -> TokenStream2 {
let struct_name = input.ident;
let (impl_generics, type_generics, maybe_where_clause) = input.generics.split_for_impl();
Expand All @@ -107,31 +105,19 @@ fn generate_view_code(input: ItemStruct, root: bool) -> TokenStream2 {
.extend(context_constraints.predicates);

let mut name_quotes = Vec::new();
let mut load_future_quotes = Vec::new();
let mut load_ident_quotes = Vec::new();
let mut load_result_quotes = Vec::new();
let mut rollback_quotes = Vec::new();
let mut flush_quotes = Vec::new();
let mut test_flush_quotes = Vec::new();
let mut clear_quotes = Vec::new();
let mut has_pending_changes_quotes = Vec::new();
let mut num_init_keys_quotes = Vec::new();
let mut pre_load_keys_quotes = Vec::new();
let mut post_load_keys_quotes = Vec::new();
for (idx, e) in input.fields.into_iter().enumerate() {
let name = e.clone().ident.unwrap();
let fut = format_ident!("{}_fut", name.to_string());
let test_flush_ident = format_ident!("deleted{}", idx);
let idx_lit = syn::LitInt::new(&idx.to_string(), Span::call_site());
let type_ident = get_type_field(e).expect("Failed to find the type");
load_future_quotes.push(quote! {
let index = #idx_lit;
let base_key = context.derive_tag_key(linera_views::common::MIN_VIEW_TAG, &index)?;
let #fut = #type_ident::load(context.clone_with_base_key(base_key));
});
load_ident_quotes.push(quote! {
#fut
});
load_result_quotes.push(quote! {
let #name = result.#idx_lit?;
});
let g = get_extended_entry(e.ty.clone());
name_quotes.push(quote! { #name });
rollback_quotes.push(quote! { self.#name.rollback(); });
flush_quotes.push(quote! { let #test_flush_ident = self.#name.flush(batch)?; });
Expand All @@ -142,19 +128,35 @@ fn generate_view_code(input: ItemStruct, root: bool) -> TokenStream2 {
return true;
}
});
num_init_keys_quotes.push(quote! { #g :: NUM_INIT_KEYS });
pre_load_keys_quotes.push(quote! {
let index = #idx_lit;
let base_key = context.derive_tag_key(linera_views::common::MIN_VIEW_TAG, &index)?;
keys.extend(#g :: pre_load(&context.clone_with_base_key(base_key))?);
});
post_load_keys_quotes.push(quote! {
let index = #idx_lit;
let pos_next = pos + #g :: NUM_INIT_KEYS;
let base_key = context.derive_tag_key(linera_views::common::MIN_VIEW_TAG, &index)?;
let #name = #g :: post_load(context.clone_with_base_key(base_key), &values[pos..pos_next])?;
pos = pos_next;
});
}
let first_name_quote = name_quotes
.first()
.expect("list of names should be non-empty");

let increment_counter = if root && cfg!(feature = "metrics") {
let load_metrics = if root && cfg!(feature = "metrics") {
quote! {
#[cfg(not(target_arch = "wasm32"))]
linera_views::increment_counter(
&linera_views::LOAD_VIEW_COUNTER,
stringify!(#struct_name),
&context.base_key(),
);
#[cfg(not(target_arch = "wasm32"))]
use linera_views::prometheus_util::MeasureLatency as _;
let _latency = linera_views::LOAD_VIEW_LATENCY.measure_latency();
}
} else {
quote! {}
Expand All @@ -165,20 +167,35 @@ fn generate_view_code(input: ItemStruct, root: bool) -> TokenStream2 {
impl #impl_generics linera_views::views::View<#context> for #struct_name #type_generics
#where_clause
{
const NUM_INIT_KEYS: usize = #(#num_init_keys_quotes)+*;

fn context(&self) -> &#context {
use linera_views::views::View;
self.#first_name_quote.context()
}

async fn load(context: #context) -> Result<Self, linera_views::views::ViewError> {
use linera_views::{futures::join, common::Context};
#increment_counter
#(#load_future_quotes)*
let result = join!(#(#load_ident_quotes),*);
#(#load_result_quotes)*
fn pre_load(context: &#context) -> Result<Vec<Vec<u8>>, linera_views::views::ViewError> {
use linera_views::common::Context as _;
let mut keys = Vec::new();
#(#pre_load_keys_quotes)*
Ok(keys)
}

fn post_load(context: #context, values: &[Option<Vec<u8>>]) -> Result<Self, linera_views::views::ViewError> {
use linera_views::common::Context as _;
let mut pos = 0;
#(#post_load_keys_quotes)*
Ok(Self {#(#name_quotes),*})
}

async fn load(context: #context) -> Result<Self, linera_views::views::ViewError> {
use linera_views::common::Context as _;
#load_metrics
let keys = Self::pre_load(&context)?;
let values = context.read_multi_values_bytes(keys).await?;
Self::post_load(context, &values)
}


fn rollback(&mut self) {
#(#rollback_quotes)*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,25 +8,67 @@ where
C: linera_views::common::Context + Send + Sync + Clone + 'static,
linera_views::views::ViewError: From<C::Error>,
{
const NUM_INIT_KEYS: usize = RegisterView::<C, usize>::NUM_INIT_KEYS
+ CollectionView::<C, usize, RegisterView<C, usize>>::NUM_INIT_KEYS;
fn context(&self) -> &C {
use linera_views::views::View;
self.register.context()
}
async fn load(context: C) -> Result<Self, linera_views::views::ViewError> {
use linera_views::{futures::join, common::Context};
fn pre_load(context: &C) -> Result<Vec<Vec<u8>>, linera_views::views::ViewError> {
use linera_views::common::Context as _;
let mut keys = Vec::new();
let index = 0;
let base_key = context
.derive_tag_key(linera_views::common::MIN_VIEW_TAG, &index)?;
keys.extend(
RegisterView::<C, usize>::pre_load(&context.clone_with_base_key(base_key))?,
);
let index = 1;
let base_key = context
.derive_tag_key(linera_views::common::MIN_VIEW_TAG, &index)?;
keys.extend(
CollectionView::<
C,
usize,
RegisterView<C, usize>,
>::pre_load(&context.clone_with_base_key(base_key))?,
);
Ok(keys)
}
fn post_load(
context: C,
values: &[Option<Vec<u8>>],
) -> Result<Self, linera_views::views::ViewError> {
use linera_views::common::Context as _;
let mut pos = 0;
let index = 0;
let pos_next = pos + RegisterView::<C, usize>::NUM_INIT_KEYS;
let base_key = context
.derive_tag_key(linera_views::common::MIN_VIEW_TAG, &index)?;
let register_fut = RegisterView::load(context.clone_with_base_key(base_key));
let register = RegisterView::<
C,
usize,
>::post_load(context.clone_with_base_key(base_key), &values[pos..pos_next])?;
pos = pos_next;
let index = 1;
let pos_next = pos
+ CollectionView::<C, usize, RegisterView<C, usize>>::NUM_INIT_KEYS;
let base_key = context
.derive_tag_key(linera_views::common::MIN_VIEW_TAG, &index)?;
let collection_fut = CollectionView::load(context.clone_with_base_key(base_key));
let result = join!(register_fut, collection_fut);
let register = result.0?;
let collection = result.1?;
let collection = CollectionView::<
C,
usize,
RegisterView<C, usize>,
>::post_load(context.clone_with_base_key(base_key), &values[pos..pos_next])?;
pos = pos_next;
Ok(Self { register, collection })
}
async fn load(context: C) -> Result<Self, linera_views::views::ViewError> {
use linera_views::common::Context as _;
let keys = Self::pre_load(&context)?;
let values = context.read_multi_values_bytes(keys).await?;
Self::post_load(context, &values)
}
fn rollback(&mut self) {
self.register.rollback();
self.collection.rollback();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,25 +9,67 @@ where
C: linera_views::common::Context + Send + Sync + Clone + 'static,
linera_views::views::ViewError: From<C::Error>,
{
const NUM_INIT_KEYS: usize = RegisterView::<C, usize>::NUM_INIT_KEYS
+ CollectionView::<C, usize, RegisterView<C, usize>>::NUM_INIT_KEYS;
fn context(&self) -> &C {
use linera_views::views::View;
self.register.context()
}
async fn load(context: C) -> Result<Self, linera_views::views::ViewError> {
use linera_views::{futures::join, common::Context};
fn pre_load(context: &C) -> Result<Vec<Vec<u8>>, linera_views::views::ViewError> {
use linera_views::common::Context as _;
let mut keys = Vec::new();
let index = 0;
let base_key = context
.derive_tag_key(linera_views::common::MIN_VIEW_TAG, &index)?;
keys.extend(
RegisterView::<C, usize>::pre_load(&context.clone_with_base_key(base_key))?,
);
let index = 1;
let base_key = context
.derive_tag_key(linera_views::common::MIN_VIEW_TAG, &index)?;
keys.extend(
CollectionView::<
C,
usize,
RegisterView<C, usize>,
>::pre_load(&context.clone_with_base_key(base_key))?,
);
Ok(keys)
}
fn post_load(
context: C,
values: &[Option<Vec<u8>>],
) -> Result<Self, linera_views::views::ViewError> {
use linera_views::common::Context as _;
let mut pos = 0;
let index = 0;
let pos_next = pos + RegisterView::<C, usize>::NUM_INIT_KEYS;
let base_key = context
.derive_tag_key(linera_views::common::MIN_VIEW_TAG, &index)?;
let register_fut = RegisterView::load(context.clone_with_base_key(base_key));
let register = RegisterView::<
C,
usize,
>::post_load(context.clone_with_base_key(base_key), &values[pos..pos_next])?;
pos = pos_next;
let index = 1;
let pos_next = pos
+ CollectionView::<C, usize, RegisterView<C, usize>>::NUM_INIT_KEYS;
let base_key = context
.derive_tag_key(linera_views::common::MIN_VIEW_TAG, &index)?;
let collection_fut = CollectionView::load(context.clone_with_base_key(base_key));
let result = join!(register_fut, collection_fut);
let register = result.0?;
let collection = result.1?;
let collection = CollectionView::<
C,
usize,
RegisterView<C, usize>,
>::post_load(context.clone_with_base_key(base_key), &values[pos..pos_next])?;
pos = pos_next;
Ok(Self { register, collection })
}
async fn load(context: C) -> Result<Self, linera_views::views::ViewError> {
use linera_views::common::Context as _;
let keys = Self::pre_load(&context)?;
let values = context.read_multi_values_bytes(keys).await?;
Self::post_load(context, &values)
}
fn rollback(&mut self) {
self.register.rollback();
self.collection.rollback();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,82 @@ expression: "pretty(generate_view_code(input, true))"
---
#[linera_views::async_trait]
impl linera_views::views::View<CustomContext> for TestView {
const NUM_INIT_KEYS: usize = RegisterView::<CustomContext, usize>::NUM_INIT_KEYS
+ CollectionView::<
CustomContext,
usize,
RegisterView<CustomContext, usize>,
>::NUM_INIT_KEYS;
fn context(&self) -> &CustomContext {
use linera_views::views::View;
self.register.context()
}
async fn load(
fn pre_load(
context: &CustomContext,
) -> Result<Vec<Vec<u8>>, linera_views::views::ViewError> {
use linera_views::common::Context as _;
let mut keys = Vec::new();
let index = 0;
let base_key = context
.derive_tag_key(linera_views::common::MIN_VIEW_TAG, &index)?;
keys.extend(
RegisterView::<
CustomContext,
usize,
>::pre_load(&context.clone_with_base_key(base_key))?,
);
let index = 1;
let base_key = context
.derive_tag_key(linera_views::common::MIN_VIEW_TAG, &index)?;
keys.extend(
CollectionView::<
CustomContext,
usize,
RegisterView<CustomContext, usize>,
>::pre_load(&context.clone_with_base_key(base_key))?,
);
Ok(keys)
}
fn post_load(
context: CustomContext,
values: &[Option<Vec<u8>>],
) -> Result<Self, linera_views::views::ViewError> {
use linera_views::{futures::join, common::Context};
use linera_views::common::Context as _;
let mut pos = 0;
let index = 0;
let pos_next = pos + RegisterView::<CustomContext, usize>::NUM_INIT_KEYS;
let base_key = context
.derive_tag_key(linera_views::common::MIN_VIEW_TAG, &index)?;
let register_fut = RegisterView::load(context.clone_with_base_key(base_key));
let register = RegisterView::<
CustomContext,
usize,
>::post_load(context.clone_with_base_key(base_key), &values[pos..pos_next])?;
pos = pos_next;
let index = 1;
let pos_next = pos
+ CollectionView::<
CustomContext,
usize,
RegisterView<CustomContext, usize>,
>::NUM_INIT_KEYS;
let base_key = context
.derive_tag_key(linera_views::common::MIN_VIEW_TAG, &index)?;
let collection_fut = CollectionView::load(context.clone_with_base_key(base_key));
let result = join!(register_fut, collection_fut);
let register = result.0?;
let collection = result.1?;
let collection = CollectionView::<
CustomContext,
usize,
RegisterView<CustomContext, usize>,
>::post_load(context.clone_with_base_key(base_key), &values[pos..pos_next])?;
pos = pos_next;
Ok(Self { register, collection })
}
async fn load(
context: CustomContext,
) -> Result<Self, linera_views::views::ViewError> {
use linera_views::common::Context as _;
let keys = Self::pre_load(&context)?;
let values = context.read_multi_values_bytes(keys).await?;
Self::post_load(context, &values)
}
fn rollback(&mut self) {
self.register.rollback();
self.collection.rollback();
Expand Down
Loading

0 comments on commit 51daaf4

Please sign in to comment.