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