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  }