/* * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC * * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL */ use crate::{SerializeInfallible, U64_LEN}; use ahash::AHashSet; use types::collection::{SyncCollection, VanishedCollection}; use utils::{codec::leb128::Leb128Vec, map::vec_map::VecMap}; use super::key::KeySerializer; #[derive(Default, Debug)] pub(crate) struct ChangeLogBuilder { pub changes: VecMap, pub vanished: VecMap, } #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub enum VanishedItem { Name(String), Id(u64), IdPair(u32, u32), } #[derive(Default, Debug)] pub(crate) struct VanishedItems(Vec); #[derive(Default, Debug)] pub struct Changes { pub item_inserts: AHashSet, pub item_updates: AHashSet, pub item_deletes: AHashSet, pub container_inserts: AHashSet, pub container_updates: AHashSet, pub container_deletes: AHashSet, pub container_property_changes: AHashSet, } impl ChangeLogBuilder { pub fn log_container_insert(&mut self, collection: SyncCollection, document_id: u32) { let changes = self.changes.get_mut_or_insert(collection); if changes.container_deletes.remove(&document_id) { changes.container_updates.insert(document_id); } else { changes.container_inserts.insert(document_id); } } pub fn log_item_insert( &mut self, collection: SyncCollection, prefix: Option, document_id: u32, ) { let id = build_id(prefix, document_id); let changes = self.changes.get_mut_or_insert(collection); if changes.item_deletes.remove(&id) { changes.item_updates.insert(id); } else { changes.item_inserts.insert(id); } } pub fn log_container_update(&mut self, collection: SyncCollection, document_id: u32) { self.changes .get_mut_or_insert(collection) .container_updates .insert(document_id); } pub fn log_container_property_update(&mut self, collection: SyncCollection, document_id: u32) { self.changes .get_mut_or_insert(collection) .container_property_changes .insert(document_id); } pub fn log_item_update( &mut self, collection: SyncCollection, prefix: Option, document_id: u32, ) { self.changes .get_mut_or_insert(collection) .item_updates .insert(build_id(prefix, document_id)); } pub fn log_container_delete(&mut self, collection: SyncCollection, document_id: u32) { let changes = self.changes.get_mut_or_insert(collection); let id = document_id; changes.container_updates.remove(&id); changes.container_property_changes.remove(&id); changes.container_deletes.insert(id); } pub fn log_item_delete( &mut self, collection: SyncCollection, prefix: Option, document_id: u32, ) { let changes = self.changes.get_mut_or_insert(collection); let id = build_id(prefix, document_id); changes.item_updates.remove(&id); changes.item_deletes.insert(id); } pub fn log_vanished_item( &mut self, collection: VanishedCollection, item: impl Into, ) { self.vanished .get_mut_or_insert(collection) .0 .push(item.into()); } } #[inline(always)] fn build_id(prefix: Option, document_id: u32) -> u64 { if let Some(prefix) = prefix { ((prefix as u64) << 32) | document_id as u64 } else { document_id as u64 } } impl Changes { pub fn has_container_changes(&self) -> bool { !self.container_inserts.is_empty() || !self.container_updates.is_empty() || !self.container_property_changes.is_empty() || !self.container_deletes.is_empty() } pub fn has_item_changes(&self) -> bool { !self.item_inserts.is_empty() || !self.item_updates.is_empty() || !self.item_deletes.is_empty() } } impl SerializeInfallible for Changes { fn serialize(&self) -> Vec { let mut buf = Vec::with_capacity( 1 + (self.item_inserts.len() + self.item_updates.len() + self.item_deletes.len() + self.container_inserts.len() + self.container_updates.len() + self.container_property_changes.len() + self.container_deletes.len() + 4) * std::mem::size_of::(), ); buf.push_leb128(self.container_inserts.len()); buf.push_leb128(self.container_updates.len()); buf.push_leb128(self.container_property_changes.len()); buf.push_leb128(self.container_deletes.len()); buf.push_leb128(self.item_inserts.len()); buf.push_leb128(self.item_updates.len()); buf.push_leb128(self.item_deletes.len()); for list in [ &self.container_inserts, &self.container_updates, &self.container_property_changes, &self.container_deletes, ] { for id in list { buf.push_leb128(*id); } } for list in [&self.item_inserts, &self.item_updates, &self.item_deletes] { for id in list { buf.push_leb128(*id); } } buf } } impl From for VanishedItem { fn from(value: String) -> Self { VanishedItem::Name(value) } } impl From for VanishedItem { fn from(value: u64) -> Self { VanishedItem::Id(value) } } impl From<(u32, u32)> for VanishedItem { fn from(value: (u32, u32)) -> Self { VanishedItem::Id((value.0 as u64) << 32 | value.1 as u64) } } impl VanishedItem { pub fn serialized_size(&self) -> usize { match self { VanishedItem::Name(name) => name.len() + 1, VanishedItem::Id(_) | VanishedItem::IdPair(..) => U64_LEN, } } } impl SerializeInfallible for VanishedItems { fn serialize(&self) -> Vec { let mut buf = KeySerializer::new(64); for item in &self.0 { buf = match item { VanishedItem::Name(name) => buf.write(name.as_bytes()).write(0u8), VanishedItem::Id(id) => buf.write(id.to_be_bytes().as_slice()), VanishedItem::IdPair(a, b) => buf .write(a.to_be_bytes().as_slice()) .write(b.to_be_bytes().as_slice()), }; } buf.finalize() } }