Skip to content

Commit b8bd337

Browse files
corrected env var percentage calculation
1 parent 99b394c commit b8bd337

File tree

1 file changed

+171
-25
lines changed

1 file changed

+171
-25
lines changed

internal/config/config.go

Lines changed: 171 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,12 @@ func LoadAppConfig(path string) (*AppConfig, error) {
7373
return nil, fmt.Errorf("invalid YAML format for config: %w", err)
7474
}
7575

76-
applyEnvOverrides(cfg)
77-
normalizePercentages(cfg)
76+
// Apply overrides and capture which percentage fields were set
77+
overriddenStats := applyEnvOverrides(cfg)
78+
79+
// Normalize based on what was overridden
80+
normalizePercentages(cfg, overriddenStats)
81+
7882
applyDefaults(cfg)
7983

8084
return cfg, nil
@@ -110,7 +114,12 @@ func applyDefaults(cfg *AppConfig) {
110114
}
111115
}
112116

113-
func applyEnvOverrides(cfg *AppConfig) {
117+
// applyEnvOverrides updates the config from ENV vars and returns a map
118+
// of percentage fields that were explicitly set.
119+
func applyEnvOverrides(cfg *AppConfig) map[string]bool {
120+
// Track which percentages are overridden
121+
overrides := make(map[string]bool)
122+
114123
// 1. Credentials
115124
if v := os.Getenv("PLGM_USERNAME"); v != "" {
116125
cfg.ConnectionParams.Username = v
@@ -190,34 +199,48 @@ func applyEnvOverrides(cfg *AppConfig) {
190199
if envDuration := os.Getenv("PLGM_DURATION"); envDuration != "" {
191200
cfg.Duration = envDuration
192201
}
202+
203+
// Percentages - we track these to prioritize them in normalization
193204
if p := os.Getenv("PLGM_FIND_PERCENT"); p != "" {
194205
if n, err := strconv.Atoi(p); err == nil && n >= 0 {
195206
cfg.FindPercent = n
207+
overrides["FindPercent"] = true
196208
}
197209
}
198210
if p := os.Getenv("PLGM_UPDATE_PERCENT"); p != "" {
199211
if n, err := strconv.Atoi(p); err == nil && n >= 0 {
200212
cfg.UpdatePercent = n
213+
overrides["UpdatePercent"] = true
201214
}
202215
}
203216
if p := os.Getenv("PLGM_DELETE_PERCENT"); p != "" {
204217
if n, err := strconv.Atoi(p); err == nil && n >= 0 {
205218
cfg.DeletePercent = n
219+
overrides["DeletePercent"] = true
206220
}
207221
}
208222
if p := os.Getenv("PLGM_INSERT_PERCENT"); p != "" {
209223
if n, err := strconv.Atoi(p); err == nil && n >= 0 {
210224
cfg.InsertPercent = n
225+
overrides["InsertPercent"] = true
211226
}
212227
}
213228
if p := os.Getenv("PLGM_AGGREGATE_PERCENT"); p != "" {
214229
if n, err := strconv.Atoi(p); err == nil && n >= 0 {
215230
cfg.AggregatePercent = n
231+
overrides["AggregatePercent"] = true
216232
}
217233
}
218234
if p := os.Getenv("PLGM_TRANSACTION_PERCENT"); p != "" {
219235
if n, err := strconv.Atoi(p); err == nil && n >= 0 {
220236
cfg.TransactionPercent = n
237+
overrides["TransactionPercent"] = true
238+
}
239+
}
240+
if p := os.Getenv("PLGM_BULK_INSERT_PERCENT"); p != "" {
241+
if n, err := strconv.Atoi(p); err == nil && n >= 0 {
242+
cfg.BulkInsertPercent = n
243+
overrides["BulkInsertPercent"] = true
221244
}
222245
}
223246

@@ -256,42 +279,165 @@ func applyEnvOverrides(cfg *AppConfig) {
256279
cfg.StatusRefreshRateSec = n
257280
}
258281
}
259-
if p := os.Getenv("PLGM_BULK_INSERT_PERCENT"); p != "" {
260-
if n, err := strconv.Atoi(p); err == nil && n >= 0 {
261-
cfg.BulkInsertPercent = n
262-
}
263-
}
264282
if v := os.Getenv("PLGM_INSERT_BATCH_SIZE"); v != "" {
265283
if n, err := strconv.Atoi(v); err == nil && n > 0 {
266284
cfg.InsertBatchSize = n
267285
}
268286
}
287+
288+
return overrides
269289
}
270290

271-
func normalizePercentages(cfg *AppConfig) {
291+
func normalizePercentages(cfg *AppConfig, pinned map[string]bool) {
292+
// 1. Enforce Transaction flag constraint immediately
272293
if !cfg.UseTransactions {
273294
cfg.TransactionPercent = 0
295+
delete(pinned, "TransactionPercent")
274296
}
275297

276-
total := cfg.FindPercent + cfg.UpdatePercent + cfg.DeletePercent + cfg.InsertPercent + cfg.AggregatePercent + cfg.TransactionPercent + cfg.BulkInsertPercent
277-
if total <= 0 {
278-
cfg.FindPercent = 100
279-
return
298+
// 2. Calculate the total of "pinned" (Environment overridden) stats
299+
pinnedTotal := 0
300+
if pinned["FindPercent"] {
301+
pinnedTotal += cfg.FindPercent
302+
}
303+
if pinned["UpdatePercent"] {
304+
pinnedTotal += cfg.UpdatePercent
305+
}
306+
if pinned["DeletePercent"] {
307+
pinnedTotal += cfg.DeletePercent
308+
}
309+
if pinned["InsertPercent"] {
310+
pinnedTotal += cfg.InsertPercent
311+
}
312+
if pinned["AggregatePercent"] {
313+
pinnedTotal += cfg.AggregatePercent
314+
}
315+
if pinned["TransactionPercent"] {
316+
pinnedTotal += cfg.TransactionPercent
317+
}
318+
if pinned["BulkInsertPercent"] {
319+
pinnedTotal += cfg.BulkInsertPercent
280320
}
281321

282-
if total != 100 {
283-
factor := 100.0 / float64(total)
284-
cfg.FindPercent = int(float64(cfg.FindPercent) * factor)
285-
cfg.UpdatePercent = int(float64(cfg.UpdatePercent) * factor)
286-
cfg.DeletePercent = int(float64(cfg.DeletePercent) * factor)
287-
cfg.InsertPercent = int(float64(cfg.InsertPercent) * factor)
288-
cfg.AggregatePercent = int(float64(cfg.AggregatePercent) * factor)
289-
cfg.TransactionPercent = int(float64(cfg.TransactionPercent) * factor)
290-
cfg.BulkInsertPercent = int(float64(cfg.BulkInsertPercent) * factor)
322+
// 3. Logic:
323+
// If Pinned Total >= 100: Zero out non-pinned, scale pinned if > 100.
324+
// If Pinned Total < 100: Distribute remainder among unpinned.
291325

292-
finalTotal := cfg.FindPercent + cfg.UpdatePercent + cfg.DeletePercent + cfg.InsertPercent + cfg.AggregatePercent + cfg.TransactionPercent + cfg.BulkInsertPercent
293-
if finalTotal != 100 {
294-
cfg.FindPercent += (100 - finalTotal)
326+
if pinnedTotal >= 100 {
327+
// Zero out all non-pinned fields
328+
if !pinned["FindPercent"] {
329+
cfg.FindPercent = 0
330+
}
331+
if !pinned["UpdatePercent"] {
332+
cfg.UpdatePercent = 0
295333
}
334+
if !pinned["DeletePercent"] {
335+
cfg.DeletePercent = 0
336+
}
337+
if !pinned["InsertPercent"] {
338+
cfg.InsertPercent = 0
339+
}
340+
if !pinned["AggregatePercent"] {
341+
cfg.AggregatePercent = 0
342+
}
343+
if !pinned["TransactionPercent"] {
344+
cfg.TransactionPercent = 0
345+
}
346+
if !pinned["BulkInsertPercent"] {
347+
cfg.BulkInsertPercent = 0
348+
}
349+
350+
// Normalize if pinned values sum > 100
351+
if pinnedTotal > 100 {
352+
factor := 100.0 / float64(pinnedTotal)
353+
if pinned["FindPercent"] {
354+
cfg.FindPercent = int(float64(cfg.FindPercent) * factor)
355+
}
356+
if pinned["UpdatePercent"] {
357+
cfg.UpdatePercent = int(float64(cfg.UpdatePercent) * factor)
358+
}
359+
if pinned["DeletePercent"] {
360+
cfg.DeletePercent = int(float64(cfg.DeletePercent) * factor)
361+
}
362+
if pinned["InsertPercent"] {
363+
cfg.InsertPercent = int(float64(cfg.InsertPercent) * factor)
364+
}
365+
if pinned["AggregatePercent"] {
366+
cfg.AggregatePercent = int(float64(cfg.AggregatePercent) * factor)
367+
}
368+
if pinned["TransactionPercent"] {
369+
cfg.TransactionPercent = int(float64(cfg.TransactionPercent) * factor)
370+
}
371+
if pinned["BulkInsertPercent"] {
372+
cfg.BulkInsertPercent = int(float64(cfg.BulkInsertPercent) * factor)
373+
}
374+
}
375+
376+
} else {
377+
// pinnedTotal < 100. We have space left.
378+
remaining := 100 - pinnedTotal
379+
380+
// Sum of unpinned (default) values
381+
unpinnedTotal := 0
382+
if !pinned["FindPercent"] {
383+
unpinnedTotal += cfg.FindPercent
384+
}
385+
if !pinned["UpdatePercent"] {
386+
unpinnedTotal += cfg.UpdatePercent
387+
}
388+
if !pinned["DeletePercent"] {
389+
unpinnedTotal += cfg.DeletePercent
390+
}
391+
if !pinned["InsertPercent"] {
392+
unpinnedTotal += cfg.InsertPercent
393+
}
394+
if !pinned["AggregatePercent"] {
395+
unpinnedTotal += cfg.AggregatePercent
396+
}
397+
if !pinned["TransactionPercent"] {
398+
unpinnedTotal += cfg.TransactionPercent
399+
}
400+
if !pinned["BulkInsertPercent"] {
401+
unpinnedTotal += cfg.BulkInsertPercent
402+
}
403+
404+
// Scale unpinned values to fill the remaining space
405+
if unpinnedTotal > 0 {
406+
factor := float64(remaining) / float64(unpinnedTotal)
407+
408+
if !pinned["FindPercent"] {
409+
cfg.FindPercent = int(float64(cfg.FindPercent) * factor)
410+
}
411+
if !pinned["UpdatePercent"] {
412+
cfg.UpdatePercent = int(float64(cfg.UpdatePercent) * factor)
413+
}
414+
if !pinned["DeletePercent"] {
415+
cfg.DeletePercent = int(float64(cfg.DeletePercent) * factor)
416+
}
417+
if !pinned["InsertPercent"] {
418+
cfg.InsertPercent = int(float64(cfg.InsertPercent) * factor)
419+
}
420+
if !pinned["AggregatePercent"] {
421+
cfg.AggregatePercent = int(float64(cfg.AggregatePercent) * factor)
422+
}
423+
if !pinned["TransactionPercent"] {
424+
cfg.TransactionPercent = int(float64(cfg.TransactionPercent) * factor)
425+
}
426+
if !pinned["BulkInsertPercent"] {
427+
cfg.BulkInsertPercent = int(float64(cfg.BulkInsertPercent) * factor)
428+
}
429+
} else {
430+
// Edge case: Pinned values sum to < 100 (e.g. 80%), but all unpinned defaults are 0.
431+
// We cannot distribute the remaining 20% proportionally among 0s.
432+
// Strategy: Assign the remainder to FindPercent (Selects) to ensure the workload sums to 100%.
433+
cfg.FindPercent += remaining
434+
}
435+
}
436+
437+
// 4. Final check: Ensure total is exactly 100 (fixing integer rounding errors)
438+
finalTotal := cfg.FindPercent + cfg.UpdatePercent + cfg.DeletePercent + cfg.InsertPercent + cfg.AggregatePercent + cfg.TransactionPercent + cfg.BulkInsertPercent
439+
if finalTotal != 100 {
440+
// Add/Subtract difference to FindPercent (simplest safety net)
441+
cfg.FindPercent += (100 - finalTotal)
296442
}
297443
}

0 commit comments

Comments
 (0)