Skip to content

DayDayRust init code #3

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Generated by Cargo
# will have compiled files and executables
/target/
**/target/

# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
Expand Down
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "daydayrust/rust-faster/faster-sys/faster"]
path = daydayrust/rust-faster/faster-sys/faster
url = https://github.com/cgair/FASTER.git
16 changes: 16 additions & 0 deletions daydayrust/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[package]
name = "daydayrust"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]

crossbeam-skiplist = { git = "https://github.com/crossbeam-rs/crossbeam.git" }
crossbeam-utils = { git = "https://github.com/crossbeam-rs/crossbeam.git" }

faster = { path = "./rust-faster" }
serde = { version = "1.0", features = ["derive"] }


18 changes: 18 additions & 0 deletions daydayrust/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Rust Hackathon Case Study: Design of Efficient Concurrent Index Data Structure

The current implementation of the index is [Lock + Btree](https://github.com/datenlord/Xline/blob/master/xline/src/storage/index.rs). However, this has some repercussions(inhibiting scalability, allowing for deadlocks, etc.). The first thing that came to my mind was to use a [reader-writer lock](https://docs.rs/parking_lot/latest/parking_lot/type.RwLock.html) instead. But in scenarios with high write frequency, I hope to find a way that allows concurrent writes to progress without mutual exclusion (use interior mutability). That is where the [crossbeam_skiplist](https://docs.rs/crossbeam-skiplist/latest/crossbeam_skiplist/) comes in.

## There's Something About Skip List

> *Skip lists are a data structure that can be used in place of balanced trees. Skip lists use probabilistic balancing rather than strictly enforced balancing and as a result the algorithms for insertion and deletion in skip lists are much simpler and significantly faster than equivalent algorithms for balanced trees.*
> *–William Pugh*

If that was a lot to take in, don't worry. It's not that important. If you really want to get it, [Open Data Structures](http://opendatastructures.org/ods-python/4_1_Basic_Structure.html) has a way more detailed description, code, and diagrams.

## Faster
Note that every insertion in skiplist triggers an allocation. Allocations are generally regarded as a slow thing to do, so that's something we'd like to avoid if possible!
[Faster](https://www.microsoft.com/en-us/research/uploads/prod/2018/03/faster-sigmod18.pdf), on the other hand, is like "lets put some arrays in there; computers love arrays". The sad thing is, I don't have time to implement it in pure rust. To add insult to injury, I have trouble [generating bindings to C++](https://rust-lang.github.io/rust-bindgen/cpp.html). I can only port an older version, but its API is not compatible with the interface we require.

## Okay But Seriously the Implementation

`TODO`
1 change: 1 addition & 0 deletions daydayrust/benches/skipmap.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
//! A place holder for benchmark
16 changes: 16 additions & 0 deletions daydayrust/rust-faster/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[package]
name = "faster"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
bincode = "1.3"
libc = "0.2"

serde = { version = "1.0", features = ["derive"] }
faster-sys = { path = "./faster-sys" }

[dev-dependencies]
tempfile = "3"
16 changes: 16 additions & 0 deletions daydayrust/rust-faster/faster-sys/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[package]
name = "faster-sys"
version = "0.1.0"
edition = "2021"

build = "build.rs"
links = "faster"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
libc = "0.2"

[build-dependencies]
bindgen = "0.63.0"
cmake = "0.1"
3 changes: 3 additions & 0 deletions daydayrust/rust-faster/faster-sys/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# faster-sys
Low level bindings to microsoft faster's C API(experimental).
FASTER KV is a concurrent key-value store + cache (available in C# and C++) that is designed for point lookups and heavy updates.
111 changes: 111 additions & 0 deletions daydayrust/rust-faster/faster-sys/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
// Credit to <https://github.com/rust-rocksdb/rust-rocksdb/blob/master/librocksdb-sys/build.rs>
use std::path::{Path, PathBuf};
use std::borrow::Borrow;
use std::process::Command;
use std::ffi::OsStr;
use std::env;

fn run_command_or_fail<P, S>(dir: &str, cmd: P, args: &[S])
where
P: AsRef<Path>,
S: Borrow<str> + AsRef<OsStr>
{
let cmd = if cmd.as_ref().is_relative() && cmd.as_ref().components().count() > 1 {
// If `cmd` is a relative path (and not a bare command that should be
// looked up in PATH), absolutize it relative to `dir`, as otherwise the
// behavior of std::process::Command is undefined.
// https://github.com/rust-lang/rust/issues/37868
PathBuf::from(dir)
.join(cmd)
.canonicalize()
.expect("Can canonicalize")
} else {
PathBuf::from(cmd.as_ref())
};

println!(
"Running command: \"{} {}\" in dir: {}",
cmd.display(),
args.join(" "),
dir
);

let ret = Command::new(cmd).current_dir(dir).args(args).status();
match ret.map(|status| (status.success(), status.code())) {
Ok((true, _)) => (),
Ok((false, Some(c))) => panic!("Command failed with error code {}", c),
Ok((false, None)) => panic!("Command got killed"),
Err(e) => panic!("Command failed with error: {}", e),

}
}

fn bindgen_faster() {
// The bindgen::Builder is the main entry point
// to bindgen, and lets you build up options for
// the resulting bindings.
let bindings = bindgen::Builder::default()
// The input header we would like to generate
// bindings for.
.header("faster/cc/src/core/faster-c.h")
// <https://github.com/rust-lang/rust-bindgen/issues/550>
.blocklist_type("max_align")
.ctypes_prefix("libc")
// Tell cargo to invalidate the built crate whenever any of the
// included header files changed.
.parse_callbacks(Box::new(bindgen::CargoCallbacks))
// Finish the builder and generate the bindings.
.generate()
.expect("Generate bindings.");

let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
bindings
.write_to_file(out_path.join("bindings.rs"))
.expect("Write faster bindings");
}

// cmake build
fn build_faster() {
let mut config = cmake::Config::new("faster/cc");

config
// .define("CMAKE_BUILD_TYPE", "Release")
.cflag("--std=c++11");

println!("Configuring and compiling faster");
let dst = config.build();

println!("cargo:rustc-link-search=native={}/{}", dst.display(), "build");
println!("cargo:rustc-link-lib=static=faster");
}

fn main() {
if !Path::new("./faster/LICENSE").exists() {
run_command_or_fail("../../", "git", &["submodule", "update", "--init"]);
}

println!("cargo:rerun-if-changed=build.rs");
// Tell cargo to invalidate the built crate whenever the faster changes
println!("cargo:rerun-if-changed=faster/");

bindgen_faster();
build_faster();

println!("cargo:rustc-link-lib=stdc++fs");
println!("cargo:rustc-link-lib=uuid");
println!("cargo:rustc-link-lib=tbb");
println!("cargo:rustc-link-lib=gcc");
println!("cargo:rustc-link-lib=stdc++");
println!("cargo:rustc-link-lib=aio");
println!("cargo:rustc-link-lib=pthread");
println!("cargo:rustc-link-lib=m");

// Allow dependent crates to locate the sources and output directory of
// this crate. Notably, this allows a dependent crate to locate the faster
// sources and built archive artifacts provided by this crate.
// println!(
// "cargo:cargo_manifest_dir={}",
// env::var("CARGO_MANIFEST_DIR").unwrap()
// );
// println!("cargo:out_dir={}", env::var("OUT_DIR").unwrap());
}
1 change: 1 addition & 0 deletions daydayrust/rust-faster/faster-sys/faster
Submodule faster added at 721816
6 changes: 6 additions & 0 deletions daydayrust/rust-faster/faster-sys/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// <https://rust-lang.github.io/rust-bindgen/tutorial-4.html>
#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]

include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
89 changes: 89 additions & 0 deletions daydayrust/rust-faster/src/builder.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
use std::ffi::CString;
use faster_sys as ffi;

use crate::{FasterError, FasterKv};

pub struct FasterKvBuilder<'a> {
table_size: u64,
log_size: u64,
storage: Option<&'a str>,
log_mutable_fraction: f64,
pre_allocate_log: bool,
}

impl<'a> FasterKvBuilder<'a> {
pub fn new(table_size: u64, log_size: u64) -> FasterKvBuilder<'a> {
FasterKvBuilder {
table_size,
log_size,
storage: None,
log_mutable_fraction: 0.9,
pre_allocate_log: false,
}
}

pub fn with_disk(&mut self, path: &'a str) -> &mut FasterKvBuilder<'a> {
self.storage = Some(path);
self
}

pub fn with_log_mutable_fraction(&mut self, fraction: f64) -> &mut FasterKvBuilder<'a> {
self.log_mutable_fraction = fraction;
self
}

pub fn set_pre_allocate_log(&mut self, pre_allocate_log: bool) -> &mut FasterKvBuilder<'a> {
self.pre_allocate_log = pre_allocate_log;
self
}

pub fn build(&self) -> Result<FasterKv, FasterError<'static>> {
if !(self.log_mutable_fraction > 0.0 && self.log_mutable_fraction <= 1.0) {
return Err(FasterError::BuilderError(
"Log mutable fraction must be between 0 and 1",
));
}
unsafe {
let mut storage_dir = None;
let faster_t = match self.storage {
None => ffi::faster_open(self.table_size, self.log_size, self.pre_allocate_log),
Some(path) => {
let storage_str = CString::new(path).unwrap();
let ptr_raw = storage_str.into_raw();
let ft = ffi::faster_open_with_disk(
self.table_size,
self.log_size,
ptr_raw,
self.log_mutable_fraction,
self.pre_allocate_log,
);
storage_dir = CString::from_raw(ptr_raw).into_string().ok();
ft
}
};
Ok(FasterKv {
faster_t,
storage_dir,
})
}
}
}

#[cfg(test)]
pub mod tests {
use super::FasterKvBuilder;
use tempfile::TempDir;
#[test]
fn can_build_with_disk() {
let dir = TempDir::new().unwrap();
let dir_str = dir.path().to_str().unwrap();
let mut builder = FasterKvBuilder::new(1 << 15, 1024 * 1024 * 1024);
builder
.with_disk(dir_str)
.set_pre_allocate_log(true)
.with_log_mutable_fraction(0.8);
let kv = builder.build().unwrap();
let storage = &kv.storage_dir;
assert_eq!(storage.as_ref().unwrap(), dir_str);
}
}
31 changes: 31 additions & 0 deletions daydayrust/rust-faster/src/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
use std::error::Error;
use std::{fmt, io};

#[derive(Debug)]
pub enum FasterError<'a> {
IOError(io::Error),
InvalidType,
RecoveryError,
CheckpointError,
BuilderError(&'a str),
}

impl<'a> fmt::Display for FasterError<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
FasterError::IOError(err) => write!(f, "{}", err.to_string()),
FasterError::InvalidType => write!(f, "Cannot call method with in-memory FasterKv"),
FasterError::RecoveryError => write!(f, "Failed to recover"),
FasterError::CheckpointError => write!(f, "Checkpoint failed"),
FasterError::BuilderError(err) => write!(f, "Builder error: {}", err),
}
}
}

impl<'a> From<io::Error> for FasterError<'a> {
fn from(e: io::Error) -> Self {
FasterError::IOError(e)
}
}

impl<'a> Error for FasterError<'a> {}
Loading