Merge branch '14259-pysdk-remote-block-copy'
[arvados.git] / services / keepstore / volume.go
index 7e001a2470943e439e24cd6a149a4410754982ee..6bce05bec033fbda6c759b6b4266bcbff0f3e051 100644 (file)
@@ -1,12 +1,19 @@
+// 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"
        "time"
+
+       "git.curoverse.com/arvados.git/sdk/go/arvados"
 )
 
 type BlockWriter interface {
@@ -231,6 +238,13 @@ 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
+
+       // Get the storage classes associated with this volume
+       GetStorageClasses() []string
 }
 
 // A VolumeWithExamples provides example configs to display in the
@@ -246,6 +260,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 +289,8 @@ 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
+       arvados.KeepMount
+       volume Volume
 }
 
 // Generate a UUID the way API server would for a "KeepVolumeMount"
@@ -289,7 +305,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 +313,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 +325,25 @@ 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,
+               sc := v.GetStorageClasses()
+               if len(sc) == 0 {
+                       sc = []string{"default"}
                }
-               if v, ok := v.(interface {
-                       DeviceID() string
-               }); ok {
-                       mnt.DeviceID = v.DeviceID()
+               mnt := &VolumeMount{
+                       KeepMount: arvados.KeepMount{
+                               UUID:           (*VolumeMount)(nil).generateUUID(),
+                               DeviceID:       v.DeviceID(),
+                               ReadOnly:       !v.Writable(),
+                               Replication:    v.Replication(),
+                               StorageClasses: sc,
+                       },
+                       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 +356,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