Brown bag typo bugfix. refs #7031
[arvados.git] / services / keepstore / volume.go
1 // A Volume is an interface representing a Keep back-end storage unit:
2 // for example, a single mounted disk, a RAID array, an Amazon S3 volume,
3 // etc.
4
5 package main
6
7 import (
8         "io"
9         "sync/atomic"
10         "time"
11 )
12
13 type Volume interface {
14         // Get a block. IFF the returned error is nil, the caller must
15         // put the returned slice back into the buffer pool when it's
16         // finished with it. (Otherwise, the buffer pool will be
17         // depleted and eventually -- when all available buffers are
18         // used and not returned -- operations will reach deadlock.)
19         Get(loc string) ([]byte, error)
20         // Confirm Get() would return a buffer with exactly the same
21         // content as buf. If so, return nil. If not, return
22         // CollisionError or DiskHashError (depending on whether the
23         // data on disk matches the expected hash), or whatever error
24         // was encountered opening/reading the file.
25         Compare(loc string, data []byte) error
26         Put(loc string, data []byte) error
27         Touch(loc string) error
28         Mtime(loc string) (time.Time, error)
29         IndexTo(prefix string, writer io.Writer) error
30         Delete(loc string) error
31         Status() *VolumeStatus
32         String() string
33         Writable() bool
34 }
35
36 // A VolumeManager tells callers which volumes can read, which volumes
37 // can write, and on which volume the next write should be attempted.
38 type VolumeManager interface {
39         // AllReadable returns all volumes.
40         AllReadable() []Volume
41         // AllWritable returns all volumes that aren't known to be in
42         // a read-only state. (There is no guarantee that a write to
43         // one will succeed, though.)
44         AllWritable() []Volume
45         // NextWritable returns the volume where the next new block
46         // should be written. A VolumeManager can select a volume in
47         // order to distribute activity across spindles, fill up disks
48         // with more free space, etc.
49         NextWritable() Volume
50         // Close shuts down the volume manager cleanly.
51         Close()
52 }
53
54 type RRVolumeManager struct {
55         readables []Volume
56         writables []Volume
57         counter   uint32
58 }
59
60 func MakeRRVolumeManager(volumes []Volume) *RRVolumeManager {
61         vm := &RRVolumeManager{}
62         for _, v := range volumes {
63                 vm.readables = append(vm.readables, v)
64                 if v.Writable() {
65                         vm.writables = append(vm.writables, v)
66                 }
67         }
68         return vm
69 }
70
71 func (vm *RRVolumeManager) AllReadable() []Volume {
72         return vm.readables
73 }
74
75 func (vm *RRVolumeManager) AllWritable() []Volume {
76         return vm.writables
77 }
78
79 func (vm *RRVolumeManager) NextWritable() Volume {
80         if len(vm.writables) == 0 {
81                 return nil
82         }
83         i := atomic.AddUint32(&vm.counter, 1)
84         return vm.writables[i%uint32(len(vm.writables))]
85 }
86
87 func (vm *RRVolumeManager) Close() {
88 }