Implement persistent storage

next
Sayan Nandan 4 years ago
parent c75556ab2c
commit 16945337fa
No known key found for this signature in database
GPG Key ID: C31EFD7DDA12AEE0

3
.gitignore vendored

@ -1,2 +1,3 @@
/target
/.vscode
/.vscode
data.bin

@ -0,0 +1,23 @@
# Changelog
All changes in this project will be noted in this file.
## Version 0.3.0 [2020-07-28]
> No breaking changes
This version enables persistence for stored data
## Version 0.2.0 [2020-07-27]
> This release introduces breaking changes
This release implements the latest version of the Terrapipe protocol.
### Migrating existing clients
All clients have to reimplement the Terrapipe protocol to match the [latest spec](https://git.io/JJZ8Z).
## Version 0.1.0 [2020-07-17]
This release provides an experimental client and server implementation.

29
Cargo.lock generated

@ -6,12 +6,28 @@ version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4d25d88fd6b8041580a654f9d0c581a047baee2b3efee13275f2fc392fc75034"
[[package]]
name = "bincode"
version = "1.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f30d3a39baa26f9651f17b375061f3233dde33424a8b72b0dbe93a68a0bc896d"
dependencies = [
"byteorder",
"serde",
]
[[package]]
name = "bitflags"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
[[package]]
name = "byteorder"
version = "1.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de"
[[package]]
name = "bytes"
version = "0.5.6"
@ -26,7 +42,7 @@ checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
[[package]]
name = "corelib"
version = "0.1.0"
version = "0.2.0"
dependencies = [
"lazy_static",
]
@ -229,6 +245,12 @@ version = "0.1.57"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce"
[[package]]
name = "serde"
version = "1.0.114"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5317f7588f0a5078ee60ef675ef96735a1442132dc645eb1d12c018620ed8cd3"
[[package]]
name = "signal-hook-registry"
version = "1.2.0"
@ -270,8 +292,9 @@ dependencies = [
[[package]]
name = "tdb"
version = "0.1.0"
version = "0.3.0"
dependencies = [
"bincode",
"bytes",
"corelib",
"tokio",
@ -314,7 +337,7 @@ dependencies = [
[[package]]
name = "tsh"
version = "0.1.0"
version = "0.2.0"
dependencies = [
"corelib",
"tokio",

@ -8,17 +8,20 @@ TerrabaseDB (or TDB for short) is an effort to provide the best of key/value sto
## Status
**Currently**, TDB is a **persistent key/value store**.
As noted earlier, TerrabaseDB is pre-alpha software and the entire API is subject to major breaking changes, at the moment.
## Platforms
![Linux supported](https://img.shields.io/badge/Linux%20x86__64-supported%20✓-228B22?style=flat-square&logo=linux) ![macOS supported](https://img.shields.io/badge/macOS%20x86__64-supported%20✓-228B22?style=flat-square&logo=apple) ![Windows supported](https://img.shields.io/badge/Windows%20x86__64-supported%20✓-228B22?style=flat-square&logo=windows)
## Getting started
We have experimental client and server implementations for the database already.
The releases are uploaded in bundles, for example, `tdb-bundle-v0.2.0-x86_64-unknown-linux-gnu.zip`. Each bundle contains `tdb` and `tsh`, that is, the database server and the client command-line tool.
The releases are uploaded in bundles, for example, `tdb-bundle-v0.2.0-x86_64-unknown-linux-gnu.zip` . Each bundle contains `tdb` and `tsh` , that is, the database server and the client command-line tool.
* Download a bundle for your platform from [releases](https://github.com/terrabasedb/terrabase/releases)
* Unzip the downloaded bundle
* Run `chmod +x tdb tsh` (on Unix systems)
* Start the database server by running `./tdb`
* Start the client by running `./tsh`

@ -1,6 +1,6 @@
[package]
name = "tsh"
version = "0.1.0"
version = "0.2.0"
authors = ["Sayan Nandan <ohsayan@outlook.com>"]
edition = "2018"

@ -1,6 +1,6 @@
[package]
name = "corelib"
version = "0.1.0"
version = "0.2.0"
authors = ["Sayan Nandan <ohsayan@outlook.com>"]
edition = "2018"

@ -1,6 +1,6 @@
[package]
name = "tdb"
version = "0.1.0"
version = "0.3.0"
authors = ["Sayan Nandan <ohsayan@outlook.com>"]
edition = "2018"
@ -9,4 +9,5 @@ edition = "2018"
[dependencies]
tokio = { version = "0.2.22", features = ["full"] }
bytes = "0.5.6"
corelib = {path ="../corelib"}
corelib = {path ="../corelib"}
bincode = "1.3.1"

@ -20,8 +20,12 @@
*/
use crate::protocol::QueryDataframe;
use bincode;
use corelib::terrapipe::{tags, ActionType, RespBytes, RespCodes, ResponseBuilder};
use corelib::TResult;
use std::collections::{hash_map::Entry, HashMap};
use std::fs;
use std::io::{ErrorKind, Write};
use std::sync::{self, Arc, RwLock};
/// Results from actions on the Database
@ -183,12 +187,22 @@ impl CoreDB {
RespCodes::ArgumentError.into_response()
}
/// Create a new `CoreDB` instance
pub fn new() -> Self {
CoreDB {
shared: Arc::new(Coretable {
coremap: RwLock::new(HashMap::new()),
}),
terminate: false,
pub fn new() -> TResult<Self> {
let coretable = CoreDB::get_saved()?;
if let Some(coretable) = coretable {
Ok(CoreDB {
shared: Arc::new(Coretable {
coremap: RwLock::new(coretable),
}),
terminate: false,
})
} else {
Ok(CoreDB {
shared: Arc::new(Coretable {
coremap: RwLock::new(HashMap::new()),
}),
terminate: false,
})
}
}
/// Acquire a write lock
@ -199,6 +213,23 @@ impl CoreDB {
fn acquire_read(&self) -> sync::RwLockReadGuard<'_, HashMap<String, String>> {
self.shared.coremap.read().unwrap()
}
pub fn flush_db(&self) -> TResult<()> {
let encoded = bincode::serialize(&*self.acquire_read())?;
let mut file = fs::File::create("./data.bin")?;
file.write_all(&encoded)?;
Ok(())
}
pub fn get_saved() -> TResult<Option<HashMap<String, String>>> {
let file = match fs::read("./data.bin") {
Ok(f) => f,
Err(e) => match e.kind() {
ErrorKind::NotFound => return Ok(None),
_ => return Err("Couldn't read flushed data from disk".into()),
},
};
let parsed: HashMap<String, String> = bincode::deserialize(&file)?;
Ok(Some(parsed))
}
}
impl Drop for CoreDB {

@ -22,6 +22,7 @@
use crate::{Connection, CoreDB};
use corelib::TResult;
use std::future::Future;
use std::process;
use std::sync::Arc;
use tokio::net::TcpListener;
use tokio::net::TcpStream;
@ -161,9 +162,16 @@ impl Drop for CHandler {
pub async fn run(listener: TcpListener, sig: impl Future) {
let (signal, _) = broadcast::channel(1);
let (terminate_tx, terminate_rx) = mpsc::channel(1);
let db = match CoreDB::new() {
Ok(d) => d,
Err(e) => {
eprintln!("ERROR: {}", e);
process::exit(0x100);
}
};
let mut server = Listener {
listener,
db: CoreDB::new(),
db,
climit: Arc::new(Semaphore::new(10000)),
signal,
terminate_tx,
@ -172,15 +180,21 @@ pub async fn run(listener: TcpListener, sig: impl Future) {
tokio::select! {
_ = server.run() => {}
_ = sig => {
println!("Shuttting down...")
println!("Shutting down...")
}
}
let Listener {
mut terminate_rx,
terminate_tx,
signal,
db,
..
} = server;
if let Ok(_) = db.flush_db() {
()
} else {
eprintln!("ERROR: Couldn't flush database! All data created in this session will be lost");
}
drop(signal);
drop(terminate_tx);
let _ = terminate_rx.recv().await;

Loading…
Cancel
Save