github-actions[bot] commented on code in PR #66612:
URL: https://github.com/apache/doris/pull/66612#discussion_r3849552378


##########
fe/be-java-extensions/paimon-connector/src/main/java/org/apache/doris/paimon/PaimonJniWriter.java:
##########
@@ -576,13 +583,31 @@ private void closeWriter() throws Exception {
             throw new IllegalStateException(
                     "A previous Paimon SDK close failed; native memory cannot 
be released safely");
         }
-        Exception failure = closeResource(writer, null);
-        failure = closeResource(globalIndexAssigner, failure);
-        failure = closeResource(ioManager, failure);
+        Exception lifecycleFailure = closeResource(writer, null);
+        Exception compactionFailure = closeCompactionExecutor();
+        if (compactionFailure != null) {
+            lifecycleFailure = appendFailure(lifecycleFailure, 
compactionFailure);
+            // The task may still reference Doris-backed memory and spill 
files. Leave all dependent
+            // Java resources reachable and open; the native backend will 
retain their handles.
+            sdkCloseFailed = true;
+            throw lifecycleFailure;
+        }
+        lifecycleFailure = closeResource(globalIndexAssigner, 
lifecycleFailure);
+        Exception cleanupFailure = closeResource(ioManager, null);
         clearWriterState();
-        if (failure != null) {
+        if (lifecycleFailure != null) {
+            if (cleanupFailure != null) {
+                lifecycleFailure.addSuppressed(cleanupFailure);
+            }
             sdkCloseFailed = true;
-            throw failure;
+            throw lifecycleFailure;
+        }
+        if (cleanupFailure != null) {

Review Comment:
   [P1] Keep residual spill files charged after cleanup failure
   
   `DorisIOManager.close()` deliberately leaves any still-existing channel 
charged when delegate deletion fails, but this branch logs that failure and 
returns Java close success. Native close then destroys the spill session, whose 
destructor subtracts all accounted bytes and drops the query-directory lease 
even though the files remain until later QueryContext teardown/GC. Other 
writers can therefore reserve that occupied space and overcommit the disk. 
Please retain or transfer the accounting and lease to the pending cleanup 
record until deletion succeeds, and extend the failure test with a real 
residual channel plus native quota assertions.



##########
regression-test/suites/external_table_p0/paimon/write/test_paimon_write_external_paths.groovy:
##########
@@ -134,8 +134,14 @@ suite("test_paimon_write_external_paths", 
"p0,external,paimon") {
             FROM numbers("number" = "16")
         """
         def oldRoundFiles = dataFiles("t_round_robin")
-        assertTrue(oldRoundFiles.any { it.startsWith("${pathRoot}/round-a/") })
-        assertTrue(oldRoundFiles.any { it.startsWith("${pathRoot}/round-b/") })
+        assertFalse(oldRoundFiles.isEmpty())
+        // Paimon randomizes the initial position of each round-robin 
provider. Since providers are
+        // scoped to a partition/bucket writer, independent writes are not 
guaranteed to hit every
+        // configured path. Verify the stable contract that all files use the 
configured path set.
+        assertTrue(oldRoundFiles.every {

Review Comment:
   [P2] Keep a deterministic round-robin oracle
   
   This now passes if the provider always chooses `round-a`, so it no longer 
tests the configured round-robin strategy. Paimon randomizes only the initial 
provider position and then advances deterministically, while the current 16-row 
bulk does not force a second file because rolling is checked every 1000 
records. Removing the cross-writer probabilistic assertion is reasonable, but 
please add one deterministic writer/bucket with enough non-compressible rows to 
roll multiple files and assert that it uses both roots.



##########
fe/be-java-extensions/paimon-connector/src/main/java/org/apache/doris/paimon/PaimonJniWriter.java:
##########
@@ -228,6 +232,10 @@ public void writeArrow(long arrayAddress, long 
schemaAddress) throws Exception {
                         VectorSchemaRoot root = Data.importVectorSchemaRoot(
                                 allocator, array, schema, dictionaries)) {
                     writeBatch(root);
+                    // Some Paimon writers (lookup stores, global indexes and 
clustering indexes)
+                    // write raw files below IOManager paths. Account their 
observed growth before
+                    // returning control to the native pipeline.
+                    ioManager.reconcile();

Review Comment:
   [P1] Avoid recursively scanning every spill file after each block
   
   This runs once per non-empty Doris `Block`, and the native callback holds 
the session mutex while recursively walking every managed root and calling 
`file_size` on every file, including buffer channels already covered by 
callbacks. After spill starts, a writer with B blocks and F accumulated files 
pays O(B x F) synchronous metadata work and blocks reserve/release callbacks 
behind each scan; this can make large writes increasingly expensive. Please use 
incremental raw-file accounting, or at least dirty/throttled and raw-only 
reconciliation with a bounded final pass, and add a many-block/many-file 
regression.



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


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to