From 26bd499facca42185cd9b00215037b25e2fbc340 Mon Sep 17 00:00:00 2001 From: sawka Date: Fri, 19 Aug 2022 12:51:37 -0700 Subject: [PATCH] update to allow a WriteAt call for cirfiles --- pkg/cirfile/cirfile.go | 31 ++++++++++++++--- pkg/cirfile/cirfile_test.go | 66 ++++++++++++++++++++++++++++++++++++- 2 files changed, 91 insertions(+), 6 deletions(-) diff --git a/pkg/cirfile/cirfile.go b/pkg/cirfile/cirfile.go index 5992b876..ce98b807 100644 --- a/pkg/cirfile/cirfile.go +++ b/pkg/cirfile/cirfile.go @@ -307,18 +307,24 @@ func (f *File) getFreeChunks() []fileChunk { return rtn } -// returns (realOffset, data, error) -// will only return io.EOF when len(data) == 0, otherwise will just do a short read -func (f *File) ReadNext(ctx context.Context, buf []byte, offset int64) (int64, int, error) { +func (f *File) ReadAll(ctx context.Context) (int64, []byte, error) { err := f.flock(ctx, syscall.LOCK_SH) if err != nil { - return 0, 0, err + return 0, nil, err } defer f.unflock() err = f.readMeta() if err != nil { - return 0, 0, err + return 0, nil, err } + chunks := f.getFileChunks() + curSize := totalChunksSize(chunks) + buf := make([]byte, curSize) + realOffset, nr, err := f.internalReadNext(buf, 0) + return realOffset, buf[0:nr], err +} + +func (f *File) internalReadNext(buf []byte, offset int64) (int64, int, error) { if offset < f.FileOffset { offset = f.FileOffset } @@ -347,6 +353,21 @@ func (f *File) ReadNext(ctx context.Context, buf []byte, offset int64) (int64, i return offset, numRead, nil } +// returns (realOffset, numread, error) +// will only return io.EOF when len(data) == 0, otherwise will just do a short read +func (f *File) ReadNext(ctx context.Context, buf []byte, offset int64) (int64, int, error) { + err := f.flock(ctx, syscall.LOCK_SH) + if err != nil { + return 0, 0, err + } + defer f.unflock() + err = f.readMeta() + if err != nil { + return 0, 0, err + } + return f.internalReadNext(buf, offset) +} + func (f *File) ensureFreeSpace(requiredSpace int64) error { chunks := f.getFileChunks() curSpace := f.MaxSize - totalChunksSize(chunks) diff --git a/pkg/cirfile/cirfile_test.go b/pkg/cirfile/cirfile_test.go index 1e655470..d38cb09a 100644 --- a/pkg/cirfile/cirfile_test.go +++ b/pkg/cirfile/cirfile_test.go @@ -5,6 +5,7 @@ import ( "fmt" "os" "path" + "strings" "syscall" "testing" "time" @@ -28,7 +29,9 @@ func validateMeta(t *testing.T, desc string, f *File, startPos int64, endPos int func dumpFile(name string) { barr, _ := os.ReadFile(name) - fmt.Printf("<<<\n%s\n>>>", string(barr)) + str := string(barr) + str = strings.ReplaceAll(str, "\x00", ".") + fmt.Printf("%s<<<\n%s\n>>>\n", name, str) } func makeData(size int) string { @@ -216,3 +219,64 @@ func TestFlock(t *testing.T) { t.Fatalf("append error (should work fd2 was closed): %v", err) } } + +func TestWriteAt(t *testing.T) { + tempDir := t.TempDir() + f1Name := path.Join(tempDir, "f1.cf") + f, err := CreateCirFile(f1Name, 100) + if err != nil { + t.Fatalf("cannot create cirfile: %v", err) + } + err = f.WriteAt(nil, []byte("hello\nmike"), 4) + if err != nil { + t.Fatalf("writeat error: %v", err) + } + err = f.WriteAt(nil, []byte("t"), 2) + if err != nil { + t.Fatalf("writeat error: %v", err) + } + err = f.WriteAt(nil, []byte("more"), 30) + if err != nil { + t.Fatalf("writeat error: %v", err) + } + err = f.WriteAt(nil, []byte("\n"), 19) + if err != nil { + t.Fatalf("writeat error: %v", err) + } + dumpFile(f1Name) + err = f.WriteAt(nil, []byte("hello"), 200) + if err != nil { + t.Fatalf("writeat error: %v", err) + } + buf := make([]byte, 10) + realOffset, nr, err := f.ReadNext(context.Background(), buf, 200) + if err != nil || realOffset != 200 || nr != 5 || string(buf[0:nr]) != "hello" { + t.Fatalf("invalid readnext: err[%v] realoffset[%d] nr[%d] buf[%s]", err, realOffset, nr, string(buf[0:nr])) + } + err = f.WriteAt(nil, []byte("0123456789\n"), 100) + if err != nil { + t.Fatalf("writeat error: %v", err) + } + dumpFile(f1Name) + dataStr := makeData(200) + err = f.WriteAt(nil, []byte(dataStr), 50) + if err != nil { + t.Fatalf("writeat error: %v", err) + } + dumpFile(f1Name) + + dataStr = makeData(1000) + err = f.WriteAt(nil, []byte(dataStr), 1002) + if err != nil { + t.Fatalf("writeat error: %v", err) + } + err = f.WriteAt(nil, []byte("hello\n"), 2010) + if err != nil { + t.Fatalf("writeat error: %v", err) + } + err = f.AppendData(nil, []byte("foo\n")) + if err != nil { + t.Fatalf("appenddata error: %v", err) + } + dumpFile(f1Name) +}