Skip to content

Commit

Permalink
feat: somlstr for parent key (#30)
Browse files Browse the repository at this point in the history
  • Loading branch information
darkskygit committed Dec 25, 2023
1 parent 3764b25 commit 4d6a29c
Show file tree
Hide file tree
Showing 13 changed files with 320 additions and 139 deletions.
11 changes: 9 additions & 2 deletions y-octo-utils/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,14 @@ version = "0.0.1"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[features]
bench = ["regex"]
fuzz = ["arbitrary", "phf"]
bench = ["regex"]
default = ["merger"]
fuzz = ["arbitrary", "phf"]
merger = ["clap", "y-octo/large_refs"]

[dependencies]
arbitrary = { version = "1.3", features = ["derive"], optional = true }
clap = { version = "4.4", features = ["derive"], optional = true }
lib0 = { version = "=0.16.5", features = ["lib0-serde"] }
phf = { version = "0.11", features = ["macros"], optional = true }
rand = "0.8"
Expand All @@ -32,6 +35,10 @@ proptest-derive = "0.4"
name = "bench_result_render"
path = "bin/bench_result_render.rs"

[[bin]]
name = "doc_merger"
path = "bin/doc_merger.rs"

[[bin]]
name = "memory_leak_test"
path = "bin/memory_leak_test.rs"
Expand Down
100 changes: 100 additions & 0 deletions y-octo-utils/bin/doc_merger.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
use std::{
fs::read,
io::{Error, ErrorKind},
path::PathBuf,
time::Instant,
};

use clap::Parser;
use y_octo::Doc;

/// ybinary merger
#[derive(Parser, Debug)]
#[command(author, version, about, long_about = None)]
struct Args {
/// Path of the ybinary to read
#[arg(short, long)]
path: String,
}

fn load_path(path: &str) -> Result<Vec<Vec<u8>>, Error> {
let path = PathBuf::from(path);
if path.is_dir() {
let mut updates = Vec::new();
let mut paths = path
.read_dir()?
.filter_map(|entry| {
let entry = entry.ok()?;
if entry.path().is_file() {
Some(entry.path())
} else {
None
}
})
.collect::<Vec<_>>();
paths.sort();

for path in paths {
println!("read {:?}", path);
updates.push(read(path)?);
}
Ok(updates)
} else if path.is_file() {
Ok(vec![read(path)?])
} else {
Err(Error::new(ErrorKind::NotFound, "not a file or directory"))
}
}

fn main() {
let args = Args::parse();
jwst_merge(&args.path);
}

fn jwst_merge(path: &str) {
let updates = load_path(path).unwrap();

let mut doc = Doc::default();
for (i, update) in updates.iter().enumerate() {
println!("apply update{i} {} bytes", update.len());
doc.apply_update_from_binary_v1(update.clone()).unwrap();
}

println!("press enter to continue");
std::io::stdin().read_line(&mut String::new()).unwrap();
let ts = Instant::now();
let history = doc.history().parse_store(Default::default());
println!("history: {:?}", ts.elapsed());
for history in history.iter().take(100) {
println!("history: {:?}", history);
}

doc.gc().unwrap();

let binary = {
let binary = doc.encode_update_v1().unwrap();

println!("merged {} bytes", binary.len());

binary
};

{
let mut doc = Doc::default();
doc.apply_update_from_binary_v1(binary.clone()).unwrap();
let new_binary = doc.encode_update_v1().unwrap();

println!("re-encoded {} bytes", new_binary.len(),);
};
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
#[ignore = "only for debug"]
fn test_gc() {
jwst_merge("/Users/ds/Downloads/out");
}
}
2 changes: 2 additions & 0 deletions y-octo/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ version = "0.0.1"
ahash = "0.8"
bitvec = "1.0"
byteorder = "1.5"
lasso = { version = "0.7", features = ["multi-threaded"] }
log = "0.4"
nanoid = "0.4"
nom = "7.1"
Expand All @@ -31,6 +32,7 @@ rand_chacha = "0.3"
rand_distr = "0.4"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
smol_str = "0.2"
thiserror = "1.0"

[features]
Expand Down
127 changes: 13 additions & 114 deletions y-octo/src/doc/codec/item.rs
Original file line number Diff line number Diff line change
@@ -1,117 +1,15 @@
use super::*;
use crate::sync::{AtomicU8, Ordering};

#[derive(Debug, Clone)]
#[cfg_attr(test, derive(proptest_derive::Arbitrary))]
pub(crate) enum Parent {
#[cfg_attr(test, proptest(skip))]
Type(YTypeRef),
String(String),
#[cfg_attr(test, proptest(value = "Parent::String(SmolStr::default())"))]
String(SmolStr),
Id(Id),
}

#[rustfmt::skip]
#[allow(dead_code)]
pub mod item_flags {
pub const ITEM_KEEP : u8 = 0b0000_0001;
pub const ITEM_COUNTABLE : u8 = 0b0000_0010;
pub const ITEM_DELETED : u8 = 0b0000_0100;
pub const ITEM_MARKED : u8 = 0b0000_1000;
pub const ITEM_HAS_PARENT_SUB : u8 = 0b0010_0000;
pub const ITEM_HAS_RIGHT_ID : u8 = 0b0100_0000;
pub const ITEM_HAS_LEFT_ID : u8 = 0b1000_0000;
pub const ITEM_HAS_SIBLING : u8 = 0b1100_0000;
}

#[derive(Debug)]
pub struct ItemFlags(AtomicU8);

impl Default for ItemFlags {
fn default() -> Self {
Self(AtomicU8::new(0))
}
}

impl Clone for ItemFlags {
fn clone(&self) -> Self {
Self(AtomicU8::new(self.0.load(Ordering::Acquire)))
}
}

impl From<u8> for ItemFlags {
fn from(flags: u8) -> Self {
Self(AtomicU8::new(flags))
}
}

#[allow(dead_code)]
impl ItemFlags {
#[inline(always)]
pub fn set(&self, flag: u8) {
self.0.fetch_or(flag, Ordering::SeqCst);
}

#[inline(always)]
pub fn clear(&self, flag: u8) {
self.0.fetch_and(flag, Ordering::SeqCst);
}

#[inline(always)]
pub fn check(&self, flag: u8) -> bool {
self.0.load(Ordering::Acquire) & flag == flag
}

#[inline(always)]
pub fn not(&self, flag: u8) -> bool {
self.0.load(Ordering::Acquire) & flag == 0
}

#[inline(always)]
pub fn keep(&self) -> bool {
self.check(item_flags::ITEM_KEEP)
}

#[inline(always)]
pub fn set_keep(&self) {
self.set(item_flags::ITEM_KEEP);
}

#[inline(always)]
pub fn clear_keep(&self) {
self.clear(item_flags::ITEM_KEEP);
}

#[inline(always)]
pub fn countable(&self) -> bool {
self.check(item_flags::ITEM_COUNTABLE)
}

#[inline(always)]
pub fn set_countable(&self) {
self.set(item_flags::ITEM_COUNTABLE);
}

#[inline(always)]
pub fn clear_countable(&self) {
self.clear(!item_flags::ITEM_COUNTABLE);
}

#[inline(always)]
pub fn deleted(&self) -> bool {
self.check(item_flags::ITEM_DELETED)
}

#[inline(always)]
pub fn set_deleted(&self) {
self.set(item_flags::ITEM_DELETED);
}

#[inline(always)]
pub fn clear_deleted(&self) {
self.clear(!item_flags::ITEM_DELETED);
}
}

#[derive(Clone)]
#[cfg_attr(all(test, not(loom)), derive(proptest_derive::Arbitrary))]
pub(crate) struct Item {
Expand All @@ -123,10 +21,11 @@ pub(crate) struct Item {
#[cfg_attr(all(test, not(loom)), proptest(value = "Somr::none()"))]
pub right: ItemRef,
pub parent: Option<Parent>,
pub parent_sub: Option<String>,
#[cfg_attr(all(test, not(loom)), proptest(value = "Option::<SmolStr>::None"))]
pub parent_sub: Option<SmolStr>,
pub content: Content,
#[cfg_attr(all(test, not(loom)), proptest(value = "ItemFlags::default()"))]
pub flags: ItemFlags,
#[cfg_attr(all(test, not(loom)), proptest(value = "ItemFlag::default()"))]
pub flags: ItemFlag,
}

// make all Item readonly
Expand Down Expand Up @@ -185,7 +84,7 @@ impl Default for Item {
parent: None,
parent_sub: None,
content: Content::Deleted(0),
flags: ItemFlags::from(0),
flags: ItemFlag::from(0),
}
}
}
Expand All @@ -197,9 +96,9 @@ impl Item {
left: Somr<Item>,
right: Somr<Item>,
parent: Option<Parent>,
parent_sub: Option<String>,
parent_sub: Option<SmolStr>,
) -> Self {
let flags = ItemFlags::from(if content.countable() {
let flags = ItemFlag::from(if content.countable() {
item_flags::ITEM_COUNTABLE
} else {
0
Expand Down Expand Up @@ -332,7 +231,7 @@ impl Item {
}

pub fn read<R: CrdtReader>(decoder: &mut R, id: Id, info: u8, first_5_bit: u8) -> JwstCodecResult<Self> {
let flags: ItemFlags = info.into();
let flags: ItemFlag = info.into();
let has_left_id = flags.check(item_flags::ITEM_HAS_LEFT_ID);
let has_right_id = flags.check(item_flags::ITEM_HAS_RIGHT_ID);
let has_parent_sub = flags.check(item_flags::ITEM_HAS_PARENT_SUB);
Expand All @@ -356,7 +255,7 @@ impl Item {
if has_not_sibling {
let has_parent = decoder.read_var_u64()? == 1;
Some(if has_parent {
Parent::String(decoder.read_var_string()?)
Parent::String(SmolStr::new(decoder.read_var_string()?))
} else {
Parent::Id(decoder.read_item_id()?)
})
Expand All @@ -365,7 +264,7 @@ impl Item {
}
},
parent_sub: if has_not_sibling && has_parent_sub {
Some(decoder.read_var_string()?)
Some(SmolStr::new(decoder.read_var_string()?))
} else {
None
},
Expand All @@ -377,7 +276,7 @@ impl Item {
},
left: Somr::none(),
right: Somr::none(),
flags: ItemFlags::from(0),
flags: ItemFlag::from(0),
};

if item.content.countable() {
Expand Down

0 comments on commit 4d6a29c

Please sign in to comment.