X-Git-Url: https://git.arvados.org/arvados.git/blobdiff_plain/8690785168e12635ce35614c02d557fe77a3fe25..13288c69988380210150124d7991af6ca6e3d62b:/services/keepstore/volume.go?ds=sidebyside diff --git a/services/keepstore/volume.go b/services/keepstore/volume.go index 7e001a2470..69802abdd1 100644 --- a/services/keepstore/volume.go +++ b/services/keepstore/volume.go @@ -1,8 +1,13 @@ +// Copyright (C) The Arvados Authors. All rights reserved. +// +// SPDX-License-Identifier: AGPL-3.0 + package main import ( "context" "crypto/rand" + "fmt" "io" "math/big" "sync/atomic" @@ -231,6 +236,10 @@ type Volume interface { // EmptyTrash looks for trashed blocks that exceeded TrashLifetime // and deletes them from the volume. EmptyTrash() + + // Return a globally unique ID of the underlying storage + // device if possible, otherwise "". + DeviceID() string } // A VolumeWithExamples provides example configs to display in the @@ -246,6 +255,11 @@ type VolumeManager interface { // Mounts returns all mounts (volume attachments). Mounts() []*VolumeMount + // Lookup returns the volume under the given mount + // UUID. Returns nil if the mount does not exist. If + // write==true, returns nil if the volume is not writable. + Lookup(uuid string, write bool) Volume + // AllReadable returns all volumes. AllReadable() []Volume @@ -270,11 +284,12 @@ type VolumeManager interface { // A VolumeMount is an attachment of a Volume to a VolumeManager. type VolumeMount struct { - UUID string - DeviceID string - ReadOnly bool - Tier int - volume Volume + UUID string + DeviceID string + ReadOnly bool + Replication int + Tier int + volume Volume } // Generate a UUID the way API server would for a "KeepVolumeMount" @@ -289,7 +304,7 @@ func (*VolumeMount) generateUUID() string { if err != nil { panic(err) } - return "zzzzz-ivpuk-" + r.Text(36) + return fmt.Sprintf("zzzzz-ivpuk-%015s", r.Text(36)) } // RRVolumeManager is a round-robin VolumeManager: the Nth call to @@ -297,6 +312,7 @@ func (*VolumeMount) generateUUID() string { // (where writables are all Volumes v where v.Writable()==true). type RRVolumeManager struct { mounts []*VolumeMount + mountMap map[string]*VolumeMount readables []Volume writables []Volume counter uint32 @@ -308,21 +324,19 @@ func MakeRRVolumeManager(volumes []Volume) *RRVolumeManager { vm := &RRVolumeManager{ iostats: make(map[Volume]*ioStats), } + vm.mountMap = make(map[string]*VolumeMount) for _, v := range volumes { mnt := &VolumeMount{ - UUID: (*VolumeMount)(nil).generateUUID(), - DeviceID: "", - ReadOnly: !v.Writable(), - Tier: 1, - volume: v, - } - if v, ok := v.(interface { - DeviceID() string - }); ok { - mnt.DeviceID = v.DeviceID() + UUID: (*VolumeMount)(nil).generateUUID(), + DeviceID: v.DeviceID(), + ReadOnly: !v.Writable(), + Replication: v.Replication(), + Tier: 1, + volume: v, } vm.iostats[v] = &ioStats{} vm.mounts = append(vm.mounts, mnt) + vm.mountMap[mnt.UUID] = mnt vm.readables = append(vm.readables, v) if v.Writable() { vm.writables = append(vm.writables, v) @@ -335,6 +349,14 @@ func (vm *RRVolumeManager) Mounts() []*VolumeMount { return vm.mounts } +func (vm *RRVolumeManager) Lookup(uuid string, needWrite bool) Volume { + if mnt, ok := vm.mountMap[uuid]; ok && (!needWrite || !mnt.ReadOnly) { + return mnt.volume + } else { + return nil + } +} + // AllReadable returns an array of all readable volumes func (vm *RRVolumeManager) AllReadable() []Volume { return vm.readables