feat(master): hybrid cloud add mediaType property to zone

(1) zone mediaType is set as the first add-in datanode's mediaType
	(2) once zone mediaType is set, all datanodes in the zone must be the same mediaType.
	(3) the cmd 'cfs-cli zone info' shows zone mediaType.

Signed-off-by: true1064 <tangjingyu@oppo.com>
This commit is contained in:
true1064 2023-11-02 05:25:48 +08:00 committed by AmazingChi
parent 029d1b359e
commit 3081a30168
10 changed files with 164 additions and 58 deletions

View File

@ -875,6 +875,7 @@ func formatZoneView(zv *proto.ZoneView) string {
sb := strings.Builder{}
sb.WriteString(fmt.Sprintf("Zone Name: %v\n", zv.Name))
sb.WriteString(fmt.Sprintf("Status: %v\n", zv.Status))
sb.WriteString(fmt.Sprintf("MediaType: %v\n", zv.MediaType))
sb.WriteString("Nodeset Selector:\n")
sb.WriteString(fmt.Sprintf(" Data:%v\n", zv.DataNodesetSelector))
sb.WriteString(fmt.Sprintf(" Meta:%v\n", zv.MetaNodesetSelector))

View File

@ -18,6 +18,8 @@ import (
"bytes"
"errors"
"fmt"
syslog "log"
"math"
"net"
"net/http"
"os"
@ -31,8 +33,6 @@ import (
"syscall"
"time"
syslog "log"
"github.com/cubefs/cubefs/cmd/common"
"github.com/cubefs/cubefs/proto"
"github.com/cubefs/cubefs/raftstore"
@ -418,14 +418,9 @@ func (s *DataNode) parseConfig(cfg *config.Config) (err error) {
s.diskUnavailablePartitionErrorCount = uint64(diskUnavailablePartitionErrorCount)
log.LogDebugf("action[parseConfig] load diskUnavailablePartitionErrorCount(%v)", s.diskUnavailablePartitionErrorCount)
mediaType := cfg.GetInt64(ConfigMediaType)
switch uint32(mediaType) {
case proto.MediaType_SSD:
s.mediaType = proto.MediaType_SSD
case proto.MediaType_HDD:
s.mediaType = proto.MediaType_HDD
default:
s.mediaType = proto.MediaType_Unspecified
var mediaType uint32
mediaTypeInt64 := cfg.GetInt64(ConfigMediaType)
if mediaTypeInt64 < 0 || mediaTypeInt64 > math.MaxUint32 {
err = fmt.Errorf("parseConfig: invalid mediaType[%v]", mediaType)
return err
}

View File

@ -103,6 +103,7 @@ type ZoneView struct {
DataNodesetSelector string
MetaNodesetSelector string
NodeSet map[uint64]*NodeSetView
MediaType string
}
func newZoneView(name string) *ZoneView {
@ -360,6 +361,7 @@ func (m *Server) getTopology(w http.ResponseWriter, r *http.Request) {
cv.Status = zone.getStatusToString()
cv.DataNodesetSelector = zone.GetDataNodesetSelector()
cv.MetaNodesetSelector = zone.GetMetaNodesetSelector()
cv.MediaType = zone.GetMediaTypeString()
tv.Zones = append(tv.Zones, cv)
nsc := zone.getAllNodeSet()
for _, ns := range nsc {

View File

@ -461,8 +461,8 @@ func (c *Cluster) scheduleToUpdateStatInfo() {
func (c *Cluster) addNodeSetGrp(ns *nodeSet, load bool) (err error) {
log.LogWarnf("addNodeSetGrp nodeSet id[%v] zonename[%v] load[%v] grpManager init[%v]",
ns.ID, ns.zoneName, load, c.domainManager.init)
if c.domainManager.init {
err = c.domainManager.putNodeSet(ns, load)
c.putZoneDomain(false)
@ -1135,7 +1135,7 @@ func (c *Cluster) addMetaNode(nodeAddr, zoneName string, nodesetId uint64) (id u
metaNode.MpCntLimit = newLimitCounter(&c.cfg.MaxMpCntLimit, defaultMaxMpCntLimit)
zone, err := c.t.getZone(zoneName)
if err != nil {
zone = c.t.putZoneIfAbsent(newZone(zoneName))
zone = c.t.putZoneIfAbsent(newZone(zoneName, proto.MediaType_Unspecified))
}
var ns *nodeSet
@ -1187,23 +1187,77 @@ func (c *Cluster) addDataNode(nodeAddr, zoneName string, nodesetId uint64, media
c.dnMutex.Lock()
defer c.dnMutex.Unlock()
var dataNode *DataNode
var needPersistZone bool
log.LogInfof("[addDataNode] to add: datanode(%v) zone(%v) nodesetId(%v) mediaType(%v)",
nodeAddr, zoneName, nodesetId, mediaType)
if node, ok := c.dataNodes.Load(nodeAddr); ok {
dataNode = node.(*DataNode)
if nodesetId > 0 && nodesetId != dataNode.NodeSetID {
return dataNode.ID, fmt.Errorf("addr already in nodeset [%v]", nodeAddr)
msg := fmt.Sprintf("datanode(%v) already in cluster, but nodesetId not match, existNodeSetID(%v) toAdd(%v)",
nodeAddr, dataNode.NodeSetID, nodesetId)
log.LogErrorf("[addDataNode] %v", msg)
return dataNode.ID, fmt.Errorf(msg)
}
if dataNode.MediaType != mediaType {
msg := fmt.Sprintf("datanode(%v) already in cluster, but datanode mediaType not match, existMediaType(%v) toAdd(%v)",
nodeAddr, proto.MediaTypeString(dataNode.MediaType), proto.MediaTypeString(mediaType))
log.LogErrorf("[addDataNode] %v", msg)
return dataNode.ID, fmt.Errorf(msg)
}
log.LogInfof("[addDataNode] already exist: datanode(%v) zone(%v) nodesetId(%v) mediaType(%v)",
nodeAddr, zoneName, nodesetId, mediaType)
return dataNode.ID, nil
}
if !proto.IsValidMediaType(mediaType) {
msg := fmt.Sprintf("invalid mediaType(%v) when adding datanode(%v)", mediaType, nodeAddr)
log.LogErrorf("[addDataNode] %v", msg)
return dataNode.ID, fmt.Errorf(msg)
}
dataNode = newDataNode(nodeAddr, zoneName, c.Name, mediaType)
dataNode.DpCntLimit = newLimitCounter(&c.cfg.MaxDpCntLimit, defaultMaxDpCntLimit)
zone, err := c.t.getZone(zoneName)
if err != nil {
zone = c.t.putZoneIfAbsent(newZone(zoneName))
log.LogInfof("[addDataNode] create zone(%v) by datanode(%v)", zoneName, nodeAddr)
zone = newZone(zoneName, mediaType)
needPersistZone = true
}
zoneMediaType := zone.GetMediaType()
if zoneMediaType != mediaType {
if zoneMediaType != proto.MediaType_Unspecified {
// if zone.mediaType is proto.MediaType_Unspecified, means has no datanode added into the zone yet
msg := fmt.Sprintf("datanode(%v) already in zone(%v) mediaType not match, existMediaType(%v) toAdd(%v)",
nodeAddr, zoneName, proto.MediaTypeString(zoneMediaType), proto.MediaTypeString(mediaType))
log.LogErrorf("[addDataNode] %v", msg)
return dataNode.ID, fmt.Errorf(msg)
} else {
zone.SetMediaType(mediaType)
log.LogInfof("[addDataNode] set zone(%v) mediaType(%v) by datanode(%v)",
zoneName, proto.MediaTypeString(mediaType), nodeAddr)
needPersistZone = true
}
}
if needPersistZone {
persistErr := c.sycnPutZoneInfo(zone)
if persistErr != nil {
msg := fmt.Sprintf("persist zone(%v) failed when adding datanode(%v)", zoneName, nodeAddr)
log.LogErrorf("[addDataNode] %v", msg)
return dataNode.ID, fmt.Errorf(msg)
}
}
c.t.putZoneIfAbsent(zone) // put if the above code creates zone
var ns *nodeSet
if nodesetId > 0 {
if ns, err = zone.getNodeSet(nodesetId); err != nil {
log.LogErrorf("[addDataNode] %v", err.Error())
return nodesetId, err
}
} else {
@ -1237,11 +1291,11 @@ func (c *Cluster) addDataNode(nodeAddr, zoneName string, nodesetId uint64, media
c.addNodeSetGrp(ns, false)
c.dataNodes.Store(nodeAddr, dataNode)
log.LogInfof("action[addDataNode],clusterID[%v] dataNodeAddr:%v,nodeSetId[%v],capacity[%v]",
log.LogInfof("action[addDataNode] clusterID[%v] dataNodeAddr:%v, nodeSetId[%v], capacity[%v]",
c.Name, nodeAddr, ns.ID, ns.Capacity)
return
errHandler:
err = fmt.Errorf("action[addDataNode],clusterID[%v] dataNodeAddr:%v err:%v ", c.Name, nodeAddr, err.Error())
err = fmt.Errorf("action[addDataNode] clusterID[%v] dataNodeAddr:%v err:%v", c.Name, nodeAddr, err.Error())
log.LogError(errors.Stack(err))
Warn(c.Name, err.Error())
return

View File

@ -863,7 +863,7 @@ func (c *Cluster) adjustMetaNode(metaNode *MetaNode) {
var zone *Zone
zone, err = c.t.getZone(metaNode.ZoneName)
if err != nil {
zone = newZone(metaNode.ZoneName)
zone = newZone(metaNode.ZoneName, proto.MediaType_Unspecified)
c.t.putZone(zone)
}
c.nsMutex.Lock()
@ -1045,7 +1045,7 @@ func (c *Cluster) adjustDataNode(dataNode *DataNode) {
var zone *Zone
zone, err = c.t.getZone(dataNode.ZoneName)
if err != nil {
zone = newZone(dataNode.ZoneName)
zone = newZone(dataNode.ZoneName, dataNode.MediaType)
c.t.putZone(zone)
}

View File

@ -64,14 +64,14 @@ const (
// default value
const (
defaultTobeFreedDataPartitionCount = 1000
defaultSecondsToFreeDataPartitionAfterLoad = 5 * 60 // a data partition can only be freed after loading 5 mins
defaultIntervalToFreeDataPartition = 10 // in terms of seconds
defaultSecondsToFreeDataPartitionAfterLoad = 5 * 60 // a data partition can only be freed after loading 5 mins
defaultIntervalToFreeDataPartition = 10 // in terms of seconds
defaultIntervalToCheck = 60
defaultIntervalToCheckHeartbeat = 6
defaultIntervalToCheckDataPartition = 5
defaultIntervalToCheckQos = 1
defaultIntervalToCheckCrc = 20 * defaultIntervalToCheck // in terms of seconds
noHeartBeatTimes = 3 // number of times that no heartbeat reported
defaultIntervalToCheckCrc = 20 * defaultIntervalToCheck // in terms of seconds
noHeartBeatTimes = 3 // number of times that no heartbeat reported
defaultNodeTimeOutSec = noHeartBeatTimes * defaultIntervalToCheckHeartbeat
defaultDataPartitionTimeOutSec = 200 * defaultIntervalToCheckHeartbeat // datanode with massive amount of dp may cost 10-min
defaultMissingDataPartitionInterval = 24 * 3600

View File

@ -24,8 +24,8 @@ import (
"golang.org/x/time/rate"
"github.com/cubefs/cubefs/depends/tiglabs/raft/proto"
bsProto "github.com/cubefs/cubefs/proto"
raftProto "github.com/cubefs/cubefs/depends/tiglabs/raft/proto"
"github.com/cubefs/cubefs/proto"
"github.com/cubefs/cubefs/util/errors"
"github.com/cubefs/cubefs/util/log"
)
@ -121,7 +121,7 @@ type metaPartitionValue struct {
VolName string
Hosts string
OfflinePeerID uint64
Peers []bsProto.Peer
Peers []proto.Peer
IsRecover bool
}
@ -146,7 +146,7 @@ type dataPartitionValue struct {
PartitionID uint64
ReplicaNum uint8
Hosts string
Peers []bsProto.Peer
Peers []proto.Peer
Status int8
VolID uint64
VolName string
@ -309,7 +309,7 @@ type volValue struct {
EnablePosixAcl bool
EnableQuota bool
EnableTransaction bsProto.TxOpMask
EnableTransaction proto.TxOpMask
TxTimeout int64
TxConflictRetryNum int64
TxConflictRetryInterval int64
@ -377,14 +377,14 @@ func newVolValue(vol *Vol) (vv *volValue) {
CacheLRUInterval: vol.CacheLRUInterval,
CacheRule: vol.CacheRule,
VolQosEnable: vol.qosManager.qosEnable,
IopsRLimit: vol.qosManager.getQosLimit(bsProto.IopsReadType),
IopsWLimit: vol.qosManager.getQosLimit(bsProto.IopsWriteType),
FlowRlimit: vol.qosManager.getQosLimit(bsProto.FlowReadType),
FlowWlimit: vol.qosManager.getQosLimit(bsProto.FlowWriteType),
IopsRMagnify: vol.qosManager.getQosMagnify(bsProto.IopsReadType),
IopsWMagnify: vol.qosManager.getQosMagnify(bsProto.IopsWriteType),
FlowRMagnify: vol.qosManager.getQosMagnify(bsProto.FlowReadType),
FlowWMagnify: vol.qosManager.getQosMagnify(bsProto.FlowWriteType),
IopsRLimit: vol.qosManager.getQosLimit(proto.IopsReadType),
IopsWLimit: vol.qosManager.getQosLimit(proto.IopsWriteType),
FlowRlimit: vol.qosManager.getQosLimit(proto.FlowReadType),
FlowWlimit: vol.qosManager.getQosLimit(proto.FlowWriteType),
IopsRMagnify: vol.qosManager.getQosMagnify(proto.IopsReadType),
IopsWMagnify: vol.qosManager.getQosMagnify(proto.IopsWriteType),
FlowRMagnify: vol.qosManager.getQosMagnify(proto.FlowReadType),
FlowWMagnify: vol.qosManager.getQosMagnify(proto.FlowWriteType),
ClientReqPeriod: vol.qosManager.ClientReqPeriod,
ClientHitTriggerCnt: vol.qosManager.ClientHitTriggerCnt,
@ -994,8 +994,8 @@ func (c *Cluster) syncPutDataNode(opType uint32, dataNode *DataNode) (err error)
func (c *Cluster) addRaftNode(nodeID uint64, addr string) (err error) {
log.LogInfof("action[addRaftNode] nodeID: %v, addr: %v:", nodeID, addr)
peer := proto.Peer{ID: nodeID}
_, err = c.partition.ChangeMember(proto.ConfAddNode, peer, []byte(addr))
peer := raftProto.Peer{ID: nodeID}
_, err = c.partition.ChangeMember(raftProto.ConfAddNode, peer, []byte(addr))
if err != nil {
return errors.New("action[addRaftNode] error: " + err.Error())
}
@ -1005,8 +1005,8 @@ func (c *Cluster) addRaftNode(nodeID uint64, addr string) (err error) {
func (c *Cluster) removeRaftNode(nodeID uint64, addr string) (err error) {
log.LogInfof("action[removeRaftNode] nodeID: %v, addr: %v:", nodeID, addr)
peer := proto.Peer{ID: nodeID}
_, err = c.partition.ChangeMember(proto.ConfRemoveNode, peer, []byte(addr))
peer := raftProto.Peer{ID: nodeID}
_, err = c.partition.ChangeMember(raftProto.ConfRemoveNode, peer, []byte(addr))
if err != nil {
return errors.New("action[removeRaftNode] error: " + err.Error())
}
@ -1014,8 +1014,8 @@ func (c *Cluster) removeRaftNode(nodeID uint64, addr string) (err error) {
}
func (c *Cluster) updateDirChildrenNumLimit(val uint32) {
if val < bsProto.MinDirChildrenNumLimit {
val = bsProto.DefaultDirChildrenNumLimit
if val < proto.MinDirChildrenNumLimit {
val = proto.DefaultDirChildrenNumLimit
}
atomic.StoreUint32(&c.cfg.DirChildrenNumLimit, val)
}
@ -1119,9 +1119,10 @@ func (c *Cluster) loadZoneValue() (err error) {
if zone.GetMetaNodesetSelector() != cv.MetaNodesetSelector {
zone.metaNodesetSelector = NewNodesetSelector(cv.MetaNodesetSelector, MetaNodeType)
}
log.LogInfof("action[loadZoneValue] load zonename[%v] with limit [%v,%v,%v,%v]",
zone.name, cv.QosFlowRLimit, cv.QosIopsWLimit, cv.QosFlowWLimit, cv.QosIopsRLimit)
log.LogInfof("action[loadZoneValue] load zoneName[%v] with limit [%v,%v,%v,%v], mediaType:%v",
zone.name, cv.QosFlowRLimit, cv.QosIopsWLimit, cv.QosFlowWLimit, cv.QosIopsRLimit, proto.MediaTypeString(cv.MediaType))
zone.loadDataNodeQosLimit()
zone.SetMediaType(cv.MediaType)
}
return
@ -1278,7 +1279,7 @@ func (c *Cluster) loadNodeSets() (err error) {
zone, err := c.t.getZone(nsv.ZoneName)
if err != nil {
log.LogErrorf("action[loadNodeSets], getZone err:%v", err)
zone = newZone(nsv.ZoneName)
zone = newZone(nsv.ZoneName, proto.MediaType_Unspecified)
c.t.putZoneIfAbsent(zone)
}
ns.UpdateMaxParallel(int32(c.DecommissionLimit))
@ -1579,7 +1580,7 @@ func (c *Cluster) loadVols() (err error) {
}
log.LogInfof("action[loadVols],vol[%v]", vol.Name)
if vol.Forbidden && vol.Status == bsProto.VolStatusMarkDelete {
if vol.Forbidden && vol.Status == proto.VolStatusMarkDelete {
c.delayDeleteVolsInfo = append(c.delayDeleteVolsInfo, &delayDeleteVolInfo{volName: vol.Name, authKey: vol.authKey, execTime: vol.DeleteExecTime, user: vol.user})
log.LogInfof("action[loadDelayDeleteVols],vol[%v]", vol.Name)
}
@ -1746,8 +1747,8 @@ type decommissionDiskValue struct {
Type uint32
DecommissionCompleteTime int64
DecommissionLimit int
IgnoreDecommissionDps []bsProto.IgnoreDecommissionDP
ResidualDecommissionDps []bsProto.IgnoreDecommissionDP
IgnoreDecommissionDps []proto.IgnoreDecommissionDP
ResidualDecommissionDps []proto.IgnoreDecommissionDP
DiskDisable bool
}
@ -1878,19 +1879,19 @@ func (c *Cluster) loadLcNodes() (err error) {
return
}
func (c *Cluster) syncAddLcConf(lcConf *bsProto.LcConfiguration) (err error) {
func (c *Cluster) syncAddLcConf(lcConf *proto.LcConfiguration) (err error) {
return c.syncPutLcConfInfo(opSyncAddLcConf, lcConf)
}
func (c *Cluster) syncDeleteLcConf(lcConf *bsProto.LcConfiguration) (err error) {
func (c *Cluster) syncDeleteLcConf(lcConf *proto.LcConfiguration) (err error) {
return c.syncPutLcConfInfo(opSyncDeleteLcConf, lcConf)
}
func (c *Cluster) syncUpdateLcConf(lcConf *bsProto.LcConfiguration) (err error) {
func (c *Cluster) syncUpdateLcConf(lcConf *proto.LcConfiguration) (err error) {
return c.syncPutLcConfInfo(opSyncUpdateLcConf, lcConf)
}
func (c *Cluster) syncPutLcConfInfo(opType uint32, lcConf *bsProto.LcConfiguration) (err error) {
func (c *Cluster) syncPutLcConfInfo(opType uint32, lcConf *proto.LcConfiguration) (err error) {
metadata := new(RaftCmd)
metadata.Op = opType
metadata.K = lcConfPrefix + lcConf.VolName
@ -1909,7 +1910,7 @@ func (c *Cluster) loadLcConfs() (err error) {
}
for _, value := range result {
lcConf := &bsProto.LcConfiguration{}
lcConf := &proto.LcConfiguration{}
if err = json.Unmarshal(value, lcConf); err != nil {
err = fmt.Errorf("action[loadLcConfs],value:%v,unmarshal err:%v", string(value), err)
return

View File

@ -1390,6 +1390,7 @@ type Zone struct {
QosIopsWLimit uint64
QosFlowRLimit uint64
QosFlowWLimit uint64
mediaType uint32
sync.RWMutex
}
@ -1401,9 +1402,10 @@ type zoneValue struct {
QosFlowWLimit uint64
DataNodesetSelector string
MetaNodesetSelector string
MediaType uint32
}
func newZone(name string) (zone *Zone) {
func newZone(name string, mediaType uint32) (zone *Zone) {
zone = &Zone{name: name}
zone.setStatus(normalZone)
zone.dataNodes = new(sync.Map)
@ -1411,6 +1413,7 @@ func newZone(name string) (zone *Zone) {
zone.nodeSetMap = make(map[uint64]*nodeSet)
zone.dataNodesetSelector = NewNodesetSelector(DefaultNodesetSelectorName, DataNodeType)
zone.metaNodesetSelector = NewNodesetSelector(DefaultNodesetSelectorName, MetaNodeType)
zone.SetMediaType(mediaType)
return
}
@ -1460,6 +1463,7 @@ func (zone *Zone) getFsmValue() *zoneValue {
QosFlowWLimit: zone.QosFlowWLimit,
DataNodesetSelector: zone.GetDataNodesetSelector(),
MetaNodesetSelector: zone.GetMetaNodesetSelector(),
MediaType: zone.GetMediaType(),
}
}
@ -1484,7 +1488,7 @@ func (zone *Zone) getNodeSet(setID uint64) (ns *nodeSet, err error) {
defer zone.nsLock.RUnlock()
ns, ok := zone.nodeSetMap[setID]
if !ok {
return nil, errors.NewErrorf("set %v not found", setID)
return nil, errors.NewErrorf("nodeset %v not found", setID)
}
return
}
@ -1944,6 +1948,18 @@ func (zone *Zone) startDecommissionListTraverse(c *Cluster) (err error) {
return
}
func (zone *Zone) GetMediaType() uint32 {
return atomic.LoadUint32(&zone.mediaType)
}
func (zone *Zone) GetMediaTypeString() string {
return proto.MediaTypeString(atomic.LoadUint32(&zone.mediaType))
}
func (zone *Zone) SetMediaType(newMediaType uint32) {
atomic.StoreUint32(&zone.mediaType, newMediaType)
}
type DecommissionDataPartitionList struct {
mu sync.Mutex
cacheMap map[uint64]*list.Element

View File

@ -25,7 +25,7 @@ func createDataNodeForTopo(addr, zoneName string, ns *nodeSet) (dn *DataNode) {
func TestSingleZone(t *testing.T) {
topo := newTopology()
zoneName := "test"
zone := newZone(zoneName)
zone := newZone(zoneName, proto.MediaType_Unspecified)
topo.putZone(zone)
c := new(Cluster)
nodeSet := newNodeSet(c, 1, 6, zoneName)
@ -93,7 +93,7 @@ func TestAllocZones(t *testing.T) {
// add three zones
zoneName1 := testZone1
zone1 := newZone(zoneName1)
zone1 := newZone(zoneName1, proto.MediaType_Unspecified)
nodeSet1 := newNodeSet(c, 1, 6, zoneName1)
zone1.putNodeSet(nodeSet1)
@ -102,7 +102,7 @@ func TestAllocZones(t *testing.T) {
topo.putDataNode(createDataNodeForTopo(mds2Addr, zoneName1, nodeSet1))
zoneName2 := testZone2
zone2 := newZone(zoneName2)
zone2 := newZone(zoneName2, proto.MediaType_Unspecified)
nodeSet2 := newNodeSet(c, 2, 6, zoneName2)
zone2.putNodeSet(nodeSet2)
@ -111,7 +111,7 @@ func TestAllocZones(t *testing.T) {
topo.putDataNode(createDataNodeForTopo(mds4Addr, zoneName2, nodeSet2))
zoneName3 := "zone3"
zone3 := newZone(zoneName3)
zone3 := newZone(zoneName3, proto.MediaType_Unspecified)
nodeSet3 := newNodeSet(c, 3, 6, zoneName3)
zone3.putNodeSet(nodeSet3)

View File

@ -1280,6 +1280,7 @@ type ZoneView struct {
DataNodesetSelector string
MetaNodesetSelector string
NodeSet map[uint64]*NodeSetView
MediaType string
}
type NodeSetView struct {
@ -1404,3 +1405,39 @@ func MediaTypeString(mediaType uint32) (value string) {
}
const ForbiddenMigrationRenewalPeriod = 2 * time.Minute
func IsValidMediaType(mediaType uint32) bool {
if mediaType >= MediaType_SSD && mediaType <= MediaType_HDD {
return true
}
return false
}
type StorageClass uint32
const (
StorageClass_Unspecified uint32 = 0
StorageClass_Replica_SSD uint32 = 1
StorageClass_Replica_HDD uint32 = 2
StorageClass_Blobtore uint32 = 3
//Types may be added later:
//StorageClass_S3
//StorageClass_ARCHIV
//StorageClass_HDFS
)
var storageClassStringMap = map[uint32]string{
StorageClass_Unspecified: "Unspecified",
StorageClass_Replica_SSD: "ReplicaSSD",
StorageClass_Replica_HDD: "ReplicaHDD",
}
func StorageClassStringMap(storageClass uint32) (value string) {
value, ok := storageClassStringMap[storageClass]
if !ok {
value = "InvalidValue"
}
return
}