Skip to content

Commit c401994

Browse files
committed
PCSM-219: Move clone flags to start subcommand
1 parent aed7710 commit c401994

File tree

7 files changed

+156
-382
lines changed

7 files changed

+156
-382
lines changed

config/config.go

Lines changed: 6 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -75,44 +75,9 @@ func UseTargetClientCompressors() []string {
7575
return rv
7676
}
7777

78-
// ResolveCloneSegmentSize resolves the clone segment size from an optional HTTP value
79-
// or falls back to the CLI config value. Both sources are validated.
80-
func ResolveCloneSegmentSize(cfg *Config, value *string) (int64, error) {
81-
if value != nil {
82-
return parseAndValidateCloneSegmentSize(*value)
83-
}
84-
85-
// Fall back to CLI config value and validate it
86-
sizeBytes := cfg.Clone.SegmentSizeBytes()
87-
88-
err := ValidateCloneSegmentSize(uint64(max(sizeBytes, 0))) //nolint:gosec
89-
if err != nil {
90-
return 0, errors.Wrap(err, "config clone-segment-size")
91-
}
92-
93-
return sizeBytes, nil
94-
}
95-
96-
// ResolveCloneReadBatchSize resolves the clone read batch size from an optional HTTP value
97-
// or falls back to the CLI config value. Both sources are validated.
98-
func ResolveCloneReadBatchSize(cfg *Config, value *string) (int32, error) {
99-
if value != nil {
100-
return parseAndValidateCloneReadBatchSize(*value)
101-
}
102-
103-
// Fall back to CLI config value and validate it
104-
sizeBytes := cfg.Clone.ReadBatchSizeBytes()
105-
106-
err := ValidateCloneReadBatchSize(uint64(max(sizeBytes, 0))) //nolint:gosec
107-
if err != nil {
108-
return 0, errors.Wrap(err, "config clone-read-batch-size")
109-
}
110-
111-
return sizeBytes, nil
112-
}
113-
114-
// parseAndValidateCloneSegmentSize parses a byte size string and validates it.
115-
func parseAndValidateCloneSegmentSize(value string) (int64, error) {
78+
// ParseAndValidateCloneSegmentSize parses a byte size string and validates it.
79+
// It allows 0 (auto) or values within [MinCloneSegmentSizeBytes, MaxCloneSegmentSizeBytes].
80+
func ParseAndValidateCloneSegmentSize(value string) (int64, error) {
11681
sizeBytes, err := humanize.ParseBytes(value)
11782
if err != nil {
11883
return 0, errors.Wrapf(err, "invalid cloneSegmentSize value: %s", value)
@@ -126,8 +91,9 @@ func parseAndValidateCloneSegmentSize(value string) (int64, error) {
12691
return int64(min(sizeBytes, math.MaxInt64)), nil //nolint:gosec
12792
}
12893

129-
// parseAndValidateCloneReadBatchSize parses a byte size string and validates it.
130-
func parseAndValidateCloneReadBatchSize(value string) (int32, error) {
94+
// ParseAndValidateCloneReadBatchSize parses a byte size string and validates it.
95+
// It allows 0 (auto) or values within [MinCloneReadBatchSizeBytes, MaxCloneReadBatchSizeBytes].
96+
func ParseAndValidateCloneReadBatchSize(value string) (int32, error) {
13197
sizeBytes, err := humanize.ParseBytes(value)
13298
if err != nil {
13399
return 0, errors.Wrapf(err, "invalid cloneReadBatchSize value: %s", value)

config/config_test.go

Lines changed: 40 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -11,91 +11,58 @@ import (
1111
"github.com/percona/percona-clustersync-mongodb/config"
1212
)
1313

14-
func TestResolveCloneSegmentSize(t *testing.T) {
14+
func TestParseAndValidateCloneSegmentSize(t *testing.T) {
1515
t.Parallel()
1616

1717
tests := []struct {
1818
name string
19-
cfg *config.Config
20-
value *string
19+
value string
2120
want int64
2221
wantErr string
2322
}{
2423
{
25-
name: "nil value - falls back to config default (empty)",
26-
cfg: &config.Config{},
27-
value: nil,
28-
want: config.AutoCloneSegmentSize,
29-
wantErr: "",
24+
name: "valid size 500MB (above minimum)",
25+
value: "500MB",
26+
want: 500 * humanize.MByte,
3027
},
3128
{
32-
name: "nil value - falls back to config value",
33-
cfg: &config.Config{
34-
Clone: config.CloneConfig{
35-
SegmentSize: "1GiB",
36-
},
37-
},
38-
value: nil,
39-
want: humanize.GiByte,
40-
wantErr: "",
29+
name: "valid size 1GiB",
30+
value: "1GiB",
31+
want: humanize.GiByte,
4132
},
4233
{
43-
name: "valid size 500MB (above minimum)",
44-
cfg: &config.Config{},
45-
value: toPtr("500MB"),
46-
want: 500 * humanize.MByte,
47-
wantErr: "",
48-
},
49-
{
50-
name: "valid size 1GiB",
51-
cfg: &config.Config{},
52-
value: toPtr("1GiB"),
53-
want: humanize.GiByte,
54-
wantErr: "",
55-
},
56-
{
57-
name: "zero value (auto)",
58-
cfg: &config.Config{},
59-
value: toPtr("0"),
60-
want: 0,
61-
wantErr: "",
34+
name: "zero value (auto)",
35+
value: "0",
36+
want: 0,
6237
},
6338
{
6439
name: "below minimum (100MB)",
65-
cfg: &config.Config{},
66-
value: toPtr("100MB"),
40+
value: "100MB",
6741
wantErr: "cloneSegmentSize must be at least",
6842
},
6943
{
7044
name: "above maximum",
71-
cfg: &config.Config{},
72-
value: toPtr("100GiB"),
45+
value: "100GiB",
7346
wantErr: "cloneSegmentSize must be at most",
7447
},
7548
{
76-
name: "at minimum boundary (using exact bytes)",
77-
cfg: &config.Config{},
78-
value: toPtr(fmt.Sprintf("%dB", config.MinCloneSegmentSizeBytes)),
79-
want: int64(config.MinCloneSegmentSizeBytes),
80-
wantErr: "",
49+
name: "at minimum boundary (using exact bytes)",
50+
value: fmt.Sprintf("%dB", config.MinCloneSegmentSizeBytes),
51+
want: int64(config.MinCloneSegmentSizeBytes),
8152
},
8253
{
83-
name: "at maximum boundary",
84-
cfg: &config.Config{},
85-
value: toPtr("64GiB"),
86-
want: int64(config.MaxCloneSegmentSizeBytes),
87-
wantErr: "",
54+
name: "at maximum boundary",
55+
value: "64GiB",
56+
want: int64(config.MaxCloneSegmentSizeBytes),
8857
},
8958
{
9059
name: "invalid format",
91-
cfg: &config.Config{},
92-
value: toPtr("abc"),
60+
value: "abc",
9361
wantErr: "invalid cloneSegmentSize value",
9462
},
9563
{
9664
name: "empty string",
97-
cfg: &config.Config{},
98-
value: toPtr(""),
65+
value: "",
9966
wantErr: "invalid cloneSegmentSize value",
10067
},
10168
}
@@ -104,7 +71,7 @@ func TestResolveCloneSegmentSize(t *testing.T) {
10471
t.Run(tt.name, func(t *testing.T) {
10572
t.Parallel()
10673

107-
got, err := config.ResolveCloneSegmentSize(tt.cfg, tt.value)
74+
got, err := config.ParseAndValidateCloneSegmentSize(tt.value)
10875

10976
if tt.wantErr == "" {
11077
require.NoError(t, err)
@@ -117,78 +84,48 @@ func TestResolveCloneSegmentSize(t *testing.T) {
11784
}
11885
}
11986

120-
func TestResolveCloneReadBatchSize(t *testing.T) {
87+
func TestParseAndValidateCloneReadBatchSize(t *testing.T) {
12188
t.Parallel()
12289

12390
tests := []struct {
12491
name string
125-
cfg *config.Config
126-
value *string
92+
value string
12793
want int32
12894
wantErr string
12995
}{
13096
{
131-
name: "nil value - falls back to config default (empty)",
132-
cfg: &config.Config{},
133-
value: nil,
134-
want: 0,
135-
wantErr: "",
97+
name: "valid size 16MiB",
98+
value: "16MiB",
99+
want: 16 * humanize.MiByte,
136100
},
137101
{
138-
name: "nil value - falls back to config value",
139-
cfg: &config.Config{
140-
Clone: config.CloneConfig{
141-
ReadBatchSize: "32MiB",
142-
},
143-
},
144-
value: nil,
145-
want: 32 * humanize.MiByte,
146-
wantErr: "",
102+
name: "valid size 48MB",
103+
value: "48MB",
104+
want: 48 * humanize.MByte,
147105
},
148106
{
149-
name: "valid size 16MiB",
150-
cfg: &config.Config{},
151-
value: toPtr("16MiB"),
152-
want: 16 * humanize.MiByte,
153-
wantErr: "",
154-
},
155-
{
156-
name: "valid size 48MB",
157-
cfg: &config.Config{},
158-
value: toPtr("48MB"),
159-
want: 48 * humanize.MByte,
160-
wantErr: "",
161-
},
162-
{
163-
name: "zero value (auto)",
164-
cfg: &config.Config{},
165-
value: toPtr("0"),
166-
want: 0,
167-
wantErr: "",
107+
name: "zero value (auto)",
108+
value: "0",
109+
want: 0,
168110
},
169111
{
170112
name: "below minimum",
171-
cfg: &config.Config{},
172-
value: toPtr("1KB"),
113+
value: "1KB",
173114
wantErr: "cloneReadBatchSize must be at least",
174115
},
175116
{
176-
name: "at minimum boundary (using exact bytes)",
177-
cfg: &config.Config{},
178-
value: toPtr(fmt.Sprintf("%dB", config.MinCloneReadBatchSizeBytes)),
179-
want: config.MinCloneReadBatchSizeBytes,
180-
wantErr: "",
117+
name: "at minimum boundary (using exact bytes)",
118+
value: fmt.Sprintf("%dB", config.MinCloneReadBatchSizeBytes),
119+
want: config.MinCloneReadBatchSizeBytes,
181120
},
182121
{
183122
name: "invalid format",
184-
cfg: &config.Config{},
185-
value: toPtr("xyz"),
123+
value: "xyz",
186124
wantErr: "invalid cloneReadBatchSize value",
187125
},
188126
{
189127
name: "empty string",
190-
cfg: &config.Config{},
191-
value: toPtr(""),
128+
value: "",
192129
wantErr: "invalid cloneReadBatchSize value",
193130
},
194131
}
@@ -197,7 +134,7 @@ func TestResolveCloneReadBatchSize(t *testing.T) {
197134
t.Run(tt.name, func(t *testing.T) {
198135
t.Parallel()
199136

200-
got, err := config.ResolveCloneReadBatchSize(tt.cfg, tt.value)
137+
got, err := config.ParseAndValidateCloneReadBatchSize(tt.value)
201138

202139
if tt.wantErr == "" {
203140
require.NoError(t, err)
@@ -290,5 +227,3 @@ func TestUseTargetClientCompressors(t *testing.T) {
290227
})
291228
}
292229
}
293-
294-
func toPtr(s string) *string { return &s }

config/schema.go

Lines changed: 0 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
11
package config
22

33
import (
4-
"math"
54
"time"
6-
7-
"github.com/dustin/go-humanize"
85
)
96

107
// Config holds all PCSM configuration.
@@ -20,9 +17,6 @@ type Config struct {
2017
// MongoDB client options
2118
MongoDB MongoDBConfig `mapstructure:",squash"`
2219

23-
// Clone tuning (CLI/HTTP only)
24-
Clone CloneConfig `mapstructure:",squash"`
25-
2620
// Internal options
2721
UseCollectionBulkWrite bool `mapstructure:"use-collection-bulk-write"`
2822

@@ -55,40 +49,3 @@ func (m *MongoDBConfig) OperationTimeoutDuration() time.Duration {
5549

5650
return DefaultMongoDBOperationTimeout
5751
}
58-
59-
// CloneConfig holds clone tuning configuration.
60-
type CloneConfig struct {
61-
NumParallelCollections int `mapstructure:"clone-num-parallel-collections"`
62-
NumReadWorkers int `mapstructure:"clone-num-read-workers"`
63-
NumInsertWorkers int `mapstructure:"clone-num-insert-workers"`
64-
SegmentSize string `mapstructure:"clone-segment-size"`
65-
ReadBatchSize string `mapstructure:"clone-read-batch-size"`
66-
}
67-
68-
// SegmentSizeBytes parses and returns the segment size in bytes.
69-
func (c *CloneConfig) SegmentSizeBytes() int64 {
70-
if c.SegmentSize == "" {
71-
return AutoCloneSegmentSize
72-
}
73-
74-
bytes, err := humanize.ParseBytes(c.SegmentSize)
75-
if err == nil && bytes > 0 {
76-
return int64(min(bytes, math.MaxInt64)) //nolint:gosec
77-
}
78-
79-
return AutoCloneSegmentSize
80-
}
81-
82-
// ReadBatchSizeBytes parses and returns the read batch size in bytes.
83-
func (c *CloneConfig) ReadBatchSizeBytes() int32 {
84-
if c.ReadBatchSize == "" {
85-
return 0
86-
}
87-
88-
bytes, err := humanize.ParseBytes(c.ReadBatchSize)
89-
if err == nil {
90-
return int32(min(bytes, math.MaxInt32)) //nolint:gosec
91-
}
92-
93-
return 0
94-
}

0 commit comments

Comments
 (0)