Skip to content

Commit

Permalink
add server-mvp
Browse files Browse the repository at this point in the history
  • Loading branch information
cospectrum committed Jan 22, 2024
1 parent 269adc6 commit 39a88f1
Show file tree
Hide file tree
Showing 28 changed files with 565 additions and 158 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ resolver = "2"

members = [
"memcrab",
"memcrab-cache",
"memcrab-server",
"memcrab-protocol",
"memcrab-cli",
]
Expand Down
9 changes: 0 additions & 9 deletions memcrab-cache/Cargo.toml

This file was deleted.

3 changes: 0 additions & 3 deletions memcrab-cache/src/lib.rs

This file was deleted.

73 changes: 0 additions & 73 deletions memcrab-cache/src/mem_lru/builder.rs

This file was deleted.

6 changes: 0 additions & 6 deletions memcrab-cache/src/mem_lru/mod.rs

This file was deleted.

22 changes: 0 additions & 22 deletions memcrab-cache/tests/memlru.rs

This file was deleted.

1 change: 0 additions & 1 deletion memcrab-cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,5 @@ repository = "https://github.com/cospectrum/memcrab"
anyhow = "1.0.79"
clap = { version = "4.4.12", features = ["derive"] }
memcrab = { version = "0.1.0", path = "../memcrab" }
memcrab-cache = { version = "0.1.0", path = "../memcrab-cache" }
rustyline = "13.0.0"
tokio = { version = "1.35.1", features = ["full"] }
19 changes: 5 additions & 14 deletions memcrab-protocol/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ Clients should only send request messages and understand responses messages howe
```rs
type PayloadLen = u64; // number of bytes in payload

type Version = u16; // protocol-version
type KeyLen = u64; // number of bytes in the encoded utf8 string key
type Expirtaion = u32; // expiration in seconds

Expand All @@ -54,12 +53,11 @@ type Key = String; // utf-8
#### Requests (first byte < 128)
| Message kind | first byte | remaining 8 bytes in header | payload
| --- | --- | --- | ---
| Version | 0 | PayloadLen | Version
| Ping | 1 | zeros | none
| Get | 2 | PayloadLen | Key
| Set | 3 | PayloadLen | KeyLen, Expirtaion, Key, Value
| Delete | 4 | PayloadLen | Key
| Clear | 5 | zeros | none
| Ping | 0 | zeros | none
| Get | 1 | PayloadLen | Key
| Set | 2 | PayloadLen | KeyLen, Expirtaion, Key, Value
| Delete | 3 | PayloadLen | Key
| Clear | 4 | zeros | none

#### Responses (first byte >= 128)
| Message kind | first byte | remaining 8 bytes in header | payload
Expand All @@ -70,10 +68,3 @@ type Key = String; // utf-8
| KeyNotFound | 131 | zeros | none
| Error | 255 | PayloadLen | String (utf-8 encoded)

### Versioning
Protocol is versioned by a number and are not backwards compatible.

The current version is `0`.

The clients must send `Version` message as their first message.
The server must close the connection if the version is not compatible.
1 change: 0 additions & 1 deletion memcrab-protocol/src/alias.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
pub type PayloadLen = u64;

pub type Version = u16;
pub type KeyLen = u64;
pub type Expiration = u32;
11 changes: 5 additions & 6 deletions memcrab-protocol/src/kind.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,11 @@ impl TryFrom<u8> for MsgKind {
#[repr(u8)]
#[derive(Debug, Clone, Copy, TryFromPrimitive, IntoPrimitive, PartialEq, Eq)]
pub enum RequestKind {
Version = 0,
Ping = 1,
Get = 2,
Set = 3,
Delete = 4,
Clear = 5,
Ping = 0,
Get = 1,
Set = 2,
Delete = 3,
Clear = 4,
}

#[repr(u8)]
Expand Down
2 changes: 0 additions & 2 deletions memcrab-protocol/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ mod socket;

use std::mem::size_of;

use alias::Version;
use parser::Parser;

pub use err::{Error, ParseError};
Expand All @@ -17,7 +16,6 @@ pub use msg::{Msg, Request, Response};
pub use socket::Socket;

const HEADER_SIZE: usize = size_of::<u8>() + size_of::<u64>();
pub const VERSION: Version = 0;

#[cfg(test)]
mod tests {
Expand Down
3 changes: 1 addition & 2 deletions memcrab-protocol/src/msg.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::alias::{Expiration, Version};
use crate::alias::Expiration;

#[derive(Debug, Clone, PartialEq)]
pub enum Msg {
Expand All @@ -8,7 +8,6 @@ pub enum Msg {

#[derive(Debug, Clone, PartialEq)]
pub enum Request {
Version(Version),
Get(String),
Set {
key: String,
Expand Down
7 changes: 1 addition & 6 deletions memcrab-protocol/src/parser.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::{
alias::{Expiration, KeyLen, PayloadLen, Version},
alias::{Expiration, KeyLen, PayloadLen},
kind::{MsgKind, RequestKind, ResponseKind},
Msg, ParseError, Request, Response, HEADER_SIZE,
};
Expand Down Expand Up @@ -32,10 +32,6 @@ impl Parser {
fn decode_request(&self, kind: RequestKind, payload: Payload) -> Result<Request, ParseError> {
use RequestKind as Kind;
Ok(match kind {
Kind::Version => {
let version = Version::from_be_bytes(payload.as_slice().try_into()?);
Request::Version(version)
}
Kind::Ping => Request::Ping,
Kind::Get => Request::Get(utf8(payload)?),
Kind::Set => {
Expand Down Expand Up @@ -92,7 +88,6 @@ impl Parser {

fn encode_request(&self, req: Request) -> (RequestKind, Payload) {
match req {
Request::Version(version) => (RequestKind::Version, version.to_be_bytes().to_vec()),
Request::Ping => (RequestKind::Ping, vec![]),
Request::Clear => (RequestKind::Clear, vec![]),
Request::Get(key) => (RequestKind::Get, key.into()),
Expand Down
5 changes: 0 additions & 5 deletions memcrab-protocol/src/socket.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,11 +101,6 @@ mod test {
// boilerplate somehow
// TODO!: tests for encoding

let mut data = vec![MsgKind::Request(RequestKind::Version).into()];
data.extend(2u64.to_be_bytes());
data.extend([0, 1]);
assert_parsed(data, Msg::Request(Request::Version(1))).await;

let mut data = vec![MsgKind::Request(RequestKind::Ping).into()];
data.extend(zero_u64_bytes);
assert_parsed(data, Msg::Request(Request::Ping)).await;
Expand Down
13 changes: 13 additions & 0 deletions memcrab-server/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[package]
name = "memcrab-server"
version = "0.1.0"
edition = "2021"

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

[dependencies]
tokio = { workspace = true, features = ["full"] }
memcrab-protocol = { version = "0.1.0", path = "../memcrab-protocol" }
lru = "0.12.1"
thiserror.workspace = true
typed-builder = "0.18.1"
18 changes: 18 additions & 0 deletions memcrab-server/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# memcrab-server

```rs
use memcrab_server::{Server, CacheCfg};

#[tokio::main]
async fn main() {
let gb = 2_usize.pow(30);
let cfg = CacheCfg::builder()
.segments(10)
.max_bytesize(gb)
.build();

let addr = "127.0.0.1:9900".parse().unwrap();
let server = Server::from(cfg);
server.start(addr).await.unwrap();
}
```
48 changes: 48 additions & 0 deletions memcrab-server/src/cache/api/cfg.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
use std::sync::Mutex;
use typed_builder::TypedBuilder;

use crate::cache::map::Map;

use super::{MemLru, Value};

#[derive(TypedBuilder)]
pub struct CacheCfg {
segments: usize,
#[builder(default=None, setter(strip_option))]
max_len: Option<usize>,
max_bytesize: usize,
}

impl CacheCfg {
pub(super) fn map(self) -> Map<String, Value> {
assert!(self.segments > 0);

let new_segment = |max_bytesize: usize, max_len: Option<usize>| {
Mutex::new(match max_len {
Some(max_len) => {
if max_len == 0 {
MemLru::with_max_bytesize(max_bytesize)
} else {
MemLru::with_max_bytesize_and_max_len(max_bytesize, max_len)
}
}
None => MemLru::with_max_bytesize(max_bytesize),
})
};

let mut segments = Vec::with_capacity(self.segments);
let segment = new_segment(
self.max_bytesize / self.segments + self.max_bytesize % self.segments,
self.max_len.map(|l| l / self.segments + l % self.segments),
);
segments.push(segment);
for _ in 1..self.segments {
let segment = new_segment(
self.max_bytesize / self.segments,
self.max_len.map(|l| l / self.segments),
);
segments.push(segment);
}
Map::from_segments(segments)
}
}
Loading

0 comments on commit 39a88f1

Please sign in to comment.