cubefs/master/api_service_balance.go
Victor1319 070b82370d style(api): improve code comments for clarity and consistency. #3942
- Add spaces after comment slashes for better readability
- Standardize comment formatting across multiple files
- Enhance clarity of comments in data partition handling

Signed-off-by: Victor1319 <zengxuewei@oppo.com>
2025-11-11 20:23:43 +08:00

730 lines
22 KiB
Go

// Copyright 2025 The CubeFS Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied. See the License for the specific language governing
// permissions and limitations under the License.
package master
import (
"fmt"
"net/http"
"strconv"
"github.com/cubefs/cubefs/proto"
"github.com/cubefs/cubefs/util"
"github.com/cubefs/cubefs/util/exporter"
"github.com/cubefs/cubefs/util/log"
)
type MetaReplicaInfo struct {
MaxInodeID uint64 `json:"MaxInodeID"`
InodeCount uint64 `json:"InodeCount"`
DentryCount uint64 `json:"DentryCount"`
FreeListLen uint64 `json:"FreeListLen"`
TxCnt uint64 `json:"TxCnt"`
TxRbInoCnt uint64 `json:"TxRbInoCnt"`
TxRbDenCnt uint64 `json:"TxRbDenCnt"`
}
type MigrateResult struct {
Mp MetaReplicaInfo `json:"mp"`
Target MetaReplicaInfo `json:"target"`
}
func (m *Server) getMetaPartitionEmptyStatus(w http.ResponseWriter, r *http.Request) {
metric := exporter.NewTPCnt(apiToMetricsName(proto.AdminMetaPartitionEmptyStatus))
defer func() {
doStatAndMetric(proto.AdminMetaPartitionEmptyStatus, metric, nil, nil)
}()
mpsStatus := make([]proto.VolEmptyMpStats, 0, len(m.cluster.vols))
for _, name := range m.cluster.allVolNames() {
vol, err := m.cluster.getVol(name)
if err != nil {
log.LogErrorf("[getMetaPartitionEmptyStatus] getVol(%s) failed: %s", name, err.Error())
continue
}
// skip the deleted volume.
if vol.Status == proto.VolStatusMarkDelete {
continue
}
volStatus := proto.VolEmptyMpStats{
Name: name,
}
volStatus.MetaPartitions = make([]*proto.MetaPartitionView, 0, len(vol.MetaPartitions))
volStatus.Total = len(vol.MetaPartitions)
mps := vol.getSortMetaPartitions()
for _, mp := range mps {
if mp.IsMetaPartitionFreezed() || mp.IsEmptyToBeClean() {
volStatus.EmptyCount++
volStatus.MetaPartitions = append(volStatus.MetaPartitions, getMetaPartitionView(mp))
}
}
if volStatus.EmptyCount > RsvEmptyMetaPartitionCnt {
mpsStatus = append(mpsStatus, volStatus)
}
}
sendOkReply(w, r, newSuccessHTTPReply(mpsStatus))
}
func (m *Server) freezeEmptyMetaPartition(w http.ResponseWriter, r *http.Request) {
metric := exporter.NewTPCnt(apiToMetricsName(proto.AdminMetaPartitionFreezeEmpty))
defer func() {
doStatAndMetric(proto.AdminMetaPartitionFreezeEmpty, metric, nil, nil)
}()
var (
name string
count int
err error
)
name, count, err = parseFreeEmptyMetaPartitionParam(r)
if err != nil {
sendErrReply(w, r, &proto.HTTPReply{Code: proto.ErrCodeParamError, Msg: err.Error()})
return
}
vol, err := m.cluster.getVol(name)
if err != nil {
sendErrReply(w, r, &proto.HTTPReply{Code: proto.ErrCodeParamError, Msg: err.Error()})
return
}
if vol.Status == proto.VolStatusMarkDelete {
sendOkReply(w, r, newSuccessHTTPReply(fmt.Sprintf("volume (%s) is deleted already.", name)))
return
}
mps := vol.getSortMetaPartitions()
total := 0
for _, mp := range mps {
if mp.IsEmptyToBeClean() {
total++
}
}
cleans := total - count
if cleans <= 0 {
sendErrReply(w, r, &proto.HTTPReply{Code: proto.ErrCodeParamError, Msg: "reserve mp number is larger than or equal empty number"})
return
}
freezeList := m.SetMetaPartitionFrozen(mps, cleans)
err = m.cluster.FreezeEmptyMetaPartitionJob(name, freezeList)
rstMsg := fmt.Sprintf("Freeze empty volume(%s) meta partitions(%d)", name, cleans)
AuditLog(r, "freezeEmptyMetaPartition", rstMsg, err)
if err != nil {
sendErrReply(w, r, &proto.HTTPReply{Code: proto.ErrCodeInternalError, Msg: err.Error()})
return
}
sendOkReply(w, r, newSuccessHTTPReply(fmt.Sprintf("Master will freeze empty meta partition of volume (%s) after 10 minutes. Task id: %s", name, name)))
}
func parseFreeEmptyMetaPartitionParam(r *http.Request) (name string, count int, err error) {
if err = r.ParseForm(); err != nil {
return
}
if name, err = extractName(r); err != nil {
return
}
if count, err = extractUint(r, countKey); err != nil {
return
}
if count < RsvEmptyMetaPartitionCnt {
// reserve 2 empty mp at least, not include the last one.
count = RsvEmptyMetaPartitionCnt
}
return
}
func (m *Server) SetMetaPartitionFrozen(mps []*MetaPartition, cleans int) []*MetaPartition {
freezeList := make([]*MetaPartition, 0, cleans)
i := 0
for _, mp := range mps {
if !mp.IsEmptyToBeClean() {
continue
}
mp.Freeze = proto.FreezingMetaPartition
if mp.Status == proto.ReadWrite {
mp.Status = proto.ReadOnly
}
// store the meta partition status.
err := m.cluster.syncUpdateMetaPartition(mp)
if err != nil {
log.LogErrorf("volume(%s) meta partition(%d) update failed: %s", mp.volName, mp.PartitionID, err.Error())
continue
}
freezeList = append(freezeList, mp)
i++
if i >= cleans {
break
}
}
return freezeList
}
func (m *Server) cleanEmptyMetaPartition(w http.ResponseWriter, r *http.Request) {
metric := exporter.NewTPCnt(apiToMetricsName(proto.AdminMetaPartitionCleanEmpty))
defer func() {
doStatAndMetric(proto.AdminMetaPartitionCleanEmpty, metric, nil, nil)
}()
var (
name string
err error
)
if err = r.ParseForm(); err != nil {
sendErrReply(w, r, &proto.HTTPReply{Code: proto.ErrCodeParamError, Msg: err.Error()})
return
}
if name, err = extractName(r); err != nil {
sendErrReply(w, r, &proto.HTTPReply{Code: proto.ErrCodeParamError, Msg: err.Error()})
return
}
vol, err := m.cluster.getVol(name)
if err != nil {
sendErrReply(w, r, &proto.HTTPReply{Code: proto.ErrCodeParamError, Msg: err.Error()})
return
}
if vol.Status == proto.VolStatusMarkDelete {
sendOkReply(w, r, newSuccessHTTPReply(fmt.Sprintf("volume (%s) is deleted already.", name)))
return
}
err = m.cluster.StartCleanEmptyMetaPartition(name)
rstMsg := fmt.Sprintf("Clean volume(%s) empty meta partitions", name)
AuditLog(r, "cleanEmptyMetaPartition", rstMsg, err)
if err != nil {
sendErrReply(w, r, &proto.HTTPReply{Code: proto.ErrCodeInternalError, Msg: err.Error()})
return
}
sendOkReply(w, r, newSuccessHTTPReply(fmt.Sprintf("Clean frozen meta partition for volume (%s) in the background. It may takes several hours. task id: %s", name, name)))
}
func (m *Server) removeBackupMetaPartition(w http.ResponseWriter, r *http.Request) {
metric := exporter.NewTPCnt(apiToMetricsName(proto.AdminMetaPartitionRemoveBackup))
defer func() {
doStatAndMetric(proto.AdminMetaPartitionRemoveBackup, metric, nil, nil)
}()
m.cluster.metaNodes.Range(func(key, value interface{}) bool {
metanode, ok := value.(*MetaNode)
if !ok {
return true
}
task := proto.NewAdminTask(proto.OpRemoveBackupMetaPartition, metanode.Addr, nil)
_, err := metanode.Sender.syncSendAdminTask(task)
if err != nil {
log.LogErrorf("failed to remove empty meta partition")
}
return true
})
AuditLog(r, "removeBackupMetaPartition", "clean all backup meta partitions", nil)
sendOkReply(w, r, newSuccessHTTPReply("Remove all backup meta partitions successfully."))
}
func (m *Server) getCleanMetaPartitionTask(w http.ResponseWriter, r *http.Request) {
metric := exporter.NewTPCnt(apiToMetricsName(proto.AdminMetaPartitionGetCleanTask))
defer func() {
doStatAndMetric(proto.AdminMetaPartitionGetCleanTask, metric, nil, nil)
}()
var (
name string
err error
)
if err = r.ParseForm(); err != nil {
sendErrReply(w, r, &proto.HTTPReply{Code: proto.ErrCodeParamError, Msg: err.Error()})
return
}
name = r.FormValue(nameKey)
m.cluster.mu.Lock()
defer m.cluster.mu.Unlock()
taskList := make([]*CleanTask, 0, len(m.cluster.cleanTask))
if name == "" {
for key, val := range m.cluster.cleanTask {
task, err := m.cluster.CalculateMetaPartitionFreezeCount(key)
if err != nil {
log.LogWarnf("CalculateMetaPartitionFreezeCount volume(%s) err: %s", key, err.Error())
continue
}
task.Status = val.Status
taskList = append(taskList, task)
}
} else {
val, ok := m.cluster.cleanTask[name]
if !ok {
sendErrReply(w, r, &proto.HTTPReply{Code: proto.ErrCodeParamError, Msg: fmt.Sprintf("Can't find task for volume(%s)", name)})
return
}
task, err := m.cluster.CalculateMetaPartitionFreezeCount(name)
if err != nil {
sendErrReply(w, r, &proto.HTTPReply{Code: proto.ErrCodeInternalError, Msg: err.Error()})
return
}
task.Status = val.Status
taskList = append(taskList, task)
}
sendOkReply(w, r, newSuccessHTTPReply(taskList))
}
func parseMigratePartitionParam(r *http.Request) (srcAddr, targetAddr string, id uint64, err error) {
if err = r.ParseForm(); err != nil {
return
}
srcAddr = r.FormValue(srcAddrKey)
if srcAddr == "" {
err = fmt.Errorf("parseMigratePartitionParam source address is empty")
return
}
if ipAddr, ok := util.ParseAddrToIpAddr(srcAddr); ok {
srcAddr = ipAddr
}
targetAddr = r.FormValue(targetAddrKey)
if targetAddr == "" {
err = fmt.Errorf("parseMigratePartitionParam target address is empty")
return
}
if ipAddr, ok := util.ParseAddrToIpAddr(targetAddr); ok {
targetAddr = ipAddr
}
if srcAddr == targetAddr {
err = fmt.Errorf("parseMigratePartitionParam srcAddr %s can't be equal to targetAddr %s", srcAddr, targetAddr)
return
}
value := r.FormValue(idKey)
if value == "" {
err = fmt.Errorf("parseMigratePartitionParam meta partition id is needed")
return
}
if id, err = strconv.ParseUint(value, 10, 64); err != nil {
return
}
return
}
func (m *Server) migrateMetaPartitionHandler(w http.ResponseWriter, r *http.Request) {
var (
srcAddr string
targetAddr string
mpid uint64
err error
mp *MetaPartition
)
metric := exporter.NewTPCnt(apiToMetricsName(proto.MigrateMetaPartition))
defer func() {
doStatAndMetric(proto.MigrateMetaPartition, metric, err, nil)
}()
srcAddr, targetAddr, mpid, err = parseMigratePartitionParam(r)
if err != nil {
sendErrReply(w, r, newErrHTTPReply(err))
return
}
targetNode, err := m.cluster.metaNode(targetAddr)
if err != nil {
sendErrReply(w, r, &proto.HTTPReply{Code: proto.ErrCodeMetaNodeNotExists, Msg: err.Error()})
return
}
if !targetNode.IsWriteAble() || !targetNode.PartitionCntLimited() {
err = fmt.Errorf("[%s] is not writable, can't used as target addr for migrate", targetAddr)
sendErrReply(w, r, newErrHTTPReply(err))
return
}
mp, err = m.cluster.getMetaPartitionByID(mpid)
if err != nil {
err = fmt.Errorf("Failed to get meta partition (%d)", mpid)
sendErrReply(w, r, newErrHTTPReply(err))
return
}
if err = m.cluster.migrateMetaPartition(srcAddr, targetAddr, mp); err != nil {
sendErrReply(w, r, newErrHTTPReply(err))
return
}
rstMsg := fmt.Sprintf("migrateMetaPartitionHandler id(%d) from src [%s] to target[%s] has migrate successfully", mpid, srcAddr, targetAddr)
AuditLog(r, "MigrateMetaPartition", rstMsg, nil)
sendOkReply(w, r, newSuccessHTTPReply(rstMsg))
}
func (m *Server) createMetaNodeBalancePlan(w http.ResponseWriter, r *http.Request) {
var err error
metric := exporter.NewTPCnt(apiToMetricsName(proto.CreateMetaNodeBalanceTask))
defer func() {
doStatAndMetric(proto.CreateMetaNodeBalanceTask, metric, err, nil)
}()
var plan *proto.ClusterPlan
// search the raft storage. Only store one plan
plan, err = m.cluster.loadBalanceTask()
if err == nil && plan != nil {
err = fmt.Errorf("There is a meta partition task plan already. Please remove it before create a new one.")
sendErrReply(w, r, &proto.HTTPReply{Code: proto.ErrCodeInternalError, Msg: err.Error(), Data: plan})
return
}
plan, err = m.cluster.GetMetaNodePressureView()
if err != nil {
sendErrReply(w, r, &proto.HTTPReply{Code: proto.ErrCodeInternalError, Msg: err.Error(), Data: plan})
return
}
if plan.Total <= 0 {
sendErrReply(w, r, &proto.HTTPReply{Code: proto.ErrCodeInternalError, Msg: "Not find meta node that needs partition rebalance.", Data: nil})
return
}
plan.Type = ManualPlan
// Save into raft storage.
err = m.cluster.syncAddBalanceTask(plan)
if err != nil {
sendErrReply(w, r, &proto.HTTPReply{Code: proto.ErrCodeInternalError, Msg: err.Error(), Data: plan})
return
}
AuditLog(r, "createBalancePlan", "create meta partition balance task", nil)
sendOkReply(w, r, newSuccessHTTPReply(plan))
}
func (m *Server) getMetaNodeBalancePlan(w http.ResponseWriter, r *http.Request) {
var err error
metric := exporter.NewTPCnt(apiToMetricsName(proto.GetMetaNodeBalanceTask))
defer func() {
doStatAndMetric(proto.GetMetaNodeBalanceTask, metric, err, nil)
}()
var plan *proto.ClusterPlan
plan, err = m.cluster.loadBalanceTask()
if err != nil {
sendErrReply(w, r, &proto.HTTPReply{Code: proto.ErrCodeInternalError, Msg: err.Error(), Data: plan})
return
}
if plan == nil || plan.Total <= 0 {
sendErrReply(w, r, &proto.HTTPReply{Code: proto.ErrCodeInternalError, Msg: "Meta partition migrate plan doesn't existed."})
return
}
sendOkReply(w, r, newSuccessHTTPReply(plan))
}
func (m *Server) runMetaNodeBalancePlan(w http.ResponseWriter, r *http.Request) {
var err error
metric := exporter.NewTPCnt(apiToMetricsName(proto.RunMetaNodeBalanceTask))
defer func() {
doStatAndMetric(proto.RunMetaNodeBalanceTask, metric, err, nil)
}()
err = m.cluster.RunMetaPartitionBalanceTask()
if err != nil {
sendErrReply(w, r, &proto.HTTPReply{Code: proto.ErrCodeInternalError, Msg: err.Error()})
return
}
AuditLog(r, "runBalancePlan", "start to run meta partition balance task", nil)
sendOkReply(w, r, newSuccessHTTPReply("Start running balance task successfully."))
}
func (m *Server) stopMetaNodeBalancePlan(w http.ResponseWriter, r *http.Request) {
var err error
metric := exporter.NewTPCnt(apiToMetricsName(proto.StopMetaNodeBalanceTask))
defer func() {
doStatAndMetric(proto.StopMetaNodeBalanceTask, metric, err, nil)
}()
err = m.cluster.StopMetaPartitionBalanceTask()
if err != nil {
sendErrReply(w, r, &proto.HTTPReply{Code: proto.ErrCodeInternalError, Msg: err.Error()})
return
}
AuditLog(r, "stopBalancePlan", "stop meta partition balance task", nil)
sendOkReply(w, r, newSuccessHTTPReply("Stop balance task successfully."))
}
func (m *Server) deleteMetaNodeBalancePlan(w http.ResponseWriter, r *http.Request) {
var err error
metric := exporter.NewTPCnt(apiToMetricsName(proto.DeleteMetaNodeBalanceTask))
defer func() {
doStatAndMetric(proto.DeleteMetaNodeBalanceTask, metric, err, nil)
}()
err = m.cluster.DeleteMetaPartitionBalanceTask()
if err != nil {
sendErrReply(w, r, &proto.HTTPReply{Code: proto.ErrCodeInternalError, Msg: err.Error()})
return
}
AuditLog(r, "deleteBalancePlan", "Remove meta partition balance task", nil)
sendOkReply(w, r, newSuccessHTTPReply("Delete balance plan task successfully."))
}
func (m *Server) offlineMetaNode(w http.ResponseWriter, r *http.Request) {
var (
rstMsg string
offLineAddr string
err error
plan *proto.ClusterPlan
metaNode *MetaNode
)
metric := exporter.NewTPCnt(apiToMetricsName(proto.OfflineMetaNode))
defer func() {
doStatAndMetric(proto.OfflineMetaNode, metric, err, nil)
AuditLog(r, proto.OfflineMetaNode, rstMsg, err)
}()
if offLineAddr, err = parseAndExtractNodeAddr(r); err != nil {
log.LogErrorf("parse node addr failed, err: %v", err)
sendErrReply(w, r, newErrHTTPReply(proto.ErrParamError))
return
}
if metaNode, err = m.cluster.metaNode(offLineAddr); err != nil {
log.LogWarnf("metanode(%s) is not exist", offLineAddr)
sendErrReply(w, r, newErrHTTPReply(proto.ErrMetaNodeNotExists))
return
}
oldRdOnly := metaNode.RdOnly
if !oldRdOnly {
metaNode.RdOnly = true
if err = m.cluster.syncUpdateMetaNode(metaNode); err != nil {
metaNode.RdOnly = oldRdOnly
log.LogErrorf("syncUpdateMetaNode(%s) err: %s", offLineAddr, err.Error())
sendErrReply(w, r, newErrHTTPReply(proto.ErrInternalError))
return
}
}
count := m.cluster.GetMpCountByMetaNode(metaNode.Addr)
if count == 0 {
err = m.cluster.DoMetaNodeOffline(offLineAddr)
if err != nil {
log.LogErrorf("DoMetaNodeOffline(%s) err: %s", offLineAddr, err.Error())
sendErrReply(w, r, newErrHTTPReply(proto.ErrInternalError))
return
}
rstMsg = fmt.Sprintf("Offline metanode %s successfully", offLineAddr)
sendOkReply(w, r, newSuccessHTTPReply(rstMsg))
return
}
// search the raft storage. Only store one plan
plan, err = m.cluster.loadBalanceTask()
if err == nil {
if plan.Status == PlanTaskDone {
// remove the done task.
log.LogWarnf("remove the plan task(%v) before kick out(%s)", plan, offLineAddr)
err = m.cluster.DeleteMetaPartitionBalanceTask()
if err != nil {
log.LogErrorf("failed to delete meta partition balance task: %s", err.Error())
sendErrReply(w, r, &proto.HTTPReply{Code: proto.ErrCodeInternalError, Msg: err.Error()})
return
}
} else {
log.LogWarnf("one balance task exist. clear it before kick out(%s)", offLineAddr)
err = fmt.Errorf("There is a meta partition task plan. Clear it before kick out new metanode")
sendErrReply(w, r, &proto.HTTPReply{Code: proto.ErrCodeInternalError, Msg: err.Error(), Data: plan})
return
}
} else if err != proto.ErrNoMpMigratePlan {
log.LogErrorf("Failed to load balance task err: %s", err.Error())
sendErrReply(w, r, newErrHTTPReply(err))
return
}
if plan, err = m.cluster.CreateOfflineMetaNodePlan(offLineAddr); err != nil {
log.LogErrorf(err.Error())
sendErrReply(w, r, newErrHTTPReply(err))
return
}
if plan.Total <= 0 {
err = fmt.Errorf("kick out plan is empty for metanode(%s)", offLineAddr)
log.LogErrorf(err.Error())
sendErrReply(w, r, newErrHTTPReply(err))
return
}
plan.Type = OfflinePlan
plan.Status = PlanTaskRun
// Save into raft storage.
err = m.cluster.syncAddBalanceTask(plan)
if err != nil {
log.LogErrorf("syncAddBalanceTask metanode(%s) err: %s", offLineAddr, err.Error())
sendErrReply(w, r, newErrHTTPReply(err))
return
}
rstMsg = fmt.Sprintf("Offline metanode %s at background successfully", offLineAddr)
sendOkReply(w, r, newSuccessHTTPReply(rstMsg))
}
// func parseNodeBalanceInfoParams(r *http.Request) (params map[string]interface{}, err error) {
// if err = r.ParseForm(); err != nil {
// return
// }
// var value string
// noParams := true
// if value = r.FormValue(dataNodeBalanceByDiskUsageHighKey); value != "" {
// noParams = false
// var val float64
// val, err = strconv.ParseFloat(value, 64)
// if err != nil {
// err = unmatchedKey(dataNodeBalanceByDiskUsageHighKey)
// return
// }
// params[dataNodeBalanceByDiskUsageHighKey] = val
// }
// if value = r.FormValue(dataNodeBalanceByDiskUsageLowKey); value != "" {
// noParams = false
// var val float64
// val, err = strconv.ParseFloat(value, 64)
// if err != nil {
// err = unmatchedKey(dataNodeBalanceByDiskUsageLowKey)
// return
// }
// params[dataNodeBalanceByDiskUsageLowKey] = val
// }
// if value = r.FormValue(dataNodeBalanceByDPCountHighKey); value != "" {
// noParams = false
// var val int64
// val, err = strconv.ParseInt(value, 10, 32)
// if err != nil {
// err = unmatchedKey(dataNodeBalanceByDPCountHighKey)
// return
// }
// params[dataNodeBalanceByDPCountHighKey] = val
// }
// if value = r.FormValue(dataNodeBalanceByDPCountLowKey); value != "" {
// noParams = false
// var val int64
// val, err = strconv.ParseInt(value, 10, 32)
// if err != nil {
// err = unmatchedKey(dataNodeBalanceByDPCountLowKey)
// return
// }
// params[dataNodeBalanceByDPCountLowKey] = val
// }
// if noParams {
// err = fmt.Errorf("no key assigned")
// return
// }
// return
// }
// func (m *Server) setDataNodeBalanceInfoHandler(w http.ResponseWriter, r *http.Request) {
// var (
// params map[string]interface{}
// err error
// val interface{}
// keyExists bool
// newDataNodeBalanceByDiskUsageLow float64
// newDataNodeBalanceByDiskUsageHigh float64
// newDataNodeBalanceByDPCountLow uint32
// newDataNodeBalanceByDPCountHigh uint32
// )
// metric := exporter.NewTPCnt(apiToMetricsName(proto.SetDataNodeBalanceInfo))
// defer func() {
// doStatAndMetric(proto.SetDataNodeBalanceInfo, metric, err, nil)
// AuditLog(r, proto.SetDataNodeBalanceInfo, fmt.Sprintf("params: %v", params), err)
// }()
// if params, err = parseNodeBalanceInfoParams(r); err != nil {
// return
// }
// if val, keyExists = params[dataNodeBalanceByDiskUsageLowKey]; keyExists {
// if v, keyExists := val.(float64); keyExists {
// newDataNodeBalanceByDiskUsageLow = v
// }
// }
// if val, keyExists = params[dataNodeBalanceByDiskUsageHighKey]; keyExists {
// if v, keyExists := val.(float64); keyExists {
// newDataNodeBalanceByDiskUsageHigh = v
// }
// }
// if val, keyExists = params[dataNodeBalanceByDPCountLowKey]; keyExists {
// if v, keyExists := val.(uint32); keyExists {
// newDataNodeBalanceByDPCountLow = v
// }
// }
// if val, keyExists = params[dataNodeBalanceByDPCountHighKey]; keyExists {
// if v, keyExists := val.(uint32); keyExists {
// newDataNodeBalanceByDPCountHigh = v
// }
// }
// // check parameters
// if newDataNodeBalanceByDiskUsageHigh <= newDataNodeBalanceByDiskUsageLow {
// err = fmt.Errorf("DataNodeBalanceByDiskUsageHigh is lower than DataNodeBalanceByDiskUsageHigh")
// sendErrReply(w, r, newErrHTTPReply(err))
// return
// }
// if newDataNodeBalanceByDPCountHigh <= newDataNodeBalanceByDPCountLow {
// err = fmt.Errorf("DataNodeBalanceByDPCountHigh is lower than DataNodeBalanceByDiskUsageLow")
// sendErrReply(w, r, newErrHTTPReply(err))
// return
// }
// // set the parameters
// m.cluster.cfg.DataNodeBalanceByDiskUsageLow = newDataNodeBalanceByDiskUsageLow
// m.cluster.cfg.DataNodeBalanceByDiskUsageHigh = newDataNodeBalanceByDiskUsageHigh
// m.cluster.cfg.DataNodeBalanceByDPCountLow = newDataNodeBalanceByDPCountLow
// m.cluster.cfg.DataNodeBalanceByDPCountHigh = newDataNodeBalanceByDPCountHigh
// }