mirror of
https://github.com/facebook/sapling.git
synced 2024-10-11 01:07:15 +03:00
treedirstate: add Store and StoreView traits
These traits represent abstract store objects than can store arbitrary data blocks with store-generated indexes. A NullStore implementation is provided which acts an always-empty StoreView. Differential Revision: https://phab.mercurial-scm.org/D1397
This commit is contained in:
parent
5931d6cf5d
commit
1537d3833e
63
rust/treedirstate/Cargo.lock
generated
63
rust/treedirstate/Cargo.lock
generated
@ -6,11 +6,53 @@ dependencies = [
|
|||||||
"memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
"memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "backtrace"
|
||||||
|
version = "0.3.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"backtrace-sys 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"dbghelp-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"rustc-demangle 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "backtrace-sys"
|
||||||
|
version = "0.1.16"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"cc 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bitflags"
|
||||||
version = "0.7.0"
|
version = "0.7.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cc"
|
||||||
|
version = "1.0.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cfg-if"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "dbghelp-sys"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "either"
|
name = "either"
|
||||||
version = "1.4.0"
|
version = "1.4.0"
|
||||||
@ -25,6 +67,14 @@ dependencies = [
|
|||||||
"regex 0.1.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
"regex 0.1.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "error-chain"
|
||||||
|
version = "0.11.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"backtrace 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fuchsia-zircon"
|
name = "fuchsia-zircon"
|
||||||
version = "0.2.1"
|
version = "0.2.1"
|
||||||
@ -112,10 +162,16 @@ name = "regex-syntax"
|
|||||||
version = "0.3.9"
|
version = "0.3.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustc-demangle"
|
||||||
|
version = "0.1.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rusttreedirstate"
|
name = "rusttreedirstate"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"itertools 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"itertools 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"quickcheck 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"quickcheck 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
@ -154,9 +210,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
|
|
||||||
[metadata]
|
[metadata]
|
||||||
"checksum aho-corasick 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ca972c2ea5f742bfce5687b9aef75506a764f61d37f8f649047846a9686ddb66"
|
"checksum aho-corasick 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ca972c2ea5f742bfce5687b9aef75506a764f61d37f8f649047846a9686ddb66"
|
||||||
|
"checksum backtrace 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "99f2ce94e22b8e664d95c57fff45b98a966c2252b60691d0b7aeeccd88d70983"
|
||||||
|
"checksum backtrace-sys 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "44585761d6161b0f57afc49482ab6bd067e4edef48c12a152c237eb0203f7661"
|
||||||
"checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d"
|
"checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d"
|
||||||
|
"checksum cc 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a9b13a57efd6b30ecd6598ebdb302cca617930b5470647570468a65d12ef9719"
|
||||||
|
"checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de"
|
||||||
|
"checksum dbghelp-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "97590ba53bcb8ac28279161ca943a924d1fd4a8fb3fa63302591647c4fc5b850"
|
||||||
"checksum either 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "740178ddf48b1a9e878e6d6509a1442a2d42fd2928aae8e7a6f8a36fb01981b3"
|
"checksum either 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "740178ddf48b1a9e878e6d6509a1442a2d42fd2928aae8e7a6f8a36fb01981b3"
|
||||||
"checksum env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "15abd780e45b3ea4f76b4e9a26ff4843258dd8a3eed2775a0e7368c2e7936c2f"
|
"checksum env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "15abd780e45b3ea4f76b4e9a26ff4843258dd8a3eed2775a0e7368c2e7936c2f"
|
||||||
|
"checksum error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff511d5dc435d703f4971bc399647c9bc38e20cb41452e3b9feb4765419ed3f3"
|
||||||
"checksum fuchsia-zircon 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f6c0581a4e363262e52b87f59ee2afe3415361c6ec35e665924eb08afe8ff159"
|
"checksum fuchsia-zircon 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f6c0581a4e363262e52b87f59ee2afe3415361c6ec35e665924eb08afe8ff159"
|
||||||
"checksum fuchsia-zircon-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "43f3795b4bae048dc6123a6b972cadde2e676f9ded08aef6bb77f5f157684a82"
|
"checksum fuchsia-zircon-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "43f3795b4bae048dc6123a6b972cadde2e676f9ded08aef6bb77f5f157684a82"
|
||||||
"checksum itertools 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2c52051d3fd3b505796a0ee90f2e5ec43213808585e8adc4d0182492cf62751a"
|
"checksum itertools 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2c52051d3fd3b505796a0ee90f2e5ec43213808585e8adc4d0182492cf62751a"
|
||||||
@ -168,6 +230,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
"checksum rand 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)" = "6475140dfd8655aeb72e1fd4b7a1cc1c202be65d71669476e392fe62532b9edd"
|
"checksum rand 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)" = "6475140dfd8655aeb72e1fd4b7a1cc1c202be65d71669476e392fe62532b9edd"
|
||||||
"checksum regex 0.1.80 (registry+https://github.com/rust-lang/crates.io-index)" = "4fd4ace6a8cf7860714a2c2280d6c1f7e6a413486c13298bbc86fd3da019402f"
|
"checksum regex 0.1.80 (registry+https://github.com/rust-lang/crates.io-index)" = "4fd4ace6a8cf7860714a2c2280d6c1f7e6a413486c13298bbc86fd3da019402f"
|
||||||
"checksum regex-syntax 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "f9ec002c35e86791825ed294b50008eea9ddfc8def4420124fbc6b08db834957"
|
"checksum regex-syntax 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "f9ec002c35e86791825ed294b50008eea9ddfc8def4420124fbc6b08db834957"
|
||||||
|
"checksum rustc-demangle 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "aee45432acc62f7b9a108cc054142dac51f979e69e71ddce7d6fc7adf29e817e"
|
||||||
"checksum thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9539db560102d1cef46b8b78ce737ff0bb64e7e18d35b2a5688f7d097d0ff03"
|
"checksum thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9539db560102d1cef46b8b78ce737ff0bb64e7e18d35b2a5688f7d097d0ff03"
|
||||||
"checksum thread_local 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "8576dbbfcaef9641452d5cf0df9b0e7eeab7694956dd33bb61515fb8f18cfdd5"
|
"checksum thread_local 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "8576dbbfcaef9641452d5cf0df9b0e7eeab7694956dd33bb61515fb8f18cfdd5"
|
||||||
"checksum utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1ca13c08c41c9c3e04224ed9ff80461d97e121589ff27c753a16cb10830ae0f"
|
"checksum utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1ca13c08c41c9c3e04224ed9ff80461d97e121589ff27c753a16cb10830ae0f"
|
||||||
|
@ -10,6 +10,9 @@ lto = true
|
|||||||
name = "rusttreedirstate"
|
name = "rusttreedirstate"
|
||||||
crate-type = ["cdylib"]
|
crate-type = ["cdylib"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
error-chain = "*"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
itertools = "0.7.2"
|
itertools = "0.7.2"
|
||||||
quickcheck = "*"
|
quickcheck = "*"
|
||||||
|
16
rust/treedirstate/src/errors.rs
Normal file
16
rust/treedirstate/src/errors.rs
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
// Copyright Facebook, Inc. 2017
|
||||||
|
//! Errors.
|
||||||
|
|
||||||
|
error_chain! {
|
||||||
|
errors {
|
||||||
|
InvalidStoreId(id: u64) {
|
||||||
|
description("invalid store id"),
|
||||||
|
display("invalid store id: {}", id),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foreign_links {
|
||||||
|
Io(::std::io::Error);
|
||||||
|
Utf8(::std::str::Utf8Error);
|
||||||
|
Utf8String(::std::string::FromUtf8Error);
|
||||||
|
}
|
||||||
|
}
|
@ -12,6 +12,9 @@
|
|||||||
//! The directory state also stores files that are in the working copy parent manifest but have
|
//! The directory state also stores files that are in the working copy parent manifest but have
|
||||||
//! been marked as removed.
|
//! been marked as removed.
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate error_chain;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
extern crate itertools;
|
extern crate itertools;
|
||||||
|
|
||||||
@ -19,4 +22,8 @@ extern crate itertools;
|
|||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate quickcheck;
|
extern crate quickcheck;
|
||||||
|
|
||||||
|
pub mod errors;
|
||||||
|
pub mod store;
|
||||||
pub mod vecmap;
|
pub mod vecmap;
|
||||||
|
|
||||||
|
pub use errors::*;
|
||||||
|
103
rust/treedirstate/src/store.rs
Normal file
103
rust/treedirstate/src/store.rs
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
// Copyright Facebook, Inc. 2017
|
||||||
|
//! Trait defining an append-only storage system.
|
||||||
|
|
||||||
|
use errors::*;
|
||||||
|
use std::borrow::Cow;
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
|
||||||
|
pub struct BlockId(u64);
|
||||||
|
|
||||||
|
/// Append-only storage. Blocks of data may be stored in an instance of a Store. Once written,
|
||||||
|
/// blocks are immutable.
|
||||||
|
pub trait Store {
|
||||||
|
/// Append a new block of data to the store. Returns the ID of the block. Note that blocks
|
||||||
|
/// may be buffered until `flush` is called.
|
||||||
|
fn append(&mut self, data: &[u8]) -> Result<BlockId>;
|
||||||
|
|
||||||
|
/// Flush all appended blocks to the backing store.
|
||||||
|
fn flush(&mut self) -> Result<()>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Read-only view of a store.
|
||||||
|
pub trait StoreView {
|
||||||
|
/// Read a block of data from the store. Blocks are immutiable, so the result may be a
|
||||||
|
/// reference to the internal copy of the data in the store.
|
||||||
|
fn read<'a>(&'a self, id: BlockId) -> Result<Cow<'a, [u8]>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Null implementation of a store. This cannot be used to store new blocks of data, and returns
|
||||||
|
/// an error if any attempts to read are made.
|
||||||
|
pub struct NullStore;
|
||||||
|
|
||||||
|
impl NullStore {
|
||||||
|
pub fn new() -> NullStore {
|
||||||
|
NullStore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl StoreView for NullStore {
|
||||||
|
fn read<'a>(&'a self, id: BlockId) -> Result<Cow<'a, [u8]>> {
|
||||||
|
bail!(ErrorKind::InvalidStoreId(id.0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
pub mod tests {
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use errors::*;
|
||||||
|
use store::{BlockId, Store, StoreView};
|
||||||
|
use std::borrow::Cow;
|
||||||
|
|
||||||
|
/// Define a Store to be used in tests. This doesn't store the data on disk, but rather
|
||||||
|
/// keeps it in memory in a hash map.
|
||||||
|
pub struct MapStore {
|
||||||
|
next_id: BlockId,
|
||||||
|
data: HashMap<BlockId, Vec<u8>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MapStore {
|
||||||
|
pub fn new() -> MapStore {
|
||||||
|
// Initial ID is set to 24 to simulate a header.
|
||||||
|
MapStore {
|
||||||
|
next_id: BlockId(24),
|
||||||
|
data: HashMap::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Store for MapStore {
|
||||||
|
fn append(&mut self, data: &[u8]) -> Result<BlockId> {
|
||||||
|
let id = self.next_id;
|
||||||
|
self.data.insert(id, data.to_vec());
|
||||||
|
self.next_id.0 += data.len() as u64;
|
||||||
|
Ok(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn flush(&mut self) -> Result<()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl StoreView for MapStore {
|
||||||
|
fn read<'a>(&'a self, id: BlockId) -> Result<Cow<'a, [u8]>> {
|
||||||
|
match self.data.get(&id) {
|
||||||
|
Some(data) => Ok(Cow::from(data.as_slice())),
|
||||||
|
None => bail!(ErrorKind::InvalidStoreId(id.0)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn basic_test() {
|
||||||
|
let mut ms = MapStore::new();
|
||||||
|
let key1 = ms.append("12345".as_bytes()).expect("append key1");
|
||||||
|
let key2 = ms.append("67890".as_bytes()).expect("append key2");
|
||||||
|
ms.flush().expect("flush");
|
||||||
|
assert_eq!(ms.read(key2).unwrap(), "67890".as_bytes());
|
||||||
|
assert_eq!(ms.read(key1).unwrap(), "12345".as_bytes());
|
||||||
|
assert_eq!(
|
||||||
|
ms.read(BlockId(999)).unwrap_err().to_string(),
|
||||||
|
"invalid store id: 999"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user