Thanks @amanmangal.
I use badger as a persistence storage for my raft protocol.
I currently take a snapshot and iterate through the keys to send them to the member over pipe which is trying to catchup with the existing database, which is slow because its a single goroutine and small buffer size. It took me around to 60 minutes for a 5GB database.
Well that all said its a custom logic on top of the snapshot.
func sendSnapshot(txn *badger.Txn, writer io.Writer) error {
it := txn.NewIterator(badger.DefaultIteratorOptions)
defer it.Close()
u32Buf := make([]byte, 4)
smallBuf := make([]byte, 32*1024)
bw := bufio.NewWriterSize(writer, 16384)
for it.Rewind(); it.Valid(); it.Next() {
item := it.Item()
var entryBuf []byte
err := item.Value(func(value []byte) error {
if len(value) == 0 {
return &kvdb.CorruptDbError{Message: "Empty ValueTuple", Key: item.KeyCopy(nil)}
}
entry := kvpb.BackupEntry{
Key: item.Key(),
ValueTuple: value,
}
if sz := entry.Size(); sz <= len(smallBuf) {
entryBuf = smallBuf[:sz]
} else {
entryBuf = make([]byte, sz)
}
n, err := entry.MarshalTo(entryBuf)
if err != nil {
return errors.Wrap(err, "Failed to marshal BackupEntry")
}
entryBuf = entryBuf[:n]
return nil
})
if err != nil {
return errors.Wrap(err, "item.Value failed")
}
binary.BigEndian.PutUint32(u32Buf, uint32(len(entryBuf)))
if _, err := bw.Write(u32Buf); err != nil {
return err
}
if _, err = bw.Write(entryBuf); err != nil {
return err
}
}
return bw.Flush()
}
I am looking to try out anything badger internally supports and can test it. I am looking at really quick way for the new member to catch up on existing db.