A failing spec'd out bitcask, a start of something fun :)
This commit is contained in:
commit
e10a9e311f
7
.gitignore
vendored
Normal file
7
.gitignore
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
zig-cache/
|
||||
zig-out/
|
||||
/release/
|
||||
/debug/
|
||||
/build/
|
||||
/build-*/
|
||||
/docgen_tmp/
|
7
README.md
Normal file
7
README.md
Normal file
@ -0,0 +1,7 @@
|
||||
# Bitcask - A Simple KV datastore
|
||||
|
||||
Do it simply and do it well.
|
||||
|
||||
## The Bitcask paper
|
||||
|
||||
https://riak.com/assets/bitcask-intro.pdf
|
34
build.zig
Normal file
34
build.zig
Normal file
@ -0,0 +1,34 @@
|
||||
const std = @import("std");
|
||||
|
||||
pub fn build(b: *std.build.Builder) void {
|
||||
// Standard target options allows the person running `zig build` to choose
|
||||
// what target to build for. Here we do not override the defaults, which
|
||||
// means any target is allowed, and the default is native. Other options
|
||||
// for restricting supported target set are available.
|
||||
const target = b.standardTargetOptions(.{});
|
||||
|
||||
// Standard release options allow the person running `zig build` to select
|
||||
// between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall.
|
||||
const mode = b.standardReleaseOptions();
|
||||
|
||||
const exe = b.addExecutable("bitcask", "src/main.zig");
|
||||
exe.setTarget(target);
|
||||
exe.setBuildMode(mode);
|
||||
exe.install();
|
||||
|
||||
const run_cmd = exe.run();
|
||||
run_cmd.step.dependOn(b.getInstallStep());
|
||||
if (b.args) |args| {
|
||||
run_cmd.addArgs(args);
|
||||
}
|
||||
|
||||
const run_step = b.step("run", "Run the app");
|
||||
run_step.dependOn(&run_cmd.step);
|
||||
|
||||
const exe_tests = b.addTest("src/main.zig");
|
||||
exe_tests.setTarget(target);
|
||||
exe_tests.setBuildMode(mode);
|
||||
|
||||
const test_step = b.step("test", "Run unit tests");
|
||||
test_step.dependOn(&exe_tests.step);
|
||||
}
|
136
src/Bitcask/bitcask.zig
Normal file
136
src/Bitcask/bitcask.zig
Normal file
@ -0,0 +1,136 @@
|
||||
const std = @import("std");
|
||||
const expect = std.testing.expect;
|
||||
|
||||
pub const BitcaskFileError = error{
|
||||
AccessDenied,
|
||||
OutOfMemory,
|
||||
FileNotFound,
|
||||
};
|
||||
|
||||
pub const BitCask = struct {
|
||||
const FILE_THRESHOLD_SIZE = 1000;
|
||||
|
||||
|
||||
// std.StringArrayHashMap
|
||||
|
||||
// From the Bitcask paper, the API should look something like this
|
||||
|
||||
//** TODO
|
||||
|
||||
// What is the BitcaskHandel? How can I represent it?
|
||||
// Implement opening and closing files
|
||||
// Impement the spec
|
||||
|
||||
// ***
|
||||
|
||||
|
||||
// bitcask:open(DirectoryName, Opts) Open a new or existing Bitcask datastore with additional options.
|
||||
// → BitCaskHandle | {error, any()} Valid options include read write (if this process is going to be a
|
||||
// writer and not just a reader) and sync on put (if this writer would
|
||||
// prefer to sync the write file after every write operation).
|
||||
// The directory must be readable and writable by this process, and
|
||||
// only one process may open a Bitcask with read write at a time.
|
||||
// bitcask:open(DirectoryName) Open a new or existing Bitcask datastore for read-only access.
|
||||
// → BitCaskHandle | {error, any()} The directory and all files in it must be readable by this process.
|
||||
fn open(directory_name: []const u8) BitcaskFileError!void {
|
||||
std.debug.print("Opening bitcask in dir {s}\n", .{directory_name});
|
||||
return error.FileNotFound;
|
||||
}
|
||||
|
||||
// bitcask:get(BitCaskHandle, Key) Retrieve a value by key from a Bitcask datastore.
|
||||
// → not found | {ok, Value}
|
||||
fn get(key: []const u8) error{NotImplemented}!void {
|
||||
std.debug.print("Getting value with key {s}\n", .{key});
|
||||
return error.NotImplemented;
|
||||
}
|
||||
|
||||
// bitcask:put(BitCaskHandle, Key, Value) Store a key and value in a Bitcask datastore.
|
||||
// → ok | {error, any()}
|
||||
fn put() error{NotImplemented}!void {
|
||||
return error.NotImplemented;
|
||||
}
|
||||
|
||||
// bitcask:delete(BitCaskHandle, Key) Delete a key from a Bitcask datastore.
|
||||
// → ok | {error, any()}
|
||||
fn delete() error{NotImplemented}!void {
|
||||
return error.NotImplemented;
|
||||
}
|
||||
|
||||
// bitcask:list keys(BitCaskHandle) List all keys in a Bitcask datastore.
|
||||
// → [Key] | {error, any()}
|
||||
fn list() error{NotImplemented}!void {
|
||||
return error.NotImplemented;
|
||||
}
|
||||
|
||||
// bitcask:fold(BitCaskHandle,Fun,Acc0) Fold over all K/V pairs in a Bitcask datastore.
|
||||
// → Acc Fun is expected to be of the form: F(K,V,Acc0) → Acc.
|
||||
fn fold() error{NotImplemented}!void {
|
||||
return error.NotImplemented;
|
||||
}
|
||||
|
||||
// bitcask:merge(DirectoryName) Merge several data files within a Bitcask datastore into a more
|
||||
// → ok | {error, any()} compact form. Also, produce hintfiles for faster startup.
|
||||
fn merge() error{NotImplemented}!void {
|
||||
return error.NotImplemented;
|
||||
}
|
||||
|
||||
// bitcask:sync(BitCaskHandle) Force any writes to sync to disk.
|
||||
// → ok
|
||||
fn sync() error{NotImplemented}!void {
|
||||
return error.NotImplemented;
|
||||
}
|
||||
|
||||
// bitcask:close(BitCaskHandle) Close a Bitcask data store and flush all pending writes (if any) to disk
|
||||
fn close() error{NotImplemented}!void {
|
||||
return error.NotImplemented;
|
||||
}
|
||||
};
|
||||
|
||||
test "Bitcask spec implementation: open" {
|
||||
const bc = BitCask;
|
||||
try bc.open("File");
|
||||
// bc.open("File") catch |err| {
|
||||
// try expect(err == error.FileNotFound);
|
||||
// };
|
||||
|
||||
}
|
||||
|
||||
test "Bitcask spec implementation: get" {
|
||||
const bc = BitCask;
|
||||
try bc.get("key");
|
||||
}
|
||||
|
||||
test "Bitcask spec implementation: put" {
|
||||
const bc = BitCask;
|
||||
try bc.put();
|
||||
}
|
||||
|
||||
test "Bitcask spec implementation: delete" {
|
||||
const bc = BitCask;
|
||||
try bc.delete();
|
||||
}
|
||||
|
||||
test "Bitcask spec implementation: list" {
|
||||
const bc = BitCask;
|
||||
try bc.list();
|
||||
}
|
||||
|
||||
test "Bitcask spec implementation: fold" {
|
||||
const bc = BitCask;
|
||||
try bc.fold();
|
||||
}
|
||||
|
||||
test "Bitcask spec implementation: merge" {
|
||||
const bc = BitCask;
|
||||
try bc.merge();
|
||||
}
|
||||
|
||||
test "Bitcask spec implementation: sync" {
|
||||
const bc = BitCask;
|
||||
try bc.merge();
|
||||
}
|
||||
|
||||
test "Bitcask spec implementation: close" {
|
||||
const bc = BitCask;
|
||||
try bc.close();
|
||||
}
|
24
src/main.zig
Normal file
24
src/main.zig
Normal file
@ -0,0 +1,24 @@
|
||||
const std = @import("std");
|
||||
|
||||
pub fn main() !void {
|
||||
// Prints to stderr (it's a shortcut based on `std.io.getStdErr()`)
|
||||
std.debug.print("All your {s} are belong to us.\n", .{"codebase"});
|
||||
|
||||
// stdout is for the actual output of your application, for example if you
|
||||
// are implementing gzip, then only the compressed bytes should be sent to
|
||||
// stdout, not any debugging messages.
|
||||
const stdout_file = std.io.getStdOut().writer();
|
||||
var bw = std.io.bufferedWriter(stdout_file);
|
||||
const stdout = bw.writer();
|
||||
|
||||
try stdout.print("Run `zig build test` to run the tests.\n", .{});
|
||||
|
||||
try bw.flush(); // don't forget to flush!
|
||||
}
|
||||
|
||||
test "simple test" {
|
||||
var list = std.ArrayList(i32).init(std.testing.allocator);
|
||||
defer list.deinit(); // try commenting this out and see if zig detects the memory leak!
|
||||
try list.append(42);
|
||||
try std.testing.expectEqual(@as(i32, 42), list.pop());
|
||||
}
|
Loading…
Reference in New Issue
Block a user