|
|
|
@ -25,15 +25,20 @@
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
use {
|
|
|
|
|
super::GNSEvent,
|
|
|
|
|
super::{GNSEvent, TransactionResult},
|
|
|
|
|
crate::{
|
|
|
|
|
engine::{
|
|
|
|
|
core::model::{delta::IRModel, Model},
|
|
|
|
|
core::{
|
|
|
|
|
model::{delta::IRModel, Field, Model},
|
|
|
|
|
space::Space,
|
|
|
|
|
GlobalNS,
|
|
|
|
|
},
|
|
|
|
|
data::uuid::Uuid,
|
|
|
|
|
idx::STIndex,
|
|
|
|
|
idx::{IndexST, IndexSTSeqCns, STIndex, STIndexSeq},
|
|
|
|
|
ql::lex::Ident,
|
|
|
|
|
storage::v1::{
|
|
|
|
|
inf::{self, obj, PersistObject},
|
|
|
|
|
BufferedScanner, SDSSResult,
|
|
|
|
|
inf::{self, map, obj, PersistObject},
|
|
|
|
|
BufferedScanner, SDSSError, SDSSResult,
|
|
|
|
|
},
|
|
|
|
|
txn::TransactionError,
|
|
|
|
|
},
|
|
|
|
@ -42,6 +47,91 @@ use {
|
|
|
|
|
std::marker::PhantomData,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
pub struct ModelID<'a>(PhantomData<&'a ()>);
|
|
|
|
|
#[derive(Debug, Clone, Copy)]
|
|
|
|
|
pub struct ModelIDRef<'a> {
|
|
|
|
|
model_name: &'a str,
|
|
|
|
|
model_uuid: Uuid,
|
|
|
|
|
model_version: u64,
|
|
|
|
|
}
|
|
|
|
|
pub struct ModelIDRes {
|
|
|
|
|
model_name: Box<str>,
|
|
|
|
|
model_uuid: Uuid,
|
|
|
|
|
model_version: u64,
|
|
|
|
|
}
|
|
|
|
|
pub struct ModelIDMD {
|
|
|
|
|
model_name_l: u64,
|
|
|
|
|
model_version: u64,
|
|
|
|
|
model_uuid: Uuid,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<'a> PersistObject for ModelID<'a> {
|
|
|
|
|
const METADATA_SIZE: usize = sizeof!(u64, 2) + sizeof!(u128);
|
|
|
|
|
type InputType = ModelIDRef<'a>;
|
|
|
|
|
type OutputType = ModelIDRes;
|
|
|
|
|
type Metadata = ModelIDMD;
|
|
|
|
|
fn pretest_can_dec_object(scanner: &BufferedScanner, md: &Self::Metadata) -> bool {
|
|
|
|
|
scanner.has_left(md.model_name_l as usize)
|
|
|
|
|
}
|
|
|
|
|
fn meta_enc(buf: &mut Vec<u8>, data: Self::InputType) {
|
|
|
|
|
buf.extend(data.model_name.len().u64_bytes_le());
|
|
|
|
|
buf.extend(data.model_version.to_le_bytes());
|
|
|
|
|
buf.extend(data.model_uuid.to_le_bytes());
|
|
|
|
|
}
|
|
|
|
|
unsafe fn meta_dec(scanner: &mut BufferedScanner) -> SDSSResult<Self::Metadata> {
|
|
|
|
|
Ok(ModelIDMD {
|
|
|
|
|
model_name_l: u64::from_le_bytes(scanner.next_chunk()),
|
|
|
|
|
model_version: u64::from_le_bytes(scanner.next_chunk()),
|
|
|
|
|
model_uuid: Uuid::from_bytes(scanner.next_chunk()),
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
fn obj_enc(buf: &mut Vec<u8>, data: Self::InputType) {
|
|
|
|
|
buf.extend(data.model_name.as_bytes());
|
|
|
|
|
}
|
|
|
|
|
unsafe fn obj_dec(s: &mut BufferedScanner, md: Self::Metadata) -> SDSSResult<Self::OutputType> {
|
|
|
|
|
Ok(ModelIDRes {
|
|
|
|
|
model_name: inf::dec::utils::decode_string(s, md.model_name_l as usize)?
|
|
|
|
|
.into_boxed_str(),
|
|
|
|
|
model_uuid: md.model_uuid,
|
|
|
|
|
model_version: md.model_version,
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn with_space<T>(
|
|
|
|
|
gns: &GlobalNS,
|
|
|
|
|
space_id: &super::SpaceIDRes,
|
|
|
|
|
mut f: impl FnMut(&Space) -> TransactionResult<T>,
|
|
|
|
|
) -> TransactionResult<T> {
|
|
|
|
|
let spaces = gns.spaces().read();
|
|
|
|
|
let Some(space) = spaces.st_get(&space_id.name) else {
|
|
|
|
|
return Err(TransactionError::OnRestoreDataMissing);
|
|
|
|
|
};
|
|
|
|
|
if space.get_uuid() != space_id.uuid {
|
|
|
|
|
return Err(TransactionError::OnRestoreDataConflictMismatch);
|
|
|
|
|
}
|
|
|
|
|
f(space)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn with_model<T>(
|
|
|
|
|
gns: &GlobalNS,
|
|
|
|
|
space_id: &super::SpaceIDRes,
|
|
|
|
|
model_id: &ModelIDRes,
|
|
|
|
|
mut f: impl FnMut(&Model) -> TransactionResult<T>,
|
|
|
|
|
) -> TransactionResult<T> {
|
|
|
|
|
with_space(gns, space_id, |space| {
|
|
|
|
|
let models = space.models().read();
|
|
|
|
|
let Some(model) = models.st_get(&model_id.model_name) else {
|
|
|
|
|
return Err(TransactionError::OnRestoreDataMissing);
|
|
|
|
|
};
|
|
|
|
|
if model.get_uuid() != model_id.model_uuid {
|
|
|
|
|
// this should have been handled by an earlier transaction
|
|
|
|
|
return Err(TransactionError::OnRestoreDataConflictMismatch);
|
|
|
|
|
}
|
|
|
|
|
f(model)
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
create model
|
|
|
|
|
*/
|
|
|
|
@ -58,8 +148,10 @@ impl<'a> CreateModelTxn<'a> {
|
|
|
|
|
model_read: &'a IRModel<'a>,
|
|
|
|
|
) -> CreateModelTxnCommitPL<'a> {
|
|
|
|
|
CreateModelTxnCommitPL {
|
|
|
|
|
space_name,
|
|
|
|
|
space_uuid,
|
|
|
|
|
space_id: super::SpaceIDRef {
|
|
|
|
|
uuid: space_uuid,
|
|
|
|
|
name: space_name,
|
|
|
|
|
},
|
|
|
|
|
model_name,
|
|
|
|
|
model,
|
|
|
|
|
model_read,
|
|
|
|
@ -69,30 +161,28 @@ impl<'a> CreateModelTxn<'a> {
|
|
|
|
|
|
|
|
|
|
#[derive(Clone, Copy)]
|
|
|
|
|
pub struct CreateModelTxnCommitPL<'a> {
|
|
|
|
|
space_name: &'a str,
|
|
|
|
|
space_uuid: Uuid,
|
|
|
|
|
space_id: super::SpaceIDRef<'a>,
|
|
|
|
|
model_name: &'a str,
|
|
|
|
|
model: &'a Model,
|
|
|
|
|
model_read: &'a IRModel<'a>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub struct CreateModelTxnRestorePL {
|
|
|
|
|
space_name: Box<str>,
|
|
|
|
|
space_uuid: Uuid,
|
|
|
|
|
space_id: super::SpaceIDRes,
|
|
|
|
|
model_name: Box<str>,
|
|
|
|
|
model: Model,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub struct CreateModelTxnMD {
|
|
|
|
|
space_name_l: u64,
|
|
|
|
|
space_uuid: Uuid,
|
|
|
|
|
space_id_meta: super::SpaceIDMD,
|
|
|
|
|
model_name_l: u64,
|
|
|
|
|
model_meta: <obj::ModelLayoutRef<'static> as PersistObject>::Metadata,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<'a> PersistObject for CreateModelTxn<'a> {
|
|
|
|
|
const METADATA_SIZE: usize =
|
|
|
|
|
sizeof!(u64, 2) + sizeof!(u128) + <obj::ModelLayoutRef<'a> as PersistObject>::METADATA_SIZE;
|
|
|
|
|
const METADATA_SIZE: usize = <super::SpaceID as PersistObject>::METADATA_SIZE
|
|
|
|
|
+ sizeof!(u64)
|
|
|
|
|
+ <obj::ModelLayoutRef<'a> as PersistObject>::METADATA_SIZE;
|
|
|
|
|
type InputType = CreateModelTxnCommitPL<'a>;
|
|
|
|
|
type OutputType = CreateModelTxnRestorePL;
|
|
|
|
|
type Metadata = CreateModelTxnMD;
|
|
|
|
@ -100,42 +190,44 @@ impl<'a> PersistObject for CreateModelTxn<'a> {
|
|
|
|
|
scanner.has_left((md.model_meta.p_key_len() + md.model_name_l) as usize)
|
|
|
|
|
}
|
|
|
|
|
fn meta_enc(buf: &mut Vec<u8>, data: Self::InputType) {
|
|
|
|
|
buf.extend(data.space_name.len().u64_bytes_le());
|
|
|
|
|
buf.extend(data.space_uuid.to_le_bytes());
|
|
|
|
|
// space ID
|
|
|
|
|
<super::SpaceID as PersistObject>::meta_enc(buf, data.space_id);
|
|
|
|
|
// model name
|
|
|
|
|
buf.extend(data.model_name.len().u64_bytes_le());
|
|
|
|
|
// model meta dump
|
|
|
|
|
<obj::ModelLayoutRef as PersistObject>::meta_enc(
|
|
|
|
|
buf,
|
|
|
|
|
obj::ModelLayoutRef::from((data.model, data.model_read)),
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
unsafe fn meta_dec(scanner: &mut BufferedScanner) -> SDSSResult<Self::Metadata> {
|
|
|
|
|
let space_name_l = u64::from_le_bytes(scanner.next_chunk());
|
|
|
|
|
let space_uuid = Uuid::from_bytes(scanner.next_chunk());
|
|
|
|
|
let space_id = <super::SpaceID as PersistObject>::meta_dec(scanner)?;
|
|
|
|
|
let model_name_l = u64::from_le_bytes(scanner.next_chunk());
|
|
|
|
|
let model_meta = <obj::ModelLayoutRef as PersistObject>::meta_dec(scanner)?;
|
|
|
|
|
Ok(CreateModelTxnMD {
|
|
|
|
|
space_name_l,
|
|
|
|
|
space_uuid,
|
|
|
|
|
space_id_meta: space_id,
|
|
|
|
|
model_name_l,
|
|
|
|
|
model_meta,
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
fn obj_enc(buf: &mut Vec<u8>, data: Self::InputType) {
|
|
|
|
|
// space id dump
|
|
|
|
|
<super::SpaceID as PersistObject>::obj_enc(buf, data.space_id);
|
|
|
|
|
// model name
|
|
|
|
|
buf.extend(data.model_name.as_bytes());
|
|
|
|
|
// model dump
|
|
|
|
|
<obj::ModelLayoutRef as PersistObject>::obj_enc(
|
|
|
|
|
buf,
|
|
|
|
|
obj::ModelLayoutRef::from((data.model, data.model_read)),
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
unsafe fn obj_dec(s: &mut BufferedScanner, md: Self::Metadata) -> SDSSResult<Self::OutputType> {
|
|
|
|
|
let space_name =
|
|
|
|
|
inf::dec::utils::decode_string(s, md.space_name_l as usize)?.into_boxed_str();
|
|
|
|
|
let space_id = <super::SpaceID as PersistObject>::obj_dec(s, md.space_id_meta)?;
|
|
|
|
|
let model_name =
|
|
|
|
|
inf::dec::utils::decode_string(s, md.model_name_l as usize)?.into_boxed_str();
|
|
|
|
|
let model = <obj::ModelLayoutRef as PersistObject>::obj_dec(s, md.model_meta)?;
|
|
|
|
|
Ok(CreateModelTxnRestorePL {
|
|
|
|
|
space_name,
|
|
|
|
|
space_uuid: md.space_uuid,
|
|
|
|
|
space_id,
|
|
|
|
|
model_name,
|
|
|
|
|
model,
|
|
|
|
|
})
|
|
|
|
@ -148,12 +240,11 @@ impl<'a> GNSEvent for CreateModelTxn<'a> {
|
|
|
|
|
type RestoreType = CreateModelTxnRestorePL;
|
|
|
|
|
fn update_global_state(
|
|
|
|
|
CreateModelTxnRestorePL {
|
|
|
|
|
space_name,
|
|
|
|
|
space_uuid,
|
|
|
|
|
space_id,
|
|
|
|
|
model_name,
|
|
|
|
|
model,
|
|
|
|
|
}: Self::RestoreType,
|
|
|
|
|
gns: &crate::engine::core::GlobalNS,
|
|
|
|
|
gns: &GlobalNS,
|
|
|
|
|
) -> crate::engine::txn::TransactionResult<()> {
|
|
|
|
|
let rgns = gns.spaces().read();
|
|
|
|
|
/*
|
|
|
|
@ -164,8 +255,8 @@ impl<'a> GNSEvent for CreateModelTxn<'a> {
|
|
|
|
|
There is no evident way about how this is going to be handled, but the ideal way would be to keep
|
|
|
|
|
versioned index of schemas.
|
|
|
|
|
*/
|
|
|
|
|
match rgns.st_get(&space_name) {
|
|
|
|
|
Some(space) if space.get_uuid() == space_uuid => {
|
|
|
|
|
match rgns.st_get(&space_id.name) {
|
|
|
|
|
Some(space) if space.get_uuid() == space_id.uuid => {
|
|
|
|
|
if space._create_model(&model_name, model).is_ok() {
|
|
|
|
|
Ok(())
|
|
|
|
|
} else {
|
|
|
|
@ -177,3 +268,387 @@ impl<'a> GNSEvent for CreateModelTxn<'a> {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
alter model add
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
pub struct AlterModelAddTxn<'a>(PhantomData<&'a ()>);
|
|
|
|
|
#[derive(Debug, Clone, Copy)]
|
|
|
|
|
pub struct AlterModelAddTxnCommitPL<'a> {
|
|
|
|
|
space_id: super::SpaceIDRef<'a>,
|
|
|
|
|
model_id: ModelIDRef<'a>,
|
|
|
|
|
new_fields: &'a IndexSTSeqCns<Box<str>, Field>,
|
|
|
|
|
}
|
|
|
|
|
pub struct AlterModelAddTxnMD {
|
|
|
|
|
space_id_meta: super::SpaceIDMD,
|
|
|
|
|
model_id_meta: ModelIDMD,
|
|
|
|
|
new_field_c: u64,
|
|
|
|
|
}
|
|
|
|
|
pub struct AlterModelAddTxnRestorePL {
|
|
|
|
|
space_id: super::SpaceIDRes,
|
|
|
|
|
model_id: ModelIDRes,
|
|
|
|
|
new_fields: IndexSTSeqCns<Box<str>, Field>,
|
|
|
|
|
}
|
|
|
|
|
impl<'a> PersistObject for AlterModelAddTxn<'a> {
|
|
|
|
|
const METADATA_SIZE: usize = <super::SpaceID as PersistObject>::METADATA_SIZE
|
|
|
|
|
+ <ModelID as PersistObject>::METADATA_SIZE
|
|
|
|
|
+ sizeof!(u64);
|
|
|
|
|
type InputType = AlterModelAddTxnCommitPL<'a>;
|
|
|
|
|
type OutputType = AlterModelAddTxnRestorePL;
|
|
|
|
|
type Metadata = AlterModelAddTxnMD;
|
|
|
|
|
fn pretest_can_dec_object(scanner: &BufferedScanner, md: &Self::Metadata) -> bool {
|
|
|
|
|
scanner.has_left((md.space_id_meta.space_name_l + md.model_id_meta.model_name_l) as usize)
|
|
|
|
|
}
|
|
|
|
|
fn meta_enc(buf: &mut Vec<u8>, data: Self::InputType) {
|
|
|
|
|
<super::SpaceID as PersistObject>::meta_enc(buf, data.space_id);
|
|
|
|
|
<ModelID as PersistObject>::meta_enc(buf, data.model_id);
|
|
|
|
|
buf.extend(data.new_fields.st_len().u64_bytes_le());
|
|
|
|
|
}
|
|
|
|
|
unsafe fn meta_dec(scanner: &mut BufferedScanner) -> SDSSResult<Self::Metadata> {
|
|
|
|
|
let space_id_meta = <super::SpaceID as PersistObject>::meta_dec(scanner)?;
|
|
|
|
|
let model_id_meta = <ModelID as PersistObject>::meta_dec(scanner)?;
|
|
|
|
|
let new_field_c = u64::from_le_bytes(scanner.next_chunk());
|
|
|
|
|
Ok(AlterModelAddTxnMD {
|
|
|
|
|
space_id_meta,
|
|
|
|
|
model_id_meta,
|
|
|
|
|
new_field_c,
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
fn obj_enc(buf: &mut Vec<u8>, data: Self::InputType) {
|
|
|
|
|
<super::SpaceID as PersistObject>::obj_enc(buf, data.space_id);
|
|
|
|
|
<ModelID as PersistObject>::obj_enc(buf, data.model_id);
|
|
|
|
|
<map::PersistMapImpl<map::FieldMapSpec> as PersistObject>::obj_enc(buf, data.new_fields);
|
|
|
|
|
}
|
|
|
|
|
unsafe fn obj_dec(s: &mut BufferedScanner, md: Self::Metadata) -> SDSSResult<Self::OutputType> {
|
|
|
|
|
let space_id = <super::SpaceID as PersistObject>::obj_dec(s, md.space_id_meta)?;
|
|
|
|
|
let model_id = <ModelID as PersistObject>::obj_dec(s, md.model_id_meta)?;
|
|
|
|
|
let new_fields = <map::PersistMapImpl<map::FieldMapSpec> as PersistObject>::obj_dec(
|
|
|
|
|
s,
|
|
|
|
|
map::MapIndexSizeMD(md.new_field_c as usize),
|
|
|
|
|
)?;
|
|
|
|
|
Ok(AlterModelAddTxnRestorePL {
|
|
|
|
|
space_id,
|
|
|
|
|
model_id,
|
|
|
|
|
new_fields,
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<'a> GNSEvent for AlterModelAddTxn<'a> {
|
|
|
|
|
const OPC: u16 = 4;
|
|
|
|
|
type CommitType = AlterModelAddTxnCommitPL<'a>;
|
|
|
|
|
type RestoreType = AlterModelAddTxnRestorePL;
|
|
|
|
|
fn update_global_state(
|
|
|
|
|
AlterModelAddTxnRestorePL {
|
|
|
|
|
space_id,
|
|
|
|
|
model_id,
|
|
|
|
|
new_fields,
|
|
|
|
|
}: Self::RestoreType,
|
|
|
|
|
gns: &GlobalNS,
|
|
|
|
|
) -> crate::engine::txn::TransactionResult<()> {
|
|
|
|
|
with_model(gns, &space_id, &model_id, |model| {
|
|
|
|
|
let mut wmodel = model.intent_write_model();
|
|
|
|
|
for (i, (field_name, field)) in new_fields.stseq_ord_kv().enumerate() {
|
|
|
|
|
if !wmodel
|
|
|
|
|
.fields_mut()
|
|
|
|
|
.st_insert(field_name.to_owned(), field.clone())
|
|
|
|
|
{
|
|
|
|
|
// rollback; corrupted
|
|
|
|
|
new_fields.stseq_ord_key().take(i).for_each(|field_id| {
|
|
|
|
|
let _ = wmodel.fields_mut().st_delete(field_id);
|
|
|
|
|
});
|
|
|
|
|
return Err(TransactionError::OnRestoreDataConflictMismatch);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Ok(())
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
alter model remove
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
pub struct AlterModelRemoveTxn<'a>(PhantomData<&'a ()>);
|
|
|
|
|
#[derive(Debug, Clone, Copy)]
|
|
|
|
|
pub struct AlterModelRemoveTxnCommitPL<'a> {
|
|
|
|
|
space_id: super::SpaceIDRef<'a>,
|
|
|
|
|
model_id: ModelIDRef<'a>,
|
|
|
|
|
removed_fields: &'a [Ident<'a>],
|
|
|
|
|
}
|
|
|
|
|
pub struct AlterModelRemoveTxnMD {
|
|
|
|
|
space_id_meta: super::SpaceIDMD,
|
|
|
|
|
model_id_meta: ModelIDMD,
|
|
|
|
|
remove_field_c: u64,
|
|
|
|
|
}
|
|
|
|
|
pub struct AlterModelRemoveTxnRestorePL {
|
|
|
|
|
space_id: super::SpaceIDRes,
|
|
|
|
|
model_id: ModelIDRes,
|
|
|
|
|
removed_fields: Box<[Box<str>]>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<'a> PersistObject for AlterModelRemoveTxn<'a> {
|
|
|
|
|
const METADATA_SIZE: usize = <super::SpaceID as PersistObject>::METADATA_SIZE
|
|
|
|
|
+ <ModelID as PersistObject>::METADATA_SIZE
|
|
|
|
|
+ sizeof!(u64);
|
|
|
|
|
type InputType = AlterModelRemoveTxnCommitPL<'a>;
|
|
|
|
|
type OutputType = AlterModelRemoveTxnRestorePL;
|
|
|
|
|
type Metadata = AlterModelRemoveTxnMD;
|
|
|
|
|
fn pretest_can_dec_object(scanner: &BufferedScanner, md: &Self::Metadata) -> bool {
|
|
|
|
|
scanner.has_left((md.space_id_meta.space_name_l + md.model_id_meta.model_name_l) as usize)
|
|
|
|
|
}
|
|
|
|
|
fn meta_enc(buf: &mut Vec<u8>, data: Self::InputType) {
|
|
|
|
|
<super::SpaceID as PersistObject>::meta_enc(buf, data.space_id);
|
|
|
|
|
<ModelID as PersistObject>::meta_enc(buf, data.model_id);
|
|
|
|
|
buf.extend(data.removed_fields.len().u64_bytes_le());
|
|
|
|
|
}
|
|
|
|
|
unsafe fn meta_dec(scanner: &mut BufferedScanner) -> SDSSResult<Self::Metadata> {
|
|
|
|
|
let space_id_meta = <super::SpaceID as PersistObject>::meta_dec(scanner)?;
|
|
|
|
|
let model_id_meta = <ModelID as PersistObject>::meta_dec(scanner)?;
|
|
|
|
|
Ok(AlterModelRemoveTxnMD {
|
|
|
|
|
space_id_meta,
|
|
|
|
|
model_id_meta,
|
|
|
|
|
remove_field_c: u64::from_le_bytes(scanner.next_chunk()),
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
fn obj_enc(buf: &mut Vec<u8>, data: Self::InputType) {
|
|
|
|
|
<super::SpaceID as PersistObject>::obj_enc(buf, data.space_id);
|
|
|
|
|
<ModelID as PersistObject>::obj_enc(buf, data.model_id);
|
|
|
|
|
for field in data.removed_fields {
|
|
|
|
|
buf.extend(field.len().u64_bytes_le());
|
|
|
|
|
buf.extend(field.as_bytes());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
unsafe fn obj_dec(s: &mut BufferedScanner, md: Self::Metadata) -> SDSSResult<Self::OutputType> {
|
|
|
|
|
let space_id = <super::SpaceID as PersistObject>::obj_dec(s, md.space_id_meta)?;
|
|
|
|
|
let model_id = <ModelID as PersistObject>::obj_dec(s, md.model_id_meta)?;
|
|
|
|
|
let mut removed_fields = Vec::with_capacity(md.remove_field_c as usize);
|
|
|
|
|
while !s.eof()
|
|
|
|
|
& (removed_fields.len() as u64 != md.remove_field_c)
|
|
|
|
|
& s.has_left(sizeof!(u64))
|
|
|
|
|
{
|
|
|
|
|
let len = u64::from_le_bytes(s.next_chunk()) as usize;
|
|
|
|
|
if !s.has_left(len) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
removed_fields.push(inf::dec::utils::decode_string(s, len)?.into_boxed_str());
|
|
|
|
|
}
|
|
|
|
|
if removed_fields.len() as u64 != md.remove_field_c {
|
|
|
|
|
return Err(SDSSError::InternalDecodeStructureCorruptedPayload);
|
|
|
|
|
}
|
|
|
|
|
Ok(AlterModelRemoveTxnRestorePL {
|
|
|
|
|
space_id,
|
|
|
|
|
model_id,
|
|
|
|
|
removed_fields: removed_fields.into_boxed_slice(),
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<'a> GNSEvent for AlterModelRemoveTxn<'a> {
|
|
|
|
|
const OPC: u16 = 5;
|
|
|
|
|
type CommitType = AlterModelRemoveTxnCommitPL<'a>;
|
|
|
|
|
type RestoreType = AlterModelRemoveTxnRestorePL;
|
|
|
|
|
fn update_global_state(
|
|
|
|
|
AlterModelRemoveTxnRestorePL {
|
|
|
|
|
space_id,
|
|
|
|
|
model_id,
|
|
|
|
|
removed_fields,
|
|
|
|
|
}: Self::RestoreType,
|
|
|
|
|
gns: &GlobalNS,
|
|
|
|
|
) -> crate::engine::txn::TransactionResult<()> {
|
|
|
|
|
with_model(gns, &space_id, &model_id, |model| {
|
|
|
|
|
let mut iwm = model.intent_write_model();
|
|
|
|
|
let mut removed_fields_rb = vec![];
|
|
|
|
|
for removed_field in removed_fields.iter() {
|
|
|
|
|
match iwm.fields_mut().st_delete_return(removed_field) {
|
|
|
|
|
Some(field) => {
|
|
|
|
|
removed_fields_rb.push((removed_field as &str, field));
|
|
|
|
|
}
|
|
|
|
|
None => {
|
|
|
|
|
// rollback
|
|
|
|
|
removed_fields_rb.into_iter().for_each(|(field_id, field)| {
|
|
|
|
|
let _ = iwm.fields_mut().st_insert(field_id.into(), field);
|
|
|
|
|
});
|
|
|
|
|
return Err(TransactionError::OnRestoreDataConflictMismatch);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Ok(())
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
alter model update
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
pub struct AlterModelUpdateTxn<'a>(PhantomData<&'a ()>);
|
|
|
|
|
#[derive(Debug, Clone, Copy)]
|
|
|
|
|
pub struct AlterModelUpdateTxnCommitPL<'a> {
|
|
|
|
|
space_id: super::SpaceIDRef<'a>,
|
|
|
|
|
model_id: ModelIDRef<'a>,
|
|
|
|
|
updated_fields: &'a IndexST<Box<str>, Field>,
|
|
|
|
|
}
|
|
|
|
|
pub struct AlterModelUpdateTxnMD {
|
|
|
|
|
space_id_md: super::SpaceIDMD,
|
|
|
|
|
model_id_md: ModelIDMD,
|
|
|
|
|
updated_field_c: u64,
|
|
|
|
|
}
|
|
|
|
|
pub struct AlterModelUpdateTxnRestorePL {
|
|
|
|
|
space_id: super::SpaceIDRes,
|
|
|
|
|
model_id: ModelIDRes,
|
|
|
|
|
updated_fields: IndexST<Box<str>, Field>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<'a> PersistObject for AlterModelUpdateTxn<'a> {
|
|
|
|
|
const METADATA_SIZE: usize = <super::SpaceID as PersistObject>::METADATA_SIZE
|
|
|
|
|
+ <ModelID as PersistObject>::METADATA_SIZE
|
|
|
|
|
+ sizeof!(u64);
|
|
|
|
|
type InputType = AlterModelUpdateTxnCommitPL<'a>;
|
|
|
|
|
type OutputType = AlterModelUpdateTxnRestorePL;
|
|
|
|
|
type Metadata = AlterModelUpdateTxnMD;
|
|
|
|
|
fn pretest_can_dec_object(scanner: &BufferedScanner, md: &Self::Metadata) -> bool {
|
|
|
|
|
scanner
|
|
|
|
|
.has_left(md.space_id_md.space_name_l as usize + md.model_id_md.model_name_l as usize)
|
|
|
|
|
}
|
|
|
|
|
fn meta_enc(buf: &mut Vec<u8>, data: Self::InputType) {
|
|
|
|
|
<super::SpaceID as PersistObject>::meta_enc(buf, data.space_id);
|
|
|
|
|
<ModelID as PersistObject>::meta_enc(buf, data.model_id);
|
|
|
|
|
buf.extend(data.updated_fields.st_len().u64_bytes_le());
|
|
|
|
|
}
|
|
|
|
|
unsafe fn meta_dec(scanner: &mut BufferedScanner) -> SDSSResult<Self::Metadata> {
|
|
|
|
|
let space_id_md = <super::SpaceID as PersistObject>::meta_dec(scanner)?;
|
|
|
|
|
let model_id_md = <ModelID as PersistObject>::meta_dec(scanner)?;
|
|
|
|
|
Ok(AlterModelUpdateTxnMD {
|
|
|
|
|
space_id_md,
|
|
|
|
|
model_id_md,
|
|
|
|
|
updated_field_c: u64::from_le_bytes(scanner.next_chunk()),
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
fn obj_enc(buf: &mut Vec<u8>, data: Self::InputType) {
|
|
|
|
|
<super::SpaceID as PersistObject>::obj_enc(buf, data.space_id);
|
|
|
|
|
<ModelID as PersistObject>::obj_enc(buf, data.model_id);
|
|
|
|
|
<map::PersistMapImpl<map::FieldMapSpecST> as PersistObject>::obj_enc(
|
|
|
|
|
buf,
|
|
|
|
|
data.updated_fields,
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
unsafe fn obj_dec(s: &mut BufferedScanner, md: Self::Metadata) -> SDSSResult<Self::OutputType> {
|
|
|
|
|
let space_id = <super::SpaceID as PersistObject>::obj_dec(s, md.space_id_md)?;
|
|
|
|
|
let model_id = <ModelID as PersistObject>::obj_dec(s, md.model_id_md)?;
|
|
|
|
|
let updated_fields = <map::PersistMapImpl<map::FieldMapSpecST> as PersistObject>::obj_dec(
|
|
|
|
|
s,
|
|
|
|
|
map::MapIndexSizeMD(md.updated_field_c as usize),
|
|
|
|
|
)?;
|
|
|
|
|
Ok(AlterModelUpdateTxnRestorePL {
|
|
|
|
|
space_id,
|
|
|
|
|
model_id,
|
|
|
|
|
updated_fields,
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<'a> GNSEvent for AlterModelUpdateTxn<'a> {
|
|
|
|
|
const OPC: u16 = 6;
|
|
|
|
|
type CommitType = AlterModelUpdateTxnCommitPL<'a>;
|
|
|
|
|
type RestoreType = AlterModelUpdateTxnRestorePL;
|
|
|
|
|
fn update_global_state(
|
|
|
|
|
AlterModelUpdateTxnRestorePL {
|
|
|
|
|
space_id,
|
|
|
|
|
model_id,
|
|
|
|
|
updated_fields,
|
|
|
|
|
}: Self::RestoreType,
|
|
|
|
|
gns: &GlobalNS,
|
|
|
|
|
) -> TransactionResult<()> {
|
|
|
|
|
with_model(gns, &space_id, &model_id, |model| {
|
|
|
|
|
let mut iwm = model.intent_write_model();
|
|
|
|
|
let mut fields_rb = vec![];
|
|
|
|
|
for (field_id, field) in updated_fields.iter() {
|
|
|
|
|
match iwm.fields_mut().st_update_return(field_id, field.clone()) {
|
|
|
|
|
Some(f) => fields_rb.push((field_id as &str, f)),
|
|
|
|
|
None => {
|
|
|
|
|
// rollback
|
|
|
|
|
fields_rb.into_iter().for_each(|(field_id, field)| {
|
|
|
|
|
let _ = iwm.fields_mut().st_update(field_id, field);
|
|
|
|
|
});
|
|
|
|
|
return Err(TransactionError::OnRestoreDataConflictMismatch);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Ok(())
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
drop model
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
pub struct DropModelTxn<'a>(PhantomData<&'a ()>);
|
|
|
|
|
#[derive(Debug, Clone, Copy)]
|
|
|
|
|
pub struct DropModelTxnCommitPL<'a> {
|
|
|
|
|
space_id: super::SpaceIDRef<'a>,
|
|
|
|
|
model_id: ModelIDRef<'a>,
|
|
|
|
|
}
|
|
|
|
|
pub struct DropModelTxnMD {
|
|
|
|
|
space_id_md: super::SpaceIDMD,
|
|
|
|
|
model_id_md: ModelIDMD,
|
|
|
|
|
}
|
|
|
|
|
pub struct DropModelTxnRestorePL {
|
|
|
|
|
space_id: super::SpaceIDRes,
|
|
|
|
|
model_id: ModelIDRes,
|
|
|
|
|
}
|
|
|
|
|
impl<'a> PersistObject for DropModelTxn<'a> {
|
|
|
|
|
const METADATA_SIZE: usize = <super::SpaceID as PersistObject>::METADATA_SIZE
|
|
|
|
|
+ <ModelID as PersistObject>::METADATA_SIZE;
|
|
|
|
|
type InputType = DropModelTxnCommitPL<'a>;
|
|
|
|
|
type OutputType = DropModelTxnRestorePL;
|
|
|
|
|
type Metadata = DropModelTxnMD;
|
|
|
|
|
fn pretest_can_dec_object(scanner: &BufferedScanner, md: &Self::Metadata) -> bool {
|
|
|
|
|
scanner
|
|
|
|
|
.has_left(md.space_id_md.space_name_l as usize + md.model_id_md.model_name_l as usize)
|
|
|
|
|
}
|
|
|
|
|
fn meta_enc(buf: &mut Vec<u8>, data: Self::InputType) {
|
|
|
|
|
<super::SpaceID as PersistObject>::meta_enc(buf, data.space_id);
|
|
|
|
|
<ModelID as PersistObject>::meta_enc(buf, data.model_id);
|
|
|
|
|
}
|
|
|
|
|
unsafe fn meta_dec(scanner: &mut BufferedScanner) -> SDSSResult<Self::Metadata> {
|
|
|
|
|
let space_id_md = <super::SpaceID as PersistObject>::meta_dec(scanner)?;
|
|
|
|
|
let model_id_md = <ModelID as PersistObject>::meta_dec(scanner)?;
|
|
|
|
|
Ok(DropModelTxnMD {
|
|
|
|
|
space_id_md,
|
|
|
|
|
model_id_md,
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
fn obj_enc(buf: &mut Vec<u8>, data: Self::InputType) {
|
|
|
|
|
<super::SpaceID as PersistObject>::obj_enc(buf, data.space_id);
|
|
|
|
|
<ModelID as PersistObject>::obj_enc(buf, data.model_id);
|
|
|
|
|
}
|
|
|
|
|
unsafe fn obj_dec(s: &mut BufferedScanner, md: Self::Metadata) -> SDSSResult<Self::OutputType> {
|
|
|
|
|
let space_id = <super::SpaceID as PersistObject>::obj_dec(s, md.space_id_md)?;
|
|
|
|
|
let model_id = <ModelID as PersistObject>::obj_dec(s, md.model_id_md)?;
|
|
|
|
|
Ok(DropModelTxnRestorePL { space_id, model_id })
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<'a> GNSEvent for DropModelTxn<'a> {
|
|
|
|
|
const OPC: u16 = 7;
|
|
|
|
|
type CommitType = DropModelTxnCommitPL<'a>;
|
|
|
|
|
type RestoreType = DropModelTxnRestorePL;
|
|
|
|
|
fn update_global_state(
|
|
|
|
|
DropModelTxnRestorePL { space_id, model_id }: Self::RestoreType,
|
|
|
|
|
gns: &GlobalNS,
|
|
|
|
|
) -> TransactionResult<()> {
|
|
|
|
|
with_space(gns, &space_id, |space| {
|
|
|
|
|
let mut wgns = space.models().write();
|
|
|
|
|
match wgns.st_delete_if(&model_id.model_name, |mdl| {
|
|
|
|
|
mdl.get_uuid() == model_id.model_uuid
|
|
|
|
|
}) {
|
|
|
|
|
Some(true) => Ok(()),
|
|
|
|
|
Some(false) => return Err(TransactionError::OnRestoreDataConflictMismatch),
|
|
|
|
|
None => Err(TransactionError::OnRestoreDataMissing),
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|