[ 
https://issues.apache.org/jira/browse/CASSANDRA-21855?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Jon Meredith updated CASSANDRA-21855:
-------------------------------------
     Bug Category: Parent values: Degradation(12984)
       Complexity: Normal
    Discovered By: User Report
    Fix Version/s: 6.0
                   7.x
         Severity: Normal
           Status: Open  (was: Triage Needed)

> CMS node with the lowest NodeId can deadlock on nonPeriodicTasks when it 
> replays a delayed log that triggers a snapshot and then drops a table
> ----------------------------------------------------------------------------------------------------------------------------------------------
>
>                 Key: CASSANDRA-21855
>                 URL: https://issues.apache.org/jira/browse/CASSANDRA-21855
>             Project: Apache Cassandra
>          Issue Type: Bug
>          Components: Transactional Cluster Metadata
>            Reporter: Jon Meredith
>            Assignee: Jon Meredith
>            Priority: Normal
>             Fix For: 6.0, 7.x
>
>
> The CMS member with the lowest {{NodeId}} can stop processing the TCM log 
> until restarted. It happens when the node is behind, enacts an epoch that 
> triggers a metadata snapshot, and then enacts a table drop. The snapshot task 
> and the drop wait on each other through 
> {{ScheduledExecutors.nonPeriodicTasks}}, and neither wait has a timeout. The 
> node needs a restart.
> The rest of the cluster keeps moving. On the stuck node, {{nodetool cms 
> describe}} shows a stale local epoch and a growing count of pending entries.
> h3. Cause
>  * {{LocalLog.snapshotListener()}} fires when an enacted epoch is a multiple 
> of {{metadata_snapshot_frequency}} and the local node has the lowest 
> {{NodeId}} among the full CMS members. It submitted 
> {{ClusterMetadataService.triggerSnapshot()}} to 
> {{{}ScheduledExecutors.nonPeriodicTasks{}}}.
>  * {{nonPeriodicTasks}} has one thread. {{LogTransaction.waitForDeletions}} 
> uses it as a barrier. It schedules a no-op on the executor and blocks until 
> the queue drains past it.
>  * The log follower enacts schema changes inline. For a dropped table it 
> reaches the barrier through {{{}SchemaListener.notifyPreCommit{}}}, 
> {{{}DistributedSchema.initializeKeyspaceInstances{}}}, 
> {{{}Keyspace.dropCf{}}}, {{ColumnFamilyStore.invalidate}} and 
> {{{}LifecycleTransaction.waitForDeletions{}}}.
>  * {{ClusterMetadataService.commit}} waits at its pre-commit barrier 
> ({{{}LocalLog.waitForHighestConsecutive{}}}) without a deadline, before it 
> consults its retry policy. If the snapshot task already holds the executor's 
> thread, it parks there until the follower finishes a loop.
>  * The follower is blocked in the deletion barrier and needs that thread to 
> run its no-op. The wait is circular. Every later commit on the node also 
> parks at the same barrier.
> h3. Stack traces
> The snapshot task holding the only {{nonPeriodicTasks}} thread and waiting on 
> the follower.
> {code}
> "NonPeriodicTasks:1" WAITING (parking)
>     at 
> org.apache.cassandra.utils.concurrent.WaitQueue$Standard$AbstractSignal.await
>     at org.apache.cassandra.tcm.log.LocalLog$Async.runOnce
>     at org.apache.cassandra.tcm.log.LocalLog.runOnce
>     at org.apache.cassandra.tcm.log.LocalLog.waitForHighestConsecutive
>     at org.apache.cassandra.tcm.ClusterMetadataService.commit
>     at org.apache.cassandra.tcm.ClusterMetadataService.commit
>     at org.apache.cassandra.tcm.ClusterMetadataService.triggerSnapshot
>     at org.apache.cassandra.tcm.log.LocalLog.lambda$snapshotListener$3
>     at org.apache.cassandra.concurrent.FutureTask.run
>     at 
> java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run
> {code}
> The log follower enacting a dropped table and waiting on the same executor.
> {code}
> "GlobalLogFollower" WAITING (parking)
>     - parking to wait for a 
> java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask
>     at java.util.concurrent.FutureTask.get
>     at org.apache.cassandra.utils.FBUtilities.waitOnFuture
>     at org.apache.cassandra.db.lifecycle.LogTransaction.waitForDeletions
>     at org.apache.cassandra.db.lifecycle.LifecycleTransaction.waitForDeletions
>     at org.apache.cassandra.db.ColumnFamilyStore.invalidate
>     at org.apache.cassandra.db.Keyspace.unloadCf
>     at org.apache.cassandra.db.Keyspace.dropCf
>     at org.apache.cassandra.schema.DistributedSchema.dropTable
>     at 
> org.apache.cassandra.schema.DistributedSchema.initializeKeyspaceInstances
>     at org.apache.cassandra.tcm.listeners.SchemaListener.notifyPreCommit
>     at org.apache.cassandra.tcm.log.LocalLog.notifyPreCommit
>     at org.apache.cassandra.tcm.log.LocalLog.processPendingInternal
>     at org.apache.cassandra.tcm.log.LocalLog$Async$AsyncRunnable.run}}
> {code}
> The park address in the second trace is the future for the no-op that the 
> first thread prevents from running.
> h3. Fix
> Trigger snapshots from a private single-thread executor, {{CMSLogTasks}}, 
> owned by {{ClusterMetadataService}}. {{nonPeriodicTasks}} then no longer 
> carries the snapshot task, so the deletion barrier can drain. The executor is 
> shut down in {{StorageService.drain()}} and in the in-JVM dtest instance 
> teardown.
>  



--
This message was sent by Atlassian Jira
(v10.3.26#10030026)

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to