hudi-agent commented on code in PR #20279:
URL: https://github.com/apache/hudi/pull/20279#discussion_r4237328070


##########
hudi-spark-datasource/hudi-spark/src/main/scala/org/apache/spark/sql/hudi/command/procedures/ValidateHoodieSyncProcedure.scala:
##########
@@ -120,83 +119,80 @@ class ValidateHoodieSyncProcedure extends BaseProcedure 
with ProcedureBuilder wi
     if (commitsToCatchup.isEmpty) {
       s"Count difference now is count(${target.getTableConfig.getTableName}) - 
count(${source.getTableConfig.getTableName}) == ${targetCount - sourceCount}"
     } else {
-      val newInserts = countNewRecords(target, commitsToCatchup.map(elem => 
elem.requestedTime))
+      val newInserts = countNewRecords(target, commitsToCatchup)
       s"Count difference now is count(${target.getTableConfig.getTableName}) - 
count(${source.getTableConfig.getTableName}) == ${targetCount - sourceCount}" +
         s". Catach up count is $newInserts"
     }
   }
 
+  @throws[SQLException]
   def countRecords(jdbcUrl: String, source: HoodieTableMetaClient, dbName: 
String, user: String, pass: String): Long = {
-    var conn: Connection = null
-    var rs: ResultSet = null
-    var count: Long = -1
-    try {
-      conn = DriverManager.getConnection(jdbcUrl, user, pass)
-      val stmt = conn.createStatement()
-
-      stmt.execute("set 
hive.input.format=org.apache.hadoop.hive.ql.io.HiveInputFormat");
-      stmt.execute("set hive.stats.autogather=false");
-
-      rs = stmt.executeQuery(
-        s"select count(`_hoodie_commit_time`) as cnt from 
$dbName.${source.getTableConfig.getTableName}")
-      if (rs.next()) {
-        count = rs.getLong("cnt")
-      }
-
-      println(s"Total records in ${source.getTableConfig.getTableName} is 
$count")
-    } finally {
-      conn.close()
-      if (rs != null) {
-        rs.close()
-      }
-    }
+    val count = executeCountQuery(jdbcUrl, user, pass,
+      s"select count(`_hoodie_commit_time`) as cnt from 
$dbName.${source.getTableConfig.getTableName}")
+    println(s"Total records in ${source.getTableConfig.getTableName} is 
$count")
     count
   }
 
   @throws[SQLException]
   def countRecords(jdbcUrl: String, source: HoodieTableMetaClient, srcDb: 
String, partitions: Int, user: String, pass: String): Long = {
-    def getDate(dateTime: DateTime): String = {
-      
s"${dateTime.getYear}-${dateTime.getMonthOfYear}%02d-${dateTime.getDayOfMonth}%02d"
-    }
     var dateTime = DateTime.now
-    val endDateStr = getDate(dateTime)
+    val endDateStr = ValidateHoodieSyncProcedure.formatDatestr(dateTime)
     dateTime = dateTime.minusDays(partitions)
-    val startDateStr = getDate(dateTime)
+    val startDateStr = ValidateHoodieSyncProcedure.formatDatestr(dateTime)
     println("Start date " + startDateStr + " and end date " + endDateStr)
     countRecords(jdbcUrl, source, srcDb, startDateStr, endDateStr, user, pass)
 
   }
 
   @throws[SQLException]
   private def countRecords(jdbcUrl: String, source: HoodieTableMetaClient, 
srcDb: String, startDateStr: String, endDateStr: String, user: String, pass: 
String): Long = {
-    var rs: ResultSet = null
+    executeCountQuery(jdbcUrl, user, pass,
+      s"select count(`_hoodie_commit_time`) as cnt from 
$srcDb.${source.getTableConfig.getTableName}" +
+        s" where datestr>'$startDateStr' and datestr<='$endDateStr'")
+  }
+
+  /**
+   * Runs a `count(...) as cnt` query over a new HiveServer2 connection and 
returns `cnt`, or -1 if
+   * the query yields no row.
+   *
+   * Each JDBC resource is closed only once it has been opened, in the reverse 
order of opening, so a
+   * failure to connect surfaces as the [[SQLException]] it is rather than as 
a failure to close a
+   * connection that was never opened.
+   */
+  @throws[SQLException]
+  private def executeCountQuery(jdbcUrl: String, user: String, pass: String, 
countQuery: String): Long = {
+    val conn: Connection = DriverManager.getConnection(jdbcUrl, user, pass)
     try {
-      val conn = DriverManager.getConnection(jdbcUrl, user, pass)
-      val stmt = conn.createStatement
-      try { // stmt.execute("set mapred.job.queue.name=<queue_name>");
+      val stmt: Statement = conn.createStatement()
+      try {
         stmt.execute("set 
hive.input.format=org.apache.hadoop.hive.ql.io.HiveInputFormat")
         stmt.execute("set hive.stats.autogather=false")
-        rs = stmt.executeQuery(s"select count(`_hoodie_commit_time`) as cnt 
from $srcDb.${source.getTableConfig.getTableName} where datestr>'$startDateStr' 
and datestr<='$endDateStr'")
-        if (rs.next)
-          rs.getLong("cnt")
-        else
-          -1
+        val rs: ResultSet = stmt.executeQuery(countQuery)
+        try {
+          if (rs.next()) rs.getLong("cnt") else -1
+        } finally {
+          rs.close()
+        }
       } finally {
-        if (rs != null) rs.close()
-        if (conn != null) conn.close()
-        if (stmt != null) stmt.close()
+        stmt.close()
       }
+    } finally {
+      conn.close()
     }
   }
 
+  /**
+   * Sums the records inserted by the given write instants. Each instant is 
read as it is on the
+   * timeline, so the deltacommits of a merge-on-read table and the 
replacecommits of a clustering
+   * or an insert overwrite are resolved under their own action. Pending 
instants are skipped, as
+   * they have not committed any records yet.
+   */
   @throws[IOException]
-  def countNewRecords(target: HoodieTableMetaClient, commitsToCatchup: 
List[String]): Long = {
+  def countNewRecords(target: HoodieTableMetaClient, commitsToCatchup: 
List[HoodieInstant]): Long = {
     var totalNew: Long = 0
-    val timeline: HoodieTimeline = 
target.reloadActiveTimeline.getCommitAndReplaceTimeline.filterCompletedInstants
-    for (commit <- commitsToCatchup) {
-      val instantGenerator = target.getTimelineLayout.getInstantGenerator
-      val instant: HoodieInstant = 
instantGenerator.createNewInstant(HoodieInstant.State.COMPLETED, 
HoodieTimeline.COMMIT_ACTION, commit)
-      val c: HoodieCommitMetadata = timeline.readCommitMetadata(instant)
+    val timeline: HoodieTimeline = 
target.reloadActiveTimeline.getCommitsTimeline.filterCompletedInstants

Review Comment:
   🤖 nit: could you rename `c` to `metadata`? It's the commit metadata being 
summed, and a single letter is easy to misread here.
   
   <sub><i>⚠️ AI-generated; verify before applying. React 👍/👎 to flag 
quality.</i></sub>



##########
hudi-spark-datasource/hudi-spark/src/main/scala/org/apache/spark/sql/hudi/command/procedures/ValidateHoodieSyncProcedure.scala:
##########
@@ -120,83 +119,80 @@ class ValidateHoodieSyncProcedure extends BaseProcedure 
with ProcedureBuilder wi
     if (commitsToCatchup.isEmpty) {
       s"Count difference now is count(${target.getTableConfig.getTableName}) - 
count(${source.getTableConfig.getTableName}) == ${targetCount - sourceCount}"
     } else {
-      val newInserts = countNewRecords(target, commitsToCatchup.map(elem => 
elem.requestedTime))
+      val newInserts = countNewRecords(target, commitsToCatchup)
       s"Count difference now is count(${target.getTableConfig.getTableName}) - 
count(${source.getTableConfig.getTableName}) == ${targetCount - sourceCount}" +
         s". Catach up count is $newInserts"
     }
   }
 
+  @throws[SQLException]
   def countRecords(jdbcUrl: String, source: HoodieTableMetaClient, dbName: 
String, user: String, pass: String): Long = {
-    var conn: Connection = null
-    var rs: ResultSet = null
-    var count: Long = -1
-    try {
-      conn = DriverManager.getConnection(jdbcUrl, user, pass)
-      val stmt = conn.createStatement()
-
-      stmt.execute("set 
hive.input.format=org.apache.hadoop.hive.ql.io.HiveInputFormat");
-      stmt.execute("set hive.stats.autogather=false");
-
-      rs = stmt.executeQuery(
-        s"select count(`_hoodie_commit_time`) as cnt from 
$dbName.${source.getTableConfig.getTableName}")
-      if (rs.next()) {
-        count = rs.getLong("cnt")
-      }
-
-      println(s"Total records in ${source.getTableConfig.getTableName} is 
$count")
-    } finally {
-      conn.close()
-      if (rs != null) {
-        rs.close()
-      }
-    }
+    val count = executeCountQuery(jdbcUrl, user, pass,
+      s"select count(`_hoodie_commit_time`) as cnt from 
$dbName.${source.getTableConfig.getTableName}")
+    println(s"Total records in ${source.getTableConfig.getTableName} is 
$count")
     count
   }
 
   @throws[SQLException]
   def countRecords(jdbcUrl: String, source: HoodieTableMetaClient, srcDb: 
String, partitions: Int, user: String, pass: String): Long = {
-    def getDate(dateTime: DateTime): String = {
-      
s"${dateTime.getYear}-${dateTime.getMonthOfYear}%02d-${dateTime.getDayOfMonth}%02d"
-    }
     var dateTime = DateTime.now
-    val endDateStr = getDate(dateTime)
+    val endDateStr = ValidateHoodieSyncProcedure.formatDatestr(dateTime)
     dateTime = dateTime.minusDays(partitions)
-    val startDateStr = getDate(dateTime)
+    val startDateStr = ValidateHoodieSyncProcedure.formatDatestr(dateTime)
     println("Start date " + startDateStr + " and end date " + endDateStr)
     countRecords(jdbcUrl, source, srcDb, startDateStr, endDateStr, user, pass)
 
   }
 
   @throws[SQLException]
   private def countRecords(jdbcUrl: String, source: HoodieTableMetaClient, 
srcDb: String, startDateStr: String, endDateStr: String, user: String, pass: 
String): Long = {
-    var rs: ResultSet = null
+    executeCountQuery(jdbcUrl, user, pass,
+      s"select count(`_hoodie_commit_time`) as cnt from 
$srcDb.${source.getTableConfig.getTableName}" +
+        s" where datestr>'$startDateStr' and datestr<='$endDateStr'")
+  }
+
+  /**
+   * Runs a `count(...) as cnt` query over a new HiveServer2 connection and 
returns `cnt`, or -1 if
+   * the query yields no row.
+   *
+   * Each JDBC resource is closed only once it has been opened, in the reverse 
order of opening, so a
+   * failure to connect surfaces as the [[SQLException]] it is rather than as 
a failure to close a
+   * connection that was never opened.
+   */
+  @throws[SQLException]
+  private def executeCountQuery(jdbcUrl: String, user: String, pass: String, 
countQuery: String): Long = {
+    val conn: Connection = DriverManager.getConnection(jdbcUrl, user, pass)
     try {
-      val conn = DriverManager.getConnection(jdbcUrl, user, pass)
-      val stmt = conn.createStatement
-      try { // stmt.execute("set mapred.job.queue.name=<queue_name>");
+      val stmt: Statement = conn.createStatement()
+      try {
         stmt.execute("set 
hive.input.format=org.apache.hadoop.hive.ql.io.HiveInputFormat")
         stmt.execute("set hive.stats.autogather=false")
-        rs = stmt.executeQuery(s"select count(`_hoodie_commit_time`) as cnt 
from $srcDb.${source.getTableConfig.getTableName} where datestr>'$startDateStr' 
and datestr<='$endDateStr'")
-        if (rs.next)
-          rs.getLong("cnt")
-        else
-          -1
+        val rs: ResultSet = stmt.executeQuery(countQuery)
+        try {
+          if (rs.next()) rs.getLong("cnt") else -1
+        } finally {
+          rs.close()
+        }
       } finally {
-        if (rs != null) rs.close()
-        if (conn != null) conn.close()
-        if (stmt != null) stmt.close()
+        stmt.close()
       }
+    } finally {
+      conn.close()
     }
   }
 
+  /**
+   * Sums the records inserted by the given write instants. Each instant is 
read as it is on the
+   * timeline, so the deltacommits of a merge-on-read table and the 
replacecommits of a clustering
+   * or an insert overwrite are resolved under their own action. Pending 
instants are skipped, as
+   * they have not committed any records yet.
+   */
   @throws[IOException]
-  def countNewRecords(target: HoodieTableMetaClient, commitsToCatchup: 
List[String]): Long = {
+  def countNewRecords(target: HoodieTableMetaClient, commitsToCatchup: 
List[HoodieInstant]): Long = {
     var totalNew: Long = 0
-    val timeline: HoodieTimeline = 
target.reloadActiveTimeline.getCommitAndReplaceTimeline.filterCompletedInstants
-    for (commit <- commitsToCatchup) {
-      val instantGenerator = target.getTimelineLayout.getInstantGenerator
-      val instant: HoodieInstant = 
instantGenerator.createNewInstant(HoodieInstant.State.COMPLETED, 
HoodieTimeline.COMMIT_ACTION, commit)
-      val c: HoodieCommitMetadata = timeline.readCommitMetadata(instant)
+    val timeline: HoodieTimeline = 
target.reloadActiveTimeline.getCommitsTimeline.filterCompletedInstants
+    for (instant <- commitsToCatchup if instant.isCompleted) {
+      val c: HoodieCommitMetadata = TimelineUtils.getCommitMetadata(instant, 
timeline)
       totalNew += c.fetchTotalRecordsWritten - c.fetchTotalUpdateRecordsWritten

Review Comment:
   🤖 non-blocking: now that clustering replacecommits and MOR compaction 
commits resolve instead of throwing, `fetchTotalRecordsWritten - 
fetchTotalUpdateRecordsWritten` counts every record they rewrite as a new 
insert, so a catch-up range with a clustering or compaction would overstate the 
count; would it make sense to skip instants whose `getOperationType` is 
`CLUSTER`, `COMPACT` or `LOG_COMPACT`?
   
   <sub><i>⚠️ AI-generated; verify before applying. React 👍/👎 to flag 
quality.</i></sub>



-- 
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