blob: a2639b4fc3a77f8b8de0a1035ed2a451963225da [file] [log] [blame]
Quentin Smith6ceaac62016-12-21 16:13:49 -05001// 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.
7package fs
8
9import (
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.
19type 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.
27type 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.
35type MemFS struct {
36 mu sync.Mutex
37 content map[string]*memFile
38}
39
40// NewMemFS constructs a new, empty MemFS.
41func 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.
49func (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.
58func (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.
72type memFile struct {
73 fs *MemFS
74 name string
75 metadata map[string]string
76 content []byte
77}
78
79func (f *memFile) Write(p []byte) (int, error) {
80 f.content = append(f.content, p...)
81 return len(p), nil
82}
83
84func (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
95func (f *memFile) CloseWithError(error) error {
96 f.fs = nil
97 return nil
98}