7121: Clarify expected behavior of Compare() in Volume interface.
[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.
17         Get(loc string) ([]byte, error)
18         // Confirm Get() would return a buffer with exactly the same
19         // content as buf. If so, return nil. If not, return
20         // CollisionError or DiskHashError (depending on whether the
21         // data on disk matches the expected hash), or whatever error
22         // was encountered opening/reading the file.
23         Compare(loc string, data []byte) error
24         Put(loc string, data []byte) error
25         Touch(loc string) error
26         Mtime(loc string) (time.Time, error)
27         IndexTo(prefix string, writer io.Writer) error
28         Delete(loc string) error
29         Status() *VolumeStatus
30         String() string
31         Writable() bool
32 }
33
34 // A VolumeManager tells callers which volumes can read, which volumes
35 // can write, and on which volume the next write should be attempted.
36 type VolumeManager interface {
37         // AllReadable returns all volumes.
38         AllReadable() []Volume
39         // AllWritable returns all volumes that aren't known to be in
40         // a read-only state. (There is no guarantee that a write to
41         // one will succeed, though.)
42         AllWritable() []Volume
43         // NextWritable returns the volume where the next new block
44         // should be written. A VolumeManager can select a volume in
45         // order to distribute activity across spindles, fill up disks
46         // with more free space, etc.
47         NextWritable() Volume
48         // Close shuts down the volume manager cleanly.
49         Close()
50 }
51
52 type RRVolumeManager struct {
53         readables []Volume
54         writables []Volume
55         counter   uint32
56 }
57
58 func MakeRRVolumeManager(volumes []Volume) *RRVolumeManager {
59         vm := &RRVolumeManager{}
60         for _, v := range volumes {
61                 vm.readables = append(vm.readables, v)
62                 if v.Writable() {
63                         vm.writables = append(vm.writables, v)
64                 }
65         }
66         return vm
67 }
68
69 func (vm *RRVolumeManager) AllReadable() []Volume {
70         return vm.readables
71 }
72
73 func (vm *RRVolumeManager) AllWritable() []Volume {
74         return vm.writables
75 }
76
77 func (vm *RRVolumeManager) NextWritable() Volume {
78         if len(vm.writables) == 0 {
79                 return nil
80         }
81         i := atomic.AddUint32(&vm.counter, 1)
82         return vm.writables[i%uint32(len(vm.writables))]
83 }
84
85 func (vm *RRVolumeManager) Close() {
86 }