diff --git a/CHANGES.txt b/CHANGES.txt index 693042563b..d11c3af1b9 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,4 +1,5 @@ 4.1 + * Introduce separate rate limiting settings for entire SSTable streaming (CASSANDRA-17065) * Implement Virtual Tables for Auth Caches (CASSANDRA-16914) * Actively update auth cache in the background (CASSANDRA-16957) * Add unix time conversion functions (CASSANDRA-17029) diff --git a/conf/cassandra.yaml b/conf/cassandra.yaml index 12221ca2c2..c47f223d11 100644 --- a/conf/cassandra.yaml +++ b/conf/cassandra.yaml @@ -930,13 +930,26 @@ sstable_preemptive_open_interval_in_mb: 50 # When enabled, permits Cassandra to zero-copy stream entire eligible # SSTables between nodes, including every component. # This speeds up the network transfer significantly subject to -# throttling specified by stream_throughput_outbound_megabits_per_sec. +# throttling specified by entire_sstable_stream_throughput_outbound_megabits_per_sec, +# and entire_sstable_inter_dc_stream_throughput_outbound_megabits_per_sec +# for inter-DC transfers. # Enabling this will reduce the GC pressure on sending and receiving node. # When unset, the default is enabled. While this feature tries to keep the # disks balanced, it cannot guarantee it. This feature will be automatically # disabled if internode encryption is enabled. # stream_entire_sstables: true +# Throttles entire SSTable outbound streaming file transfers on +# this node to the given total throughput in Mbps. +# Setting this value to 0 it disables throttling. +# When unset, the default is 200 Mbps or 25 MB/s. +# entire_sstable_stream_throughput_outbound_megabits_per_sec: 200 + +# Throttles entire SSTable file streaming between datacenters. +# Setting this value to 0 disables throttling for entire SSTable inter-DC file streaming. +# When unset, the default is 200 Mbps or 25 MB/s. +# entire_sstable_inter_dc_stream_throughput_outbound_megabits_per_sec: 200 + # Throttles all outbound streaming file transfers on this node to the # given total throughput in Mbps. This is necessary because Cassandra does # mostly sequential IO when streaming data during bootstrap or repair, which @@ -948,7 +961,7 @@ sstable_preemptive_open_interval_in_mb: 50 # this setting allows users to throttle inter dc stream throughput in addition # to throttling all network stream traffic as configured with # stream_throughput_outbound_megabits_per_sec -# When unset, the default is 200 Mbps or 25 MB/s +# When unset, the default is 200 Mbps or 25 MB/s. # inter_dc_stream_throughput_outbound_megabits_per_sec: 200 # Server side timeouts for requests. The server will return a timeout exception diff --git a/src/java/org/apache/cassandra/config/Config.java b/src/java/org/apache/cassandra/config/Config.java index 5a1d048af1..e043c0164f 100644 --- a/src/java/org/apache/cassandra/config/Config.java +++ b/src/java/org/apache/cassandra/config/Config.java @@ -244,6 +244,9 @@ public class Config public volatile int stream_throughput_outbound_megabits_per_sec = 200; public volatile int inter_dc_stream_throughput_outbound_megabits_per_sec = 200; + public volatile int entire_sstable_stream_throughput_outbound_megabits_per_sec = 200; + public volatile int entire_sstable_inter_dc_stream_throughput_outbound_megabits_per_sec = 200; + public String[] data_file_directories = new String[0]; /** diff --git a/src/java/org/apache/cassandra/config/DatabaseDescriptor.java b/src/java/org/apache/cassandra/config/DatabaseDescriptor.java index 3ef16034da..8633277566 100644 --- a/src/java/org/apache/cassandra/config/DatabaseDescriptor.java +++ b/src/java/org/apache/cassandra/config/DatabaseDescriptor.java @@ -1884,6 +1884,16 @@ public class DatabaseDescriptor conf.stream_throughput_outbound_megabits_per_sec = value; } + public static int getEntireSSTableStreamThroughputOutboundMegabitsPerSec() + { + return conf.entire_sstable_stream_throughput_outbound_megabits_per_sec; + } + + public static void setEntireSSTableStreamThroughputOutboundMegabitsPerSec(int value) + { + conf.entire_sstable_stream_throughput_outbound_megabits_per_sec = value; + } + public static int getInterDCStreamThroughputOutboundMegabitsPerSec() { return conf.inter_dc_stream_throughput_outbound_megabits_per_sec; @@ -1894,6 +1904,16 @@ public class DatabaseDescriptor conf.inter_dc_stream_throughput_outbound_megabits_per_sec = value; } + public static int getEntireSSTableInterDCStreamThroughputOutboundMegabitsPerSec() + { + return conf.entire_sstable_inter_dc_stream_throughput_outbound_megabits_per_sec; + } + + public static void setEntireSSTableInterDCStreamThroughputOutboundMegabitsPerSec(int value) + { + conf.entire_sstable_inter_dc_stream_throughput_outbound_megabits_per_sec = value; + } + /** * Checks if the local system data must be stored in a specific location which supports redundancy. * diff --git a/src/java/org/apache/cassandra/db/streaming/CassandraEntireSSTableStreamWriter.java b/src/java/org/apache/cassandra/db/streaming/CassandraEntireSSTableStreamWriter.java index f096e576c0..b4f2170b92 100644 --- a/src/java/org/apache/cassandra/db/streaming/CassandraEntireSSTableStreamWriter.java +++ b/src/java/org/apache/cassandra/db/streaming/CassandraEntireSSTableStreamWriter.java @@ -53,7 +53,7 @@ public class CassandraEntireSSTableStreamWriter this.sstable = sstable; this.context = context; this.manifest = context.manifest(); - this.limiter = StreamManager.getRateLimiter(session.peer); + this.limiter = StreamManager.getEntireSSTableRateLimiter(session.peer); } /** diff --git a/src/java/org/apache/cassandra/net/AsyncChannelOutputPlus.java b/src/java/org/apache/cassandra/net/AsyncChannelOutputPlus.java index 7fcdc051e3..983db3ef51 100644 --- a/src/java/org/apache/cassandra/net/AsyncChannelOutputPlus.java +++ b/src/java/org/apache/cassandra/net/AsyncChannelOutputPlus.java @@ -92,7 +92,7 @@ public abstract class AsyncChannelOutputPlus extends BufferedDataOutputStreamPlu *
* If this method returns normally, the ChannelPromise MUST be writtenAndFlushed, or else completed exceptionally.
*/
- protected ChannelPromise beginFlush(int byteCount, int lowWaterMark, int highWaterMark) throws IOException
+ protected ChannelPromise beginFlush(long byteCount, long lowWaterMark, long highWaterMark) throws IOException
{
waitForSpace(byteCount, lowWaterMark, highWaterMark);
@@ -125,18 +125,18 @@ public abstract class AsyncChannelOutputPlus extends BufferedDataOutputStreamPlu
*
* If we currently have lowWaterMark or fewer bytes flushing, we are good to go.
* If our new write will not take us over our highWaterMark, we are good to go.
- * Otherwise we wait until either of these conditions are met.
+ * Otherwise, we wait until either of these conditions are met.
*
* This may only be invoked by the writer thread, never by the eventLoop.
*
* @throws IOException if a prior asynchronous flush failed
*/
- private void waitForSpace(int bytesToWrite, int lowWaterMark, int highWaterMark) throws IOException
+ private void waitForSpace(long bytesToWrite, long lowWaterMark, long highWaterMark) throws IOException
{
// decide when we would be willing to carry on writing
// we are always writable if we have lowWaterMark or fewer bytes, no matter how many bytes we are flushing
// our callers should not be supplying more than (highWaterMark - lowWaterMark) bytes, but we must work correctly if they do
- int wakeUpWhenFlushing = highWaterMark - bytesToWrite;
+ long wakeUpWhenFlushing = highWaterMark - bytesToWrite;
waitUntilFlushed(max(lowWaterMark, wakeUpWhenFlushing), lowWaterMark);
flushing += bytesToWrite;
}
@@ -147,7 +147,7 @@ public abstract class AsyncChannelOutputPlus extends BufferedDataOutputStreamPlu
*
* This may only be invoked by the writer thread, never by the eventLoop.
*/
- void waitUntilFlushed(int wakeUpWhenExcessBytesWritten, int signalWhenExcessBytesWritten) throws IOException
+ void waitUntilFlushed(long wakeUpWhenExcessBytesWritten, long signalWhenExcessBytesWritten) throws IOException
{
// we assume that we are happy to wake up at least as early as we will be signalled; otherwise we will never exit
assert signalWhenExcessBytesWritten <= wakeUpWhenExcessBytesWritten;
diff --git a/src/java/org/apache/cassandra/net/AsyncStreamingOutputPlus.java b/src/java/org/apache/cassandra/net/AsyncStreamingOutputPlus.java
index 096b883f20..2a51ae3071 100644
--- a/src/java/org/apache/cassandra/net/AsyncStreamingOutputPlus.java
+++ b/src/java/org/apache/cassandra/net/AsyncStreamingOutputPlus.java
@@ -29,6 +29,7 @@ import org.slf4j.LoggerFactory;
import io.netty.channel.Channel;
import io.netty.channel.ChannelPromise;
+import io.netty.channel.DefaultFileRegion;
import io.netty.channel.FileRegion;
import io.netty.channel.WriteBufferWaterMark;
import io.netty.handler.ssl.SslHandler;
@@ -203,6 +204,28 @@ public class AsyncStreamingOutputPlus extends AsyncChannelOutputPlus implements
@VisibleForTesting
long writeFileToChannelZeroCopy(FileChannel file, RateLimiter limiter, int batchSize, int lowWaterMark, int highWaterMark) throws IOException
+ {
+ if (!limiter.isRateLimited())
+ return writeFileToChannelZeroCopyUnthrottled(file);
+ else
+ return writeFileToChannelZeroCopyThrottled(file, limiter, batchSize, lowWaterMark, highWaterMark);
+ }
+
+ private long writeFileToChannelZeroCopyUnthrottled(FileChannel file) throws IOException
+ {
+ final long length = file.size();
+
+ if (logger.isTraceEnabled())
+ logger.trace("Writing {} bytes", length);
+
+ ChannelPromise promise = beginFlush(length, 0, length);
+ final DefaultFileRegion defaultFileRegion = new DefaultFileRegion(file, 0, length);
+ channel.writeAndFlush(defaultFileRegion, promise);
+
+ return length;
+ }
+
+ private long writeFileToChannelZeroCopyThrottled(FileChannel file, RateLimiter limiter, int batchSize, int lowWaterMark, int highWaterMark) throws IOException
{
final long length = file.size();
long bytesTransferred = 0;
@@ -210,9 +233,10 @@ public class AsyncStreamingOutputPlus extends AsyncChannelOutputPlus implements
final SharedFileChannel sharedFile = SharedDefaultFileRegion.share(file);
try
{
+ int toWrite;
while (bytesTransferred < length)
{
- int toWrite = (int) min(batchSize, length - bytesTransferred);
+ toWrite = (int) min(batchSize, length - bytesTransferred);
limiter.acquire(toWrite);
ChannelPromise promise = beginFlush(toWrite, lowWaterMark, highWaterMark);
diff --git a/src/java/org/apache/cassandra/service/StorageService.java b/src/java/org/apache/cassandra/service/StorageService.java
index c1ad9cb04d..dc3b878f72 100644
--- a/src/java/org/apache/cassandra/service/StorageService.java
+++ b/src/java/org/apache/cassandra/service/StorageService.java
@@ -62,8 +62,6 @@ import com.google.common.util.concurrent.*;
import org.apache.cassandra.config.CassandraRelevantProperties;
import org.apache.cassandra.concurrent.*;
-import org.apache.cassandra.config.CassandraRelevantProperties;
-import org.apache.cassandra.config.ParameterizedClass;
import org.apache.cassandra.dht.RangeStreamer.FetchReplica;
import org.apache.cassandra.fql.FullQueryLogger;
import org.apache.cassandra.fql.FullQueryLoggerOptions;
@@ -1511,7 +1509,7 @@ public class StorageService extends NotificationBroadcasterSupport implements IE
int oldValue = DatabaseDescriptor.getStreamThroughputOutboundMegabitsPerSec();
DatabaseDescriptor.setStreamThroughputOutboundMegabitsPerSec(value);
StreamManager.StreamRateLimiter.updateThroughput();
- logger.info("setstreamthroughput: throttle set to {} Mb/s (was {} Mb/s)", value, oldValue);
+ logger.info("setstreamthroughput: throttle set to {}{} Mb/s (was {} Mb/s)", value, value <= 0 ? " (unlimited)" : "", oldValue);
}
public int getStreamThroughputMbPerSec()
@@ -1519,12 +1517,25 @@ public class StorageService extends NotificationBroadcasterSupport implements IE
return DatabaseDescriptor.getStreamThroughputOutboundMegabitsPerSec();
}
+ public void setEntireSSTableStreamThroughputMbPerSec(int value)
+ {
+ int oldValue = DatabaseDescriptor.getEntireSSTableStreamThroughputOutboundMegabitsPerSec();
+ DatabaseDescriptor.setEntireSSTableStreamThroughputOutboundMegabitsPerSec(value);
+ StreamManager.StreamRateLimiter.updateEntireSSTableThroughput();
+ logger.info("setstreamthroughput (entire SSTable): throttle set to {}{} Mb/s (was {} Mb/s)", value, value <= 0 ? " (unlimited)" : "", oldValue);
+ }
+
+ public int getEntireSSTableStreamThroughputMbPerSec()
+ {
+ return DatabaseDescriptor.getEntireSSTableStreamThroughputOutboundMegabitsPerSec();
+ }
+
public void setInterDCStreamThroughputMbPerSec(int value)
{
int oldValue = DatabaseDescriptor.getInterDCStreamThroughputOutboundMegabitsPerSec();
DatabaseDescriptor.setInterDCStreamThroughputOutboundMegabitsPerSec(value);
StreamManager.StreamRateLimiter.updateInterDCThroughput();
- logger.info("setinterdcstreamthroughput: throttle set to {} Mb/s (was {} Mb/s)", value, oldValue);
+ logger.info("setinterdcstreamthroughput: throttle set to {}{} Mb/s (was {} Mb/s)", value, value <= 0 ? " (unlimited)" : "", oldValue);
}
public int getInterDCStreamThroughputMbPerSec()
@@ -1532,6 +1543,18 @@ public class StorageService extends NotificationBroadcasterSupport implements IE
return DatabaseDescriptor.getInterDCStreamThroughputOutboundMegabitsPerSec();
}
+ public void setEntireSSTableInterDCStreamThroughputMbPerSec(int value)
+ {
+ int oldValue = DatabaseDescriptor.getEntireSSTableInterDCStreamThroughputOutboundMegabitsPerSec();
+ DatabaseDescriptor.setEntireSSTableInterDCStreamThroughputOutboundMegabitsPerSec(value);
+ StreamManager.StreamRateLimiter.updateEntireSSTableInterDCThroughput();
+ logger.info("setinterdcstreamthroughput (entire SSTable): throttle set to {}{} Mb/s (was {} Mb/s)", value, value <= 0 ? " (unlimited)" : "", oldValue);
+ }
+
+ public int getEntireSSTableInterDCStreamThroughputMbPerSec()
+ {
+ return DatabaseDescriptor.getEntireSSTableInterDCStreamThroughputOutboundMegabitsPerSec();
+ }
public int getCompactionThroughputMbPerSec()
{
diff --git a/src/java/org/apache/cassandra/service/StorageServiceMBean.java b/src/java/org/apache/cassandra/service/StorageServiceMBean.java
index 256083fc5b..ed31e3c479 100644
--- a/src/java/org/apache/cassandra/service/StorageServiceMBean.java
+++ b/src/java/org/apache/cassandra/service/StorageServiceMBean.java
@@ -624,6 +624,12 @@ public interface StorageServiceMBean extends NotificationEmitter
public void setInterDCStreamThroughputMbPerSec(int value);
public int getInterDCStreamThroughputMbPerSec();
+ public void setEntireSSTableStreamThroughputMbPerSec(int value);
+ public int getEntireSSTableStreamThroughputMbPerSec();
+
+ public void setEntireSSTableInterDCStreamThroughputMbPerSec(int value);
+ public int getEntireSSTableInterDCStreamThroughputMbPerSec();
+
public int getCompactionThroughputMbPerSec();
public void setCompactionThroughputMbPerSec(int value);
diff --git a/src/java/org/apache/cassandra/streaming/StreamManager.java b/src/java/org/apache/cassandra/streaming/StreamManager.java
index 9c24c1c74f..8cc9494cb6 100644
--- a/src/java/org/apache/cassandra/streaming/StreamManager.java
+++ b/src/java/org/apache/cassandra/streaming/StreamManager.java
@@ -31,8 +31,8 @@ import com.google.common.base.Function;
import com.google.common.collect.Iterables;
import com.google.common.collect.Sets;
import com.google.common.util.concurrent.RateLimiter;
-
import org.cliffc.high_scale_lib.NonBlockingHashMap;
+
import org.apache.cassandra.config.DatabaseDescriptor;
import org.apache.cassandra.locator.InetAddressAndPort;
import org.apache.cassandra.streaming.management.StreamEventJMXNotifier;
@@ -57,25 +57,60 @@ public class StreamManager implements StreamManagerMBean
*/
public static StreamRateLimiter getRateLimiter(InetAddressAndPort peer)
{
- return new StreamRateLimiter(peer);
+ return new StreamRateLimiter(peer,
+ StreamRateLimiter.LIMITER,
+ StreamRateLimiter.INTER_DC_LIMITER,
+ DatabaseDescriptor.getStreamThroughputOutboundMegabitsPerSec(),
+ DatabaseDescriptor.getInterDCStreamThroughputOutboundMegabitsPerSec());
+ }
+
+ /**
+ * Get streaming rate limiter for entire SSTable operations.
+ * When {@code entire_sstable_stream_throughput_outbound_megabits_per_sec}
+ * is less than or equal ot {@code 0}, this returns rate limiter with the
+ * rate of {@link Double.MAX_VALUE} bytes per second.
+ * Rate unit is bytes per sec.
+ *
+ * @param peer the peer location
+ * @return {@link StreamRateLimiter} with entire SSTable rate limit set based on peer location
+ */
+ public static StreamRateLimiter getEntireSSTableRateLimiter(InetAddressAndPort peer)
+ {
+ return new StreamRateLimiter(peer,
+ StreamRateLimiter.ENTIRE_SSTABLE_LIMITER,
+ StreamRateLimiter.ENTIRE_SSTABLE_INTER_DC_LIMITER,
+ DatabaseDescriptor.getEntireSSTableStreamThroughputOutboundMegabitsPerSec(),
+ DatabaseDescriptor.getEntireSSTableInterDCStreamThroughputOutboundMegabitsPerSec());
}
public static class StreamRateLimiter implements StreamingDataOutputPlus.RateLimiter
{
public static final double BYTES_PER_MEGABIT = (1024 * 1024) / 8; // from bits
- private static final RateLimiter limiter = RateLimiter.create(calculateRateInBytes());
- private static final RateLimiter interDCLimiter = RateLimiter.create(calculateInterDCRateInBytes());
- private final boolean isLocalDC;
+ private static final RateLimiter LIMITER = RateLimiter.create(calculateRateInBytes());
+ private static final RateLimiter INTER_DC_LIMITER = RateLimiter.create(calculateInterDCRateInBytes());
+ private static final RateLimiter ENTIRE_SSTABLE_LIMITER = RateLimiter.create(calculateEntireSSTableRateInBytes());
+ private static final RateLimiter ENTIRE_SSTABLE_INTER_DC_LIMITER = RateLimiter.create(calculateEntireSSTableInterDCRateInBytes());
- public StreamRateLimiter(InetAddressAndPort peer)
+ private final RateLimiter limiter;
+ private final RateLimiter interDCLimiter;
+ private final boolean isLocalDC;
+ private final int throughput;
+ private final int interDCThroughput;
+
+ private StreamRateLimiter(InetAddressAndPort peer, RateLimiter limiter, RateLimiter interDCLimiter, int throughput, int interDCThroughput)
{
+ this.limiter = limiter;
+ this.interDCLimiter = interDCLimiter;
+ this.throughput = throughput;
+ this.interDCThroughput = interDCThroughput;
if (DatabaseDescriptor.getLocalDataCenter() != null && DatabaseDescriptor.getEndpointSnitch() != null)
isLocalDC = DatabaseDescriptor.getLocalDataCenter().equals(
- DatabaseDescriptor.getEndpointSnitch().getDatacenter(peer));
+ DatabaseDescriptor.getEndpointSnitch().getDatacenter(peer));
else
isLocalDC = true;
}
+ @Override
public void acquire(int toTransfer)
{
limiter.acquire(toTransfer);
@@ -83,40 +118,88 @@ public class StreamManager implements StreamManagerMBean
interDCLimiter.acquire(toTransfer);
}
+ @Override
+ public boolean isRateLimited()
+ {
+ // Rate limiting is enabled when throughput greater than 0.
+ // If the peer is not local, also check whether inter-DC rate limiting is enabled.
+ return throughput > 0 || (!isLocalDC && interDCThroughput > 0);
+ }
+
public static void updateThroughput()
{
- limiter.setRate(calculateRateInBytes());
+ LIMITER.setRate(calculateRateInBytes());
}
public static void updateInterDCThroughput()
{
- interDCLimiter.setRate(calculateInterDCRateInBytes());
+ INTER_DC_LIMITER.setRate(calculateInterDCRateInBytes());
+ }
+
+ public static void updateEntireSSTableThroughput()
+ {
+ ENTIRE_SSTABLE_LIMITER.setRate(calculateEntireSSTableRateInBytes());
+ }
+
+ public static void updateEntireSSTableInterDCThroughput()
+ {
+ ENTIRE_SSTABLE_INTER_DC_LIMITER.setRate(calculateEntireSSTableInterDCRateInBytes());
}
private static double calculateRateInBytes()
{
- return DatabaseDescriptor.getStreamThroughputOutboundMegabitsPerSec() > 0
- ? DatabaseDescriptor.getStreamThroughputOutboundMegabitsPerSec() * BYTES_PER_MEGABIT
- : Double.MAX_VALUE; // if throughput is set to 0 or negative value, throttling is disabled
+ int throughput = DatabaseDescriptor.getStreamThroughputOutboundMegabitsPerSec();
+ return calculateEffectiveRateInBytes(throughput);
}
private static double calculateInterDCRateInBytes()
{
- return DatabaseDescriptor.getInterDCStreamThroughputOutboundMegabitsPerSec() > 0
- ? DatabaseDescriptor.getInterDCStreamThroughputOutboundMegabitsPerSec() * BYTES_PER_MEGABIT
- : Double.MAX_VALUE; // if throughput is set to 0 or negative value, throttling is disabled
+ int throughput = DatabaseDescriptor.getInterDCStreamThroughputOutboundMegabitsPerSec();
+ return calculateEffectiveRateInBytes(throughput);
+ }
+
+ private static double calculateEntireSSTableRateInBytes()
+ {
+ int throughput = DatabaseDescriptor.getEntireSSTableStreamThroughputOutboundMegabitsPerSec();
+ return calculateEffectiveRateInBytes(throughput);
+ }
+
+ private static double calculateEntireSSTableInterDCRateInBytes()
+ {
+ int throughput = DatabaseDescriptor.getEntireSSTableInterDCStreamThroughputOutboundMegabitsPerSec();
+ return calculateEffectiveRateInBytes(throughput);
}
@VisibleForTesting
public static double getRateLimiterRateInBytes()
{
- return limiter.getRate();
+ return LIMITER.getRate();
}
@VisibleForTesting
public static double getInterDCRateLimiterRateInBytes()
{
- return interDCLimiter.getRate();
+ return INTER_DC_LIMITER.getRate();
+ }
+
+ @VisibleForTesting
+ public static double getEntireSSTableRateLimiterRateInBytes()
+ {
+ return ENTIRE_SSTABLE_LIMITER.getRate();
+ }
+
+ @VisibleForTesting
+ public static double getEntireSSTableInterDCRateLimiterRateInBytes()
+ {
+ return ENTIRE_SSTABLE_INTER_DC_LIMITER.getRate();
+ }
+
+ private static double calculateEffectiveRateInBytes(int throughput)
+ {
+ // if throughput is set to 0 or negative value, throttling is disabled
+ return throughput > 0
+ ? throughput * BYTES_PER_MEGABIT
+ : Double.MAX_VALUE;
}
}
@@ -157,7 +240,7 @@ public class StreamManager implements StreamManagerMBean
result.addListener(() -> followerStreams.remove(result.planId));
StreamResultFuture previous = followerStreams.putIfAbsent(result.planId, result);
- return previous == null ? result : previous;
+ return previous == null ? result : previous;
}
public StreamResultFuture getReceivingStream(UUID planId)
diff --git a/src/java/org/apache/cassandra/streaming/StreamingDataOutputPlus.java b/src/java/org/apache/cassandra/streaming/StreamingDataOutputPlus.java
index 3f68b3ada5..ab147c6f4f 100644
--- a/src/java/org/apache/cassandra/streaming/StreamingDataOutputPlus.java
+++ b/src/java/org/apache/cassandra/streaming/StreamingDataOutputPlus.java
@@ -58,6 +58,8 @@ public interface StreamingDataOutputPlus extends DataOutputPlus, Closeable
interface RateLimiter
{
void acquire(int bytes);
+
+ boolean isRateLimited();
}
/**
diff --git a/src/java/org/apache/cassandra/tools/LoaderOptions.java b/src/java/org/apache/cassandra/tools/LoaderOptions.java
index 62f5046e1c..5334eabb18 100644
--- a/src/java/org/apache/cassandra/tools/LoaderOptions.java
+++ b/src/java/org/apache/cassandra/tools/LoaderOptions.java
@@ -58,6 +58,8 @@ public class LoaderOptions
public static final String CONFIG_PATH = "conf-path";
public static final String THROTTLE_MBITS = "throttle";
public static final String INTER_DC_THROTTLE_MBITS = "inter-dc-throttle";
+ public static final String ENTIRE_SSTABLE_THROTTLE_MBITS = "entire-sstable-throttle";
+ public static final String ENTIRE_SSTABLE_INTER_DC_THROTTLE_MBITS = "entire-sstable-inter-dc-throttle";
public static final String TOOL_NAME = "sstableloader";
public static final String TARGET_KEYSPACE = "target-keyspace";
@@ -81,6 +83,8 @@ public class LoaderOptions
public final AuthProvider authProvider;
public final int throttle;
public final int interDcThrottle;
+ public final int entireSSTableThrottle;
+ public final int entireSSTableInterDcThrottle;
public final int storagePort;
public final int sslStoragePort;
public final EncryptionOptions clientEncOptions;
@@ -102,6 +106,8 @@ public class LoaderOptions
authProvider = builder.authProvider;
throttle = builder.throttle;
interDcThrottle = builder.interDcThrottle;
+ entireSSTableThrottle = builder.entireSSTableThrottle;
+ entireSSTableInterDcThrottle = builder.entireSSTableInterDcThrottle;
storagePort = builder.storagePort;
sslStoragePort = builder.sslStoragePort;
clientEncOptions = builder.clientEncOptions;
@@ -125,6 +131,8 @@ public class LoaderOptions
AuthProvider authProvider;
int throttle = 0;
int interDcThrottle = 0;
+ int entireSSTableThrottle = 0;
+ int entireSSTableInterDcThrottle = 0;
int storagePort;
int sslStoragePort;
EncryptionOptions clientEncOptions = new EncryptionOptions();
@@ -224,6 +232,18 @@ public class LoaderOptions
return this;
}
+ public Builder entireSSTableThrottle(int entireSSTableThrottle)
+ {
+ this.entireSSTableThrottle = entireSSTableThrottle;
+ return this;
+ }
+
+ public Builder entireSSTableInterDcThrottle(int entireSSTableInterDcThrottle)
+ {
+ this.entireSSTableInterDcThrottle = entireSSTableInterDcThrottle;
+ return this;
+ }
+
public Builder storagePort(int storagePort)
{
this.storagePort = storagePort;
@@ -384,6 +404,8 @@ public class LoaderOptions
// unthrottle stream by default
config.stream_throughput_outbound_megabits_per_sec = 0;
config.inter_dc_stream_throughput_outbound_megabits_per_sec = 0;
+ config.entire_sstable_stream_throughput_outbound_megabits_per_sec = 0;
+ config.entire_sstable_inter_dc_stream_throughput_outbound_megabits_per_sec = 0;
}
@@ -454,6 +476,16 @@ public class LoaderOptions
interDcThrottle = Integer.parseInt(cmd.getOptionValue(INTER_DC_THROTTLE_MBITS));
}
+ if (cmd.hasOption(ENTIRE_SSTABLE_THROTTLE_MBITS))
+ {
+ entireSSTableThrottle = Integer.parseInt(cmd.getOptionValue(ENTIRE_SSTABLE_THROTTLE_MBITS));
+ }
+
+ if (cmd.hasOption(ENTIRE_SSTABLE_INTER_DC_THROTTLE_MBITS))
+ {
+ entireSSTableInterDcThrottle = Integer.parseInt(cmd.getOptionValue(ENTIRE_SSTABLE_INTER_DC_THROTTLE_MBITS));
+ }
+
if (cmd.hasOption(SSL_TRUSTSTORE) || cmd.hasOption(SSL_TRUSTSTORE_PW) ||
cmd.hasOption(SSL_KEYSTORE) || cmd.hasOption(SSL_KEYSTORE_PW))
{
@@ -613,6 +645,8 @@ public class LoaderOptions
options.addOption("ssp", SSL_STORAGE_PORT_OPTION, "ssl storage port", "port used for TLS internode communication (default 7001)");
options.addOption("t", THROTTLE_MBITS, "throttle", "throttle speed in Mbits (default unlimited)");
options.addOption("idct", INTER_DC_THROTTLE_MBITS, "inter-dc-throttle", "inter-datacenter throttle speed in Mbits (default unlimited)");
+ options.addOption("e", ENTIRE_SSTABLE_THROTTLE_MBITS, "entire-sstable-throttle", "entire SSTable throttle speed in Mbits (default unlimited)");
+ options.addOption("eidct", ENTIRE_SSTABLE_INTER_DC_THROTTLE_MBITS, "entire-sstable-inter-dc-throttle", "entire SSTable inter-datacenter throttle speed in Mbits (default unlimited)");
options.addOption("u", USER_OPTION, "username", "username for cassandra authentication");
options.addOption("pw", PASSWD_OPTION, "password", "password for cassandra authentication");
options.addOption("ap", AUTH_PROVIDER_OPTION, "auth provider", "custom AuthProvider class name for cassandra authentication");
diff --git a/src/java/org/apache/cassandra/tools/NodeProbe.java b/src/java/org/apache/cassandra/tools/NodeProbe.java
index 07a5804b61..0371630e03 100644
--- a/src/java/org/apache/cassandra/tools/NodeProbe.java
+++ b/src/java/org/apache/cassandra/tools/NodeProbe.java
@@ -1291,6 +1291,16 @@ public class NodeProbe implements AutoCloseable
return ssProxy.getInterDCStreamThroughputMbPerSec();
}
+ public int getEntireSSTableStreamThroughput()
+ {
+ return ssProxy.getEntireSSTableStreamThroughputMbPerSec();
+ }
+
+ public int getEntireSSTableInterDCStreamThroughput()
+ {
+ return ssProxy.getEntireSSTableInterDCStreamThroughputMbPerSec();
+ }
+
public double getTraceProbability()
{
return ssProxy.getTraceProbability();
@@ -1394,6 +1404,16 @@ public class NodeProbe implements AutoCloseable
ssProxy.setInterDCStreamThroughputMbPerSec(value);
}
+ public void setEntireSSTableStreamThroughput(int value)
+ {
+ ssProxy.setEntireSSTableStreamThroughputMbPerSec(value);
+ }
+
+ public void setEntireSSTableInterDCStreamThroughput(int value)
+ {
+ ssProxy.setEntireSSTableInterDCStreamThroughputMbPerSec(value);
+ }
+
public void setTraceProbability(double value)
{
ssProxy.setTraceProbability(value);
diff --git a/src/java/org/apache/cassandra/tools/NodeTool.java b/src/java/org/apache/cassandra/tools/NodeTool.java
index f3a88386d7..3d62fde705 100644
--- a/src/java/org/apache/cassandra/tools/NodeTool.java
+++ b/src/java/org/apache/cassandra/tools/NodeTool.java
@@ -35,7 +35,6 @@ import java.io.FileNotFoundException;
import java.io.IOError;
import java.io.IOException;
import java.net.UnknownHostException;
-import java.nio.file.NoSuchFileException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
@@ -340,7 +339,7 @@ public class NodeTool
@Option(type = OptionType.GLOBAL, name = {"-pwf", "--password-file"}, description = "Path to the JMX password file")
private String passwordFilePath = EMPTY;
- @Option(type = OptionType.GLOBAL, name = { "-pp", "--print-port"}, description = "Operate in 4.0 mode with hosts disambiguated by port number", arity = 0)
+ @Option(type = OptionType.GLOBAL, name = { "-pp", "--print-port"}, description = "Operate in 4.0 mode with hosts disambiguated by port number", arity = 0)
protected boolean printPort = false;
private INodeProbeFactory nodeProbeFactory;
diff --git a/src/java/org/apache/cassandra/tools/nodetool/GetInterDCStreamThroughput.java b/src/java/org/apache/cassandra/tools/nodetool/GetInterDCStreamThroughput.java
index 554876de49..25abb3fda6 100644
--- a/src/java/org/apache/cassandra/tools/nodetool/GetInterDCStreamThroughput.java
+++ b/src/java/org/apache/cassandra/tools/nodetool/GetInterDCStreamThroughput.java
@@ -18,16 +18,24 @@
package org.apache.cassandra.tools.nodetool;
import io.airlift.airline.Command;
-
+import io.airlift.airline.Option;
import org.apache.cassandra.tools.NodeProbe;
import org.apache.cassandra.tools.NodeTool.NodeToolCmd;
-@Command(name = "getinterdcstreamthroughput", description = "Print the Mb/s throughput cap for inter-datacenter streaming in the system")
+@Command(name = "getinterdcstreamthroughput", description = "Print the Mb/s throughput cap for inter-datacenter streaming and entire SSTable inter-datacenter streaming in the system")
public class GetInterDCStreamThroughput extends NodeToolCmd
{
+ @SuppressWarnings("UnusedDeclaration")
+ @Option(name = { "-e", "--entire-sstable-throughput" }, description = "Print entire SSTable streaming throughput")
+ private boolean entireSSTableThroughput;
+
@Override
public void execute(NodeProbe probe)
{
- probe.output().out.println("Current inter-datacenter stream throughput: " + probe.getInterDCStreamThroughput() + " Mb/s");
+ int throughput = entireSSTableThroughput ? probe.getEntireSSTableInterDCStreamThroughput() : probe.getInterDCStreamThroughput();
+
+ probe.output().out.printf("Current %sinter-datacenter stream throughput: %s%n",
+ entireSSTableThroughput ? "entire SSTable " : "",
+ throughput > 0 ? throughput + " Mb/s" : "unlimited");
}
}
diff --git a/src/java/org/apache/cassandra/tools/nodetool/GetStreamThroughput.java b/src/java/org/apache/cassandra/tools/nodetool/GetStreamThroughput.java
index 9014d3cf54..4c849a92ce 100644
--- a/src/java/org/apache/cassandra/tools/nodetool/GetStreamThroughput.java
+++ b/src/java/org/apache/cassandra/tools/nodetool/GetStreamThroughput.java
@@ -18,16 +18,24 @@
package org.apache.cassandra.tools.nodetool;
import io.airlift.airline.Command;
-
+import io.airlift.airline.Option;
import org.apache.cassandra.tools.NodeProbe;
import org.apache.cassandra.tools.NodeTool.NodeToolCmd;
-@Command(name = "getstreamthroughput", description = "Print the Mb/s throughput cap for streaming in the system")
+@Command(name = "getstreamthroughput", description = "Print the Mb/s throughput cap for streaming and entire SSTable streaming in the system")
public class GetStreamThroughput extends NodeToolCmd
{
+ @SuppressWarnings("UnusedDeclaration")
+ @Option(name = { "-e", "--entire-sstable-throughput" }, description = "Print entire SSTable streaming throughput")
+ private boolean entireSSTableThroughput;
+
@Override
public void execute(NodeProbe probe)
{
- probe.output().out.println("Current stream throughput: " + probe.getStreamThroughput() + " Mb/s");
+ int throughput = entireSSTableThroughput ? probe.getEntireSSTableStreamThroughput() : probe.getStreamThroughput();
+
+ probe.output().out.printf("Current %sstream throughput: %s%n",
+ entireSSTableThroughput ? "entire SSTable " : "",
+ throughput > 0 ? throughput + " Mb/s" : "unlimited");
}
}
diff --git a/src/java/org/apache/cassandra/tools/nodetool/SetInterDCStreamThroughput.java b/src/java/org/apache/cassandra/tools/nodetool/SetInterDCStreamThroughput.java
index 1397573e38..f454c1b4c7 100644
--- a/src/java/org/apache/cassandra/tools/nodetool/SetInterDCStreamThroughput.java
+++ b/src/java/org/apache/cassandra/tools/nodetool/SetInterDCStreamThroughput.java
@@ -19,20 +19,27 @@ package org.apache.cassandra.tools.nodetool;
import io.airlift.airline.Arguments;
import io.airlift.airline.Command;
-
+import io.airlift.airline.Option;
import org.apache.cassandra.tools.NodeProbe;
import org.apache.cassandra.tools.NodeTool.NodeToolCmd;
-@Command(name = "setinterdcstreamthroughput", description = "Set the Mb/s throughput cap for inter-datacenter streaming in the system, or 0 to disable throttling")
+@Command(name = "setinterdcstreamthroughput", description = "Set the Mb/s throughput cap for inter-datacenter streaming and entire SSTable inter-datacenter streaming in the system, or 0 to disable throttling")
public class SetInterDCStreamThroughput extends NodeToolCmd
{
@SuppressWarnings("UnusedDeclaration")
@Arguments(title = "inter_dc_stream_throughput", usage = "