1
// Copyright 2018 The CubeFS Authors.
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
7
// http://www.apache.org/licenses/LICENSE-2.0
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
12
// implied. See the License for the specific language governing
13
// permissions and limitations under the License.
24
"github.com/cubefs/cubefs/util/log"
28
KFasterRandomSelectorName = "kfaster"
32
_ = RegisterDataPartitionSelector(KFasterRandomSelectorName, newKFasterRandomSelector)
35
func newKFasterRandomSelector(selectorParam string) (selector DataPartitionSelector, e error) {
36
param, err := strconv.Atoi(selectorParam)
38
return nil, fmt.Errorf("KFasterRandomSelector: get param failed[%v]", err)
41
if (param <= 0) || (param >= 100) {
42
return nil, fmt.Errorf("KFasterRandomSelector: invalid param[%v]", param)
45
selector = &KFasterRandomSelector{
47
partitions: make([]*DataPartition, 0),
49
log.LogInfof("KFasterRandomSelector: init selector success, kValueHundred is %v", param)
53
type KFasterRandomSelector struct {
57
partitions []*DataPartition
60
func (s *KFasterRandomSelector) Name() string {
61
return KFasterRandomSelectorName
64
func (s *KFasterRandomSelector) Refresh(partitions []*DataPartition) (err error) {
65
kValue := (len(partitions)-1)*s.kValueHundred/100 + 1
66
selectKminDataPartition(partitions, kValue)
72
s.partitions = partitions
76
func (s *KFasterRandomSelector) Select(exclude map[string]struct{}) (dp *DataPartition, err error) {
78
partitions := s.partitions
82
if len(partitions) == 0 {
83
log.LogError("KFasterRandomSelector: no writable data partition with empty partitions")
84
return nil, fmt.Errorf("no writable data partition")
87
// select random dataPartition from fasterRwPartitions
88
rand.Seed(time.Now().UnixNano())
89
index := rand.Intn(kValue)
90
dp = partitions[index]
91
if !isExcluded(dp, exclude) {
92
log.LogDebugf("KFasterRandomSelector: select faster dp[%v], index %v, kValue(%v/%v)",
93
dp, index, kValue, len(partitions))
97
log.LogWarnf("KFasterRandomSelector: first random fasterRwPartition was excluded, get partition from other faster")
99
// if partitions[index] is excluded, select next in fasterRwPartitions
100
for i := 1; i < kValue; i++ {
101
dp = partitions[(index+i)%kValue]
102
if !isExcluded(dp, exclude) {
103
log.LogDebugf("KFasterRandomSelector: select faster dp[%v], index %v, kValue(%v/%v)",
104
dp, (index+i)%kValue, kValue, len(partitions))
109
log.LogWarnf("KFasterRandomSelector: all fasterRwPartitions were excluded, get partition from slower")
111
// if all fasterRwPartitions are excluded, select random dataPartition in slowerRwPartitions
112
slowerRwPartitionsNum := len(partitions) - kValue
113
for i := 0; i < slowerRwPartitionsNum; i++ {
114
dp = partitions[(index+i)%slowerRwPartitionsNum+kValue]
115
if !isExcluded(dp, exclude) {
116
log.LogDebugf("KFasterRandomSelector: select slower dp[%v], index %v, kValue(%v/%v)",
117
dp, (index+i)%slowerRwPartitionsNum+kValue, kValue, len(partitions))
121
log.LogErrorf("KFasterRandomSelector: no writable data partition with %v partitions and exclude(%v)",
122
len(partitions), exclude)
123
return nil, fmt.Errorf("no writable data partition")
126
func (s *KFasterRandomSelector) RemoveDP(partitionID uint64) {
128
partitions := s.partitions
132
for i = 0; i < len(partitions); i++ {
133
if partitions[i].PartitionID == partitionID {
137
if i >= len(partitions) {
140
newRwPartition := make([]*DataPartition, 0)
141
newRwPartition = append(newRwPartition, partitions[:i]...)
142
newRwPartition = append(newRwPartition, partitions[i+1:]...)
144
s.Refresh(newRwPartition)
149
func (s *KFasterRandomSelector) Count() int {
152
return len(s.partitions)
155
func swap(s []*DataPartition, i int, j int) {
156
s[i], s[j] = s[j], s[i]
159
func partByPrivot(partitions []*DataPartition, low, high int) int {
162
for i = low + 1; i < high; i++ {
163
if partitions[i].GetAvgWrite() > partitions[low].GetAvgWrite() {
167
for j = high; j > low; j-- {
168
if partitions[j].GetAvgWrite() <= partitions[low].GetAvgWrite() {
175
swap(partitions, i, j)
178
swap(partitions, low, j)
183
func selectKminDataPartition(partitions []*DataPartition, k int) int {
184
if len(partitions) <= 1 {
187
low, high := 0, len(partitions)-1
189
privot := partByPrivot(partitions, low, high)
192
} else if privot > k {