docs: Verify/review config descriptions (#1960)

- Reviewed and modified descriptions.
- Added some minor formatting.
- Removed the "Key:" before every key name, seems redundant.
This commit is contained in:
Maria Shodunke
2025-04-09 17:49:11 +01:00
committed by GitHub
parent fcd891148b
commit 4a5fee7548
12 changed files with 785 additions and 605 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -18,7 +18,8 @@ Clio needs access to a `rippled` server in order to work. The following configur
- A port to handle gRPC requests, with the IP(s) of Clio specified in the `secure_gateway` entry
The example configs of [rippled](https://github.com/XRPLF/rippled/blob/develop/cfg/rippled-example.cfg) and [Clio](../docs/examples/config/example-config.json) are set up in a way that minimal changes are required.
The example configs of [rippled](https://github.com/XRPLF/rippled/blob/develop/cfg/rippled-example.cfg) and [Clio](../docs/examples/config/example-config.json) are set up in a way that minimal changes are required. However, if you want to view all configuration keys available in Clio, see [config-description.md](./config-description.md).
When running locally, the only change needed is to uncomment the `port_grpc` section of the `rippled` config.
If you're running Clio and `rippled` on separate machines, in addition to uncommenting the `port_grpc` section, a few other steps must be taken:

View File

@@ -185,7 +185,7 @@ ETLService::publishNextSequence(uint32_t nextSequence)
if (!success) {
LOG(log_.warn()) << "Failed to publish ledger with sequence = " << nextSequence << " . Beginning ETL";
// returns the most recent sequence published empty optional if no sequence was published
// returns the most recent sequence published. empty optional if no sequence was published
std::optional<uint32_t> lastPublished = runETLPipeline(nextSequence, extractorThreads_);
LOG(log_.info()) << "Aborting ETL. Falling back to publishing";
@@ -283,7 +283,6 @@ ETLService::ETLService(
finishSequence_ = config.maybeValue<uint32_t>("finish_sequence");
state_.isReadOnly = config.get<bool>("read_only");
extractorThreads_ = config.get<uint32_t>("extractor_threads");
txnThreshold_ = config.get<std::size_t>("txn_threshold");
// This should probably be done in the backend factory but we don't have state available until here
backend_->setCorruptionDetector(CorruptionDetector{state_, backend->cache()});

View File

@@ -117,7 +117,6 @@ class ETLService : public etlng::ETLServiceInterface, ETLServiceTag {
size_t numMarkers_ = 2;
std::optional<uint32_t> startSequence_;
std::optional<uint32_t> finishSequence_;
size_t txnThreshold_ = 0;
public:
/**

View File

@@ -208,7 +208,7 @@ private:
void
print(std::ostream& stream) const override
{
stream << fmt::format("The minimum value is `{}`. The maximum value is `{}", kPORT_MIN, kPORT_MAX);
stream << fmt::format("The minimum value is `{}`. The maximum value is `{}`.", kPORT_MIN, kPORT_MAX);
}
static constexpr uint32_t kPORT_MIN = 1;
@@ -249,7 +249,7 @@ private:
void
print(std::ostream& stream) const override
{
stream << "The value must be a valid IP address";
stream << "The value must be a valid IP address.";
}
};
@@ -313,7 +313,13 @@ private:
void
print(std::ostream& stream) const override
{
stream << fmt::format("The value must be one of the following: `{}`", fmt::join(arr_, ", "));
std::string valuesStream;
std::ranges::for_each(arr_, [&valuesStream](std::string const& elem) {
valuesStream += fmt::format(" `{}`,", elem);
});
// replace the last "," with "."
valuesStream.back() = '.';
stream << fmt::format("The value must be one of the following:{}", valuesStream);
}
std::string_view key_;
@@ -376,7 +382,7 @@ private:
void
print(std::ostream& stream) const override
{
stream << fmt::format("The minimum value is `{}`. The maximum value is `{}`", min_, max_);
stream << fmt::format("The minimum value is `{}`. The maximum value is `{}`.", min_, max_);
}
NumType min_;
@@ -417,7 +423,7 @@ private:
void
print(std::ostream& stream) const override
{
stream << fmt::format("The value must be a positive double number");
stream << "The value must be a positive double number.";
}
};
@@ -433,21 +439,15 @@ static constinit OneOf gValidateProcessingPolicy{"server.processing_policy", kPR
static constinit PositiveDouble gValidatePositiveDouble{};
static constinit NumberValueConstraint<uint32_t> gValidateNumMarkers{1, 256};
static constinit NumberValueConstraint<uint32_t> gValidateIOThreads{1, std::numeric_limits<uint16_t>::max()};
static constinit NumberValueConstraint<uint16_t> gValidateNumMarkers{1, 256};
static constinit NumberValueConstraint<uint16_t> gValidateNumCursors{0, std::numeric_limits<uint16_t>::max()};
static constinit NumberValueConstraint<uint16_t> gValidateUint16{
std::numeric_limits<uint16_t>::min(),
std::numeric_limits<uint16_t>::max()
};
// replication factor can be 0
static constinit NumberValueConstraint<uint16_t> gValidateReplicationFactor{0, std::numeric_limits<uint16_t>::max()};
// log file size minimum is 1mb, log rotation time minimum is 1hr
static constinit NumberValueConstraint<uint32_t> gValidateLogSize{1, std::numeric_limits<uint32_t>::max()};
static constinit NumberValueConstraint<uint32_t> gValidateLogRotationTime{1, std::numeric_limits<uint32_t>::max()};
static constinit NumberValueConstraint<uint32_t> gValidateUint32{
std::numeric_limits<uint32_t>::min(),
std::numeric_limits<uint32_t>::max()
};
static constinit NumberValueConstraint<uint16_t> gValidateUint16{1, std::numeric_limits<uint16_t>::max()};
static constinit NumberValueConstraint<uint32_t> gValidateUint32{1, std::numeric_limits<uint32_t>::max()};
static constinit NumberValueConstraint<uint32_t> gValidateApiVersion{rpc::kAPI_VERSION_MIN, rpc::kAPI_VERSION_MAX};
} // namespace util::config

View File

@@ -266,7 +266,7 @@ static ClioConfigDefinition gClioConfig = ClioConfigDefinition{
{"database.cassandra.port", ConfigValue{ConfigType::Integer}.withConstraint(gValidatePort).optional()},
{"database.cassandra.keyspace", ConfigValue{ConfigType::String}.defaultValue("clio")},
{"database.cassandra.replication_factor",
ConfigValue{ConfigType::Integer}.defaultValue(3u).withConstraint(gValidateUint16)},
ConfigValue{ConfigType::Integer}.defaultValue(3u).withConstraint(gValidateReplicationFactor)},
{"database.cassandra.table_prefix", ConfigValue{ConfigType::String}.optional()},
{"database.cassandra.max_write_requests_outstanding",
ConfigValue{ConfigType::Integer}.defaultValue(10'000).withConstraint(gValidateUint32)},
@@ -321,7 +321,7 @@ static ClioConfigDefinition gClioConfig = ClioConfigDefinition{
.withConstraint(gValidateUint32)},
{"server.ip", ConfigValue{ConfigType::String}.withConstraint(gValidateIp)},
{"server.port", ConfigValue{ConfigType::Integer}.withConstraint(gValidatePort)},
{"server.max_queue_size", ConfigValue{ConfigType::Integer}.defaultValue(0).withConstraint(gValidateUint32)},
{"server.max_queue_size", ConfigValue{ConfigType::Integer}.defaultValue(1).withConstraint(gValidateUint32)},
{"server.local_admin", ConfigValue{ConfigType::Boolean}.optional()},
{"server.admin_password", ConfigValue{ConfigType::String}.optional()},
{"server.processing_policy",
@@ -334,7 +334,7 @@ static ClioConfigDefinition gClioConfig = ClioConfigDefinition{
{"prometheus.enabled", ConfigValue{ConfigType::Boolean}.defaultValue(true)},
{"prometheus.compress_reply", ConfigValue{ConfigType::Boolean}.defaultValue(true)},
{"io_threads", ConfigValue{ConfigType::Integer}.defaultValue(2).withConstraint(gValidateIOThreads)},
{"io_threads", ConfigValue{ConfigType::Integer}.defaultValue(2).withConstraint(gValidateUint16)},
{"subscription_workers", ConfigValue{ConfigType::Integer}.defaultValue(1).withConstraint(gValidateUint32)},
@@ -342,9 +342,10 @@ static ClioConfigDefinition gClioConfig = ClioConfigDefinition{
{"cache.num_diffs", ConfigValue{ConfigType::Integer}.defaultValue(32).withConstraint(gValidateUint16)},
{"cache.num_markers", ConfigValue{ConfigType::Integer}.defaultValue(48).withConstraint(gValidateUint16)},
{"cache.num_cursors_from_diff", ConfigValue{ConfigType::Integer}.defaultValue(0).withConstraint(gValidateUint16)},
{"cache.num_cursors_from_account", ConfigValue{ConfigType::Integer}.defaultValue(0).withConstraint(gValidateUint16)
},
{"cache.num_cursors_from_diff",
ConfigValue{ConfigType::Integer}.defaultValue(0).withConstraint(gValidateNumCursors)},
{"cache.num_cursors_from_account",
ConfigValue{ConfigType::Integer}.defaultValue(0).withConstraint(gValidateNumCursors)},
{"cache.page_fetch_size", ConfigValue{ConfigType::Integer}.defaultValue(512).withConstraint(gValidateUint16)},
{"cache.load", ConfigValue{ConfigType::String}.defaultValue("async").withConstraint(gValidateLoadMode)},
@@ -364,13 +365,12 @@ static ClioConfigDefinition gClioConfig = ClioConfigDefinition{
{"log_directory", ConfigValue{ConfigType::String}.optional()},
{"log_rotation_size", ConfigValue{ConfigType::Integer}.defaultValue(2048).withConstraint(gValidateLogSize)},
{"log_rotation_size", ConfigValue{ConfigType::Integer}.defaultValue(2048).withConstraint(gValidateUint32)},
{"log_directory_max_size",
ConfigValue{ConfigType::Integer}.defaultValue(50 * 1024).withConstraint(gValidateLogSize)},
{"log_directory_max_size", ConfigValue{ConfigType::Integer}.defaultValue(50 * 1024).withConstraint(gValidateUint32)
},
{"log_rotation_hour_interval",
ConfigValue{ConfigType::Integer}.defaultValue(12).withConstraint(gValidateLogRotationTime)},
{"log_rotation_hour_interval", ConfigValue{ConfigType::Integer}.defaultValue(12).withConstraint(gValidateUint32)},
{"log_tag_style", ConfigValue{ConfigType::String}.defaultValue("none").withConstraint(gValidateLogTag)},
@@ -378,8 +378,6 @@ static ClioConfigDefinition gClioConfig = ClioConfigDefinition{
{"read_only", ConfigValue{ConfigType::Boolean}.defaultValue(false)},
{"txn_threshold", ConfigValue{ConfigType::Integer}.defaultValue(0).withConstraint(gValidateUint16)},
{"start_sequence", ConfigValue{ConfigType::Integer}.optional().withConstraint(gValidateUint32)},
{"finish_sequence", ConfigValue{ConfigType::Integer}.optional().withConstraint(gValidateUint32)},
@@ -398,7 +396,6 @@ static ClioConfigDefinition gClioConfig = ClioConfigDefinition{
{"migration.full_scan_threads", ConfigValue{ConfigType::Integer}.defaultValue(2).withConstraint(gValidateUint32)},
{"migration.full_scan_jobs", ConfigValue{ConfigType::Integer}.defaultValue(4).withConstraint(gValidateUint32)},
{"migration.cursors_per_job", ConfigValue{ConfigType::Integer}.defaultValue(100).withConstraint(gValidateUint32)}},
};
} // namespace util::config

View File

@@ -110,12 +110,16 @@ public:
static void
writeConfigDescriptionToFile(std::ostream& file)
{
file << "# Clio Config Description\n";
file << "This file lists all Clio Configuration definitions in detail.\n\n";
file << "## Configuration Details\n\n";
file << "# Clio Config Description\n\n";
file << "This document provides a list of all available Clio configuration properties in detail.\n\n";
file << "> [!NOTE]\n";
file << "> Dot notation in configuration key names represents nested fields. For example, "
"**database.scylladb** refers to the _scylladb_ field inside the _database_ object. If a key name "
"includes \"[]\", it indicates that the nested field is an array (e.g., etl_sources.[]).\n\n";
file << "## Configuration Details\n";
for (auto const& [key, val] : kCONFIG_DESCRIPTION) {
file << "### Key: " << key << "\n";
file << "\n### " << key << "\n\n";
// Every type of value is directed to operator<< in ConfigValue.hpp
// as ConfigValue is the one that holds all the info regarding the config values
@@ -124,137 +128,171 @@ public:
} else {
file << gClioConfig.getValueView(key);
}
file << " - **Description**: " << val << "\n";
file << "- **Description**: " << val << "\n";
}
file << "\n";
}
private:
static constexpr auto kCONFIG_DESCRIPTION = std::array{
KV{.key = "database.type",
.value = "Type of database to use. We currently support Cassandra and Scylladb. We default to Scylladb."},
KV{.key = "database.cassandra.contact_points",
.value = "A list of IP addresses or hostnames of the initial nodes (Cassandra/Scylladb cluster nodes) that "
"the client will connect to when establishing a connection with the database. If you're running "
"locally, it should be 'localhost' or 127.0.0.1"},
KV{.key = "database.cassandra.secure_connect_bundle",
.value = "Configuration file that contains the necessary security credentials and connection details for "
"securely "
"connecting to a Cassandra database cluster."},
KV{.key = "database.cassandra.port", .value = "Port number to connect to the database."},
KV{.key = "database.cassandra.keyspace", .value = "Keyspace to use for the database."},
KV{.key = "database.cassandra.replication_factor",
.value = "Number of replicated nodes for Scylladb. Visit this link for more details : "
"https://university.scylladb.com/courses/scylla-essentials-overview/lessons/high-availability/"
"topic/fault-tolerance-replication-factor/ "},
KV{.key = "database.cassandra.table_prefix", .value = "Prefix for Database table names."},
KV{.key = "database.cassandra.max_write_requests_outstanding",
.value = "Maximum number of outstanding write requests. Write requests are api calls that write to database "
},
KV{.key = "database.cassandra.max_read_requests_outstanding",
.value = "Maximum number of outstanding read requests, which reads from database"},
KV{.key = "database.cassandra.threads", .value = "Number of threads that will be used for database operations."
},
KV{.key = "database.cassandra.core_connections_per_host",
.value = "Number of core connections per host for Cassandra."},
KV{.key = "database.cassandra.queue_size_io", .value = "Queue size for I/O operations in Cassandra."},
KV{.key = "database.cassandra.write_batch_size", .value = "Batch size for write operations in Cassandra."},
KV{.key = "database.cassandra.connect_timeout",
.value = "The maximum amount of time in seconds the system will wait for a connection to be successfully "
"established "
"with the database."},
KV{.key = "database.cassandra.request_timeout",
.value =
"The maximum amount of time in seconds the system will wait for a request to be fetched from database."},
"Specifies the type of database used for storing and retrieving data required by the Clio server. Both "
"ScyllaDB and Cassandra can serve as backends for Clio; however, this value must be set to `cassandra`."
},
KV{.key = "database.cassandra.contact_points",
.value = "A list of IP addresses or hostnames for the initial cluster nodes (Cassandra or ScyllaDB) that "
"the client connects to when establishing a database connection. If you're running Clio locally, "
"set this value to `localhost` or `127.0.0.1`."},
KV{.key = "database.cassandra.secure_connect_bundle",
.value = "The configuration file that contains the necessary credentials and connection details for "
"securely connecting to a Cassandra database cluster."},
KV{.key = "database.cassandra.port", .value = "The port number used to connect to the Cassandra database."},
KV{.key = "database.cassandra.keyspace",
.value = "The Cassandra keyspace to use for the database. If you don't provide a value, this is set to "
"`clio` by default."},
KV{.key = "database.cassandra.replication_factor",
.value = "Represents the number of replicated nodes for ScyllaDB. For more details see [Fault Tolerance "
"Replication "
"Factor](https://university.scylladb.com/courses/scylla-essentials-overview/lessons/"
"high-availability/topic/fault-tolerance-replication-factor/)."},
KV{.key = "database.cassandra.table_prefix",
.value = "An optional field to specify a prefix for the Cassandra database table names."},
KV{.key = "database.cassandra.max_write_requests_outstanding",
.value = "Represents the maximum number of outstanding write requests. Write requests are API calls that "
"write to the database."},
KV{.key = "database.cassandra.max_read_requests_outstanding",
.value =
"Maximum number of outstanding read requests. Read requests are API calls that read from the database."},
KV{.key = "database.cassandra.threads",
.value = "Represents the number of threads that will be used for database operations."},
KV{.key = "database.cassandra.core_connections_per_host",
.value = "The number of core connections per host for the Cassandra database."},
KV{.key = "database.cassandra.queue_size_io",
.value = "Defines the queue size of the input/output (I/O) operations in Cassandra."},
KV{.key = "database.cassandra.write_batch_size",
.value = "Represents the batch size for write operations in Cassandra."},
KV{.key = "database.cassandra.connect_timeout",
.value = "The maximum amount of time in seconds that the system waits for a database connection to be "
"established."},
KV{.key = "database.cassandra.request_timeout",
.value = "The maximum amount of time in seconds that the system waits for a request to be fetched from the "
"database."},
KV{.key = "database.cassandra.username", .value = "The username used for authenticating with the database."},
KV{.key = "database.cassandra.password", .value = "The password used for authenticating with the database."},
KV{.key = "database.cassandra.certfile",
.value = "The path to the SSL/TLS certificate file used to establish a secure connection between the client "
"and the "
"Cassandra database."},
KV{.key = "allow_no_etl", .value = "If True, no ETL nodes will run with Clio."},
KV{.key = "etl_sources.[].ip", .value = "IP address of the ETL source."},
KV{.key = "etl_sources.[].ws_port", .value = "WebSocket port of the ETL source."},
KV{.key = "etl_sources.[].grpc_port", .value = "gRPC port of the ETL source."},
"and the Cassandra database."},
KV{.key = "allow_no_etl", .value = "If set to `True`, allows Clio to start without any ETL source."},
KV{.key = "etl_sources.[].ip", .value = "The IP address of the ETL source."},
KV{.key = "etl_sources.[].ws_port", .value = "The WebSocket port of the ETL source."},
KV{.key = "etl_sources.[].grpc_port", .value = "The gRPC port of the ETL source."},
KV{.key = "forwarding.cache_timeout",
.value = "Timeout duration for the forwarding cache used in Rippled communication."},
.value = "Specifies the timeout duration (in seconds) for the forwarding cache used in `rippled` "
"communication. A value of `0` means disabling this feature."},
KV{.key = "forwarding.request_timeout",
.value = "Timeout duration for the forwarding request used in Rippled communication."},
KV{.key = "rpc.cache_timeout", .value = "Timeout duration for RPC requests."},
KV{.key = "num_markers",
.value = "The number of markers is the number of coroutines to download the initial ledger"},
KV{.key = "dos_guard.whitelist.[]", .value = "List of IP addresses to whitelist for DOS protection."},
KV{.key = "dos_guard.max_fetches", .value = "Maximum number of fetch operations allowed by DOS guard."},
KV{.key = "dos_guard.max_connections", .value = "Maximum number of concurrent connections allowed by DOS guard."
},
KV{.key = "dos_guard.max_requests", .value = "Maximum number of requests allowed by DOS guard."},
KV{.key = "dos_guard.sweep_interval", .value = "Interval in seconds for DOS guard to sweep/clear its state."},
KV{.key = "workers", .value = "Number of threads to process RPC requests."},
KV{.key = "server.ip", .value = "IP address of the Clio HTTP server."},
KV{.key = "server.port", .value = "Port number of the Clio HTTP server."},
KV{.key = "server.max_queue_size",
.value = "Maximum size of the server's request queue. Value of 0 is no limit."},
KV{.key = "server.local_admin",
.value = "Indicates if the server should run with admin privileges. Only one of local_admin or "
"admin_password can be set."},
KV{.key = "server.admin_password",
.value = "Password for Clio admin-only APIs. Only one of local_admin or admin_password can be set."},
KV{.key = "server.processing_policy",
.value = R"(Could be "sequent" or "parallel". For the sequent policy, requests from a single client
connection are processed one by one, with the next request read only after the previous one is processed. For the parallel policy, Clio will accept
all requests and process them in parallel, sending a reply for each request as soon as it is ready.)"},
KV{.key = "server.parallel_requests_limit",
.value =
R"(Optional parameter, used only if processing_strategy `parallel`. It limits the number of requests for a single client connection that are processed in parallel. If not specified, the limit is infinite.)"
"Specifies the timeout duration (in seconds) for the forwarding request used in `rippled` communication."
},
KV{.key = "rpc.cache_timeout",
.value = "Specifies the timeout duration (in seconds) for RPC cache response to timeout. A value of `0` "
"means disabling this feature."},
KV{.key = "num_markers", .value = "Specifies the number of coroutines used to download the initial ledger."},
KV{.key = "dos_guard.whitelist.[]", .value = "The list of IP addresses to whitelist for DOS protection."},
KV{.key = "dos_guard.max_fetches", .value = "The maximum number of fetch operations allowed by DOS guard."},
KV{.key = "dos_guard.max_connections",
.value = "The maximum number of concurrent connections for a specific IP address."},
KV{.key = "dos_guard.max_requests", .value = "The maximum number of requests allowed for a specific IP address."
},
KV{.key = "dos_guard.sweep_interval", .value = "Interval in seconds for DOS guard to sweep(clear) its state."},
KV{.key = "workers", .value = "The number of threads used to process RPC requests."},
KV{.key = "server.ip", .value = "The IP address of the Clio HTTP server."},
KV{.key = "server.port", .value = "The port number of the Clio HTTP server."},
KV{.key = "server.max_queue_size",
.value =
"The maximum size of the server's request queue. If set to `0`, this means there is no queue size limit."
},
KV{.key = "server.local_admin",
.value = "Indicates if requests from `localhost` are allowed to call Clio admin-only APIs. Note that this "
"setting cannot be enabled "
"together with [server.admin_password](#serveradmin_password)."},
KV{.key = "server.admin_password",
.value = "The password for Clio admin-only APIs. Note that this setting cannot be enabled together with "
"[server.local_admin](#serveradmin_password)."},
KV{.key = "server.processing_policy",
.value = "For the `sequent` policy, requests from a single client connection are processed one by one, with "
"the next request read only after the previous one is processed. For the `parallel` policy, Clio "
"will accept all requests and process them in parallel, sending a reply for each request as soon "
"as it is ready."},
KV{.key = "server.parallel_requests_limit",
.value = "This is an optional parameter, used only if the `processing_strategy` is `parallel`. It limits "
"the number of requests processed in parallel for a single client connection. If not specified, no "
"limit is enforced."},
KV{.key = "server.ws_max_sending_queue_size",
.value = "Maximum queue size for sending subscription data to clients. This queue buffers data when a "
"client is slow to receive it, ensuring delivery once the client is ready."},
KV{.key = "prometheus.enabled", .value = "Enables or disables Prometheus metrics."},
KV{.key = "prometheus.compress_reply", .value = "Enables or disables compression of Prometheus responses."},
KV{.key = "io_threads", .value = "The number of input/output (I/O) threads. The value cannot be less than `1`."
},
KV{.key = "server.ws_max_sending_queue_size", .value = "Maximum size of the websocket sending queue."},
KV{.key = "prometheus.enabled", .value = "Enable or disable Prometheus metrics."},
KV{.key = "prometheus.compress_reply", .value = "Enable or disable compression of Prometheus responses."},
KV{.key = "io_threads", .value = "Number of I/O threads. Value cannot be less than 1"},
KV{.key = "subscription_workers",
.value = "The number of worker threads or processes that are responsible for managing and processing "
"subscription-based tasks from rippled"},
KV{.key = "graceful_period", .value = "Number of milliseconds server will wait to shutdown gracefully."},
KV{.key = "cache.num_diffs", .value = "Number of diffs to cache. For more info, consult readme.md in etc"},
KV{.key = "cache.num_markers", .value = "Number of markers to cache."},
KV{.key = "cache.num_cursors_from_diff", .value = "Num of cursors that are different."},
KV{.key = "cache.num_cursors_from_account", .value = "Number of cursors from an account."},
KV{.key = "cache.page_fetch_size", .value = "Page fetch size for cache operations."},
KV{.key = "cache.load", .value = "Cache loading strategy ('sync' or 'async')."},
KV{.key = "log_channels.[].channel",
.value = "Name of the log channel."
"'RPC', 'ETL', and 'Performance'"},
KV{.key = "log_channels.[].log_level",
.value = "Log level for the specific log channel."
"`warning`, `error`, `fatal`"},
"subscription-based tasks from `rippled`."},
KV{.key = "graceful_period",
.value = "The number of milliseconds the server waits to shutdown gracefully. If Clio does not shutdown "
"gracefully after the specified value, it will be killed instead."},
KV{.key = "cache.num_diffs",
.value = "The number of cursors generated is the number of changed (without counting deleted) objects in "
"the latest `cache.num_diffs` number of ledgers. Cursors are workers that load the ledger cache "
"from the position of markers concurrently. For more information, please read "
"[README.md](../src/etl/README.md)."},
KV{.key = "cache.num_markers",
.value = " Specifies how many markers are placed randomly within the cache. These markers define the "
"positions on the ledger that will be loaded concurrently by the workers. The higher the number, "
"the more places within the cache we potentially cover."},
KV{.key = "cache.num_cursors_from_diff",
.value = "`cache.num_cursors_from_diff` number of cursors are generated by looking at the number of changed "
"objects in the most recent ledger. If number of changed objects in current ledger is not enough, "
"it will keep reading previous ledgers until it hit `cache.num_cursors_from_diff`. If set to `0`, "
"the system defaults to generating cursors based on `cache.num_diffs`."},
KV{.key = "cache.num_cursors_from_account",
.value = "`cache.num_cursors_from_diff` of cursors are generated by reading accounts in `account_tx` table. "
"If set to `0`, the system defaults to generating cursors based on `cache.num_diffs`."},
KV{.key = "cache.page_fetch_size", .value = "The number of ledger objects to fetch concurrently per marker."},
KV{.key = "cache.load", .value = "The strategy used for Cache loading."},
KV{.key = "log_channels.[].channel", .value = "The name of the log channel."},
KV{.key = "log_channels.[].log_level", .value = "The log level for the specific log channel."},
KV{.key = "log_level",
.value = "General logging level of Clio. This level will be applied to all log channels that do not have an "
.value = "The general logging level of Clio. This level is applied to all log channels that do not have an "
"explicitly defined logging level."},
KV{.key = "log_format", .value = "Format string for log messages."},
KV{.key = "log_to_console", .value = "Enable or disable logging to console."},
KV{.key = "log_directory", .value = "Directory path for log files."},
KV{.key = "log_format",
.value = "The format string for log messages. The format is described here: "
"https://www.boost.org/doc/libs/1_83_0/libs/log/doc/html/log/tutorial/formatters.html."},
KV{.key = "log_to_console", .value = "Enables or disables logging to the console."},
KV{.key = "log_directory", .value = "The directory path for the log files."},
KV{.key = "log_rotation_size",
.value =
"Log rotation size in megabytes. When the log file reaches this particular size, a new log file starts."
},
KV{.key = "log_directory_max_size", .value = "Maximum size of the log directory in megabytes."},
.value = "The log rotation size in megabytes. When the log file reaches this particular size, a new log "
"file starts."},
KV{.key = "log_directory_max_size", .value = "The maximum size of the log directory in megabytes."},
KV{.key = "log_rotation_hour_interval",
.value = "Interval in hours for log rotation. If the current log file reaches this value in logging, a new "
"log file starts."},
KV{.key = "log_tag_style", .value = "Style for log tags."},
KV{.key = "extractor_threads", .value = "Number of extractor threads."},
KV{.key = "read_only", .value = "Indicates if the server should have read-only privileges."},
KV{.key = "txn_threshold", .value = "Transaction threshold value."},
KV{.key = "start_sequence", .value = "Starting ledger index."},
KV{.key = "finish_sequence", .value = "Ending ledger index."},
KV{.key = "ssl_cert_file", .value = "Path to the SSL certificate file."},
KV{.key = "ssl_key_file", .value = "Path to the SSL key file."},
KV{.key = "api_version.default", .value = "Default API version Clio will run on."},
KV{.key = "api_version.min", .value = "Minimum API version."},
KV{.key = "api_version.max", .value = "Maximum API version."},
.value = "Represents the interval (in hours) for log rotation. If the current log file reaches this value "
"in logging, a new log file starts."},
KV{.key = "log_tag_style",
.value =
"Log tags are unique identifiers for log messages. `uint`/`int` starts logging from 0 and increments, "
"making it faster. In contrast, `uuid` generates a random unique identifier, which adds overhead."},
KV{.key = "extractor_threads", .value = "Number of threads used to extract data from ETL source."},
KV{.key = "read_only", .value = "Indicates if the server is allowed to write data to the database."},
KV{.key = "start_sequence",
.value = "If specified, the ledger index Clio will start writing to the database from."},
KV{.key = "finish_sequence", .value = "If specified, the final ledger that Clio will write to the database."},
KV{.key = "ssl_cert_file", .value = "The path to the SSL certificate file."},
KV{.key = "ssl_key_file", .value = "The path to the SSL key file."},
KV{.key = "api_version.default", .value = "The default API version that the Clio server will run on."},
KV{.key = "api_version.min", .value = "The minimum API version allowed to use."},
KV{.key = "api_version.max", .value = "The maximum API version allowed to use."},
KV{.key = "migration.full_scan_threads", .value = "The number of threads used to scan the table."},
KV{.key = "migration.full_scan_jobs", .value = "The number of coroutines used to scan the table."},
KV{.key = "migration.cursors_per_job", .value = "The number of cursors each coroutine will scan."}
KV{.key = "migration.cursors_per_job", .value = "The number of cursors each job will scan."}
};
};

View File

@@ -217,8 +217,10 @@ public:
stream << "- **Type**: " << val.type() << "\n";
if (val.description_.has_value()) {
stream << "- **Default value**: " << *val.description_ << "\n";
} else if (val.hasValue()) {
stream << "- **Default value**: `" << *val.value_ << "`\n";
} else {
stream << "- **Default value**: " << (val.hasValue() ? *val.value_ : "None") << "\n";
stream << "- **Default value**: None\n";
}
stream << "- **Constraints**: ";

View File

@@ -97,13 +97,13 @@ protected:
{"log_directory", ConfigValue{ConfigType::String}.optional()},
{"log_rotation_size",
ConfigValue{ConfigType::Integer}.defaultValue(2048).withConstraint(config::gValidateLogSize)},
ConfigValue{ConfigType::Integer}.defaultValue(2048).withConstraint(config::gValidateUint32)},
{"log_directory_max_size",
ConfigValue{ConfigType::Integer}.defaultValue(50 * 1024).withConstraint(config::gValidateLogSize)},
ConfigValue{ConfigType::Integer}.defaultValue(50 * 1024).withConstraint(config::gValidateUint32)},
{"log_rotation_hour_interval",
ConfigValue{ConfigType::Integer}.defaultValue(12).withConstraint(config::gValidateLogRotationTime)},
ConfigValue{ConfigType::Integer}.defaultValue(12).withConstraint(config::gValidateUint32)},
{"log_tag_style", ConfigValue{ConfigType::String}.defaultValue("none")},
};

View File

@@ -213,7 +213,10 @@ TEST_F(CliArgsTestsWithTmpFile, Parse_ConfigDescriptionFileContent)
auto const fileContent = buffer.str();
EXPECT_TRUE(fileContent.find("# Clio Config Description") != std::string::npos);
EXPECT_TRUE(fileContent.find("This file lists all Clio Configuration definitions in detail.") != std::string::npos);
EXPECT_TRUE(
fileContent.find("This document provides a list of all available Clio configuration properties in detail.") !=
std::string::npos
);
EXPECT_TRUE(fileContent.find("## Configuration Details") != std::string::npos);
// all keys that exist in clio config should be listed in config description file

View File

@@ -173,10 +173,11 @@ TEST(ConfigDescription, GetValues)
EXPECT_EQ(
definition.get("database.type"),
"Type of database to use. We currently support Cassandra and Scylladb. We default to Scylladb."
"Specifies the type of database used for storing and retrieving data required by the Clio server. Both "
"ScyllaDB and Cassandra can serve as backends for Clio; however, this value must be set to `cassandra`."
);
EXPECT_EQ(definition.get("etl_sources.[].ip"), "IP address of the ETL source.");
EXPECT_EQ(definition.get("prometheus.enabled"), "Enable or disable Prometheus metrics.");
EXPECT_EQ(definition.get("etl_sources.[].ip"), "The IP address of the ETL source.");
EXPECT_EQ(definition.get("prometheus.enabled"), "Enables or disables Prometheus metrics.");
}
struct ConfigDescriptionAssertTest : common::util::WithMockAssert {};

View File

@@ -236,7 +236,7 @@ TEST_F(ConstraintTest, SetValuesOnNumberConstraint)
auto positiveNum = ConfigValue{ConfigType::Integer}.defaultValue(20u).withConstraint(gValidateUint16);
auto const err = positiveNum.setValue(-22, "key");
EXPECT_TRUE(err.has_value());
EXPECT_EQ(err->error, fmt::format("key Number must be between {} and {}", 0, 65535));
EXPECT_EQ(err->error, fmt::format("key Number must be between {} and {}", 1, 65535));
EXPECT_FALSE(positiveNum.setValue(99, "key"));
}
@@ -268,7 +268,7 @@ INSTANTIATE_TEST_SUITE_P(
ConstraintTestBundle{"ipConstraint", gValidateIp},
ConstraintTestBundle{"channelConstraint", gValidateChannelName},
ConstraintTestBundle{"logLevelConstraint", gValidateLogLevelName},
ConstraintTestBundle{"cannsandraNameCnstraint", gValidateCassandraName},
ConstraintTestBundle{"cassandraNameConstraint", gValidateCassandraName},
ConstraintTestBundle{"loadModeConstraint", gValidateLoadMode},
ConstraintTestBundle{"ChannelNameConstraint", gValidateChannelName},
ConstraintTestBundle{"ApiVersionConstraint", gValidateApiVersion},