github.com/jgbaldwinbrown/perf@v0.1.1/storage/fs/fs.go (about) 1 // Copyright 2016 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // Package fs provides a backend-agnostic filesystem layer for storing 6 // performance results. 7 package fs 8 9 import ( 10 "errors" 11 "io" 12 "sort" 13 "sync" 14 15 "golang.org/x/net/context" 16 ) 17 18 // An FS stores uploaded benchmark data files. 19 type FS interface { 20 // NewWriter returns a Writer for a given file name. 21 // When the Writer is closed, the file will be stored with the 22 // given metadata and the data written to the writer. 23 NewWriter(ctx context.Context, name string, metadata map[string]string) (Writer, error) 24 } 25 26 // A Writer is an io.Writer that can also be closed with an error. 27 type Writer interface { 28 io.WriteCloser 29 // CloseWithError cancels the writing of the file, removing 30 // any partially written data. 31 CloseWithError(error) error 32 } 33 34 // MemFS is an in-memory filesystem implementing the FS interface. 35 type MemFS struct { 36 mu sync.Mutex 37 content map[string]*memFile 38 } 39 40 // NewMemFS constructs a new, empty MemFS. 41 func NewMemFS() *MemFS { 42 return &MemFS{ 43 content: make(map[string]*memFile), 44 } 45 } 46 47 // NewWriter returns a Writer for a given file name. As a side effect, 48 // it associates the given metadata with the file. 49 func (fs *MemFS) NewWriter(_ context.Context, name string, metadata map[string]string) (Writer, error) { 50 meta := make(map[string]string) 51 for k, v := range metadata { 52 meta[k] = v 53 } 54 return &memFile{fs: fs, name: name, metadata: meta}, nil 55 } 56 57 // Files returns the names of the files written to fs. 58 func (fs *MemFS) Files() []string { 59 fs.mu.Lock() 60 defer fs.mu.Unlock() 61 var files []string 62 for f := range fs.content { 63 files = append(files, f) 64 } 65 sort.Strings(files) 66 return files 67 } 68 69 // memFile represents a file in a MemFS. While the file is being 70 // written, fs points to the filesystem. Close writes the file's 71 // content to fs and sets fs to nil. 72 type memFile struct { 73 fs *MemFS 74 name string 75 metadata map[string]string 76 content []byte 77 } 78 79 func (f *memFile) Write(p []byte) (int, error) { 80 f.content = append(f.content, p...) 81 return len(p), nil 82 } 83 84 func (f *memFile) Close() error { 85 if f.fs == nil { 86 return errors.New("already closed") 87 } 88 f.fs.mu.Lock() 89 defer f.fs.mu.Unlock() 90 f.fs.content[f.name] = f 91 f.fs = nil 92 return nil 93 } 94 95 func (f *memFile) CloseWithError(error) error { 96 f.fs = nil 97 return nil 98 }