Skip to content

Commit

Permalink
KAFKA-15432: RLM Stop partitions should not be invoked for non-tiered…
Browse files Browse the repository at this point in the history
… storage topics (apache#14667)

Reviewers: Christo Lolov <[email protected]>, Divij Vaidya <[email protected]>, Kamal Chandraprakash <[email protected]>
  • Loading branch information
hudeqi authored Nov 2, 2023
1 parent 7b0c076 commit 9911fab
Show file tree
Hide file tree
Showing 5 changed files with 55 additions and 10 deletions.
5 changes: 2 additions & 3 deletions core/src/main/java/kafka/log/remote/RemoteLogManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -365,9 +365,6 @@ public void stopPartitions(Set<StopPartition> stopPartitions,
for (StopPartition stopPartition: stopPartitions) {
TopicPartition tp = stopPartition.topicPartition();
try {
// We are assuming that if the topic exists in topicIdByPartitionMap then it has active archival
// otherwise not. Ideally, `stopPartitions` should not be called for internal and non-tiered-storage
// topics. See KAFKA-15432 for more details.
if (topicIdByPartitionMap.containsKey(tp)) {
TopicIdPartition tpId = new TopicIdPartition(topicIdByPartitionMap.get(tp), tp);
RLMTaskWithFuture task = leaderOrFollowerTasks.remove(tpId);
Expand All @@ -379,6 +376,8 @@ public void stopPartitions(Set<StopPartition> stopPartitions,
LOGGER.info("Deleting the remote log segments task for partition: {}", tpId);
deleteRemoteLogPartition(tpId);
}
} else {
LOGGER.warn("StopPartition call is not expected for partition: {}", tp);
}
} catch (Exception ex) {
errorHandler.accept(tp, ex);
Expand Down
5 changes: 4 additions & 1 deletion core/src/main/scala/kafka/server/ReplicaManager.scala
Original file line number Diff line number Diff line change
Expand Up @@ -630,13 +630,16 @@ class ReplicaManager(val config: KafkaConfig,

// Third delete the logs and checkpoint.
val errorMap = new mutable.HashMap[TopicPartition, Throwable]()
val remotePartitionsToStop = partitionsToStop.filter {
sp => logManager.getLog(sp.topicPartition).exists(unifiedLog => unifiedLog.remoteLogEnabled())
}
if (partitionsToDelete.nonEmpty) {
// Delete the logs and checkpoint.
logManager.asyncDelete(partitionsToDelete, isStray = false, (tp, e) => errorMap.put(tp, e))
}
remoteLogManager.foreach { rlm =>
// exclude the partitions with offline/error state
val partitions = partitionsToStop.filterNot(sp => errorMap.contains(sp.topicPartition)).toSet.asJava
val partitions = remotePartitionsToStop.filterNot(sp => errorMap.contains(sp.topicPartition)).toSet.asJava
if (!partitions.isEmpty) {
rlm.stopPartitions(partitions, (tp, e) => errorMap.put(tp, e))
}
Expand Down
48 changes: 45 additions & 3 deletions core/src/test/scala/unit/kafka/server/ReplicaManagerTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ import org.junit.jupiter.params.ParameterizedTest
import org.junit.jupiter.params.provider.{EnumSource, ValueSource}
import com.yammer.metrics.core.Gauge
import kafka.log.remote.RemoteLogManager
import org.apache.kafka.common.config.AbstractConfig
import org.apache.kafka.common.config.{AbstractConfig, TopicConfig}
import org.apache.kafka.raft.RaftConfig
import org.apache.kafka.server.log.remote.storage.{NoOpRemoteLogMetadataManager, NoOpRemoteStorageManager, RemoteLogManagerConfig}
import org.apache.kafka.server.util.timer.MockTimer
Expand Down Expand Up @@ -3118,7 +3118,8 @@ class ReplicaManagerTest {
isShuttingDown: AtomicBoolean = new AtomicBoolean(false),
enableRemoteStorage: Boolean = false,
shouldMockLog: Boolean = false,
remoteLogManager: Option[RemoteLogManager] = None
remoteLogManager: Option[RemoteLogManager] = None,
defaultTopicRemoteLogStorageEnable: Boolean = true
): ReplicaManager = {
val props = TestUtils.createBrokerConfig(brokerId, TestUtils.MockZkConnect)
val path1 = TestUtils.tempRelativeDir("data").getAbsolutePath
Expand All @@ -3127,8 +3128,11 @@ class ReplicaManagerTest {
propsModifier.apply(props)
val config = KafkaConfig.fromProps(props)
val logProps = new Properties()
if (enableRemoteStorage && defaultTopicRemoteLogStorageEnable) {
logProps.put(TopicConfig.REMOTE_LOG_STORAGE_ENABLE_CONFIG, "true")
}
val mockLog = setupMockLog(path1)
val mockLogMgr = TestUtils.createLogManager(config.logDirs.map(new File(_)), new LogConfig(logProps), log = if (shouldMockLog) Some(mockLog) else None)
val mockLogMgr = TestUtils.createLogManager(config.logDirs.map(new File(_)), new LogConfig(logProps), log = if (shouldMockLog) Some(mockLog) else None, remoteStorageSystemEnable = enableRemoteStorage)
val aliveBrokers = aliveBrokerIds.map(brokerId => new Node(brokerId, s"host$brokerId", brokerId))

val metadataCache: MetadataCache = mock(classOf[MetadataCache])
Expand Down Expand Up @@ -5668,6 +5672,44 @@ class ReplicaManagerTest {

verify(spyRm).checkpointHighWatermarks()
}

@Test
def testNotCallStopPartitionsForNonTieredTopics(): Unit = {
val mockTimer = new MockTimer(time)
val replicaManager = setupReplicaManagerWithMockedPurgatories(mockTimer, aliveBrokerIds = Seq(0, 1),
enableRemoteStorage = true, defaultTopicRemoteLogStorageEnable = false)

try {
val tp0 = new TopicPartition(topic, 0)
val offsetCheckpoints = new LazyOffsetCheckpoints(replicaManager.highWatermarkCheckpoints)
val partition = replicaManager.createPartition(tp0)
// The unified log created is not tiered because `defaultTopicRemoteLogStorageEnable` is set to false
partition.createLogIfNotExists(isNew = false, isFutureReplica = false, offsetCheckpoints, None)

val leaderAndIsr = LeaderAndIsr(0, 1, List(0, 1), LeaderRecoveryState.RECOVERED, LeaderAndIsr.InitialPartitionEpoch)
val becomeLeaderRequest = makeLeaderAndIsrRequest(topicIds(tp0.topic), tp0, Seq(0, 1), leaderAndIsr)

replicaManager.becomeLeaderOrFollower(1, becomeLeaderRequest, (_, _) => ())
verifyRLMOnLeadershipChange(Collections.singleton(partition), Collections.emptySet())

val requestLeaderEpoch = 1
val deleteLocalLog = true
val partitionStates = Map(tp0 -> new StopReplicaPartitionState()
.setPartitionIndex(tp0.partition)
.setLeaderEpoch(requestLeaderEpoch)
.setDeletePartition(deleteLocalLog)
)

val (result, error) = replicaManager.stopReplicas(1, 0, 0, partitionStates)

assertEquals(Errors.NONE, error)
assertEquals(Map(tp0 -> Errors.NONE), result)
assertEquals(HostedPartition.None, replicaManager.getPartition(tp0))
verifyNoMoreInteractions(mockRemoteLogManager)
} finally {
replicaManager.shutdown(checkpointHW = false)
}
}
}

class MockReplicaSelector extends ReplicaSelector {
Expand Down
5 changes: 3 additions & 2 deletions core/src/test/scala/unit/kafka/utils/TestUtils.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1415,7 +1415,8 @@ object TestUtils extends Logging {
interBrokerProtocolVersion: MetadataVersion = MetadataVersion.latest,
recoveryThreadsPerDataDir: Int = 4,
transactionVerificationEnabled: Boolean = false,
log: Option[UnifiedLog] = None): LogManager = {
log: Option[UnifiedLog] = None,
remoteStorageSystemEnable: Boolean = false): LogManager = {
val logManager = new LogManager(logDirs = logDirs.map(_.getAbsoluteFile),
initialOfflineDirs = Array.empty[File],
configRepository = configRepository,
Expand All @@ -1435,7 +1436,7 @@ object TestUtils extends Logging {
logDirFailureChannel = new LogDirFailureChannel(logDirs.size),
keepPartitionMetadataFile = true,
interBrokerProtocolVersion = interBrokerProtocolVersion,
remoteStorageSystemEnable = false)
remoteStorageSystemEnable = remoteStorageSystemEnable)

if (log.isDefined) {
val spyLogManager = Mockito.spy(logManager)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ public void setup() {
JavaConverters.seqAsJavaList(brokerProperties.logDirs()).stream().map(File::new).collect(Collectors.toList());
this.logManager = TestUtils.createLogManager(JavaConverters.asScalaBuffer(files),
new LogConfig(new Properties()), new MockConfigRepository(), new CleanerConfig(1, 4 * 1024 * 1024L, 0.9d,
1024 * 1024, 32 * 1024 * 1024, Double.MAX_VALUE, 15 * 1000, true), time, MetadataVersion.latest(), 4, false, Option.empty());
1024 * 1024, 32 * 1024 * 1024, Double.MAX_VALUE, 15 * 1000, true), time, MetadataVersion.latest(), 4, false, Option.empty(), false);
scheduler.startup();
final BrokerTopicStats brokerTopicStats = new BrokerTopicStats(Optional.empty());
final MetadataCache metadataCache =
Expand Down

0 comments on commit 9911fab

Please sign in to comment.