Commit 1f872d49 authored by Hero Bird's avatar Hero Bird
Browse files

[pdsl_core] Implement flushing for SyncCell and storage::Value

parent 6b94ec75
......@@ -18,7 +18,9 @@ use crate::{
storage::{
cell::TypedCell,
Allocator,
Flush,
},
memory::boxed::Box,
};
use core::{
......@@ -58,8 +60,22 @@ pub struct SyncCacheEntry<T> {
cell_val: Pin<Box<Option<T>>>,
}
impl<T> SyncCacheEntry<T>
where
T: Unpin
{
/// Updates the cached value.
pub fn update(&mut self, new_val: Option<T>) {
*self.cell_val = new_val;
}
}
impl<T> SyncCacheEntry<T> {
/// Initializes this synchronized cache entry with the given value.
///
/// # Note
///
/// The cache will _not_ be marked as dirty after this operation.
pub fn new(val: Option<T>) -> Self {
Self{
dirty: false,
......@@ -72,6 +88,16 @@ impl<T> SyncCacheEntry<T> {
self.dirty
}
/// Marks the cached value as dirty.
pub fn mark_dirty(&mut self) {
self.dirty = true;
}
/// Marks the cached value as clean.
pub fn mark_clean(&mut self) {
self.dirty = false;
}
/// Returns an immutable reference to the synchronized cached value.
pub fn get(&self) -> Option<&T> {
(&*self.cell_val).into()
......@@ -87,7 +113,7 @@ where
/// This also marks the cache entry as being dirty since
/// the callee could potentially mutate the value.
pub fn get_mut(&mut self) -> Option<&mut T> {
self.dirty = true;
self.mark_dirty();
self.cell_val.as_mut().get_mut().into()
}
}
......@@ -107,6 +133,23 @@ impl<T> Default for CacheEntry<T> {
}
}
impl<T> CacheEntry<T>
where
T: Unpin
{
/// Updates the cached value.
pub fn update(&mut self, new_val: Option<T>) {
match self {
CacheEntry::Desync => {
*self = CacheEntry::Sync(SyncCacheEntry::new(new_val))
}
CacheEntry::Sync(sync_entry) => {
sync_entry.update(new_val)
}
}
}
}
impl<T> CacheEntry<T> {
/// Returns `true` if the cache is in sync.
pub fn is_synced(&self) -> bool {
......@@ -124,6 +167,22 @@ impl<T> CacheEntry<T> {
}
}
/// Marks the cache as dirty.
pub fn mark_dirty(&mut self) {
match self {
CacheEntry::Sync(sync_entry) => sync_entry.mark_dirty(),
CacheEntry::Desync => (),
}
}
/// Marks the cache as clean.
pub fn mark_clean(&mut self) {
match self {
CacheEntry::Sync(sync_entry) => sync_entry.mark_clean(),
CacheEntry::Desync => (),
}
}
/// Returns an immutable reference to the internal cached entity if any.
///
/// # Panics
......@@ -181,6 +240,21 @@ impl<T> Default for Cache<T> {
}
}
impl<T> Cache<T>
where
T: Unpin
{
/// Updates the synchronized value.
///
/// # Note
///
/// - The cache will be in sync after this operation.
/// - The cache will not be dirty after this operation.
pub fn update(&self, new_val: Option<T>) {
self.entry.borrow_mut().update(new_val)
}
}
impl<T> Cache<T> {
/// Returns `true` if the cache is in sync.
pub fn is_synced(&self) -> bool {
......@@ -189,22 +263,17 @@ impl<T> Cache<T> {
/// Returns `true` if the cache is dirty.
pub fn is_dirty(&self) -> bool {
match self.get_entry() {
CacheEntry::Desync => false,
CacheEntry::Sync(sync_entry) => sync_entry.is_dirty(),
}
self.entry.borrow().is_dirty()
}
/// Updates the synchronized value.
///
/// # Note
///
/// - The cache will be in sync after this operation.
/// - The cache will not be dirty after this operation.
pub fn update(&self, new_val: Option<T>) {
self.entry.replace(
CacheEntry::Sync(SyncCacheEntry::new(new_val))
);
/// Marks the cache dirty.
pub fn mark_dirty(&mut self) {
self.entry.borrow_mut().mark_dirty()
}
/// Marks the cache clean.
pub fn mark_clean(&mut self) {
self.entry.borrow_mut().mark_clean()
}
/// Returns an immutable reference to the internal cache entry.
......@@ -261,6 +330,21 @@ impl<T> parity_codec::Decode for SyncCell<T> {
}
}
impl<T> Flush for SyncCell<T>
where
T: parity_codec::Codec,
{
fn flush(&mut self) {
if self.cache.is_dirty() {
match self.cache.get() {
Some(val) => self.cell.store(val),
None => self.cell.clear(),
}
self.cache.mark_clean();
}
}
}
impl<T> SyncCell<T> {
/// Allocates a new sync cell using the given storage allocator.
///
......@@ -277,17 +361,23 @@ impl<T> SyncCell<T> {
cache: Default::default(),
}
}
}
impl<T> SyncCell<T>
where
T: Unpin
{
/// Removes the value from the cell.
pub fn clear(&mut self) {
self.cell.clear();
self.cell.clear(); // TODO: Removes this after implementation of flushing
self.cache.update(None);
self.cache.mark_dirty();
}
}
impl<T> SyncCell<T>
where
T: parity_codec::Decode
T: parity_codec::Decode + Unpin
{
/// Returns an immutable reference to the value of the cell.
pub fn get(&self) -> Option<&T> {
......@@ -301,12 +391,13 @@ where
impl<T> SyncCell<T>
where
T: parity_codec::Encode
T: parity_codec::Encode + Unpin
{
/// Sets the value of the cell.
pub fn set(&mut self, val: T) {
self.cell.store(&val);
self.cache.update(Some(val))
self.cell.store(&val); // TODO: Removes this after implementation of flushing
self.cache.update(Some(val));
self.cache.mark_dirty();
}
}
......@@ -320,6 +411,7 @@ where
let loaded = self.cell.load();
self.cache.update(loaded);
}
self.cache.mark_dirty();
self.cache.get_mut()
}
......
......@@ -33,5 +33,5 @@
/// `storage::Vec` or `storage::Value`.
pub trait Flush {
/// Flushes the cached state back to the contract storage, if any.
fn flush();
fn flush(&mut self);
}
......@@ -83,6 +83,7 @@ pub mod chunk;
mod collections;
mod setup;
mod value;
mod flush;
use self::non_clone::NonCloneMarker;
......@@ -108,6 +109,9 @@ pub use self::{
setup::{
Setup,
},
flush::{
Flush,
},
};
#[doc(inline)]
......
......@@ -18,6 +18,7 @@ use crate::{
storage::{
self,
cell::SyncCell,
Flush,
},
};
use parity_codec::{Encode, Decode};
......@@ -42,14 +43,17 @@ use parity_codec::{Encode, Decode};
/// [`set`](struct.Value.html#method.set) or
/// [`mutate_with`](struct.Value.html#method.mutate_with).
#[derive(Debug, Encode, Decode)]
pub struct Value<T> {
pub struct Value<T>
where
T: Unpin,
{
/// The cell of the storage value.
cell: SyncCell<T>,
}
impl<T> Value<T>
where
T: parity_codec::Codec + Default
T: parity_codec::Codec + Default + Unpin,
{
/// Creates a new storage value initialized as its default value.
///
......@@ -67,7 +71,7 @@ where
impl<T> Value<T>
where
T: parity_codec::Codec,
T: parity_codec::Codec + Unpin,
{
/// Creates a new storage value initialized by the given value.
///
......@@ -114,7 +118,7 @@ where
impl<T, R> core::convert::AsRef<R> for Value<T>
where
T: core::convert::AsRef<R> + parity_codec::Codec,
T: core::convert::AsRef<R> + parity_codec::Codec + Unpin,
{
fn as_ref(&self) -> &R {
self.get().as_ref()
......@@ -123,7 +127,7 @@ where
impl<T> core::ops::Deref for Value<T>
where
T: parity_codec::Codec,
T: parity_codec::Codec + Unpin,
{
type Target = T;
......@@ -132,9 +136,21 @@ where
}
}
impl<T> Drop for Value<T> {
impl<T> Flush for Value<T>
where
T: parity_codec::Codec + Unpin,
{
fn flush(&mut self) {
self.cell.flush()
}
}
impl<T> Drop for Value<T>
where
T: Unpin,
{
fn drop(&mut self) {
self.cell.clear();
self.cell.clear()
}
}
......@@ -146,7 +162,7 @@ macro_rules! impl_ops_for_value {
) => {
impl<T> core::ops::$trait_name<T> for &Value<T>
where
T: core::ops::$trait_name<T> + Copy + parity_codec::Codec,
T: core::ops::$trait_name<T> + Copy + parity_codec::Codec + Unpin,
{
type Output = <T as core::ops::$trait_name>::Output;
......@@ -157,7 +173,7 @@ macro_rules! impl_ops_for_value {
impl<T> core::ops::$trait_name for &Value<T>
where
T: core::ops::$trait_name<T> + Copy + parity_codec::Codec,
T: core::ops::$trait_name<T> + Copy + parity_codec::Codec + Unpin,
{
type Output = <T as core::ops::$trait_name>::Output;
......@@ -198,7 +214,7 @@ impl_ops_for_value!(BitXor, bitxor, BitXorAssign, bitxor_assign; ^, ^=);
impl<T> core::ops::Neg for &Value<T>
where
T: core::ops::Neg + Copy + parity_codec::Codec,
T: core::ops::Neg + Copy + parity_codec::Codec + Unpin,
{
type Output = <T as core::ops::Neg>::Output;
......@@ -209,7 +225,7 @@ where
impl<T> core::ops::Not for &Value<T>
where
T: core::ops::Not + Copy + parity_codec::Codec,
T: core::ops::Not + Copy + parity_codec::Codec + Unpin,
{
type Output = <T as core::ops::Not>::Output;
......@@ -225,7 +241,7 @@ macro_rules! impl_shift_for_value {
) => {
impl<T, R> core::ops::$trait_name<R> for &Value<T>
where
T: core::ops::$trait_name<R> + Copy + parity_codec::Codec,
T: core::ops::$trait_name<R> + Copy + parity_codec::Codec + Unpin,
{
type Output = <T as core::ops::$trait_name<R>>::Output;
......@@ -250,7 +266,7 @@ impl_shift_for_value!(Shr, shr, >>; ShrAssign, shr_assign, >>=);
impl<T, I> core::ops::Index<I> for Value<T>
where
T: core::ops::Index<I> + parity_codec::Codec,
T: core::ops::Index<I> + parity_codec::Codec + Unpin,
{
type Output = <T as core::ops::Index<I>>::Output;
......@@ -261,7 +277,7 @@ where
impl<T> PartialEq<T> for Value<T>
where
T: PartialEq + parity_codec::Codec,
T: PartialEq + parity_codec::Codec + Unpin,
{
fn eq(&self, rhs: &T) -> bool {
self.get().eq(rhs)
......@@ -270,20 +286,23 @@ where
impl<T> PartialEq for Value<T>
where
T: PartialEq + parity_codec::Codec,
T: PartialEq + parity_codec::Codec + Unpin,
{
fn eq(&self, rhs: &Self) -> bool {
self.get().eq(rhs.get())
}
}
impl<T> Eq for Value<T> where T: Eq + parity_codec::Codec {}
impl<T> Eq for Value<T>
where
T: Eq + parity_codec::Codec + Unpin
{}
use core::cmp::Ordering;
impl<T> PartialOrd<T> for Value<T>
where
T: PartialOrd + parity_codec::Codec,
T: PartialOrd + parity_codec::Codec + Unpin,
{
fn partial_cmp(&self, other: &T) -> Option<Ordering> {
self.get().partial_cmp(other)
......@@ -292,14 +311,17 @@ where
impl<T> PartialOrd<Value<T>> for Value<T>
where
T: PartialOrd + parity_codec::Codec,
T: PartialOrd + parity_codec::Codec + Unpin,
{
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
self.get().partial_cmp(other.get())
}
}
impl<T> Ord for Value<T> where T: Ord + parity_codec::Codec {
impl<T> Ord for Value<T>
where
T: Ord + parity_codec::Codec + Unpin
{
fn cmp(&self, other: &Self) -> Ordering {
self.get().cmp(other.get())
}
......@@ -307,7 +329,7 @@ impl<T> Ord for Value<T> where T: Ord + parity_codec::Codec {
impl<T> core::hash::Hash for Value<T>
where
T: core::hash::Hash + parity_codec::Codec,
T: core::hash::Hash + parity_codec::Codec + Unpin,
{
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
self.get().hash(state)
......@@ -316,7 +338,7 @@ where
impl<T> core::fmt::Display for Value<T>
where
T: core::fmt::Display + parity_codec::Codec,
T: core::fmt::Display + parity_codec::Codec + Unpin,
{
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
self.get().fmt(f)
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment