diff --git a/storage/kv.go b/storage/kv.go index e0a37cb42..aa8b12333 100644 --- a/storage/kv.go +++ b/storage/kv.go @@ -40,6 +40,10 @@ type KV interface { Compact(rev int64) error + // Get the hash of KV state. + // This method is designed for consistency checking purpose. + Hash() (uint32, error) + // Write a snapshot to the given io writer Snapshot(w io.Writer) (int64, error) diff --git a/storage/kv_test.go b/storage/kv_test.go index 808a53089..279c4dd3b 100644 --- a/storage/kv_test.go +++ b/storage/kv_test.go @@ -608,6 +608,28 @@ func TestKVCompactBad(t *testing.T) { } } +func TestKVHash(t *testing.T) { + hashes := make([]uint32, 3) + + for i := 0; i < len(hashes); i++ { + var err error + kv := New(tmpPath) + kv.Put([]byte("foo0"), []byte("bar0")) + kv.Put([]byte("foo1"), []byte("bar0")) + hashes[i], err = kv.Hash() + if err != nil { + t.Fatalf("failed to get hash: %v", err) + } + cleanup(kv, tmpPath) + } + + for i := 1; i < len(hashes); i++ { + if hashes[i-1] != hashes[i] { + t.Errorf("hash[%d](%d) != hash[%d](%d)", i-1, hashes[i-1], i, hashes[i]) + } + } +} + func TestKVRestore(t *testing.T) { tests := []func(kv KV){ func(kv KV) { diff --git a/storage/kvstore.go b/storage/kvstore.go index 538fc6f8b..7a8850d04 100644 --- a/storage/kvstore.go +++ b/storage/kvstore.go @@ -2,6 +2,7 @@ package storage import ( "errors" + "hash/crc32" "io" "log" "math" @@ -203,6 +204,15 @@ func (s *store) Compact(rev int64) error { return nil } +func (s *store) Hash() (uint32, error) { + h := crc32.New(crc32.MakeTable(crc32.Castagnoli)) + _, err := s.Snapshot(h) + if err != nil { + return 0, err + } + return h.Sum32(), nil +} + func (s *store) Snapshot(w io.Writer) (int64, error) { s.b.ForceCommit() return s.b.Snapshot(w)