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,
14 type Volume interface {
15 Get(loc string) ([]byte, error)
16 Put(loc string, block []byte) error
17 Index(prefix string) string
18 Delete(loc string) error
19 Status() *VolumeStatus
23 // MockVolumes are Volumes used to test the Keep front end.
25 // If the Bad field is true, this volume should return an error
26 // on all writes and puts.
28 type MockVolume struct {
29 Store map[string][]byte
33 func CreateMockVolume() *MockVolume {
34 return &MockVolume{make(map[string][]byte), false}
37 func (v *MockVolume) Get(loc string) ([]byte, error) {
39 return nil, errors.New("Bad volume")
40 } else if block, ok := v.Store[loc]; ok {
43 return nil, os.ErrNotExist
46 func (v *MockVolume) Put(loc string, block []byte) error {
48 return errors.New("Bad volume")
54 func (v *MockVolume) Index(prefix string) string {
56 for loc, block := range v.Store {
57 if IsValidLocator(loc) && strings.HasPrefix(loc, prefix) {
58 result = result + fmt.Sprintf("%s+%d %d\n",
59 loc, len(block), 123456789)
65 func (v *MockVolume) Delete(loc string) error {
66 if _, ok := v.Store[loc]; ok {
73 func (v *MockVolume) Status() *VolumeStatus {
75 for _, block := range v.Store {
76 used = used + uint64(len(block))
78 return &VolumeStatus{"/bogo", 123, 1000000 - used, used}
81 func (v *MockVolume) String() string {
85 // A VolumeManager manages a collection of volumes.
87 // - Volumes is a slice of available Volumes.
88 // - Choose() returns a Volume suitable for writing to.
89 // - Quit() instructs the VolumeManager to shut down gracefully.
91 type VolumeManager interface {
97 type RRVolumeManager struct {
103 func MakeRRVolumeManager(vols []Volume) *RRVolumeManager {
104 // Create a new VolumeManager struct with the specified volumes,
105 // and with new Nextwrite and Quit channels.
106 // The Quit channel is buffered with a capacity of 1 so that
107 // another routine may write to it without blocking.
108 vm := &RRVolumeManager{vols, make(chan Volume), make(chan int, 1)}
110 // This goroutine implements round-robin volume selection.
111 // It sends each available Volume in turn to the Nextwrite
112 // channel, until receiving a notification on the Quit channel
113 // that it should terminate.
120 case vm.nextwrite <- vm.volumes[i]:
121 i = (i + 1) % len(vm.volumes)
129 func (vm *RRVolumeManager) Volumes() []Volume {
133 func (vm *RRVolumeManager) Choose() Volume {
134 return <-vm.nextwrite
137 func (vm *RRVolumeManager) Quit() {