mirror of https://github.com/apache/kafka.git
KAFKA-16074: close leaking threads in replica manager tests (#15077)
Following @dajac 's finding in #15063, I found we also create new RemoteLogManager in ReplicaManagerTest, but didn't close them. While investigating ReplicaManagerTest, I also found there are other threads leaking: 1. remote fetch reaper thread. It's because we create a reaper thread in test, which is not expected. We should create a mocked one like other purgatory instance. 2. Throttle threads. We created a quotaManager to feed into the replicaManager, but didn't close it. Actually, we have created a global quotaManager instance and will close it on AfterEach. We should re-use it. 3. replicaManager and logManager didn't invoke close after test. Reviewers: Divij Vaidya <divijvaidya13@gmail.com>, Satish Duggana <satishd@apache.org>, Justine Olshan <jolshan@confluent.io>
This commit is contained in:
parent
bdb4895f88
commit
d071cceffc
|
@ -23,7 +23,7 @@ import java.net.InetAddress
|
||||||
import java.nio.file.{Files, Paths}
|
import java.nio.file.{Files, Paths}
|
||||||
import java.util
|
import java.util
|
||||||
import java.util.concurrent.atomic.{AtomicBoolean, AtomicLong, AtomicReference}
|
import java.util.concurrent.atomic.{AtomicBoolean, AtomicLong, AtomicReference}
|
||||||
import java.util.concurrent.{CountDownLatch, TimeUnit}
|
import java.util.concurrent.{Callable, CountDownLatch, TimeUnit}
|
||||||
import java.util.stream.IntStream
|
import java.util.stream.IntStream
|
||||||
import java.util.{Collections, Optional, OptionalLong, Properties}
|
import java.util.{Collections, Optional, OptionalLong, Properties}
|
||||||
import kafka.api._
|
import kafka.api._
|
||||||
|
@ -2633,18 +2633,21 @@ class ReplicaManagerTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
val logManager = TestUtils.createLogManager(config.logDirs.map(new File(_)), defaultConfig = new LogConfig(new Properties()), time = time)
|
val logManager = TestUtils.createLogManager(config.logDirs.map(new File(_)), defaultConfig = new LogConfig(new Properties()), time = time)
|
||||||
|
val quotaManager = QuotaFactory.instantiate(config, metrics, time, "")
|
||||||
val replicaManager = new ReplicaManager(
|
val replicaManager = new ReplicaManager(
|
||||||
metrics = metrics,
|
metrics = metrics,
|
||||||
config = config,
|
config = config,
|
||||||
time = time,
|
time = time,
|
||||||
scheduler = time.scheduler,
|
scheduler = time.scheduler,
|
||||||
logManager = logManager,
|
logManager = logManager,
|
||||||
quotaManagers = QuotaFactory.instantiate(config, metrics, time, ""),
|
quotaManagers = quotaManager,
|
||||||
metadataCache = MetadataCache.zkMetadataCache(config.brokerId, config.interBrokerProtocolVersion),
|
metadataCache = MetadataCache.zkMetadataCache(config.brokerId, config.interBrokerProtocolVersion),
|
||||||
logDirFailureChannel = new LogDirFailureChannel(config.logDirs.size),
|
logDirFailureChannel = new LogDirFailureChannel(config.logDirs.size),
|
||||||
alterPartitionManager = alterPartitionManager,
|
alterPartitionManager = alterPartitionManager,
|
||||||
threadNamePrefix = Option(this.getClass.getName))
|
threadNamePrefix = Option(this.getClass.getName))
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
logManager.startup(Set.empty[String])
|
logManager.startup(Set.empty[String])
|
||||||
|
|
||||||
// Create a hosted topic, a hosted topic that will become stray
|
// Create a hosted topic, a hosted topic that will become stray
|
||||||
|
@ -2693,23 +2696,41 @@ class ReplicaManagerTest {
|
||||||
} else {
|
} else {
|
||||||
assertTrue(stray0.isInstanceOf[HostedPartition.Online])
|
assertTrue(stray0.isInstanceOf[HostedPartition.Online])
|
||||||
}
|
}
|
||||||
|
} finally {
|
||||||
|
Utils.tryAll(util.Arrays.asList[Callable[Void]] (
|
||||||
|
() => {
|
||||||
|
replicaManager.shutdown(checkpointHW = false)
|
||||||
|
null
|
||||||
|
},
|
||||||
|
() => {
|
||||||
|
logManager.shutdown()
|
||||||
|
null
|
||||||
|
},
|
||||||
|
() => {
|
||||||
|
quotaManager.shutdown()
|
||||||
|
null
|
||||||
|
}
|
||||||
|
))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
def testUpdateStrayLogs(): Unit = {
|
def testUpdateStrayLogs(): Unit = {
|
||||||
val logManager = TestUtils.createLogManager(config.logDirs.map(new File(_)), defaultConfig = new LogConfig(new Properties()), time = time)
|
val logManager = TestUtils.createLogManager(config.logDirs.map(new File(_)), defaultConfig = new LogConfig(new Properties()), time = time)
|
||||||
|
val quotaManager = QuotaFactory.instantiate(config, metrics, time, "")
|
||||||
val replicaManager = new ReplicaManager(
|
val replicaManager = new ReplicaManager(
|
||||||
metrics = metrics,
|
metrics = metrics,
|
||||||
config = config,
|
config = config,
|
||||||
time = time,
|
time = time,
|
||||||
scheduler = time.scheduler,
|
scheduler = time.scheduler,
|
||||||
logManager = logManager,
|
logManager = logManager,
|
||||||
quotaManagers = QuotaFactory.instantiate(config, metrics, time, ""),
|
quotaManagers = quotaManager,
|
||||||
metadataCache = MetadataCache.zkMetadataCache(config.brokerId, config.interBrokerProtocolVersion),
|
metadataCache = MetadataCache.zkMetadataCache(config.brokerId, config.interBrokerProtocolVersion),
|
||||||
logDirFailureChannel = new LogDirFailureChannel(config.logDirs.size),
|
logDirFailureChannel = new LogDirFailureChannel(config.logDirs.size),
|
||||||
alterPartitionManager = alterPartitionManager,
|
alterPartitionManager = alterPartitionManager,
|
||||||
threadNamePrefix = Option(this.getClass.getName))
|
threadNamePrefix = Option(this.getClass.getName))
|
||||||
|
|
||||||
|
try {
|
||||||
logManager.startup(Set.empty[String])
|
logManager.startup(Set.empty[String])
|
||||||
|
|
||||||
// Create a hosted topic, a hosted topic that will become stray, and a stray topic
|
// Create a hosted topic, a hosted topic that will become stray, and a stray topic
|
||||||
|
@ -2723,9 +2744,22 @@ class ReplicaManagerTest {
|
||||||
|
|
||||||
assertEquals(validLogs, logManager.allLogs.toSet)
|
assertEquals(validLogs, logManager.allLogs.toSet)
|
||||||
assertEquals(validLogs.size, replicaManager.partitionCount.value)
|
assertEquals(validLogs.size, replicaManager.partitionCount.value)
|
||||||
|
} finally {
|
||||||
replicaManager.shutdown()
|
Utils.tryAll(util.Arrays.asList[Callable[Void]](
|
||||||
|
() => {
|
||||||
|
replicaManager.shutdown(checkpointHW = false)
|
||||||
|
null
|
||||||
|
},
|
||||||
|
() => {
|
||||||
logManager.shutdown()
|
logManager.shutdown()
|
||||||
|
null
|
||||||
|
},
|
||||||
|
() => {
|
||||||
|
quotaManager.shutdown()
|
||||||
|
null
|
||||||
|
}
|
||||||
|
))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private def createHostedLogs(name: String, numLogs: Int, replicaManager: ReplicaManager): Seq[UnifiedLog] = {
|
private def createHostedLogs(name: String, numLogs: Int, replicaManager: ReplicaManager): Seq[UnifiedLog] = {
|
||||||
|
@ -2878,6 +2912,8 @@ class ReplicaManagerTest {
|
||||||
purgatoryName = "DeleteRecords", timer, reaperEnabled = false)
|
purgatoryName = "DeleteRecords", timer, reaperEnabled = false)
|
||||||
val mockElectLeaderPurgatory = new DelayedOperationPurgatory[DelayedElectLeader](
|
val mockElectLeaderPurgatory = new DelayedOperationPurgatory[DelayedElectLeader](
|
||||||
purgatoryName = "ElectLeader", timer, reaperEnabled = false)
|
purgatoryName = "ElectLeader", timer, reaperEnabled = false)
|
||||||
|
val mockRemoteFetchPurgatory = new DelayedOperationPurgatory[DelayedRemoteFetch](
|
||||||
|
purgatoryName = "RemoteFetch", timer, reaperEnabled = false)
|
||||||
|
|
||||||
// Mock network client to show leader offset of 5
|
// Mock network client to show leader offset of 5
|
||||||
val blockingSend = new MockBlockingSender(
|
val blockingSend = new MockBlockingSender(
|
||||||
|
@ -2902,6 +2938,7 @@ class ReplicaManagerTest {
|
||||||
delayedFetchPurgatoryParam = Some(mockFetchPurgatory),
|
delayedFetchPurgatoryParam = Some(mockFetchPurgatory),
|
||||||
delayedDeleteRecordsPurgatoryParam = Some(mockDeleteRecordsPurgatory),
|
delayedDeleteRecordsPurgatoryParam = Some(mockDeleteRecordsPurgatory),
|
||||||
delayedElectLeaderPurgatoryParam = Some(mockElectLeaderPurgatory),
|
delayedElectLeaderPurgatoryParam = Some(mockElectLeaderPurgatory),
|
||||||
|
delayedRemoteFetchPurgatoryParam = Some(mockRemoteFetchPurgatory),
|
||||||
threadNamePrefix = Option(this.getClass.getName)) {
|
threadNamePrefix = Option(this.getClass.getName)) {
|
||||||
|
|
||||||
override protected def createReplicaFetcherManager(metrics: Metrics,
|
override protected def createReplicaFetcherManager(metrics: Metrics,
|
||||||
|
@ -3458,8 +3495,16 @@ class ReplicaManagerTest {
|
||||||
rm0.becomeLeaderOrFollower(correlationId, leaderAndIsrRequest2, (_, _) => ())
|
rm0.becomeLeaderOrFollower(correlationId, leaderAndIsrRequest2, (_, _) => ())
|
||||||
rm1.becomeLeaderOrFollower(correlationId, leaderAndIsrRequest2, (_, _) => ())
|
rm1.becomeLeaderOrFollower(correlationId, leaderAndIsrRequest2, (_, _) => ())
|
||||||
} finally {
|
} finally {
|
||||||
|
Utils.tryAll(util.Arrays.asList[Callable[Void]](
|
||||||
|
() => {
|
||||||
rm0.shutdown(checkpointHW = false)
|
rm0.shutdown(checkpointHW = false)
|
||||||
|
null
|
||||||
|
},
|
||||||
|
() => {
|
||||||
rm1.shutdown(checkpointHW = false)
|
rm1.shutdown(checkpointHW = false)
|
||||||
|
null
|
||||||
|
}
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
// verify that broker 1 did remove its metrics when no longer being the leader of partition 1
|
// verify that broker 1 did remove its metrics when no longer being the leader of partition 1
|
||||||
|
@ -3546,8 +3591,16 @@ class ReplicaManagerTest {
|
||||||
rm0.becomeLeaderOrFollower(correlationId, leaderAndIsrRequest2, (_, _) => ())
|
rm0.becomeLeaderOrFollower(correlationId, leaderAndIsrRequest2, (_, _) => ())
|
||||||
rm1.becomeLeaderOrFollower(correlationId, leaderAndIsrRequest2, (_, _) => ())
|
rm1.becomeLeaderOrFollower(correlationId, leaderAndIsrRequest2, (_, _) => ())
|
||||||
} finally {
|
} finally {
|
||||||
|
Utils.tryAll(util.Arrays.asList[Callable[Void]](
|
||||||
|
() => {
|
||||||
rm0.shutdown(checkpointHW = false)
|
rm0.shutdown(checkpointHW = false)
|
||||||
|
null
|
||||||
|
},
|
||||||
|
() => {
|
||||||
rm1.shutdown(checkpointHW = false)
|
rm1.shutdown(checkpointHW = false)
|
||||||
|
null
|
||||||
|
}
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
// verify that broker 1 did remove its metrics when no longer being the leader of partition 1
|
// verify that broker 1 did remove its metrics when no longer being the leader of partition 1
|
||||||
|
@ -4019,7 +4072,16 @@ class ReplicaManagerTest {
|
||||||
// unlock all tasks
|
// unlock all tasks
|
||||||
doneLatch.countDown()
|
doneLatch.countDown()
|
||||||
} finally {
|
} finally {
|
||||||
|
Utils.tryAll(util.Arrays.asList[Callable[Void]](
|
||||||
|
() => {
|
||||||
replicaManager.shutdown(checkpointHW = false)
|
replicaManager.shutdown(checkpointHW = false)
|
||||||
|
null
|
||||||
|
},
|
||||||
|
() => {
|
||||||
|
remoteLogManager.close()
|
||||||
|
null
|
||||||
|
}
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4115,7 +4177,16 @@ class ReplicaManagerTest {
|
||||||
safeYammerMetricValue("type=DelayedRemoteFetchMetrics,name=ExpiresPerSec").asInstanceOf[Long])
|
safeYammerMetricValue("type=DelayedRemoteFetchMetrics,name=ExpiresPerSec").asInstanceOf[Long])
|
||||||
latch.countDown()
|
latch.countDown()
|
||||||
} finally {
|
} finally {
|
||||||
|
Utils.tryAll(util.Arrays.asList[Callable[Void]](
|
||||||
|
() => {
|
||||||
replicaManager.shutdown(checkpointHW = false)
|
replicaManager.shutdown(checkpointHW = false)
|
||||||
|
null
|
||||||
|
},
|
||||||
|
() => {
|
||||||
|
remoteLogManager.close()
|
||||||
|
null
|
||||||
|
}
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue