Skip to content

Commit 6ab4e09

Browse files
Improve workload configuration logic and startup feedback
1 parent 19bc88a commit 6ab4e09

File tree

8 files changed

+124
-61
lines changed

8 files changed

+124
-61
lines changed

README.md

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -183,10 +183,9 @@ export PLGM_COLLECTIONS_PATH="./resources/custom_collections/"
183183
#### Default Workload Filtering
184184
When using **Directory Mode**, the behavior depends on the `PLGM_DEFAULT_WORKLOAD` setting:
185185

186-
* **`true` (Default):** Loads **all** JSON files in the directory, including `default.json`.
186+
* **`true` (Default):** Loads **only** `default.json` (if present). It ignores all other files in the folder.
187187
* **`false` (Custom):** Loads all JSON files **except** `default.json`.
188-
* *Use Case:* You can keep the example `default.json` in your folder for reference but exclude it from your actual test run by setting `PLGM_DEFAULT_WORKLOAD=false`.
189-
188+
* *Use Case:* Set this to `false` to run your custom workload files while keeping `default.json` in the folder for reference (it will be ignored).
190189

191190
### 5. Docker & Kubernetes
192191
Prefer running in a container? We have a dedicated guide for building Docker images and running performance jobs directly inside Kubernetes (recommended for accurate network latency testing).

cmd/plgm/main.go

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -113,38 +113,31 @@ func main() {
113113
}
114114

115115
// --- Secure Credentials Logic ---
116-
117-
// 1. Analyze the Base URI to see if it already has credentials
118116
u, err := url.Parse(appCfg.URI)
119117
if err != nil {
120118
log.Fatalf("Invalid PLGM_URI: %v", err)
121119
}
122120
uriHasUser := u.User != nil && u.User.Username() != ""
123121

124-
// 2. Prompt for Username if missing (from both URI and Env/Config)
125122
if !uriHasUser && appCfg.ConnectionParams.Username == "" {
126123
fmt.Print("Enter MongoDB Username: ")
127124
var inputUser string
128125
if _, err := fmt.Scanln(&inputUser); err != nil {
129-
// Handle case where user hits enter or pipe closes
130126
if err.Error() != "unexpected newline" {
131127
log.Fatal(err)
132128
}
133129
}
134130
appCfg.ConnectionParams.Username = inputUser
135131
}
136132

137-
// 3. Prompt for Password if missing
138-
// Logic: If we have a username defined in config/prompt (overriding whatever is in URI),
139-
// and no password is set for it, we must prompt.
140133
if appCfg.ConnectionParams.Username != "" && appCfg.ConnectionParams.Password == "" {
141134
fmt.Printf("Enter Password for user '%s': ", appCfg.ConnectionParams.Username)
142135
bytePassword, err := term.ReadPassword(int(os.Stdin.Fd()))
143136
if err != nil {
144137
log.Fatal("\nError reading password:", err)
145138
}
146139
appCfg.ConnectionParams.Password = string(bytePassword)
147-
fmt.Println() // Print newline after input
140+
fmt.Println()
148141
}
149142

150143
// --- Load Collections ---
@@ -185,7 +178,6 @@ func main() {
185178
}
186179
queriesCfg.Queries = filteredQueries
187180

188-
// Determine DB name from first collection for the banner
189181
dbName := collectionsCfg.Collections[0].DatabaseName
190182

191183
// -----------------------------------------------------------------------------------
@@ -201,7 +193,6 @@ func main() {
201193
defer conn.Disconnect(ctx)
202194

203195
// --- Log Setup Details (Execution Phase) ---
204-
// Now we print the logs, so they appear below the plan
205196
logger.Info("Loaded %d collection definition(s)", len(collectionsCfg.Collections))
206197
logger.Info("Loaded %d query templates(s)", len(queriesCfg.Queries))
207198

@@ -218,11 +209,9 @@ func main() {
218209
log.Fatal(err)
219210
}
220211

221-
// --- Seed documents (initial dataset) ---
212+
// --- Seed documents ---
222213
if !appCfg.SkipSeed {
223214
if appCfg.DocumentsCount > 0 {
224-
// NOTE: Logging is handled inside InsertRandomDocuments,
225-
// but we can add a high-level log here if we want.
226215
for _, col := range collectionsCfg.Collections {
227216
if err := mongo.InsertRandomDocuments(ctx, conn.Database, col, appCfg.DocumentsCount, appCfg); err != nil {
228217
log.Fatal(err)

internal/config/collections.go

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -43,13 +43,10 @@ type CollectionsFile struct {
4343
Collections []CollectionDefinition `json:"collections"`
4444
}
4545

46-
// LoadCollections loads files from a path.
47-
// If path is a folder:
48-
// - If loadDefault is TRUE: Loads ALL .json files (including default.json).
49-
// - If loadDefault is FALSE: Loads ALL .json files EXCEPT default.json.
50-
//
51-
// If path is a file:
52-
// - Loads the file unconditionally.
46+
// LoadCollections filters files based on the 'loadDefault' flag.
47+
// - If loadDefault is TRUE: Load ONLY 'default.json'.
48+
// - If loadDefault is FALSE: Load ALL files EXCEPT 'default.json'.
49+
// - Single file paths are always loaded.
5350
func LoadCollections(path string, loadDefault bool) (*CollectionsFile, error) {
5451
if path == "" {
5552
return &CollectionsFile{}, nil
@@ -74,10 +71,16 @@ func LoadCollections(path string, loadDefault bool) (*CollectionsFile, error) {
7471

7572
isDefault := strings.EqualFold(entry.Name(), "default.json")
7673

77-
// If default_workload is FALSE, we explicitly ignore 'default.json' in folder mode.
78-
// If default_workload is TRUE, we load everything (no continue).
79-
if !loadDefault && isDefault {
80-
continue
74+
if loadDefault {
75+
// Mode: Default Workload -> Load ONLY default.json
76+
if !isDefault {
77+
continue
78+
}
79+
} else {
80+
// Mode: Custom Workload -> Load EVERYTHING ELSE
81+
if isDefault {
82+
continue
83+
}
8184
}
8285

8386
fullPath := filepath.Join(path, entry.Name())
@@ -88,7 +91,7 @@ func LoadCollections(path string, loadDefault bool) (*CollectionsFile, error) {
8891
allCollections = append(allCollections, loaded.Collections...)
8992
}
9093
} else {
91-
// Single file: Always load it if the user specifically pointed to it.
94+
// Single file: Always load it (explicit user choice).
9295
loaded, err := loadCollectionsFromFile(path)
9396
if err != nil {
9497
return nil, err

internal/config/config.go

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -111,17 +111,23 @@ func applyDefaults(cfg *AppConfig) {
111111
}
112112

113113
func applyEnvOverrides(cfg *AppConfig) {
114+
// 1. Credentials
114115
if v := os.Getenv("PLGM_USERNAME"); v != "" {
115116
cfg.ConnectionParams.Username = v
116117
}
117118
if v := os.Getenv("PLGM_PASSWORD"); v != "" {
118119
cfg.ConnectionParams.Password = v
119120
}
121+
122+
// 2. Default Workload (Explicit Override)
123+
// If the user sets this Env Var, it takes precedence over everything.
120124
if v := os.Getenv("PLGM_DEFAULT_WORKLOAD"); v != "" {
121125
if b, err := strconv.ParseBool(v); err == nil {
122126
cfg.DefaultWorkload = b
123127
}
124128
}
129+
130+
// 3. Other Settings
125131
if envDebug := os.Getenv("PLGM_DEBUG_MODE"); envDebug != "" {
126132
if b, err := strconv.ParseBool(envDebug); err == nil {
127133
cfg.DebugMode = b
@@ -142,17 +148,12 @@ func applyEnvOverrides(cfg *AppConfig) {
142148
cfg.ConnectionParams.ReadPreference = v
143149
}
144150

145-
customWorkloadEnv := false
151+
// 4. Custom Paths
146152
if envCollectionsPath := os.Getenv("PLGM_COLLECTIONS_PATH"); envCollectionsPath != "" {
147153
cfg.CollectionsPath = envCollectionsPath
148-
customWorkloadEnv = true
149154
}
150155
if envQueriesPath := os.Getenv("PLGM_QUERIES_PATH"); envQueriesPath != "" {
151156
cfg.QueriesPath = envQueriesPath
152-
customWorkloadEnv = true
153-
}
154-
if customWorkloadEnv {
155-
cfg.DefaultWorkload = false
156157
}
157158

158159
if envDrop := os.Getenv("PLGM_DROP_COLLECTIONS"); envDrop != "" {

internal/config/queries.go

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,10 @@ type QueriesFile struct {
2424
Queries []QueryDefinition
2525
}
2626

27-
// LoadQueries loads files from a path.
28-
// If path is a folder:
29-
// - If loadDefault is TRUE: Loads ALL .json files (including default.json).
30-
// - If loadDefault is FALSE: Loads ALL .json files EXCEPT default.json.
31-
//
32-
// If path is a file:
33-
// - Loads the file unconditionally.
27+
// LoadQueries filters files based on the 'loadDefault' flag.
28+
// - If loadDefault is TRUE: Load ONLY 'default.json'.
29+
// - If loadDefault is FALSE: Load ALL files EXCEPT 'default.json'.
30+
// - Single file paths are always loaded.
3431
func LoadQueries(path string, loadDefault bool) (*QueriesFile, error) {
3532
if path == "" {
3633
return &QueriesFile{}, nil
@@ -55,10 +52,16 @@ func LoadQueries(path string, loadDefault bool) (*QueriesFile, error) {
5552

5653
isDefault := strings.EqualFold(entry.Name(), "default.json")
5754

58-
// If default_workload is FALSE, we explicitly ignore 'default.json' in folder mode.
59-
// If default_workload is TRUE, we load everything.
60-
if !loadDefault && isDefault {
61-
continue
55+
if loadDefault {
56+
// Mode: Default Workload -> Load ONLY default.json
57+
if !isDefault {
58+
continue
59+
}
60+
} else {
61+
// Mode: Custom Workload -> Load EVERYTHING ELSE
62+
if isDefault {
63+
continue
64+
}
6265
}
6366

6467
fullPath := filepath.Join(path, entry.Name())

internal/mongo/runner.go

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,11 @@ func insertDocumentProducer(ctx context.Context, col config.CollectionDefinition
177177
}
178178
}
179179

180+
// Helper to get collection handle
181+
func getCollectionHandle(db *mongo.Database, col config.CollectionDefinition) *mongo.Collection {
182+
return db.Client().Database(col.DatabaseName).Collection(col.Name)
183+
}
184+
180185
func runTransaction(ctx context.Context, id int, wCfg workloadConfig, rng *rand.Rand) {
181186
session, err := wCfg.database.Client().StartSession()
182187
if err != nil {
@@ -215,7 +220,8 @@ func runTransaction(ctx context.Context, id int, wCfg workloadConfig, rng *rand.
215220
continue
216221
}
217222

218-
coll := wCfg.database.Collection(currentCol.Name)
223+
coll := getCollectionHandle(wCfg.database, currentCol)
224+
219225
filter := cloneMap(q.Filter)
220226
processRecursive(filter, rng)
221227

@@ -304,7 +310,8 @@ func independentWorker(ctx context.Context, id int, wg *sync.WaitGroup, wCfg wor
304310
continue
305311
}
306312

307-
coll := wCfg.database.Collection(currentCol.Name)
313+
coll := getCollectionHandle(wCfg.database, currentCol)
314+
308315
var filter map[string]interface{}
309316
var pipeline []interface{}
310317

@@ -532,7 +539,12 @@ func queryWorkerOnce(ctx context.Context, id int, tasks <-chan *queryTask, wg *s
532539
dbOpCtx := context.Background()
533540
for task := range tasks {
534541
q := task.definition
535-
coll := task.database.Collection(q.Collection)
542+
coll := task.database.Client().Database(q.Database).Collection(q.Collection)
543+
if q.Database == "" {
544+
// Fallback if not specified in query
545+
coll = task.database.Collection(q.Collection)
546+
}
547+
536548
filter := cloneMap(q.Filter)
537549
processRecursive(filter, task.rng)
538550
switch q.Operation {

internal/mongo/setup.go

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,19 @@ import (
1515
)
1616

1717
func InsertRandomDocuments(ctx context.Context, db *mongo.Database, col config.CollectionDefinition, count int, cfg *config.AppConfig) error {
18-
logger.Info("Seeding %d documents into '%s'...", count, col.Name)
18+
logger.Info("Seeding %d documents into '%s.%s'...", count, col.DatabaseName, col.Name)
1919
docs := make([]interface{}, count)
2020

2121
for i := 0; i < count; i++ {
2222
docs[i] = workloads.GenerateDocument(col, cfg)
2323
}
2424

2525
if len(docs) > 0 {
26-
_, err := db.Collection(col.Name).InsertMany(ctx, docs)
26+
// Use database from definition
27+
targetDB := db.Client().Database(col.DatabaseName)
28+
_, err := targetDB.Collection(col.Name).InsertMany(ctx, docs)
2729
if err != nil {
28-
return fmt.Errorf("insert documents into %s: %w", col.Name, err)
30+
return fmt.Errorf("insert documents into %s.%s: %w", col.DatabaseName, col.Name, err)
2931
}
3032
}
3133
return nil
@@ -35,7 +37,7 @@ func InsertRandomDocuments(ctx context.Context, db *mongo.Database, col config.C
3537
func CreateCollectionsFromConfig(ctx context.Context, db *mongo.Database, cfg *config.CollectionsFile, drop bool) error {
3638
adminDB := db.Client().Database("admin")
3739

38-
// 1. Check if the cluster is actually sharded, if the output has isdbgrid this means it is a sharded cluster)
40+
// 1. Check if the cluster is actually sharded
3941
var helloResult bson.M
4042
isShardedCluster := false
4143
if err := adminDB.RunCommand(ctx, bson.D{{Key: "hello", Value: 1}}).Decode(&helloResult); err == nil {
@@ -45,16 +47,18 @@ func CreateCollectionsFromConfig(ctx context.Context, db *mongo.Database, cfg *c
4547
}
4648

4749
for _, col := range cfg.Collections {
50+
// Derive database handle
51+
targetDB := db.Client().Database(col.DatabaseName)
52+
4853
// 2. Drop if requested
4954
if drop {
50-
_ = db.Collection(col.Name).Drop(ctx)
55+
_ = targetDB.Collection(col.Name).Drop(ctx)
5156
}
5257

5358
// 3. Create Collection
54-
// We only log if we actually create it or if it's significant
55-
if err := db.CreateCollection(ctx, col.Name); err != nil {
59+
if err := targetDB.CreateCollection(ctx, col.Name); err != nil {
5660
if drop {
57-
return fmt.Errorf("create collection %s: %w", col.Name, err)
61+
return fmt.Errorf("create collection %s.%s: %w", col.DatabaseName, col.Name, err)
5862
}
5963
}
6064

@@ -90,7 +94,9 @@ func CreateIndexesFromConfig(ctx context.Context, db *mongo.Database, cfg *confi
9094
if len(col.Indexes) == 0 {
9195
continue
9296
}
93-
collection := db.Collection(col.Name)
97+
98+
targetDB := db.Client().Database(col.DatabaseName)
99+
collection := targetDB.Collection(col.Name)
94100
models := make([]mongo.IndexModel, 0, len(col.Indexes))
95101

96102
for _, idx := range col.Indexes {
@@ -112,11 +118,10 @@ func CreateIndexesFromConfig(ctx context.Context, db *mongo.Database, cfg *confi
112118
opts := options.CreateIndexes()
113119

114120
if _, err := collection.Indexes().CreateMany(ctxCreate, models, opts); err != nil {
115-
return fmt.Errorf("create indexes on %s: %w", col.Name, err)
121+
return fmt.Errorf("create indexes on %s.%s: %w", col.DatabaseName, col.Name, err)
116122
}
117123

118-
// Consolidated Log:
119-
logger.Info("Created %d indexes on '%s'", len(models), col.Name)
124+
logger.Info("Created %d indexes on '%s.%s'", len(models), col.DatabaseName, col.Name)
120125
}
121126
return nil
122127
}

0 commit comments

Comments
 (0)