Make table objects slightly more fool-proof; add key table

This commit is contained in:
Alex Auvolat
2020-04-23 18:16:33 +00:00
parent c9c6b0dbd4
commit 44a1089d95
7 changed files with 290 additions and 75 deletions
+41 -5
View File
@@ -15,7 +15,44 @@ pub struct Bucket {
pub deleted: bool,
// Authorized keys
pub authorized_keys: Vec<AllowedKey>,
authorized_keys: Vec<AllowedKey>,
}
impl Bucket {
pub fn new(
name: String,
timestamp: u64,
deleted: bool,
authorized_keys: Vec<AllowedKey>,
) -> Self {
let mut ret = Bucket {
name,
timestamp,
deleted,
authorized_keys: vec![],
};
for key in authorized_keys {
ret.add_key(key)
.expect("Duplicate AllowedKey in Bucket constructor");
}
ret
}
/// Add a key only if it is not already present
pub fn add_key(&mut self, key: AllowedKey) -> Result<(), ()> {
match self
.authorized_keys
.binary_search_by(|k| k.access_key_id.cmp(&key.access_key_id))
{
Err(i) => {
self.authorized_keys.insert(i, key);
Ok(())
}
Ok(_) => Err(()),
}
}
pub fn authorized_keys(&self) -> &[AllowedKey] {
&self.authorized_keys[..]
}
}
#[derive(PartialEq, Clone, Debug, Serialize, Deserialize)]
@@ -39,9 +76,10 @@ impl Entry<EmptyKey, String> for Bucket {
*self = other.clone();
return;
}
if self.timestamp > other.timestamp {
if self.timestamp > other.timestamp || self.deleted {
return;
}
for ak in other.authorized_keys.iter() {
match self
.authorized_keys
@@ -50,9 +88,7 @@ impl Entry<EmptyKey, String> for Bucket {
Ok(i) => {
let our_ak = &mut self.authorized_keys[i];
if ak.timestamp > our_ak.timestamp {
our_ak.timestamp = ak.timestamp;
our_ak.allowed_read = ak.allowed_read;
our_ak.allowed_write = ak.allowed_write;
*our_ak = ak.clone();
}
}
Err(i) => {
+121
View File
@@ -0,0 +1,121 @@
use async_trait::async_trait;
use serde::{Deserialize, Serialize};
use crate::error::Error;
use crate::table::*;
#[derive(PartialEq, Clone, Debug, Serialize, Deserialize)]
pub struct Key {
// Primary key
pub access_key_id: String,
// Associated secret key (immutable)
pub secret_access_key: String,
// Deletion
pub deleted: bool,
// Authorized keys
authorized_buckets: Vec<AllowedBucket>,
}
impl Key {
pub fn new(buckets: Vec<AllowedBucket>) -> Self {
let access_key_id = format!("GK{}", hex::encode(&rand::random::<[u8; 12]>()[..]));
let secret_access_key = hex::encode(&rand::random::<[u8; 32]>()[..]);
let mut ret = Self {
access_key_id,
secret_access_key,
deleted: false,
authorized_buckets: vec![],
};
for b in buckets {
ret.add_bucket(b);
}
ret
}
pub fn delete(access_key_id: String, secret_access_key: String) -> Self {
Self {
access_key_id,
secret_access_key,
deleted: true,
authorized_buckets: vec![],
}
}
/// Add an authorized bucket, only if it wasn't there before
pub fn add_bucket(&mut self, new: AllowedBucket) -> Result<(), ()> {
match self
.authorized_buckets
.binary_search_by(|b| b.bucket.cmp(&new.bucket))
{
Err(i) => {
self.authorized_buckets.insert(i, new);
Ok(())
}
Ok(_) => Err(()),
}
}
pub fn authorized_buckets(&self) -> &[AllowedBucket] {
&self.authorized_buckets[..]
}
}
#[derive(PartialEq, Clone, Debug, Serialize, Deserialize)]
pub struct AllowedBucket {
pub bucket: String,
pub timestamp: u64,
pub allowed_read: bool,
pub allowed_write: bool,
}
impl Entry<EmptyKey, String> for Key {
fn partition_key(&self) -> &EmptyKey {
&EmptyKey
}
fn sort_key(&self) -> &String {
&self.access_key_id
}
fn merge(&mut self, other: &Self) {
if other.deleted {
self.deleted = true;
self.authorized_buckets.clear();
return;
}
for ab in other.authorized_buckets.iter() {
match self
.authorized_buckets
.binary_search_by(|our_ab| our_ab.bucket.cmp(&ab.bucket))
{
Ok(i) => {
let our_ab = &mut self.authorized_buckets[i];
if ab.timestamp > our_ab.timestamp {
*our_ab = ab.clone();
}
}
Err(i) => {
self.authorized_buckets.insert(i, ab.clone());
}
}
}
}
}
pub struct KeyTable;
#[async_trait]
impl TableSchema for KeyTable {
type P = EmptyKey;
type S = String;
type E = Key;
type Filter = ();
async fn updated(&self, _old: Option<Self::E>, _new: Option<Self::E>) -> Result<(), Error> {
Ok(())
}
fn matches_filter(entry: &Self::E, _filter: &Self::Filter) -> bool {
!entry.deleted
}
}
+1
View File
@@ -1,5 +1,6 @@
pub mod block;
pub mod block_ref_table;
pub mod bucket_table;
pub mod key_table;
pub mod object_table;
pub mod version_table;
+39 -8
View File
@@ -20,7 +20,38 @@ pub struct Object {
pub key: String,
// Data
pub versions: Vec<Box<ObjectVersion>>,
versions: Vec<ObjectVersion>,
}
impl Object {
pub fn new(bucket: String, key: String, versions: Vec<ObjectVersion>) -> Self {
let mut ret = Self {
bucket,
key,
versions: vec![],
};
for v in versions {
ret.add_version(v)
.expect("Twice the same ObjectVersion in Object constructor");
}
ret
}
/// Adds a version if it wasn't already present
pub fn add_version(&mut self, new: ObjectVersion) -> Result<(), ()> {
match self
.versions
.binary_search_by(|v| v.cmp_key().cmp(&new.cmp_key()))
{
Err(i) => {
self.versions.insert(i, new);
Ok(())
}
Ok(_) => Err(()),
}
}
pub fn versions(&self) -> &[ObjectVersion] {
&self.versions[..]
}
}
#[derive(PartialEq, Clone, Debug, Serialize, Deserialize)]
@@ -113,13 +144,13 @@ impl TableSchema for ObjectTable {
.binary_search_by(|nv| nv.cmp_key().cmp(&v.cmp_key()))
.is_err()
{
let deleted_version = Version {
uuid: v.uuid,
deleted: true,
blocks: vec![],
bucket: old_v.bucket.clone(),
key: old_v.key.clone(),
};
let deleted_version = Version::new(
v.uuid,
old_v.bucket.clone(),
old_v.key.clone(),
true,
vec![],
);
version_table.insert(&deleted_version).await?;
}
}
+37 -1
View File
@@ -18,7 +18,7 @@ pub struct Version {
// Actual data: the blocks for this version
pub deleted: bool,
pub blocks: Vec<VersionBlock>,
blocks: Vec<VersionBlock>,
// Back link to bucket+key so that we can figure if
// this was deleted later on
@@ -26,6 +26,42 @@ pub struct Version {
pub key: String,
}
impl Version {
pub fn new(
uuid: UUID,
bucket: String,
key: String,
deleted: bool,
blocks: Vec<VersionBlock>,
) -> Self {
let mut ret = Self {
uuid,
deleted,
blocks: vec![],
bucket,
key,
};
for b in blocks {
ret.add_block(b)
.expect("Twice the same VersionBlock in Version constructor");
}
ret
}
/// Adds a block if it wasn't already present
pub fn add_block(&mut self, new: VersionBlock) -> Result<(), ()> {
match self.blocks.binary_search_by(|b| b.offset.cmp(&new.offset)) {
Err(i) => {
self.blocks.insert(i, new);
Ok(())
}
Ok(_) => Err(()),
}
}
pub fn blocks(&self) -> &[VersionBlock] {
&self.blocks[..]
}
}
#[derive(PartialEq, Clone, Debug, Serialize, Deserialize)]
pub struct VersionBlock {
pub offset: u64,