Show HN: voidDB – A transactional key-value DB written in Go for 64-bit Linux
github.com
github.com
// voidDB is a cherished toy, a journey into the Unknown, a heroic struggle,
// and a work of love. It is the “Twee!” of a bird; a tree falling in the
// forest; yet another programmer pouring their drop into the proverbial [bit]
// bucket. Above all, it is a shrine unto simple, readable, and functional
// code; an assertion that the dichotomy between such aesthetics and practical
// performance is mere illusion.
[1] https://github.com/voidDB/voidDB/blob/ac104867749e2c698b3d61...Huginn: thought, perception, comprehension, ...
Muninn: care, urge, wonder, curiosity, interest, ...
goos: linux
goarch: arm64
pkg: github.com/voidDB/voidDB/test
BenchmarkVoidPut-2 131072 14933 ns/op
BenchmarkVoidGet-2 131072 1060 ns/op
BenchmarkVoidGetNext-2 131072 245.8 ns/op
BenchmarkLMDBPut-2 131072 22414 ns/op
BenchmarkLMDBGet-2 131072 1826 ns/op
BenchmarkLMDBGetNext-2 131072 602.2 ns/op
BenchmarkBoltPut-2 131072 66984 ns/op
BenchmarkBoltGet-2 131072 2552 ns/op
BenchmarkBoltGetNext-2 131072 254.6 ns/op
BenchmarkLevelPut-2 131072 44182 ns/op
BenchmarkLevelGet-2 131072 30949 ns/op
BenchmarkLevelGetNext-2 131072 3441 ns/op
BenchmarkBadgerPut-2 131072 15182 ns/op
BenchmarkBadgerGet-2 131072 33114 ns/op
BenchmarkBadgerGetNext-2 131072 12895 ns/op
BenchmarkNothing-2 131072 0.3239 ns/op
Check out the docs at https://pkg.go.dev/github.com/voidDB/voidDB[1]: https://github.com/voidDB/voidDB/blob/master/test/bench_test...
For example:
- BenchmarkVoidPut runs a single O(n) sized transaction
- BenchmarkLMDBPut runs a single O(n) sized transaction
- BenchmarkBadgetPut runs O(n) O(n) sized transactions (!!!)
I made a local change so that all Put benchmarks ran O(n) O(1) sized transactions and the results were quite different: Void was the slowest, followed by LMDB, Bold, LevelDB, then Badger.
I'd also wager the LMDB author would also (lovingly!) tell us we're holding it wrong
In order to interface with C code safely, Go's runtime has to jump to the system stack and do some additional setup, make the call, and then switch back. (Adding to that, if the call takes too long, this prevents other goroutines on the same OS thread from running, so the scheduler must jump in and move those goroutines to a different thread.)
All of this is expensive, though we are talking about nanoseconds, not milliseconds. Performance is mostly a problem when doing lots of very quick calls (e.g. you're writing a game engine interacting with something like OpenGL) or lots of slow calls (causing scheduler trashing).
require golang.org/x/sys v0.29.0
Could have used "syscall" in the standard library instead of "golang.org/x/sys/unix" if not for these: https://pkg.go.dev/golang.org/x/sys/unix#F_OFD_GETLK... and this: https://go.googlesource.com/proposal/+/refs/heads/master/des...
~/go/src/github.com/voidDB/voidDB git:(master)
$ go run github.com/tailscale/depaware@latest
github.com/voidDB/voidDB dependencies: (generated by github.com/tailscale/depaware)
github.com/voidDB/voidDB/common from github.com/voidDB/voidDB+
github.com/voidDB/voidDB/cursor from github.com/voidDB/voidDB
github.com/voidDB/voidDB/free from github.com/voidDB/voidDB
github.com/voidDB/voidDB/node from github.com/voidDB/voidDB+
github.com/voidDB/voidDB/reader from github.com/voidDB/voidDB
golang.org/x/sys/unix from github.com/voidDB/voidDB+
bytes from github.com/voidDB/voidDB+
cmp from internal/fmtsort+
encoding/binary from github.com/voidDB/voidDB/common+
errors from bytes+
D fmt from golang.org/x/sys/unix
hash from github.com/voidDB/voidDB+
hash/fnv from github.com/voidDB/voidDB
io from bytes+
io/fs from internal/filepathlite+
iter from reflect+
math from encoding/binary+
math/bits from golang.org/x/sys/unix+
os from fmt+
path from io/fs
reflect from encoding/binary+
slices from encoding/binary+
LD sort from golang.org/x/sys/unix
strconv from fmt+
LD strings from golang.org/x/sys/unix
sync from encoding/binary+
sync/atomic from internal/bisect+
syscall from github.com/voidDB/voidDB/cursor+
time from github.com/voidDB/voidDB+
unicode from bytes+
W unicode/utf16 from internal/poll+
unicode/utf8 from bytes+Go tooling will preserve your go.mod comments and structure.
You can also consider moving integration tests and benchmarks to another module in the same repo.