New model for buckets

This commit is contained in:
Alex Auvolat
2021-12-14 13:55:11 +01:00
parent 8f6026de5e
commit 5b1117e582
38 changed files with 1173 additions and 496 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "garage_util"
version = "0.5.0"
version = "0.6.0"
authors = ["Alex Auvolat <alex@adnab.me>"]
edition = "2018"
license = "AGPL-3.0"
+72
View File
@@ -0,0 +1,72 @@
use serde::{Deserialize, Serialize};
use crate::crdt::crdt::*;
/// Deletable object (once deleted, cannot go back)
#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq)]
pub enum Deletable<T> {
Present(T),
Deleted,
}
impl<T: Crdt> Deletable<T> {
/// Create a new deletable object that isn't deleted
pub fn present(v: T) -> Self {
Self::Present(v)
}
/// Create a new deletable object that is deleted
pub fn delete() -> Self {
Self::Deleted
}
/// As option
pub fn as_option(&self) -> Option<&T> {
match self {
Self::Present(v) => Some(v),
Self::Deleted => None,
}
}
/// As option, mutable
pub fn as_option_mut(&mut self) -> Option<&mut T> {
match self {
Self::Present(v) => Some(v),
Self::Deleted => None,
}
}
/// Into option
pub fn into_option(self) -> Option<T> {
match self {
Self::Present(v) => Some(v),
Self::Deleted => None,
}
}
/// Is object deleted?
pub fn is_deleted(&self) -> bool {
matches!(self, Self::Deleted)
}
}
impl<T> From<Option<T>> for Deletable<T> {
fn from(v: Option<T>) -> Self {
v.map(Self::Present).unwrap_or(Self::Deleted)
}
}
impl<T> From<Deletable<T>> for Option<T> {
fn from(v: Deletable<T>) -> Option<T> {
match v {
Deletable::Present(v) => Some(v),
Deletable::Deleted => None,
}
}
}
impl<T: Crdt> Crdt for Deletable<T> {
fn merge(&mut self, other: &Self) {
if let Deletable::Present(v) = self {
match other {
Deletable::Deleted => *self = Deletable::Deleted,
Deletable::Present(v2) => v.merge(v2),
}
}
}
}
+5
View File
@@ -82,6 +82,11 @@ where
&self.v
}
/// Take the value inside the CRDT (discards the timesamp)
pub fn take(self) -> T {
self.v
}
/// Get a mutable reference to the CRDT's value
///
/// This is usefull to mutate the inside value without changing the LWW timestamp.
+8 -4
View File
@@ -30,8 +30,8 @@ pub struct LwwMap<K, V> {
impl<K, V> LwwMap<K, V>
where
K: Ord,
V: Crdt,
K: Clone + Ord,
V: Clone + Crdt,
{
/// Create a new empty map CRDT
pub fn new() -> Self {
@@ -73,6 +73,10 @@ where
};
Self { vals: new_vals }
}
pub fn update_in_place(&mut self, k: K, new_v: V) {
self.merge(&self.update_mutator(k, new_v));
}
/// Takes all of the values of the map and returns them. The current map is reset to the
/// empty map. This is very usefull to produce in-place a new map that contains only a delta
/// that modifies a certain value:
@@ -158,8 +162,8 @@ where
impl<K, V> Default for LwwMap<K, V>
where
K: Ord,
V: Crdt,
K: Clone + Ord,
V: Clone + Crdt,
{
fn default() -> Self {
Self::new()
+2
View File
@@ -12,12 +12,14 @@
mod bool;
#[allow(clippy::module_inception)]
mod crdt;
mod deletable;
mod lww;
mod lww_map;
mod map;
pub use self::bool::*;
pub use crdt::*;
pub use deletable::*;
pub use lww::*;
pub use lww_map::*;
pub use map::*;
+29
View File
@@ -119,6 +119,35 @@ where
}
}
/// Trait to map error to the Bad Request error code
pub trait OkOrMessage {
type S2;
fn ok_or_message<M: Into<String>>(self, message: M) -> Self::S2;
}
impl<T, E> OkOrMessage for Result<T, E>
where
E: std::fmt::Display,
{
type S2 = Result<T, Error>;
fn ok_or_message<M: Into<String>>(self, message: M) -> Result<T, Error> {
match self {
Ok(x) => Ok(x),
Err(e) => Err(Error::Message(format!("{}: {}", message.into(), e))),
}
}
}
impl<T> OkOrMessage for Option<T> {
type S2 = Result<T, Error>;
fn ok_or_message<M: Into<String>>(self, message: M) -> Result<T, Error> {
match self {
Some(x) => Ok(x),
None => Err(Error::Message(message.into())),
}
}
}
// Custom serialization for our error type, for use in RPC.
// Errors are serialized as a string of their Display representation.
// Upon deserialization, they all become a RemoteError with the
+5
View File
@@ -10,6 +10,11 @@ pub fn now_msec() -> u64 {
.as_millis() as u64
}
/// Increment logical clock
pub fn increment_logical_clock(prev: u64) -> u64 {
std::cmp::max(prev + 1, now_msec())
}
/// Convert a timestamp represented as milliseconds since UNIX Epoch to
/// its RFC3339 representation, such as "2021-01-01T12:30:00Z"
pub fn msec_to_rfc3339(msecs: u64) -> String {