From d7503fb7b5510f2fae32efbba5f95562371dee2e Mon Sep 17 00:00:00 2001 From: true1064 Date: Thu, 27 Jun 2024 14:32:17 +0800 Subject: [PATCH] feat(master): hybrid cloud support cross zone when creating volume Signed-off-by: true1064 --- master/api_service.go | 2 +- master/cluster.go | 5 ++--- master/cluster_test.go | 30 ++++++++++++++---------------- master/topology.go | 34 ++++++++++++++++++++++++++++------ 4 files changed, 45 insertions(+), 26 deletions(-) diff --git a/master/api_service.go b/master/api_service.go index 3df7d33c9..404d41753 100644 --- a/master/api_service.go +++ b/master/api_service.go @@ -1553,7 +1553,7 @@ func (m *Server) createDataPartition(w http.ResponseWriter, r *http.Request) { lastTotalDataPartitions = len(vol.dataPartitions.partitions) clusterTotalDataPartitions = m.cluster.getDataPartitionCount() - // TODO:tangjingyu need to support requester to specify volStorageClass? + // TODO:tangjingyu to support assign mediaType err = m.cluster.batchCreateDataPartition(vol, reqCreateCount, false, proto.GetMediaTypeByStorageClass(vol.volStorageClass)) rstMsg = fmt.Sprintf(" createDataPartition succeeeds. "+ "clusterLastTotalDataPartitions[%v],vol[%v] has %v data partitions previously and %v data partitions now", diff --git a/master/cluster.go b/master/cluster.go index 08fd032a0..5290eb635 100644 --- a/master/cluster.go +++ b/master/cluster.go @@ -2043,7 +2043,7 @@ func (c *Cluster) getSpecificZoneList(specifiedZone string) (zones []*Zone, err func (c *Cluster) getHostFromNormalZone(nodeType uint32, excludeZones []string, excludeNodeSets []uint64, excludeHosts []string, replicaNum int, zoneNumNeed int, - specifiedZoneName string, mediaType uint32) (hosts []string, peers []proto.Peer, err error, + specifiedZoneName string, dataMediaType uint32) (hosts []string, peers []proto.Peer, err error, ) { var zonesQualified []*Zone if replicaNum <= zoneNumNeed { @@ -2053,7 +2053,6 @@ func (c *Cluster) getHostFromNormalZone(nodeType uint32, excludeZones []string, var specifiedZones []*Zone var rsMgr *rsManager if specifiedZoneName != "" { - // TODO:tangjngyu mediaType if specifiedZones, err = c.getSpecificZoneList(specifiedZoneName); err != nil { return } @@ -2065,7 +2064,7 @@ func (c *Cluster) getHostFromNormalZone(nodeType uint32, excludeZones []string, } // get all zones that qualified - if zonesQualified, err = c.t.allocZonesForNode(rsMgr, zoneNumNeed, replicaNum, excludeZones, specifiedZones, mediaType); err != nil { + if zonesQualified, err = c.t.allocZonesForNode(rsMgr, zoneNumNeed, replicaNum, excludeZones, specifiedZones, dataMediaType); err != nil { return } diff --git a/master/cluster_test.go b/master/cluster_test.go index a2e7183ba..09f6f203c 100644 --- a/master/cluster_test.go +++ b/master/cluster_test.go @@ -389,23 +389,21 @@ func TestCreateVolWithDpCount(t *testing.T) { t.Run("dpCount != default count", func(t *testing.T) { req := &createVolReq{ - name: commonVolName + "001", - owner: "cfs", - dpSize: 11, - mpCount: 30, - dpCount: 30, - dpReplicaNum: 3, - capacity: 100, - followerRead: false, - authenticate: false, - // crossZone: true, //TODO: tangjingyu: hybrid cloud support crossZone - crossZone: false, + name: commonVolName + "001", + owner: "cfs", + dpSize: 11, + mpCount: 30, + dpCount: 30, + dpReplicaNum: 3, + capacity: 100, + followerRead: false, + authenticate: false, + crossZone: true, normalZonesFirst: false, - // zoneName: testZone1 + "," + testZone2, //TODO: tangjingyu: hybrid cloud support crossZone - zoneName: testZone2, - description: "", - qosLimitArgs: &qosArgs{}, - volStorageClass: defaultVolStorageClass, + zoneName: testZone1 + "," + testZone2, + description: "", + qosLimitArgs: &qosArgs{}, + volStorageClass: defaultVolStorageClass, } // auto set allowedStorageClass[] in createVolReq diff --git a/master/topology.go b/master/topology.go index ca560bf31..643756fe1 100644 --- a/master/topology.go +++ b/master/topology.go @@ -1379,6 +1379,24 @@ func calculateDemandWriteNodes(zoneNum int, replicaNum int, isSpecialZoneName bo return } +func (t *topology) pickUpZonesByMediaType(zones []*Zone, dataMediaType uint32) (zonesOfMediaType []*Zone) { + if dataMediaType == proto.MediaType_Unspecified { + log.LogDebugf("[pickUpZonesByMediaType] not require dataMediaType, zoneLen(%v)", len(zones)) + zonesOfMediaType = zones + return + } + + zonesOfMediaType = make([]*Zone, 0) + for _, zone := range zones { + if zone.dataMediaType == dataMediaType { + log.LogDebugf("[pickUpZonesByMediaType] pick up zone(%v), dataMediaType(%v)", zone.name, dataMediaType) + zonesOfMediaType = append(zonesOfMediaType, zone) + } + } + + return zonesOfMediaType +} + // Choose the zone if it is writable and adapt to the rules for classifying zones func (t *topology) allocZonesForNode(rsMgr *rsManager, zoneNumNeed, replicaNum int, excludeZone []string, specialZones []*Zone, dataMediaType uint32) (zones []*Zone, err error) { @@ -1389,8 +1407,7 @@ func (t *topology) allocZonesForNode(rsMgr *rsManager, zoneNumNeed, replicaNum i zones = t.getDomainExcludeZones() log.LogInfof("action[allocZonesForNode] getDomainExcludeZones zones [%v]", t.domainExcludeZones) } else if specialZones != nil && len(specialZones) > 0 { - // TODO:tangjingyu: mediaType - zones = specialZones + zones = t.pickUpZonesByMediaType(specialZones, dataMediaType) zoneNumNeed = len(specialZones) } else { // if domain enable, will not enter here @@ -1421,9 +1438,15 @@ func (t *topology) allocZonesForNode(rsMgr *rsManager, zoneNumNeed, replicaNum i // if across zone,candidateZones must be larger than or equal with 2,otherwise,must have a candidate zone if (zoneNumNeed >= 2 && len(candidateZones) < 2) || len(candidateZones) < 1 { - log.LogError(fmt.Sprintf("action[allocZonesForNode],reqZoneNum[%v],candidateZones[%v],demandWriteNodes[%v],err:%v", - zoneNumNeed, len(candidateZones), demandWriteNodesCntPerZone, proto.ErrNoZoneToCreateMetaPartition)) - return nil, proto.ErrNoZoneToCreateMetaPartition + if rsMgr.nodeType == DataNodeType { + err = proto.ErrNoZoneToCreateDataPartition + } else { + err = proto.ErrNoZoneToCreateMetaPartition + } + + log.LogErrorf("action[allocZonesForNode],reqZoneNum[%v],candidateZones[%v],demandWriteNodes[%v],err:%v", + zoneNumNeed, len(candidateZones), demandWriteNodesCntPerZone, err.Error()) + return nil, err } zones = candidateZones err = nil @@ -1854,7 +1877,6 @@ func (zone *Zone) getDataNodeMaxTotal() (maxTotal uint64) { return } -// TODO:tangjingyu mediaType func (zone *Zone) getAvailNodeHosts(nodeType uint32, excludeNodeSets []uint64, excludeHosts []string, replicaNum int) (newHosts []string, peers []proto.Peer, err error) { if replicaNum == 0 { return