alexr17 commented on code in PR #13886:
URL: https://github.com/apache/hudi/pull/13886#discussion_r2353939422


##########
hudi-cli/src/main/java/org/apache/hudi/cli/commands/LockAuditingCommand.java:
##########
@@ -185,4 +272,323 @@ public String showLockAuditStatus() {
       return String.format("Failed to check lock audit status: %s", 
e.getMessage());
     }
   }
+
+  /**
+   * Validates the audit lock files for consistency and integrity.
+   * This command checks for issues such as corrupted files, invalid format,
+   * incorrect state transitions, and orphaned locks.
+   * 
+   * @return Validation results including any issues found
+   */
+  @ShellMethod(key = "locks audit validate", value = "Validate audit lock 
files for consistency and integrity")
+  public String validateAuditLocks() {
+    
+    if (HoodieCLI.basePath == null) {
+      return "No Hudi table loaded. Please connect to a table first.";
+    }
+
+    try {
+      String auditFolderPath = 
StorageLockProviderAuditService.getAuditFolderPath(HoodieCLI.basePath);
+      StoragePath auditFolder = new StoragePath(auditFolderPath);
+      
+      // Check if audit folder exists
+      if (!HoodieCLI.storage.exists(auditFolder)) {
+        return "Validation Result: PASSED\n"
+            + "Transactions Validated: 0\n"
+            + "Issues Found: 0\n"
+            + "Details: No audit folder found - nothing to validate";
+      }
+      
+      // Get all audit files
+      List<StoragePathInfo> allFiles = 
HoodieCLI.storage.listDirectEntries(auditFolder);
+      List<StoragePathInfo> auditFiles = new ArrayList<>();
+      for (StoragePathInfo pathInfo : allFiles) {
+        if (pathInfo.isFile() && 
pathInfo.getPath().getName().endsWith(".jsonl")) {
+          auditFiles.add(pathInfo);
+        }
+      }
+      
+      if (auditFiles.isEmpty()) {
+        return "Validation Result: PASSED\n"
+            + "Transactions Validated: 0\n"
+            + "Issues Found: 0\n"
+            + "Details: No audit files found - nothing to validate";
+      }
+      
+      // Parse all audit files into transaction windows
+      List<TransactionWindow> windows = new ArrayList<>();
+      for (StoragePathInfo pathInfo : auditFiles) {
+        Option<TransactionWindow> window = parseAuditFile(pathInfo);
+        if (window.isPresent()) {
+          windows.add(window.get());
+        }
+      }
+      
+      if (windows.isEmpty()) {
+        return String.format("Validation Result: FAILED\n"
+            + "Transactions Validated: 0\n"
+            + "Issues Found: %d\n"
+            + "Details: Failed to parse any audit files", auditFiles.size());
+      }
+      
+      // Validate transactions
+      ValidationResults validationResults = 
validateTransactionWindows(windows);
+      
+      // Generate result
+      int totalIssues = validationResults.errors.size() + 
validationResults.warnings.size();
+      String result;
+      String details;
+      
+      if (totalIssues == 0) {
+        result = "PASSED";
+        details = "All audit lock transactions validated successfully";
+      } else {
+        result = validationResults.errors.isEmpty() ? "WARNING" : "FAILED";
+        List<String> allIssues = new ArrayList<>();
+        allIssues.addAll(validationResults.errors);
+        allIssues.addAll(validationResults.warnings);
+        details = String.join(", ", allIssues);
+      }
+      
+      return String.format("Validation Result: %s\n"
+          + "Transactions Validated: %d\n"
+          + "Issues Found: %d\n"
+          + "Details: %s", result, windows.size(), totalIssues, details);
+      
+    } catch (Exception e) {
+      LOG.error("Error validating audit locks", e);
+      return String.format("Validation Result: ERROR\n"
+          + "Transactions Validated: 0\n"
+          + "Issues Found: -1\n"
+          + "Details: Validation failed: %s", e.getMessage());
+    }
+  }
+
+  /**
+   * Cleans up old audit lock files based on age threshold.
+   * This command removes audit files that are older than the specified number 
of days.
+   * 
+   * @param dryRun Whether to perform a dry run (preview changes without 
deletion)
+   * @param ageDays Number of days to keep audit files (default 7)
+   * @return Status message indicating files cleaned or to be cleaned
+   */
+  @ShellMethod(key = "locks audit cleanup", value = "Clean up old audit lock 
files")
+  public String cleanupAuditLocks(
+      @ShellOption(value = {"--dryRun"}, defaultValue = "false",
+          help = "Preview changes without actually deleting files") final 
boolean dryRun,
+      @ShellOption(value = {"--ageDays"}, defaultValue = "7",
+          help = "Delete audit files older than this many days") final int 
ageDays) {
+    
+    if (HoodieCLI.basePath == null) {
+      return "No Hudi table loaded. Please connect to a table first.";
+    }
+
+    if (ageDays <= 0) {
+      return "Error: ageDays must be a positive integer.";
+    }
+
+    return performAuditCleanup(dryRun, ageDays).toString();
+  }
+
+  /**
+   * Internal method to perform audit cleanup. Used by both the CLI command 
and disable method.
+   *
+   * @param dryRun Whether to perform a dry run (preview changes without 
deletion)
+   * @param ageDays Number of days to keep audit files (0 means delete all)
+   * @return CleanupResult containing cleanup operation details
+   */
+  private CleanupResult performAuditCleanup(boolean dryRun, int ageDays) {
+    try {
+      String auditFolderPath = 
StorageLockProviderAuditService.getAuditFolderPath(HoodieCLI.basePath);
+      StoragePath auditFolder = new StoragePath(auditFolderPath);
+      
+      // Check if audit folder exists
+      if (!HoodieCLI.storage.exists(auditFolder)) {
+        String message = "No audit folder found - nothing to cleanup.";
+        return new CleanupResult(true, 0, 0, 0, message, dryRun);
+      }
+      

Review Comment:
   it's on the original method jfyi



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