initial commit

This commit is contained in:
Alain Zscheile 2022-10-15 13:48:32 +02:00
commit bec8f6cfc2
10 changed files with 672 additions and 0 deletions

6
.gitignore vendored Normal file
View file

@ -0,0 +1,6 @@
.#*
/target
result
result-*
perf.data*
flamegraph.svg

394
Cargo.lock generated Normal file
View file

@ -0,0 +1,394 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "ambient-authority"
version = "0.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec8ad6edb4840b78c5c3d88de606b22252d552b55f3a4699fbb10fc070ec3049"
[[package]]
name = "base64"
version = "0.20.0-alpha.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "149ea5dc24cb11513350770afebba32b68e3d2e356f9221351a2a1ee89112a82"
[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "byr-core"
version = "0.1.0"
dependencies = [
"cap-std",
"fs2",
"tracing",
"yzb64",
"zstd",
]
[[package]]
name = "cap-primitives"
version = "0.26.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af3f336aa91cce16033ed3c94ac91d98956c49b420e6d6cd0dd7d0e386a57085"
dependencies = [
"ambient-authority",
"fs-set-times",
"io-extras",
"io-lifetimes",
"ipnet",
"maybe-owned",
"rustix",
"winapi-util",
"windows-sys",
"winx",
]
[[package]]
name = "cap-std"
version = "0.26.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c9d6e70b626eceac9d6fc790fe2d72cc3f2f7bc3c35f467690c54a526b0f56db"
dependencies = [
"cap-primitives",
"io-extras",
"io-lifetimes",
"ipnet",
"rustix",
]
[[package]]
name = "cc"
version = "1.0.73"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11"
dependencies = [
"jobserver",
]
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "errno"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1"
dependencies = [
"errno-dragonfly",
"libc",
"winapi",
]
[[package]]
name = "errno-dragonfly"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf"
dependencies = [
"cc",
"libc",
]
[[package]]
name = "fs-set-times"
version = "0.17.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a267b6a9304912e018610d53fe07115d8b530b160e85db4d2d3a59f3ddde1aec"
dependencies = [
"io-lifetimes",
"rustix",
"windows-sys",
]
[[package]]
name = "fs2"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213"
dependencies = [
"libc",
"winapi",
]
[[package]]
name = "io-extras"
version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a5d8c2ab5becd8720e30fd25f8fa5500d8dc3fceadd8378f05859bd7b46fc49"
dependencies = [
"io-lifetimes",
"windows-sys",
]
[[package]]
name = "io-lifetimes"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ea37f355c05dde75b84bba2d767906ad522e97cd9e2eef2be7a4ab7fb442c06"
[[package]]
name = "ipnet"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "879d54834c8c76457ef4293a689b2a8c59b076067ad77b15efafbb05f92a592b"
[[package]]
name = "itoa"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc"
[[package]]
name = "jobserver"
version = "0.1.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "068b1ee6743e4d11fb9c6a1e6064b3693a1b600e7f5f5988047d98b3dc9fb90b"
dependencies = [
"libc",
]
[[package]]
name = "libc"
version = "0.2.135"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68783febc7782c6c5cb401fbda4de5a9898be1762314da0bb2c10ced61f18b0c"
[[package]]
name = "linux-raw-sys"
version = "0.0.46"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4d2456c373231a208ad294c33dc5bff30051eafd954cd4caae83a712b12854d"
[[package]]
name = "maybe-owned"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4facc753ae494aeb6e3c22f839b158aebd4f9270f55cd3c79906c45476c47ab4"
[[package]]
name = "once_cell"
version = "1.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e82dad04139b71a90c080c8463fe0dc7902db5192d939bd0950f074d014339e1"
[[package]]
name = "pin-project-lite"
version = "0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116"
[[package]]
name = "proc-macro2"
version = "1.0.47"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179"
dependencies = [
"proc-macro2",
]
[[package]]
name = "rustix"
version = "0.35.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fbb2fda4666def1433b1b05431ab402e42a1084285477222b72d6c564c417cef"
dependencies = [
"bitflags",
"errno",
"io-lifetimes",
"itoa",
"libc",
"linux-raw-sys",
"once_cell",
"windows-sys",
]
[[package]]
name = "syn"
version = "1.0.102"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fcd952facd492f9be3ef0d0b7032a6e442ee9b361d4acc2b1d0c4aaa5f613a1"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "tracing"
version = "0.1.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8"
dependencies = [
"cfg-if",
"pin-project-lite",
"tracing-attributes",
"tracing-core",
]
[[package]]
name = "tracing-attributes"
version = "0.1.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "tracing-core"
version = "0.1.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a"
dependencies = [
"once_cell",
]
[[package]]
name = "unicode-ident"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3"
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-util"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
dependencies = [
"winapi",
]
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows-sys"
version = "0.36.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2"
dependencies = [
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_msvc"
version = "0.36.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47"
[[package]]
name = "windows_i686_gnu"
version = "0.36.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6"
[[package]]
name = "windows_i686_msvc"
version = "0.36.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024"
[[package]]
name = "windows_x86_64_gnu"
version = "0.36.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1"
[[package]]
name = "windows_x86_64_msvc"
version = "0.36.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680"
[[package]]
name = "winx"
version = "0.33.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b7b01e010390eb263a4518c8cebf86cb67469d1511c00b749a47b64c39e8054d"
dependencies = [
"bitflags",
"io-lifetimes",
"windows-sys",
]
[[package]]
name = "yzb64"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2fcbb8a264fd63a6dfe4532b0c1b039d5c4bdc2548d83a7af43f28870ef3f5b2"
dependencies = [
"base64",
"once_cell",
]
[[package]]
name = "zstd"
version = "0.11.2+zstd.1.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4"
dependencies = [
"zstd-safe",
]
[[package]]
name = "zstd-safe"
version = "5.0.2+zstd.1.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db"
dependencies = [
"libc",
"zstd-sys",
]
[[package]]
name = "zstd-sys"
version = "2.0.1+zstd.1.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9fd07cbbc53846d9145dbffdf6dd09a7a0aa52be46741825f5c97bdd4f73f12b"
dependencies = [
"cc",
"libc",
]

7
Cargo.toml Normal file
View file

@ -0,0 +1,7 @@
[workspace]
members = ["crates/*"]
[profile.release]
codegen-units = 1
debug = 1
lto = "thin"

19
README.md Normal file
View file

@ -0,0 +1,19 @@
# byr
Byr is a list-based event-sourced version control derivate (see also [esvc2](https://github.com/zseri/esvc2)).
## data structures
<dl>
<dt>blob</dt>
<dd>A byte string containing a serialization of the data</dd>
<dt>event/change</dt>
<dd>The smallest element usually used, describes a single operation to be performed
on the data (which is usually a byte string, but can also be more structured).</dd>
<dt>changelist</dt>
<dd>An ordered list of changes (referenced by hash) plus a reference to an anchor snapshot</dd>
<dt>snapshot</dt>
<dd>A blob, including metadata, and the history leading to the blob (changelist);
such that the collection of all previous snapshots + the following changelist
suffices to reconstruct the state of a branch (the changes itself are usually not stored in the snapshot)</dd>
</dl>

View file

@ -0,0 +1,12 @@
[package]
name = "byr-core"
version = "0.1.0"
edition = "2021"
license = "Apache-2.0"
[dependencies]
cap-std = "0.26"
fs2 = "0.4"
tracing = "0.1"
yzb64 = "0.1"
zstd = "0.11"

View file

@ -0,0 +1,47 @@
use core::fmt;
use std::io::{Read, Result as IoResult, Write};
/// Note that the first entry has a special meaning, it is the anchor hash
/// a changelist may also be empty in degraded cases (e.g. in a root snapshot)
#[derive(Clone, Default)]
pub struct ChangeList(pub Vec<crate::ChangeHash>);
impl fmt::Debug for ChangeList {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use yzb64::{base64, B64_ENGINE};
f.debug_list()
.entries(
self.0
.iter()
.map(|i| format!("{}", base64::display::Base64Display::from(i, &*B64_ENGINE))),
)
.finish()
}
}
impl ChangeList {
pub fn read_from_stream(f: &mut impl Read) -> IoResult<Self> {
let l = {
let mut lbuf = [0u8; 2];
f.read_exact(&mut lbuf)?;
u16::from_be_bytes(lbuf)
};
let lu = usize::from(l);
let mut ret = Vec::with_capacity(lu);
let mut buf = [0u8; 32];
for _ in 0..lu {
f.read_exact(&mut buf)?;
ret.push(buf);
}
Ok(Self(ret))
}
pub fn write_to_stream(&self, f: &mut impl Write) -> IoResult<()> {
let lbuf = u16::try_from(self.0.len())
.map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e))?
.to_be_bytes();
f.write_all(&lbuf)?;
self.0.iter().try_for_each(|i| f.write_all(i))?;
Ok(())
}
}

View file

@ -0,0 +1,98 @@
use cap_std::fs::Dir;
use std::io::{Read, Result as IoResult, Write};
mod traits;
pub use traits::{Event, FlowData};
mod lock;
use lock::RepoLock;
mod changelist;
pub use changelist::ChangeList;
mod thin_snapshot;
pub use thin_snapshot::ThinSnapshot;
pub struct Repository(pub Dir);
impl Repository {
fn subdir(&self, sd: &str) -> IoResult<Dir> {
let _ = self.0.create_dir(sd);
self.0.open_dir(sd)
}
pub fn changes(&self) -> IoResult<Changes> {
self.subdir("changes").map(Changes)
}
pub fn snapshots(&self) -> IoResult<Snapshots> {
self.subdir("snapshots").map(Snapshots)
}
}
pub type ChangeHash = [u8; 32];
pub struct Changes(Dir);
fn yzb64_file_name(h: &ChangeHash) -> [u8; 43] {
let mut buf = [0u8; 43];
assert_eq!(
yzb64::base64::encode_engine_slice(h, &mut buf, &*yzb64::B64_ENGINE),
43
);
buf
}
impl Changes {
pub fn insert(&self, h: &ChangeHash, contents: &[u8]) -> IoResult<bool> {
let buf = yzb64_file_name(h);
let buf = std::str::from_utf8(&buf).unwrap();
let _l = RepoLock::lock_write(&self.0, ".lock");
if self.0.exists(buf) {
return Ok(false);
}
let mut ecd = zstd::stream::write::Encoder::new(self.0.create(buf)?, 5)?;
ecd.write_all(contents)?;
ecd.finish()?;
Ok(true)
}
pub fn remove(&self, h: &ChangeHash) -> IoResult<()> {
let buf = yzb64_file_name(h);
let buf = std::str::from_utf8(&buf).unwrap();
let _l = RepoLock::lock_write(&self.0, ".lock");
self.0.remove_file(buf)
}
pub fn get(&self, h: &ChangeHash) -> IoResult<Vec<u8>> {
let buf = yzb64_file_name(h);
let buf = std::str::from_utf8(&buf).unwrap();
let _l = RepoLock::lock_read(&self.0, ".lock");
let mut dcd = zstd::stream::read::Decoder::new(self.0.open(buf)?)?;
let mut buf2 = Vec::new();
dcd.read_to_end(&mut buf2)?;
Ok(buf2)
}
}
pub struct Snapshots(Dir);
impl Snapshots {
pub fn insert_thin(&self, name: &str, contents: &ThinSnapshot) -> IoResult<bool> {
let _l = RepoLock::lock_write(&self.0, ".lock");
if self.0.exists(name) {
return Ok(false);
}
let f = self.0.create(name)?;
contents.write_to_stream(f)?;
Ok(true)
}
pub fn remove(&self, name: &str) -> IoResult<()> {
let _l = RepoLock::lock_write(&self.0, ".lock");
self.0.remove_file(name)
}
pub fn get_thin(&self, name: &str) -> IoResult<ThinSnapshot> {
let _l = RepoLock::lock_read(&self.0, ".lock");
let f = self.0.open(name)?;
ThinSnapshot::read_from_stream(f)
}
}

View file

@ -0,0 +1,28 @@
use cap_std::fs::{Dir, OpenOptions};
use fs2::FileExt;
use std::fs::File;
use std::io::Result as IoResult;
pub struct RepoLock(File);
impl Drop for RepoLock {
fn drop(&mut self) {
if let Err(e) = self.0.unlock() {
tracing::error!("RepoLock unlock failed: {}", e);
}
}
}
impl RepoLock {
pub fn lock_read(d: &Dir, nam: &str) -> IoResult<RepoLock> {
let f = d.open(nam)?.into_std();
f.lock_shared()?;
Ok(RepoLock(f))
}
pub fn lock_write(d: &Dir, nam: &str) -> IoResult<RepoLock> {
let f = d.open_with(nam, OpenOptions::new().write(true))?.into_std();
f.lock_exclusive()?;
Ok(RepoLock(f))
}
}

View file

@ -0,0 +1,39 @@
use super::ChangeList;
use std::io::{Read, Result as IoResult, Write};
/**
A thin snapshot contains:
* metadata, 256 bytes
* changelist, prefixed by 16bit big-endian item count (length = cnt * 32)
* data blob
**/
pub struct ThinSnapshot {
pub meta: [u8; 256],
pub changelist: ChangeList,
pub data: Vec<u8>,
}
impl ThinSnapshot {
pub fn read_from_stream(f: impl Read) -> IoResult<Self> {
let mut dcd = zstd::stream::read::Decoder::new(f)?;
let mut meta = [0u8; 256];
dcd.read_exact(&mut meta)?;
let changelist = ChangeList::read_from_stream(&mut dcd)?;
let mut data = Vec::new();
dcd.read_to_end(&mut data)?;
Ok(Self {
meta,
changelist,
data,
})
}
pub fn write_to_stream(&self, f: impl Write) -> IoResult<()> {
let mut ecd = zstd::stream::write::Encoder::new(f, 5)?;
ecd.write_all(&self.meta)?;
self.changelist.write_to_stream(&mut ecd)?;
ecd.write_all(&self.data[..])?;
ecd.finish()?;
Ok(())
}
}

View file

@ -0,0 +1,22 @@
use core::cmp::Eq;
pub trait FlowData: Clone + Eq {}
impl<T> FlowData for T where T: Clone + Eq {}
/// This trait must be implemented for any type which should be used as an event
pub trait Event {
type Data: FlowData;
type Err;
fn run(&self, data: &mut Self::Data) -> Result<(), Self::Err>;
}
impl<T: Event> Event for [T] {
type Data = T::Data;
type Err = T::Err;
fn run(&self, data: &mut T::Data) -> Result<(), T::Err> {
self.iter().try_for_each(|i| i.run(data))
}
}