You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cassandra.apache.org by az...@apache.org on 2021/11/13 17:04:50 UTC

[cassandra] 01/01: Expose Auth Caches metrics

This is an automated email from the ASF dual-hosted git repository.

azotcsit pushed a commit to branch cassandra-17062_auth_caches_metrics
in repository https://gitbox.apache.org/repos/asf/cassandra.git

commit 9df7ddc0a33188ec8bc5f617bc87cd69ca105edc
Author: Aleksei Zotov <az...@gmail.com>
AuthorDate: Sat Nov 13 21:04:22 2021 +0400

    Expose Auth Caches metrics
    
    patch by Aleksei Zotov; reviewed by XXX for CASSANDRA-17062
---
 doc/source/new/virtualtables.rst                   | 27 ++++--
 doc/source/operating/metrics.rst                   |  9 +-
 src/java/org/apache/cassandra/auth/AuthCache.java  | 53 ++++++++++--
 src/java/org/apache/cassandra/cache/CacheSize.java | 15 ++++
 .../org/apache/cassandra/cache/ChunkCache.java     |  2 +-
 .../apache/cassandra/db/virtual/CachesTable.java   | 37 ++++++---
 .../org/apache/cassandra/auth/AuthCacheTest.java   | 38 +++++++++
 .../cassandra/db/virtual/CachesTableTest.java      | 95 ++++++++++++++++++++++
 8 files changed, 247 insertions(+), 29 deletions(-)

diff --git a/doc/source/new/virtualtables.rst b/doc/source/new/virtualtables.rst
index 50a37c2..5cf50e9 100644
--- a/doc/source/new/virtualtables.rst
+++ b/doc/source/new/virtualtables.rst
@@ -203,19 +203,28 @@ The virtual tables may be described with ``DESCRIBE`` statement. The DDL listed
 
 Caches Virtual Table
 ********************
-The ``caches`` virtual table lists information about the caches. The four caches presently created are chunks, counters, keys and rows. A query on the ``caches`` virtual table returns the following details:
+The ``caches`` virtual table lists information about the caches. A query on the ``caches`` virtual table returns the following details:
 
 ::
 
  cqlsh:system_views> SELECT * FROM system_views.caches;
- name     | capacity_bytes | entry_count | hit_count | hit_ratio | recent_hit_rate_per_second | recent_request_rate_per_second | request_count | size_bytes
- ---------+----------------+-------------+-----------+-----------+----------------------------+--------------------------------+---------------+------------
-   chunks |      229638144 |          29 |       166 |      0.83 |                          5 |                              6 |           200 |     475136
- counters |       26214400 |           0 |         0 |       NaN |                          0 |                              0 |             0 |          0
-     keys |       52428800 |          14 |       124 |  0.873239 |                          4 |                              4 |           142 |       1248
-     rows |              0 |           0 |         0 |       NaN |                          0 |                              0 |             0 |          0
-
- (4 rows)
+ name                | capacity_bytes | entry_count | hit_count | hit_ratio | recent_hit_rate_per_second | recent_request_rate_per_second | request_count | size_bytes
+ --------------------+----------------+-------------+-----------+-----------+----------------------------+--------------------------------+---------------+------------
+              chunks |      229638144 |          29 |       166 |      0.83 |                          5 |                              6 |           200 |     475136
+            counters |       26214400 |           0 |         0 |       NaN |                          0 |                              0 |             0 |          0
+         credentials |           1000 |           1 |         2 |         1 |                          0 |                              0 |             2 |          1
+     jmx_permissions |           1000 |           0 |         0 |       NaN |                          0 |                              0 |             0 |          0
+                keys |       52428800 |          14 |       124 |  0.873239 |                          4 |                              4 |           142 |       1248
+ network_permissions |           1000 |           1 |        18 |         1 |                          2 |                              2 |            18 |          1
+         permissions |           1000 |           1 |         1 |         1 |                          0 |                              0 |             1 |          1
+               roles |           1000 |           1 |         9 |         1 |                          0 |                              0 |             9 |          1
+                rows |              0 |           0 |         0 |       NaN |                          0 |                              0 |             0 |          0
+
+ (8 rows)
+
+.. NOTE::
+   * chunk cache is only available if it is enabled.
+   * auth caches are only available if corresponding authorizers and authenticators are used.
 
 Settings Virtual Table
 **********************
diff --git a/doc/source/operating/metrics.rst b/doc/source/operating/metrics.rst
index e3af955..7f7e851 100644
--- a/doc/source/operating/metrics.rst
+++ b/doc/source/operating/metrics.rst
@@ -384,12 +384,19 @@ Name                         Description
 ============================ ===========
 ChunkCache                   In process uncompressed page cache.
 CounterCache                 Keeps hot counters in memory for performance.
+CredentialsCache             Auth cache for credentials.
+JmxPermissionsCache          Auth cache for JMX permissions.
 KeyCache                     Cache for partition to sstable offsets.
+NetworkPermissionsCache      Auth cache for network permissions.
+PermissionsCache             Auth cache for permissions.
+RolesCache                   Auth cache for roles.
 RowCache                     Cache for rows kept in memory.
 ============================ ===========
 
 .. NOTE::
-    Misses and MissLatency are only defined for the ChunkCache
+   * MissLatency is only defined for the ChunkCache.
+   * ChunkCache MBean is only available if the cache is enabled.
+   * AuthCache MBeans are only available if corresponding authorizers and authenticators are used.
 
 CQL Metrics
 ^^^^^^^^^^^
diff --git a/src/java/org/apache/cassandra/auth/AuthCache.java b/src/java/org/apache/cassandra/auth/AuthCache.java
index 04d3784..d96e098 100644
--- a/src/java/org/apache/cassandra/auth/AuthCache.java
+++ b/src/java/org/apache/cassandra/auth/AuthCache.java
@@ -19,7 +19,6 @@
 package org.apache.cassandra.auth;
 
 import java.util.Collections;
-import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.ScheduledFuture;
@@ -32,31 +31,35 @@ import java.util.function.Function;
 import java.util.function.IntConsumer;
 import java.util.function.IntSupplier;
 
+import com.google.common.collect.Sets;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.github.benmanes.caffeine.cache.Caffeine;
 import com.github.benmanes.caffeine.cache.LoadingCache;
 import com.github.benmanes.caffeine.cache.Policy;
+import org.apache.cassandra.cache.CacheSize;
 import org.apache.cassandra.concurrent.ExecutorPlus;
 import org.apache.cassandra.concurrent.ScheduledExecutors;
 import org.apache.cassandra.concurrent.Shutdownable;
+import org.apache.cassandra.metrics.CacheMetrics;
 import org.apache.cassandra.utils.ExecutorUtils;
 import org.apache.cassandra.utils.MBeanWrapper;
 
 import static com.google.common.base.Preconditions.checkNotNull;
 import static org.apache.cassandra.concurrent.ExecutorFactory.Global.executorFactory;
 
-public class AuthCache<K, V> implements AuthCacheMBean, Shutdownable
+public class AuthCache<K, V> implements AuthCacheMBean, CacheSize, Shutdownable
 {
     private static final Logger logger = LoggerFactory.getLogger(AuthCache.class);
 
     public static final String MBEAN_NAME_BASE = "org.apache.cassandra.auth:type=";
 
+    @SuppressWarnings("rawtypes")
     private volatile ScheduledFuture cacheRefresher = null;
 
     // Keep a handle on created instances so their executors can be terminated cleanly
-    private static final Set<Shutdownable> REGISTRY = new HashSet<>(4);
+    private static final Set<Shutdownable> REGISTRY = Sets.newHashSetWithExpectedSize(5);
 
     public static void shutdownAllAndWait(long timeout, TimeUnit unit) throws InterruptedException, TimeoutException
     {
@@ -87,6 +90,8 @@ public class AuthCache<K, V> implements AuthCacheMBean, Shutdownable
     // values until the natural expiry time.
     private final BiPredicate<K, V> invalidateCondition;
 
+    private final CacheMetrics metrics;
+
     /**
      * @param name Used for MBean
      * @param setValidityDelegate Used to set cache validity period. See {@link Policy#expireAfterWrite()}
@@ -166,6 +171,7 @@ public class AuthCache<K, V> implements AuthCacheMBean, Shutdownable
         this.loadFunction = checkNotNull(loadFunction);
         this.enableCache = checkNotNull(cacheEnabledDelegate);
         this.invalidateCondition = checkNotNull(invalidationCondition);
+        this.metrics = new CacheMetrics(name, this);
         init();
     }
 
@@ -204,7 +210,7 @@ public class AuthCache<K, V> implements AuthCacheMBean, Shutdownable
     /**
      * Retrieve a value from the cache. Will call {@link LoadingCache#get(Object)} which will
      * "load" the value if it's not present, thus populating the key.
-     * @param k
+     * @param k key
      * @return The current value of {@code K} if cached or loaded.
      *
      * See {@link LoadingCache#get(Object)} for possible exceptions.
@@ -214,7 +220,13 @@ public class AuthCache<K, V> implements AuthCacheMBean, Shutdownable
         if (cache == null)
             return loadFunction.apply(k);
 
-        return cache.get(k);
+        metrics.requests.mark();
+        V v = cache.get(k);
+        if (v != null)
+            metrics.hits.mark();
+        else
+            metrics.misses.mark();
+        return v;
     }
 
     /**
@@ -273,7 +285,7 @@ public class AuthCache<K, V> implements AuthCacheMBean, Shutdownable
 
     /**
      * Set maximum number of entries in the cache.
-     * @param maxEntries
+     * @param maxEntries max number of entries
      */
     public synchronized void setMaxEntries(int maxEntries)
     {
@@ -303,6 +315,11 @@ public class AuthCache<K, V> implements AuthCacheMBean, Shutdownable
         cache = initCache(cache);
     }
 
+    public CacheMetrics getMetrics()
+    {
+        return metrics;
+    }
+
     /**
      * (Re-)initialise the underlying cache. Will update validity, max entries, and update interval if
      * any have changed. The underlying {@link LoadingCache} will be initiated based on the provided {@code loadFunction}.
@@ -382,4 +399,28 @@ public class AuthCache<K, V> implements AuthCacheMBean, Shutdownable
     {
         return cacheRefreshExecutor.awaitTermination(timeout, units);
     }
+
+    @Override
+    public long capacity()
+    {
+        return getMaxEntries();
+    }
+
+    @Override
+    public void setCapacity(long capacity)
+    {
+        setMaxEntries(Math.toIntExact(capacity));
+    }
+
+    @Override
+    public int size()
+    {
+        return Math.toIntExact(cache.estimatedSize());
+    }
+
+    @Override
+    public long weightedSize()
+    {
+        return cache.estimatedSize();
+    }
 }
diff --git a/src/java/org/apache/cassandra/cache/CacheSize.java b/src/java/org/apache/cassandra/cache/CacheSize.java
index 71365bb..accff5e 100644
--- a/src/java/org/apache/cassandra/cache/CacheSize.java
+++ b/src/java/org/apache/cassandra/cache/CacheSize.java
@@ -23,12 +23,27 @@ package org.apache.cassandra.cache;
 public interface CacheSize
 {
 
+    /**
+     * Returns the maximum total weighted or unweighted size (number of entries) of this cache, depending on how the
+     * cache was constructed.
+     */
     long capacity();
 
+    /**
+     * Specifies the maximum total size of this cache. This value may be interpreted as the weighted or unweighted
+     * (number of entries) threshold size based on how this cache was constructed.
+     */
     void setCapacity(long capacity);
 
+    /**
+     * Returns the approximate number of entries in this cache.
+     */
     int size();
 
+    /**
+     * Returns the approximate accumulated weight of entries in this cache. If this cache does not use a weighted size
+     * bound, then it equals to the approximate number of entries.
+     */
     long weightedSize();
 
 }
diff --git a/src/java/org/apache/cassandra/cache/ChunkCache.java b/src/java/org/apache/cassandra/cache/ChunkCache.java
index c53810a..fed7ffd 100644
--- a/src/java/org/apache/cassandra/cache/ChunkCache.java
+++ b/src/java/org/apache/cassandra/cache/ChunkCache.java
@@ -165,7 +165,7 @@ public class ChunkCache
         buffer.release();
     }
 
-    public void close()
+    public void clear()
     {
         cache.invalidateAll();
     }
diff --git a/src/java/org/apache/cassandra/db/virtual/CachesTable.java b/src/java/org/apache/cassandra/db/virtual/CachesTable.java
index 5a265e6..e9c9ea3 100644
--- a/src/java/org/apache/cassandra/db/virtual/CachesTable.java
+++ b/src/java/org/apache/cassandra/db/virtual/CachesTable.java
@@ -17,7 +17,13 @@
  */
 package org.apache.cassandra.db.virtual;
 
+import org.apache.cassandra.auth.AuthenticatedUser;
+import org.apache.cassandra.auth.IAuthenticator;
+import org.apache.cassandra.auth.PasswordAuthenticator;
+import org.apache.cassandra.auth.Roles;
+import org.apache.cassandra.auth.jmx.AuthorizationProxy;
 import org.apache.cassandra.cache.ChunkCache;
+import org.apache.cassandra.config.DatabaseDescriptor;
 import org.apache.cassandra.db.marshal.*;
 import org.apache.cassandra.dht.LocalPartitioner;
 import org.apache.cassandra.metrics.CacheMetrics;
@@ -27,14 +33,14 @@ import org.apache.cassandra.service.CacheService;
 final class CachesTable extends AbstractVirtualTable
 {
     private static final String NAME = "name";
-    private static final String CAPACITY_BYTES = "capacity_bytes";
-    private static final String SIZE_BYTES = "size_bytes";
+    private static final String CAPACITY = "capacity";
     private static final String ENTRY_COUNT = "entry_count";
-    private static final String REQUEST_COUNT = "request_count";
     private static final String HIT_COUNT = "hit_count";
     private static final String HIT_RATIO = "hit_ratio";
     private static final String RECENT_REQUEST_RATE_PER_SECOND = "recent_request_rate_per_second";
     private static final String RECENT_HIT_RATE_PER_SECOND = "recent_hit_rate_per_second";
+    private static final String REQUEST_COUNT = "request_count";
+    private static final String SIZE = "size";
 
     CachesTable(String keyspace)
     {
@@ -43,38 +49,45 @@ final class CachesTable extends AbstractVirtualTable
                            .kind(TableMetadata.Kind.VIRTUAL)
                            .partitioner(new LocalPartitioner(UTF8Type.instance))
                            .addPartitionKeyColumn(NAME, UTF8Type.instance)
-                           .addRegularColumn(CAPACITY_BYTES, LongType.instance)
-                           .addRegularColumn(SIZE_BYTES, LongType.instance)
+                           .addRegularColumn(CAPACITY, LongType.instance)
                            .addRegularColumn(ENTRY_COUNT, Int32Type.instance)
-                           .addRegularColumn(REQUEST_COUNT, LongType.instance)
                            .addRegularColumn(HIT_COUNT, LongType.instance)
                            .addRegularColumn(HIT_RATIO, DoubleType.instance)
-                           .addRegularColumn(RECENT_REQUEST_RATE_PER_SECOND, LongType.instance)
                            .addRegularColumn(RECENT_HIT_RATE_PER_SECOND, LongType.instance)
+                           .addRegularColumn(RECENT_REQUEST_RATE_PER_SECOND, LongType.instance)
+                           .addRegularColumn(REQUEST_COUNT, LongType.instance)
+                           .addRegularColumn(SIZE, LongType.instance)
                            .build());
     }
 
     private void addRow(SimpleDataSet result, String name, CacheMetrics metrics)
     {
         result.row(name)
-              .column(CAPACITY_BYTES, metrics.capacity.getValue())
-              .column(SIZE_BYTES, metrics.size.getValue())
+              .column(CAPACITY, metrics.capacity.getValue())
               .column(ENTRY_COUNT, metrics.entries.getValue())
-              .column(REQUEST_COUNT, metrics.requests.getCount())
               .column(HIT_COUNT, metrics.hits.getCount())
               .column(HIT_RATIO, metrics.hitRate.getValue())
+              .column(RECENT_HIT_RATE_PER_SECOND, (long) metrics.hits.getFifteenMinuteRate())
               .column(RECENT_REQUEST_RATE_PER_SECOND, (long) metrics.requests.getFifteenMinuteRate())
-              .column(RECENT_HIT_RATE_PER_SECOND, (long) metrics.hits.getFifteenMinuteRate());
+              .column(REQUEST_COUNT, metrics.requests.getCount())
+              .column(SIZE, metrics.size.getValue());
     }
 
     public DataSet data()
     {
         SimpleDataSet result = new SimpleDataSet(metadata());
 
-        if (null != ChunkCache.instance)
+        if (ChunkCache.instance != null)
             addRow(result, "chunks", ChunkCache.instance.metrics);
         addRow(result, "counters", CacheService.instance.counterCache.getMetrics());
+        IAuthenticator authenticator = DatabaseDescriptor.getAuthenticator();
+        if (authenticator instanceof PasswordAuthenticator)
+            addRow(result, "credentials", ((PasswordAuthenticator) authenticator).getCredentialsCache().getMetrics());
+        addRow(result, "jmx_permissions", AuthorizationProxy.jmxPermissionsCache.getMetrics());
         addRow(result, "keys", CacheService.instance.keyCache.getMetrics());
+        addRow(result, "network_permissions", AuthenticatedUser.networkPermissionsCache.getMetrics());
+        addRow(result, "permissions", AuthenticatedUser.permissionsCache.getMetrics());
+        addRow(result, "roles", Roles.cache.getMetrics());
         addRow(result, "rows", CacheService.instance.rowCache.getMetrics());
 
         return result;
diff --git a/test/unit/org/apache/cassandra/auth/AuthCacheTest.java b/test/unit/org/apache/cassandra/auth/AuthCacheTest.java
index bf3d7bb..909b2e6 100644
--- a/test/unit/org/apache/cassandra/auth/AuthCacheTest.java
+++ b/test/unit/org/apache/cassandra/auth/AuthCacheTest.java
@@ -263,6 +263,31 @@ public class AuthCacheTest
         assertEquals(1, loadCounter);
     }
 
+    @Test
+    public void testMetricsOnCacheEnabled()
+    {
+        TestCache<String, Integer> authCache = new TestCache<>(this::countingLoaderForEvenNumbers, this::setValidity, () -> validity, () -> isCacheEnabled);
+        authCache.get("10");
+        authCache.get("11");
+
+        assertThat(authCache.getMetrics().requests.getCount()).isEqualTo(2L);
+        assertThat(authCache.getMetrics().hits.getCount()).isEqualTo(1L);
+        assertThat(authCache.getMetrics().misses.getCount()).isEqualTo(1L);
+    }
+
+    @Test
+    public void testMetricsOnCacheDisabled()
+    {
+        isCacheEnabled = false;
+        TestCache<String, Integer> authCache = new TestCache<>(this::countingLoaderForEvenNumbers, this::setValidity, () -> validity, () -> isCacheEnabled);
+        authCache.get("10");
+        authCache.get("11");
+
+        assertThat(authCache.getMetrics().requests.getCount()).isEqualTo(0L);
+        assertThat(authCache.getMetrics().hits.getCount()).isEqualTo(0L);
+        assertThat(authCache.getMetrics().misses.getCount()).isEqualTo(0L);
+    }
+
     private void setValidity(int validity)
     {
         this.validity = validity;
@@ -284,6 +309,19 @@ public class AuthCacheTest
         return loadedValue;
     }
 
+    /**
+     * Loads the key if it represents an even number.
+     */
+    private Integer countingLoaderForEvenNumbers(String s)
+    {
+        Integer loadedValue = countingLoader(s);
+
+        if (loadedValue % 2 == 0)
+            return loadedValue;
+        else
+            return null;
+    }
+
     private static class TestCache<K, V> extends AuthCache<K, V>
     {
         private static int nameCounter = 0; // Allow us to create many instances of cache with same name prefix
diff --git a/test/unit/org/apache/cassandra/db/virtual/CachesTableTest.java b/test/unit/org/apache/cassandra/db/virtual/CachesTableTest.java
new file mode 100644
index 0000000..d87d6f0
--- /dev/null
+++ b/test/unit/org/apache/cassandra/db/virtual/CachesTableTest.java
@@ -0,0 +1,95 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.cassandra.db.virtual;
+
+import com.google.common.collect.ImmutableList;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import org.apache.cassandra.auth.AuthenticatedUser;
+import org.apache.cassandra.auth.PasswordAuthenticator;
+import org.apache.cassandra.auth.Roles;
+import org.apache.cassandra.auth.jmx.AuthorizationProxy;
+import org.apache.cassandra.cache.ChunkCache;
+import org.apache.cassandra.config.DatabaseDescriptor;
+import org.apache.cassandra.cql3.CQLTester;
+import org.apache.cassandra.service.CacheService;
+
+public class CachesTableTest extends CQLTester
+{
+    private static final String KS_NAME = "vts";
+
+    @SuppressWarnings("FieldCanBeLocal")
+    private CachesTable table;
+
+    @BeforeClass
+    public static void setUpClass()
+    {
+        CQLTester.setUpClass();
+        CQLTester.requireAuthentication();
+    }
+
+    @Before
+    public void config()
+    {
+        table = new CachesTable(KS_NAME);
+        VirtualKeyspaceRegistry.instance.register(new VirtualKeyspace(KS_NAME, ImmutableList.of(table)));
+    }
+
+    @Test
+    public void testSelectAllWhenMetricsAreZeroed() throws Throwable
+    {
+        resetAllCaches();
+
+        assertRows(execute("SELECT * FROM vts.caches"),
+                   row("chunks",         503316480L, 0, 0L, Double.NaN, 0L, 0L, 0L, 0L),
+                   row("counters",         5242880L, 0, 0L, Double.NaN, 0L, 0L, 0L, 0L),
+                   row("credentials",         1000L, 0, 0L, Double.NaN, 0L, 0L, 0L, 0L),
+                   row("jmx_permissions",     1000L, 0, 0L, Double.NaN, 0L, 0L, 0L, 0L),
+                   row("keys",            11534336L, 0, 0L, Double.NaN, 0L, 0L, 0L, 0L),
+                   row("network_permissions", 1000L, 0, 0L, Double.NaN, 0L, 0L, 0L, 0L),
+                   row("permissions",         1000L, 0, 0L, Double.NaN, 0L, 0L, 0L, 0L),
+                   row("roles",               1000L, 0, 0L, Double.NaN, 0L, 0L, 0L, 0L),
+                   row("rows",            16777216L, 0, 0L, Double.NaN, 0L, 0L, 0L, 0L));
+    }
+
+    private void resetAllCaches()
+    {
+        ChunkCache.instance.clear();
+        ChunkCache.instance.metrics.reset();
+        CacheService.instance.counterCache.clear();
+        CacheService.instance.counterCache.getMetrics().reset();
+        PasswordAuthenticator.CredentialsCache credentialsCache = ((PasswordAuthenticator) DatabaseDescriptor.getAuthenticator()).getCredentialsCache();
+        credentialsCache.invalidate();
+        credentialsCache.getMetrics().reset();
+        AuthorizationProxy.jmxPermissionsCache.invalidate();
+        AuthorizationProxy.jmxPermissionsCache.getMetrics().reset();
+        CacheService.instance.keyCache.clear();
+        CacheService.instance.keyCache.getMetrics().reset();
+        AuthenticatedUser.networkPermissionsCache.invalidate();
+        AuthenticatedUser.networkPermissionsCache.getMetrics().reset();
+        AuthenticatedUser.permissionsCache.invalidate();
+        AuthenticatedUser.permissionsCache.getMetrics().reset();
+        Roles.cache.invalidate();
+        Roles.cache.getMetrics().reset();
+        CacheService.instance.rowCache.clear();
+        CacheService.instance.rowCache.getMetrics().reset();
+    }
+}

---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@cassandra.apache.org
For additional commands, e-mail: commits-help@cassandra.apache.org