mirror of https://github.com/apache/cassandra
Merge branch 'cassandra-3.0' into cassandra-3.X
This commit is contained in:
commit
2e18adf257
|
|
@ -70,6 +70,7 @@
|
||||||
* Remove compaction Severity from DynamicEndpointSnitch (CASSANDRA-11738)
|
* Remove compaction Severity from DynamicEndpointSnitch (CASSANDRA-11738)
|
||||||
* Restore resumable hints delivery (CASSANDRA-11960)
|
* Restore resumable hints delivery (CASSANDRA-11960)
|
||||||
Merged from 3.0:
|
Merged from 3.0:
|
||||||
|
* Unify drain and shutdown processes (CASSANDRA-12509)
|
||||||
* Fix NPE in ComponentOfSlice.isEQ() (CASSANDRA-12706)
|
* Fix NPE in ComponentOfSlice.isEQ() (CASSANDRA-12706)
|
||||||
* Fix failure in LogTransactionTest (CASSANDRA-12632)
|
* Fix failure in LogTransactionTest (CASSANDRA-12632)
|
||||||
* Fix potentially incomplete non-frozen UDT values when querying with the
|
* Fix potentially incomplete non-frozen UDT values when querying with the
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,8 @@ appender reference in the root level section below.
|
||||||
|
|
||||||
<configuration scan="true">
|
<configuration scan="true">
|
||||||
<jmxConfigurator />
|
<jmxConfigurator />
|
||||||
<shutdownHook class="ch.qos.logback.core.hook.DelayingShutdownHook"/>
|
|
||||||
|
<!-- No shutdown hook; we run it ourselves in StorageService after shutdown -->
|
||||||
|
|
||||||
<!-- SYSTEMLOG rolling file appender to system.log (INFO level) -->
|
<!-- SYSTEMLOG rolling file appender to system.log (INFO level) -->
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ public class DebuggableScheduledThreadPoolExecutor extends ScheduledThreadPoolEx
|
||||||
{
|
{
|
||||||
if (executor.isShutdown())
|
if (executor.isShutdown())
|
||||||
{
|
{
|
||||||
if (!StorageService.instance.isInShutdownHook())
|
if (!StorageService.instance.isShutdown())
|
||||||
throw new RejectedExecutionException("ScheduledThreadPoolExecutor has shut down.");
|
throw new RejectedExecutionException("ScheduledThreadPoolExecutor has shut down.");
|
||||||
|
|
||||||
//Give some notification to the caller the task isn't going to run
|
//Give some notification to the caller the task isn't going to run
|
||||||
|
|
|
||||||
|
|
@ -2411,7 +2411,13 @@ public class StorageProxy implements StorageProxyMBean
|
||||||
|
|
||||||
public void setHintedHandoffEnabled(boolean b)
|
public void setHintedHandoffEnabled(boolean b)
|
||||||
{
|
{
|
||||||
DatabaseDescriptor.setHintedHandoffEnabled(b);
|
synchronized (StorageService.instance)
|
||||||
|
{
|
||||||
|
if (b)
|
||||||
|
StorageService.instance.checkServiceAllowedToStart("hinted handoff");
|
||||||
|
|
||||||
|
DatabaseDescriptor.setHintedHandoffEnabled(b);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void enableHintsForDC(String dc)
|
public void enableHintsForDC(String dc)
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,7 @@ import ch.qos.logback.classic.LoggerContext;
|
||||||
import ch.qos.logback.classic.jmx.JMXConfiguratorMBean;
|
import ch.qos.logback.classic.jmx.JMXConfiguratorMBean;
|
||||||
import ch.qos.logback.classic.spi.ILoggingEvent;
|
import ch.qos.logback.classic.spi.ILoggingEvent;
|
||||||
import ch.qos.logback.core.Appender;
|
import ch.qos.logback.core.Appender;
|
||||||
|
import ch.qos.logback.core.hook.DelayingShutdownHook;
|
||||||
import org.apache.cassandra.auth.AuthKeyspace;
|
import org.apache.cassandra.auth.AuthKeyspace;
|
||||||
import org.apache.cassandra.auth.AuthMigrationListener;
|
import org.apache.cassandra.auth.AuthMigrationListener;
|
||||||
import org.apache.cassandra.batchlog.BatchRemoveVerbHandler;
|
import org.apache.cassandra.batchlog.BatchRemoveVerbHandler;
|
||||||
|
|
@ -140,13 +141,19 @@ public class StorageService extends NotificationBroadcasterSupport implements IE
|
||||||
public volatile VersionedValue.VersionedValueFactory valueFactory = new VersionedValue.VersionedValueFactory(tokenMetadata.partitioner);
|
public volatile VersionedValue.VersionedValueFactory valueFactory = new VersionedValue.VersionedValueFactory(tokenMetadata.partitioner);
|
||||||
|
|
||||||
private Thread drainOnShutdown = null;
|
private Thread drainOnShutdown = null;
|
||||||
private volatile boolean inShutdownHook = false;
|
private volatile boolean isShutdown = false;
|
||||||
|
|
||||||
public static final StorageService instance = new StorageService();
|
public static final StorageService instance = new StorageService();
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public boolean isInShutdownHook()
|
public boolean isInShutdownHook()
|
||||||
{
|
{
|
||||||
return inShutdownHook;
|
return isShutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isShutdown()
|
||||||
|
{
|
||||||
|
return isShutdown;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Collection<Range<Token>> getLocalRanges(String keyspaceName)
|
public Collection<Range<Token>> getLocalRanges(String keyspaceName)
|
||||||
|
|
@ -187,7 +194,7 @@ public class StorageService extends NotificationBroadcasterSupport implements IE
|
||||||
private double traceProbability = 0.0;
|
private double traceProbability = 0.0;
|
||||||
|
|
||||||
private static enum Mode { STARTING, NORMAL, JOINING, LEAVING, DECOMMISSIONED, MOVING, DRAINING, DRAINED }
|
private static enum Mode { STARTING, NORMAL, JOINING, LEAVING, DECOMMISSIONED, MOVING, DRAINING, DRAINED }
|
||||||
private Mode operationMode = Mode.STARTING;
|
private volatile Mode operationMode = Mode.STARTING;
|
||||||
|
|
||||||
/* Used for tracking drain progress */
|
/* Used for tracking drain progress */
|
||||||
private volatile int totalCFs, remainingCFs;
|
private volatile int totalCFs, remainingCFs;
|
||||||
|
|
@ -309,10 +316,12 @@ public class StorageService extends NotificationBroadcasterSupport implements IE
|
||||||
}
|
}
|
||||||
|
|
||||||
// should only be called via JMX
|
// should only be called via JMX
|
||||||
public void startGossiping()
|
public synchronized void startGossiping()
|
||||||
{
|
{
|
||||||
if (!gossipActive)
|
if (!gossipActive)
|
||||||
{
|
{
|
||||||
|
checkServiceAllowedToStart("gossip");
|
||||||
|
|
||||||
logger.warn("Starting gossip by operator request");
|
logger.warn("Starting gossip by operator request");
|
||||||
Collection<Token> tokens = SystemKeyspace.getSavedTokens();
|
Collection<Token> tokens = SystemKeyspace.getSavedTokens();
|
||||||
|
|
||||||
|
|
@ -338,8 +347,10 @@ public class StorageService extends NotificationBroadcasterSupport implements IE
|
||||||
}
|
}
|
||||||
|
|
||||||
// should only be called via JMX
|
// should only be called via JMX
|
||||||
public void startRPCServer()
|
public synchronized void startRPCServer()
|
||||||
{
|
{
|
||||||
|
checkServiceAllowedToStart("thrift");
|
||||||
|
|
||||||
if (daemon == null)
|
if (daemon == null)
|
||||||
{
|
{
|
||||||
throw new IllegalStateException("No configured daemon");
|
throw new IllegalStateException("No configured daemon");
|
||||||
|
|
@ -366,8 +377,10 @@ public class StorageService extends NotificationBroadcasterSupport implements IE
|
||||||
return daemon.thriftServer.isRunning();
|
return daemon.thriftServer.isRunning();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void startNativeTransport()
|
public synchronized void startNativeTransport()
|
||||||
{
|
{
|
||||||
|
checkServiceAllowedToStart("native transport");
|
||||||
|
|
||||||
if (daemon == null)
|
if (daemon == null)
|
||||||
{
|
{
|
||||||
throw new IllegalStateException("No configured daemon");
|
throw new IllegalStateException("No configured daemon");
|
||||||
|
|
@ -605,65 +618,17 @@ public class StorageService extends NotificationBroadcasterSupport implements IE
|
||||||
drainOnShutdown = new Thread(new WrappedRunnable()
|
drainOnShutdown = new Thread(new WrappedRunnable()
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
public void runMayThrow() throws InterruptedException, ExecutionException
|
public void runMayThrow() throws InterruptedException, ExecutionException, IOException
|
||||||
{
|
{
|
||||||
inShutdownHook = true;
|
drain(true);
|
||||||
ExecutorService viewMutationStage = StageManager.getStage(Stage.VIEW_MUTATION);
|
|
||||||
ExecutorService counterMutationStage = StageManager.getStage(Stage.COUNTER_MUTATION);
|
|
||||||
ExecutorService mutationStage = StageManager.getStage(Stage.MUTATION);
|
|
||||||
if (mutationStage.isShutdown()
|
|
||||||
&& counterMutationStage.isShutdown()
|
|
||||||
&& viewMutationStage.isShutdown())
|
|
||||||
return; // drained already
|
|
||||||
|
|
||||||
if (daemon != null)
|
|
||||||
shutdownClientServers();
|
|
||||||
ScheduledExecutors.optionalTasks.shutdown();
|
|
||||||
Gossiper.instance.stop();
|
|
||||||
|
|
||||||
// In-progress writes originating here could generate hints to be written, so shut down MessagingService
|
|
||||||
// before mutation stage, so we can get all the hints saved before shutting down
|
|
||||||
MessagingService.instance().shutdown();
|
|
||||||
viewMutationStage.shutdown();
|
|
||||||
BatchlogManager.instance.shutdown();
|
|
||||||
HintsService.instance.pauseDispatch();
|
|
||||||
counterMutationStage.shutdown();
|
|
||||||
mutationStage.shutdown();
|
|
||||||
viewMutationStage.awaitTermination(3600, TimeUnit.SECONDS);
|
|
||||||
counterMutationStage.awaitTermination(3600, TimeUnit.SECONDS);
|
|
||||||
mutationStage.awaitTermination(3600, TimeUnit.SECONDS);
|
|
||||||
StorageProxy.instance.verifyNoHintsInProgress();
|
|
||||||
|
|
||||||
List<Future<?>> flushes = new ArrayList<>();
|
|
||||||
for (Keyspace keyspace : Keyspace.all())
|
|
||||||
{
|
|
||||||
KeyspaceMetadata ksm = Schema.instance.getKSMetaData(keyspace.getName());
|
|
||||||
if (!ksm.params.durableWrites)
|
|
||||||
for (ColumnFamilyStore cfs : keyspace.getColumnFamilyStores())
|
|
||||||
flushes.add(cfs.forceFlush());
|
|
||||||
}
|
|
||||||
try
|
|
||||||
{
|
|
||||||
FBUtilities.waitOnFutures(flushes);
|
|
||||||
}
|
|
||||||
catch (Throwable t)
|
|
||||||
{
|
|
||||||
JVMStabilityInspector.inspectThrowable(t);
|
|
||||||
// don't let this stop us from shutting down the commitlog and other thread pools
|
|
||||||
logger.warn("Caught exception while waiting for memtable flushes during shutdown hook", t);
|
|
||||||
}
|
|
||||||
|
|
||||||
CommitLog.instance.shutdownBlocking();
|
|
||||||
|
|
||||||
if (FBUtilities.isWindows)
|
if (FBUtilities.isWindows)
|
||||||
WindowsTimer.endTimerPeriod(DatabaseDescriptor.getWindowsTimerInterval());
|
WindowsTimer.endTimerPeriod(DatabaseDescriptor.getWindowsTimerInterval());
|
||||||
|
|
||||||
HintsService.instance.shutdownBlocking();
|
// Cleanup logback
|
||||||
|
DelayingShutdownHook logbackHook = new DelayingShutdownHook();
|
||||||
// wait for miscellaneous tasks like sstable and commitlog segment deletion
|
logbackHook.setContext((LoggerContext)LoggerFactory.getILoggerFactory());
|
||||||
ScheduledExecutors.nonPeriodicTasks.shutdown();
|
logbackHook.run();
|
||||||
if (!ScheduledExecutors.nonPeriodicTasks.awaitTermination(1, TimeUnit.MINUTES))
|
|
||||||
logger.warn("Miscellaneous task executor still busy after one minute; proceeding with shutdown");
|
|
||||||
}
|
}
|
||||||
}, "StorageServiceShutdownHook");
|
}, "StorageServiceShutdownHook");
|
||||||
Runtime.getRuntime().addShutdownHook(drainOnShutdown);
|
Runtime.getRuntime().addShutdownHook(drainOnShutdown);
|
||||||
|
|
@ -1168,7 +1133,7 @@ public class StorageService extends NotificationBroadcasterSupport implements IE
|
||||||
|
|
||||||
public void rebuild(String sourceDc, String keyspace, String tokens, String specificSources)
|
public void rebuild(String sourceDc, String keyspace, String tokens, String specificSources)
|
||||||
{
|
{
|
||||||
// check on going rebuild
|
// check ongoing rebuild
|
||||||
if (!isRebuilding.compareAndSet(false, true))
|
if (!isRebuilding.compareAndSet(false, true))
|
||||||
{
|
{
|
||||||
throw new IllegalStateException("Node is still rebuilding. Check nodetool netstats.");
|
throw new IllegalStateException("Node is still rebuilding. Check nodetool netstats.");
|
||||||
|
|
@ -4373,6 +4338,16 @@ public class StorageService extends NotificationBroadcasterSupport implements IE
|
||||||
return operationMode == Mode.JOINING;
|
return operationMode == Mode.JOINING;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isDrained()
|
||||||
|
{
|
||||||
|
return operationMode == Mode.DRAINED;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isDraining()
|
||||||
|
{
|
||||||
|
return operationMode == Mode.DRAINING;
|
||||||
|
}
|
||||||
|
|
||||||
public String getDrainProgress()
|
public String getDrainProgress()
|
||||||
{
|
{
|
||||||
return String.format("Drained %s/%s ColumnFamilies", remainingCFs, totalCFs);
|
return String.format("Drained %s/%s ColumnFamilies", remainingCFs, totalCFs);
|
||||||
|
|
@ -4380,102 +4355,146 @@ public class StorageService extends NotificationBroadcasterSupport implements IE
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shuts node off to writes, empties memtables and the commit log.
|
* Shuts node off to writes, empties memtables and the commit log.
|
||||||
* There are two differences between drain and the normal shutdown hook:
|
|
||||||
* - Drain waits for in-progress streaming to complete
|
|
||||||
* - Drain flushes *all* columnfamilies (shutdown hook only flushes non-durable CFs)
|
|
||||||
*/
|
*/
|
||||||
public synchronized void drain() throws IOException, InterruptedException, ExecutionException
|
public synchronized void drain() throws IOException, InterruptedException, ExecutionException
|
||||||
{
|
{
|
||||||
inShutdownHook = true;
|
drain(false);
|
||||||
|
}
|
||||||
BatchlogManager.instance.shutdown();
|
|
||||||
|
|
||||||
HintsService.instance.pauseDispatch();
|
|
||||||
|
|
||||||
|
protected synchronized void drain(boolean isFinalShutdown) throws IOException, InterruptedException, ExecutionException
|
||||||
|
{
|
||||||
ExecutorService counterMutationStage = StageManager.getStage(Stage.COUNTER_MUTATION);
|
ExecutorService counterMutationStage = StageManager.getStage(Stage.COUNTER_MUTATION);
|
||||||
ExecutorService viewMutationStage = StageManager.getStage(Stage.VIEW_MUTATION);
|
ExecutorService viewMutationStage = StageManager.getStage(Stage.VIEW_MUTATION);
|
||||||
ExecutorService mutationStage = StageManager.getStage(Stage.MUTATION);
|
ExecutorService mutationStage = StageManager.getStage(Stage.MUTATION);
|
||||||
|
|
||||||
if (mutationStage.isTerminated()
|
if (mutationStage.isTerminated()
|
||||||
&& counterMutationStage.isTerminated()
|
&& counterMutationStage.isTerminated()
|
||||||
&& viewMutationStage.isTerminated())
|
&& viewMutationStage.isTerminated())
|
||||||
{
|
{
|
||||||
logger.warn("Cannot drain node (did it already happen?)");
|
if (!isFinalShutdown)
|
||||||
|
logger.warn("Cannot drain node (did it already happen?)");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setMode(Mode.DRAINING, "starting drain process", true);
|
|
||||||
shutdownClientServers();
|
|
||||||
ScheduledExecutors.optionalTasks.shutdown();
|
|
||||||
Gossiper.instance.stop();
|
|
||||||
|
|
||||||
setMode(Mode.DRAINING, "shutting down MessageService", false);
|
assert !isShutdown;
|
||||||
MessagingService.instance().shutdown();
|
isShutdown = true;
|
||||||
|
|
||||||
setMode(Mode.DRAINING, "clearing mutation stage", false);
|
try
|
||||||
viewMutationStage.shutdown();
|
|
||||||
counterMutationStage.shutdown();
|
|
||||||
mutationStage.shutdown();
|
|
||||||
viewMutationStage.awaitTermination(3600, TimeUnit.SECONDS);
|
|
||||||
counterMutationStage.awaitTermination(3600, TimeUnit.SECONDS);
|
|
||||||
mutationStage.awaitTermination(3600, TimeUnit.SECONDS);
|
|
||||||
|
|
||||||
StorageProxy.instance.verifyNoHintsInProgress();
|
|
||||||
|
|
||||||
setMode(Mode.DRAINING, "flushing column families", false);
|
|
||||||
|
|
||||||
// disable autocompaction - we don't want to start any new compactions while we are draining
|
|
||||||
for (Keyspace keyspace : Keyspace.all())
|
|
||||||
for (ColumnFamilyStore cfs : keyspace.getColumnFamilyStores())
|
|
||||||
cfs.disableAutoCompaction();
|
|
||||||
|
|
||||||
// count CFs first, since forceFlush could block for the flushWriter to get a queue slot empty
|
|
||||||
totalCFs = 0;
|
|
||||||
for (Keyspace keyspace : Keyspace.nonSystem())
|
|
||||||
totalCFs += keyspace.getColumnFamilyStores().size();
|
|
||||||
remainingCFs = totalCFs;
|
|
||||||
// flush
|
|
||||||
List<Future<?>> flushes = new ArrayList<>();
|
|
||||||
for (Keyspace keyspace : Keyspace.nonSystem())
|
|
||||||
{
|
{
|
||||||
for (ColumnFamilyStore cfs : keyspace.getColumnFamilyStores())
|
setMode(Mode.DRAINING, "starting drain process", !isFinalShutdown);
|
||||||
flushes.add(cfs.forceFlush());
|
|
||||||
|
BatchlogManager.instance.shutdown();
|
||||||
|
HintsService.instance.pauseDispatch();
|
||||||
|
|
||||||
|
if (daemon != null)
|
||||||
|
shutdownClientServers();
|
||||||
|
ScheduledExecutors.optionalTasks.shutdown();
|
||||||
|
Gossiper.instance.stop();
|
||||||
|
|
||||||
|
if (!isFinalShutdown)
|
||||||
|
setMode(Mode.DRAINING, "shutting down MessageService", false);
|
||||||
|
|
||||||
|
// In-progress writes originating here could generate hints to be written, so shut down MessagingService
|
||||||
|
// before mutation stage, so we can get all the hints saved before shutting down
|
||||||
|
MessagingService.instance().shutdown();
|
||||||
|
|
||||||
|
if (!isFinalShutdown)
|
||||||
|
setMode(Mode.DRAINING, "clearing mutation stage", false);
|
||||||
|
viewMutationStage.shutdown();
|
||||||
|
counterMutationStage.shutdown();
|
||||||
|
mutationStage.shutdown();
|
||||||
|
viewMutationStage.awaitTermination(3600, TimeUnit.SECONDS);
|
||||||
|
counterMutationStage.awaitTermination(3600, TimeUnit.SECONDS);
|
||||||
|
mutationStage.awaitTermination(3600, TimeUnit.SECONDS);
|
||||||
|
|
||||||
|
StorageProxy.instance.verifyNoHintsInProgress();
|
||||||
|
|
||||||
|
if (!isFinalShutdown)
|
||||||
|
setMode(Mode.DRAINING, "flushing column families", false);
|
||||||
|
|
||||||
|
// disable autocompaction - we don't want to start any new compactions while we are draining
|
||||||
|
for (Keyspace keyspace : Keyspace.all())
|
||||||
|
for (ColumnFamilyStore cfs : keyspace.getColumnFamilyStores())
|
||||||
|
cfs.disableAutoCompaction();
|
||||||
|
|
||||||
|
// count CFs first, since forceFlush could block for the flushWriter to get a queue slot empty
|
||||||
|
totalCFs = 0;
|
||||||
|
for (Keyspace keyspace : Keyspace.nonSystem())
|
||||||
|
totalCFs += keyspace.getColumnFamilyStores().size();
|
||||||
|
remainingCFs = totalCFs;
|
||||||
|
// flush
|
||||||
|
List<Future<?>> flushes = new ArrayList<>();
|
||||||
|
for (Keyspace keyspace : Keyspace.nonSystem())
|
||||||
|
{
|
||||||
|
for (ColumnFamilyStore cfs : keyspace.getColumnFamilyStores())
|
||||||
|
flushes.add(cfs.forceFlush());
|
||||||
|
}
|
||||||
|
// wait for the flushes.
|
||||||
|
// TODO this is a godawful way to track progress, since they flush in parallel. a long one could
|
||||||
|
// thus make several short ones "instant" if we wait for them later.
|
||||||
|
for (Future f : flushes)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
FBUtilities.waitOnFuture(f);
|
||||||
|
}
|
||||||
|
catch (Throwable t)
|
||||||
|
{
|
||||||
|
JVMStabilityInspector.inspectThrowable(t);
|
||||||
|
// don't let this stop us from shutting down the commitlog and other thread pools
|
||||||
|
logger.warn("Caught exception while waiting for memtable flushes during shutdown hook", t);
|
||||||
|
}
|
||||||
|
|
||||||
|
remainingCFs--;
|
||||||
|
}
|
||||||
|
// flush the system ones after all the rest are done, just in case flushing modifies any system state
|
||||||
|
// like CASSANDRA-5151. don't bother with progress tracking since system data is tiny.
|
||||||
|
flushes.clear();
|
||||||
|
for (Keyspace keyspace : Keyspace.system())
|
||||||
|
{
|
||||||
|
for (ColumnFamilyStore cfs : keyspace.getColumnFamilyStores())
|
||||||
|
flushes.add(cfs.forceFlush());
|
||||||
|
}
|
||||||
|
FBUtilities.waitOnFutures(flushes);
|
||||||
|
|
||||||
|
HintsService.instance.shutdownBlocking();
|
||||||
|
|
||||||
|
// Interrupt ongoing compactions and shutdown CM to prevent further compactions.
|
||||||
|
CompactionManager.instance.forceShutdown();
|
||||||
|
|
||||||
|
// whilst we've flushed all the CFs, which will have recycled all completed segments, we want to ensure
|
||||||
|
// there are no segments to replay, so we force the recycling of any remaining (should be at most one)
|
||||||
|
CommitLog.instance.forceRecycleAllSegments();
|
||||||
|
|
||||||
|
CommitLog.instance.shutdownBlocking();
|
||||||
|
|
||||||
|
// wait for miscellaneous tasks like sstable and commitlog segment deletion
|
||||||
|
ScheduledExecutors.nonPeriodicTasks.shutdown();
|
||||||
|
if (!ScheduledExecutors.nonPeriodicTasks.awaitTermination(1, TimeUnit.MINUTES))
|
||||||
|
logger.warn("Miscellaneous task executor still busy after one minute; proceeding with shutdown");
|
||||||
|
|
||||||
|
ColumnFamilyStore.shutdownPostFlushExecutor();
|
||||||
|
setMode(Mode.DRAINED, !isFinalShutdown);
|
||||||
}
|
}
|
||||||
// wait for the flushes.
|
catch (Throwable t)
|
||||||
// TODO this is a godawful way to track progress, since they flush in parallel. a long one could
|
|
||||||
// thus make several short ones "instant" if we wait for them later.
|
|
||||||
for (Future f : flushes)
|
|
||||||
{
|
{
|
||||||
FBUtilities.waitOnFuture(f);
|
logger.error("Caught an exception while draining ", t);
|
||||||
remainingCFs--;
|
|
||||||
}
|
}
|
||||||
// flush the system ones after all the rest are done, just in case flushing modifies any system state
|
}
|
||||||
// like CASSANDRA-5151. don't bother with progress tracking since system data is tiny.
|
|
||||||
flushes.clear();
|
|
||||||
for (Keyspace keyspace : Keyspace.system())
|
|
||||||
{
|
|
||||||
for (ColumnFamilyStore cfs : keyspace.getColumnFamilyStores())
|
|
||||||
flushes.add(cfs.forceFlush());
|
|
||||||
}
|
|
||||||
FBUtilities.waitOnFutures(flushes);
|
|
||||||
|
|
||||||
HintsService.instance.shutdownBlocking();
|
/**
|
||||||
|
* Some services are shutdown during draining and we should not attempt to start them again.
|
||||||
|
*
|
||||||
|
* @param service - the name of the service we are trying to start.
|
||||||
|
* @throws IllegalStateException - an exception that nodetool is able to convert into a message to display to the user
|
||||||
|
*/
|
||||||
|
synchronized void checkServiceAllowedToStart(String service)
|
||||||
|
{
|
||||||
|
if (isDraining()) // when draining isShutdown is also true, so we check first to return a more accurate message
|
||||||
|
throw new IllegalStateException(String.format("Unable to start %s because the node is draining.", service));
|
||||||
|
|
||||||
// Interrupt on going compaction and shutdown to prevent further compaction
|
if (isShutdown()) // do not rely on operationMode in case it gets changed to decomissioned or other
|
||||||
CompactionManager.instance.forceShutdown();
|
throw new IllegalStateException(String.format("Unable to start %s because the node was drained.", service));
|
||||||
|
|
||||||
// whilst we've flushed all the CFs, which will have recycled all completed segments, we want to ensure
|
|
||||||
// there are no segments to replay, so we force the recycling of any remaining (should be at most one)
|
|
||||||
CommitLog.instance.forceRecycleAllSegments();
|
|
||||||
|
|
||||||
CommitLog.instance.shutdownBlocking();
|
|
||||||
|
|
||||||
// wait for miscellaneous tasks like sstable and commitlog segment deletion
|
|
||||||
ScheduledExecutors.nonPeriodicTasks.shutdown();
|
|
||||||
if (!ScheduledExecutors.nonPeriodicTasks.awaitTermination(1, TimeUnit.MINUTES))
|
|
||||||
logger.warn("Miscellaneous task executor still busy after one minute; proceeding with shutdown");
|
|
||||||
|
|
||||||
ColumnFamilyStore.shutdownPostFlushExecutor();
|
|
||||||
|
|
||||||
setMode(Mode.DRAINED, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Never ever do this at home. Used by tests.
|
// Never ever do this at home. Used by tests.
|
||||||
|
|
@ -4966,8 +4985,10 @@ public class StorageService extends NotificationBroadcasterSupport implements IE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void enableAutoCompaction(String ks, String... tables) throws IOException
|
public synchronized void enableAutoCompaction(String ks, String... tables) throws IOException
|
||||||
{
|
{
|
||||||
|
checkServiceAllowedToStart("auto compaction");
|
||||||
|
|
||||||
for (ColumnFamilyStore cfs : getValidColumnFamilies(true, true, ks, tables))
|
for (ColumnFamilyStore cfs : getValidColumnFamilies(true, true, ks, tables))
|
||||||
{
|
{
|
||||||
cfs.enableAutoCompaction();
|
cfs.enableAutoCompaction();
|
||||||
|
|
|
||||||
|
|
@ -526,6 +526,8 @@ public interface StorageServiceMBean extends NotificationEmitter
|
||||||
// allows a node that have been started without joining the ring to join it
|
// allows a node that have been started without joining the ring to join it
|
||||||
public void joinRing() throws IOException;
|
public void joinRing() throws IOException;
|
||||||
public boolean isJoined();
|
public boolean isJoined();
|
||||||
|
public boolean isDrained();
|
||||||
|
public boolean isDraining();
|
||||||
|
|
||||||
public void setRpcTimeout(long value);
|
public void setRpcTimeout(long value);
|
||||||
public long getRpcTimeout();
|
public long getRpcTimeout();
|
||||||
|
|
|
||||||
|
|
@ -616,6 +616,16 @@ public class NodeProbe implements AutoCloseable
|
||||||
return ssProxy.isJoined();
|
return ssProxy.isJoined();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isDrained()
|
||||||
|
{
|
||||||
|
return ssProxy.isDrained();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isDraining()
|
||||||
|
{
|
||||||
|
return ssProxy.isDraining();
|
||||||
|
}
|
||||||
|
|
||||||
public void joinRing() throws IOException
|
public void joinRing() throws IOException
|
||||||
{
|
{
|
||||||
ssProxy.joinRing();
|
ssProxy.joinRing();
|
||||||
|
|
|
||||||
|
|
@ -2331,7 +2331,7 @@ public class UFTest extends CQLTester
|
||||||
'}'},
|
'}'},
|
||||||
{"org.apache.cassandra.service.StorageService",
|
{"org.apache.cassandra.service.StorageService",
|
||||||
"try {" +
|
"try {" +
|
||||||
" org.apache.cassandra.service.StorageService v = org.apache.cassandra.service.StorageService.instance; v.isInShutdownHook(); return 0d;" +
|
" org.apache.cassandra.service.StorageService v = org.apache.cassandra.service.StorageService.instance; v.isShutdown(); return 0d;" +
|
||||||
"} catch (Exception t) {" +
|
"} catch (Exception t) {" +
|
||||||
" throw new RuntimeException(t);" +
|
" throw new RuntimeException(t);" +
|
||||||
'}'},
|
'}'},
|
||||||
|
|
@ -2371,7 +2371,7 @@ public class UFTest extends CQLTester
|
||||||
"RETURNS NULL ON NULL INPUT " +
|
"RETURNS NULL ON NULL INPUT " +
|
||||||
"RETURNS double " +
|
"RETURNS double " +
|
||||||
"LANGUAGE javascript\n" +
|
"LANGUAGE javascript\n" +
|
||||||
"AS 'org.apache.cassandra.service.StorageService.instance.isInShutdownHook(); 0;';");
|
"AS 'org.apache.cassandra.service.StorageService.instance.isShutdown(); 0;';");
|
||||||
execute("SELECT " + fName + "(dval) FROM %s WHERE key=1");
|
execute("SELECT " + fName + "(dval) FROM %s WHERE key=1");
|
||||||
Assert.fail("Javascript security check failed");
|
Assert.fail("Javascript security check failed");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue