You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cassandra.apache.org by bl...@apache.org on 2017/08/08 15:17:02 UTC

[09/10] cassandra git commit: Merge branch cassandra-3.0 into cassandra-3.11

Merge branch cassandra-3.0 into cassandra-3.11


Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo
Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/303dba65
Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/303dba65
Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/303dba65

Branch: refs/heads/trunk
Commit: 303dba6504ba069b5ea92ee18a47d3ba87c1563e
Parents: 47a2839 1a70ded
Author: Benjamin Lerer <b....@gmail.com>
Authored: Tue Aug 8 17:09:06 2017 +0200
Committer: Benjamin Lerer <b....@gmail.com>
Committed: Tue Aug 8 17:11:24 2017 +0200

----------------------------------------------------------------------
 CHANGES.txt                                     |   1 +
 .../cassandra/config/DatabaseDescriptor.java    |  26 ++-
 .../org/apache/cassandra/db/Directories.java    |   3 +-
 .../org/apache/cassandra/io/util/FileUtils.java | 181 +++++++++++++++++--
 4 files changed, 191 insertions(+), 20 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cassandra/blob/303dba65/CHANGES.txt
----------------------------------------------------------------------
diff --cc CHANGES.txt
index b778df6,1f42c70..145a746
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@@ -17,9 -13,11 +17,10 @@@ Merged from 3.0
   * Make concat work with iterators that have different subsets of columns (CASSANDRA-13482)
   * Set test.runners based on cores and memory size (CASSANDRA-13078)
   * Allow different NUMACTL_ARGS to be passed in (CASSANDRA-13557)
 - * Allow native function calls in CQLSSTableWriter (CASSANDRA-12606)
   * Fix secondary index queries on COMPACT tables (CASSANDRA-13627)
   * Nodetool listsnapshots output is missing a newline, if there are no snapshots (CASSANDRA-13568)
 - Merged from 2.2:
 +Merged from 2.2:
+  * Prevent integer overflow on exabyte filesystems (CASSANDRA-13067)
   * Fix queries with LIMIT and filtering on clustering columns (CASSANDRA-11223)
   * Fix potential NPE when resume bootstrap fails (CASSANDRA-13272)
   * Fix toJSONString for the UDT, tuple and collection types (CASSANDRA-13592)

http://git-wip-us.apache.org/repos/asf/cassandra/blob/303dba65/src/java/org/apache/cassandra/config/DatabaseDescriptor.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/config/DatabaseDescriptor.java
index 87b388e,aba7617..ad43565
--- a/src/java/org/apache/cassandra/config/DatabaseDescriptor.java
+++ b/src/java/org/apache/cassandra/config/DatabaseDescriptor.java
@@@ -19,10 -19,8 +19,9 @@@ package org.apache.cassandra.config
  
  import java.io.File;
  import java.io.IOException;
 +import java.lang.reflect.Constructor;
  import java.net.*;
  import java.nio.file.FileStore;
- import java.nio.file.Files;
  import java.nio.file.NoSuchFileException;
  import java.nio.file.Path;
  import java.nio.file.Paths;
@@@ -46,25 -40,24 +45,27 @@@ import org.apache.cassandra.config.Conf
  import org.apache.cassandra.dht.IPartitioner;
  import org.apache.cassandra.exceptions.ConfigurationException;
  import org.apache.cassandra.io.FSWriteError;
 -import org.apache.cassandra.io.sstable.format.SSTableFormat;
 +import org.apache.cassandra.io.util.DiskOptimizationStrategy;
  import org.apache.cassandra.io.util.FileUtils;
 -import org.apache.cassandra.locator.*;
 -import org.apache.cassandra.net.MessagingService;
 +import org.apache.cassandra.io.util.SpinningDiskOptimizationStrategy;
 +import org.apache.cassandra.io.util.SsdDiskOptimizationStrategy;
 +import org.apache.cassandra.locator.DynamicEndpointSnitch;
 +import org.apache.cassandra.locator.EndpointSnitchInfo;
 +import org.apache.cassandra.locator.IEndpointSnitch;
 +import org.apache.cassandra.locator.SeedProvider;
 +import org.apache.cassandra.net.BackPressureStrategy;
 +import org.apache.cassandra.net.RateBasedBackPressure;
  import org.apache.cassandra.scheduler.IRequestScheduler;
  import org.apache.cassandra.scheduler.NoScheduler;
 -import org.apache.cassandra.service.CacheService;
 -import org.apache.cassandra.thrift.ThriftServer;
 +import org.apache.cassandra.security.EncryptionContext;
 +import org.apache.cassandra.service.CacheService.CacheType;
 +import org.apache.cassandra.thrift.ThriftServer.ThriftServerType;
  import org.apache.cassandra.utils.FBUtilities;
 -import org.apache.cassandra.utils.memory.*;
 +
 +import org.apache.commons.lang3.StringUtils;
  
+ import static org.apache.cassandra.io.util.FileUtils.ONE_GB;
 -import static org.apache.cassandra.io.util.FileUtils.ONE_MB;
+ 
  public class DatabaseDescriptor
  {
      private static final Logger logger = LoggerFactory.getLogger(DatabaseDescriptor.class);
@@@ -429,53 -443,96 +430,53 @@@
          if (conf.native_transport_max_frame_size_in_mb <= 0)
              throw new ConfigurationException("native_transport_max_frame_size_in_mb must be positive, but was " + conf.native_transport_max_frame_size_in_mb, false);
  
 -        // fail early instead of OOMing (see CASSANDRA-8116)
 -        if (ThriftServer.HSHA.equals(conf.rpc_server_type) && conf.rpc_max_threads == Integer.MAX_VALUE)
 -            throw new ConfigurationException("The hsha rpc_server_type is not compatible with an rpc_max_threads " +
 -                                             "setting of 'unlimited'.  Please see the comments in cassandra.yaml " +
 -                                             "for rpc_server_type and rpc_max_threads.",
 -                                             false);
 -        if (ThriftServer.HSHA.equals(conf.rpc_server_type) && conf.rpc_max_threads > (FBUtilities.getAvailableProcessors() * 2 + 1024))
 -            logger.warn("rpc_max_threads setting of {} may be too high for the hsha server and cause unnecessary thread contention, reducing performance", conf.rpc_max_threads);
 +        // if data dirs, commitlog dir, or saved caches dir are set in cassandra.yaml, use that.  Otherwise,
 +        // use -Dcassandra.storagedir (set in cassandra-env.sh) as the parent dir for data/, commitlog/, and saved_caches/
 +        if (conf.commitlog_directory == null)
 +        {
 +            conf.commitlog_directory = storagedirFor("commitlog");
 +        }
  
 -        /* end point snitch */
 -        if (conf.endpoint_snitch == null)
 +        if (conf.hints_directory == null)
          {
 -            throw new ConfigurationException("Missing endpoint_snitch directive", false);
 +            conf.hints_directory = storagedirFor("hints");
          }
 -        snitch = createEndpointSnitch(conf.endpoint_snitch);
 -        EndpointSnitchInfo.create();
  
 -        localDC = snitch.getDatacenter(FBUtilities.getBroadcastAddress());
 -        localComparator = new Comparator<InetAddress>()
 +        if (conf.cdc_raw_directory == null)
          {
 -            public int compare(InetAddress endpoint1, InetAddress endpoint2)
 -            {
 -                boolean local1 = localDC.equals(snitch.getDatacenter(endpoint1));
 -                boolean local2 = localDC.equals(snitch.getDatacenter(endpoint2));
 -                if (local1 && !local2)
 -                    return -1;
 -                if (local2 && !local1)
 -                    return 1;
 -                return 0;
 -            }
 -        };
 +            conf.cdc_raw_directory = storagedirFor("cdc_raw");
 +        }
  
 -        /* Request Scheduler setup */
 -        requestSchedulerOptions = conf.request_scheduler_options;
 -        if (conf.request_scheduler != null)
 +        if (conf.commitlog_total_space_in_mb == null)
          {
 +            int preferredSize = 8192;
 +            int minSize = 0;
              try
              {
 -                if (requestSchedulerOptions == null)
 -                {
 -                    requestSchedulerOptions = new RequestSchedulerOptions();
 -                }
 -                Class<?> cls = Class.forName(conf.request_scheduler);
 -                requestScheduler = (IRequestScheduler) cls.getConstructor(RequestSchedulerOptions.class).newInstance(requestSchedulerOptions);
 +                // use 1/4 of available space.  See discussion on #10013 and #10199
-                 minSize = Ints.checkedCast((guessFileStore(conf.commitlog_directory).getTotalSpace() / 1048576) / 4);
++                minSize = Ints.saturatedCast((guessFileStore(conf.commitlog_directory).getTotalSpace() / 1048576) / 4);
              }
 -            catch (ClassNotFoundException e)
 +            catch (IOException e)
              {
 -                throw new ConfigurationException("Invalid Request Scheduler class " + conf.request_scheduler, false);
 +                logger.debug("Error checking disk space", e);
 +                throw new ConfigurationException(String.format("Unable to check disk space available to %s. Perhaps the Cassandra user does not have the necessary permissions",
 +                                                               conf.commitlog_directory), e);
              }
 -            catch (Exception e)
 +            if (minSize < preferredSize)
              {
 -                throw new ConfigurationException("Unable to instantiate request scheduler", e);
 +                logger.warn("Small commitlog volume detected at {}; setting commitlog_total_space_in_mb to {}.  You can override this in cassandra.yaml",
 +                            conf.commitlog_directory, minSize);
 +                conf.commitlog_total_space_in_mb = minSize;
 +            }
 +            else
 +            {
 +                conf.commitlog_total_space_in_mb = preferredSize;
              }
 -        }
 -        else
 -        {
 -            requestScheduler = new NoScheduler();
          }
  
 -        if (conf.request_scheduler_id == RequestSchedulerId.keyspace)
 -        {
 -            requestSchedulerId = conf.request_scheduler_id;
 -        }
 -        else
 -        {
 -            // Default to Keyspace
 -            requestSchedulerId = RequestSchedulerId.keyspace;
 -        }
 -
 -        // if data dirs, commitlog dir, or saved caches dir are set in cassandra.yaml, use that.  Otherwise,
 -        // use -Dcassandra.storagedir (set in cassandra-env.sh) as the parent dir for data/, commitlog/, and saved_caches/
 -        if (conf.commitlog_directory == null)
 -        {
 -            conf.commitlog_directory = System.getProperty("cassandra.storagedir", null);
 -            if (conf.commitlog_directory == null)
 -                throw new ConfigurationException("commitlog_directory is missing and -Dcassandra.storagedir is not set", false);
 -            conf.commitlog_directory += File.separator + "commitlog";
 -        }
 -
 -        if (conf.hints_directory == null)
 +        if (conf.cdc_total_space_in_mb == 0)
          {
 -            conf.hints_directory = System.getProperty("cassandra.storagedir", null);
 -            if (conf.hints_directory == null)
 -                throw new ConfigurationException("hints_directory is missing and -Dcassandra.storagedir is not set", false);
 -            conf.hints_directory += File.separator + "hints";
 -        }
 -
 -        if (conf.commitlog_total_space_in_mb == null)
 -        {
 -            int preferredSize = 8192;
 +            int preferredSize = 4096;
              int minSize = 0;
              try
              {
@@@ -536,11 -594,11 +537,10 @@@
                                                                 datadir), e);
              }
          }
-         if (dataFreeBytes < 64L * 1024 * 1048576) // 64 GB
 -        if (dataFreeBytes < 64 * ONE_GB)
 -            logger.warn("Only {} MB free across all data volumes. Consider adding more capacity to your cluster or removing obsolete snapshots",
 -                        dataFreeBytes / ONE_MB);
 -
++        if (dataFreeBytes < 64 * ONE_GB) // 64 GB
 +            logger.warn("Only {} free across all data volumes. Consider adding more capacity to your cluster or removing obsolete snapshots",
 +                        FBUtilities.prettyPrintMemory(dataFreeBytes));
  
- 
          if (conf.commitlog_directory.equals(conf.saved_caches_directory))
              throw new ConfigurationException("saved_caches_directory must not be the same as the commitlog_directory", false);
          if (conf.commitlog_directory.equals(conf.hints_directory))
@@@ -970,16 -699,62 +970,30 @@@
          }
          try
          {
 -            Class<?> seedProviderClass = Class.forName(conf.seed_provider.class_name);
 -            seedProvider = (SeedProvider)seedProviderClass.getConstructor(Map.class).newInstance(conf.seed_provider.parameters);
 +            partitioner = FBUtilities.newPartitioner(System.getProperty(Config.PROPERTY_PREFIX + "partitioner", conf.partitioner));
          }
 -        // there are about 5 checked exceptions that could be thrown here.
          catch (Exception e)
          {
 -            throw new ConfigurationException(e.getMessage() + "\nFatal configuration error; unable to start server.  See log for stacktrace.", true);
 -        }
 -        if (seedProvider.getSeeds().size() == 0)
 -            throw new ConfigurationException("The seed provider lists no seeds.", false);
 -
 -        if (conf.user_defined_function_fail_timeout < 0)
 -            throw new ConfigurationException("user_defined_function_fail_timeout must not be negative", false);
 -        if (conf.user_defined_function_warn_timeout < 0)
 -            throw new ConfigurationException("user_defined_function_warn_timeout must not be negative", false);
 -
 -        if (conf.user_defined_function_fail_timeout < conf.user_defined_function_warn_timeout)
 -            throw new ConfigurationException("user_defined_function_warn_timeout must less than user_defined_function_fail_timeout", false);
 -
 -        if (conf.max_mutation_size_in_kb == null)
 -            conf.max_mutation_size_in_kb = conf.commitlog_segment_size_in_mb * 1024 / 2;
 -        else if (conf.commitlog_segment_size_in_mb * 1024 < 2 * conf.max_mutation_size_in_kb)
 -            throw new ConfigurationException("commitlog_segment_size_in_mb must be at least twice the size of max_mutation_size_in_kb / 1024", false);
 -
 -        // native transport encryption options
 -        if (conf.native_transport_port_ssl != null
 -            && conf.native_transport_port_ssl.intValue() != conf.native_transport_port.intValue()
 -            && !conf.client_encryption_options.enabled)
 -        {
 -            throw new ConfigurationException("Encryption must be enabled in client_encryption_options for native_transport_port_ssl", false);
 +            throw new ConfigurationException("Invalid partitioner class " + conf.partitioner, false);
          }
  
 -        if (conf.max_value_size_in_mb == null || conf.max_value_size_in_mb <= 0)
 -            throw new ConfigurationException("max_value_size_in_mb must be positive", false);
 -
 -        if (conf.otc_coalescing_enough_coalesced_messages > 128)
 -            throw new ConfigurationException("otc_coalescing_enough_coalesced_messages must be smaller than 128", false);
 -
 -        if (conf.otc_coalescing_enough_coalesced_messages <= 0)
 -            throw new ConfigurationException("otc_coalescing_enough_coalesced_messages must be positive", false);
 +        paritionerName = partitioner.getClass().getCanonicalName();
      }
  
+     /**
+      * Computes the sum of the 2 specified positive values returning {@code Long.MAX_VALUE} if the sum overflow.
+      *
+      * @param left the left operand
+      * @param right the right operand
+      * @return the sum of the 2 specified positive values of {@code Long.MAX_VALUE} if the sum overflow.
+      */
+     private static long saturatedSum(long left, long right)
+     {
+         assert left >= 0 && right >= 0;
+         long sum = left + right;
+         return sum < 0 ? Long.MAX_VALUE : sum;
+     }
+ 
      private static FileStore guessFileStore(String dir) throws IOException
      {
          Path path = Paths.get(dir);

http://git-wip-us.apache.org/repos/asf/cassandra/blob/303dba65/src/java/org/apache/cassandra/db/Directories.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/cassandra/blob/303dba65/src/java/org/apache/cassandra/io/util/FileUtils.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/io/util/FileUtils.java
index c6e4e63,80df67b..24017cf
--- a/src/java/org/apache/cassandra/io/util/FileUtils.java
+++ b/src/java/org/apache/cassandra/io/util/FileUtils.java
@@@ -23,7 -23,8 +23,9 @@@ import java.nio.channels.FileChannel
  import java.nio.charset.Charset;
  import java.nio.charset.StandardCharsets;
  import java.nio.file.*;
 +import java.nio.file.attribute.BasicFileAttributes;
+ import java.nio.file.attribute.FileAttributeView;
+ import java.nio.file.attribute.FileStoreAttributeView;
  import java.text.DecimalFormat;
  import java.util.Arrays;
  import java.util.Collections;
@@@ -54,14 -54,14 +56,14 @@@ public final class FileUtil
      public static final Charset CHARSET = StandardCharsets.UTF_8;
  
      private static final Logger logger = LoggerFactory.getLogger(FileUtils.class);
-     private static final double KB = 1024d;
-     private static final double MB = 1024*1024d;
-     private static final double GB = 1024*1024*1024d;
-     private static final double TB = 1024*1024*1024*1024d;
+     public static final long ONE_KB = 1024;
+     public static final long ONE_MB = 1024 * ONE_KB;
+     public static final long ONE_GB = 1024 * ONE_MB;
+     public static final long ONE_TB = 1024 * ONE_GB;
  
      private static final DecimalFormat df = new DecimalFormat("#.##");
 -    private static final boolean canCleanDirectBuffers;
 -    private static final AtomicReference<FSErrorHandler> fsErrorHandler = new AtomicReference<>();
 +    public static final boolean isCleanerAvailable;
 +    private static final AtomicReference<Optional<FSErrorHandler>> fsErrorHandler = new AtomicReference<>(Optional.empty());
  
      static
      {
@@@ -415,29 -418,29 +417,29 @@@
      public static String stringifyFileSize(double value)
      {
          double d;
-         if ( value >= TB )
+         if ( value >= ONE_TB )
          {
-             d = value / TB;
+             d = value / ONE_TB;
              String val = df.format(d);
 -            return val + " TB";
 +            return val + " TiB";
          }
-         else if ( value >= GB )
+         else if ( value >= ONE_GB )
          {
-             d = value / GB;
+             d = value / ONE_GB;
              String val = df.format(d);
 -            return val + " GB";
 +            return val + " GiB";
          }
-         else if ( value >= MB )
+         else if ( value >= ONE_MB )
          {
-             d = value / MB;
+             d = value / ONE_MB;
              String val = df.format(d);
 -            return val + " MB";
 +            return val + " MiB";
          }
-         else if ( value >= KB )
+         else if ( value >= ONE_KB )
          {
-             d = value / KB;
+             d = value / ONE_KB;
              String val = df.format(d);
 -            return val + " KB";
 +            return val + " KiB";
          }
          else
          {
@@@ -606,6 -603,161 +608,161 @@@
  
      public static void setFSErrorHandler(FSErrorHandler handler)
      {
 -        fsErrorHandler.getAndSet(handler);
 +        fsErrorHandler.getAndSet(Optional.ofNullable(handler));
      }
+ 
+     /**
+      * Returns the size of the specified partition.
+      * <p>This method handles large file system by returning {@code Long.MAX_VALUE} if the  size overflow.
+      * See <a href='https://bugs.openjdk.java.net/browse/JDK-8179320'>JDK-8179320</a> for more information.</p>
+      *
+      * @param file the partition
+      * @return the size, in bytes, of the partition or {@code 0L} if the abstract pathname does not name a partition
+      */
+     public static long getTotalSpace(File file)
+     {
+         return handleLargeFileSystem(file.getTotalSpace());
+     }
+ 
+     /**
+      * Returns the number of unallocated bytes on the specified partition.
+      * <p>This method handles large file system by returning {@code Long.MAX_VALUE} if the  number of unallocated bytes
+      * overflow. See <a href='https://bugs.openjdk.java.net/browse/JDK-8179320'>JDK-8179320</a> for more information</p>
+      *
+      * @param file the partition
+      * @return the number of unallocated bytes on the partition or {@code 0L}
+      * if the abstract pathname does not name a partition.
+      */
+     public static long getFreeSpace(File file)
+     {
+         return handleLargeFileSystem(file.getFreeSpace());
+     }
+ 
+     /**
+      * Returns the number of available bytes on the specified partition.
+      * <p>This method handles large file system by returning {@code Long.MAX_VALUE} if the  number of available bytes
+      * overflow. See <a href='https://bugs.openjdk.java.net/browse/JDK-8179320'>JDK-8179320</a> for more information</p>
+      *
+      * @param file the partition
+      * @return the number of available bytes on the partition or {@code 0L}
+      * if the abstract pathname does not name a partition.
+      */
+     public static long getUsableSpace(File file)
+     {
+         return handleLargeFileSystem(file.getUsableSpace());
+     }
+ 
+     /**
+      * Returns the {@link FileStore} representing the file store where a file
+      * is located. This {@link FileStore} handles large file system by returning {@code Long.MAX_VALUE}
+      * from {@code FileStore#getTotalSpace()}, {@code FileStore#getUnallocatedSpace()} and {@code FileStore#getUsableSpace()}
+      * it the value is bigger than {@code Long.MAX_VALUE}. See <a href='https://bugs.openjdk.java.net/browse/JDK-8162520'>JDK-8162520</a>
+      * for more information.
+      *
+      * @param path the path to the file
+      * @return the file store where the file is stored
+      */
+     public static FileStore getFileStore(Path path) throws IOException
+     {
+         return new SafeFileStore(Files.getFileStore(path));
+     }
+ 
+     /**
+      * Handle large file system by returning {@code Long.MAX_VALUE} when the size overflows.
+      * @param size returned by the Java's FileStore methods
+      * @return the size or {@code Long.MAX_VALUE} if the size was bigger than {@code Long.MAX_VALUE}
+      */
+     private static long handleLargeFileSystem(long size)
+     {
+         return size < 0 ? Long.MAX_VALUE : size;
+     }
+ 
+     /**
+      * Private constructor as the class contains only static methods.
+      */
+     private FileUtils()
+     {
+     }
+ 
+     /**
+      * FileStore decorator used to safely handle large file system.
+      *
+      * <p>Java's FileStore methods (getTotalSpace/getUnallocatedSpace/getUsableSpace) are limited to reporting bytes as
+      * signed long (2^63-1), if the filesystem is any bigger, then the size overflows. {@code SafeFileStore} will
+      * return {@code Long.MAX_VALUE} if the size overflow.</p>
+      *
+      * @see https://bugs.openjdk.java.net/browse/JDK-8162520.
+      */
+     private static final class SafeFileStore extends FileStore
+     {
+         /**
+          * The decorated {@code FileStore}
+          */
+         private final FileStore fileStore;
+ 
+         public SafeFileStore(FileStore fileStore)
+         {
+             this.fileStore = fileStore;
+         }
+ 
+         @Override
+         public String name()
+         {
+             return fileStore.name();
+         }
+ 
+         @Override
+         public String type()
+         {
+             return fileStore.type();
+         }
+ 
+         @Override
+         public boolean isReadOnly()
+         {
+             return fileStore.isReadOnly();
+         }
+ 
+         @Override
+         public long getTotalSpace() throws IOException
+         {
+             return handleLargeFileSystem(fileStore.getTotalSpace());
+         }
+ 
+         @Override
+         public long getUsableSpace() throws IOException
+         {
+             return handleLargeFileSystem(fileStore.getUsableSpace());
+         }
+ 
+         @Override
+         public long getUnallocatedSpace() throws IOException
+         {
+             return handleLargeFileSystem(fileStore.getUnallocatedSpace());
+         }
+ 
+         @Override
+         public boolean supportsFileAttributeView(Class<? extends FileAttributeView> type)
+         {
+             return fileStore.supportsFileAttributeView(type);
+         }
+ 
+         @Override
+         public boolean supportsFileAttributeView(String name)
+         {
+             return fileStore.supportsFileAttributeView(name);
+         }
+ 
+         @Override
+         public <V extends FileStoreAttributeView> V getFileStoreAttributeView(Class<V> type)
+         {
+             return fileStore.getFileStoreAttributeView(type);
+         }
+ 
+         @Override
+         public Object getAttribute(String attribute) throws IOException
+         {
+             return fileStore.getAttribute(attribute);
+         }
+     }
  }


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