diff options
-rw-r--r-- | pkg/api/api0/api0testutil/storage.go | 58 | ||||
-rw-r--r-- | pkg/api/api0/storage.go | 11 | ||||
-rw-r--r-- | pkg/storage/memstore/memstore.go | 8 |
3 files changed, 68 insertions, 9 deletions
diff --git a/pkg/api/api0/api0testutil/storage.go b/pkg/api/api0/api0testutil/storage.go index f88c27c..be3bd4a 100644 --- a/pkg/api/api0/api0testutil/storage.go +++ b/pkg/api/api0/api0testutil/storage.go @@ -25,6 +25,18 @@ func TestPdataStorage(t *testing.T, s api0.PdataStorage) { pdata1SHA := sha256.Sum256(pdata1) pdata2SHA := sha256.Sum256(pdata2) + t.Run("HashForNonexistentUser1", func(t *testing.T) { + hash, exists, err := s.GetPdataHash(user1) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if exists { + t.Fatalf("exists should be false") + } + if hash != zeroSHA { + t.Fatalf("should not return hash") + } + }) t.Run("GetForNonexistentUser1", func(t *testing.T) { for _, tc := range []struct { Name string @@ -52,6 +64,18 @@ func TestPdataStorage(t *testing.T, s api0.PdataStorage) { t.Fatalf("unexpected error: %v", err) } }) + t.Run("HashForExistingUser1Pdata1", func(t *testing.T) { + hash, exists, err := s.GetPdataHash(user1) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if !exists { + t.Fatalf("exists should be true") + } + if hash != pdata1SHA { + t.Fatalf("should return correct hash") + } + }) t.Run("GetForExistingUser1", func(t *testing.T) { for _, tc := range []struct { Name string @@ -92,6 +116,18 @@ func TestPdataStorage(t *testing.T, s api0.PdataStorage) { t.Fatalf("unexpected error: %v", err) } }) + t.Run("HashForExistingUser1Pdata2", func(t *testing.T) { + hash, exists, err := s.GetPdataHash(user1) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if !exists { + t.Fatalf("exists should be true") + } + if hash != pdata2SHA { + t.Fatalf("should return correct hash") + } + }) t.Run("GetForExistingUser2", func(t *testing.T) { for _, tc := range []struct { Name string @@ -170,36 +206,48 @@ func TestPdataStorage(t *testing.T, s api0.PdataStorage) { } randSched() - if buf, exists, err := s.GetPdataCached(uid, data1sha); err != nil || !exists || buf != nil { + if hash, exists, err := s.GetPdataHash(uid); err != nil || !exists || hash != data1sha { fail.Store(4) return } randSched() - if buf, exists, err := s.GetPdataCached(uid, data2sha); err != nil || !exists || !bytes.Equal(buf, data1) { + if buf, exists, err := s.GetPdataCached(uid, data1sha); err != nil || !exists || buf != nil { fail.Store(5) return } randSched() - if err := s.SetPdata(uid, data2); err != nil { + if buf, exists, err := s.GetPdataCached(uid, data2sha); err != nil || !exists || !bytes.Equal(buf, data1) { fail.Store(6) return } randSched() - if buf, exists, err := s.GetPdataCached(uid, data2sha); err != nil || !exists || buf != nil { + if err := s.SetPdata(uid, data2); err != nil { fail.Store(7) return } randSched() - if buf, exists, err := s.GetPdataCached(uid, data1sha); err != nil || !exists || !bytes.Equal(buf, data2) { + if hash, exists, err := s.GetPdataHash(uid); err != nil || !exists || hash != data2sha { fail.Store(8) return } randSched() + if buf, exists, err := s.GetPdataCached(uid, data2sha); err != nil || !exists || buf != nil { + fail.Store(9) + return + } + randSched() + + if buf, exists, err := s.GetPdataCached(uid, data1sha); err != nil || !exists || !bytes.Equal(buf, data2) { + fail.Store(10) + return + } + randSched() + }(uid) } if wg.Wait(); fail.Load() != 0 { diff --git a/pkg/api/api0/storage.go b/pkg/api/api0/storage.go index cf7b078..a17e8da 100644 --- a/pkg/api/api0/storage.go +++ b/pkg/api/api0/storage.go @@ -6,11 +6,14 @@ import "crypto/sha256" // on the contents of the stored blobs (including validity). It may compress the // stored data. It must be safe for concurrent use. type PdataStorage interface { + // GetPdataHash gets the current pdata hash for uid. If there is not any + // pdata for uid, exists is false. If another error occurs, err is non-nil. + GetPdataHash(uid uint64) (hash [sha256.Size]byte, exists bool, err error) + // GetPdataCached gets the pdata for uid. If there is not any pdata for uid, - // ok is false. If the provided hash is nonzero and the current pdata - // matches, buf is nil. If another error occurs, buf is nil, ok is false, - // and err is non-nil. - GetPdataCached(uid uint64, sha256 [sha256.Size]byte) (buf []byte, exists bool, err error) + // exists is false. If the provided hash is nonzero and the current pdata + // matches, buf is nil. If another error occurs, err is non-nil. + GetPdataCached(uid uint64, sha [sha256.Size]byte) (buf []byte, exists bool, err error) // SetPdata sets the raw pdata for uid. SetPdata(uid uint64, buf []byte) (err error) diff --git a/pkg/storage/memstore/memstore.go b/pkg/storage/memstore/memstore.go index f0c60f5..50dc889 100644 --- a/pkg/storage/memstore/memstore.go +++ b/pkg/storage/memstore/memstore.go @@ -27,6 +27,14 @@ func NewPdataStore(compress bool) *PdataStore { } } +func (m *PdataStore) GetPdataHash(uid uint64) ([sha256.Size]byte, bool, error) { + v, ok := m.pdata.Load(uid) + if !ok { + return [sha256.Size]byte{}, ok, nil + } + return v.(pdataStoreEntry).Hash, ok, nil +} + func (m *PdataStore) GetPdataCached(uid uint64, sha [sha256.Size]byte) ([]byte, bool, error) { v, ok := m.pdata.Load(uid) if !ok { |