LevelDBがどのようにレコードにデータを保存しているか
だいたいこのような感じだとおもう.
package main import ( "encoding/binary" "fmt" ) const kBatchHdrLen = 8 + 4 // LevelDBはbatch単位で書き込む.(マルチスレッド対応のため? type Batch struct { buf []byte } func (b *Batch) grow(n int) { off := len(b.buf) if off == 0 { off = kBatchHdrLen // 先頭はヘッダのために空けておく n += off } if cap(b.buf)-off >= n { return } buf := make([]byte, 2*cap(b.buf)+n) copy(buf, b.buf) b.buf = buf[:off] } func (b *Batch) appendRec(t byte, key, value []byte) { n := 1 + binary.MaxVarintLen32 + len(key) if t == byte(1) { n += binary.MaxVarintLen32 + len(value) } b.grow(n) off := len(b.buf) buf := b.buf[:off+n] buf[off] = t fmt.Println(buf) // 論理削除フラグをセット(Put操作とDelete操作でわけてる off += 1 off += binary.PutUvarint(buf[off:], uint64(len(key))) // keyの格納にどれだけ必要になるか fmt.Println(buf) // 同時にバッファにkeyの長さを書き込んでいる copy(buf[off:], key) // keyをバッファに書き込む fmt.Println(buf) off += len(key) if t == byte(1) { // valueもおなじかんじ off += binary.PutUvarint(buf[off:], uint64(len(value))) copy(buf[off:], value) off += len(value) fmt.Println(buf) } b.buf = buf[:off] // 足切り fmt.Println(b.buf) } func (b *Batch) Put(key, value []byte) { b.appendRec(byte(1), key, value) // byte(1) = 論理削除フラグ } func main() { b := new(Batch) b.Put([]byte("key"), []byte("vlue")) }
出力結果:
$ go run batch.go [0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0 0 0 0 0 1 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0 0 0 0 0 1 3 107 101 121 0 0 0 0 0 0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0 0 0 0 0 1 3 107 101 121 4 118 108 117 101 0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0 0 0 0 0 1 3 107 101 121 4 118 108 117 101]
あんまり調べてないけど,いくつかのKVSもにたかんじだったのでレコードの書式ってどれも似たようなものなんだろうか. bitcaskとかは全然違ってたけど.