use constants
This commit is contained in:
@@ -24,10 +24,23 @@ import (
|
||||
const (
|
||||
defaultBalanceTimeoutSeconds = int32(10 * 60)
|
||||
maxProposalStringLength = 200
|
||||
)
|
||||
|
||||
// Collection filter mode constants.
|
||||
collectionFilterAll = "ALL_COLLECTIONS"
|
||||
collectionFilterEach = "EACH_COLLECTION"
|
||||
// collectionFilterMode controls how collections are handled during balance detection.
|
||||
type collectionFilterMode string
|
||||
|
||||
const (
|
||||
collectionFilterAll collectionFilterMode = "ALL_COLLECTIONS"
|
||||
collectionFilterEach collectionFilterMode = "EACH_COLLECTION"
|
||||
)
|
||||
|
||||
// volumeState controls which volumes participate in balance detection.
|
||||
type volumeState string
|
||||
|
||||
const (
|
||||
volumeStateAll volumeState = "ALL"
|
||||
volumeStateActive volumeState = "ACTIVE"
|
||||
volumeStateFull volumeState = "FULL"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@@ -102,9 +115,9 @@ func (h *VolumeBalanceHandler) Descriptor() *plugin_pb.JobTypeDescriptor {
|
||||
FieldType: plugin_pb.ConfigFieldType_CONFIG_FIELD_TYPE_ENUM,
|
||||
Widget: plugin_pb.ConfigWidget_CONFIG_WIDGET_SELECT,
|
||||
Options: []*plugin_pb.ConfigOption{
|
||||
{Value: "ALL", Label: "All Volumes"},
|
||||
{Value: "ACTIVE", Label: "Active (writable)"},
|
||||
{Value: "FULL", Label: "Full (read-only)"},
|
||||
{Value: string(volumeStateAll), Label: "All Volumes"},
|
||||
{Value: string(volumeStateActive), Label: "Active (writable)"},
|
||||
{Value: string(volumeStateFull), Label: "Full (read-only)"},
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -139,7 +152,7 @@ func (h *VolumeBalanceHandler) Descriptor() *plugin_pb.JobTypeDescriptor {
|
||||
Kind: &plugin_pb.ConfigValue_StringValue{StringValue: ""},
|
||||
},
|
||||
"volume_state": {
|
||||
Kind: &plugin_pb.ConfigValue_StringValue{StringValue: "ALL"},
|
||||
Kind: &plugin_pb.ConfigValue_StringValue{StringValue: string(volumeStateAll)},
|
||||
},
|
||||
"data_center_filter": {
|
||||
Kind: &plugin_pb.ConfigValue_StringValue{StringValue: ""},
|
||||
@@ -319,8 +332,8 @@ func (h *VolumeBalanceHandler) Detect(
|
||||
return err
|
||||
}
|
||||
|
||||
volumeState := strings.ToUpper(strings.TrimSpace(readStringConfig(request.GetAdminConfigValues(), "volume_state", "ALL")))
|
||||
metrics = filterMetricsByVolumeState(metrics, volumeState)
|
||||
volState := volumeState(strings.ToUpper(strings.TrimSpace(readStringConfig(request.GetAdminConfigValues(), "volume_state", string(volumeStateAll)))))
|
||||
metrics = filterMetricsByVolumeState(metrics, volState)
|
||||
|
||||
dataCenterFilter := strings.TrimSpace(readStringConfig(request.GetAdminConfigValues(), "data_center_filter", ""))
|
||||
rackFilter := strings.TrimSpace(readStringConfig(request.GetAdminConfigValues(), "rack_filter", ""))
|
||||
@@ -343,7 +356,7 @@ func (h *VolumeBalanceHandler) Detect(
|
||||
var results []*workertypes.TaskDetectionResult
|
||||
var hasMore bool
|
||||
|
||||
if collectionFilter == collectionFilterEach {
|
||||
if collectionFilterMode(collectionFilter) == collectionFilterEach {
|
||||
// Group metrics by collection in a single pass (O(N) instead of O(C*N))
|
||||
metricsByCollection := make(map[string][]*workertypes.VolumeHealthMetrics)
|
||||
for _, m := range metrics {
|
||||
@@ -664,16 +677,16 @@ func emitVolumeBalanceDetectionDecisionTrace(
|
||||
// "ACTIVE" keeps volumes with FullnessRatio < 1.01 (writable, below size limit).
|
||||
// "FULL" keeps volumes with FullnessRatio >= 1.01 (read-only, above size limit).
|
||||
// "ALL" or any other value returns all metrics unfiltered.
|
||||
func filterMetricsByVolumeState(metrics []*workertypes.VolumeHealthMetrics, volumeState string) []*workertypes.VolumeHealthMetrics {
|
||||
func filterMetricsByVolumeState(metrics []*workertypes.VolumeHealthMetrics, state volumeState) []*workertypes.VolumeHealthMetrics {
|
||||
const fullnessThreshold = 1.01
|
||||
|
||||
var predicate func(m *workertypes.VolumeHealthMetrics) bool
|
||||
switch volumeState {
|
||||
case "ACTIVE":
|
||||
switch state {
|
||||
case volumeStateActive:
|
||||
predicate = func(m *workertypes.VolumeHealthMetrics) bool {
|
||||
return m.FullnessRatio < fullnessThreshold
|
||||
}
|
||||
case "FULL":
|
||||
case volumeStateFull:
|
||||
predicate = func(m *workertypes.VolumeHealthMetrics) bool {
|
||||
return m.FullnessRatio >= fullnessThreshold
|
||||
}
|
||||
|
||||
@@ -712,7 +712,7 @@ func TestFilterMetricsByVolumeState(t *testing.T) {
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result := filterMetricsByVolumeState(metrics, tt.state)
|
||||
result := filterMetricsByVolumeState(metrics, volumeState(tt.state))
|
||||
if len(result) != len(tt.expectedIDs) {
|
||||
t.Fatalf("expected %d metrics, got %d", len(tt.expectedIDs), len(result))
|
||||
}
|
||||
@@ -732,23 +732,23 @@ func TestFilterMetricsByVolumeState_NilElement(t *testing.T) {
|
||||
nil,
|
||||
{VolumeID: 2, FullnessRatio: 1.5},
|
||||
}
|
||||
result := filterMetricsByVolumeState(metrics, "ACTIVE")
|
||||
result := filterMetricsByVolumeState(metrics, volumeStateActive)
|
||||
if len(result) != 1 || result[0].VolumeID != 1 {
|
||||
t.Fatalf("expected [vol 1] for ACTIVE with nil elements, got %d results", len(result))
|
||||
}
|
||||
result = filterMetricsByVolumeState(metrics, "FULL")
|
||||
result = filterMetricsByVolumeState(metrics, volumeStateFull)
|
||||
if len(result) != 1 || result[0].VolumeID != 2 {
|
||||
t.Fatalf("expected [vol 2] for FULL with nil elements, got %d results", len(result))
|
||||
}
|
||||
}
|
||||
|
||||
func TestFilterMetricsByVolumeState_EmptyInput(t *testing.T) {
|
||||
result := filterMetricsByVolumeState(nil, "ACTIVE")
|
||||
result := filterMetricsByVolumeState(nil, volumeStateActive)
|
||||
if len(result) != 0 {
|
||||
t.Fatalf("expected 0 metrics for nil input, got %d", len(result))
|
||||
}
|
||||
|
||||
result = filterMetricsByVolumeState([]*workertypes.VolumeHealthMetrics{}, "FULL")
|
||||
result = filterMetricsByVolumeState([]*workertypes.VolumeHealthMetrics{}, volumeStateFull)
|
||||
if len(result) != 0 {
|
||||
t.Fatalf("expected 0 metrics for empty input, got %d", len(result))
|
||||
}
|
||||
|
||||
@@ -101,7 +101,8 @@ func buildVolumeMetrics(
|
||||
|
||||
var collectionRegex *regexp.Regexp
|
||||
trimmedFilter := strings.TrimSpace(collectionFilter)
|
||||
if trimmedFilter != "" && trimmedFilter != collectionFilterAll && trimmedFilter != collectionFilterEach && trimmedFilter != "*" {
|
||||
filterMode := collectionFilterMode(trimmedFilter)
|
||||
if trimmedFilter != "" && filterMode != collectionFilterAll && filterMode != collectionFilterEach && trimmedFilter != "*" {
|
||||
var err error
|
||||
collectionRegex, err = regexp.Compile(trimmedFilter)
|
||||
if err != nil {
|
||||
|
||||
@@ -53,7 +53,7 @@ func TestBuildVolumeMetricsAllCollections(t *testing.T) {
|
||||
&master_pb.VolumeInformationMessage{Id: 1, Collection: "photos", Size: 100},
|
||||
&master_pb.VolumeInformationMessage{Id: 2, Collection: "videos", Size: 200},
|
||||
)
|
||||
metrics, _, _, err := buildVolumeMetrics(resp, collectionFilterAll)
|
||||
metrics, _, _, err := buildVolumeMetrics(resp, string(collectionFilterAll))
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
@@ -68,7 +68,7 @@ func TestBuildVolumeMetricsEachCollection(t *testing.T) {
|
||||
&master_pb.VolumeInformationMessage{Id: 2, Collection: "videos", Size: 200},
|
||||
)
|
||||
// EACH_COLLECTION passes all volumes through; filtering happens in the handler
|
||||
metrics, _, _, err := buildVolumeMetrics(resp, collectionFilterEach)
|
||||
metrics, _, _, err := buildVolumeMetrics(resp, string(collectionFilterEach))
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user