mirror of
https://github.com/facebook/sapling.git
synced 2024-10-10 16:57:49 +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)",
|
||||
]
|
||||
|
||||
[[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]]
|
||||
name = "bitflags"
|
||||
version = "0.7.0"
|
||||
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]]
|
||||
name = "either"
|
||||
version = "1.4.0"
|
||||
@ -25,6 +67,14 @@ dependencies = [
|
||||
"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]]
|
||||
name = "fuchsia-zircon"
|
||||
version = "0.2.1"
|
||||
@ -112,10 +162,16 @@ name = "regex-syntax"
|
||||
version = "0.3.9"
|
||||
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]]
|
||||
name = "rusttreedirstate"
|
||||
version = "0.1.0"
|
||||
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)",
|
||||
"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]
|
||||
"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 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 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-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"
|
||||
@ -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 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 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_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"
|
||||
|
@ -10,6 +10,9 @@ lto = true
|
||||
name = "rusttreedirstate"
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[dependencies]
|
||||
error-chain = "*"
|
||||
|
||||
[dev-dependencies]
|
||||
itertools = "0.7.2"
|
||||
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
|
||||
//! been marked as removed.
|
||||
|
||||
#[macro_use]
|
||||
extern crate error_chain;
|
||||
|
||||
#[cfg(test)]
|
||||
extern crate itertools;
|
||||
|
||||
@ -19,4 +22,8 @@ extern crate itertools;
|
||||
#[macro_use]
|
||||
extern crate quickcheck;
|
||||
|
||||
pub mod errors;
|
||||
pub mod store;
|
||||
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