diff --git a/.gitignore b/.gitignore index f03cd376..cc34382a 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,6 @@ tests/integration/ace_tasks.db # Added by goreleaser init: dist/ +# Local config generated by `ace config init` (the tracked template is ace.example.yaml) +/ace.yaml +/pg_service.conf diff --git a/Dockerfile b/Dockerfile index 101f70ca..c944e274 100644 --- a/Dockerfile +++ b/Dockerfile @@ -44,7 +44,7 @@ COPY --from=downloader --chown=nonroot:nonroot /opt/ace/ace /usr/local/bin/ace COPY --from=downloader /opt/ace/LICENSE /licenses/LICENSE COPY --from=downloader /opt/ace/README.md /licenses/README.md -COPY --chown=nonroot:nonroot ace.yaml /etc/ace/ace.yaml +COPY --chown=nonroot:nonroot ace.example.yaml /etc/ace/ace.yaml ENV ACE_CONFIG=/etc/ace/ace.yaml diff --git a/README.md b/README.md index 557c1180..0dc11e74 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,7 @@ Set the `default_cluster` key in `ace.yaml` to the cluster name you most frequen For detailed information about creating and modifying ACE configuration files, visit [here](/docs/configuration.md). -The [`ace.yaml` file](ace.yaml) defines default values used when executing ACE commands like `table-diff` or `mtree table-diff`. You can modify properties that influence ACE performance and execution like timeout values and certificate information. +The [`ace.example.yaml` file](ace.example.yaml) is a reference copy of the configuration, showing the default values used when executing ACE commands like `table-diff` or `mtree table-diff`. In your own `ace.yaml`, you can modify properties that influence ACE performance and execution like timeout values and certificate information. The `pg_service.conf` file contains cluster connection details that help ACE locate nodes. After creating the file: diff --git a/ace.yaml b/ace.example.yaml similarity index 98% rename from ace.yaml rename to ace.example.yaml index 44d8fb91..f80dbe35 100644 --- a/ace.yaml +++ b/ace.example.yaml @@ -20,7 +20,7 @@ postgres: tcp_keepalives_count: 5 table_diff: - concurrency_factor: 1 + concurrency_factor: 0.5 max_diff_rows: 1000000 min_diff_block_size: 1 max_diff_block_size: 1000000 @@ -77,6 +77,7 @@ server: tls_key_file: "" client_crl_file: "" allowed_common_names: [] + taskstore_path: "" schedule_jobs: [] schedule_config: [] diff --git a/docs/configuration.md b/docs/configuration.md index 46c54795..81df430e 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -16,7 +16,7 @@ ACE first attempts to use the Postgres service file to resolve connection inform ## The ace.yaml file -The [`ace.yaml` file](https://github.com/pgEdge/ace/blob/main/ace.yaml) defines default values used when calling the ACE commands. The file contains properties that control the resources used by ACE commands; after creating the `ace.yaml` file, use your choice of editor to customize the properties for your system: +The [`ace.example.yaml` file](https://github.com/pgEdge/ace/blob/main/ace.example.yaml) is a reference copy of the configuration that ACE ships, showing the default values used when calling the ACE commands. The file contains properties that control the resources used by ACE commands; after creating your own `ace.yaml` file, use your choice of editor to customize the properties for your system: diff --git a/internal/cli/default_config.yaml b/internal/cli/default_config.yaml index f792a4c5..f80dbe35 100644 --- a/internal/cli/default_config.yaml +++ b/internal/cli/default_config.yaml @@ -28,6 +28,7 @@ table_diff: diff_batch_size: 1 max_diff_batch_size: 1000 compare_unit_size: 10000 + max_connections: 0 # max DB connections per node (0 = derive from concurrency factor) mtree: cdc: @@ -36,6 +37,13 @@ mtree: cdc_processing_timeout: 300 cdc_metadata_flush_seconds: 10 cdc_flush_batch_size: 10000 + # Escalate a table to a whole-tree rehash when a bounded drain sees more + # than max(adaptive_drain_min_changes, adaptive_drain_fraction * rows) + # UPDATE changes for it (inserts/deletes are always tracked individually, + # preserving block split/merge maintenance). Set adaptive_drain_fraction + # to -1 to disable. + adaptive_drain_fraction: 0.01 + adaptive_drain_min_changes: 1000 schema: "pgedge_ace" diff: diff --git a/internal/cli/default_config_test.go b/internal/cli/default_config_test.go new file mode 100644 index 00000000..5656f20b --- /dev/null +++ b/internal/cli/default_config_test.go @@ -0,0 +1,59 @@ +// /////////////////////////////////////////////////////////////////////////// +// +// # ACE - Active Consistency Engine +// +// Copyright (C) 2023 - 2026, pgEdge (https://www.pgedge.com/) +// +// This software is released under the PostgreSQL License: +// https://opensource.org/license/postgresql +// +// /////////////////////////////////////////////////////////////////////////// + +package cli + +import ( + "os" + "testing" + + "gopkg.in/yaml.v3" + + "github.com/pgedge/ace/pkg/config" +) + +// exampleConfigPath is the repo-root reference copy that the README and +// docs/configuration.md link to. It must stay byte-identical to the template +// embedded in ConfigInitCLI, otherwise the documented defaults are not the +// defaults users actually get from `ace config init`. +const exampleConfigPath = "../../ace.example.yaml" + +func TestExampleConfigMatchesEmbeddedTemplate(t *testing.T) { + example, err := os.ReadFile(exampleConfigPath) + if err != nil { + t.Fatalf("read %s: %v", exampleConfigPath, err) + } + + if string(example) != defaultConfigYAML { + t.Errorf( + "%s has drifted from internal/cli/default_config.yaml.\n"+ + "`ace config init` writes the embedded template, so the two must "+ + "match or the documented defaults are wrong.\n"+ + "Run: cp internal/cli/default_config.yaml ace.example.yaml", + exampleConfigPath, + ) + } +} + +// TestDefaultConfigTemplateParses guards against shipping a template that +// fails to load, which would break `ace config init` followed by any command. +func TestDefaultConfigTemplateParses(t *testing.T) { + var cfg config.Config + if err := yaml.Unmarshal([]byte(defaultConfigYAML), &cfg); err != nil { + t.Fatalf("default_config.yaml does not parse into config.Config: %v", err) + } + + // The template must agree with the concurrency-factor default advertised by + // the CLI flag; disagreement is the drift that shipped a documented "1". + if got, want := cfg.TableDiff.ConcurrencyFactor, 0.5; got != want { + t.Errorf("table_diff.concurrency_factor = %v, want %v (matches the --concurrency-factor flag default)", got, want) + } +} diff --git a/tests/integration/main_test.go b/tests/integration/main_test.go index 2860c85d..f393238f 100644 --- a/tests/integration/main_test.go +++ b/tests/integration/main_test.go @@ -377,7 +377,7 @@ func TestMain(m *testing.M) { ) tcLog.SetDefault(log.New(io.Discard, "", 0)) - if err := config.Init("../../ace.yaml"); err != nil { + if err := config.Init("../../ace.example.yaml"); err != nil { log.Fatalf("Failed to load config: %v", err) }