Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 8 additions & 4 deletions core/src/main/scala/kafka/cluster/Partition.scala
Original file line number Diff line number Diff line change
Expand Up @@ -307,17 +307,21 @@ class Partition(val topicPartition: TopicPartition,
LogConfig.fromProps(logManager.currentDefaultConfig.originals, props)
}

logManager.initializingLog(topicPartition)
var maybeLog: Option[Log] = None
try {
val log = logManager.getOrCreateLog(topicPartition, fetchLogConfig, isNew, isFutureReplica)
def updateHighWatermark(log: Log) = {
val checkpointHighWatermark = offsetCheckpoints.fetch(log.parentDir, topicPartition).getOrElse {
info(s"No checkpointed highwatermark is found for partition $topicPartition")
0L
}
val initialHighWatermark = log.updateHighWatermark(checkpointHighWatermark)
info(s"Log loaded for partition $topicPartition with initial high watermark $initialHighWatermark")
}

logManager.initializingLog(topicPartition)
var maybeLog: Option[Log] = None
try {
val log = logManager.getOrCreateLog(topicPartition, () => fetchLogConfig, isNew, isFutureReplica)
maybeLog = Some(log)
updateHighWatermark(log)
log
} finally {
logManager.finishedInitializingLog(topicPartition, maybeLog, () => fetchLogConfig)
Expand Down
16 changes: 9 additions & 7 deletions core/src/main/scala/kafka/log/LogManager.scala
Original file line number Diff line number Diff line change
Expand Up @@ -687,16 +687,17 @@ class LogManager(logDirs: Seq[File],

/**
* Method to indicate that the log initialization for the partition passed in as argument is
* finished. This method should follow a call to [[kafka.log.LogManager#initializingLog]]
* finished. This method should follow a call to [[kafka.log.LogManager#initializingLog]].
*
* It will retrieve the topic configs a second time if they were updated while the
* relevant log was being loaded.
*/
def finishedInitializingLog(topicPartition: TopicPartition,
maybeLog: Option[Log],
fetchLogConfig: () => LogConfig): Unit = {
if (partitionsInitializing(topicPartition)) {
val removedValue = partitionsInitializing.remove(topicPartition)
if (removedValue.contains(true))
maybeLog.foreach(_.updateConfig(fetchLogConfig()))
}

partitionsInitializing -= topicPartition
}

/**
Expand All @@ -705,12 +706,12 @@ class LogManager(logDirs: Seq[File],
* Otherwise throw KafkaStorageException
*
* @param topicPartition The partition whose log needs to be returned or created
* @param config The configuration of the log that should be applied for log creation
* @param loadConfig A function to retrieve the log config, this is only called if the log is created
* @param isNew Whether the replica should have existed on the broker or not
* @param isFuture True if the future log of the specified partition should be returned or created
* @throws KafkaStorageException if isNew=false, log is not found in the cache and there is offline log directory on the broker
*/
def getOrCreateLog(topicPartition: TopicPartition, config: LogConfig, isNew: Boolean = false, isFuture: Boolean = false): Log = {
def getOrCreateLog(topicPartition: TopicPartition, loadConfig: () => LogConfig, isNew: Boolean = false, isFuture: Boolean = false): Log = {
logCreationOrDeletionLock synchronized {
getLog(topicPartition, isFuture).getOrElse {
// create the log if it has not already been created in another thread
Expand Down Expand Up @@ -747,6 +748,7 @@ class LogManager(logDirs: Seq[File],
.getOrElse(Failure(new KafkaStorageException("No log directories available. Tried " + logDirs.map(_.getAbsolutePath).mkString(", "))))
.get // If Failure, will throw

val config = loadConfig()
val log = Log(
dir = logDir,
config = config,
Expand Down
24 changes: 12 additions & 12 deletions core/src/test/scala/unit/kafka/cluster/PartitionTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ class PartitionTest extends AbstractPartitionTest {
def testMakeLeaderUpdatesEpochCache(): Unit = {
val leaderEpoch = 8

val log = logManager.getOrCreateLog(topicPartition, logConfig)
val log = logManager.getOrCreateLog(topicPartition, () => logConfig)
log.appendAsLeader(MemoryRecords.withRecords(0L, CompressionType.NONE, 0,
new SimpleRecord("k1".getBytes, "v1".getBytes),
new SimpleRecord("k2".getBytes, "v2".getBytes)
Expand All @@ -80,7 +80,7 @@ class PartitionTest extends AbstractPartitionTest {

val logConfig = LogConfig(createLogProperties(Map(
LogConfig.MessageFormatVersionProp -> kafka.api.KAFKA_0_10_2_IV0.shortVersion)))
val log = logManager.getOrCreateLog(topicPartition, logConfig)
val log = logManager.getOrCreateLog(topicPartition, () => logConfig)
log.appendAsLeader(TestUtils.records(List(
new SimpleRecord("k1".getBytes, "v1".getBytes),
new SimpleRecord("k2".getBytes, "v2".getBytes)),
Expand Down Expand Up @@ -634,7 +634,7 @@ class PartitionTest extends AbstractPartitionTest {

private def setupPartitionWithMocks(leaderEpoch: Int,
isLeader: Boolean,
log: Log = logManager.getOrCreateLog(topicPartition, logConfig)): Partition = {
log: Log = logManager.getOrCreateLog(topicPartition, () => logConfig)): Partition = {
partition.createLogIfNotExists(isNew = false, isFutureReplica = false, offsetCheckpoints)

val controllerEpoch = 0
Expand Down Expand Up @@ -940,7 +940,7 @@ class PartitionTest extends AbstractPartitionTest {
val logConfig = LogConfig(new Properties)

val topicPartitions = (0 until 5).map { i => new TopicPartition("test-topic", i) }
val logs = topicPartitions.map { tp => logManager.getOrCreateLog(tp, logConfig) }
val logs = topicPartitions.map { tp => logManager.getOrCreateLog(tp, () => logConfig) }
val partitions = ListBuffer.empty[Partition]

logs.foreach { log =>
Expand Down Expand Up @@ -1072,7 +1072,7 @@ class PartitionTest extends AbstractPartitionTest {

@Test
def testUpdateFollowerFetchState(): Unit = {
val log = logManager.getOrCreateLog(topicPartition, logConfig)
val log = logManager.getOrCreateLog(topicPartition, () => logConfig)
seedLogData(log, numRecords = 6, leaderEpoch = 4)

val controllerEpoch = 0
Expand Down Expand Up @@ -1133,7 +1133,7 @@ class PartitionTest extends AbstractPartitionTest {

@Test
def testIsrExpansion(): Unit = {
val log = logManager.getOrCreateLog(topicPartition, logConfig)
val log = logManager.getOrCreateLog(topicPartition, () => logConfig)
seedLogData(log, numRecords = 10, leaderEpoch = 4)

val controllerEpoch = 0
Expand Down Expand Up @@ -1197,7 +1197,7 @@ class PartitionTest extends AbstractPartitionTest {

@Test
def testIsrNotExpandedIfUpdateFails(): Unit = {
val log = logManager.getOrCreateLog(topicPartition, logConfig)
val log = logManager.getOrCreateLog(topicPartition, () => logConfig)
seedLogData(log, numRecords = 10, leaderEpoch = 4)

val controllerEpoch = 0
Expand Down Expand Up @@ -1249,7 +1249,7 @@ class PartitionTest extends AbstractPartitionTest {

@Test
def testMaybeShrinkIsr(): Unit = {
val log = logManager.getOrCreateLog(topicPartition, logConfig)
val log = logManager.getOrCreateLog(topicPartition, () => logConfig)
seedLogData(log, numRecords = 10, leaderEpoch = 4)

val controllerEpoch = 0
Expand Down Expand Up @@ -1303,7 +1303,7 @@ class PartitionTest extends AbstractPartitionTest {

@Test
def testShouldNotShrinkIsrIfPreviousFetchIsCaughtUp(): Unit = {
val log = logManager.getOrCreateLog(topicPartition, logConfig)
val log = logManager.getOrCreateLog(topicPartition, () => logConfig)
seedLogData(log, numRecords = 10, leaderEpoch = 4)

val controllerEpoch = 0
Expand Down Expand Up @@ -1374,7 +1374,7 @@ class PartitionTest extends AbstractPartitionTest {

@Test
def testShouldNotShrinkIsrIfFollowerCaughtUpToLogEnd(): Unit = {
val log = logManager.getOrCreateLog(topicPartition, logConfig)
val log = logManager.getOrCreateLog(topicPartition, () => logConfig)
seedLogData(log, numRecords = 10, leaderEpoch = 4)

val controllerEpoch = 0
Expand Down Expand Up @@ -1430,7 +1430,7 @@ class PartitionTest extends AbstractPartitionTest {

@Test
def testIsrNotShrunkIfUpdateFails(): Unit = {
val log = logManager.getOrCreateLog(topicPartition, logConfig)
val log = logManager.getOrCreateLog(topicPartition, () => logConfig)
seedLogData(log, numRecords = 10, leaderEpoch = 4)

val controllerEpoch = 0
Expand Down Expand Up @@ -1479,7 +1479,7 @@ class PartitionTest extends AbstractPartitionTest {

@Test
def testUseCheckpointToInitializeHighWatermark(): Unit = {
val log = logManager.getOrCreateLog(topicPartition, logConfig)
val log = logManager.getOrCreateLog(topicPartition, () => logConfig)
seedLogData(log, numRecords = 6, leaderEpoch = 5)

when(offsetCheckpoints.fetch(logDir1.getAbsolutePath, topicPartition))
Expand Down
24 changes: 12 additions & 12 deletions core/src/test/scala/unit/kafka/log/LogManagerTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ class LogManagerTest {
*/
@Test
def testCreateLog(): Unit = {
val log = logManager.getOrCreateLog(new TopicPartition(name, 0), logConfig)
val log = logManager.getOrCreateLog(new TopicPartition(name, 0), () => logConfig)
assertEquals(1, logManager.liveLogDirs.size)

val logFile = new File(logDir, name + "-0")
Expand All @@ -95,7 +95,7 @@ class LogManagerTest {
logManager = createLogManager(dirs)
logManager.startup()

val log = logManager.getOrCreateLog(new TopicPartition(name, 0), logConfig, isNew = true)
val log = logManager.getOrCreateLog(new TopicPartition(name, 0), () => logConfig, isNew = true)
val logFile = new File(logDir, name + "-0")
assertTrue(logFile.exists)
log.appendAsLeader(TestUtils.singletonRecords("test".getBytes()), leaderEpoch = 0)
Expand Down Expand Up @@ -127,7 +127,7 @@ class LogManagerTest {

// Request creating a new log.
// LogManager should try using all configured log directories until one succeeds.
logManager.getOrCreateLog(new TopicPartition(name, 0), logConfig, isNew = true)
logManager.getOrCreateLog(new TopicPartition(name, 0), () => logConfig, isNew = true)

// Verify that half the directories were considered broken,
assertEquals(dirs.length / 2, brokenDirs.size)
Expand Down Expand Up @@ -156,7 +156,7 @@ class LogManagerTest {
*/
@Test
def testCleanupExpiredSegments(): Unit = {
val log = logManager.getOrCreateLog(new TopicPartition(name, 0), logConfig)
val log = logManager.getOrCreateLog(new TopicPartition(name, 0), () => logConfig)
var offset = 0L
for(_ <- 0 until 200) {
val set = TestUtils.singletonRecords("test".getBytes())
Expand Down Expand Up @@ -207,7 +207,7 @@ class LogManagerTest {
logManager.startup()

// create a log
val log = logManager.getOrCreateLog(new TopicPartition(name, 0), config)
val log = logManager.getOrCreateLog(new TopicPartition(name, 0), () => config)
var offset = 0L

// add a bunch of messages that should be larger than the retentionSize
Expand Down Expand Up @@ -261,7 +261,7 @@ class LogManagerTest {
private def testDoesntCleanLogs(policy: String): Unit = {
val logProps = new Properties()
logProps.put(LogConfig.CleanupPolicyProp, policy)
val log = logManager.getOrCreateLog(new TopicPartition(name, 0), LogConfig.fromProps(logConfig.originals, logProps))
val log = logManager.getOrCreateLog(new TopicPartition(name, 0), () => LogConfig.fromProps(logConfig.originals, logProps))
var offset = 0L
for (_ <- 0 until 200) {
val set = TestUtils.singletonRecords("test".getBytes(), key="test".getBytes())
Expand Down Expand Up @@ -290,7 +290,7 @@ class LogManagerTest {

logManager = createLogManager()
logManager.startup()
val log = logManager.getOrCreateLog(new TopicPartition(name, 0), config)
val log = logManager.getOrCreateLog(new TopicPartition(name, 0), () => config)
val lastFlush = log.lastFlushTime
for (_ <- 0 until 200) {
val set = TestUtils.singletonRecords("test".getBytes())
Expand All @@ -314,7 +314,7 @@ class LogManagerTest {

// verify that logs are always assigned to the least loaded partition
for(partition <- 0 until 20) {
logManager.getOrCreateLog(new TopicPartition("test", partition), logConfig)
logManager.getOrCreateLog(new TopicPartition("test", partition), () => logConfig)
assertEquals("We should have created the right number of logs", partition + 1, logManager.allLogs.size)
val counts = logManager.allLogs.groupBy(_.dir.getParent).values.map(_.size)
assertTrue("Load should balance evenly", counts.max <= counts.min + 1)
Expand Down Expand Up @@ -365,7 +365,7 @@ class LogManagerTest {
}

private def verifyCheckpointRecovery(topicPartitions: Seq[TopicPartition], logManager: LogManager, logDir: File): Unit = {
val logs = topicPartitions.map(logManager.getOrCreateLog(_, logConfig))
val logs = topicPartitions.map(logManager.getOrCreateLog(_, () => logConfig))
logs.foreach { log =>
for (_ <- 0 until 50)
log.appendAsLeader(TestUtils.singletonRecords("test".getBytes()), leaderEpoch = 0)
Expand All @@ -391,7 +391,7 @@ class LogManagerTest {

@Test
def testFileReferencesAfterAsyncDelete(): Unit = {
val log = logManager.getOrCreateLog(new TopicPartition(name, 0), logConfig)
val log = logManager.getOrCreateLog(new TopicPartition(name, 0), () => logConfig)
val activeSegment = log.activeSegment
val logName = activeSegment.log.file.getName
val indexName = activeSegment.offsetIndex.file.getName
Expand Down Expand Up @@ -428,7 +428,7 @@ class LogManagerTest {
@Test
def testCreateAndDeleteOverlyLongTopic(): Unit = {
val invalidTopicName = String.join("", Collections.nCopies(253, "x"))
logManager.getOrCreateLog(new TopicPartition(invalidTopicName, 0), logConfig)
logManager.getOrCreateLog(new TopicPartition(invalidTopicName, 0), () => logConfig)
logManager.asyncDelete(new TopicPartition(invalidTopicName, 0))
}

Expand All @@ -441,7 +441,7 @@ class LogManagerTest {
new TopicPartition("test-b", 0),
new TopicPartition("test-b", 1))

val allLogs = tps.map(logManager.getOrCreateLog(_, logConfig))
val allLogs = tps.map(logManager.getOrCreateLog(_, () => logConfig))
allLogs.foreach { log =>
for (_ <- 0 until 50)
log.appendAsLeader(TestUtils.singletonRecords("test".getBytes), leaderEpoch = 0)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ class HighwatermarkPersistenceTest {
val tp0 = new TopicPartition(topic, 0)
val partition0 = replicaManager.createPartition(tp0)
// create leader and follower replicas
val log0 = logManagers.head.getOrCreateLog(new TopicPartition(topic, 0), LogConfig())
val log0 = logManagers.head.getOrCreateLog(new TopicPartition(topic, 0), () => LogConfig())
partition0.setLog(log0, isFutureLog = false)

partition0.updateAssignmentAndIsr(
Expand Down Expand Up @@ -125,7 +125,7 @@ class HighwatermarkPersistenceTest {
val t1p0 = new TopicPartition(topic1, 0)
val topic1Partition0 = replicaManager.createPartition(t1p0)
// create leader log
val topic1Log0 = logManagers.head.getOrCreateLog(t1p0, LogConfig())
val topic1Log0 = logManagers.head.getOrCreateLog(t1p0, () => LogConfig())
// create a local replica for topic1
topic1Partition0.setLog(topic1Log0, isFutureLog = false)
replicaManager.checkpointHighWatermarks()
Expand All @@ -142,7 +142,7 @@ class HighwatermarkPersistenceTest {
val t2p0 = new TopicPartition(topic2, 0)
val topic2Partition0 = replicaManager.createPartition(t2p0)
// create leader log
val topic2Log0 = logManagers.head.getOrCreateLog(t2p0, LogConfig())
val topic2Log0 = logManagers.head.getOrCreateLog(t2p0, () => LogConfig())
// create a local replica for topic2
topic2Partition0.setLog(topic2Log0, isFutureLog = false)
replicaManager.checkpointHighWatermarks()
Expand Down
4 changes: 2 additions & 2 deletions core/src/test/scala/unit/kafka/server/LogOffsetTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ class LogOffsetTest extends BaseRequestTest {
createTopic(topic, 3, 1)

val logManager = server.getLogManager
val log = logManager.getOrCreateLog(topicPartition, logManager.initialDefaultConfig)
val log = logManager.getOrCreateLog(topicPartition, () => logManager.initialDefaultConfig)

for (_ <- 0 until 20)
log.appendAsLeader(TestUtils.singletonRecords(value = Integer.toString(42).getBytes()), leaderEpoch = 0)
Expand Down Expand Up @@ -192,7 +192,7 @@ class LogOffsetTest extends BaseRequestTest {
createTopic(topic, 3, 1)

val logManager = server.getLogManager
val log = logManager.getOrCreateLog(topicPartition, logManager.initialDefaultConfig)
val log = logManager.getOrCreateLog(topicPartition, () => logManager.initialDefaultConfig)
for (_ <- 0 until 20)
log.appendAsLeader(TestUtils.singletonRecords(value = Integer.toString(42).getBytes()), leaderEpoch = 0)
log.flush()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1331,9 +1331,9 @@ class ReplicaManagerTest {
val topicPartitionObj = new TopicPartition(topic, topicPartition)
val mockLogMgr: LogManager = EasyMock.createMock(classOf[LogManager])
EasyMock.expect(mockLogMgr.liveLogDirs).andReturn(config.logDirs.map(new File(_).getAbsoluteFile)).anyTimes
EasyMock.expect(mockLogMgr.currentDefaultConfig).andReturn(LogConfig())
EasyMock.expect(mockLogMgr.getOrCreateLog(topicPartitionObj,
LogConfig(), isNew = false, isFuture = false)).andReturn(mockLog).anyTimes
EasyMock.expect(mockLogMgr.getOrCreateLog(EasyMock.eq(topicPartitionObj),
EasyMock.anyObject[() => LogConfig](), isNew = EasyMock.eq(false),
isFuture = EasyMock.eq(false))).andReturn(mockLog).anyTimes
if (expectTruncation) {
EasyMock.expect(mockLogMgr.truncateTo(Map(topicPartitionObj -> offsetFromLeader),
isFuture = false)).once
Expand Down Expand Up @@ -1846,7 +1846,7 @@ class ReplicaManagerTest {
val replicaManager = setupReplicaManagerWithMockedPurgatories(mockTimer, aliveBrokerIds = Seq(0, 1))

val tp0 = new TopicPartition(topic, 0)
val log = replicaManager.logManager.getOrCreateLog(tp0, LogConfig(), true)
val log = replicaManager.logManager.getOrCreateLog(tp0, () => LogConfig(), true)

if (throwIOException) {
// Delete the underlying directory to trigger an KafkaStorageException
Expand Down