blob: 9eda902f7e77afd1f3964cd4cc16a1d9a2c45594 [file] [log] [blame]
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>Apache Cassandra | Apache Cassandra Documentation</title>
<link rel="stylesheet" href="../../assets/css/site.css">
<link rel="schema.dcterms" href="https://purl.org/dc/terms/">
<meta name="dcterms.subject" content="_">
<meta name="dcterms.identifier" content="master">
<meta name="generator" content="Antora 2.3.4">
<link rel="icon" href="../../assets/img/favicon.ico" type="image/x-icon">
<script>
const script = document.createElement("script");
const domain = window.location.hostname;
script.type = "text/javascript";
script.src = "https://plausible.cassandra.apache.org/js/plausible.js";
script.setAttribute("data-domain",domain);
script.setAttribute("defer",'true');
script.setAttribute("async",'true');
document.getElementsByTagName("head")[0].appendChild(script);
</script> </head>
<body class="basic ">
<div class="container mx-auto relative">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<meta property="og:type" content="website" />
<meta property="og:url" content="/" />
<meta property="og:site_name" content="Apache Cassandra" />
<header id="top-nav">
<div class="inner relative">
<div class="header-social-icons text-right">
<a href="https://twitter.com/cassandra?lang=en" target="_blank" styles="margin-left: 20px;"><img src="../../assets/img/twitter-icon-circle-white.svg" alt="twitter icon" width="24"></a>
<a href="https://www.linkedin.com/company/apache-cassandra/" target="_blank" styles="margin-left: 20px;"><img src="../../assets/img/LI-In-Bug.png" alt="linked-in icon" width="24"></a>
<a href="https://www.youtube.com/c/PlanetCassandra" target="_blank" styles="margin-left: 20px;"><img src="../../assets/img/youtube-icon.png" alt="youtube icon" width="24"></a>
</div>
<div class="cf">
<div class="logo left"><a href="/"><img src="../../assets/img/logo-white-r.png" alt="cassandra logo"></a></div>
<div class="mobile-nav-icon right">
<img class="toggle-icon" src="../../assets/img/hamburger-nav.svg">
</div>
<ul class="main-nav nav-links right flex flex-vert-center flex-space-between">
<li>
<a class="nav-link hide-mobile">Get Started</a>
<ul class="sub-menu bg-white">
<li class="pa-micro">
<a href="/_/cassandra-basics.html">
<div class="sub-nav-icon">
<img src="../../assets/img/sub-menu-basics.png" alt="cassandra basics icon">
</div>
<div class="sub-nav-text teal py-small">
Cassandra Basics
</div>
</a>
</li>
<li class="pa-micro">
<a href="/_/quickstart.html">
<div class="sub-nav-icon">
<img src="../../assets/img/sub-menu-rocket.png" alt="cassandra basics icon">
</div>
<div class="sub-nav-text teal py-small">
Quickstart
</div>
</a>
</li>
<li class="pa-micro">
<a href="/_/ecosystem.html">
<div class="sub-nav-icon">
<img src="../../assets/img/sub-menu-ecosystem.png" alt="cassandra basics icon">
</div>
<div class="sub-nav-text teal py-small">
Ecosystem
</div>
</a>
</li>
</ul>
</li>
<li><a class="nav-link" href="/doc/latest/">Documentation</a></li>
<li>
<a class="nav-link" href="/_/community.html">Community</a>
<ul class="sub-menu bg-white">
<li class="pa-micro">
<a href="/_/community.html#code-of-conduct">
<div class="sub-nav-icon">
<img src="../../assets/img/sub-menu-welcome.png" alt="welcome icon">
</div>
<div class="sub-nav-text teal py-small">
Welcome
</div>
</a>
</li>
<li class="pa-micro hide-mobile">
<a href="/_/community.html#discussions">
<div class="sub-nav-icon">
<img src="../../assets/img/sub-menu-discussions.png" alt="discussions icon">
</div>
<div class="sub-nav-text teal py-small">
Discussions
</div>
</a>
</li>
<li class="pa-micro hide-mobile">
<a href="/_/community.html#project-governance">
<div class="sub-nav-icon">
<img src="../../assets/img/sub-menu-governance.png" alt="Governance icon">
</div>
<div class="sub-nav-text teal py-small">
Governance
</div>
</a>
</li>
<li class="pa-micro hide-mobile">
<a href="/_/community.html#how-to-contribute">
<div class="sub-nav-icon">
<img src="../../assets/img/sub-menu-contribute.png" alt="Contribute icon">
</div>
<div class="sub-nav-text teal py-small">
Contribute
</div>
</a>
</li>
<li class="pa-micro hide-mobile">
<a href="/_/community.html#meet-the-community">
<div class="sub-nav-icon">
<img src="../../assets/img/sub-menu-community.png" alt="Meet the Community icon">
</div>
<div class="sub-nav-text teal py-small">
Meet the Community
</div>
</a>
</li>
<li class="pa-micro hide-mobile">
<a href="/_/cassandra-catalyst-program.html">
<div class="sub-nav-icon">
<img src="../../assets/img/sub-menu-catalyst.png" alt="Catalyst icon">
</div>
<div class="sub-nav-text teal py-small">
Catalyst Program
</div>
</a>
</li>
<li class="pa-micro hide-mobile">
<a href="/_/events.html">
<div class="sub-nav-icon">
<img src="../../assets/img/sub-menu-events.png" alt="Events icon">
</div>
<div class="sub-nav-text teal py-small">
Events
</div>
</a>
</li>
</ul>
</li>
<li>
<a class="nav-link hide-mobile">Learn</a>
<ul class="sub-menu bg-white">
<li class="pa-micro">
<a href="/_/Apache-Cassandra-5.0-Moving-Toward-an-AI-Driven-Future.html">
<div class="sub-nav-icon">
<img src="../../assets/img/sub-menu-basics.png" alt="Basics icon">
</div>
<div class="sub-nav-text teal py-small">
Cassandra 5.0
</div>
</a>
</li>
<li class="pa-micro">
<a href="/_/case-studies.html">
<div class="sub-nav-icon">
<img src="../../assets/img/sub-menu-case-study.png" alt="Case Studies icon">
</div>
<div class="sub-nav-text teal py-small">
Case Studies
</div>
</a>
</li>
<li class="pa-micro">
<a href="/_/resources.html">
<div class="sub-nav-icon">
<img src="../../assets/img/sub-menu-resources.png" alt="Resources icon">
</div>
<div class="sub-nav-text teal py-small">
Resources
</div>
</a>
</li>
<li class="pa-micro">
<a href="/_/blog.html">
<div class="sub-nav-icon">
<img src="../../assets/img/sub-menu-blog.png" alt="Blog icon">
</div>
<div class="sub-nav-text teal py-small">
Blog
</div>
</a>
</li>
</ul>
</li>
<li><a class="nav-link btn btn--filled" href="/_/download.html">Download Now</a></li>
</ul>
</div>
</div>
</header>
<div class="hero hero--home grad">
<div class="eye"></div>
<div id="home-content" class="text-center flex flex-center flex-column relative z2 ma-xlarge">
<h1>Contributing to Cassandra</h1>
</div>
</div>
<div class="flex-center py-large arrow">
<div class="inner inner--narrow">
<div id="preamble">
<div class="sectionbody">
<div class="ulist">
<ul>
<li>
<p><a href="gettingstarted.html" class="page">Getting started</a></p>
</li>
<li>
<p><a href="ide.html" class="page">Building and IDE integration</a></p>
</li>
<li>
<p><a href="testing.html" class="page">Testing</a></p>
</li>
<li>
<p><a href="code_style.html" class="page">Code style</a></p>
</li>
<li>
<p><a href="how_to_commit.html" class="page">How to commit</a></p>
</li>
<li>
<p><a href="how_to_review.html" class="page">How to review</a></p>
</li>
<li>
<p><a href="patches.html" class="page">Patches</a></p>
</li>
<li>
<p><a href="ci.html" class="page">CI</a></p>
</li>
<li>
<p><a href="dependencies.html" class="page">Dependencies</a></p>
</li>
<li>
<p><a href="documentation.html" class="page">Documentation</a></p>
</li>
<li>
<p><a href="release_process.html" class="page">Release process</a></p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="getting-started"><a class="anchor" href="#getting-started"></a>Getting Started</h2>
<div class="sectionbody">
<div class="sect2">
<h3 id="initial-contributions"><a class="anchor" href="#initial-contributions"></a>Initial Contributions</h3>
<div class="paragraph">
<p>Writing a new feature is just one way to contribute to the Cassandra
project.
In fact, making sure that supporting tasks, such as quality testing,
documentation, and helping users are completed is just as important.
Tracking the development of new features is an ongoing challenge for this project,
like most open source projects.
We suggest learning how this project gets things done before tackling a new feature.
Here are some suggestions for ways to contribute:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Update the documentation</p>
</li>
<li>
<p>Answer questions on the user list</p>
</li>
<li>
<p>Review and test a submitted patch</p>
</li>
<li>
<p>Investigate and fix a reported bug</p>
</li>
<li>
<p>Create unit tests and d-tests</p>
</li>
</ul>
</div>
</div>
<div class="sect2">
<h3 id="updating-documentation"><a class="anchor" href="#updating-documentation"></a>Updating documentation</h3>
<div class="paragraph">
<p>The Cassandra documentation is maintained in the Cassandra source
repository along with the Cassandra code base.
To submit changes to the documentation, follow the standard process for
submitting a <a href="patches.html" class="page">patch</a>.</p>
</div>
</div>
<div class="sect2">
<h3 id="answering-questions-on-the-user-list"><a class="anchor" href="#answering-questions-on-the-user-list"></a>Answering questions on the user list</h3>
<div class="paragraph">
<p>Subscribe to the user list, look for some questions you can answer and write a reply.
Simple as that! See the <a href="http://cassandra.apache.org/community/">community</a> page
for details on how to subscribe to the mailing list.</p>
</div>
</div>
<div class="sect2">
<h3 id="reviewing-and-testing-a-submitted-patch"><a class="anchor" href="#reviewing-and-testing-a-submitted-patch"></a>Reviewing and testing a submitted patch</h3>
<div class="paragraph">
<p>Reviewing patches is not the sole domain of committers.
If others review a patch, it can reduce the load on the committers.
Less time spent reviewing patches means committers can more great features
or review more complex patches.
Follow the instructions in <a href="how_to_review.html" class="page">How to review</a> or alternatively, create a build with the patch and test it with your own workload.
Add a comment to the JIRA ticket to let others know you&#8217;ve reviewed and tested,
along with the results of your work.
For example:</p>
</div>
<div class="exampleblock">
<div class="content">
<div class="paragraph">
<p>"I tested this performance enhancement on our application&#8217;s standard production
load test and found a 3% improvement."</p>
</div>
</div>
</div>
</div>
<div class="sect2">
<h3 id="investigate-andor-fix-a-reported-bug"><a class="anchor" href="#investigate-andor-fix-a-reported-bug"></a>Investigate and/or fix a reported bug</h3>
<div class="paragraph">
<p>Often, the hardest work in fixing a bug is reproducing it.
Even if youdon&#8217;t have the knowledge to produce a fix, figuring out a way to
reliably reproduce an issue can be a massive contribution.
Document your method of reproduction in a JIRA comment or,
better yet, produce an automated test that reproduces the issue and
attach it to the ticket.
If you go as far as producing a fix, follow the process for submitting a <a href="#:patches.adoc" class="page unresolved">patch</a>.</p>
</div>
<div class="paragraph">
<p>To create a JIRA account, please request it on <a href="../community.html#discussions" class="page">the #cassandra or #cassandra-dev channels on ASF Slack</a>, or on <a href="../community.html#discussions" class="page">the user or dev mailing list</a>.</p>
</div>
</div>
<div class="sect2">
<h3 id="create-unit-tests-and-dtests"><a class="anchor" href="#create-unit-tests-and-dtests"></a>Create unit tests and Dtests</h3>
<div class="paragraph">
<p>Test coverage for Cassandra will always benefit from more automated test
coverage, as with most code bases.
Before starting work on a particular area of code, consider reviewing and
enhancing the existing test coverage.
You&#8217;ll both improve your knowledge of the code before you start on an
enhancement, and reduce the chance introducing issues with your change. See <a href="testing.html" class="page">testing</a> and <a href="patches.html" class="page">patches</a> for more detail.</p>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="building-and-ide-integration"><a class="anchor" href="#building-and-ide-integration"></a>Building and IDE Integration</h2>
<div class="sectionbody">
<div class="sect2">
<h3 id="prerequisites"><a class="anchor" href="#prerequisites"></a>Prerequisites</h3>
<div class="paragraph">
<p>Building Cassandra from source is the first important step in contributing to the Apache Cassandra project.
You will need to install Java (JDK 8 or 11, depending on which version
you want to build Cassandra against, best is to install both and then
switch between them when needed), Git, and Ant (including ant-optional).</p>
</div>
</div>
<div class="sect2">
<h3 id="getting-the-source-code"><a class="anchor" href="#getting-the-source-code"></a>Getting the source code</h3>
<div class="paragraph">
<p>The source code for Cassandra is shared on the central Apache Git
repository and organized by branch, one branch for each major version.
You can access the code for the current development branch at
<a href="https://gitbox.apache.org/repos/asf/cassandra.git" class="bare">gitbox.apache.org/repos/asf/cassandra.git</a> (the primary location)
or at <a href="https://github.com/apache/cassandra" class="bare">github.com/apache/cassandra</a> (a mirror location).</p>
</div>
<div class="paragraph">
<p>However, to develop a patch or a new feature, you should fork the Cassandra
project first and then clone it from your own fork:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-plaintext hljs" data-lang="plaintext">git clone https://github.com/&lt;your_git_name&gt;/cassandra.git cassandra</code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="building-cassandra"><a class="anchor" href="#building-cassandra"></a>Building Cassandra</h3>
<div class="paragraph">
<p>Cassandra is a Java project which is built using Ant.
The build file, <code>build.xml</code> located in the root of the project content,
has various tasks defined (you can list all of them with some short
descriptions by running <code>ant -p</code>).</p>
</div>
<div class="paragraph">
<p>The build uses the Java compiler which is currently set up in your
shell. By default, the build uses Java 8. If you want to build
with Java 11, you need to either add a build property <code>-Duse.jdk11=true</code>
to your Ant build command or export the environment variable
<code>CASSANDRA_USE_JDK11=true</code>. Otherwise, if you run the build using
Java 11, the build script complains.</p>
</div>
<div class="paragraph">
<p>Now you can build Cassandra with the default task - just execute
<code>ant</code> or <code>ant jar</code>. This may take a significant amount of time depending
on artifacts that have to be downloaded or the number of classes that
need to be compiled. When the build completes, you can find a JAR file
in the build directory, and the database service can be started with
the <code>bin/cassandra</code> script.</p>
</div>
</div>
<div class="sect2">
<h3 id="building-a-distribution"><a class="anchor" href="#building-a-distribution"></a>Building a distribution</h3>
<div class="paragraph">
<p>Some tasks you might be interested in are:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>build</code> - compile the production code without producing any JARs</p>
</li>
<li>
<p><code>build-test</code> - compile the test code without producing any JARs</p>
</li>
<li>
<p><code>artifacts</code> - generate Cassandra distribution in <code>build/dist</code>
directory and package it to <code>tar.gz</code> (with and without sources)</p>
</li>
<li>
<p><code>mvn-install</code> - generate <code>cassandra-all</code> JAR artifact along with
sources and JavaDoc, and install it in the local Maven repository</p>
</li>
<li>
<p><code>realclean</code> - clean the project from any build products, as well as
from any dependencies (in fact that means removing <code>build</code> and <code>lib</code>
directories)</p>
</li>
</ul>
</div>
<div class="admonitionblock tip">
<table>
<tr>
<td class="icon">
<i class="fa icon-tip" title="Tip"></i>
</td>
<td class="content">
<div class="title">Hint</div>
<div class="paragraph">
<p>Remember to clean the project after switching branches as build artifacts
are versioned.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>There are other tasks related to testing, and they are covered in
<a href="testing.adoc">Testing</a> section.</p>
</div>
</div>
<div class="sect2">
<h3 id="setting-up-cassandra-in-intellij-idea"><a class="anchor" href="#setting-up-cassandra-in-intellij-idea"></a>Setting up Cassandra in IntelliJ IDEA</h3>
<div class="paragraph">
<p><a href="https://www.jetbrains.com/idea/">IntelliJ IDEA</a> by JetBrains is one of
the most popular IDEs for Cassandra and Java development in general.
The Community Edition can be freely downloaded with all features needed to get started developing Cassandra.</p>
</div>
<div class="paragraph">
<p>Use the following procedure for Cassandra 2.1.5+:</p>
</div>
<div class="olist arabic">
<ol class="arabic">
<li>
<p>Generate project files by executing the following target from Ant build:</p>
</li>
</ol>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-plaintext hljs" data-lang="plaintext">ant generate-idea-files</code></pre>
</div>
</div>
<div class="olist arabic">
<ol class="arabic" start="2">
<li>
<p>Start IDEA.</p>
</li>
<li>
<p>Open the IDEA project from the checked-out Cassandra directory using <code>File &gt; Open</code> in IDEA&#8217;s menu.</p>
</li>
</ol>
</div>
<div class="paragraph">
<p>The project generated by <code>ant generate-idea-files</code> contains
nearly everything you need to debug Cassandra and execute unit tests.</p>
</div>
<div class="admonitionblock tip">
<table>
<tr>
<td class="icon">
<i class="fa icon-tip" title="Tip"></i>
</td>
<td class="content">
<div class="title">Hint</div>
<div class="paragraph">
<p>Although you do not need to build the project with <code>ant jar</code> to import
it some tests run tools as external processes and need the regular
artifacts to be created. Such tests may require you to rebuild the
project using Ant before each run even when you run the test in IDEA.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>You should be able to:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Run/debug defaults for JUnit</p>
</li>
<li>
<p>Run/debug configuration for Cassandra daemon</p>
</li>
<li>
<p>Read/modify the license header for Java source files</p>
</li>
<li>
<p>Study Cassandra code style</p>
</li>
<li>
<p>Inspections</p>
</li>
</ul>
</div>
<div class="admonitionblock tip">
<table>
<tr>
<td class="icon">
<i class="fa icon-tip" title="Tip"></i>
</td>
<td class="content">
<div class="title">Hint</div>
<div class="paragraph">
<p>If you wish to work with older Cassandra versions, see our <a href="https://cwiki.apache.org/confluence/display/CASSANDRA2/RunningCassandraInIDEA">wiki</a> for instructions.</p>
</div>
</td>
</tr>
</table>
</div>
</div>
<div class="sect2">
<h3 id="opening-cassandra-in-apache-netbeans"><a class="anchor" href="#opening-cassandra-in-apache-netbeans"></a>Opening Cassandra in Apache NetBeans</h3>
<div class="paragraph">
<p><a href="https://netbeans.apache.org/">Apache NetBeans</a> is the elder of the open sourced java IDEs,
and can be used for Cassandra development.
There is no project setup or generation required to open Cassandra in NetBeans.
Use the following procedure for Cassandra 4.0+.</p>
</div>
<div class="paragraph">
<p>First, clone and build Cassandra.
Then execute the following steps to use NetBeans.</p>
</div>
<div class="olist arabic">
<ol class="arabic">
<li>
<p>Start Apache NetBeans</p>
</li>
<li>
<p>Open the NetBeans project from the <em>ide/</em> folder of the
checked-out Cassandra directory using <code>File &gt; Open Project</code> in NetBeans' menu.</p>
</li>
</ol>
</div>
<div class="paragraph">
<p>You should be able to:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Build code</p>
</li>
<li>
<p>Run code</p>
</li>
<li>
<p>Debug code</p>
</li>
<li>
<p>Profile code</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>These capabilities use the <em>build.xml</em> script.
Build/Run/Debug Project are available via the Run/Debug menus, or the
project context menu.
Profile Project is available via the Profile menu. In the opened
Profiler tab, click the green "Profile" button.
Cassandra&#8217;s code style is honored in <em>ide/nbproject/project.properties</em>.
The <code>JAVA8_HOME</code> system environment variable must be set for NetBeans to execute the Run/Debug/Profile <code>ant</code> targets to execute.</p>
</div>
</div>
<div class="sect2">
<h3 id="setting-up-cassandra-in-eclipse"><a class="anchor" href="#setting-up-cassandra-in-eclipse"></a>Setting up Cassandra in Eclipse</h3>
<div class="paragraph">
<p>Eclipse is a popular open source IDE that can be used for Cassandra
development. Various Eclipse environments are available from the
<a href="https://www.eclipse.org/downloads/eclipse-packages/">download page</a>. The
following guide was created with "Eclipse IDE for Java Developers".</p>
</div>
<div class="paragraph">
<p>These instructions were tested on Ubuntu 16.04 with Eclipse Neon (4.6)
using Cassandra versions 2.1 through 3.x.</p>
</div>
<div class="paragraph">
<p>First, clone and build Cassandra.
Then execute the following steps to use Eclipse.</p>
</div>
<div class="olist arabic">
<ol class="arabic">
<li>
<p>Generate the IDEA files using ant:</p>
</li>
</ol>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-plaintext hljs" data-lang="plaintext">ant generate-eclipse-files</code></pre>
</div>
</div>
<div class="olist arabic">
<ol class="arabic" start="2">
<li>
<p>Start Eclipse.</p>
</li>
<li>
<p>Open the Eclipse project from the checked-out Cassandra directory using
<code>File &gt; Import &gt; Existing Projects</code> and <code>Workspace &gt; Select</code> git directory.
Select the correct branch, such as <code>cassandra-trunk</code>.</p>
</li>
<li>
<p>Confirm and select <code>Finish</code> to import your project.</p>
</li>
</ol>
</div>
<div class="paragraph">
<p>Find the project in <code>Package Explorer</code> or <code>Project Explorer</code>.
You should not get errors if you build the project automatically using these
instructions. Don&#8217;t set up the project before generating the files with <code>ant</code>.</p>
</div>
<div class="paragraph">
<p>You should be able to:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Run/debug defaults for JUnit</p>
</li>
<li>
<p>Run/debug Cassandra</p>
</li>
<li>
<p>Study Cassandra code style</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Unit tests can be run from Eclipse by simply right-clicking the class
file or method and selecting <code>Run As &gt; JUnit Test</code>.
Tests can be debugged by defining breakpoints (double-click line number) and
selecting <code>Debug As &gt; JUnit Test</code>.</p>
</div>
<div class="paragraph">
<p>Alternatively all unit tests can be run from the command line as
described in <a href="#:testing.adoc" class="page unresolved">testing</a>.</p>
</div>
<div class="sect3">
<h4 id="debugging-cassandra-using-eclipse"><a class="anchor" href="#debugging-cassandra-using-eclipse"></a>Debugging Cassandra Using Eclipse</h4>
<div class="paragraph">
<p>There are two ways to start a local Cassandra instance with Eclipse for debugging.
You can either start Cassandra from the command line or from within Eclipse.</p>
</div>
<div class="sect4">
<h5 id="debugging-cassandra-started-at-command-line"><a class="anchor" href="#debugging-cassandra-started-at-command-line"></a>Debugging Cassandra started at command line</h5>
<div class="olist arabic">
<ol class="arabic">
<li>
<p>Set environment variable to define remote debugging options for the
JVM: <code>export JVM_EXTRA_OPTS="-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=1414"</code></p>
</li>
<li>
<p>Start Cassandra by executing the <code>./bin/cassandra</code></p>
</li>
</ol>
</div>
<div class="paragraph">
<p>Next, connect to the running Cassandra process by:</p>
</div>
<div class="olist arabic">
<ol class="arabic" start="3">
<li>
<p>In Eclipse, select <code>Run &gt; Debug Configurations</code>.</p>
</li>
</ol>
</div>
<div class="imageblock">
<div class="content">
<img src="../_images/eclipse_debug0.png" alt="image">
</div>
</div>
<div class="olist arabic">
<ol class="arabic" start="4">
<li>
<p>Create new remote application.</p>
</li>
</ol>
</div>
<div class="imageblock">
<div class="content">
<img src="../_images/eclipse_debug1.png" alt="image">
</div>
</div>
<div class="olist arabic">
<ol class="arabic" start="5">
<li>
<p>Configure <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/troubleshoot/introclientissues005.html">connection settings</a> by specifying a name and port 1414.
Confirm <code>Debug</code> and start debugging.</p>
</li>
</ol>
</div>
<div class="imageblock">
<div class="content">
<img src="../_images/eclipse_debug2.png" alt="image">
</div>
</div>
</div>
<div class="sect4">
<h5 id="debugging-cassandra-started-from-eclipse"><a class="anchor" href="#debugging-cassandra-started-from-eclipse"></a>Debugging Cassandra started from Eclipse</h5>
<div class="paragraph">
<p>Cassandra can also be started directly from Eclipse if you don&#8217;t want to
use the command line.</p>
</div>
<div class="olist arabic">
<ol class="arabic" start="1">
<li>
<p>In Eclipse, select <code>Run &gt; Run Configurations</code>.</p>
</li>
</ol>
</div>
<div class="imageblock">
<div class="content">
<img src="../_images/eclipse_debug3.png" alt="image">
</div>
</div>
<div class="olist arabic">
<ol class="arabic" start="2">
<li>
<p>Create new application.</p>
</li>
</ol>
</div>
<div class="imageblock">
<div class="content">
<img src="../_images/eclipse_debug4.png" alt="image">
</div>
</div>
<div class="olist arabic">
<ol class="arabic" start="3">
<li>
<p>Specify name, project and main class <code>org.apache.cassandra.service.CassandraDaemon</code></p>
</li>
</ol>
</div>
<div class="imageblock">
<div class="content">
<img src="../_images/eclipse_debug5.png" alt="image">
</div>
</div>
<div class="olist arabic">
<ol class="arabic" start="4">
<li>
<p>Configure additional JVM specific parameters that will start Cassandra
with some of the settings created by the regular startup script. Change
heap related values as needed.</p>
</li>
</ol>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-plaintext hljs" data-lang="plaintext">-Xms1024M -Xmx1024M -Xmn220M -Xss256k -ea -XX:+UseThreadPriorities -XX:ThreadPriorityPolicy=42 -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:+CMSParallelRemarkEnabled -XX:+UseCondCardMark -javaagent:./lib/jamm-0.3.0.jar -Djava.net.preferIPv4Stack=true</code></pre>
</div>
</div>
<div class="imageblock">
<div class="content">
<img src="../_images/eclipse_debug6.png" alt="image">
</div>
</div>
<div class="olist arabic">
<ol class="arabic" start="5">
<li>
<p>Confirm <code>Debug</code> and you should see the output of Cassandra start up in the Eclipse console.</p>
</li>
</ol>
</div>
<div class="paragraph">
<p>You can now set breakpoints and start debugging!</p>
</div>
</div>
</div>
</div>
<div class="sect2">
<h3 id="general-notes"><a class="anchor" href="#general-notes"></a>General notes</h3>
<div class="paragraph">
<p>You may sometimes encounter some odd build failures when running the <code>ant</code> commands above. If you do, start <code>ant</code> with the <code>realclean</code> option:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-plaintext hljs" data-lang="plaintext">ant realclean</code></pre>
</div>
</div>
<div class="paragraph">
<p>Remember that all the tasks mentioned above may depend on building source files. If there are actual compilation errors in the code, you may not be able to generate project files for IntelliJ Idea, Netbeans, or Eclipse.
It is especially important that you have imported the project adequately into IDE before doing merges or rebases. Otherwise, if there are conflicts, the project cannot be opened in IDE, and you will be unable to use any fancy conflict resolution tools offered by those IDEs.</p>
</div>
</div>
</div>
</div>
<h1 id="testing" class="sect0"><a class="anchor" href="#testing"></a>Testing</h1>
<div class="paragraph">
<p>Creating tests is one of the most important and also most difficult
parts of developing Cassandra. There are different ways to test your
code depending on what you&#8217;re working on.</p>
</div>
<div class="paragraph">
<p>Cassandra tests can be divided into three main categories, based on the
way how they are executed:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><strong><a href="#java_tests">Java tests</a></strong> - tests implemented in Java and being a part of the
Cassandra project. You can distinguish the following subcategories there:</p>
<div class="ulist">
<ul>
<li>
<p><strong><a href="#junit_tests">JUnit tests</a></strong> - consists of unit tests, single-node integration
tests and some tool tests; those tests may run a server with limited
functionality in the same JVM as the test code</p>
</li>
<li>
<p><strong><a href="#jvm_distributed_tests">JVM distributed tests</a></strong> - integrated tests against one or multiple
nodes, each running in their own classloader; also contains upgrade
tests</p>
</li>
<li>
<p><strong><a href="#microbenchmarks">Micro-benchmarks</a></strong> - micro-benchmarks implemented with
<a href="https://github.com/openjdk/jmh">JMH framework</a></p>
</li>
</ul>
</div>
</li>
<li>
<p><strong><a href="#cqlsh_tests">CQLSH tests</a></strong> - CQLSH tests are Python tests written with the Nose
test framework. They verify the CQLSH client that can be found in the
bin directory. They aim at verifying CQLSH specific behavior like output
formatting, autocompletion, parsing, etc).</p>
</li>
<li>
<p><strong><a href="#python_dtests">Python distributed tests</a></strong> - Python distributed tests are
implemented on top of the PyTest framework and located outside the main
Cassandra project in the separate repository
<a href="https://github.com/apache/cassandra-dtest">apache/cassandra-dtest</a>. They
test Cassandra via <a href="https://github.com/riptano/ccm">CCM</a> verifying
operation results, logs, and cluster state. Python Distributed tests are
Cassandra version agnostic. They include upgrade tests.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>In case you want to run DTests with your own version of CCM, please refer to requirements.txt in
<a href="https://github.com/apache/cassandra-dtest">apache/cassandra-dtest</a> how to do it.</p>
</div>
<div class="paragraph">
<p>The recipes for running those tests can be found in the cassandra-builds repository <a href="https://github.com/apache/cassandra-builds/tree/trunk/build-scripts">here</a>.</p>
</div>
<div class="paragraph">
<p>Running full test suites locally takes hours, if not days. Beyond running specific tests you know are applicable, or are failing, to the work at hand, it is recommended to rely upon the project&#8217;s <a href="/_/development/ci.html">Continuous Integration systems</a>. If you are not a committer, and don&#8217;t have access to a premium CircleCI plan, ask one of the committers to test your patch on the project&#8217;s <a href="https://ci-cassandra.apache.org/">ci-cassandra.apache.org</a>.</p>
</div>
<div class="sect1">
<h2 id="java_tests"><a class="anchor" href="#java_tests"></a>Java tests</h2>
<div class="sectionbody">
<div class="paragraph">
<p>The simplest test to write for Cassandra code is a unit test. Cassandra
uses JUnit as a testing framework and test cases can be found in the
<code>test/unit</code> directory. Ideally, you’ll create a unit test for
your implementation that exclusively covers the class you created
(the unit under test).</p>
</div>
<div class="paragraph">
<p>Unfortunately, this is not always possible, because Cassandra doesn&#8217;t
have a very mock friendly code base. Often you’ll find yourself in a
situation where you have to use the embedded Cassandra instance to
interact with your test. If you want to use CQL in your test,
you can extend CQLTester and use some convenient helper methods, as
shown here:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@Test
public void testBatchAndList() throws Throwable
{
createTable("CREATE TABLE %s (k int PRIMARY KEY, l list&lt;int&gt;)");
execute("BEGIN BATCH " +
"UPDATE %1$s SET l = l +[ 1 ] WHERE k = 0; " +
"UPDATE %1$s SET l = l + [ 2 ] WHERE k = 0; " +
"UPDATE %1$s SET l = l + [ 3 ] WHERE k = 0; " +
"APPLY BATCH");
assertRows(execute("SELECT l FROM %s WHERE k = 0"),
row(list(1, 2, 3)));
}</code></pre>
</div>
</div>
<div class="sect2">
<h3 id="junit_tests"><a class="anchor" href="#junit_tests"></a>JUnit tests</h3>
<div class="paragraph">
<p>To run the unit tests:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-none hljs" data-lang="none">ant test</code></pre>
</div>
</div>
<div class="paragraph">
<p>However, this is probably not what you want to do, since that
command would run all the unit tests (those from <code>test/unit</code>). It would
take about an hour or more to finish.</p>
</div>
<div class="paragraph">
<p>To run the specific test class or even a method, use the following
command:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-none hljs" data-lang="none">ant testsome -Dtest.name=&lt;TestClassName&gt; -Dtest.methods=&lt;testMethodName&gt;</code></pre>
</div>
</div>
<div class="ulist">
<ul>
<li>
<p><code>test.name</code> property is for either a simple or fully qualified class
name</p>
</li>
<li>
<p><code>test.methods</code> property is optional; if not specified, all test cases
from the specified class are executed. Though, you can also specify
multiple methods separating them by comma</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>You can also use the IDE to run the tests - when you generate IDE files and
properly import the Cassandra project, you can run the
tests by right-clicking on the test class or package name. Remember that
it is not enough to compile with IDE for some tests, and you need to
call <code>ant jar</code> to build the distribution artifacts. When
the test runs some tool as an external process, the tool expects
Cassandra artifacts to be in the build directory.</p>
</div>
<div class="paragraph">
<p>Note that those commands apply to the tests in the <code>test/unit</code>
directory. There are, however, some other test categories that have
tests in individual directories:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>test/burn</code> - to run them, call <code>ant test-burn</code> or
<code>ant burn-testsome</code>;
<code>ant burn-test-jar</code> builds a self-contained jar for e.g. remote execution; not currently
used for running burn tests in our scripts. <code>ant burn-test-jar</code> exists only on 4.0+ branches</p>
</li>
<li>
<p><code>test/long</code> - to run them, call <code>ant long-test</code> or <code>ant long-testsome</code></p>
</li>
<li>
<p><code>test/memory</code> - to run them, call <code>ant test-memory</code></p>
</li>
<li>
<p><code>test/microbench</code> discussed in <a href="#microbenchmarks">Micro-benchmarks</a></p>
</li>
<li>
<p><code>test/distributed</code> discussed in <a href="#jvm_distributed_tests">JVM distributed tests</a></p>
</li>
</ul>
</div>
<div class="admonitionblock tip">
<table>
<tr>
<td class="icon">
<i class="fa icon-tip" title="Tip"></i>
</td>
<td class="content">
<div class="title">Hint</div>
<div class="paragraph">
<p>If you get the error similar to the one below, install the
<code>ant-optional</code> package
because you need the <code>JUnitTask</code> class
(see <a href="ide.html" class="page">prerequisites</a>).</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-none hljs" data-lang="none">Throws: cassandra-trunk/build.xml:1134: taskdef A class needed by class org.krummas.junit.JStackJUnitTask cannot be found:
org/apache/tools/ant/taskdefs/optional/junit/JUnitTask using the classloader
AntClassLoader[/.../cassandra-trunk/lib/jstackjunit-0.0.1.jar]</code></pre>
</div>
</div>
</td>
</tr>
</table>
</div>
</div>
<div class="sect2">
<h3 id="stress_and_fqltool_tests"><a class="anchor" href="#stress_and_fqltool_tests"></a>Stress and FQLTool tests</h3>
<div class="paragraph">
<p><em>Stress</em> and <em>FQLTool</em> are separate modules located under the <code>tools</code>
directory in the Cassandra project. They have their own source code and
unit tests. To run the tests for those tools, first, build jar artifacts
for them by calling:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-asciidoc hljs" data-lang="asciidoc">ant fqltool-build fqltool-build-test
ant stress-build stress-build-test</code></pre>
</div>
</div>
<div class="paragraph">
<p>Then you can execute the tests with either one of the commands:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-plaintext hljs" data-lang="plaintext">ant fqltool-test
ant stress-test
and stress-test-some</code></pre>
</div>
</div>
<div class="paragraph">
<p>or using your IDE.</p>
</div>
</div>
<div class="sect2">
<h3 id="jvm_distributed_tests"><a class="anchor" href="#jvm_distributed_tests"></a>JVM distributed tests</h3>
<div class="paragraph">
<p>JVM distributed tests can run a cluster of nodes inside a single JVM -
they utilize a particular framework (that can be found at
<a href="https://github.com/apache/cassandra-in-jvm-dtest-api">apache/cassandra-in-jvm-dtest-api</a>)
for that purpose. Those tests are intended to test features that require
more started nodes or verify specific behaviors when the nodes get
restarted, including upgrading them from one version to another. The
tests are located at the <code>test/distributed</code> directory of the Cassandra
project; however, only <code>org.apache.cassandra.distributed.test</code> and
<code>org.apache.cassandra.upgrade</code> packages contain the actual tests. The
rest of the files are various utilities related to the distributed test
framework.</p>
</div>
<div class="paragraph">
<p>The distributed tests can be run in few ways. <code>ant test-jvm-dtest</code>
command runs all the distributed JVM tests. It is not very useful; thus,
there is also <code>ant test-jvm-dtest-some</code>, which allows specifying test
class and test name in the similar way as you could do that for the
<code>ant testsome</code> command, for example:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-plaintext hljs" data-lang="plaintext">ant test-jvm-dtest-some -Dtest.name=org.apache.cassandra.distributed.test.SchemaTest
ant test-jvm-dtest-some -Dtest.name=org.apache.cassandra.distributed.test.SchemaTest -Dtest.methods=readRepair</code></pre>
</div>
</div>
<div class="admonitionblock tip">
<table>
<tr>
<td class="icon">
<i class="fa icon-tip" title="Tip"></i>
</td>
<td class="content">
<div class="title">Hint</div>
<div class="paragraph">
<p>Unlike for JUnit tests, for JVM distributed tests you need to provide
fully qualified class name</p>
</div>
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>Distributed tests can also be run using IDE (in fact, you can even debug
them).</p>
</div>
<div class="sect3">
<h4 id="upgrade-tests"><a class="anchor" href="#upgrade-tests"></a>Upgrade tests</h4>
<div class="paragraph">
<p>JVM upgrade tests can be run precisely in the same way as any other JVM
distributed tests. However, running them requires some preparation -
for example, if a test verifies the upgrade from Cassandra 3.0 and
Cassandra 3.11 to the current version (say Cassandra 4.0), you need to
have prepared dtest uber JARs for all involved versions. To do this:</p>
</div>
<div class="olist arabic">
<ol class="arabic">
<li>
<p>Check out Cassandra 3.0 based branch you want to test the upgrade
from into some other directory</p>
</li>
<li>
<p>Build dtest uber JAR with <code>ant dtest-jar</code> command</p>
</li>
<li>
<p>Copy the created <code>build/dtest-3.0.x.jar</code> to the build
directory of your target Cassandra project</p>
</li>
<li>
<p>Repeat the procedure for Cassandra 3.11</p>
</li>
<li>
<p>Once you have dtest jars of all the involved versions for the upgrade
test, you can finally execute the test using your favorite method, say:</p>
</li>
</ol>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-plaintext hljs" data-lang="plaintext">ant test-jvm-dtest-some -Dtest.name=org.apache.cassandra.distributed.upgrade.MixedModeReadTest</code></pre>
</div>
</div>
<div class="admonitionblock tip">
<table>
<tr>
<td class="icon">
<i class="fa icon-tip" title="Tip"></i>
</td>
<td class="content">
<div class="title">Hint</div>
<div class="paragraph">
<p>You may pre-generate dtest uber JARs for certain past Cassandra
releases, store is somewhere and reuse in you future work - no need to
rebuild them all the time.</p>
</div>
</td>
</tr>
</table>
</div>
</div>
</div>
<div class="sect2">
<h3 id="running-multiple-tests"><a class="anchor" href="#running-multiple-tests"></a>Running multiple tests</h3>
<div class="paragraph">
<p>It is possible to define a list of test classes to run with a single command.
Define a text file, by default called <code>testlist.txt</code>, and put it into your project directory.
Here is an example of that file:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-none hljs" data-lang="none">org/apache/cassandra/db/ReadCommandTest.java
org/apache/cassandra/db/ReadCommandVerbHandlerTest.java</code></pre>
</div>
</div>
<div class="paragraph">
<p>Essentially, you list the paths to the class files of the tests you want
to run. Then you call <code>ant testclasslist</code>, which uses the text file
to run the listed tests. Note that, by default, it applies to
the tests under the <code>test/unit</code> directory and takes the <code>testlist.txt</code>
file, but this behavior can be modified by providing additional
parameters:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-plaintext hljs" data-lang="plaintext">ant testclasslist -Dtest.classlistprefix=&lt;category&gt; -Dtest.classlistfile=&lt;class list file&gt;</code></pre>
</div>
</div>
<div class="paragraph">
<p>For example, if you want to run the distributed tests this way, and say
our tests were listed in the <code>distributed-tests-set.txt</code> file (paths to
test classes relative to <code>test/distributed</code> directory), you can do that
by calling:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-plaintext hljs" data-lang="plaintext">ant testclasslist -Dtest.classlistprefix=distributed -Dtest.classlistfile=distributed-tests-set.txt</code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="running-coverage-analysis"><a class="anchor" href="#running-coverage-analysis"></a>Running coverage analysis</h3>
<div class="paragraph">
<p>Coverage reports from the executed JVM tests can be obtained in two ways
- through IDE - for example, IntelliJ supports running tests with
coverage analysis (another run button next to the one for running in debug mode).</p>
</div>
<div class="paragraph">
<p>The other way is to run Ant target <code>codecoverage</code>. Basically, it works
for all the ways mentioned above of running JVM tests - the only
difference is that instead of specifying the target directly, you pass it
as a property called <code>taskname</code>. For example - given the original test
command is:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-plaintext hljs" data-lang="plaintext">ant testsome -Dtest.name=org.apache.cassandra.utils.concurrent.AccumulatorTest</code></pre>
</div>
</div>
<div class="paragraph">
<p>to run it with coverage analysis, do:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-plaintext hljs" data-lang="plaintext">ant codecoverage -Dtaskname=testsome -Dtest.name=org.apache.cassandra.utils.concurrent.AccumulatorTest</code></pre>
</div>
</div>
<div class="paragraph">
<p>It applies to all the targets like <code>test</code>, <code>testsome</code>, <code>test-long</code>,
etc., even <code>testclasslist</code>. You can find the coverage report in
<code>build/jacoco</code> (<code>index.html</code> is the entry point for the HTML version,
but there are also XML and CSV reports).</p>
</div>
<div class="paragraph">
<p>Note that if you run various tests that way, the coverage information is
added to the previously collected runs. That is, you get the cumulative
coverage from all runs unless you clean up the project or at least clean
up the recorded coverage information by executing the command
<code>ant jacoco-cleanup</code>.</p>
</div>
</div>
<div class="sect2">
<h3 id="microbenchmarks"><a class="anchor" href="#microbenchmarks"></a>Micro-benchmarks</h3>
<div class="paragraph">
<p>To run micro-benchmarks, first build the uber jar for the JMH framework.
Use the following <code>ant</code> command:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-plaintext hljs" data-lang="plaintext">ant build-jmh</code></pre>
</div>
</div>
<div class="paragraph">
<p>Then, you can run either all benchmarks (from the <code>test/microbench</code>
directory) or the tests matching the name specified by the
<code>benchmark.name</code> property when executing the <code>ant microbench</code> command.
Whether you run all benchmarks or just a selected one, only classes
under the <code>microbench</code> package are selected. The class selection pattern
is actually <code>.*microbench.*${benchmark.name}</code>. For example,
in order to run <code>org.apache.cassandra.test.microbench.ChecksumBench</code>,
execute:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-plaintext hljs" data-lang="plaintext">ant microbench -Dbenchmark.name=ChecksumBench</code></pre>
</div>
</div>
<div class="paragraph">
<p>The <code>ant microbench</code> command runs the benchmarks with default parameters
as defined in the <code>build.xml</code> file (see the <code>microbench</code> target
definition). If you want to run JMH with custom parameters,
consider using the <code>test/bin/jmh</code> script. In addition to allowing you to
customize JMH options, it also sets up the environment and JVM options
by running Cassandra init script (<code>conf/cassandra-env.sh</code>). Therefore,
it lets the environment for running the tests to be more similar to
the production environment. For example:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-plaintext hljs" data-lang="plaintext">test/bin/jmh -gc true org.apache.cassandra.test.microbench.CompactionBench.compactTest</code></pre>
</div>
</div>
<div class="paragraph">
<p>You may also find it useful to run the command to list all the tests:
<code>test/bin/jmh -l</code> or <code>test/bin/jmh -lp</code> (also showing the default
parameters). The list of all options can be shown by running
<code>test/bin/jmh -h</code></p>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="python-tests"><a class="anchor" href="#python-tests"></a>Python tests</h2>
<div class="sectionbody">
<div class="sect2">
<h3 id="docker"><a class="anchor" href="#docker"></a>Docker</h3>
<div class="paragraph">
<p>The Docker approach is recommended for running Python distributed tests.
The behavior will be more repeatable, matching the same environment as
the official testing on <a href="https://ci-cassandra.apache.org/">Cassandra CI</a>.</p>
</div>
<div class="sect3">
<h4 id="setup-docker"><a class="anchor" href="#setup-docker"></a>Setup Docker</h4>
<div class="paragraph">
<p>If you are on Linux, you need to install Docker using the system package
manager.</p>
</div>
<div class="paragraph">
<p>If you are on MacOS, you can use either
<a href="https://www.docker.com/products/docker-desktop">Docker Desktop</a> or some
<a href="https://runnable.com/docker/install-docker-on-macos">other approach</a>.</p>
</div>
</div>
<div class="sect3">
<h4 id="pull-the-docker-image"><a class="anchor" href="#pull-the-docker-image"></a>Pull the Docker image</h4>
<div class="paragraph">
<p>The Docker image used on the official Cassandra CI can be found in
<a href="https://github.com/apache/cassandra-builds">this</a> repository.
You can use either
<a href="https://github.com/apache/cassandra-builds/blob/trunk/docker/testing/ubuntu2004_j11.docker">docker/testing/ubuntu2004_j11.docker</a>
or
<a href="https://github.com/apache/cassandra-builds/blob/trunk/docker/testing/ubuntu2004_j11_w_dependencies.docker">docker/testing/ubuntu2004_j11_w_dependencies.docker</a>
The second choice has prefetched dependencies for building each main
Cassandra branch. Those images can be either built
locally (as per instructions in the GitHub repo) or pulled from the
Docker Hub - see
<a href="https://hub.docker.com/search?q=apache%2Fcassandra-testing&amp;type=image">here</a>.</p>
</div>
<div class="paragraph">
<p>First, pull the image from Docker Hub (it will either fetch or
update the image you previously fetched):</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-plaintext hljs" data-lang="plaintext">docker pull apache/cassandra-testing-ubuntu2004-java11-w-dependencies</code></pre>
</div>
</div>
</div>
<div class="sect3">
<h4 id="start-the-container"><a class="anchor" href="#start-the-container"></a>Start the container</h4>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-plaintext hljs" data-lang="plaintext">docker run -di -m 8G --cpus 4 \
--mount type=bind,source=/path/to/cassandra/project,target=/home/cassandra/cassandra \
--mount type=bind,source=/path/to/cassandra-dtest,target=/home/cassandra/cassandra-dtest \
--name test \
apache/cassandra-testing-ubuntu2004-java11-w-dependencies \
dumb-init bash</code></pre>
</div>
</div>
<div class="admonitionblock tip">
<table>
<tr>
<td class="icon">
<i class="fa icon-tip" title="Tip"></i>
</td>
<td class="content">
<div class="title">Hint</div>
<div class="paragraph">
<p>Many distributed tests are not that demanding in terms of resources
- 4G / 2 cores should be enough to start one node. However, some tests
really run multiple nodes, and some of them are automatically skipped
if the machine has less than 32G (there is a way to force running them
though). Usually 8G / 4 cores is a convenient choice which is enough
for most of the tests.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>To log into the container, use the following <code>docker exec</code> command:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-plaintext hljs" data-lang="plaintext">docker exec -it `docker container ls -f name=test -q` bash</code></pre>
</div>
</div>
</div>
<div class="sect3">
<h4 id="setup_python_env"><a class="anchor" href="#setup_python_env"></a>Setup Python environment</h4>
<div class="paragraph">
<p>The tests are implemented in Python, so a Python virtual environment
(see <a href="https://docs.python.org/3/tutorial/venv.html">here</a> for details)
with all the required dependencies is good to be set up. If you are
familiar with the Python ecosystem, you know what it is all about.
Otherwise, follow the instructions; it should be enough to run the
tests.</p>
</div>
<div class="paragraph">
<p>For Python distributed tests do:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-plaintext hljs" data-lang="plaintext">cd /home/cassandra/cassandra-dtest
virtualenv --python=python3 --clear --always-copy ../dtest-venv
source ../dtest-venv/bin/activate
CASS_DRIVER_NO_CYTHON=1 pip install -r requirements.txt</code></pre>
</div>
</div>
<div class="paragraph">
<p>For CQLSH tests, replace some paths:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-plaintext hljs" data-lang="plaintext">cd /home/cassandra/cassandra/pylib
virtualenv --python=python3 --clear --always-copy ../../cqlsh-venv
source ../../cqlsh-venv/bin/activate
CASS_DRIVER_NO_CYTHON=1 pip install -r requirements.txt</code></pre>
</div>
</div>
<div class="admonitionblock tip">
<table>
<tr>
<td class="icon">
<i class="fa icon-tip" title="Tip"></i>
</td>
<td class="content">
<div class="title">Hint</div>
<div class="paragraph">
<p>You may wonder why this weird environment variable <code>CASS_DRIVER_NO_CYTHON=1</code> was added - it is not required at all. Still, it allows avoiding the compilation of Cassandra driver with Cython, which is not needed unless you want to test that Cython compiled driver. In the end, it speeds up the installation of the requirements significantly from the order of minutes to the order of seconds.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>The above commands are also helpful for importing those test projects
into your IDE. In that case, you need to run them on your host
system rather than in Docker container. For example, when you open the
project in IntelliJ, the Python plugin may ask you to select the runtime
environment. In this case, choose the existing <em>virtualenv</em>
based environment and point to <code>bin/python</code> under the created
<code>dtest-venv</code> directory (or <code>cqlsh-venv</code>, or whichever name you have
chosen).</p>
</div>
<div class="paragraph">
<p>Whether you want to play with Python distributed tests or CQLSH tests,
you need to select the right virtual environment. Remember to switch to
the one you want:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-plaintext hljs" data-lang="plaintext">deactivate
source /home/cassandra/dtest-venv/bin/activate</code></pre>
</div>
</div>
<div class="paragraph">
<p>or</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-plaintext hljs" data-lang="plaintext">deactivate
source /home/cassandra/cqlsh-venv/bin/activate</code></pre>
</div>
</div>
</div>
</div>
<div class="sect2">
<h3 id="cqlsh_tests"><a class="anchor" href="#cqlsh_tests"></a>CQLSH tests</h3>
<div class="paragraph">
<p>CQLSH tests are located in the <code>pylib/cqlshlib/test</code> directory. They are
based on the Nose framework. They require a running Cassandra cluster
(it can be one or more nodes cluster) as they start a CQL shell
client which tries to connect to a live node. Each test case starts the
CQLSH client as a subprocess, issues some commands, and verifies the
outcome returned by CQLSH to the console.</p>
</div>
<div class="paragraph">
<p>You need to set up and activate the <code>virtualenv</code> for CQLSH tests (see
<a href="#setup_python_env">Setup Python environment</a> section for details).</p>
</div>
<div class="paragraph">
<p>So let’s start the cluster first - you can use CCM for that (note that
CCM gets automatically installed with the <code>virtualenv</code> and is
immediately available once the <code>virtualenv</code> is activated):</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-plaintext hljs" data-lang="plaintext">ccm create test -n 1 --install-dir=/home/cassandra/cassandra
ccm updateconf "enable_user_defined_functions: true"
ccm updateconf "enable_scripted_user_defined_functions: true"
ccm updateconf "cdc_enabled: true"
ccm start --wait-for-binary-proto</code></pre>
</div>
</div>
<div class="paragraph">
<p>When those commands complete successfully, there is a cluster up and
running, and you can run the CQLSH tests. To do so, go to the
<code>pylib/cqlshlib</code> directory (not to the test subdirectory) and call
the <code>nosetests</code> command without any arguments. The tests take around
5 minutes to complete.</p>
</div>
<div class="paragraph">
<p>Finally, remember that since you manually started the cluster, you need
to stop it manually - just call:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-plaintext hljs" data-lang="plaintext">ccm remove test</code></pre>
</div>
</div>
<div class="paragraph">
<p>There is a helper script that does all of those things for you. In
particular, it builds the Cassandra project, creates a virtual
environment, runs the CCM cluster, executes the tests, and eventually
removes the cluster. You find the script in the <code>pylib</code> directory. The
only argument it requires is the Cassandra project directory:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-plaintext hljs" data-lang="plaintext">cassandra@b69a382da7cd:~/cassandra/pylib$ ./cassandra-cqlsh-tests.sh /home/cassandra/cassandra</code></pre>
</div>
</div>
<div class="paragraph">
<p>As you noticed, if you have already built Cassandra, the previous method
of running tests is much faster. Just remember that all the
<code>ccm updateconf</code> calls must be aligned with the Cassandra version you
are testing, with the supported features enabled.
Otherwise, Cassandra won’t start.</p>
</div>
<div class="sect3">
<h4 id="running-selected-tests"><a class="anchor" href="#running-selected-tests"></a>Running selected tests</h4>
<div class="paragraph">
<p>You may run all test tests from the selected file by passing that
file as an argument:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-plaintext hljs" data-lang="plaintext">~/cassandra/pylib/cqlshlib$ nosetests test/test_constants.py</code></pre>
</div>
</div>
<div class="paragraph">
<p>To run a specific test case, you need to specify the module, class name,
and the test name, for example:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-plaintext hljs" data-lang="plaintext">~/cassandra/pylib/cqlshlib$ nosetests cqlshlib.test.test_cqlsh_output:TestCqlshOutput.test_boolean_output</code></pre>
</div>
</div>
<div class="paragraph">
<p>For more information on selecting tests with the Nose framework, see
<a href="https://nose.readthedocs.io/en/latest/usage.html">this</a> page.</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="python_dtests"><a class="anchor" href="#python_dtests"></a>Python distributed tests</h3>
<div class="paragraph">
<p>One way of doing integration or system testing at larger scale is
using <a href="https://github.com/apache/cassandra-dtest">dtest</a> (Cassandra distributed test).
These dtests automatically setup Cassandra clusters with certain configurations and simulate use cases you want to test.</p>
</div>
<div class="paragraph">
<p>The best way to learn how to write dtests is probably by reading the
introduction "http://www.datastax.com/dev/blog/how-to-write-a-dtest[How
to Write a Dtest]".
Looking at existing, recently updated tests in the project is another good activity.
New tests must follow certain
<a href="https://github.com/apache/cassandra-dtest/blob/master/CONTRIBUTING.md">style
conventions</a> that are checked before contributions are accepted.
In contrast to Cassandra, dtest issues and pull requests are managed on
github, therefore you should make sure to link any created dtests in your
Cassandra ticket and also refer to the ticket number in your dtest PR.</p>
</div>
<div class="paragraph">
<p>Creating a good dtest can be tough, but it should not prevent you from
submitting patches!
Please ask in the corresponding JIRA ticket how to write a good dtest for the patch.
In most cases a reviewer or committer will able to support you, and in some cases they may offer to write a dtest for you.</p>
</div>
<div class="sect3">
<h4 id="run-the-tests-quick-examples"><a class="anchor" href="#run-the-tests-quick-examples"></a>Run the tests - quick examples</h4>
<div class="paragraph">
<p>Note that you need to set up and activate the virtualenv for DTests
(see <a href="#setup_python_env">Setup Python environment</a> section for details). Tests are implemented
with the PyTest framework, so you use the pytest command to run them.
Let’s run some tests:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-plaintext hljs" data-lang="plaintext">pytest --cassandra-dir=/home/cassandra/cassandra schema_metadata_test.py::TestSchemaMetadata::test_clustering_order</code></pre>
</div>
</div>
<div class="paragraph">
<p>That command runs the <code>test_clustering_order</code> test case from
<code>TestSchemaMetadata</code> class, located in the <code>schema_metadata_test.py</code>
file. You may also provide the file and class to run all test cases from
that class:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-plaintext hljs" data-lang="plaintext">pytest --cassandra-dir=/home/cassandra/cassandra schema_metadata_test.py::TestSchemaMetadata</code></pre>
</div>
</div>
<div class="paragraph">
<p>or just the file name to run all test cases from all classes defined in that file.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-plaintext hljs" data-lang="plaintext">pytest --cassandra-dir=/home/cassandra/cassandra schema_metadata_test.py</code></pre>
</div>
</div>
<div class="paragraph">
<p>You may also specify more individual targets:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-plaintext hljs" data-lang="plaintext">pytest --cassandra-dir=/home/cassandra/cassandra schema_metadata_test.py::TestSchemaMetadata::test_basic_table_datatype schema_metadata_test.py::TestSchemaMetadata::test_udf</code></pre>
</div>
</div>
<div class="paragraph">
<p>If you run pytest without specifying any test, it considers running all
the tests it can find. More on the test selection
<a href="https://docs.pytest.org/en/6.2.x/usage.html#specifying-tests-selecting-tests">here</a>
You probably noticed that <code>--cassandra-dir=/home/cassandra/cassandra</code>
is constantly added to the command line. It is
one of the <code>cassandra-dtest</code> custom arguments - the mandatory one -
unless it is defined, you cannot run any Cassandra dtest.</p>
</div>
</div>
<div class="sect3">
<h4 id="setting-up-pytest"><a class="anchor" href="#setting-up-pytest"></a>Setting up PyTest</h4>
<div class="paragraph">
<p>All the possible options can be listed by invoking pytest <code>--help</code>. You
see tons of possible parameters - some of them are native PyTest
options, and some come from Cassandra DTest. When you look carefully at
the help note, you notice that some commonly used options, usually fixed
for all the invocations, can be put into the <code>pytest.ini</code> file. In
particular, it is quite practical to define the following:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-none hljs" data-lang="none">cassandra_dir = /home/cassandra/cassandra
log_cli = True
log_cli_level = DEBUG</code></pre>
</div>
</div>
<div class="paragraph">
<p>so that you do not have to provide <code>--cassandra-dir</code> param each time you
run a test. The other two options set up console logging - remove them
if you want logs stored only in log files.</p>
</div>
</div>
<div class="sect3">
<h4 id="running-tests-with-specific-configuration"><a class="anchor" href="#running-tests-with-specific-configuration"></a>Running tests with specific configuration</h4>
<div class="paragraph">
<p>There are a couple of options to enforce exact test configuration (their
names are quite self-explanatory):</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>--use-vnodes</code></p>
</li>
<li>
<p><code>--num-token=xxx</code> - enables the support of virtual nodes with a certain
number of tokens</p>
</li>
<li>
<p><code>--use-off-heap-memtables</code> - use off-heap memtables instead of the
default heap-based</p>
</li>
<li>
<p>`--data-dir-count-per-instance=xxx - the number of data directories
configured per each instance</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Note that the list can grow in the future as new predefined
configurations can be added to dtests. It is also possible to pass extra
Java properties to each Cassandra node started by the tests - define
those options in the <code>JVM_EXTRA_OPTS</code> environment variable before
running the test.</p>
</div>
</div>
<div class="sect3">
<h4 id="listing-the-tests"><a class="anchor" href="#listing-the-tests"></a>Listing the tests</h4>
<div class="paragraph">
<p>You can do a dry run, so that the tests are only listed and not
invoked. To do that, add <code>--collect-only</code> to the pytest command.
That additional <code>-q</code> option will print the results in the same
format as you would pass the test name to the pytest command:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-plaintext hljs" data-lang="plaintext">pytest --collect-only -q</code></pre>
</div>
</div>
<div class="paragraph">
<p>lists all the tests pytest would run if no particular test is specified.
Similarly, to list test cases in some class, do:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-plaintext hljs" data-lang="plaintext">$ pytest --collect-only -q schema_metadata_test.py::TestSchemaMetadata
schema_metadata_test.py::TestSchemaMetadata::test_creating_and_dropping_keyspace
schema_metadata_test.py::TestSchemaMetadata::test_creating_and_dropping_table
schema_metadata_test.py::TestSchemaMetadata::test_creating_and_dropping_table_with_2ary_indexes
schema_metadata_test.py::TestSchemaMetadata::test_creating_and_dropping_user_types
schema_metadata_test.py::TestSchemaMetadata::test_creating_and_dropping_udf
schema_metadata_test.py::TestSchemaMetadata::test_creating_and_dropping_uda
schema_metadata_test.py::TestSchemaMetadata::test_basic_table_datatype
schema_metadata_test.py::TestSchemaMetadata::test_collection_table_datatype
schema_metadata_test.py::TestSchemaMetadata::test_clustering_order
schema_metadata_test.py::TestSchemaMetadata::test_compact_storage
schema_metadata_test.py::TestSchemaMetadata::test_compact_storage_composite
schema_metadata_test.py::TestSchemaMetadata::test_nondefault_table_settings
schema_metadata_test.py::TestSchemaMetadata::test_indexes
schema_metadata_test.py::TestSchemaMetadata::test_durable_writes
schema_metadata_test.py::TestSchemaMetadata::test_static_column
schema_metadata_test.py::TestSchemaMetadata::test_udt_table
schema_metadata_test.py::TestSchemaMetadata::test_udf
schema_metadata_test.py::TestSchemaMetadata::test_uda</code></pre>
</div>
</div>
<div class="paragraph">
<p>You can copy/paste the selected test case to the pytest command to
run it.</p>
</div>
</div>
<div class="sect3">
<h4 id="filtering-tests"><a class="anchor" href="#filtering-tests"></a>Filtering tests</h4>
<div class="sect4">
<h5 id="based-on-configuration"><a class="anchor" href="#based-on-configuration"></a>Based on configuration</h5>
<div class="paragraph">
<p>Most tests run with any configuration, but a subset of tests (test
cases) only run if a specific configuration is used. In particular,
there are tests annotated with:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>@pytest.mark.vnodes</code> - the test is only invoked when the support of
virtual nodes is enabled</p>
</li>
<li>
<p><code>@pytest.mark.no_vnodes</code> - the test is only invoked when the support
of virtual nodes is disabled</p>
</li>
<li>
<p><code>@pytest.mark.no_offheap_memtables</code> - the test is only invoked if
off-heap memtables are not used</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Note that enabling or disabling <em>vnodes</em> is obviously mutually
exclusive. If a test is marked to run only with <em>vnodes</em>, it does not
run when <em>vnodes</em> is disabled; similarly, when a test is marked to run
only without <em>vnodes</em>, it does not run when <em>vnodes</em> is enabled -
therefore, there are always some tests which would not run with a single
configuration.</p>
</div>
</div>
<div class="sect4">
<h5 id="based-on-resource-usage"><a class="anchor" href="#based-on-resource-usage"></a>Based on resource usage</h5>
<div class="paragraph">
<p>There are also tests marked with:</p>
</div>
<div class="paragraph">
<p><code>@pytest.mark.resource_intensive</code></p>
</div>
<div class="paragraph">
<p>which means that the test requires more resources than a regular test
because it usually starts a cluster of several nodes. The meaning of
resource-intensive is hardcoded to 32GB of available memory, and unless
your machine or docker container has at least that amount of RAM, such
test is skipped. There are a couple of arguments that allow for some
control of that automatic exclusion:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>--force-resource-intensive-tests</code> - forces the execution of tests
marked as <code>resource_intensive</code>, regardless of whether there is enough
memory available or not</p>
</li>
<li>
<p><code>--only-resource-intensive-tests</code> - only run tests marked as
<code>resource_intensive</code> - it makes all the tests without
<code>resource_intensive</code> annotation to be filtered out; technically, it is
equivalent to passing native PyTest argument: <code>-m resource_intensive</code></p>
</li>
<li>
<p><code>--skip-resource-intensive-tests</code> - skip all tests marked as
<code>resource_intensive</code> - it is the opposite argument to the previous one,
and it is equivalent to the PyTest native argument: <code>-m 'not resource_intensive'</code></p>
</li>
</ul>
</div>
</div>
<div class="sect4">
<h5 id="based-on-the-test-type"><a class="anchor" href="#based-on-the-test-type"></a>Based on the test type</h5>
<div class="paragraph">
<p>Upgrade tests are marked with:</p>
</div>
<div class="paragraph">
<p><code>@pytest.mark.upgrade_test</code></p>
</div>
<div class="paragraph">
<p>Those tests are not invoked by default at all (just like running
PyTest with <code>-m 'not upgrade_test'</code>), and you have to add some extra
options to run them:
* <code>--execute-upgrade-tests</code> - enables execution of upgrade tests along
with other tests - when this option is added, the upgrade tests are not
filtered out
* <code>--execute-upgrade-tests-only</code> - execute only upgrade tests and filter
out all other tests which do not have <code>@pytest.mark.upgrade_test</code>
annotation (just like running PyTest with <code>-m 'upgrade_test'</code>)</p>
</div>
</div>
<div class="sect4">
<h5 id="filtering-examples"><a class="anchor" href="#filtering-examples"></a>Filtering examples</h5>
<div class="paragraph">
<p>It does not matter whether you want to invoke individual tests or all
tests or whether you only want to list them; the above filtering rules
apply. So by using <code>--collect-only</code> option, you can learn which tests
would be invoked.</p>
</div>
<div class="paragraph">
<p>To list all the applicable tests for the current configuration, use the
following command:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-plaintext hljs" data-lang="plaintext">pytest --collect-only -q --execute-upgrade-tests --force-resource-intensive-tests</code></pre>
</div>
</div>
<div class="paragraph">
<p>List tests specific to vnodes (which would only run if vnodes are enabled):</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-plaintext hljs" data-lang="plaintext">pytest --collect-only -q --execute-upgrade-tests --force-resource-intensive-tests --use-vnodes -m vnodes</code></pre>
</div>
</div>
<div class="paragraph">
<p>List tests that are not resource-intensive</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-plaintext hljs" data-lang="plaintext">pytest --collect-only -q --execute-upgrade-tests --skip-resource-intensive-tests</code></pre>
</div>
</div>
</div>
</div>
<div class="sect3">
<h4 id="upgrade-tests-2"><a class="anchor" href="#upgrade-tests-2"></a>Upgrade tests</h4>
<div class="paragraph">
<p>Upgrade tests always involve more than one product version. There are
two kinds of upgrade tests regarding the product versions they span -
let’s call them fixed and generated.</p>
</div>
<div class="paragraph">
<p>In case of fixed tests, the origin and target versions are hardcoded.
They look pretty usual, for example:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-plaintext hljs" data-lang="plaintext">pytest --collect-only -q --execute-upgrade-tests --execute-upgrade-tests-only upgrade_tests/upgrade_supercolumns_test.py</code></pre>
</div>
</div>
<div class="paragraph">
<p>prints:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-plaintext hljs" data-lang="plaintext">upgrade_tests/upgrade_supercolumns_test.py::TestSCUpgrade::test_upgrade_super_columns_through_all_versions
upgrade_tests/upgrade_supercolumns_test.py::TestSCUpgrade::test_upgrade_super_columns_through_limited_versions</code></pre>
</div>
</div>
<div class="paragraph">
<p>When you look into the code, you will see the fixed upgrade path:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-python hljs" data-lang="python">def test_upgrade_super_columns_through_all_versions(self):
self._upgrade_super_columns_through_versions_test(upgrade_path=[indev_2_2_x, indev_3_0_x, indev_3_11_x, indev_trunk])</code></pre>
</div>
</div>
<div class="paragraph">
<p>The generated upgrade tests are listed several times - the first
occurrence of the test case is a generic test definition, and then
it is repeated many times in generated test classes. For example:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-plaintext hljs" data-lang="plaintext">pytest --cassandra-dir=/home/cassandra/cassandra --collect-only -q --execute-upgrade-tests --execute-upgrade-tests-only upgrade_tests/cql_tests.py -k test_set</code></pre>
</div>
</div>
<div class="paragraph">
<p>prints:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-plaintext hljs" data-lang="plaintext">upgrade_tests/cql_tests.py::cls::test_set
upgrade_tests/cql_tests.py::TestCQLNodes3RF3_Upgrade_current_2_2_x_To_indev_2_2_x::test_set
upgrade_tests/cql_tests.py::TestCQLNodes3RF3_Upgrade_current_3_0_x_To_indev_3_0_x::test_set
upgrade_tests/cql_tests.py::TestCQLNodes3RF3_Upgrade_current_3_11_x_To_indev_3_11_x::test_set
upgrade_tests/cql_tests.py::TestCQLNodes3RF3_Upgrade_current_4_0_x_To_indev_4_0_x::test_set
upgrade_tests/cql_tests.py::TestCQLNodes3RF3_Upgrade_indev_2_2_x_To_indev_3_0_x::test_set
upgrade_tests/cql_tests.py::TestCQLNodes3RF3_Upgrade_indev_2_2_x_To_indev_3_11_x::test_set
upgrade_tests/cql_tests.py::TestCQLNodes3RF3_Upgrade_indev_3_0_x_To_indev_3_11_x::test_set
upgrade_tests/cql_tests.py::TestCQLNodes3RF3_Upgrade_indev_3_0_x_To_indev_4_0_x::test_set
upgrade_tests/cql_tests.py::TestCQLNodes3RF3_Upgrade_indev_3_11_x_To_indev_4_0_x::test_set
upgrade_tests/cql_tests.py::TestCQLNodes3RF3_Upgrade_indev_4_0_x_To_indev_trunk::test_set
upgrade_tests/cql_tests.py::TestCQLNodes2RF1_Upgrade_current_2_2_x_To_indev_2_2_x::test_set
upgrade_tests/cql_tests.py::TestCQLNodes2RF1_Upgrade_current_3_0_x_To_indev_3_0_x::test_set
upgrade_tests/cql_tests.py::TestCQLNodes2RF1_Upgrade_current_3_11_x_To_indev_3_11_x::test_set
upgrade_tests/cql_tests.py::TestCQLNodes2RF1_Upgrade_current_4_0_x_To_indev_4_0_x::test_set
upgrade_tests/cql_tests.py::TestCQLNodes2RF1_Upgrade_indev_2_2_x_To_indev_3_0_x::test_set
upgrade_tests/cql_tests.py::TestCQLNodes2RF1_Upgrade_indev_2_2_x_To_indev_3_11_x::test_set
upgrade_tests/cql_tests.py::TestCQLNodes2RF1_Upgrade_indev_3_0_x_To_indev_3_11_x::test_set
upgrade_tests/cql_tests.py::TestCQLNodes2RF1_Upgrade_indev_3_0_x_To_indev_4_0_x::test_set
upgrade_tests/cql_tests.py::TestCQLNodes2RF1_Upgrade_indev_3_11_x_To_indev_4_0_x::test_set
upgrade_tests/cql_tests.py::TestCQLNodes2RF1_Upgrade_indev_4_0_x_To_indev_trunk::test_set</code></pre>
</div>
</div>
<div class="paragraph">
<p>In this example, the test case name is just <code>test_set</code>, and the class
name is <code>TestCQL</code> - the suffix of the class name is automatically
generated from the provided specification. The first component is the
cluster specification - there are two variants: <code>Nodes2RF1</code> and <code>Nodes3RF3</code>
- they denote that the upgrade is tested on 2 nodes cluster with a
keyspace using replication factor = 1. Analogously the second variant
uses 3 nodes cluster with RF = 3.</p>
</div>
<div class="paragraph">
<p>Then, there is the upgrade specification - for example,
<code>Upgrade_indev_3_11_x_To_indev_4_0_x</code> - which means that this test
upgrades from the development version of Cassandra 3.11 to the
development version of Cassandra 4.0 - the meaning of <code>indev/current</code>
and where they are defined is explained later.</p>
</div>
<div class="paragraph">
<p>When you look into the implementation, you notice that such upgrade test
classes inherit from <code>UpgradeTester</code> class, and they have the
specifications defined at the end of the file. In this particular case,
it is something like:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-python hljs" data-lang="python">topology_specs = [
{'NODES': 3,
'RF': 3,
'CL': ConsistencyLevel.ALL},
{'NODES': 2,
'RF': 1},
]
specs = [dict(s, UPGRADE_PATH=p, __test__=True)
for s, p in itertools.product(topology_specs, build_upgrade_pairs())]</code></pre>
</div>
</div>
<div class="paragraph">
<p>As you can see, there is a list of the cluster specifications and
the cross product is calculated with upgrade paths returned by the
<code>build_upgrade_pairs()</code> function. That list of specifications is used to
dynamically generate upgrade tests.</p>
</div>
<div class="paragraph">
<p>Suppose you need to test something specifically for your scenario. In
that case, you can add more cluster specifications, like a test with 1
node or a test with 5 nodes with some different replication factor or
consistency level. The <code>build_upgrade_pairs()</code> returns the list of
upgrade paths (actually just the origin and target version). That list
is generated according to the upgrade manifest.</p>
</div>
<div class="sect4">
<h5 id="upgrade-manifest"><a class="anchor" href="#upgrade-manifest"></a>Upgrade manifest</h5>
<div class="paragraph">
<p>The upgrade manifest is a file where all the upgrade paths are defined.
It is a regular Python file located at
<code>upgrade_tests/upgrade_manifest.py</code>.
As you noticed, Cassandra origin and target version descriptions
mentioned in the upgrade test consist of <code>indev</code> or <code>current</code> prefix
followed by version string. The definitions of each such version
description can be found in the manifest, for example:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-python hljs" data-lang="python">indev_3_11_x = VersionMeta(name='indev_3_11_x', family=CASSANDRA_3_11, variant='indev', version='github:apache/cassandra-3.11', min_proto_v=3, max_proto_v=4, java_versions=(8,))
current_3_11_x = VersionMeta(name='current_3_11_x', family=CASSANDRA_3_11, variant='current', version='3.11.10', min_proto_v=3, max_proto_v=4, java_versions=(8,))</code></pre>
</div>
</div>
<div class="paragraph">
<p>There are a couple of different properties which describe those two
versions:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>name</code> - is a name as you can see in the names of the generated
test classes</p>
</li>
<li>
<p><code>family</code> - families is an enumeration defined in the beginning of
the upgrade manifest - say family <code>CASSANDRA_3_11</code> is just a string
<code>"3.11"</code>. Some major features were introduced or removed with new
version families, and therefore some checks can be done or some features
can be enabled/disabled according to that, for example:</p>
</li>
</ul>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-python hljs" data-lang="python">if self.cluster.version() &lt; CASSANDRA_4_0:
node1.nodetool("enablethrift")</code></pre>
</div>
</div>
<div class="paragraph">
<p>But it is also used to determine whether our checked-out version matches
the target version in the upgrade pair (more on that later)</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>variant</code> and <code>version</code> - there are <code>indev</code> or <code>current</code> variants:</p>
<div class="ulist">
<ul>
<li>
<p><code>indev</code> variant means that the development version of Cassandra
will be used. That is, that version is checked out from the Git
repository and built before running the upgrade (CCM does it). In this
case, the version string is specified as <code>github:apache/cassandra-3.11</code>,
which means that it will checkout the <code>cassandra-3.11</code> branch from the
GitHub repository whose alias is <code>apache</code>. Aliases are defined in CCM
configuration file, usually located at <code>~/.ccm/config</code> - in this
particular case, it could be something like:</p>
</li>
</ul>
</div>
</li>
</ul>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-none hljs" data-lang="none">[aliases]
apache:git@github.com:apache/cassandra.git</code></pre>
</div>
</div>
<div class="ulist">
<ul>
<li>
<p><code>current</code> variant means that a released version of Cassandra will
be used. It means that Cassandra distribution denoted by the specified
version (3.11.10 in this case) is downloaded from the Apache
repository/mirror - again, the repository can be defined in CCM
configuration file, under repositories section, something like:</p>
</li>
</ul>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-none hljs" data-lang="none">[repositories]
cassandra=https://archive.apache.org/dist/cassandra</code></pre>
</div>
</div>
<div class="ulist">
<ul>
<li>
<p><code>min_proto_v</code>, <code>max_proto_v</code> - the range of usable Cassandra driver
protocol versions</p>
</li>
<li>
<p><code>java_versions</code> - supported Java versions</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>The possible upgrade paths are defined later in the upgrade manifest -
when you scroll the file, you will find the <code>MANIFEST</code> map which may
look similar to:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-python hljs" data-lang="python">MANIFEST = {
current_2_1_x: [indev_2_2_x, indev_3_0_x, indev_3_11_x],
current_2_2_x: [indev_2_2_x, indev_3_0_x, indev_3_11_x],
current_3_0_x: [indev_3_0_x, indev_3_11_x, indev_4_0_x],
current_3_11_x: [indev_3_11_x, indev_4_0_x],
current_4_0_x: [indev_4_0_x, indev_trunk],
indev_2_2_x: [indev_3_0_x, indev_3_11_x],
indev_3_0_x: [indev_3_11_x, indev_4_0_x],
indev_3_11_x: [indev_4_0_x],
indev_4_0_x: [indev_trunk]
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>It is a simple map where for the origin version (as a key), there is
a list of possible target versions (as a value). Say:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-python hljs" data-lang="python">current_4_0_x: [indev_4_0_x, indev_trunk]</code></pre>
</div>
</div>
<div class="paragraph">
<p>means that upgrades from <code>current_4_0_x</code> to
<code>indev_4_0_x</code> and from <code>current_4_0_x</code> to <code>indev_trunk</code> will be considered.
You may make changes to that upgrade scenario in your development branch
according to your needs.
There is a command-line option that allows filtering across upgrade
scenarios: <code>--upgrade-version-selection=xxx</code>. The possible values for
that options are as follows:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>indev</code> - which is the default, only selects those upgrade scenarios
where the target version is in <code>indev</code> variant</p>
</li>
<li>
<p><code>both</code> - selects upgrade paths where either both origin and target
versions are in the same variant or have the same version family</p>
</li>
<li>
<p><code>releases</code> - selects upgrade paths between versions in current variant
or from the <code>current</code> to <code>indev</code> variant if both have the same version
family</p>
</li>
<li>
<p><code>all</code> - no filtering at all - all variants are tested</p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect3">
<h4 id="running-upgrades-with-local-distribution"><a class="anchor" href="#running-upgrades-with-local-distribution"></a>Running upgrades with local distribution</h4>
<div class="paragraph">
<p>The upgrade test can use your local Cassandra distribution, the one
specified by the <code>cassandra_dir</code> property, as the target version if the
following preconditions are satisfied:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>the target version is in the <code>indev</code> variant,</p>
</li>
<li>
<p>the version family set in the version description matches the version
family of your local distribution</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>For example, your local distribution is branched off from the
<code>cassandra-4.0</code> branch, likely matching <code>indev_4_0_x</code>. It means that the
upgrade path with target version <code>indev_4_0_x</code> uses your local
distribution.
There is a handy command line option which will filter out all the
upgrade tests which do not match the local distribution:
<code>--upgrade-target-version-only</code>. Given you are on <code>cassandra-4.0</code> branch,
when applied to the previous example, it will be something similar to:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-plaintext hljs" data-lang="plaintext">pytest --cassandra-dir=/home/cassandra/cassandra --collect-only -q --execute-upgrade-tests --execute-upgrade-tests-only upgrade_tests/cql_tests.py -k test_set --upgrade-target-version-only</code></pre>
</div>
</div>
<div class="paragraph">
<p>prints:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-plaintext hljs" data-lang="plaintext">upgrade_tests/cql_tests.py::cls::test_set
upgrade_tests/cql_tests.py::TestCQLNodes3RF3_Upgrade_current_4_0_x_To_indev_4_0_x::test_set
upgrade_tests/cql_tests.py::TestCQLNodes3RF3_Upgrade_indev_3_0_x_To_indev_4_0_x::test_set
upgrade_tests/cql_tests.py::TestCQLNodes3RF3_Upgrade_indev_3_11_x_To_indev_4_0_x::test_set
upgrade_tests/cql_tests.py::TestCQLNodes2RF1_Upgrade_current_4_0_x_To_indev_4_0_x::test_set
upgrade_tests/cql_tests.py::TestCQLNodes2RF1_Upgrade_indev_3_0_x_To_indev_4_0_x::test_set
upgrade_tests/cql_tests.py::TestCQLNodes2RF1_Upgrade_indev_3_11_x_To_indev_4_0_x::test_set</code></pre>
</div>
</div>
<div class="paragraph">
<p>You can see that the upgrade tests were limited to the ones whose target
version is <code>indev</code> and family matches 4.0.</p>
</div>
</div>
<div class="sect3">
<h4 id="logging"><a class="anchor" href="#logging"></a>Logging</h4>
<div class="paragraph">
<p>A couple of common PyTest arguments control what is logged to the file
and the console from the Python test code. Those arguments which start
from <code>--log-xxx</code> are pretty well described in the help message
(<code>pytest --help</code>) and in PyTest documentation, so it will not be discussed
further. However, most of the tests start with the cluster of
Cassandra nodes, and each node generates its own logging information and
has its own data directories.</p>
</div>
<div class="paragraph">
<p>By default the logs from the nodes are copied to the unique directory
created under logs subdirectory under root of dtest project. For example:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-plaintext hljs" data-lang="plaintext">(venv) cassandra@b69a382da7cd:~/cassandra-dtest$ ls logs/ -1
1627455923457_test_set
1627456019264_test_set
1627456474949_test_set
1627456527540_test_list
last</code></pre>
</div>
</div>
<div class="paragraph">
<p>The <code>last</code> item is a symbolic link to the directory containing the logs
from the last executed test. Each such directory includes logs from each
started node - system, debug, GC as well as standard streams registered
upon each time the node was started:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-plaintext hljs" data-lang="plaintext">(venv) cassandra@b69a382da7cd:~/cassandra-dtest$ ls logs/last -1
node1.log
node1_debug.log
node1_gc.log
node1_startup-1627456480.3398306-stderr.log
node1_startup-1627456480.3398306-stdout.log
node1_startup-1627456507.2186499-stderr.log
node1_startup-1627456507.2186499-stdout.log
node2.log
node2_debug.log
node2_gc.log
node2_startup-1627456481.10463-stderr.log
node2_startup-1627456481.10463-stdout.log</code></pre>
</div>
</div>
<div class="paragraph">
<p>Those log files are not collected if <code>--delete-logs</code> command-line option
is added to PyTest. The nodes also produce data files which may be
sometimes useful to examine to resolve some failures. Those files are
usually deleted when the test is completed, but there are some options
to control that behavior:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>--keep-test-dir</code> - keep the whole CCM directory with data files and
logs when the test completes</p>
</li>
<li>
<p><code>--keep-failed-test-dir</code> – only keep that directory when the test has
failed</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Now, how to find where is that directory for the certain test - you need
to grab that information from the test logs - for example, you may add
<code>-s</code> option to the command line and then look for <code>"dtest_setup INFO"</code>
messages. For example:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-plain hljs" data-lang="plain">05:56:06,383 dtest_setup INFO cluster ccm directory: /tmp/dtest-0onwvgkr</code></pre>
</div>
</div>
<div class="paragraph">
<p>says that the cluster work directory is <code>/tmp/dtest-0onwvgkr</code>, and all
node directories can be found under the <code>test</code> subdirectory:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-plaintext hljs" data-lang="plaintext">(venv) cassandra@b69a382da7cd:~/cassandra-dtest$ ls /tmp/dtest-0onwvgkr/test -1
cluster.conf
node1
node2</code></pre>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="performance-testing"><a class="anchor" href="#performance-testing"></a>Performance Testing</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Performance tests for Cassandra are a special breed of tests that are
not part of the usual patch contribution process. In fact, many people
contribute a lot of patches to Cassandra without ever running performance
tests. However, they are important when working on performance
improvements; such improvements must be measurable.</p>
</div>
<div class="paragraph">
<p>Several tools exist for running performance tests. Here are a few to investigate:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Described above <a href="#microbenchmarks">Micro-benchmarks</a></p>
</li>
<li>
<p><code>cassandra-stress</code>: built-in Cassandra stress tool</p>
</li>
<li>
<p><a href="https://github.com/thelastpickle/tlp-stress">tlp-stress</a></p>
</li>
<li>
<p><a href="https://github.com/nosqlbench/nosqlbench">NoSQLBench</a></p>
</li>
</ul>
</div>
</div>
</div>
<h1 id="code-style" class="sect0"><a class="anchor" href="#code-style"></a>Code Style</h1>
<div class="paragraph">
<p>The Cassandra project follows
<a href="http://java.sun.com/docs/codeconv/html/CodeConvTOC.doc.html">Sun&#8217;s Java
coding conventions</a> for anything not expressly outlined in this document.</p>
</div>
<div class="paragraph">
<p>Note that the project has a variety of styles that have accumulated in different subsystems. Where possible a balance should be struck between these guidelines and the style of the code that is being modified as part of a patch. Patches should also limit their scope to the minimum necessary for safely addressing the concerns of the patch.</p>
</div>
<div class="sect1">
<h2 id="checkstyle"><a class="anchor" href="#checkstyle"></a>Checkstyle</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Cassandra uses <a href="https://checkstyle.sourceforge.io/">Checkstyle</a> project for enforcing various checkstyle policies the project follows. Checkstyle is part of the build from Cassandra 4.1 included.
You can consult the checkstyle configuration file called <code>checkstyle.xml</code> for the source code in <code>src</code> directory and <code>checkstyle_test.xml</code> for all code in <code>test</code> directory.
The configuration files are located in the root of the Cassandra repository. Checkstyle can be executed independently for the main source code as well as for the tests by executing <code>ant checkstyle</code> and <code>ant checkstyle-test</code> respectively.</p>
</div>
<div class="paragraph">
<p>The checkstyle target is executed by default when e.g. <code>build</code> or <code>jar</code> targets are executed. There is a flag you can use for <em>not</em> enforcing checkstyle. This is particularly handy upon development.
For example, by default, the checkstyle target checks that your changes in Java code do not include imports which are not used.
However, while you develop, you do not want this check to be enforced because you are not interested in it while you develop as your code tends to be in the in-progress state.
You can turn whole checkstyle off by specifying <code>-Dno-checkstyle=true</code> on the command line, for example like this: <code>ant build -Dno-checkstyle=true</code>.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="naming-and-clear-semantics"><a class="anchor" href="#naming-and-clear-semantics"></a>Naming and Clear Semantics</h2>
<div class="sectionbody">
<div class="sect3">
<h4 id="class-method-and-variable-naming"><a class="anchor" href="#class-method-and-variable-naming"></a>Class, Method and Variable Naming</h4>
<div class="paragraph">
<p>Avoid extraneous words, for example prefer <code>x()</code> over <code>getX()</code> or <code>setX()</code> where it makes semantic sense. At the same time, do not avoid using words that are necessary, for example if a descriptive word provides semantic context such as <code>liveReplicas</code> over <code>replicas</code>. This is essential when there are many conceptual instantiations for a variable that are not enforced by the type system, but be sure to be consistent in the word choice and order across all instantiations of the variable.</p>
</div>
<div class="paragraph">
<p>e.g. <em>allReplicas</em>, <em>naturalReplicas</em>, <em>pendingReplicas</em>, <em>allLiveReplicas</em>, etc.</p>
</div>
</div>
<div class="sect3">
<h4 id="method-and-variable-naming-consistency"><a class="anchor" href="#method-and-variable-naming-consistency"></a>Method and Variable Naming Consistency</h4>
<div class="paragraph">
<p>Ensure consistency of naming within a method, and between methods. It may be that multiple names are appropriate for a concept, but these should not be mixed and matched within the project. If you modify a concept, or improve the naming of a concept, make all relevant - including existing - code consistent with the new terminology. If possible, correspond with a prior author before modifying their semantics.</p>
</div>
<div class="sect4">
<h5 id="standard-word-meanings-in-method-or-property-names"><a class="anchor" href="#standard-word-meanings-in-method-or-property-names"></a>Standard word meanings in method or property names</h5>
<table class="tableblock frame-all grid-all stretch">
<colgroup>
<col style="width: 50%;">
<col style="width: 50%;">
</colgroup>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>calculateX</code>,<code>computeX</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Perform some potentially expensive work to produce x</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>refreshX</code>,<code>updateX</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Recompute a memoized x</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>lookupX</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Find x in a map, or other structure, that is efficient but not free</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>x</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Return x, relatively cheaply</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>toX</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Return a potentially expensive translation to x</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>asX</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Return a cheap translation to x</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>asXView</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Return a cheap translation to x, that will reflect changes in the source</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>isX</code>, <code>hasX</code>, <code>canX</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Boolean property or method indicating a capability or logical state</p></td>
</tr>
</tbody>
</table>
<div class="paragraph">
<p>For boolean variables, fields and methods, choose names that sound like predicates and cannot be confused with nouns.</p>
</div>
</div>
</div>
<div class="sect3">
<h4 id="semantic-distinctions-via-the-type-system"><a class="anchor" href="#semantic-distinctions-via-the-type-system"></a>Semantic Distinctions via the Type System</h4>
<div class="paragraph">
<p>If possible, enforce semantic distinctions at compile time with the type system.</p>
</div>
<div class="paragraph">
<p><em>e.g. <code>RangesAtEndpoint</code>, <code>EndpointsForRange</code> and <code>EndpointsForToken</code> are all semantically different variants on a collection of replicas.</em></p>
</div>
<div class="paragraph">
<p>This makes the intent of the code clearer, and helps the compiler indicate where we may have unintentionally conflated concepts. They also provide opportunities to insert stronger runtime checks that our assumptions hold, and these constraints can provide further clarity when reading the code.</p>
</div>
<div class="paragraph">
<p><em>In the case of <code>EndpointsForX</code>, for instance, we enforce that we have no duplicate endpoints, and that all of the endpoints do fully cover X.</em></p>
</div>
<div class="sect4">
<h5 id="enums-for-boolean-properties"><a class="anchor" href="#enums-for-boolean-properties"></a>Enums for Boolean Properties</h5>
<div class="paragraph">
<p>Prefer an <code>enum</code> to <code>boolean</code> properties and parameters, unless clarity will be harmed (e.g. helper methods that accept a computed boolean predicate result, of the same name as used in the method they assist). Try to balance name clashes that would affect static imports, against clear and simple names that represent the behavioural switch.</p>
</div>
</div>
</div>
<div class="sect3">
<h4 id="semantic-distinctions-via-member-variables"><a class="anchor" href="#semantic-distinctions-via-member-variables"></a>Semantic Distinctions via Member Variables</h4>
<div class="paragraph">
<p>If a separate type for all concepts is too burdensome, a type that aggregates concepts together within member variables might be applicable.</p>
</div>
<div class="paragraph">
<p>The most obvious counter-example is not to use <code>Pair</code>, or a similar tuple. Unless it is extremely obvious, prefer a dedicated type with well named member variables.</p>
</div>
<div class="paragraph">
<p><em>For example, <code>FetchReplicas</code> for source and target replicas, and <code>ReplicaLayout</code> for the distinction between natural and pending replicas.</em></p>
</div>
<div class="paragraph">
<p>This may help authors notice other semantics they had overlooked, that might have led to subtly incorrect parameter provision to methods. Conversely, methods may choose to accept one of these encapsulating types, so that callers do not need to consider which member they should provide.</p>
</div>
<div class="paragraph">
<p><em>e.g. <code>ConsistencyLevel.assureSufficientLiveReplicas</code> requires very specific replica collections, that are quite distinct, that might be easily incorrectly provided (though this is still inadequate, as it needs to distinguish between live and non-live semantics, which remains to be improved)</em></p>
</div>
</div>
<div class="sect3">
<h4 id="public-apis"><a class="anchor" href="#public-apis"></a>Public APIs</h4>
<div class="paragraph">
<p>These considerations are especially important for public APIs, including CQL, virtual tables, JMX, yaml, system properties, etc. Any planned additions must be carefully considered in the context of any existing APIs. Where possible the approach of any existing API should be followed. Where the existing API is poorly suited, a strategy should be developed to modify or replace the existing API with one that is more coherent in light of the changes - which should also carefully consider any planned or expected future changes to minimise churn. Any strategy for modifying APIs should be brought to <a href="mailto:dev@cassandra.apache.org">dev@cassandra.apache.org</a> for discussion.</p>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="code-structure"><a class="anchor" href="#code-structure"></a>Code Structure</h2>
<div class="sectionbody">
<div class="sect3">
<h4 id="necessity"><a class="anchor" href="#necessity"></a>Necessity</h4>
<div class="paragraph">
<p>If an interface has only one implementation, remove it. If a method isn’t used, delete it.</p>
</div>
<div class="paragraph">
<p>Don’t implement <code>hashCode()</code>, <code>equals()</code>, <code>toString()</code> or other methods unless they provide immediate utility.</p>
</div>
</div>
<div class="sect3">
<h4 id="specificity"><a class="anchor" href="#specificity"></a>Specificity</h4>
<div class="paragraph">
<p>Don’t overgeneralise. Implement the most specific method or class that you can, that handles the present use cases.</p>
</div>
<div class="paragraph">
<p>Methods and classes should have a single clear purpose, and should avoid special-cases where practical.</p>
</div>
</div>
<div class="sect3">
<h4 id="class-layout"><a class="anchor" href="#class-layout"></a>Class Layout</h4>
<div class="paragraph">
<p>Consider where your methods and inner classes live with respect to each other. Methods that are of a similar category should be adjacent, as should methods that are primarily dependent on each other. Try to use a consistent pattern, e.g. helper methods may occur either before or after the method that uses them, but not both; method signatures that cover different combinations of parameters should occur in a consistent order visiting the parameter space.</p>
</div>
<div class="paragraph">
<p>Class declaration order should, approximately, go: inner classes, static properties, instance properties, constructors (incl static factory methods), getters/setters, main functional/API methods, helper (incl static) methods and classes. Clarity should always come first, however.</p>
</div>
</div>
<div class="sect3">
<h4 id="method-clarity"><a class="anchor" href="#method-clarity"></a>Method Clarity</h4>
<div class="paragraph">
<p>A method should be short. There is no hard size limit, but a filled screen is a good warning size. However, be careful not to over-minimise your methods; a page of tiny functions is also hard to read.</p>
</div>
<div class="paragraph">
<p>The body of a method should be limited to the main conceptual work being done. Substantive ancillary logic, such as computing an intermediate result, evaluating complex predicates, performing auditing, logging, etc, are prime candidates for helper methods.</p>
</div>
</div>
<div class="sect3">
<h4 id="compiler-assistance"><a class="anchor" href="#compiler-assistance"></a>Compiler Assistance</h4>
<div class="paragraph">
<p>Always use <code>@Override</code> annotations when implementing abstract or interface methods or overriding a parent method.</p>
</div>
<div class="paragraph">
<p><code>@Nullable</code>, <code>@NonNull</code>, <code>@ThreadSafe</code>, <code>@NotThreadSafe</code> and <code>@Immutable</code> should be used as appropriate to communicate to both the compiler and readers.</p>
</div>
</div>
<div class="sect3">
<h4 id="boilerplate"><a class="anchor" href="#boilerplate"></a>Boilerplate</h4>
<div class="paragraph">
<p>Prefer <code>public final</code> fields to private fields with getters (but prefer encapsulating behavior in "real" methods to either).</p>
</div>
<div class="paragraph">
<p>Declare class properties <code>final</code> wherever possible, but never declare local variables and parameters <code>final</code>. Variables and parameters should still be treated as immutable wherever possible, with explicit code blocks introduced as necessary to minimize the scope of any mutable variables.</p>
</div>
<div class="paragraph">
<p>Prefer initialization in a constructor to setters, and builders where the constructor is complex with many optional parameters.</p>
</div>
<div class="paragraph">
<p>Avoid redundant <code>this</code> references to member fields or methods, except for consistency with other assignments e.g. in the constructor</p>
</div>
</div>
<div class="sect3">
<h4 id="exception-handling"><a class="anchor" href="#exception-handling"></a>Exception handling</h4>
<div class="paragraph">
<p>Never ever write <code>catch (…)</code> {} or <code>catch (…) { logger.error() }</code> merely to satisfy Java’s compile-time exception checking.</p>
</div>
<div class="paragraph">
<p>Always catch the narrowest exception type possible for achieving your goal. If Throwable must be caught for handling exceptional termination, it must be rethrown. If an exception cannot be safely handled locally, propagate it - but use unchecked exceptions if no caller expects to handle the case. Rethrow as <code>RuntimeException</code>, <code>IOError</code>, or your own <code>UncheckedXException</code>, or <code>IllegalStateException</code> if it “can’t happen”</p>
</div>
<div class="paragraph">
<p>Only if an exception is an explicitly acceptable condition can it be ignored, but this must be explained carefully in a comment detailing how this is handled correctly.</p>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="formatting"><a class="anchor" href="#formatting"></a>Formatting</h2>
<div class="sectionbody">
<div class="paragraph">
<p><code>{</code> and <code>}</code> are placed on a new line except when empty or opening a multi-line lambda expression. Braces may be elided to a depth of one if the condition or loop guards a single expression.</p>
</div>
<div class="paragraph">
<p>Lambda expressions accepting a single parameter should elide the braces that encapsulate the parameter. E.g. <code>x &#8594; doSomething()</code> and <code>(x, y) &#8594; doSomething()</code></p>
</div>
<div class="sect3">
<h4 id="multiline-statements"><a class="anchor" href="#multiline-statements"></a>Multiline statements</h4>
<div class="paragraph">
<p>Where possible prefer keeping a logical action to a single line. Prefer introducing additional variables, or well-named methods encapsulating actions, to multi-line statements - unless this harms clarity (e.g. in an already short method).</p>
</div>
<div class="paragraph">
<p>Try to keep lines under 120 characters, but use good judgment. It is better to exceed this limit, than to split a line that has no natural splitting points, particularly when the remainder of the line is boilerplate or easily inferred by the reader.</p>
</div>
<div class="paragraph">
<p>If a line wraps inside a method call, first extract any long parameter expressions to local variables before trying to group natural parameters together on a single line, aligning the start of parameters on each line, e.g.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">Type newType = new Type(someValueWithLongName, someOtherRelatedValueWithLongName,
someUnrelatedValueWithLongName,
someDoublyUnrelatedValueWithLongName);</code></pre>
</div>
</div>
<div class="paragraph">
<p>When splitting a ternary, use one line per clause, carry the operator, and where possible align the start of the ternary condition, e.g.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">var = bar == null
? doFoo()
: doBar();</code></pre>
</div>
</div>
<div class="paragraph">
<p>It is usually preferable to carry the operator for multiline expressions, with the exception of some multiline string literals.</p>
</div>
</div>
<div class="sect3">
<h4 id="whitespace"><a class="anchor" href="#whitespace"></a>Whitespace</h4>
<div class="paragraph">
<p>Make sure to use 4 spaces instead of the tab character for all your indentation.
Many lines in the current files have a bunch of trailing whitespace. If you encounter incorrect whitespace, clean up in a separate patch. Current and future reviewers won’t want to review whitespace diffs.</p>
</div>
</div>
<div class="sect3">
<h4 id="static-imports"><a class="anchor" href="#static-imports"></a>Static Imports</h4>
<div class="paragraph">
<p>Consider using static imports for frequently used utility methods that are unambiguous. E.g. <code>String.format</code>, <code>ByteBufferUtil.bytes</code>, <code>Iterables.filter/any/transform</code>.</p>
</div>
<div class="paragraph">
<p>When naming static methods, select names that maintain semantic legibility when statically imported, and are unlikely to clash with other method names that may be mixed in the same context.</p>
</div>
</div>
<div class="sect3">
<h4 id="imports"><a class="anchor" href="#imports"></a>Imports</h4>
<div class="paragraph">
<p>Observe the following order for your imports:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">java
[blank line]
com.google.common
org.apache.commons
org.junit
org.slf4j
[blank line]
everything else alphabetically</code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="format-files-for-ides"><a class="anchor" href="#format-files-for-ides"></a>Format files for IDEs</h3>
<div class="ulist">
<ul>
<li>
<p>IntelliJ:
<a href="https://wiki.apache.org/cassandra/CodeStyle?action=AttachFile&amp;do=view&amp;target=intellij-codestyle.jar">intellij-codestyle.jar</a></p>
</li>
<li>
<p>IntelliJ 13:
<a href="https://gist.github.com/jdsumsion/9ab750a05c2a567c6afc">gist for IntelliJ
13</a> (this is a work in progress, still working on javadoc, ternary
style, line continuations, etc)</p>
</li>
<li>
<p>Eclipse: (<a href="https://github.com/tjake/cassandra-style-eclipse" class="bare">github.com/tjake/cassandra-style-eclipse</a>)</p>
</li>
</ul>
</div>
</div>
</div>
</div>
<h1 id="how-to-commit" class="sect0"><a class="anchor" href="#how-to-commit"></a>How-to Commit</h1>
<div class="paragraph">
<p>If you are a committer, feel free to pick any process that works for you
- so long as you are planning to commit the work yourself.</p>
</div>
<div class="sect1">
<h2 id="patch-based-contribution"><a class="anchor" href="#patch-based-contribution"></a>Patch based Contribution</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Here is how committing and merging will usually look for merging and
pushing for tickets that follow the convention (if patch-based):</p>
</div>
<div class="paragraph">
<p>Hypothetical CASSANDRA-12345 ticket is a cassandra-4.0 based bug fix
that requires different code for cassandra-4.0, cassandra-4.1, and
trunk. Contributor Jackie supplied a patch for the root branch
(12345-4.0.patch), and patches for the remaining branches
(12345-4.1.patch, 12345-5.0.patch, 12345-trunk.patch).</p>
</div>
<div class="dlist">
<dl>
<dt class="hdlist1">On cassandra-4.0</dt>
<dd>
<div class="olist arabic">
<ol class="arabic">
<li>
<p><code>git am -3 12345-4.0.patch</code> (any problem b/c of CHANGES.txt not
merging anymore, fix it in place)</p>
</li>
<li>
<p><code>ant realclean &amp;&amp; ant jar</code> (rebuild to make sure code
compiles)</p>
</li>
<li>
<p><code>git commit --amend</code> (Notice this will squash the 4.0 applied
patch into the forward merge commit)</p>
</li>
</ol>
</div>
</dd>
<dt class="hdlist1">On cassandra-4.1</dt>
<dd>
<div class="olist arabic">
<ol class="arabic">
<li>
<p><code>git merge cassandra-4.0 -s ours --log</code></p>
</li>
<li>
<p><code>git apply -3 12345-4.1.patch</code> (any issue with CHANGES.txt : fix
and <span class="title-ref">git add CHANGES.txt</span>)</p>
</li>
<li>
<p><code>ant realclean &amp;&amp; ant jar</code> (rebuild to make sure code
compiles)</p>
</li>
<li>
<p><code>git commit --amend</code> (Notice this will squash the 4.1 applied
patch into the forward merge commit)</p>
</li>
</ol>
</div>
</dd>
<dt class="hdlist1">On cassandra-5.0</dt>
<dd>
<div class="olist arabic">
<ol class="arabic">
<li>
<p><code>git merge cassandra-4.1 -s ours --log</code></p>
</li>
<li>
<p><code>git apply -3 12345-5.0.patch</code> (any issue with CHANGES.txt : fix
and <span class="title-ref">git add CHANGES.txt</span>)</p>
</li>
<li>
<p><code>ant realclean &amp;&amp; ant jar check</code> (rebuild to make sure code
compiles)</p>
</li>
<li>
<p><code>git commit --amend</code> (Notice this will squash the 4.1 applied
patch into the forward merge commit)</p>
</li>
</ol>
</div>
</dd>
<dt class="hdlist1">On trunk</dt>
<dd>
<div class="olist arabic">
<ol class="arabic">
<li>
<p><code>git merge cassandra-5.0 -s ours --log</code></p>
</li>
<li>
<p><code>git apply -3 12345-trunk.patch</code> (any issue with CHANGES.txt : fix
and <span class="title-ref">git add CHANGES.txt</span>)</p>
</li>
<li>
<p><code>ant realclean &amp;&amp; ant jar check</code> (rebuild to make sure code
compiles)</p>
</li>
<li>
<p><code>git commit --amend</code> (Notice this will squash the trunk applied
patch into the forward merge commit)</p>
</li>
</ol>
</div>
</dd>
<dt class="hdlist1">On any branch</dt>
<dd>
<div class="olist arabic">
<ol class="arabic">
<li>
<p><code>git push origin cassandra-4.0 cassandra-4.1 cassandra-5.0 trunk --atomic -n</code>
(dryrun check)</p>
</li>
<li>
<p><code>git push origin cassandra-4.0 cassandra-4.1 cassandra-5.0 trunk --atomic</code></p>
</li>
</ol>
</div>
</dd>
</dl>
</div>
</div>
</div>
<div class="sect1">
<h2 id="git-branch-based-contribution"><a class="anchor" href="#git-branch-based-contribution"></a>Git branch based Contribution</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Same scenario, but a branch-based contribution:</p>
</div>
<div class="dlist">
<dl>
<dt class="hdlist1">On cassandra-4.0</dt>
<dd>
<div class="olist arabic">
<ol class="arabic">
<li>
<p><code>git cherry-pick &lt;sha-of-4.0-commit&gt;</code> (any problem b/c of
CHANGES.txt not merging anymore, fix it in place)</p>
</li>
<li>
<p><code>ant realclean &amp;&amp; ant jar</code> (rebuild to make sure code
compiles)</p>
</li>
</ol>
</div>
</dd>
<dt class="hdlist1">On cassandra-4.1</dt>
<dd>
<div class="olist arabic">
<ol class="arabic">
<li>
<p><code>git merge cassandra-4.0 -s ours --log</code></p>
</li>
<li>
<p><code>git format-patch -1 &lt;sha-of-4.1-commit&gt;</code> (alternative to
format-patch and apply is <span class="title-ref">cherry-pick -n</span>)</p>
</li>
<li>
<p><code>git apply -3 &lt;sha-of-4.1-commit&gt;.patch</code> (any issue with
CHANGES.txt : fix and <span class="title-ref">git add CHANGES.txt</span>)</p>
</li>
<li>
<p><code>ant realclean &amp;&amp; ant jar</code> (rebuild to make sure code
compiles)</p>
</li>
<li>
<p><code>git commit --amend</code> (Notice this will squash the 4.1 applied
patch into the forward merge commit)</p>
</li>
</ol>
</div>
</dd>
<dt class="hdlist1">On cassandra-5.0</dt>
<dd>
<div class="olist arabic">
<ol class="arabic">
<li>
<p><code>git merge cassandra-4.1 -s ours --log</code></p>
</li>
<li>
<p><code>git format-patch -1 &lt;sha-of-5.0-commit&gt;</code> (alternative to
format-patch and apply is <span class="title-ref">cherry-pick -n</span>)</p>
</li>
<li>
<p><code>git apply -3 &lt;sha-of-5.0-commit&gt;.patch</code> (any issue with
CHANGES.txt : fix and <span class="title-ref">git add CHANGES.txt</span>)</p>
</li>
<li>
<p><code>ant realclean &amp;&amp; ant jar check</code> (rebuild to make sure code
compiles)</p>
</li>
<li>
<p><code>git commit --amend</code> (Notice this will squash the 5.0 applied
patch into the forward merge commit)</p>
</li>
</ol>
</div>
</dd>
<dt class="hdlist1">On trunk</dt>
<dd>
<div class="olist arabic">
<ol class="arabic">
<li>
<p><code>git merge cassandra-5.0 -s ours --log</code></p>
</li>
<li>
<p><code>git format-patch -1 &lt;sha-of-trunk-commit&gt;</code> (alternative to
format-patch and apply is <span class="title-ref">cherry-pick -n</span>)</p>
</li>
<li>
<p><code>git apply -3 &lt;sha-of-trunk-commit&gt;.patch</code> (any issue with
CHANGES.txt : fix and <span class="title-ref">git add CHANGES.txt</span>)</p>
</li>
<li>
<p><code>ant realclean &amp;&amp; ant jar check</code> (rebuild to make sure code
compiles)</p>
</li>
<li>
<p><code>git commit --amend</code> (Notice this will squash the trunk applied
patch into the forward merge commit)</p>
</li>
</ol>
</div>
</dd>
<dt class="hdlist1">On any branch</dt>
<dd>
<div class="olist arabic">
<ol class="arabic">
<li>
<p><code>git push origin cassandra-4.0 cassandra-4.1 cassandra-5.0 trunk --atomic -n</code>
(dryrun check)</p>
</li>
<li>
<p><code>git push origin cassandra-4.0 cassandra-4.1 cassandra-5.0 trunk --atomic</code></p>
</li>
</ol>
</div>
</dd>
</dl>
</div>
</div>
</div>
<div class="sect1">
<h2 id="contributions-only-for-release-branches"><a class="anchor" href="#contributions-only-for-release-branches"></a>Contributions only for release branches</h2>
<div class="sectionbody">
<div class="paragraph">
<p>If the patch is for an older branch, and doesn&#8217;t impact later branches
(such as trunk), we still need to merge up.</p>
</div>
<div class="dlist">
<dl>
<dt class="hdlist1">On cassandra-4.0</dt>
<dd>
<div class="olist arabic">
<ol class="arabic">
<li>
<p><code>git cherry-pick &lt;sha-of-4.0-commit&gt;</code> (any problem b/c of
CHANGES.txt not merging anymore, fix it in place)</p>
</li>
<li>
<p><code>ant realclean &amp;&amp; ant jar</code> (rebuild to make sure code
compiles)</p>
</li>
</ol>
</div>
</dd>
<dt class="hdlist1">On cassandra-4.1</dt>
<dd>
<div class="olist arabic">
<ol class="arabic">
<li>
<p><code>git merge cassandra-4.0 -s ours --log</code></p>
</li>
<li>
<p><code>ant realclean &amp;&amp; ant jar</code> (rebuild to make sure code
compiles)</p>
</li>
</ol>
</div>
</dd>
<dt class="hdlist1">On cassandra-5.0</dt>
<dd>
<div class="olist arabic">
<ol class="arabic">
<li>
<p><code>git merge cassandra-4.1 -s ours --log</code></p>
</li>
<li>
<p><code>ant realclean &amp;&amp; ant jar check</code> (rebuild to make sure code
compiles)</p>
</li>
</ol>
</div>
</dd>
<dt class="hdlist1">On trunk</dt>
<dd>
<div class="olist arabic">
<ol class="arabic">
<li>
<p><code>git merge cassandra-4.1 -s ours --log</code></p>
</li>
<li>
<p><code>ant realclean &amp;&amp; ant jar check</code> (rebuild to make sure code
compiles)</p>
</li>
</ol>
</div>
</dd>
<dt class="hdlist1">On any branch</dt>
<dd>
<div class="olist arabic">
<ol class="arabic">
<li>
<p><code>git push origin cassandra-4.0 cassandra-4.1 trunk --atomic -n</code>
(dryrun check)</p>
</li>
<li>
<p><code>git push origin cassandra-4.0 cassandra-4.1 trunk --atomic</code></p>
</li>
</ol>
</div>
</dd>
</dl>
</div>
</div>
</div>
<div class="sect1">
<h2 id="tips"><a class="anchor" href="#tips"></a>Tips</h2>
<div class="sectionbody">
<div class="admonitionblock tip">
<table>
<tr>
<td class="icon">
<i class="fa icon-tip" title="Tip"></i>
</td>
<td class="content">
<div class="title">Tip</div>
<div class="paragraph">
<p>A template for commit messages:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-none hljs" data-lang="none">&lt;One sentence description, usually Jira title or CHANGES.txt summary&gt;
&lt;Optional lengthier description&gt;
patch by &lt;Authors&gt;; reviewed by &lt;Reviewers&gt; for CASSANDRA-#####
Co-authored-by: Name1 &lt;email1&gt;
Co-authored-by: Name2 &lt;email2&gt;</code></pre>
</div>
</div>
</td>
</tr>
</table>
</div>
<div class="admonitionblock tip">
<table>
<tr>
<td class="icon">
<i class="fa icon-tip" title="Tip"></i>
</td>
<td class="content">
<div class="title">Tip</div>
<div class="paragraph">
<p>Notes on git flags: <code>-3</code> flag to am and apply will instruct git to
perform a 3-way merge for you. If a conflict is detected, you can either
resolve it manually or invoke git mergetool - for both am and apply.</p>
</div>
<div class="paragraph">
<p><code>--atomic</code> flag to git push does the obvious thing: pushes all or
nothing. Without the flag, the command is equivalent to running git push
once per each branch. This is nifty in case a race condition happens -
you won’t push half the branches, blocking other committers’ progress
while you are resolving the issue.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="admonitionblock tip">
<table>
<tr>
<td class="icon">
<i class="fa icon-tip" title="Tip"></i>
</td>
<td class="content">
<div class="title">Tip</div>
<div class="paragraph">
<p>The fastest way to get a patch from someone’s commit in a branch on GH -
if you don’t have their repo in remotes - is to append .patch to the
commit url, e.g. curl -O
<a href="https://github.com/apache/cassandra/commit/7374e9b5ab08c1f1e612bf72293ea14c959b0c3c.patch" class="bare">github.com/apache/cassandra/commit/7374e9b5ab08c1f1e612bf72293ea14c959b0c3c.patch</a></p>
</div>
</td>
</tr>
</table>
</div>
<div class="admonitionblock tip">
<table>
<tr>
<td class="icon">
<i class="fa icon-tip" title="Tip"></i>
</td>
<td class="content">
<div class="title">Tip</div>
<div class="paragraph">
<p><code>git cherry-pick -n &lt;sha-of-X.X-commit&gt;</code> can be used in place of the
<code>git format-patch -1 &lt;sha-of-X.X-commit&gt; ; git apply -3 &lt;sha-of-X.X-commit&gt;.patch</code>
steps.</p>
</div>
</td>
</tr>
</table>
</div>
</div>
</div>
<div class="sect1">
<h2 id="review-checklist"><a class="anchor" href="#review-checklist"></a>Review Checklist</h2>
<div class="sectionbody">
<div class="paragraph">
<p>When reviewing tickets in Apache JIRA, the following items should be
covered as part of the review process:</p>
</div>
<div class="sect2">
<h3 id="general"><a class="anchor" href="#general"></a>General</h3>
<div class="ulist">
<ul>
<li>
<p>Does it conform to the <code>code_style</code> guidelines?</p>
</li>
<li>
<p>Is there any redundant or duplicate code?</p>
</li>
<li>
<p>Is the code as modular as possible?</p>
</li>
<li>
<p>Can any singletons be avoided?</p>
</li>
<li>
<p>Can any of the code be replaced with library functions?</p>
</li>
<li>
<p>Are units of measurement used in the code consistent, both internally
and with the rest of the ecosystem?</p>
</li>
</ul>
</div>
</div>
<div class="sect2">
<h3 id="error-handling"><a class="anchor" href="#error-handling"></a>Error-Handling</h3>
<div class="ulist">
<ul>
<li>
<p>Are all data inputs and outputs checked (for the correct type, length,
format, and range) and encoded?</p>
</li>
<li>
<p>Where third-party utilities are used, are returning errors being
caught?</p>
</li>
<li>
<p>Are invalid parameter values handled?</p>
</li>
<li>
<p>Are any Throwable/Exceptions passed to the JVMStabilityInspector?</p>
</li>
<li>
<p>Are errors well-documented? Does the error message tell the user how
to proceed?</p>
</li>
<li>
<p>Do exceptions propagate to the appropriate level in the code?</p>
</li>
</ul>
</div>
</div>
<div class="sect2">
<h3 id="documentation"><a class="anchor" href="#documentation"></a>Documentation</h3>
<div class="ulist">
<ul>
<li>
<p>Do comments exist and describe the intent of the code (the "why", not
the "how")?</p>
</li>
<li>
<p>Are javadocs added where appropriate?</p>
</li>
<li>
<p>Is any unusual behavior or edge-case handling described?</p>
</li>
<li>
<p>Are data structures and units of measurement explained?</p>
</li>
<li>
<p>Is there any incomplete code? If so, should it be removed or flagged
with a suitable marker like ‘TODO’?</p>
</li>
<li>
<p>Does the code self-document via clear naming, abstractions, and flow
control?</p>
</li>
<li>
<p>Have NEWS.txt, the cql3 docs, and the native protocol spec been
updated if needed?</p>
</li>
<li>
<p>Is the ticket tagged with "client-impacting" and "doc-impacting",
where appropriate?</p>
</li>
<li>
<p>Has lib/licences been updated for third-party libs? Are they Apache
License compatible?</p>
</li>
<li>
<p>Is the Component on the JIRA ticket set appropriately?</p>
</li>
</ul>
</div>
</div>
<div class="sect2">
<h3 id="testing-2"><a class="anchor" href="#testing-2"></a>Testing</h3>
<div class="ulist">
<ul>
<li>
<p>Is the code testable? i.e. don’t add too many or hide dependencies,
unable to initialize objects, test frameworks can use methods etc.</p>
</li>
<li>
<p>Do tests exist and are they comprehensive?</p>
</li>
<li>
<p>Do unit tests actually test that the code is performing the intended
functionality?</p>
</li>
<li>
<p>Could any test code use common functionality (e.g. ccm, dtest, or
CqlTester methods) or abstract it there for reuse?</p>
</li>
<li>
<p>If the code may be affected by multi-node clusters, are there dtests?</p>
</li>
<li>
<p>If the code may take a long time to test properly, are there CVH
tests?</p>
</li>
<li>
<p>Is the test passing on CI for all affected branches (up to trunk, if
applicable)? Are there any regressions?</p>
</li>
<li>
<p>If patch affects read/write path, did we test for performance
regressions w/multiple workloads?</p>
</li>
<li>
<p>If adding a new feature, were tests added and performed confirming it
meets the expected SLA/use-case requirements for the feature?</p>
</li>
</ul>
</div>
</div>
<div class="sect2">
<h3 id="logging-2"><a class="anchor" href="#logging-2"></a>Logging</h3>
<div class="ulist">
<ul>
<li>
<p>Are logging statements logged at the correct level?</p>
</li>
<li>
<p>Are there logs in the critical path that could affect performance?</p>
</li>
<li>
<p>Is there any log that could be added to communicate status or
troubleshoot potential problems in this feature?</p>
</li>
<li>
<p>Can any unnecessary logging statement be removed?</p>
</li>
</ul>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="contributing-code-changes"><a class="anchor" href="#contributing-code-changes"></a>Contributing Code Changes</h2>
<div class="sectionbody">
<div class="sect2">
<h3 id="choosing-what-to-work-on"><a class="anchor" href="#choosing-what-to-work-on"></a>Choosing What to Work on</h3>
<div class="paragraph">
<p>Submitted patches can include bug fixes, changes to the Java code base,
improvements for tooling (both Java or Python), documentation, testing
or any other changes that requires changing the code base. Although the
process of contributing code is always the same, the amount of work and
time it takes to get a patch accepted also depends on the kind of issue
you&#8217;re addressing.</p>
</div>
<div class="dlist">
<dl>
<dt class="hdlist1">As a general rule of thumb</dt>
<dd>
<div class="ulist">
<ul>
<li>
<p>Major new features and significant changes to the code base will
likely not be accepted without deeper discussion within the
<a href="http://cassandra.apache.org/community/">developer community</a>.</p>
</li>
<li>
<p>Bug fixes take higher priority compared to features.</p>
</li>
<li>
<p>The extent to which tests are required depends on how likely your
changes will effect the stability of Cassandra in production. Tooling
changes requires fewer tests than storage engine changes.</p>
</li>
<li>
<p>Less complex patches will be reviewed faster; consider breaking up
an issue into individual tasks and contributions that can be reviewed
separately.</p>
</li>
</ul>
</div>
</dd>
</dl>
</div>
<div class="admonitionblock tip">
<table>
<tr>
<td class="icon">
<i class="fa icon-tip" title="Tip"></i>
</td>
<td class="content">
<div class="title">Hint</div>
<div class="paragraph">
<p>Not sure what to work? Just pick an issue marked as
<a href="https://issues.apache.org/jira/issues/?jql=project%20%3D%20CASSANDRA%20AND%20Complexity%20%3D%20%22Low%20Hanging%20Fruit%22%20and%20status%20!%3D%20resolved">Low
Hanging Fruit</a> Complexity in JIRA, which flags issues that often turn out to be good starter tasks for beginners.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>To create a JIRA account, please request it on <a href="../community.html#discussions" class="page">the #cassandra or #cassandra-dev channels on ASF Slack</a>, or on <a href="../community.html#discussions" class="page">the user or dev mailing list</a>.</p>
</div>
</div>
<div class="sect2">
<h3 id="before-you-start-coding"><a class="anchor" href="#before-you-start-coding"></a>Before You Start Coding</h3>
<div class="paragraph">
<p>Although contributions are highly appreciated, we do not guarantee that
every contribution will become a part of Cassandra. Therefore, it&#8217;s
generally a good idea to first get some feedback on the thing you plan
to do, especially about any new features or major changes to the
code base. You can reach out to other developers on the mailing list or
<code>Slack</code>.</p>
</div>
<div class="dlist">
<dl>
<dt class="hdlist1">You should also</dt>
<dd>
<div class="ulist">
<ul>
<li>
<p>Avoid redundant work by searching for already reported issues in
<a href="https://issues.apache.org/jira/browse/CASSANDRA">JIRA</a> to work on.</p>
</li>
<li>
<p>Create a new issue early in the process describing what you&#8217;re
working on - before finishing your patch.</p>
</li>
<li>
<p>Link related JIRA issues with your own ticket to provide a better
context.</p>
</li>
<li>
<p>Update your ticket from time to time by giving feedback on your
progress and link a GitHub WIP branch with your current code.</p>
</li>
<li>
<p>Ping people who you actively like to ask for advice on JIRA by
<a href="https://confluence.atlassian.com/doc/mentions-251725350.html">mentioning users</a>.</p>
</li>
</ul>
</div>
</dd>
<dt class="hdlist1">There are also some fixed rules that you need to be aware</dt>
<dd>
<div class="ulist">
<ul>
<li>
<p>Patches will only be applied to branches by following the release
model</p>
</li>
<li>
<p>Code must be testable</p>
</li>
<li>
<p>Code must follow the <a href="code_style.html" class="page">code style</a> convention</p>
</li>
<li>
<p>Changes must not break compatibility between different Cassandra
versions</p>
</li>
<li>
<p>Contributions must be covered by the Apache License</p>
</li>
</ul>
</div>
</dd>
</dl>
</div>
<div class="sect3">
<h4 id="choosing-the-right-branches-to-work-on"><a class="anchor" href="#choosing-the-right-branches-to-work-on"></a>Choosing the Right Branches to Work on</h4>
<div class="paragraph">
<p>There are currently multiple Cassandra versions maintained in individual
branches:</p>
</div>
<table class="tableblock frame-all grid-all stretch">
<colgroup>
<col style="width: 50%;">
<col style="width: 50%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Version</th>
<th class="tableblock halign-left valign-top">Policy</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">4.0</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Code freeze (see below)</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">3.11</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Critical bug fixes only</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">3.0</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Critical bug fixes only</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">2.2</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Critical bug fixes only</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">2.1</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Critical bug fixes only</p></td>
</tr>
</tbody>
</table>
<div class="paragraph">
<p>Corresponding branches in git are easy to recognize as they are named
<code>cassandra-&lt;release&gt;</code> (e.g. <code>cassandra-3.0</code>). The <code>trunk</code> branch is an
exception, as it contains the most recent commits from all other
branches and is used for creating new branches for future tick-tock
releases.</p>
</div>
</div>
<div class="sect3">
<h4 id="4-0-code-freeze"><a class="anchor" href="#4-0-code-freeze"></a>4.0 Code Freeze</h4>
<div class="paragraph">
<p>Patches for new features are currently not accepted for 4.0 or any
earlier versions.
All efforts should focus on stabilizing the 4.0 branch before the first
official release. During that time, only the following patches will be
considered for acceptance:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Bug fixes</p>
</li>
<li>
<p>Measurable performance improvements</p>
</li>
<li>
<p>Changes not distributed as part of the release such as:</p>
</li>
<li>
<p>Testing related improvements and fixes</p>
</li>
<li>
<p>Build and infrastructure related changes</p>
</li>
<li>
<p>Documentation</p>
</li>
</ul>
</div>
</div>
<div class="sect3">
<h4 id="bug-fixes"><a class="anchor" href="#bug-fixes"></a>Bug Fixes</h4>
<div class="paragraph">
<p>Creating patches for bug fixes is a bit more complicated and will
depend on how many different versions of Cassandra are affected. In each
case, the order for merging such changes will be <code>cassandra-2.1</code> &#8594;
<code>cassandra-2.2</code> &#8594; <code>cassandra-3.0</code> &#8594; <code>cassandra-3.x</code> &#8594; <code>trunk</code>.
But don&#8217;t worry, merging from 2.1 would be the worst case for bugs that
affect all currently supported versions, an uncommon event. As a
contributor, you&#8217;re also not expected to provide a single patch for each
version. What you need to do however is:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Be clear about which versions you could verify to be affected by the
bug</p>
</li>
<li>
<p>For 2.x: ask if a bug qualifies to be fixed in this release line, as
this may be handled on case by case bases</p>
</li>
<li>
<p>If possible, create a patch against the lowest version in the branches
listed above (e.g. if you found the bug in 3.9 you should try to fix it
already in 3.0)</p>
</li>
<li>
<p>Test if the patch can be merged cleanly across branches in the
direction listed above</p>
</li>
<li>
<p>Be clear which branches may need attention by the committer or even
create custom patches for those if you can</p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect2">
<h3 id="creating-a-patch"><a class="anchor" href="#creating-a-patch"></a>Creating a Patch</h3>
<div class="paragraph">
<p>So you&#8217;ve finished coding and the great moment arrives: it&#8217;s time to
submit your patch!</p>
</div>
<div class="olist arabic">
<ol class="arabic">
<li>
<p>Create a branch for your changes if you haven&#8217;t done already. Many
contributors name their branches based on ticket number and Cassandra
version, e.g. <code>git checkout -b 12345-3.0</code> or
<code>git checkout -b CASSANDRA-12345-3.0</code>.</p>
</li>
</ol>
</div>
<div class="admonitionblock tip">
<table>
<tr>
<td class="icon">
<i class="fa icon-tip" title="Tip"></i>
</td>
<td class="content">
<div class="title">Hint</div>
<div class="paragraph">
<p>When working on multiple patches at the same time, instead of cloning
the repository separately for each of them, set up multiple
working trees for different Cassandra versions from the same repository
using <a href="https://git-scm.com/docs/git-worktree">Git worktrees</a> feature.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="olist arabic">
<ol class="arabic">
<li>
<p>Verify that you follow Cassandra&#8217;s <a href="code_style.html" class="page">code style</a></p>
</li>
<li>
<p>Make sure all tests (including yours) pass using ant as described in
<a href="testing.html" class="page">testing</a>. If you suspect a test failure
is unrelated to your change, it may be useful to check the test&#8217;s
status by searching the issue tracker or looking at
<a href="https://builds.apache.org/">CI</a> results for the relevant upstream
version. Note that the full test suites take many hours to complete,
so it is common to only run specific relevant tests locally before
uploading a patch. Once a patch has been uploaded, the reviewer or
committer can help setup CI jobs to run the full test suites.</p>
</li>
<li>
<p>Consider going through the <a href="how_to_review.html" class="page">how
to review</a> page for your code. This will help you to understand how
others will consider your change for inclusion.</p>
</li>
<li>
<p>Don’t make the committer squash commits for you in the root branch
either. Multiple commits are fine - and often preferable - during review
stage, especially for incremental review, but once +1d, do either:</p>
</li>
</ol>
</div>
<div class="olist loweralpha">
<ol class="loweralpha" type="a">
<li>
<p>Attach a patch to JIRA with a single squashed commit in it (per
branch), or</p>
</li>
<li>
<p>Squash the commits in-place in your branches into one</p>
</li>
</ol>
</div>
<div class="olist arabic">
<ol class="arabic" start="6">
<li>
<p>Include a CHANGES.txt entry (put it at the top of the list), and
format the commit message appropriately in your patch as below. Please
note that only user-impacting items
<a href="https://lists.apache.org/thread.html/rde1128131a621e43b0a9c88778398c053a234da0f4c654b82dcbbe0e%40%3Cdev.cassandra.apache.org%3E">should</a>
be listed in CHANGES.txt. If you fix a test that does not affect users
and does not require changes in runtime code, then no CHANGES.txt entry
is necessary.</p>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-none hljs" data-lang="none">&lt;One sentence description, usually Jira title and CHANGES.txt summary&gt;
&lt;Optional lengthier description&gt;
patch by &lt;Authors&gt;; reviewed by &lt;Reviewers&gt; for CASSANDRA-#####</code></pre>
</div>
</div>
</li>
<li>
<p>When you&#8217;re happy with the result, create a patch. We suggest that
you use a similar format (note blank lines) for the commit log message:</p>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-none hljs" data-lang="none">&lt;one sentence description&gt;
&lt;optional lengthier description&gt;
Patch by &lt;authors&gt;; reviewed by &lt;Reviewers&gt; for CASSANDRA-#####</code></pre>
</div>
</div>
</li>
</ol>
</div>
<div class="paragraph">
<p>If you don&#8217;t know who is reviewing your change yet, you can use <code>TBD</code>
and amend the commit later to note the people who helped you.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-none hljs" data-lang="none">git add &lt;any new or modified file&gt;
git commit
git format-patch HEAD~1
mv &lt;patch-file&gt; &lt;ticket-branchname.txt&gt; (e.g. 12345-trunk.txt, 12345-3.0.txt)</code></pre>
</div>
</div>
<div class="paragraph">
<p>Alternatively, many contributors prefer to make their branch available
on GitHub. In this case, fork the Cassandra repository on GitHub and
push your branch:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-none hljs" data-lang="none">git push --set-upstream origin 12345-3.0</code></pre>
</div>
</div>
<div class="olist arabic">
<ol class="arabic" start="8">
<li>
<p>To make life easier for your reviewer/committer, you may want to make
sure your patch applies cleanly to later branches and create additional
patches/branches for later Cassandra versions to which your original
patch does not apply cleanly. That said, this is not critical, and you
will receive feedback on your patch regardless.</p>
</li>
<li>
<p>Attach the newly generated patch to the ticket/add a link to your
branch and click "Submit Patch" at the top of the ticket. This will move
the ticket into "Patch Available" status, indicating that your
submission is ready for review.</p>
</li>
<li>
<p>Wait for other developers or committers to review it and hopefully
+1 the ticket (see <a href="how_to_review.html" class="page">how to
review</a>). If your change does not receive a +1, do not be discouraged.
If possible, the reviewer will give suggestions to improve your patch
or explain why it is not suitable.</p>
</li>
<li>
<p>If the reviewer has given feedback to improve the patch, make the
necessary changes and move the ticket into "Patch Available" once again.</p>
</li>
<li>
<p>Once you&#8217;ve had the patch reviewed you can amend the commit to update
the commit message <code>TBD</code> with the reviewers who helped you.</p>
</li>
</ol>
</div>
<div class="paragraph">
<p>Once the review process is complete, you will receive a +1. Wait for a
committer to commit it. Do not delete your branches immediately after
they’ve been committed - keep them on GitHub for a while. Alternatively,
attach a patch to JIRA for historical record. It’s not that uncommon for
a committer to mess up a merge. In case of that happening, access to the
original code is required, or else you’ll have to redo some of the work.</p>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="ci-environments"><a class="anchor" href="#ci-environments"></a>CI Environments</h2>
<div class="sectionbody">
<div class="sect2">
<h3 id="about-ci-testing-and-apache-cassandra"><a class="anchor" href="#about-ci-testing-and-apache-cassandra"></a>About CI testing and Apache Cassandra</h3>
<div class="paragraph">
<p>Cassandra can be automatically tested using various test suites, that
are either implemented based on JUnit or the
<a href="https://github.com/apache/cassandra-dtest">dtest</a> scripts written in
Python. As outlined in <code>testing</code>, each kind of test suite addresses a
different way to test Cassandra. Eventually, all of the tests will be
executed together on the CI platform at
<a href="https://builds.apache.org">builds.apache.org</a>, running
<a href="http://jenkins-ci.org">Jenkins</a>.</p>
</div>
</div>
<div class="sect2">
<h3 id="setting-up-your-own-jenkins-server"><a class="anchor" href="#setting-up-your-own-jenkins-server"></a>Setting up your own Jenkins server</h3>
<div class="paragraph">
<p>Jenkins is an open source solution that can be installed on a large
number of platforms. Setting up a custom Jenkins instance for Cassandra
may be desirable for users who have hardware to spare, or organizations
that want to run Cassandra tests for custom patches before contribution.</p>
</div>
<div class="paragraph">
<p>Please refer to the Jenkins download and documentation pages for details
on how to get Jenkins running, possibly also including slave build
executor instances. The rest of the document will focus on how to setup
Cassandra jobs in your Jenkins environment.</p>
</div>
<div class="sect3">
<h4 id="required-plugins"><a class="anchor" href="#required-plugins"></a>Required plugins</h4>
<div class="paragraph">
<p>In addition, the following plugins need to be installed along with the standard
plugins (git, ant, ..).</p>
</div>
<div class="paragraph">
<p>You can install any missing plugins using the install manager.</p>
</div>
<div class="paragraph">
<p>Go to <code>Manage Jenkins &#8594; Manage Plugins &#8594; Available</code> and install the
following plugins and respective dependencies:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Job DSL</p>
</li>
<li>
<p>Javadoc Plugin</p>
</li>
<li>
<p>description setter plugin</p>
</li>
<li>
<p>Throttle Concurrent Builds Plug-in</p>
</li>
<li>
<p>Test stability history</p>
</li>
<li>
<p>Post Build Script</p>
</li>
</ul>
</div>
</div>
<div class="sect3">
<h4 id="setup-seed-job"><a class="anchor" href="#setup-seed-job"></a>Setup seed job</h4>
<div class="olist arabic">
<ol class="arabic">
<li>
<p>Config <code>New Item</code></p>
<div class="ulist">
<ul>
<li>
<p>Name it <code>Cassandra-Job-DSL</code></p>
</li>
<li>
<p>Select <code>Freestyle project</code></p>
</li>
</ul>
</div>
</li>
<li>
<p>Under <code>Source Code Management</code> select Git using the repository:
<code><a href="https://github.com/apache/cassandra-builds" class="bare">github.com/apache/cassandra-builds</a></code></p>
</li>
<li>
<p>Under <code>Build</code>, confirm <code>Add build step</code> &#8594; <code>Process Job DSLs</code> and enter
at <code>Look on Filesystem</code>: <code>jenkins-dsl/cassandra_job_dsl_seed.groovy</code></p>
</li>
</ol>
</div>
<div class="paragraph">
<p>Generated jobs will be created based on the Groovy script&#8217;s default
settings. You may want to override settings by checking
<code>This project is parameterized</code> and add <code>String Parameter</code> for on the
variables that can be found in the top of the script. This will allow
you to setup jobs for your own repository and branches (e.g. working
branches).</p>
</div>
<div class="olist arabic">
<ol class="arabic" start="4">
<li>
<p>When done, confirm "Save".</p>
</li>
</ol>
</div>
<div class="paragraph">
<p>You should now find a new entry with the given name in your project
list. However, building the project will still fail and abort with an
error message "Processing DSL script
cassandra_job_dsl_seed.groovy ERROR: script not yet approved for use".
Go to <code>Manage Jenkins</code> &#8594; <code>In-process Script Approval</code> to fix this issue.
Afterwards you should be able to run the script and have it generate
numerous new jobs based on the found branches and configured templates.</p>
</div>
<div class="paragraph">
<p>Jobs are triggered by either changes in Git or are scheduled to execute
periodically, e.g. on daily basis.
Jenkins will use any available executor with the label "cassandra", once the job
is to be run.
Please make sure to make any executors available by selecting
<code>Build Executor Status</code> &#8594; <code>Configure</code> &#8594; Add &#8220;cassandra&#8221; as label and
save.</p>
</div>
<div class="paragraph">
<p>Executors need to have "JDK 1.8 (latest)" installed. This is done under
<code>Manage Jenkins &#8594; Global Tool Configuration &#8594; JDK Installations…</code>.
Executors also need to have the <code>virtualenv</code> package installed on their
system.</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="circleci"><a class="anchor" href="#circleci"></a>CircleCI</h3>
<div class="paragraph">
<p>Cassandra ships with a default <a href="https://circleci.com">CircleCI</a>
configuration to enable running tests on your branches.
Go to the CircleCI website, click "Login" and log in with your github account.
Then give CircleCI permission to watch your repositories.</p>
</div>
<div class="paragraph">
<p>Once you have done that, you can optionally configure CircleCI to run
tests in parallel if you wish:</p>
</div>
<div class="olist arabic">
<ol class="arabic" start="1">
<li>
<p>Click <code>Projects</code> and select your github account, and then click the settings for your project.</p>
</li>
<li>
<p>Set the parallelism setting. If you leave the default value of 1
for Cassandra, only <code>ant eclipse-warnings</code> and <code>ant test</code> will be run.
If you change the value to 4, Circle CI also runs <code>ant long-test</code>,
<code>ant test-compression</code> and <code>ant stress-test</code>.</p>
</li>
</ol>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="dependency-management"><a class="anchor" href="#dependency-management"></a>Dependency Management</h2>
<div class="sectionbody">
<div class="paragraph">
<p>New dependencies should not be included without community consensus first being
obtained via a <code>[DISCUSS]</code> thread on the <a href="mailto:dev@cassandra.apache.org">dev@cassandra.apache.org</a> mailing list.</p>
</div>
<div class="paragraph">
<p>As Cassandra is an ASF project, all included libraries must follow Apache&#8217;s
<a href="https://www.apache.org/legal/resolved.html">software license requirements</a>.</p>
</div>
<div class="paragraph">
<p>Cassandra uses the Ant build system and Maven POMs for dependency
specification. In Cassandra 5.0 the format of POMs was moved from within the
<code>build.xml</code> file to separate POM template files that are processed by Ant. In
both pre-5.0 and post-5.0 Cassandra, there are several POMs that dependencies
can be included in:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><strong>parent-pom</strong></p>
<div class="ulist">
<ul>
<li>
<p>Contains all dependencies with the respective version. All other poms
will refer to the artifacts with specified versions listed here.</p>
</li>
<li>
<p>Since Cassandra 5.0, the <code>parent-pom</code> template is <code>.build/parent-pom-template.xml</code>.</p>
</li>
</ul>
</div>
</li>
<li>
<p><strong>build-deps-pom(-sources)</strong> + <strong>coverage-deps-pom</strong></p>
<div class="ulist">
<ul>
<li>
<p>used by the <code>ant build</code> target. Listed dependencies will be resolved and
copied to <code>build/lib/{jar,sources}</code> by executing the
<code>maven-ant-tasks-retrieve-build</code> target. This should contain libraries that are
required for build tools (grammar, docs, instrumentation), but are not
shipped as part of the Cassandra distribution.</p>
</li>
<li>
<p>Since Cassandra 4.0, <code>coverage-deps-pom</code> has been removed and the
<code>build-deps-pom</code> template is <code>.build/cassandra-build-deps-template.xml</code>.</p>
</li>
</ul>
</div>
</li>
<li>
<p><strong>all-pom</strong></p>
<div class="ulist">
<ul>
<li>
<p>POM for
<a href="https://mvnrepository.com/artifact/org.apache.cassandra/cassandra-all">cassandra-all.jar</a>.
See <a href="/_/development/release_process.html">release process docs</a>.</p>
</li>
<li>
<p>Since Cassandra 5.0, the <code>all-pom</code> template is <code>.build/cassandra-deps-template.xml</code>.</p>
</li>
</ul>
</div>
</li>
<li>
<p><strong>test-deps-pom</strong></p>
<div class="ulist">
<ul>
<li>
<p>Referenced by <code>maven-ant-tasks-retrieve-test</code> to retrieve and save
dependencies to <code>build/test/lib</code>. Exclusively used during JUnit test
execution.</p>
</li>
<li>
<p>Since Cassandra 3.0, <code>test-deps-pom</code> has been removed.</p>
</li>
</ul>
</div>
</li>
</ul>
</div>
<div class="paragraph">
<p>The <code>ant write-poms</code> target produces valid POM files in the <code>build/</code> directory.</p>
</div>
<div class="paragraph">
<p>Dependencies added to the <code>lib/</code> directory are built into the release artifacts
by the <code>ant artifacts</code> target (see target <code>resolver-dist-lib</code>). Libraries
distributed this way must meet the
<a href="https://www.apache.org/legal/resolved.html">ASF distribution policy</a>.</p>
</div>
<div class="sect2">
<h3 id="dependency-management-before-cassandra-5-0"><a class="anchor" href="#dependency-management-before-cassandra-5-0"></a>Dependency management before Cassandra 5.0</h3>
<div class="paragraph">
<p>To update dependencies, update the parent and child POM definitions in
<code>build.xml</code>. The parent POM should include the <code>dependency</code> tag with <code>groupId</code>,
<code>artifactId</code>, <code>version</code>, and optional <code>scope</code> fields. The child POM(s) should
include the <code>dependency</code> tag with <code>groupId</code> and <code>artifactId</code>. See the
<a href="https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html#Dependency_Management">Maven docs</a>
for a complete reference on how to reference dependencies across parent and
child POMs.</p>
</div>
<div class="paragraph">
<p>Here is
<a href="https://github.com/apache/cassandra/commit/4b3f07fc74089151efeff7a8fdfa9c414a1f0d6a#diff-766797f233c18114f9499750cf1ffbf3829aeea50283850619c01bd173132021">an example</a>
of a commit that changes dependency versions pre-5.0.</p>
</div>
</div>
<div class="sect2">
<h3 id="dependency-management-in-cassandra-5-0-and-later"><a class="anchor" href="#dependency-management-in-cassandra-5-0-and-later"></a>Dependency management in Cassandra 5.0 and later</h3>
<div class="paragraph">
<p>In Cassandra 5.0 and later, dependencies are managed in Maven POM templates in
<code>.build/*-template.xml</code>. These templates are processed into valid Maven POMs
and copied to <code>build/\*.pom</code> by the <code>ant write-poms</code> task.</p>
</div>
<div class="paragraph">
<p>For new dependencies, add to <code>parent-pom-template</code> and
<code>cassandra-deps-template</code>, and optionally <code>cassandra-build-deps-template</code> if
the dependency is required for build only. See
<a href="https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html#Dependency_Management">the Maven docs</a>
on how to reference dependencies in the parent POM from the child POMs.</p>
</div>
<div class="paragraph">
<p>For dependency versions that need to be available in <code>build.xml</code> and
<code>parent-pom-template</code>, specify the version as a property in <code>build.xml</code>, add it
to the <code>ant write-poms</code> target, then add the property to <code>parent-pom-template</code>
with the value of the template substitution.</p>
</div>
<div class="paragraph">
<p>Here is
<a href="https://github.com/apache/cassandra/commit/b61bd93e574503aff8c29f0efefbe9879d3b32eb">an example</a>
of a commit that changes dependency versions since 5.0.</p>
</div>
</div>
<div class="sect2">
<h3 id="troubleshooting-and-conflict-resolution"><a class="anchor" href="#troubleshooting-and-conflict-resolution"></a>Troubleshooting and conflict resolution</h3>
<div class="paragraph">
<p>Here are some useful commands that may help you out resolving conflicts.</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>ant realclean</code> - gets rid of the build directory, including build
artifacts.</p>
</li>
<li>
<p><code>mvn dependency:tree -f build/apache-cassandra-\*-SNAPSHOT.pom -Dverbose -Dincludes=org.slf4j</code></p>
<div class="ulist">
<ul>
<li>
<p>shows transitive dependency tree for artifacts, e.g. org.slf4j. In
case the command above fails due to a missing parent pom file, try
running <code>ant mvn-install</code>.</p>
</li>
</ul>
</div>
</li>
<li>
<p><code>rm ~/.m2/repository/org/apache/cassandra/apache-cassandra/</code> - removes
cached local Cassandra maven artifacts</p>
</li>
</ul>
</div>
</div>
</div>
</div>
<h1 id="working-on-documentation" class="sect0"><a class="anchor" href="#working-on-documentation"></a>Working on Documentation</h1>
<div class="sect1">
<h2 id="working-on-documentation-2"><a class="anchor" href="#working-on-documentation-2"></a>Working on Documentation</h2>
<div class="sectionbody">
<div class="sect2">
<h3 id="how-cassandra-is-documented"><a class="anchor" href="#how-cassandra-is-documented"></a>How Cassandra is documented</h3>
<div class="paragraph">
<p>The official Cassandra documentation lives in the project&#8217;s git
repository.
We use a static site generator, <a href="http://www.antora.org/">Antora</a>, to create pages hosted at
<a href="/doc/latest/">cassandra.apache.org</a>.</p>
</div>
<div class="paragraph">
<p>&lt;!-- You&#8217;ll also find developer-centric content about Cassandra internals in our
retired <a href="https://wiki.apache.org/cassandra">wiki</a> (not covered by this
guide). -&#8594;</p>
</div>
<div class="paragraph">
<p>Using a static site generator often requires the use of a markup language
instead of visual editors (which some people would call good news).
Antora processes <a href="http://www.asciidoc.org">AsciiDoc</a>, the markup language used to generate our documentation.
Markup languages allow you to format text using certain syntax elements.
Your document structure will also have to follow specific conventions.
Feel free to take a look at <a href="/doc/">existing documents</a> to get a better idea how we structure our documents.</p>
</div>
<div class="paragraph">
<p>So how do you actually start making contributions?</p>
</div>
</div>
<div class="sect2">
<h3 id="github-based-work-flow"><a class="anchor" href="#github-based-work-flow"></a>GitHub based work flow</h3>
<div class="paragraph">
<p><em>Recommended for shorter documents and minor changes on existing content
(e.g. fixing typos or updating descriptions)</em></p>
</div>
<div class="paragraph">
<p>Follow these steps to contribute using GitHub. It&#8217;s assumed that you&#8217;re
logged in with an existing account.</p>
</div>
<div class="olist arabic">
<ol class="arabic">
<li>
<p>Fork the GitHub mirror of the
<a href="https://github.com/apache/cassandra">Cassandra repository</a></p>
</li>
</ol>
</div>
<div class="imageblock">
<div class="content">
<img src="../_images/docs_fork.png" alt="image">
</div>
</div>
<div class="olist arabic">
<ol class="arabic" start="2">
<li>
<p>Create a new branch that you can use to make your edits. It&#8217;s
recommended to have a separate branch for each of your working projects.
It will also make it easier to create a pull request later to when you
decide you’re ready to contribute your work.</p>
</li>
</ol>
</div>
<div class="imageblock">
<div class="content">
<img src="../_images/docs_create_branch.png" alt="image">
</div>
</div>
<div class="olist arabic">
<ol class="arabic" start="3">
<li>
<p>Navigate to document sources <code>doc/source/modules</code> to find the <code>.adoc</code> file to
edit. The URL of the document should correspond to the directory
structure within the modules, where first the <code>component</code> name, such as <code>cassandra</code> is listed, and then the actual pages inside the <code>pages</code> directory. New files can be created using the "Create new file" button:</p>
</li>
</ol>
</div>
<div class="imageblock">
<div class="content">
<img src="../_images/docs_create_file.png" alt="image">
</div>
</div>
<div class="olist arabic">
<ol class="arabic" start="4">
<li>
<p>At this point you should be able to edit the file using the GitHub web
editor. Start by naming your file and add some content. Have a look at
other existing <code>.adoc</code> files to get a better idea what format elements to
use.</p>
</li>
</ol>
</div>
<div class="imageblock">
<div class="content">
<img src="../_images/docs_editor.png" alt="image">
</div>
</div>
<div class="paragraph">
<p>Make sure to preview added content before committing any changes.</p>
</div>
<div class="imageblock">
<div class="content">
<img src="../_images/docs_preview.png" alt="image">
</div>
</div>
<div class="olist arabic">
<ol class="arabic" start="5">
<li>
<p>Commit your work when you&#8217;re done. Make sure to add a short
description of all your edits since the last time you committed before.</p>
</li>
</ol>
</div>
<div class="imageblock">
<div class="content">
<img src="../_images/docs_commit.png" alt="image">
</div>
</div>
<div class="olist arabic">
<ol class="arabic" start="6">
<li>
<p>Finally if you decide that you&#8217;re done working on your branch, it&#8217;s
time to create a pull request!</p>
</li>
</ol>
</div>
<div class="imageblock">
<div class="content">
<img src="../_images/docs_pr.png" alt="image">
</div>
</div>
<div class="paragraph">
<p>Afterwards the GitHub Cassandra mirror will list your pull request and
you&#8217;re done. Congratulations! Please give us some time to look at your
suggested changes before we get back to you.</p>
</div>
</div>
<div class="sect2">
<h3 id="jira-based-work-flow"><a class="anchor" href="#jira-based-work-flow"></a>Jira based work flow</h3>
<div class="paragraph">
<p><em>Recommended for major changes</em></p>
</div>
<div class="paragraph">
<p>Significant changes to the documentation are best managed through our
Jira issue tracker. Please follow the same
<a href="patches.html" class="page">contribution
guides</a> as for regular code contributions. Creating high quality content
takes a lot of effort. It’s therefore always a good idea to create a
ticket before you start and explain what you’re planning to do. This will
create the opportunity for other contributors and committers to comment
on your ideas and work so far. Eventually your patch gets a formal
review before it is committed.</p>
</div>
</div>
<div class="sect2">
<h3 id="working-on-documents-locally-using-antora"><a class="anchor" href="#working-on-documents-locally-using-antora"></a>Working on documents locally using Antora</h3>
<div class="paragraph">
<p><em>Recommended for advanced editing</em></p>
</div>
<div class="paragraph">
<p>Using the GitHub web interface should allow you to use most common
layout elements including images. More advanced formatting options and
navigation elements depend on Antora to render correctly. Therefore, it’s
a good idea to setup Antora locally for any serious editing. Please
follow the instructions in the Cassandra source directory at
<code>doc/README.md</code>. Setup is very easy (at least on OSX and Linux).</p>
</div>
</div>
<div class="sect2">
<h3 id="notes-for-committers"><a class="anchor" href="#notes-for-committers"></a>Notes for committers</h3>
<div class="paragraph">
<p>Please feel free to get involved and merge pull requests created on the
GitHub mirror if you&#8217;re a committer. As this is a read-only repository,
you won&#8217;t be able to merge a PR directly on GitHub. You&#8217;ll have to
commit the changes against the Apache repository with a comment that
will close the PR when the committ syncs with GitHub.</p>
</div>
<div class="paragraph">
<p>You may use a git work flow like this:</p>
</div>
<div class="literalblock">
<div class="content">
<pre>git remote add github https://github.com/apache/cassandra.git
git fetch github pull/&lt;PR-ID&gt;/head:&lt;PR-ID&gt;
git checkout &lt;PR-ID&gt;</pre>
</div>
</div>
<div class="paragraph">
<p>Now either rebase or squash the commit, e.g. for squashing:</p>
</div>
<div class="literalblock">
<div class="content">
<pre>git reset --soft origin/trunk
git commit --author &lt;PR Author&gt;</pre>
</div>
</div>
<div class="paragraph">
<p>Make sure to add a proper commit message including a "Closes #&lt;PR-ID&gt;"
text to automatically close the PR.</p>
</div>
<div class="sect3">
<h4 id="publishing"><a class="anchor" href="#publishing"></a>Publishing</h4>
<div class="paragraph">
<p>Details for building and publishing of the site at cassandra.apache.org
can be found
<a href="https://github.com/apache/cassandra-website/blob/master/README.md">here</a>.</p>
</div>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="release-process"><a class="anchor" href="#release-process"></a>Release Process</h2>
<div class="sectionbody">
<div class="paragraph">
<p>The steps for Release Managers to create, vote, and publish releases for
Apache Cassandra.</p>
</div>
<div class="paragraph">
<p>While a committer can perform the initial steps of creating and calling
a vote on a proposed release, only a PMC member can complete the process
of publishing and announcing the release.</p>
</div>
<div class="sect2">
<h3 id="prerequisites-2"><a class="anchor" href="#prerequisites-2"></a>Prerequisites</h3>
<div class="dlist">
<dl>
<dt class="hdlist1">Background docs</dt>
<dd>
<div class="ulist">
<ul>
<li>
<p><a href="http://www.apache.org/legal/release-policy.html">ASF Release Policy</a></p>
</li>
<li>
<p><a href="http://www.apache.org/dev/release-distribution">ASF Release
Distribution Policy</a></p>
</li>
<li>
<p><a href="https://infra.apache.org/release-publishing.html">ASF Release
Best Practices</a></p>
</li>
</ul>
</div>
</dd>
</dl>
</div>
<div class="paragraph">
<p>A debian based linux OS is required to run the release steps from.
Debian-based distros provide the required RPM, dpkg and repository
management tools.</p>
</div>
<div class="sect3">
<h4 id="create-and-publish-your-gpg-key"><a class="anchor" href="#create-and-publish-your-gpg-key"></a>Create and publish your GPG key</h4>
<div class="paragraph">
<p>To create a GPG key, follow the
<a href="http://www.apache.org/dev/openpgp.html">guidelines</a>. <strong>The key must be 4096
bit RSA.</strong></p>
</div>
<div class="paragraph">
<p>Publish your GPG key in a PGP key server, such as
<a href="http://pgp.mit.edu/">MIT Keyserver</a>. Some <code>gpg</code> clients are publishing the keys <a href="https://keys.openpgp.org/">here</a>. You are
welcome to set the server where the keys will be published by following <a href="https://keys.openpgp.org/about/usage">this guide</a>.</p>
</div>
<div class="paragraph">
<p>Once completed, you need to create a ticket <a href="https://issues.apache.org/jira/browse/CASSANDRA-18205">like this</a>
and ask a PMC to add your key to <code>KEYS</code> file.</p>
</div>
<div class="paragraph">
<p>A PMC will include your public key to this file:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-none hljs" data-lang="none">https://dist.apache.org/repos/dist/release/cassandra/KEYS</code></pre>
</div>
</div>
</div>
</div>
<div class="sect2">
<h3 id="create-release-artifacts"><a class="anchor" href="#create-release-artifacts"></a>Create Release Artifacts</h3>
<div class="paragraph">
<p>Any committer can perform the following steps to create and call a vote
on a proposed release.</p>
</div>
<div class="paragraph">
<p>Check that there are no open urgent Jira tickets currently being worked
on. Also check with the PMC that there&#8217;s security vulnerabilities
currently being worked on in private. Current project habit is to check
the timing for a new release on the dev mailing lists.</p>
</div>
<div class="paragraph">
<p>For successful building process, install this tooling locally:
svn, git, ant, devscripts, reprepro, rpmsign, docker, createrepo (the script is checking this tooling is present
before proceeding any further). The names of these "packages" are Debian-centric,
but equivalents should be discoverable in other systems too.</p>
</div>
<div class="paragraph">
<p>There is a package called <a href="https://packages.debian.org/bullseye/createrepo-c">createrepo-c</a> in Debian Bullseye.
Please beware that <code>createrepo</code> package is not located in Ubuntu 20.04 LTS. <code>createrepo</code> package is present in
Ubuntu Bionic (18.04), <code>createrepo-c</code> is in Ubuntu Jammy (22.04 LTS) and more recent.</p>
</div>
<div class="sect3">
<h4 id="perform-the-release"><a class="anchor" href="#perform-the-release"></a>Perform the Release</h4>
<div class="paragraph">
<p>Run the following commands to generate and upload release artifacts, to
the ASF nexus staging repository and dev distribution location:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-none hljs" data-lang="none">cd ~/git
git clone https://github.com/apache/cassandra-builds.git
git clone https://github.com/apache/cassandra.git</code></pre>
</div>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-none hljs" data-lang="none"># Edit the variables at the top of the `prepare_release.sh` file
edit cassandra-builds/cassandra-release/prepare_release.sh</code></pre>
</div>
</div>
<div class="paragraph">
<p>You must specify your ASF username to <code>asf_username</code> variable. Next, <code>gpg_key</code> environment variable must be
set to a fingerprint of your gpg key. Execute <code>gpg --list-keys</code> or a similar command to get the value. Finally, you must
add ASF remote to your cloned repository and <code>git_asf_remote</code> variable needs to be set to point to that. For example, when this command is executed:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-none hljs" data-lang="none">git remote add asf https://gitbox.apache.org/repos/asf/cassandra.git</code></pre>
</div>
</div>
<div class="paragraph">
<p>then <code>git_asf_remote</code> variable needs to be set to <code>asf</code>.
NOTE: This is very important step as tags are pushed to ASF repository and they are synchronized to GitHub automatically.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-none hljs" data-lang="none"># Ensure your 4096 RSA key is the default secret key
edit ~/.gnupg/gpg.conf # update the `default-key` line</code></pre>
</div>
</div>
<div class="paragraph">
<p>A reference configuration should look like these examples:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-none hljs" data-lang="none">default-key &lt;fingerprint of your key&gt;
personal-digest-preferences SHA512
cert-digest-algo SHA512
default-preference-list SHA512 SHA384 SHA256 SHA224 AES256 AES192 AES CAST5 ZLIB BZIP2 ZIP Uncompressed</code></pre>
</div>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-none hljs" data-lang="none">edit ~/.rpmmacros # update the `%_gpg_name &lt;key_id&gt;` line
# Ensure DEBFULLNAME and DEBEMAIL is defined and exported, in the debian scripts configuration
edit ~/.devscripts</code></pre>
</div>
</div>
<div class="paragraph">
<p>The reference content of these files is:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-none hljs" data-lang="none">$ cat ~/.rpmmacros
%_gpg_name email@youusedforyourkey.org
$ cat ~/.devscripts
DEBFULLNAME="Your Name"
DEBEMAIL=email@youusedforyourkey.org</code></pre>
</div>
</div>
<div class="paragraph">
<p>Empirical testing shows that you also must have the above <code>DEB*</code> environemnt variables exported before proceeding.</p>
</div>
<div class="paragraph">
<p>Additionally, you must configure <code>$HOME/.m2/settings.xml</code> to contain the credentials used to upload artifacts to <a href="https://repository.apache.org/">staging repository</a>. The credentials are your ASF credentials.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-none hljs" data-lang="none">$ cat ~/.m2/settings.xml
&lt;settings&gt;
&lt;servers&gt;
&lt;server&gt;
&lt;id&gt;apache.releases.https&lt;/id&gt;
&lt;username&gt;yourasflogin&lt;/username&gt;
&lt;password&gt;yourasfpassword&lt;/password&gt;
&lt;/server&gt;
&lt;server&gt;
&lt;id&gt;apache.snapshots.https&lt;/id&gt;
&lt;username&gt;yourasflogin&lt;/username&gt;
&lt;password&gt;yourasfpassword&lt;/password&gt;
&lt;/server&gt;
&lt;/servers&gt;
&lt;/settings&gt;</code></pre>
</div>
</div>
<div class="paragraph">
<p>The script will eventually ask you for a username and password to push artifacts to SVN. The default prompt for user
will be equal to a username of an account at your machine. If your ASF login is not same as your username locally, just error out the prompt
(put there wrong password and confirm), and it will ask you for username again without providing any default value.</p>
</div>
<div class="paragraph">
<p>The <code>prepare_release.sh</code> is run from the actual cassandra git checkout,
on the branch/commit that we wish to tag for the tentative release along with version number to tag.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-none hljs" data-lang="none">cd cassandra
git switch cassandra-&lt;version-branch&gt;
# The following cuts the release artifacts (including deb and rpm packages) and deploy to staging environments
../cassandra-builds/cassandra-release/prepare_release.sh -v &lt;version&gt;</code></pre>
</div>
</div>
<div class="paragraph">
<p>Follow the prompts.</p>
</div>
<div class="paragraph">
<p>Once artifacts are built and pushed to the staging area, the script will pause and require you to go to the
<a href="https://repository.apache.org/#stagingRepositories">Staging repositories</a>, where you will find the repository.
Select the Cassandra repository and push the "Close" button.
Please take a note of the number of that repository like <code>orgapachecassandra-1283</code> - number is 1283.
The script will require the repo number to proceed. It will use this number in the rendered e-mail template sent to the dev list, etc.</p>
</div>
<div class="paragraph">
<p>If building the deb or rpm packages fail, those steps can be repeated
individually using the <span class="title-ref">-d</span> and <span class="title-ref">-r</span> flags,
respectively.</p>
</div>
<div class="paragraph">
<p>Once DEBs and RPMs are also uploaded, do not forget to merge your commit to prepare the release to trunk
and push after all artifacts are uploaded finish the process. You will be also reminded to do that by
the script itself at the end.</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="call-for-a-vote"><a class="anchor" href="#call-for-a-vote"></a>Call for a Vote</h3>
<div class="paragraph">
<p>Fill out the following email template you find in <code>$HOME/Mail</code> directory and send to the dev mailing list:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-none hljs" data-lang="none">I propose the following artifacts for release as &lt;version&gt;.
sha1: &lt;git-sha&gt;
Git: https://gitbox.apache.org/repos/asf?p=cassandra.git;a=shortlog;h=refs/tags/&lt;version&gt;-tentative
Artifacts: https://repository.apache.org/content/repositories/orgapachecassandra-&lt;nexus-id&gt;/org/apache/cassandra/apache-cassandra/&lt;version&gt;/
Staging repository: https://repository.apache.org/content/repositories/orgapachecassandra-&lt;nexus-id&gt;/
The distribution packages are available here: https://dist.apache.org/repos/dist/dev/cassandra/${version}/
The vote will be open for 72 hours (longer if needed).
[1]: (CHANGES.txt) https://git1-us-west.apache.org/repos/asf?p=cassandra.git;a=blob_plain;f=CHANGES.txt;hb=&lt;version&gt;-tentative
[2]: (NEWS.txt) https://git1-us-west.apache.org/repos/asf?p=cassandra.git;a=blob_plain;f=NEWS.txt;hb=&lt;version&gt;-tentative</code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="post-vote-operations"><a class="anchor" href="#post-vote-operations"></a>Post-vote operations</h3>
<div class="paragraph">
<p>Any PMC member can perform the following steps to formalize and publish
a successfully voted release.</p>
</div>
<div class="sect3">
<h4 id="publish-artifacts"><a class="anchor" href="#publish-artifacts"></a>Publish Artifacts</h4>
<div class="paragraph">
<p>Run the following commands to publish the voted release artifacts:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-none hljs" data-lang="none">cd ~/git
# edit the variables at the top of the `finish_release.sh` file
edit cassandra-builds/cassandra-release/finish_release.sh
# After cloning cassandra-builds repo, `finish_release.sh` is run from the actual cassandra git checkout,
# on the tentative release tag that we wish to tag for the final release version number tag.
cd ~/git/cassandra/
git checkout &lt;version&gt;-tentative
../cassandra-builds/cassandra-release/finish_release.sh -v &lt;version&gt;</code></pre>
</div>
</div>
<div class="paragraph">
<p>If successful, take note of the email text output which can be used in
the next section "Send Release Announcement". The output will also list
the next steps that are required.</p>
</div>
</div>
<div class="sect3">
<h4 id="promote-nexus-repository"><a class="anchor" href="#promote-nexus-repository"></a>Promote Nexus Repository</h4>
<div class="ulist">
<ul>
<li>
<p>Login to <a href="https://repository.apache.org">Nexus repository</a> again.</p>
</li>
<li>
<p>Click on "Staging Repositories" and then on the repository with id
"cassandra-staging".</p>
</li>
<li>
<p>Find your closed staging repository, select it and choose "Release". This
may take some time, but eventually the repository will no longer show in
Staging Repositories.</p>
</li>
<li>
<p>Next click on "Repositories", and select "Public Repositories" and
validate that your artifacts exist as you expect them.</p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect2">
<h3 id="update-and-publish-website"><a class="anchor" href="#update-and-publish-website"></a>Update and Publish Website</h3>
<div class="paragraph">
<p>See <a href="https://svn.apache.org/repos/asf/cassandra/site/src/README">docs</a> for
building and publishing the website.</p>
</div>
<div class="paragraph">
<p>Also update the CQL doc if appropriate.</p>
</div>
</div>
<div class="sect2">
<h3 id="release-version-in-jira"><a class="anchor" href="#release-version-in-jira"></a>Release version in JIRA</h3>
<div class="paragraph">
<p>Release the JIRA version.</p>
</div>
<div class="ulist">
<ul>
<li>
<p>In JIRA go to the version that you want to release and release it.</p>
</li>
<li>
<p>Create a new version, if it has not been done before.</p>
</li>
</ul>
</div>
</div>
<div class="sect2">
<h3 id="update-to-next-development-version"><a class="anchor" href="#update-to-next-development-version"></a>Update to Next Development Version</h3>
<div class="paragraph">
<p>Update the codebase to point to the next development version:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-none hljs" data-lang="none">cd ~/git/cassandra/
git checkout cassandra-&lt;version-branch&gt;
edit build.xml # update `&lt;property name="base.version" value="…"/&gt; `
edit debian/changelog # add entry for new version
edit CHANGES.txt # add entry for new version
git commit -m "Increment version to &lt;next-version&gt;" build.xml debian/changelog CHANGES.txt
# …and forward merge and push per normal procedure</code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="wait-for-artifacts-to-sync"><a class="anchor" href="#wait-for-artifacts-to-sync"></a>Wait for Artifacts to Sync</h3>
<div class="paragraph">
<p>Wait for the artifacts to sync at
<a href="https://downloads.apache.org/cassandra/" class="bare">downloads.apache.org/cassandra/</a></p>
</div>
</div>
<div class="sect2">
<h3 id="send-release-announcement"><a class="anchor" href="#send-release-announcement"></a>Send Release Announcement</h3>
<div class="paragraph">
<p>Fill out the following email template and send to both user and dev
mailing lists:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-none hljs" data-lang="none">The Cassandra team is pleased to announce the release of Apache Cassandra version &lt;version&gt;.
Apache Cassandra is a fully distributed database. It is the right choice
when you need scalability and high availability without compromising
performance.
http://cassandra.apache.org/
Downloads of source and binary distributions are listed in our download
section:
http://cassandra.apache.org/download/
This version is &lt;the first|a bug fix&gt; release[1] on the &lt;version-base&gt; series. As always,
please pay attention to the release notes[2] and let us know[3] if you
were to encounter any problem.
Enjoy!
[1]: (CHANGES.txt) https://git1-us-west.apache.org/repos/asf?p=cassandra.git;a=blob_plain;f=CHANGES.txt;hb=&lt;version&gt;
[2]: (NEWS.txt) https://git1-us-west.apache.org/repos/asf?p=cassandra.git;a=blob_plain;f=NEWS.txt;hb=&lt;version&gt;
[3]: https://issues.apache.org/jira/browse/CASSANDRA</code></pre>
</div>
</div>
<div class="paragraph">
<p>Update Slack Cassandra topic ---------------------------</p>
</div>
<div class="dlist">
<dl>
<dt class="hdlist1">Update topic in <code>cassandra</code> <code>Slack room &lt;slack&gt;</code></dt>
<dd>
<p>/topic cassandra.apache.org | Latest releases: 4.1.0, 4.0.7, 3.11.4, 3.0.18 | ask, don&#8217;t ask to ask</p>
</dd>
</dl>
</div>
</div>
<div class="sect2">
<h3 id="tweet-from-cassandra"><a class="anchor" href="#tweet-from-cassandra"></a>Tweet from @Cassandra</h3>
<div class="paragraph">
<p>Tweet the new release, from the @Cassandra account</p>
</div>
</div>
<div class="sect2">
<h3 id="delete-old-releases"><a class="anchor" href="#delete-old-releases"></a>Delete Old Releases</h3>
<div class="paragraph">
<p>As described in
<a href="http://www.apache.org/dev/release.html#when-to-archive">When to Archive</a>.</p>
</div>
<div class="paragraph">
<p>An example of removing old releases:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-none hljs" data-lang="none">svn co https://dist.apache.org/repos/dist/release/cassandra/ cassandra-dist
svn rm &lt;previous_version&gt; debian/pool/main/c/cassandra/&lt;previous_version&gt;*
svn st
# check and commit</code></pre>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<footer class="grad grad--two flex-center pb-xlarge">
<div class="inner text-center z2 relative">
<h2 class="white py-small">Get started with Cassandra, fast.</h2>
<a id="footer-cta" href="/_/quickstart.html" class="btn btn--filled ma-medium">Quickstart Guide</a>
</div>
<div class="inner flex flex-distribute-items mt-xlarge z2 relative">
<div class="col-2">
<div id="footer-logo" class="logo logo--footer mb-medium"><img src="../../assets/img/logo-white-r.png" alt="Cassandra Logo"></div>
<p>Apache Cassandra<img src="../../assets/img/registered.svg" alt="®" style="width:18px;"> powers mission-critical deployments with improved performance and unparalleled levels of scale in the cloud.</p>
<div class="footer-social-icons">
<a href="https://twitter.com/cassandra?lang=en" target="_blank"><img src="../../assets/img/twitter-icon-circle-white.svg" alt="twitter icon" width="24"></a>
<a href="https://www.linkedin.com/company/apache-cassandra/" target="_blank"><img src="../../assets/img/LI-In-Bug.png" alt="linked-in icon" width="24"></a>
<a href="https://www.youtube.com/c/PlanetCassandra" target="_blank"><img src="../../assets/img/youtube-icon.png" alt="youtube icon" width="24"></a>
</div>
</div>
<div class="col-2 flex flex-center">
<ul class="columns-2">
<li class="mb-small"><a href="/">Home</a></li>
<li class="mb-small"><a href="/_/cassandra-basics.html">Cassandra Basics</a></li>
<li class="mb-small"><a href="/_/quickstart.html">Quickstart</a></li>
<li class="mb-small"><a href="/_/ecosystem.html">Ecosystem</a></li>
<li class="mb-small"><a href="/doc/latest/">Documentation</a></li>
<li class="mb-small"><a href="/_/community.html">Community</a></li>
<li class="mb-small"><a href="/_/case-studies.html">Case Studies</a></li>
<li class="mb-small"><a href="/_/resources.html">Resources</a></li>
<li class="mb-small"><a href="/_/blog.html">Blog</a></li>
</ul>
</div>
</div>
</footer>
<div class="lower-footer bg-white pa-medium">
<div class="flex flex-row flex-vert-center">
<div class="pr-medium"><img src="../../assets/img//feather-small.png" alt="ASF" width="20"></div>
<div class="pr-medium"><a href="http://www.apache.org/" target="_blank">Foundation</a></div>
<div class="pr-medium"><a href="https://www.apache.org/events/current-event.html" target="_blank">Events</a></div>
<div class="pr-medium"><a href="https://www.apache.org/licenses/" target="_blank">License</a></div>
<div class="pr-medium"><a href="https://www.apache.org/foundation/thanks" target="_blank">Thanks</a></div>
<div class="pr-medium"><a href="https://www.apache.org/security" target="_blank">Security</a></div>
<div class="pr-medium"><a href="https://privacy.apache.org/policies/privacy-policy-public.html" target="_blank">Privacy</a></div>
<div class="pr-medium"><a href="https://www.apache.org/foundation/sponsorship" target="_blank">Sponsorship</a></div>
</div>
<p class="my-medium">© 2009-<script>document.write(new Date().getFullYear())</script> <a href="https://apache.org" target="_blank">The Apache Software Foundation</a> under the terms of the Apache License 2.0. Apache, the Apache feather logo, Apache Cassandra, Cassandra, and the Cassandra logo, are either registered trademarks or trademarks of The Apache Software Foundation.</p>
</div>
<div id="fade" class="hidden"></div>
<div id="modal" class="hidden">
<div id="close-modal" class="cursor-pointer"><svg viewBox="0 0 24 24" width="24" height="24" stroke="currentColor" stroke-width="2" fill="none" stroke-linecap="round" stroke-linejoin="round" class="css-i6dzq1"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg></div>
<div id="mod-content" class="vid-mod-content resp-container"></div>
</div>
<script>
jQuery(function(){
var windowW = $(window).width();
$(document)
.on('click','.mobile-nav-icon',function(){
$('.main-nav').fadeIn();
})
.on('click','.main-nav',function(){
if(windowW <= 1000){
$(this).fadeOut();
}
})
.on('click','#version-toggle',function(){
$(this).toggleClass('active');
$(this).next().fadeToggle();
})
.on('click','#mobile-docs-nav-burger', function(){
$(this).toggleClass('active');
$('.docs-nav').toggleClass('active');
});
var url = window.location.pathname;
var isQuickstart = url.includes('quickstart.html');
if(isQuickstart){
var footerCTA = document.getElementById('footer-cta');
footerCTA.innerHTML = 'Get latest updates';
footerCTA.setAttribute('href', '/_/blog.html');
}
});
</script>
</div>
</body>
<script>
jQuery(function(){
jQuery(document)
.on('click','.cassandra-cloud h3',function(){
var el = jQuery(this);
el.toggleClass('active');
el.next().slideToggle();
})
.on('click','.image-expand img', function(){
$(this).clone().appendTo('#mod-content');
$('#fade,#modal,#close-modal').fadeIn();
$('body,html').addClass('no-scroll');
})
.on('click','#fade,#close-modal', function(){
$('#fade,#modal,#close-modal').fadeOut();
$('body,html').removeClass('no-scroll');
$('#mod-content').html('');
});
});
</script>
</html>