Blake Eggleston created CASSANDRA-7837:
------------------------------------------

             Summary: Factor out static initialization / singletons
                 Key: CASSANDRA-7837
                 URL: https://issues.apache.org/jira/browse/CASSANDRA-7837
             Project: Cassandra
          Issue Type: Improvement
            Reporter: Blake Eggleston


I've been spending some time experimenting with ways to factor out static 
initialization and static singletons in Cassandra.

This is a known issue, with obvious implications on testability and 
extensibility. It also leads to subtle changes in behavior of the database and 
tests, as access patterns to static methods reorder the initialization order of 
the static state. For instance, the test 
org.apache.cassandra.config.DatabaseDescriptorTest.testKSMetaDataSerialization 
is no longer testing anything, because Schema.getKeyspaceDefinitions() is now 
returning an empty array. Once the initialization order is changed, the test 
fails because system keyspaces aren't being filtered out, and fromThrift throws 
an exceptions when it sees LocalStrategy. Removing static state and singletons 
will make testing each component in isolation easier, leading to fewer 
regressions.

With a large refactor like this, we'd want to avoid having the refactor branch, 
and the trunk branch diverging too far, or for too long. After a few failed 
attempts, I've worked out a way to perform the refactor in a way that can be 
performed with a series of (relatively) small patches, and avoid a big, scary 
merge. Each patch will build, the tests will pass, and can be merged into trunk 
daily/regularly as they are completed.

The process is as follows:

# Condense all static state into static singletons. 
(DatabaseDescriptor.getPartitioner() -> 
DatabaseDescriptor.instance.getPartitioner())
** In some cases, classes will need to be split into pairs of instance and 
factory classes, like in the case of Keyspace and ColumnFamilyStore
# Identify all non-singleton usages of static state (grep for '.instance.'), 
and refactor to pass dependencies into their constructors from their 
instantiating services.
# Work out and implement an initialization order for the singletons, preferring 
final members passed into their constructor, using volatile members assigned 
during startup where there are circular dependencies.
** We should consider splitting some of the singletons into more component 
specific classes before this step. There is definitely a case for making that 
another ticket, but with the non-singleton dependencies clearly defined at this 
point, we will have a clear idea of what can be split up. Doing that would 
reduce the number of circular dependencies between singletons, and make this 
stage a lot easier, with the additional benefit of further modularizing the 
code.
# Remove static singleton instances. Initialize and start C* from a static 
method that takes a configuration as an argument.
** CassandraDaemon and utilities will need to be updated, and we'll need a 
helper method so tests can instantiate the database with a one or two liner.

Obviously, this is a lot of work, but I think it's worth the effort. I've 
already gone through a few practice runs, and it's doable. I'm happy to do the 
work, with guidance and input from the C* team.

Thoughts?



--
This message was sent by Atlassian JIRA
(v6.2#6252)

Reply via email to