refactor: map delete value

This commit is contained in:
leeeon233 2023-09-15 13:52:40 +08:00
parent fb64ff5422
commit 3f3fcc11f3
11 changed files with 103 additions and 63 deletions

View file

@ -10,7 +10,7 @@ use crate::{
container::{
idx::ContainerIdx,
list::list_op::{InnerListOp, ListOp},
map::InnerMapSet,
map::{InnerMapSet, MapSet},
text::text_content::SliceRange,
ContainerID,
},
@ -81,15 +81,16 @@ impl<'a> OpConverter<'a> {
};
match content {
crate::op::RawOpContent::Map(map) => {
let value = _alloc_value(&mut self.values, map.value) as u32;
crate::op::RawOpContent::Map(MapSet { key, value }) => {
let value = if let Some(value) = value {
Some(_alloc_value(&mut self.values, value) as u32)
} else {
None
};
Op {
counter,
container,
content: crate::op::InnerContent::Map(InnerMapSet {
key: map.key,
value,
}),
content: crate::op::InnerContent::Map(InnerMapSet { key, value }),
}
}
crate::op::RawOpContent::List(list) => match list {
@ -291,15 +292,16 @@ impl SharedArena {
container: ContainerIdx,
) -> Op {
match content {
crate::op::RawOpContent::Map(map) => {
let value = self.alloc_value(map.value) as u32;
crate::op::RawOpContent::Map(MapSet { key, value }) => {
let value = if let Some(value) = value {
Some(self.alloc_value(value) as u32)
} else {
None
};
Op {
counter,
container,
content: crate::op::InnerContent::Map(InnerMapSet {
key: map.key,
value,
}),
content: crate::op::InnerContent::Map(InnerMapSet { key, value }),
}
}
crate::op::RawOpContent::List(list) => match list {

View file

@ -7,14 +7,15 @@ use crate::{InternalString, LoroValue};
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct MapSet {
pub(crate) key: InternalString,
pub(crate) value: LoroValue,
// the key is deleted if value is None
pub(crate) value: Option<LoroValue>,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct InnerMapSet {
pub(crate) key: InternalString,
// FIXME: how to set None?
pub(crate) value: u32,
// the key is deleted if value is None
pub(crate) value: Option<u32>,
}
impl Mergable for MapSet {}
@ -50,9 +51,9 @@ mod test {
fn fix_fields_order() {
let map_set = vec![MapSet {
key: "key".to_string().into(),
value: "value".to_string().into(),
value: Some("value".to_string().into()),
}];
let map_set_buf = vec![1, 3, 107, 101, 121, 4, 5, 118, 97, 108, 117, 101];
let map_set_buf = vec![1, 3, 107, 101, 121, 1, 4, 5, 118, 97, 108, 117, 101];
assert_eq!(
postcard::from_bytes::<Vec<MapSet>>(&map_set_buf).unwrap(),
map_set

View file

@ -293,7 +293,7 @@ impl DiffCalculatorTrait for MapDiffCalculator {
for (key, value) in changed {
let value = value
.map(|v| {
let value = oplog.arena.get_value(v.value as usize);
let value = v.value.map(|v| oplog.arena.get_value(v as usize)).flatten();
MapValue {
counter: v.counter,
value,
@ -317,7 +317,7 @@ struct CompactMapValue {
lamport: Lamport,
peer: PeerID,
counter: Counter,
value: u32,
value: Option<u32>,
}
impl HasId for CompactMapValue {

View file

@ -51,7 +51,7 @@ struct OpEncoding {
/// key index or insert/delete pos
#[columnar(strategy = "DeltaRle")]
prop: usize,
value: LoroValue,
value: Option<LoroValue>,
}
#[columnar(vec, ser, de, iterable)]
@ -169,16 +169,16 @@ pub(super) fn encode_oplog_changes(oplog: &OpLog, vv: &VersionVector) -> Vec<u8>
ListOp::Insert { slice, pos } => (
pos,
// TODO: perf may be optimized by using borrow type instead
match slice {
Some(match slice {
ListSlice::RawData(v) => LoroValue::List(Arc::new(v.to_vec())),
ListSlice::RawStr {
str,
unicode_len: _,
} => LoroValue::String(Arc::new(str.to_string())),
},
}),
),
ListOp::Delete(span) => {
(span.pos as usize, LoroValue::I32(span.len as i32))
(span.pos as usize, Some(LoroValue::I32(span.len as i32)))
}
},
};
@ -270,6 +270,7 @@ pub(super) fn decode_changes_to_inner_format_oplog(
}
ContainerType::List | ContainerType::Text => {
let pos = prop;
let value = value.unwrap();
let list_op = match value {
LoroValue::I32(len) => ListOp::Delete(DeleteSpan {
pos: pos as isize,

View file

@ -110,7 +110,7 @@ struct DocEncoding<'a> {
#[columnar(borrow)]
root_containers: VarZeroVec<'a, RootContainerULE, Index32>,
start_counter: Vec<Counter>,
values: Vec<LoroValue>,
values: Vec<Option<LoroValue>>,
clients: Vec<PeerID>,
keys: Vec<InternalString>,
}
@ -200,7 +200,7 @@ pub fn encode_oplog_v2(oplog: &OpLog, vv: &VersionVector) -> Vec<u8> {
let mut len = 0;
match slice {
ListSlice::RawData(v) => {
values.push(LoroValue::List(Arc::new(v.to_vec())));
values.push(Some(LoroValue::List(Arc::new(v.to_vec()))));
}
ListSlice::RawStr {
str,
@ -451,7 +451,7 @@ pub fn decode_oplog_v2(oplog: &mut OpLog, input: &[u8]) -> Result<(), LoroError>
})
}
ContainerType::List => {
let value = value_iter.next().unwrap();
let value = value_iter.next().flatten().unwrap();
RawOpContent::List(ListOp::Insert {
slice: ListSlice::RawData(Cow::Owned(
match Arc::try_unwrap(value.into_list().unwrap()) {

View file

@ -527,7 +527,7 @@ impl MapHandler {
self.container_idx,
crate::op::RawOpContent::Map(crate::container::map::MapSet {
key: key.into(),
value,
value: Some(value),
}),
None,
&self.state,
@ -548,7 +548,7 @@ impl MapHandler {
self.container_idx,
crate::op::RawOpContent::Map(crate::container::map::MapSet {
key: key.into(),
value: LoroValue::Container(container_id),
value: Some(LoroValue::Container(container_id)),
}),
None,
&self.state,
@ -562,8 +562,7 @@ impl MapHandler {
self.container_idx,
crate::op::RawOpContent::Map(crate::container::map::MapSet {
key: key.into(),
// TODO: use another special value to delete?
value: LoroValue::Null,
value: None,
}),
None,
&self.state,

View file

@ -198,10 +198,10 @@ mod test {
RawOpContent::List(ListOp::Delete(DeleteSpan { pos: 0, len: 1 })),
RawOpContent::Map(MapSet {
key: "a".to_string().into(),
value: "b".to_string().into(),
value: Some("b".to_string().into()),
}),
];
let remote_content_buf = vec![2, 1, 1, 0, 2, 0, 1, 97, 4, 1, 98];
let remote_content_buf = vec![2, 1, 1, 0, 2, 0, 1, 97, 1, 4, 1, 98];
assert_eq!(
postcard::from_bytes::<Vec<RawOpContent>>(&remote_content_buf).unwrap(),
remote_content

View file

@ -382,10 +382,13 @@ impl OpLog {
}
},
crate::op::InnerContent::Map(map) => {
let value = self.arena.get_value(map.value as usize);
let value = map
.value
.map(|v| self.arena.get_value(v as usize))
.flatten();
contents.push(RawOpContent::Map(crate::container::map::MapSet {
key: map.key.clone(),
value: value.unwrap_or(crate::LoroValue::Null), // TODO: decide map delete value
value,
}))
}
};

View file

@ -145,7 +145,7 @@ pub fn decode_oplog(
id,
InnerContent::Map(InnerMapSet {
key: (&*keys[key]).into(),
value: value_idx_plus_one - 1,
value: value_idx_plus_one.map(|v| v - 1),
}),
container_idx,
),
@ -326,14 +326,26 @@ struct EncodedSnapshotOp {
// List: 0 | value index
// Map: value index
#[columnar(strategy = "DeltaRle")]
value: usize,
value: isize,
}
enum SnapshotOp {
TextInsert { pos: usize, len: usize },
ListInsert { pos: usize, value_idx: u32 },
TextOrListDelete { pos: usize, len: isize },
Map { key: usize, value_idx_plus_one: u32 },
TextInsert {
pos: usize,
len: usize,
},
ListInsert {
pos: usize,
value_idx: u32,
},
TextOrListDelete {
pos: usize,
len: isize,
},
Map {
key: usize,
value_idx_plus_one: Option<u32>,
},
}
impl EncodedSnapshotOp {
@ -366,9 +378,14 @@ impl EncodedSnapshotOp {
}
pub fn get_map(&self) -> SnapshotOp {
let value_idx_plus_one = if self.value < 0 {
None
} else {
Some(self.value as u32)
};
SnapshotOp::Map {
key: self.prop,
value_idx_plus_one: self.value as u32,
value_idx_plus_one,
}
}
@ -382,7 +399,7 @@ impl EncodedSnapshotOp {
prop: pos,
len: 0,
is_del: false,
value: start as usize,
value: start as isize,
},
SnapshotOp::TextOrListDelete { pos, len } => Self {
container,
@ -394,13 +411,16 @@ impl EncodedSnapshotOp {
SnapshotOp::Map {
key,
value_idx_plus_one: value,
} => Self {
container,
prop: key,
len: 0,
is_del: false,
value: value as usize,
},
} => {
let value = if let Some(v) = value { v as isize } else { -1 };
Self {
container,
prop: key,
len: 0,
is_del: false,
value,
}
}
SnapshotOp::TextInsert { pos, len } => Self {
container,
prop: pos,
@ -666,17 +686,19 @@ fn encode_oplog(oplog: &OpLog, state_ref: Option<PreEncodedState>) -> FinalPhase
},
InnerContent::Map(map) => {
let key = record_key(&map.key);
let value = oplog.arena.get_value(map.value as usize);
// FIXME: delete in map
let value = map
.value
.map(|v| oplog.arena.get_value(v as usize))
.flatten();
let value = if let Some(value) = value {
record_value(&value) + 1
Some((record_value(&value) + 1) as u32)
} else {
0
None
};
encoded_ops.push(EncodedSnapshotOp::from(
SnapshotOp::Map {
key,
value_idx_plus_one: value as u32,
value_idx_plus_one: value,
},
op.container.to_index(),
));

View file

@ -5,7 +5,7 @@ use loro_common::ContainerID;
use crate::{
arena::SharedArena,
container::idx::ContainerIdx,
container::{idx::ContainerIdx, map::MapSet},
delta::MapValue,
event::{Diff, Index},
op::{RawOp, RawOpContent},
@ -39,18 +39,30 @@ impl ContainerState for MapState {
fn apply_op(&mut self, op: RawOp, arena: &SharedArena) {
match op.content {
RawOpContent::Map(map) => {
if map.value.is_container() {
let idx = arena.register_container(map.value.as_container().unwrap());
RawOpContent::Map(MapSet { key, value }) => {
if value.is_none() {
self.insert(
key,
MapValue {
lamport: (op.lamport, op.id.peer),
counter: op.id.counter,
value: None,
},
);
return;
}
let value = value.unwrap();
if value.is_container() {
let idx = arena.register_container(value.as_container().unwrap());
arena.set_parent(idx, Some(self.idx));
}
self.insert(
map.key,
key,
MapValue {
lamport: (op.lamport, op.id.peer),
counter: op.id.counter,
value: Some(map.value),
value: Some(value),
},
)
}

View file

@ -342,13 +342,13 @@ fn change_to_diff(
),
},
crate::op::InnerContent::Map(map) => {
let value = arena.get_value(map.value as usize).unwrap();
let value = map.value.map(|v| arena.get_value(v as usize)).flatten();
let mut updated: FxHashMap<_, _> = Default::default();
updated.insert(
map.key.clone(),
MapValue {
counter,
value: Some(value),
value,
lamport: (lamport, peer),
},
);