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とかは全然違ってたけど.