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