Class DefaultDriverConfigReporter
- java.lang.Object
-
- com.datastax.driver.core.DefaultDriverConfigReporter
-
- All Implemented Interfaces:
DriverConfigReporter
@Beta public class DefaultDriverConfigReporter extends Object implements DriverConfigReporter
DefaultDriverConfigReporter: serializes the driver configuration to the cross-driverDRIVER_CONFIGJSON shape, whichConnection.Factorythen sends in the control connection'sSTARTUPoptions.The report is built afresh for every control connection, from inside its
STARTUPframe assembly, and never cached: it describes the objects that are in force at that handshake rather than the configuration theClusterwas constructed from. That distinction is not theoretical.Cluster.Manager.init()builds theConnection.Factorybefore it callsLoadBalancingPolicy.init(com.datastax.driver.core.Cluster, java.util.Collection<com.datastax.driver.core.Host>), and the first control connection'sSTARTUPgoes out in between — so a datacenter or rack the policy infers from the node it reaches cannot be known on the first report and is known on every later one. A reconnect therefore costs one report build and may legitimately report more than the connection before it did.The report follows the normative cross-driver schema (report
version1): kebab-case keys, nested objects, and omission of any key or group that has no value (nothing is ever emitted asnull). The same applies where a configured value falls outside what the schema can express but the key is optional: a disabled connect timeout, a disabled read timeout, a disabledSO_LINGER, an unbounded page size and a non-serial default serial consistency level are omitted rather than emitted as a value the schema rejects. Two keys are omitted for a third reason — the schema admits only a boolean, and 3.x cannot observe which one applies:query.defaults.client-timestampsfor a timestamp generator that is none of the driver's own, andconnection.tls.hostname-verificationfor anySSLOptionsother thanSniSSLOptions. Both keys are documented as absent when the behavior is unknown, which is exactly the case here: a custom generator decides per call whether to assign a timestamp at all, and every otherSSLOptionsbuilds its engine from a user-suppliedSSLContext(or hands the whole handler over to Netty), so nothing the reporter can read says whether the hostname is checked. Two more optional bounds are omitted for the opposite reason — 3.x simply has no such bound to report:connection.reconnection.policy.max-attempts, since its reconnection policies retry forever, andquery.retry.policy.max-retries, since no single number describes a 3.x retry policy:RetryPolicy.onRequestError(com.datastax.driver.core.Statement, com.datastax.driver.core.ConsistencyLevel, com.datastax.driver.core.exceptions.DriverException, int)is the one path that does not stop after a single retry, and it is only reached for an idempotent statement, so the same policy bounds a non-idempotent request at one retry and an idempotent one at the length of the query plan. Which of the two a statement gets is not configuration —Statement.setIdempotent(boolean)overrides the reportedquery.defaults.idempotenceper statement.Only a token-aware chain has a built-in shape in the schema, whose
query.load-balancing.policy.typeadmitstoken-awareandcustomand nothing else. That shape carries no name, so it is claimed only for a chain every element of which the group can describe; any other chain iscustom, named after every policy in it —WhiteListPolicy(TokenAwarePolicy(DCAwareRoundRobinPolicy))— and keeps the capability keys it can still state, which thecustombranch admits as additional properties. SeeloadBalancingPolicy(java.util.List<com.datastax.driver.core.policies.LoadBalancingPolicy>, com.datastax.driver.core.policies.LoadBalancingPolicy, com.datastax.driver.core.DefaultDriverConfigReporter.NodeLocation). A datacenter and rack are reported inquery.load-balancing.node-preferencewhenever the chain prefers one: from a DC- or rack-aware policy, or from a filter restricting the session to a single datacenter. A bareRoundRobinPolicy, or aWhiteListPolicyover one, prefers neither and both preference keys are omitted.The schema reports that preference in a second, optional place,
connection.node-preference, which describes the part of the cluster the driver holds connections to rather than how a query is routed. OneLoadBalancingPolicydecides both in 3.x, sinceLoadBalancingPolicy.distance(Host)is what governs whether a host is pooled at all, so that key is derived from the same chain — but from its datacenter half alone. A rack-aware policy'sdistance()returnsREMOTE, neverIGNORED, for a local-datacenter host in another rack, so those hosts are still pooled and the rack does not scope what the driver connects to. The datacenter does: a host outside the preferred one isIGNOREDunless the policy is configured to use hosts there, and an ignored host gets no pool at all.That last claim is exact only for the policy the preference was read from. A chainable policy above it can narrow pooling further:
HostFilterPolicy.distance(Host)— and thereforeWhiteListPolicy's — returnsIGNOREDfor any host failing its predicate, including one inside the reported datacenter, and a custom policy computesdistance()itself and need honor nothing the chain below it prefers. The reported datacenter is thus necessary but not sufficient: it is what the located policy prefers, not the whole of what gets a pool. Reported all the same, deliberately, on the grounds that hiding a datacenter the operator really did configure is the worse failure mode — note the asymmetry with the inferred values above, in that nothing is inferred on a third party's behalf while what was explicitly configured is passed through even where a wrapper may override it.A filter that restricts the session to exactly one datacenter is read the other way round:
HostFilterPolicy.fromDCWhiteList(LoadBalancingPolicy, Iterable)retains the datacenters it was given, so when nothing in the chain prefers a datacenter of its own —fromDCWhiteList(new RoundRobinPolicy(), ["dc1"])— the restriction is what decides the preference and is reported as one. Anything a filter can express that names no single datacenter keeps the group omitted: a blacklist, several allowed datacenters, a blank name, aWhiteListPolicy(which filters on addresses), or a caller-suppliedPredicate<Host>, which stays opaque. A filter the preference was not read from — because a location-aware policy below it won — narrows the chain without being stated anywhere, so it costs the chain its built-in shape and is named instead, exactly like any other restricting wrapper.Known limitations: omission is not always available, because these fields are required by the schema.
connection.requests.in-flight.maxmust be positive, whilePoolingOptions.setMaxRequestsPerConnection(HostDistance, int)also accepts 0.query.speculative-execution.policy.percentileis bounded to 0..100 exclusive by the schema, whilePercentileSpeculativeExecutionPolicyaccepts a percentile of 0.
connection.requests.orphaned.maxused to belong to that list and no longer does: 3.x has no orphaned-request setting to report it from — a request the driver stopped waiting for keeps its stream identifier until the response arrives, with no configurable bound and no connection replacement (only 4.x hasadvanced.connection.max-orphan-requests) — and the schema now makes the group optional for exactly that case, so omission is the schema-valid answer.Such a value is reported as-is, and a key with no equivalent stays omitted: the reporter deliberately neither fabricates an in-range value — which would misreport a setting an operator may have chosen on purpose, or a policy 3.x does not implement — nor drops the whole report over one field, so the document is accurate but fails schema validation. Tracked as a cross-driver schema gap: the fix is to let those fields express the value, the way
control-plane.schema.agreement.timeout-msalready admits 0.The read timeout feeds three places, all of them optional, so disabling it omits all three:
connection.read,control-plane.queries.system.timeout.client-side-msandquery.defaults.request.
-
-
Field Summary
Fields Modifier and Type Field Description protected Configurationconfigurationstatic StringDRIVER_CONFIG_KEYSTARTUP option key under which the config JSON is sent.
-
Constructor Summary
Constructors Constructor Description DefaultDriverConfigReporter(Configuration configuration)
-
Method Summary
All Methods Instance Methods Concrete Methods Modifier and Type Method Description protected StringbuildJson()Builds the compact, single-line JSON configuration report.StringbuildReport()Builds the configuration report, or returnsnullif it could not be built (in which case noDRIVER_CONFIGoption is sent).protected voidpopulateConfig(ObjectNode root)Populates the three top-level configuration groups onto the report root fromconfigurationand its policies.
-
-
-
Field Detail
-
DRIVER_CONFIG_KEY
public static final String DRIVER_CONFIG_KEY
STARTUP option key under which the config JSON is sent.- See Also:
- Constant Field Values
-
configuration
protected final Configuration configuration
-
-
Constructor Detail
-
DefaultDriverConfigReporter
public DefaultDriverConfigReporter(Configuration configuration)
-
-
Method Detail
-
buildReport
public String buildReport()
Description copied from interface:DriverConfigReporterBuilds the configuration report, or returnsnullif it could not be built (in which case noDRIVER_CONFIGoption is sent).Called once per control connection, from its
STARTUPframe assembly, and not cached: the report describes the objects in force at the handshake that sends it, rather than the configuration theClusterwas constructed from. Implementations must therefore tolerate being called on a Netty event loop, and repeatedly over a cluster's lifetime.Implementations must not throw: a failure to build the report must be swallowed (and logged) rather than propagated, so that a diagnostic aid can never break cluster initialization. For the same reason they must bound the report's size and return
nullrather than an oversized one:STARTUPoption values carry an unchecked 16-bit length prefix, so a value over 65535 encoded bytes corrupts the frame instead of merely being useless. The built-in reporter caps the report at 32KiB of UTF-8, the limit the other ScyllaDB drivers apply.An implementation that cannot even be loaded is handled one level up rather than here:
DefaultDriverConfigReporterneeds Jackson, and on a classpath without it the failure is aLinkageErrorraised while initializing the class, which no method of this interface could catch.Connection.Factory.buildDriverConfigReportcontains that and reports nothing, so the connection is still established.- Specified by:
buildReportin interfaceDriverConfigReporter- Returns:
- the report to send under the
DRIVER_CONFIGstartup option, ornullto send nothing.
-
buildJson
protected String buildJson()
Builds the compact, single-line JSON configuration report.
-
populateConfig
protected void populateConfig(ObjectNode root)
Populates the three top-level configuration groups onto the report root fromconfigurationand its policies. Keys the driver has no equivalent for (or cannot introspect in 3.x) are omitted rather than emitted asnull.
-
-