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