diff --git a/pkg/blockstore/blockstore.go b/pkg/blockstore/blockstore.go index 36cde7e4..4329624f 100644 --- a/pkg/blockstore/blockstore.go +++ b/pkg/blockstore/blockstore.go @@ -395,10 +395,11 @@ func (s *BlockStore) ReadAt(ctx context.Context, blockId string, name string, of // limit read to the actual size of the file size = entry.FileEntry.File.Size - offset } - for partIdx, _ := range dataEntries { - if entry.DataEntries[partIdx] != nil { - dataEntries[partIdx] = entry.DataEntries[partIdx] + for _, partIdx := range partsNeeded { + if len(entry.DataEntries) <= partIdx || entry.DataEntries[partIdx] == nil { + continue } + dataEntries[partIdx] = entry.DataEntries[partIdx] } return nil }) @@ -428,6 +429,17 @@ func (s *BlockStore) ReadAt(ctx context.Context, blockId string, name string, of return offset, rtn, nil } +func (s *BlockStore) ReadFile(ctx context.Context, blockId string, name string) (int64, []byte, error) { + file, err := s.Stat(ctx, blockId, name) + if err != nil { + return 0, nil, fmt.Errorf("error getting file: %v", err) + } + if file == nil { + return 0, nil, fmt.Errorf("file not found") + } + return s.ReadAt(ctx, blockId, name, 0, file.Size) +} + func minInt64(a, b int64) int64 { if a < b { return a diff --git a/pkg/blockstore/blockstore_cache.go b/pkg/blockstore/blockstore_cache.go index 8b72fa5a..b9b85324 100644 --- a/pkg/blockstore/blockstore_cache.go +++ b/pkg/blockstore/blockstore_cache.go @@ -4,6 +4,7 @@ package blockstore import ( + "bytes" "fmt" "sync" "sync/atomic" @@ -43,6 +44,35 @@ type CacheEntry struct { DataEntries []*DataCacheEntry } +func (e *CacheEntry) dump() string { + var buf bytes.Buffer + fmt.Fprintf(&buf, "CacheEntry{\nBlockId: %q, Name: %q, Version: %d, PinCount: %d, Deleted: %v\n", e.BlockId, e.Name, e.Version, e.PinCount, e.Deleted) + if e.FileEntry != nil { + fmt.Fprintf(&buf, "FileEntry: %v\n", e.FileEntry.File) + } + for i, dce := range e.DataEntries { + if dce != nil { + fmt.Fprintf(&buf, "DataEntry[%d][%v]: %q\n", i, dce.Dirty.Load(), string(dce.Data)) + } + } + buf.WriteString("}\n") + return buf.String() +} + +func (s *BlockStore) dump() string { + s.Lock.Lock() + defer s.Lock.Unlock() + var buf bytes.Buffer + buf.WriteString(fmt.Sprintf("BlockStore %d entries\n", len(s.Cache))) + for _, v := range s.Cache { + entryStr := v.dump() + buf.WriteString(entryStr) + buf.WriteString("\n") + } + return buf.String() + +} + // for testing func (s *BlockStore) getCacheSize() int { s.Lock.Lock() diff --git a/pkg/blockstore/blockstore_test.go b/pkg/blockstore/blockstore_test.go index d963dd8c..bfdd80f1 100644 --- a/pkg/blockstore/blockstore_test.go +++ b/pkg/blockstore/blockstore_test.go @@ -132,3 +132,57 @@ func TestSetMeta(t *testing.T) { } checkMapsEqual(t, map[string]any{"a": 6, "b": "hello", "c": "world", "d": 7}, file.Meta, "meta") } + +func checkFileSize(t *testing.T, ctx context.Context, blockId string, name string, size int64) { + file, err := GBS.Stat(ctx, blockId, name) + if err != nil { + t.Errorf("error stating file %q: %v", name, err) + return + } + if file == nil { + t.Errorf("file %q not found", name) + return + } + if file.Size != size { + t.Errorf("size mismatch for file %q: expected %d, got %d", name, size, file.Size) + } +} + +func checkFileData(t *testing.T, ctx context.Context, blockId string, name string, data string) { + _, rdata, err := GBS.ReadFile(ctx, blockId, name) + if err != nil { + t.Errorf("error reading data for file %q: %v", name, err) + return + } + if string(rdata) != data { + t.Errorf("data mismatch for file %q: expected %q, got %q", name, data, string(rdata)) + } +} + +func TestAppend(t *testing.T) { + initDb(t) + defer cleanupDb(t) + + ctx, cancelFn := context.WithTimeout(context.Background(), 5*time.Second) + defer cancelFn() + blockId := uuid.New().String() + fileName := "t2" + err := GBS.MakeFile(ctx, blockId, fileName, nil, FileOptsType{}) + if err != nil { + t.Fatalf("error creating file: %v", err) + } + err = GBS.AppendData(ctx, blockId, fileName, []byte("hello")) + if err != nil { + t.Fatalf("error appending data: %v", err) + } + // fmt.Print(GBS.dump()) + checkFileSize(t, ctx, blockId, fileName, 5) + checkFileData(t, ctx, blockId, fileName, "hello") + err = GBS.AppendData(ctx, blockId, fileName, []byte(" world")) + if err != nil { + t.Fatalf("error appending data: %v", err) + } + // fmt.Print(GBS.dump()) + checkFileSize(t, ctx, blockId, fileName, 11) + checkFileData(t, ctx, blockId, fileName, "hello world") +}