2023-07-31 03:49:55 +00:00
|
|
|
use fxhash::FxHashMap;
|
|
|
|
use loro_common::PeerID;
|
|
|
|
|
|
|
|
use crate::{change::Change, op::RemoteOp};
|
|
|
|
|
|
|
|
pub(crate) type RemoteClientChanges<'a> = FxHashMap<PeerID, Vec<Change<RemoteOp<'a>>>>;
|
|
|
|
|
2023-08-28 08:16:40 +00:00
|
|
|
mod encode_enhanced;
|
2023-10-31 02:36:21 +00:00
|
|
|
pub(crate) mod encode_snapshot;
|
2023-07-31 03:49:55 +00:00
|
|
|
mod encode_updates;
|
|
|
|
|
|
|
|
use rle::HasLength;
|
|
|
|
|
|
|
|
use crate::{oplog::OpLog, LoroError, VersionVector};
|
|
|
|
|
2023-10-31 02:36:21 +00:00
|
|
|
use self::encode_updates::decode_oplog_updates;
|
2023-07-31 03:49:55 +00:00
|
|
|
|
2023-08-29 02:38:48 +00:00
|
|
|
pub(crate) use encode_enhanced::{decode_oplog_v2, encode_oplog_v2};
|
2023-07-31 03:49:55 +00:00
|
|
|
pub(crate) use encode_updates::encode_oplog_updates;
|
|
|
|
|
2023-08-16 03:33:55 +00:00
|
|
|
pub(crate) const COMPRESS_RLE_THRESHOLD: usize = 20 * 1024;
|
2023-07-31 03:49:55 +00:00
|
|
|
// TODO: Test this threshold
|
2023-10-29 06:02:13 +00:00
|
|
|
#[cfg(not(test))]
|
2023-11-03 08:59:27 +00:00
|
|
|
pub(crate) const UPDATE_ENCODE_THRESHOLD: usize = 32;
|
2023-10-29 06:02:13 +00:00
|
|
|
#[cfg(test)]
|
|
|
|
pub(crate) const UPDATE_ENCODE_THRESHOLD: usize = 16;
|
2023-07-31 03:49:55 +00:00
|
|
|
pub(crate) const MAGIC_BYTES: [u8; 4] = [0x6c, 0x6f, 0x72, 0x6f];
|
|
|
|
pub(crate) const ENCODE_SCHEMA_VERSION: u8 = 0;
|
2023-08-30 04:27:23 +00:00
|
|
|
|
|
|
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
|
|
|
pub(crate) enum EncodeMode {
|
|
|
|
// This is a config option, it won't be used in encoding.
|
|
|
|
Auto = 255,
|
|
|
|
Updates = 0,
|
2023-10-31 02:36:21 +00:00
|
|
|
Snapshot = 1,
|
|
|
|
RleUpdates = 2,
|
2023-08-30 04:27:23 +00:00
|
|
|
CompressedRleUpdates = 3,
|
2023-07-31 03:49:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl EncodeMode {
|
2023-08-30 04:27:23 +00:00
|
|
|
pub fn to_byte(self) -> u8 {
|
2023-07-31 03:49:55 +00:00
|
|
|
match self {
|
2023-08-30 04:27:23 +00:00
|
|
|
EncodeMode::Auto => 255,
|
|
|
|
EncodeMode::Updates => 0,
|
2023-10-31 02:36:21 +00:00
|
|
|
EncodeMode::Snapshot => 1,
|
|
|
|
EncodeMode::RleUpdates => 2,
|
2023-08-30 04:27:23 +00:00
|
|
|
EncodeMode::CompressedRleUpdates => 3,
|
2023-07-31 03:49:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-30 08:41:04 +00:00
|
|
|
impl TryFrom<u8> for EncodeMode {
|
|
|
|
type Error = LoroError;
|
|
|
|
|
|
|
|
fn try_from(value: u8) -> Result<Self, Self::Error> {
|
2023-07-31 03:49:55 +00:00
|
|
|
match value {
|
2023-08-30 08:41:04 +00:00
|
|
|
0 => Ok(EncodeMode::Updates),
|
2023-10-31 02:36:21 +00:00
|
|
|
1 => Ok(EncodeMode::Snapshot),
|
|
|
|
2 => Ok(EncodeMode::RleUpdates),
|
2023-08-30 08:41:04 +00:00
|
|
|
3 => Ok(EncodeMode::CompressedRleUpdates),
|
|
|
|
_ => Err(LoroError::DecodeError("Unknown encode mode".into())),
|
2023-07-31 03:49:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-30 04:27:23 +00:00
|
|
|
pub(crate) fn encode_oplog(oplog: &OpLog, vv: &VersionVector, mode: EncodeMode) -> Vec<u8> {
|
2023-07-31 03:49:55 +00:00
|
|
|
let version = ENCODE_SCHEMA_VERSION;
|
|
|
|
let mut ans = Vec::from(MAGIC_BYTES);
|
|
|
|
// maybe u8 is enough
|
|
|
|
ans.push(version);
|
|
|
|
let mode = match mode {
|
2023-08-30 04:27:23 +00:00
|
|
|
EncodeMode::Auto => {
|
2023-07-31 03:49:55 +00:00
|
|
|
let self_vv = oplog.vv();
|
2023-08-30 04:27:23 +00:00
|
|
|
let diff = self_vv.diff(vv);
|
2023-07-31 03:49:55 +00:00
|
|
|
let update_total_len = diff
|
|
|
|
.left
|
|
|
|
.values()
|
|
|
|
.map(|value| value.atom_len())
|
|
|
|
.sum::<usize>();
|
2023-08-29 09:15:41 +00:00
|
|
|
|
|
|
|
// EncodeMode::RleUpdates(vv)
|
|
|
|
if update_total_len <= UPDATE_ENCODE_THRESHOLD {
|
2023-08-30 04:27:23 +00:00
|
|
|
EncodeMode::Updates
|
|
|
|
} else if update_total_len <= COMPRESS_RLE_THRESHOLD {
|
2023-10-31 02:36:21 +00:00
|
|
|
EncodeMode::RleUpdates
|
2023-07-31 03:49:55 +00:00
|
|
|
} else {
|
2023-10-31 02:36:21 +00:00
|
|
|
EncodeMode::CompressedRleUpdates
|
2023-07-31 03:49:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
mode => mode,
|
|
|
|
};
|
2023-10-30 03:13:52 +00:00
|
|
|
|
2023-07-31 03:49:55 +00:00
|
|
|
let encoded = match &mode {
|
2023-08-30 04:27:23 +00:00
|
|
|
EncodeMode::Updates => encode_oplog_updates(oplog, vv),
|
2023-10-31 02:36:21 +00:00
|
|
|
EncodeMode::RleUpdates => encode_oplog_v2(oplog, vv),
|
2023-08-30 04:27:23 +00:00
|
|
|
EncodeMode::CompressedRleUpdates => {
|
|
|
|
let bytes = encode_oplog_v2(oplog, vv);
|
|
|
|
miniz_oxide::deflate::compress_to_vec(&bytes, 7)
|
|
|
|
}
|
2023-07-31 03:49:55 +00:00
|
|
|
_ => unreachable!(),
|
|
|
|
};
|
|
|
|
ans.push(mode.to_byte());
|
|
|
|
ans.extend(encoded);
|
|
|
|
ans
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn decode_oplog(oplog: &mut OpLog, input: &[u8]) -> Result<(), LoroError> {
|
2023-08-30 08:41:04 +00:00
|
|
|
if input.len() < 6 {
|
|
|
|
return Err(LoroError::DecodeError("".into()));
|
|
|
|
}
|
|
|
|
|
2023-07-31 03:49:55 +00:00
|
|
|
let (magic_bytes, input) = input.split_at(4);
|
|
|
|
let magic_bytes: [u8; 4] = magic_bytes.try_into().unwrap();
|
|
|
|
if magic_bytes != MAGIC_BYTES {
|
|
|
|
return Err(LoroError::DecodeError("Invalid header bytes".into()));
|
|
|
|
}
|
|
|
|
let (version, input) = input.split_at(1);
|
|
|
|
if version != [ENCODE_SCHEMA_VERSION] {
|
|
|
|
return Err(LoroError::DecodeError("Invalid version".into()));
|
|
|
|
}
|
|
|
|
|
2023-08-30 08:41:04 +00:00
|
|
|
let mode: EncodeMode = input[0].try_into()?;
|
2023-07-31 03:49:55 +00:00
|
|
|
let decoded = &input[1..];
|
|
|
|
match mode {
|
2023-08-30 04:27:23 +00:00
|
|
|
EncodeMode::Updates => decode_oplog_updates(oplog, decoded),
|
|
|
|
EncodeMode::Snapshot => unimplemented!(),
|
2023-10-31 02:36:21 +00:00
|
|
|
EncodeMode::RleUpdates => decode_oplog_v2(oplog, decoded),
|
|
|
|
EncodeMode::CompressedRleUpdates => miniz_oxide::inflate::decompress_to_vec(decoded)
|
2023-08-30 04:27:23 +00:00
|
|
|
.map_err(|_| LoroError::DecodeError("Invalid compressed data".into()))
|
|
|
|
.and_then(|bytes| decode_oplog_v2(oplog, &bytes)),
|
|
|
|
EncodeMode::Auto => unreachable!(),
|
2023-07-31 03:49:55 +00:00
|
|
|
}
|
|
|
|
}
|