Skip to content

Commit 99b394c

Browse files
embed default resources and simplify quick start
1 parent 25a8a9f commit 99b394c

File tree

4 files changed

+96
-29
lines changed

4 files changed

+96
-29
lines changed

README.md

Lines changed: 35 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -31,27 +31,6 @@ tar -xzvf plgm-linux-amd64.tar.gz
3131
tar -xzvf plgm-darwin-arm64.tar.gz
3232
```
3333

34-
2. Create Resources
35-
36-
If you are not cloning the repository, you will need to follow a few extra steps:
37-
38-
A. Download the [config.yaml](./config.yaml).
39-
40-
B. Modify the file so that it points to the location of your collection and query definitions.
41-
42-
> **Note:** If you do not create a `default.json` file for your collection and query definitions, you **must** disable the default workload in `config.yaml` (set `default_workload: false`). Otherwise, `plgm` will attempt to load the default workload and fail when the file is not found.
43-
44-
> **Note:** You can specify different locations for both collection and query definitions. Refer to the `config.yaml` file and the instructions below for more details.
45-
46-
> **Tip:** The simplest approach is to clone the repository. This provides all the necessary files and structures, which you can then customize to your liking. (You will still need to download the correct release as mentioned in Step 1).
47-
48-
3. Once the steps above are complete, you can run `plgm`.
49-
50-
```bash
51-
# The extracted binary will have the OS suffix
52-
./plgm-linux-amd64 --version
53-
```
54-
5534
**Option 2: Build from Source** (Requires Go 1.25+)
5635

5736
This project includes a `Makefile` to simplify building and packaging.
@@ -68,9 +47,42 @@ make build-local
6847
./bin/plgm --help
6948
```
7049

50+
### 2. Configuration & Resources
51+
52+
To run the application, you need a configuration file. Depending on whether you want to run the built-in test or your own custom workload, you may also need to create resource folders.
53+
54+
**Step A: Get the Config**
55+
56+
Download the [`config.yaml`](./config.yaml) and adjust the `uri` to point to your MongoDB instance.
57+
58+
**Step B: Choose Your Workload**
59+
60+
* **Mode 1: Default Workload (Easiest)**
61+
62+
By default (`default_workload: true` in `config.yaml`), the application uses the embedded collection and query definitions. You do **not** need to create any extra folders or files.
63+
64+
* **Mode 2: Custom Workload**
65+
66+
To run your own stress tests, you must set `default_workload: false` in `config.yaml` and provide the necessary files:
67+
68+
1. **Create Directories**: Create folders for your definitions (e.g., `resources/collections` and `resources/queries`).
69+
2. **Add Files**: Place your JSON schema and query definitions inside these folders.
70+
3. **Update Config**: Ensure `collections_path` and `queries_path` in your `config.yaml` point to these new directories.
71+
72+
> **Important:** If you are running in Custom Mode, the application expects these folders to exist. If the folders are missing, `plgm` will revert to the embedded defaults to prevent a crash, but your custom test **will not run** until the files are in place.
73+
74+
### 3. Run
75+
76+
Once configured, run the application:
77+
78+
```bash
79+
# The extracted binary will have the OS suffix
80+
./plgm-linux-amd64
81+
```
82+
7183
**Cross-Compilation (Build for different OS)**
7284

73-
If you are preparing binaries for other users (or other servers), use the main build command. This will compile binaries for Linux and Mac and automatically package them into .tar.gz files in the bin/ folder.
85+
If you are preparing binaries for other users (or other servers), use the main build command. This will compile binaries for Linux and Mac and automatically package them into .tar.gz files in the `bin/` folder.
7486

7587
```bash
7688
# Generate all release packages
@@ -82,6 +94,7 @@ make build
8294
# bin/plgm-darwin-arm64.tar.gz
8395
```
8496

97+
8598
### Usage
8699

87100
To view the full usage guide, including available flags and environment variables, run the help command:

internal/config/collections.go

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import (
66
"os"
77
"path/filepath"
88
"strings"
9+
10+
"github.com/Percona-Lab/percona-load-generator-mongodb/resources"
911
)
1012

1113
type CollectionField struct {
@@ -43,6 +45,8 @@ type CollectionsFile struct {
4345
Collections []CollectionDefinition `json:"collections"`
4446
}
4547

48+
// LoadCollections attempts to load from disk. If the path is not found,
49+
// it falls back to the embedded default.json.
4650
// LoadCollections filters files based on the 'loadDefault' flag.
4751
// - If loadDefault is TRUE: Load ONLY 'default.json'.
4852
// - If loadDefault is FALSE: Load ALL files EXCEPT 'default.json'.
@@ -51,13 +55,23 @@ func LoadCollections(path string, loadDefault bool) (*CollectionsFile, error) {
5155
if path == "" {
5256
return &CollectionsFile{}, nil
5357
}
58+
59+
// 1. Try to access the folder on disk
5460
info, err := os.Stat(path)
61+
62+
// 2. Fallback Logic: If folder/file not found, use Embedded Default
63+
if os.IsNotExist(err) {
64+
fmt.Printf("Warning: Collections path '%s' not found. Using embedded default.json.\n", path)
65+
return loadEmbeddedCollection("collections/default.json")
66+
}
67+
5568
if err != nil {
5669
return nil, fmt.Errorf("stat path %s: %w", path, err)
5770
}
5871

5972
var allCollections []CollectionDefinition
6073

74+
// 3. Normal Disk Loading Logic
6175
if info.IsDir() {
6276
entries, err := os.ReadDir(path)
6377
if err != nil {
@@ -72,12 +86,10 @@ func LoadCollections(path string, loadDefault bool) (*CollectionsFile, error) {
7286
isDefault := strings.EqualFold(entry.Name(), "default.json")
7387

7488
if loadDefault {
75-
// Mode: Default Workload -> Load ONLY default.json
7689
if !isDefault {
7790
continue
7891
}
7992
} else {
80-
// Mode: Custom Workload -> Load EVERYTHING ELSE
8193
if isDefault {
8294
continue
8395
}
@@ -91,7 +103,7 @@ func LoadCollections(path string, loadDefault bool) (*CollectionsFile, error) {
91103
allCollections = append(allCollections, loaded.Collections...)
92104
}
93105
} else {
94-
// Single file: Always load it (explicit user choice).
106+
// Single file path provided by user
95107
loaded, err := loadCollectionsFromFile(path)
96108
if err != nil {
97109
return nil, err
@@ -102,12 +114,25 @@ func LoadCollections(path string, loadDefault bool) (*CollectionsFile, error) {
102114
return &CollectionsFile{Collections: allCollections}, nil
103115
}
104116

117+
// loadEmbeddedCollection reads a specific file from the embedded FS
118+
func loadEmbeddedCollection(embedPath string) (*CollectionsFile, error) {
119+
b, err := resources.Defaults.ReadFile(embedPath)
120+
if err != nil {
121+
return nil, fmt.Errorf("failed to read embedded file %s: %w", embedPath, err)
122+
}
123+
return parseCollectionsBytes(b)
124+
}
125+
105126
func loadCollectionsFromFile(path string) (*CollectionsFile, error) {
106127
b, err := os.ReadFile(path)
107128
if err != nil {
108129
return nil, fmt.Errorf("read collections file: %w", err)
109130
}
131+
return parseCollectionsBytes(b)
132+
}
110133

134+
// Common parsing logic for both Disk and Embed
135+
func parseCollectionsBytes(b []byte) (*CollectionsFile, error) {
111136
var wrapped CollectionsFile
112137
if err := json.Unmarshal(b, &wrapped); err == nil && len(wrapped.Collections) > 0 {
113138
return &wrapped, nil
@@ -118,5 +143,5 @@ func loadCollectionsFromFile(path string) (*CollectionsFile, error) {
118143
return &CollectionsFile{Collections: arr}, nil
119144
}
120145

121-
return nil, fmt.Errorf("invalid collections format in %s", path)
146+
return nil, fmt.Errorf("invalid collections format")
122147
}

internal/config/queries.go

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import (
66
"os"
77
"path/filepath"
88
"strings"
9+
10+
"github.com/Percona-Lab/percona-load-generator-mongodb/resources"
911
)
1012

1113
type QueryDefinition struct {
@@ -32,13 +34,23 @@ func LoadQueries(path string, loadDefault bool) (*QueriesFile, error) {
3234
if path == "" {
3335
return &QueriesFile{}, nil
3436
}
37+
38+
// 1. Try to access the folder on disk
3539
info, err := os.Stat(path)
40+
41+
// 2. Fallback Logic
42+
if os.IsNotExist(err) {
43+
fmt.Printf("Warning: Queries path '%s' not found. Using embedded default.json.\n", path)
44+
return loadEmbeddedQuery("queries/default.json")
45+
}
46+
3647
if err != nil {
3748
return nil, fmt.Errorf("stat path %s: %w", path, err)
3849
}
3950

4051
var allQueries []QueryDefinition
4152

53+
// 3. Normal Disk Loading Logic
4254
if info.IsDir() {
4355
entries, err := os.ReadDir(path)
4456
if err != nil {
@@ -53,12 +65,10 @@ func LoadQueries(path string, loadDefault bool) (*QueriesFile, error) {
5365
isDefault := strings.EqualFold(entry.Name(), "default.json")
5466

5567
if loadDefault {
56-
// Mode: Default Workload -> Load ONLY default.json
5768
if !isDefault {
5869
continue
5970
}
6071
} else {
61-
// Mode: Custom Workload -> Load EVERYTHING ELSE
6272
if isDefault {
6373
continue
6474
}
@@ -72,7 +82,6 @@ func LoadQueries(path string, loadDefault bool) (*QueriesFile, error) {
7282
allQueries = append(allQueries, loaded.Queries...)
7383
}
7484
} else {
75-
// Single file: Always load it.
7685
loaded, err := loadQueriesFromFile(path)
7786
if err != nil {
7887
return nil, err
@@ -83,6 +92,20 @@ func LoadQueries(path string, loadDefault bool) (*QueriesFile, error) {
8392
return &QueriesFile{Queries: allQueries}, nil
8493
}
8594

95+
// loadEmbeddedQuery reads from embedded FS
96+
func loadEmbeddedQuery(embedPath string) (*QueriesFile, error) {
97+
b, err := resources.Defaults.ReadFile(embedPath)
98+
if err != nil {
99+
return nil, fmt.Errorf("failed to read embedded file %s: %w", embedPath, err)
100+
}
101+
102+
var defs []QueryDefinition
103+
if err := json.Unmarshal(b, &defs); err != nil {
104+
return nil, fmt.Errorf("invalid JSON format for embedded queries: %w", err)
105+
}
106+
return &QueriesFile{Queries: defs}, nil
107+
}
108+
86109
func loadQueriesFromFile(path string) (*QueriesFile, error) {
87110
b, err := os.ReadFile(path)
88111
if err != nil {

resources/resources.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package resources
2+
3+
import "embed"
4+
5+
//go:embed collections/default.json queries/default.json
6+
var Defaults embed.FS

0 commit comments

Comments
 (0)