Hello everyone,

I would like to share and discuss the key point of the solution design
with you before I finalise a pull request with tedious changes
remaining so that we are all on the same page with the changes to the
valuable Config class and its accessors.

Here is the issue I'm working on:
"Allow UPDATE on settings virtual table to change running configurations".
https://issues.apache.org/jira/browse/CASSANDRA-15254

Below is the restricted solution design at a very high level, all the
details have been discussed in the related JIRA issue.


= What we have now =

- We use JMX MBeans to mutate this runtime configuration during the
node run or to view the configuration values. Some of the JMX MBean
methods use camel case to match configuration field names;
- We use the SettingsTable only to view configuration values at
runtime, but we are not able to mutate the configuration through it;
- We load the configuration from cassandra.yaml into the Config class
instance during the node bootstrap (is accessed with
DatabaseDescriptor, GuardrailsOptions);
- The Config class itself has nested configurations such as
ReplicaFilteringProtectionOptions (it is important to keep this always
in mind);


= What we want to achieve =

We want to use the SettingsTable virtual table to change the runtime
configuration, as we do it now with JMX MBeans, and:
- If the affected component is updated (or the component's logic is
executed) before or after the property change, we want to keep this
behaviour for the virtual table for the same configuration property;
- We want to ensure consistency of such changes between the virtual
table API and the JMX API used;


= The main question =

To enable configuration management with the virtual table, we need to
know the answer to the following key question:
- How can we be sure to determine at runtime which of the properties
we can change and which we can't?


= Options for an answer to the question above =

1. Rely on the volatile keyword in front of fields in the Config class;

I would say this is the most confusing option for me because it
doesn't give us all the guarantees we need, and also:
- We have no explicit control over what exactly we expose to a user.
When we modify the JMX API, we're implementing a new method for the
MBean, which in turn makes this action an explicit exposure;
- The volatile keyword is not the only way to achieve thread safety,
and looks strange for the public API design point;
- A good example is the setEnableDropCompactStorage method, which
changes the volatile field, but is only visible for testing purposes;

2. Annotation-based exposition.

I have created Exposure(Exposure.Policy.READ_ONLY),
Exposure(Exposure.Policy.READ_WRITE) annotations to mark all the
configuration fields we are going to expose to the public API (JMX, as
well as the SettingsTable) in the Config class. All the configuration
fields (in the Config class and any nested classes) that we want to
expose (and already are used by JMX) need to tag with an annotation of
the appropriate type.

The most confusing thing here, apart from the number of tedious
changes: we are using reflection to mutate configuration field values
at runtime, which makes some of the fields look "unused" in the IDE.
This can be not very pleasant for developers looking at the Config
class for the first time.

You can find the PR related to this type of change here (only a few
configuration fields have been annotated for the visibility of all
changes):
https://github.com/apache/cassandra/pull/2133/files


3. Enforce setter/getter method name rules by converting these methods
in camel case to the field name with underscores.

To rely on setter methods, we need to enforce the naming rules of the
setters. I have collected information about which field names match
their camel case getter/setter methods:

total: 345
setters: 109, missed 236
volatile setters: 90, missed 255
jmx setters: 35, missed 310
getters: 139, missed 206
volatile getters: 107, missed 238
jmx getters: 63, missed 282

The most confusing part of this type of change is the number of
changes in additional classes according to the calculation above and
some difficulties with enforcing this rule for nested configuration
classes.

Find out what this change is about here:
https://github.com/apache/cassandra/pull/2172/files


= Summary =

In summary, from my point of view, the annotation approach will be the
most robust solution for us, so I'd like to continue with it. It also
provides an easy way to extend the SettingTable with additional
columns such as runtime type (READ_ONLY, READ_WRITE) and a description
column. This ends up looking much more user-friendly.

Another advantage of the annotation approach is that we can rely on
this annotation to generate dedicated dynamic JMX beans that only
respond to node configuration management to avoid any inconsistencies
like those mentioned here [2] (I have described a similar approach
here [1], but for metrics). But all this is beyond the scope of the
current changes.

Looking forward to your thoughts.


[1] https://lists.apache.org/thread/26j9hhy39okw0wy79mtylb753w6xjclg
[2] https://issues.apache.org/jira/browse/CASSANDRA-17734

Reply via email to