jolshan commented on code in PR #23943:
URL: https://github.com/apache/kafka/pull/23943#discussion_r4383325988


##########
core/src/main/scala/kafka/coordinator/transaction/TransactionStateManager.scala:
##########
@@ -605,7 +611,85 @@ class TransactionStateManager(brokerId: Int,
     }
 
     val scheduleStartMs = time.milliseconds()
-    scheduler.scheduleOnce(s"load-txns-for-partition-$topicPartition", () => 
loadTransactions(scheduleStartMs))
+
+    def scheduleLoad(hwmWaitTimeMs: Long): Unit =
+      scheduler.scheduleOnce(s"load-txns-for-partition-$topicPartition", () => 
loadTransactions(scheduleStartMs, hwmWaitTimeMs))
+
+    // The listener is invoked with partition locks held, so instead of 
blocking on stateLock there, this runs on
+    // the scheduler, which also serializes it with the load tasks for the 
partition.
+    def scheduleAbandonLoad(reason: String): Unit =
+      
scheduler.scheduleOnce(s"abandon-load-txns-for-partition-$topicPartition", () 
=> {
+        inWriteLock[Exception](stateLock, () => {
+          loadingPartitions.remove(partitionAndLeaderEpoch)
+        })
+        info(s"Abandoned loading transaction metadata from $topicPartition at 
epoch $coordinatorEpoch because $reason")
+      })
+
+    // The load reads up to the log end offset, but a newly elected leader may 
have records above the high watermark
+    // that are not committed yet and may still get truncated. The coordinator 
does not write to the partition while
+    // it is loading, so the log end offset doesn't change; wait until the 
high watermark catches up to it so that
+    // all the records the load reads are committed.
+    replicaManager.getLog(topicPartition) match {
+      case Some(log) if log.highWatermark < log.logEndOffset =>
+        val logEndOffset = log.logEndOffset
+        info(s"Waiting for the high watermark of $topicPartition (currently 
${log.highWatermark}) to reach the log end " +
+          s"offset $logEndOffset before loading transaction metadata at epoch 
$coordinatorEpoch")
+        val listener = new HighWatermarkWaitListener(topicPartition, 
logEndOffset, coordinatorEpoch, scheduleLoad, scheduleAbandonLoad)
+        if (!replicaManager.maybeAddListener(topicPartition, listener)) {
+          listener.abandon(s"$topicPartition is not online")
+        } else {
+          // the high watermark may have been updated after it was read above 
but before the listener was added,
+          // in which case the listener isn't notified of the update: check it 
again now that the listener is added
+          listener.onHighWatermarkUpdated(topicPartition, log.highWatermark)
+          // the wait may have finished before the listener was added; in that 
case remove it again
+          if (listener.isFinished)
+            replicaManager.removeListener(topicPartition, listener)
+        }
+      case _ =>

Review Comment:
   What would this case represent?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to