[
https://issues.apache.org/jira/browse/HDDS-14600?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
Siyao Meng updated HDDS-14600:
------------------------------
Description:
When using File System Optimized (FSO) buckets (with Ratis enabled),
non-recursive directory deletion can fail with "Directory is not empty" error
(also visible in OM logs, DIRECTORY_NOT_EMPTY) even after all child directories
have been successfully deleted. This occurs when the double buffer hasn't
flushed child delete transactions to the DB yet.
This issue was discovered when using S3A with Hive CTAS operations but affects
any client using the filesystem APIs.
h2. Symptom
Issue was initially found when using FSO bucket via S3A connector from Hive
when creating an external table:
{code:sql|title=SQL}
create external table ctas_src_ext_part partitioned by (age) as select name,
age from default.studenttab10k;
{code}
{code:java|title=Hive client log}
ERROR : Job Commit failed with exception
'org.apache.hadoop.hive.ql.metadata.HiveException(org.apache.hadoop.fs.s3a.AWSS3IOException:
Remove S3 Dir Markers on
s3a://s3hive/iceberg_test_db_hive2/.hive-staging_hive_2026-02-09_19-42-25_275_4928242460862214784-9/_task_tmp.-ext-10002:
org.apache.hadoop.fs.s3a.impl.MultiObjectDeleteException:
[S3Error(Key=iceberg_test_db_hive2/.hive-staging_hive_2026-02-09_19-42-25_275_4928242460862214784-9/_task_tmp.-ext-10002/,
Code=InternalError, Message=Directory is not empty.
Key:iceberg_test_db_hive2/.hive-staging_hive_2026-02-09_19-42-25_275_4928242460862214784-9/_task_tmp.-ext-10002)]:
InternalError:
iceberg_test_db_hive2/.hive-staging_hive_2026-02-09_19-42-25_275_4928242460862214784-9/_task_tmp.-ext-10002/:
Directory is not empty.
Key:iceberg_test_db_hive2/.hive-staging_hive_2026-02-09_19-42-25_275_4928242460862214784-9/_task_tmp.-ext-10002
:
[S3Error(Key=iceberg_test_db_hive2/.hive-staging_hive_2026-02-09_19-42-25_275_4928242460862214784-9/_task_tmp.-ext-10002/,
Code=InternalError, Message=Directory is not empty.
Key:iceberg_test_db_hive2/.hive-staging_hive_2026-02-09_19-42-25_275_4928242460862214784-9/_task_tmp.-ext-10002)])'
org.apache.hadoop.hive.ql.metadata.HiveException:
org.apache.hadoop.fs.s3a.AWSS3IOException: Remove S3 Dir Markers on
s3a://s3hive/iceberg_test_db_hive2/.hive-staging_hive_2026-02-09_19-42-25_275_4928242460862214784-9/_task_tmp.-ext-10002:
org.apache.hadoop.fs.s3a.impl.MultiObjectDeleteException:
[S3Error(Key=iceberg_test_db_hive2/.hive-staging_hive_2026-02-09_19-42-25_275_4928242460862214784-9/_task_tmp.-ext-10002/,
Code=InternalError, Message=Directory is not empty.
Key:iceberg_test_db_hive2/.hive-staging_hive_2026-02-09_19-42-25_275_4928242460862214784-9/_task_tmp.-ext-10002)]:
InternalError:
iceberg_test_db_hive2/.hive-staging_hive_2026-02-09_19-42-25_275_4928242460862214784-9/_task_tmp.-ext-10002/:
Directory is not empty.
Key:iceberg_test_db_hive2/.hive-staging_hive_2026-02-09_19-42-25_275_4928242460862214784-9/_task_tmp.-ext-10002
:
[S3Error(Key=iceberg_test_db_hive2/.hive-staging_hive_2026-02-09_19-42-25_275_4928242460862214784-9/_task_tmp.-ext-10002/,
Code=InternalError, Message=Directory is not empty.
Key:iceberg_test_db_hive2/.hive-staging_hive_2026-02-09_19-42-25_275_4928242460862214784-9/_task_tmp.-ext-10002)]
at
org.apache.hadoop.hive.ql.exec.FileSinkOperator.jobCloseOp(FileSinkOperator.java:1629)
at org.apache.hadoop.hive.ql.exec.Operator.jobClose(Operator.java:797)
at org.apache.hadoop.hive.ql.exec.Operator.jobClose(Operator.java:802)
at org.apache.hadoop.hive.ql.exec.tez.TezTask.close(TezTask.java:734)
at org.apache.hadoop.hive.ql.exec.tez.TezTask.execute(TezTask.java:394)
at org.apache.hadoop.hive.ql.exec.Task.executeTask(Task.java:213)
at
org.apache.hadoop.hive.ql.exec.TaskRunner.runSequential(TaskRunner.java:105)
at org.apache.hadoop.hive.ql.Executor.launchTask(Executor.java:356)
at org.apache.hadoop.hive.ql.Executor.launchTasks(Executor.java:329)
at org.apache.hadoop.hive.ql.Executor.runTasks(Executor.java:246)
at org.apache.hadoop.hive.ql.Executor.execute(Executor.java:107)
at org.apache.hadoop.hive.ql.Driver.runInternal(Driver.java:804)
at org.apache.hadoop.hive.ql.Driver.run(Driver.java:539)
at org.apache.hadoop.hive.ql.Driver.run(Driver.java:533)
at
org.apache.hadoop.hive.ql.reexec.ReExecDriver.run(ReExecDriver.java:190)
at
org.apache.hive.service.cli.operation.SQLOperation.runQuery(SQLOperation.java:235)
at
org.apache.hive.service.cli.operation.SQLOperation.access$700(SQLOperation.java:91)
at
org.apache.hive.service.cli.operation.SQLOperation$BackgroundWork$1.run(SQLOperation.java:342)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at java.base/javax.security.auth.Subject.doAs(Subject.java:423)
at
org.apache.hadoop.security.UserGroupInformation.doAs(UserGroupInformation.java:1910)
at
org.apache.hive.service.cli.operation.SQLOperation$BackgroundWork.run(SQLOperation.java:362)
at
java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
at
java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
at
java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at
java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at java.base/java.lang.Thread.run(Thread.java:829)
Caused by: org.apache.hadoop.fs.s3a.AWSS3IOException: Remove S3 Dir Markers on
s3a://s3hive/iceberg_test_db_hive2/.hive-staging_hive_2026-02-09_19-42-25_275_4928242460862214784-9/_task_tmp.-ext-10002:
org.apache.hadoop.fs.s3a.impl.MultiObjectDeleteException:
[S3Error(Key=iceberg_test_db_hive2/.hive-staging_hive_2026-02-09_19-42-25_275_4928242460862214784-9/_task_tmp.-ext-10002/,
Code=InternalError, Message=Directory is not empty.
Key:iceberg_test_db_hive2/.hive-staging_hive_2026-02-09_19-42-25_275_4928242460862214784-9/_task_tmp.-ext-10002)]:
InternalError:
iceberg_test_db_hive2/.hive-staging_hive_2026-02-09_19-42-25_275_4928242460862214784-9/_task_tmp.-ext-10002/:
Directory is not empty.
Key:iceberg_test_db_hive2/.hive-staging_hive_2026-02-09_19-42-25_275_4928242460862214784-9/_task_tmp.-ext-10002
:
[S3Error(Key=iceberg_test_db_hive2/.hive-staging_hive_2026-02-09_19-42-25_275_4928242460862214784-9/_task_tmp.-ext-10002/,
Code=InternalError, Message=Directory is not empty.
Key:iceberg_test_db_hive2/.hive-staging_hive_2026-02-09_19-42-25_275_4928242460862214784-9/_task_tmp.-ext-10002)]
at
org.apache.hadoop.fs.s3a.impl.MultiObjectDeleteException.translateException(MultiObjectDeleteException.java:101)
at
org.apache.hadoop.fs.s3a.S3AUtils.translateException(S3AUtils.java:347)
at org.apache.hadoop.fs.s3a.Invoker.once(Invoker.java:124)
at org.apache.hadoop.fs.s3a.Invoker.once(Invoker.java:163)
at
org.apache.hadoop.fs.s3a.impl.DeleteOperation.asyncDeleteAction(DeleteOperation.java:443)
at
org.apache.hadoop.fs.s3a.impl.DeleteOperation.lambda$submitDelete$2(DeleteOperation.java:401)
at
org.apache.hadoop.fs.store.audit.AuditingFunctions.lambda$callableWithinAuditSpan$3(AuditingFunctions.java:117)
at
org.apache.hadoop.fs.s3a.impl.CallableSupplier.get(CallableSupplier.java:88)
at
java.base/java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1700)
at
org.apache.hadoop.util.SemaphoredDelegatingExecutor$RunnableWithPermitRelease.run(SemaphoredDelegatingExecutor.java:226)
at
org.apache.hadoop.util.SemaphoredDelegatingExecutor$RunnableWithPermitRelease.run(SemaphoredDelegatingExecutor.java:226)
... 3 more
Caused by: org.apache.hadoop.fs.s3a.impl.MultiObjectDeleteException:
[S3Error(Key=iceberg_test_db_hive2/.hive-staging_hive_2026-02-09_19-42-25_275_4928242460862214784-9/_task_tmp.-ext-10002/,
Code=InternalError, Message=Directory is not empty.
Key:iceberg_test_db_hive2/.hive-staging_hive_2026-02-09_19-42-25_275_4928242460862214784-9/_task_tmp.-ext-10002)]
at
org.apache.hadoop.fs.s3a.S3AFileSystem.deleteObjects(S3AFileSystem.java:3233)
at
org.apache.hadoop.fs.s3a.S3AFileSystem.removeKeysS3(S3AFileSystem.java:3460)
at
org.apache.hadoop.fs.s3a.S3AFileSystem.removeKeys(S3AFileSystem.java:3530)
at
org.apache.hadoop.fs.s3a.S3AFileSystem$OperationCallbacksImpl.removeKeys(S3AFileSystem.java:2604)
at
org.apache.hadoop.fs.s3a.impl.DeleteOperation.lambda$asyncDeleteAction$8(DeleteOperation.java:445)
at org.apache.hadoop.fs.s3a.Invoker.lambda$once$0(Invoker.java:165)
at org.apache.hadoop.fs.s3a.Invoker.once(Invoker.java:122)
... 11 more
{code}
h2. Root cause analysis
Hive initiates the call to {{fs.delete()}} on the dir with recursive set to
true into S3A:
{code:java|title=https://github.com/apache/hive/blob/98da62c93f198126c78d3352bf3ac6aeacefa53c/ql/src/java/org/apache/hadoop/hive/ql/exec/Utilities.java#L1535-L1536}
Utilities.FILE_OP_LOGGER.trace("deleting taskTmpPath {}", taskTmpPath);
fs.delete(taskTmpPath, true);
{code}
S3A would list and delete all keys under the dir if recursive=true:
https://github.com/apache/hadoop/blob/e221231e81cdc4bc34ad69ca7d606a3efa8f79d1/hadoop-tools/hadoop-aws/src/main/java/org/apache/hadoop/fs/s3a/impl/DeleteOperation.java#L228
(Thus even though Ozone S3 Gateway sets recursive=false when calling to OM, it
would not become an issue at this point:
https://github.com/apache/ozone/blob/9f9773df69302b0a8ee92a2c59515c37c6ac205d/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/endpoint/ObjectEndpoint.java#L720
)
After adding debug messages around and an attempt to repro the issue locally,
it turns out {{OMFileRequest#checkSubDirectoryExists}} would still find the
deleted child dir:
{code}
2026-02-09 15:28:30,989 [main] DEBUG key.OMKeyDeleteRequestWithFSO
(OMKeyDeleteRequestWithFSO.java:validateAndUpdateCache(168)) - DELETE_KEY:
Recursive delete requested for directory. Key: parent/child, ObjectID:
1770679710931, Transaction: 1000
2026-02-09 15:28:30,991 [main] DEBUG key.OMKeyDeleteRequestWithFSO
(OMKeyDeleteRequestWithFSO.java:validateAndUpdateCache(231)) - Key deleted.
Volume:084ac152-cbf9-4571-a8dd-b6b40b1e7a8e,
Bucket:1f5b5722-6fc3-4f6d-aef3-c0a9b500eabc, Key:parent/child
2026-02-09 15:28:30,991 [main] DEBUG key.OMKeyDeleteRequestWithFSO
(OMKeyDeleteRequestWithFSO.java:validateAndUpdateCache(147)) - DELETE_KEY:
Checking if directory is empty. Key: parent, ObjectID: 1770679710930,
ParentObjectID: 1770679710919, Transaction: 1001
2026-02-09 15:28:30,991 [main] DEBUG file.OMFileRequest
(OMFileRequest.java:hasChildren(871)) - hasChildren: Checking for children.
Key: parent, ObjectID: 1770679710930, ParentObjectID: 1770679710919, Volume:
084ac152-cbf9-4571-a8dd-b6b40b1e7a8e, Bucket:
1f5b5722-6fc3-4f6d-aef3-c0a9b500eabc
2026-02-09 15:28:30,991 [main] DEBUG file.OMFileRequest
(OMFileRequest.java:checkSubDirectoryExists(925)) - checkSubDirectoryExists: No
children in cache. Key: parent, ObjectID: 1770679710930, Cache entries checked:
2
2026-02-09 15:28:30,991 [main] DEBUG file.OMFileRequest
(OMFileRequest.java:checkSubDirectoryExists(936)) - checkSubDirectoryExists:
Checking DB with seekKey: /1770679710884/1770679710919/1770679710930/
2026-02-09 15:28:30,995 [main] WARN file.OMFileRequest
(OMFileRequest.java:checkSubDirectoryExists(950)) - checkSubDirectoryExists:
Found child directory in DB. Parent Key: parent, Parent ObjectID:
1770679710930, Child Name: child, Child ObjectID: 1770679710931, Child
ParentObjectID: 1770679710930, DB Key:
/1770679710884/1770679710919/1770679710930/child
2026-02-09 15:28:30,995 [main] WARN file.OMFileRequest
(OMFileRequest.java:hasChildren(879)) - hasChildren: Found subdirectories. Key:
parent, ObjectID: 1770679710930
2026-02-09 15:28:30,995 [main] WARN key.OMKeyDeleteRequestWithFSO
(OMKeyDeleteRequestWithFSO.java:validateAndUpdateCache(155)) - DELETE_KEY:
Directory not empty check FAILED. Key: parent, ObjectID: 1770679710930,
ParentObjectID: 1770679710919, recursive: false, Transaction: 1001,
ozonePathKey: /1770679710884/1770679710919/1770679710919/parent
2026-02-09 15:28:31,004 [main] ERROR key.OMKeyDeleteRequestWithFSO
(OMKeyDeleteRequestWithFSO.java:validateAndUpdateCache(236)) - Key delete
failed. Volume:084ac152-cbf9-4571-a8dd-b6b40b1e7a8e,
Bucket:1f5b5722-6fc3-4f6d-aef3-c0a9b500eabc, Key:parent.
DIRECTORY_NOT_EMPTY org.apache.hadoop.ozone.om.exceptions.OMException:
Directory is not empty. Key:parent
at
org.apache.hadoop.ozone.om.request.key.OMKeyDeleteRequestWithFSO.validateAndUpdateCache(OMKeyDeleteRequestWithFSO.java:160)
at
org.apache.hadoop.ozone.om.request.OMClientRequest.validateAndUpdateCache(OMClientRequest.java:145)
at
org.apache.hadoop.ozone.om.request.key.TestOMKeyDeleteRequestWithFSO.testDeleteParentAfterChildrenDeleted(TestOMKeyDeleteRequestWithFSO.java:414)
{code}
At this point, it is clear enough that this most likely is a cache-related
issue. It didn't take long after that to find that {{checkSubDirectoryExists}}
(and in extension, {{checkSubFileExists}}) didn't properly check for deleted
dir/file tombstones in cache.
h2. Repro
Proper unit test and integration test would be added in the PR, below is just
for illustration:
{code:java}
Path parent = new Path("/parent");
Path child = new Path(parent, "child");
fs.mkdirs(parent);
fs.mkdirs(child);
fs.delete(child, false); // Succeeds
fs.delete(parent, false); // Fails with "Directory is not empty" when double
buffer didn't flush fast enough after the immediately previous delete() call
{code}
was:
When using File System Optimized (FSO) buckets (with Ratis enabled),
non-recursive directory deletion can fail with "Directory is not empty" error
(also visible in OM logs, DIRECTORY_NOT_EMPTY) even after all child directories
have been successfully deleted. This occurs when the double buffer hasn't
flushed child delete transactions to the DB yet.
This issue was discovered when using S3A with Hive CTAS operations but affects
any client using the filesystem APIs.
h2. Symptom
Issue was initially found when using FSO bucket via S3A connector from Hive
when creating an external table:
{code:title=SQL}
create external table ctas_src_ext_part partitioned by (age) as select name,
age from default.studenttab10k;
{code}
{code:title=Hive client log}
ERROR : Job Commit failed with exception
'org.apache.hadoop.hive.ql.metadata.HiveException(org.apache.hadoop.fs.s3a.AWSS3IOException:
Remove S3 Dir Markers on
s3a://s3hive/iceberg_test_db_hive2/.hive-staging_hive_2026-02-09_19-42-25_275_4928242460862214784-9/_task_tmp.-ext-10002:
org.apache.hadoop.fs.s3a.impl.MultiObjectDeleteException:
[S3Error(Key=iceberg_test_db_hive2/.hive-staging_hive_2026-02-09_19-42-25_275_4928242460862214784-9/_task_tmp.-ext-10002/,
Code=InternalError, Message=Directory is not empty.
Key:iceberg_test_db_hive2/.hive-staging_hive_2026-02-09_19-42-25_275_4928242460862214784-9/_task_tmp.-ext-10002)]:
InternalError:
iceberg_test_db_hive2/.hive-staging_hive_2026-02-09_19-42-25_275_4928242460862214784-9/_task_tmp.-ext-10002/:
Directory is not empty.
Key:iceberg_test_db_hive2/.hive-staging_hive_2026-02-09_19-42-25_275_4928242460862214784-9/_task_tmp.-ext-10002
:
[S3Error(Key=iceberg_test_db_hive2/.hive-staging_hive_2026-02-09_19-42-25_275_4928242460862214784-9/_task_tmp.-ext-10002/,
Code=InternalError, Message=Directory is not empty.
Key:iceberg_test_db_hive2/.hive-staging_hive_2026-02-09_19-42-25_275_4928242460862214784-9/_task_tmp.-ext-10002)])'
org.apache.hadoop.hive.ql.metadata.HiveException:
org.apache.hadoop.fs.s3a.AWSS3IOException: Remove S3 Dir Markers on
s3a://s3hive/iceberg_test_db_hive2/.hive-staging_hive_2026-02-09_19-42-25_275_4928242460862214784-9/_task_tmp.-ext-10002:
org.apache.hadoop.fs.s3a.impl.MultiObjectDeleteException:
[S3Error(Key=iceberg_test_db_hive2/.hive-staging_hive_2026-02-09_19-42-25_275_4928242460862214784-9/_task_tmp.-ext-10002/,
Code=InternalError, Message=Directory is not empty.
Key:iceberg_test_db_hive2/.hive-staging_hive_2026-02-09_19-42-25_275_4928242460862214784-9/_task_tmp.-ext-10002)]:
InternalError:
iceberg_test_db_hive2/.hive-staging_hive_2026-02-09_19-42-25_275_4928242460862214784-9/_task_tmp.-ext-10002/:
Directory is not empty.
Key:iceberg_test_db_hive2/.hive-staging_hive_2026-02-09_19-42-25_275_4928242460862214784-9/_task_tmp.-ext-10002
:
[S3Error(Key=iceberg_test_db_hive2/.hive-staging_hive_2026-02-09_19-42-25_275_4928242460862214784-9/_task_tmp.-ext-10002/,
Code=InternalError, Message=Directory is not empty.
Key:iceberg_test_db_hive2/.hive-staging_hive_2026-02-09_19-42-25_275_4928242460862214784-9/_task_tmp.-ext-10002)]
at
org.apache.hadoop.hive.ql.exec.FileSinkOperator.jobCloseOp(FileSinkOperator.java:1629)
at org.apache.hadoop.hive.ql.exec.Operator.jobClose(Operator.java:797)
at org.apache.hadoop.hive.ql.exec.Operator.jobClose(Operator.java:802)
at org.apache.hadoop.hive.ql.exec.tez.TezTask.close(TezTask.java:734)
at org.apache.hadoop.hive.ql.exec.tez.TezTask.execute(TezTask.java:394)
at org.apache.hadoop.hive.ql.exec.Task.executeTask(Task.java:213)
at
org.apache.hadoop.hive.ql.exec.TaskRunner.runSequential(TaskRunner.java:105)
at org.apache.hadoop.hive.ql.Executor.launchTask(Executor.java:356)
at org.apache.hadoop.hive.ql.Executor.launchTasks(Executor.java:329)
at org.apache.hadoop.hive.ql.Executor.runTasks(Executor.java:246)
at org.apache.hadoop.hive.ql.Executor.execute(Executor.java:107)
at org.apache.hadoop.hive.ql.Driver.runInternal(Driver.java:804)
at org.apache.hadoop.hive.ql.Driver.run(Driver.java:539)
at org.apache.hadoop.hive.ql.Driver.run(Driver.java:533)
at
org.apache.hadoop.hive.ql.reexec.ReExecDriver.run(ReExecDriver.java:190)
at
org.apache.hive.service.cli.operation.SQLOperation.runQuery(SQLOperation.java:235)
at
org.apache.hive.service.cli.operation.SQLOperation.access$700(SQLOperation.java:91)
at
org.apache.hive.service.cli.operation.SQLOperation$BackgroundWork$1.run(SQLOperation.java:342)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at java.base/javax.security.auth.Subject.doAs(Subject.java:423)
at
org.apache.hadoop.security.UserGroupInformation.doAs(UserGroupInformation.java:1910)
at
org.apache.hive.service.cli.operation.SQLOperation$BackgroundWork.run(SQLOperation.java:362)
at
java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
at
java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
at
java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at
java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at java.base/java.lang.Thread.run(Thread.java:829)
Caused by: org.apache.hadoop.fs.s3a.AWSS3IOException: Remove S3 Dir Markers on
s3a://s3hive/iceberg_test_db_hive2/.hive-staging_hive_2026-02-09_19-42-25_275_4928242460862214784-9/_task_tmp.-ext-10002:
org.apache.hadoop.fs.s3a.impl.MultiObjectDeleteException:
[S3Error(Key=iceberg_test_db_hive2/.hive-staging_hive_2026-02-09_19-42-25_275_4928242460862214784-9/_task_tmp.-ext-10002/,
Code=InternalError, Message=Directory is not empty.
Key:iceberg_test_db_hive2/.hive-staging_hive_2026-02-09_19-42-25_275_4928242460862214784-9/_task_tmp.-ext-10002)]:
InternalError:
iceberg_test_db_hive2/.hive-staging_hive_2026-02-09_19-42-25_275_4928242460862214784-9/_task_tmp.-ext-10002/:
Directory is not empty.
Key:iceberg_test_db_hive2/.hive-staging_hive_2026-02-09_19-42-25_275_4928242460862214784-9/_task_tmp.-ext-10002
:
[S3Error(Key=iceberg_test_db_hive2/.hive-staging_hive_2026-02-09_19-42-25_275_4928242460862214784-9/_task_tmp.-ext-10002/,
Code=InternalError, Message=Directory is not empty.
Key:iceberg_test_db_hive2/.hive-staging_hive_2026-02-09_19-42-25_275_4928242460862214784-9/_task_tmp.-ext-10002)]
at
org.apache.hadoop.fs.s3a.impl.MultiObjectDeleteException.translateException(MultiObjectDeleteException.java:101)
at
org.apache.hadoop.fs.s3a.S3AUtils.translateException(S3AUtils.java:347)
at org.apache.hadoop.fs.s3a.Invoker.once(Invoker.java:124)
at org.apache.hadoop.fs.s3a.Invoker.once(Invoker.java:163)
at
org.apache.hadoop.fs.s3a.impl.DeleteOperation.asyncDeleteAction(DeleteOperation.java:443)
at
org.apache.hadoop.fs.s3a.impl.DeleteOperation.lambda$submitDelete$2(DeleteOperation.java:401)
at
org.apache.hadoop.fs.store.audit.AuditingFunctions.lambda$callableWithinAuditSpan$3(AuditingFunctions.java:117)
at
org.apache.hadoop.fs.s3a.impl.CallableSupplier.get(CallableSupplier.java:88)
at
java.base/java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1700)
at
org.apache.hadoop.util.SemaphoredDelegatingExecutor$RunnableWithPermitRelease.run(SemaphoredDelegatingExecutor.java:226)
at
org.apache.hadoop.util.SemaphoredDelegatingExecutor$RunnableWithPermitRelease.run(SemaphoredDelegatingExecutor.java:226)
... 3 more
Caused by: org.apache.hadoop.fs.s3a.impl.MultiObjectDeleteException:
[S3Error(Key=iceberg_test_db_hive2/.hive-staging_hive_2026-02-09_19-42-25_275_4928242460862214784-9/_task_tmp.-ext-10002/,
Code=InternalError, Message=Directory is not empty.
Key:iceberg_test_db_hive2/.hive-staging_hive_2026-02-09_19-42-25_275_4928242460862214784-9/_task_tmp.-ext-10002)]
at
org.apache.hadoop.fs.s3a.S3AFileSystem.deleteObjects(S3AFileSystem.java:3233)
at
org.apache.hadoop.fs.s3a.S3AFileSystem.removeKeysS3(S3AFileSystem.java:3460)
at
org.apache.hadoop.fs.s3a.S3AFileSystem.removeKeys(S3AFileSystem.java:3530)
at
org.apache.hadoop.fs.s3a.S3AFileSystem$OperationCallbacksImpl.removeKeys(S3AFileSystem.java:2604)
at
org.apache.hadoop.fs.s3a.impl.DeleteOperation.lambda$asyncDeleteAction$8(DeleteOperation.java:445)
at org.apache.hadoop.fs.s3a.Invoker.lambda$once$0(Invoker.java:165)
at org.apache.hadoop.fs.s3a.Invoker.once(Invoker.java:122)
... 11 more
{code}
h2. Root cause analysis
Hive initiates the call to {{fs.delete()}} on the dir with recursive set to
true into S3A:
{code:java|title=https://github.com/apache/hive/blob/98da62c93f198126c78d3352bf3ac6aeacefa53c/ql/src/java/org/apache/hadoop/hive/ql/exec/Utilities.java#L1535-L1536}
Utilities.FILE_OP_LOGGER.trace("deleting taskTmpPath {}", taskTmpPath);
fs.delete(taskTmpPath, true);
{code}
S3A would list and delete all keys under the dir if recursive=true:
https://github.com/apache/hadoop/blob/e221231e81cdc4bc34ad69ca7d606a3efa8f79d1/hadoop-tools/hadoop-aws/src/main/java/org/apache/hadoop/fs/s3a/impl/DeleteOperation.java#L228
(Thus even though Ozone S3 Gateway sets recursive=false when calling to OM, it
would not become an issue at this point:
https://github.com/apache/ozone/blob/9f9773df69302b0a8ee92a2c59515c37c6ac205d/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/endpoint/ObjectEndpoint.java#L720
)
After adding debug messages around and an attempt to repro the issue locally,
it turns out {{OMFileRequest#checkSubDirectoryExists}} would still find the
deleted child dir:
{code}
2026-02-09 15:28:30,989 [main] DEBUG key.OMKeyDeleteRequestWithFSO
(OMKeyDeleteRequestWithFSO.java:validateAndUpdateCache(168)) - DELETE_KEY:
Recursive delete requested for directory. Key: parent/child, ObjectID:
1770679710931, Transaction: 1000
2026-02-09 15:28:30,991 [main] DEBUG key.OMKeyDeleteRequestWithFSO
(OMKeyDeleteRequestWithFSO.java:validateAndUpdateCache(231)) - Key deleted.
Volume:084ac152-cbf9-4571-a8dd-b6b40b1e7a8e,
Bucket:1f5b5722-6fc3-4f6d-aef3-c0a9b500eabc, Key:parent/child
2026-02-09 15:28:30,991 [main] DEBUG key.OMKeyDeleteRequestWithFSO
(OMKeyDeleteRequestWithFSO.java:validateAndUpdateCache(147)) - DELETE_KEY:
Checking if directory is empty. Key: parent, ObjectID: 1770679710930,
ParentObjectID: 1770679710919, Transaction: 1001
2026-02-09 15:28:30,991 [main] DEBUG file.OMFileRequest
(OMFileRequest.java:hasChildren(871)) - hasChildren: Checking for children.
Key: parent, ObjectID: 1770679710930, ParentObjectID: 1770679710919, Volume:
084ac152-cbf9-4571-a8dd-b6b40b1e7a8e, Bucket:
1f5b5722-6fc3-4f6d-aef3-c0a9b500eabc
2026-02-09 15:28:30,991 [main] DEBUG file.OMFileRequest
(OMFileRequest.java:checkSubDirectoryExists(925)) - checkSubDirectoryExists: No
children in cache. Key: parent, ObjectID: 1770679710930, Cache entries checked:
2
2026-02-09 15:28:30,991 [main] DEBUG file.OMFileRequest
(OMFileRequest.java:checkSubDirectoryExists(936)) - checkSubDirectoryExists:
Checking DB with seekKey: /1770679710884/1770679710919/1770679710930/
2026-02-09 15:28:30,995 [main] WARN file.OMFileRequest
(OMFileRequest.java:checkSubDirectoryExists(950)) - checkSubDirectoryExists:
Found child directory in DB. Parent Key: parent, Parent ObjectID:
1770679710930, Child Name: child, Child ObjectID: 1770679710931, Child
ParentObjectID: 1770679710930, DB Key:
/1770679710884/1770679710919/1770679710930/child
2026-02-09 15:28:30,995 [main] WARN file.OMFileRequest
(OMFileRequest.java:hasChildren(879)) - hasChildren: Found subdirectories. Key:
parent, ObjectID: 1770679710930
2026-02-09 15:28:30,995 [main] WARN key.OMKeyDeleteRequestWithFSO
(OMKeyDeleteRequestWithFSO.java:validateAndUpdateCache(155)) - DELETE_KEY:
Directory not empty check FAILED. Key: parent, ObjectID: 1770679710930,
ParentObjectID: 1770679710919, recursive: false, Transaction: 1001,
ozonePathKey: /1770679710884/1770679710919/1770679710919/parent
2026-02-09 15:28:31,004 [main] ERROR key.OMKeyDeleteRequestWithFSO
(OMKeyDeleteRequestWithFSO.java:validateAndUpdateCache(236)) - Key delete
failed. Volume:084ac152-cbf9-4571-a8dd-b6b40b1e7a8e,
Bucket:1f5b5722-6fc3-4f6d-aef3-c0a9b500eabc, Key:parent.
DIRECTORY_NOT_EMPTY org.apache.hadoop.ozone.om.exceptions.OMException:
Directory is not empty. Key:parent
at
org.apache.hadoop.ozone.om.request.key.OMKeyDeleteRequestWithFSO.validateAndUpdateCache(OMKeyDeleteRequestWithFSO.java:160)
at
org.apache.hadoop.ozone.om.request.OMClientRequest.validateAndUpdateCache(OMClientRequest.java:145)
at
org.apache.hadoop.ozone.om.request.key.TestOMKeyDeleteRequestWithFSO.testDeleteParentAfterChildrenDeleted(TestOMKeyDeleteRequestWithFSO.java:414)
{code}
At this point, it is clear enough that this most likely is a cache-related
issue. It didn't take long after that to find that {{checkSubDirectoryExists}}
(and in extension, {{checkSubFileExists}}) didn't properly check for deleted
dir/file tombstones in cache.
h2. Repro
Proper unit test and integration test would be added in the PR, below is just
for illustration:
{code:java}
Path parent = new Path("/parent");
Path child = new Path(parent, "child");
fs.mkdirs(parent);
fs.mkdirs(child);
fs.delete(child, false); // Succeeds
fs.delete(parent, false); // Fails with "Directory is not empty" when double
buffer didn't flush fast enough after the immediately previous delete() call
{code}
> [FSO] Non-recursive dir deletion fails with "Directory is not empty" despite
> all child dirs deleted when double buffer is not flushed
> -------------------------------------------------------------------------------------------------------------------------------------
>
> Key: HDDS-14600
> URL: https://issues.apache.org/jira/browse/HDDS-14600
> Project: Apache Ozone
> Issue Type: Bug
> Reporter: Siyao Meng
> Priority: Major
>
> When using File System Optimized (FSO) buckets (with Ratis enabled),
> non-recursive directory deletion can fail with "Directory is not empty" error
> (also visible in OM logs, DIRECTORY_NOT_EMPTY) even after all child
> directories have been successfully deleted. This occurs when the double
> buffer hasn't flushed child delete transactions to the DB yet.
> This issue was discovered when using S3A with Hive CTAS operations but
> affects any client using the filesystem APIs.
> h2. Symptom
> Issue was initially found when using FSO bucket via S3A connector from Hive
> when creating an external table:
> {code:sql|title=SQL}
> create external table ctas_src_ext_part partitioned by (age) as select name,
> age from default.studenttab10k;
> {code}
> {code:java|title=Hive client log}
> ERROR : Job Commit failed with exception
> 'org.apache.hadoop.hive.ql.metadata.HiveException(org.apache.hadoop.fs.s3a.AWSS3IOException:
> Remove S3 Dir Markers on
> s3a://s3hive/iceberg_test_db_hive2/.hive-staging_hive_2026-02-09_19-42-25_275_4928242460862214784-9/_task_tmp.-ext-10002:
> org.apache.hadoop.fs.s3a.impl.MultiObjectDeleteException:
> [S3Error(Key=iceberg_test_db_hive2/.hive-staging_hive_2026-02-09_19-42-25_275_4928242460862214784-9/_task_tmp.-ext-10002/,
> Code=InternalError, Message=Directory is not empty.
> Key:iceberg_test_db_hive2/.hive-staging_hive_2026-02-09_19-42-25_275_4928242460862214784-9/_task_tmp.-ext-10002)]:
> InternalError:
> iceberg_test_db_hive2/.hive-staging_hive_2026-02-09_19-42-25_275_4928242460862214784-9/_task_tmp.-ext-10002/:
> Directory is not empty.
> Key:iceberg_test_db_hive2/.hive-staging_hive_2026-02-09_19-42-25_275_4928242460862214784-9/_task_tmp.-ext-10002
> :
> [S3Error(Key=iceberg_test_db_hive2/.hive-staging_hive_2026-02-09_19-42-25_275_4928242460862214784-9/_task_tmp.-ext-10002/,
> Code=InternalError, Message=Directory is not empty.
> Key:iceberg_test_db_hive2/.hive-staging_hive_2026-02-09_19-42-25_275_4928242460862214784-9/_task_tmp.-ext-10002)])'
> org.apache.hadoop.hive.ql.metadata.HiveException:
> org.apache.hadoop.fs.s3a.AWSS3IOException: Remove S3 Dir Markers on
> s3a://s3hive/iceberg_test_db_hive2/.hive-staging_hive_2026-02-09_19-42-25_275_4928242460862214784-9/_task_tmp.-ext-10002:
> org.apache.hadoop.fs.s3a.impl.MultiObjectDeleteException:
> [S3Error(Key=iceberg_test_db_hive2/.hive-staging_hive_2026-02-09_19-42-25_275_4928242460862214784-9/_task_tmp.-ext-10002/,
> Code=InternalError, Message=Directory is not empty.
> Key:iceberg_test_db_hive2/.hive-staging_hive_2026-02-09_19-42-25_275_4928242460862214784-9/_task_tmp.-ext-10002)]:
> InternalError:
> iceberg_test_db_hive2/.hive-staging_hive_2026-02-09_19-42-25_275_4928242460862214784-9/_task_tmp.-ext-10002/:
> Directory is not empty.
> Key:iceberg_test_db_hive2/.hive-staging_hive_2026-02-09_19-42-25_275_4928242460862214784-9/_task_tmp.-ext-10002
> :
> [S3Error(Key=iceberg_test_db_hive2/.hive-staging_hive_2026-02-09_19-42-25_275_4928242460862214784-9/_task_tmp.-ext-10002/,
> Code=InternalError, Message=Directory is not empty.
> Key:iceberg_test_db_hive2/.hive-staging_hive_2026-02-09_19-42-25_275_4928242460862214784-9/_task_tmp.-ext-10002)]
> at
> org.apache.hadoop.hive.ql.exec.FileSinkOperator.jobCloseOp(FileSinkOperator.java:1629)
> at org.apache.hadoop.hive.ql.exec.Operator.jobClose(Operator.java:797)
> at org.apache.hadoop.hive.ql.exec.Operator.jobClose(Operator.java:802)
> at org.apache.hadoop.hive.ql.exec.tez.TezTask.close(TezTask.java:734)
> at org.apache.hadoop.hive.ql.exec.tez.TezTask.execute(TezTask.java:394)
> at org.apache.hadoop.hive.ql.exec.Task.executeTask(Task.java:213)
> at
> org.apache.hadoop.hive.ql.exec.TaskRunner.runSequential(TaskRunner.java:105)
> at org.apache.hadoop.hive.ql.Executor.launchTask(Executor.java:356)
> at org.apache.hadoop.hive.ql.Executor.launchTasks(Executor.java:329)
> at org.apache.hadoop.hive.ql.Executor.runTasks(Executor.java:246)
> at org.apache.hadoop.hive.ql.Executor.execute(Executor.java:107)
> at org.apache.hadoop.hive.ql.Driver.runInternal(Driver.java:804)
> at org.apache.hadoop.hive.ql.Driver.run(Driver.java:539)
> at org.apache.hadoop.hive.ql.Driver.run(Driver.java:533)
> at
> org.apache.hadoop.hive.ql.reexec.ReExecDriver.run(ReExecDriver.java:190)
> at
> org.apache.hive.service.cli.operation.SQLOperation.runQuery(SQLOperation.java:235)
> at
> org.apache.hive.service.cli.operation.SQLOperation.access$700(SQLOperation.java:91)
> at
> org.apache.hive.service.cli.operation.SQLOperation$BackgroundWork$1.run(SQLOperation.java:342)
> at java.base/java.security.AccessController.doPrivileged(Native Method)
> at java.base/javax.security.auth.Subject.doAs(Subject.java:423)
> at
> org.apache.hadoop.security.UserGroupInformation.doAs(UserGroupInformation.java:1910)
> at
> org.apache.hive.service.cli.operation.SQLOperation$BackgroundWork.run(SQLOperation.java:362)
> at
> java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)
> at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
> at
> java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)
> at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
> at
> java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
> at
> java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
> at java.base/java.lang.Thread.run(Thread.java:829)
> Caused by: org.apache.hadoop.fs.s3a.AWSS3IOException: Remove S3 Dir Markers
> on
> s3a://s3hive/iceberg_test_db_hive2/.hive-staging_hive_2026-02-09_19-42-25_275_4928242460862214784-9/_task_tmp.-ext-10002:
> org.apache.hadoop.fs.s3a.impl.MultiObjectDeleteException:
> [S3Error(Key=iceberg_test_db_hive2/.hive-staging_hive_2026-02-09_19-42-25_275_4928242460862214784-9/_task_tmp.-ext-10002/,
> Code=InternalError, Message=Directory is not empty.
> Key:iceberg_test_db_hive2/.hive-staging_hive_2026-02-09_19-42-25_275_4928242460862214784-9/_task_tmp.-ext-10002)]:
> InternalError:
> iceberg_test_db_hive2/.hive-staging_hive_2026-02-09_19-42-25_275_4928242460862214784-9/_task_tmp.-ext-10002/:
> Directory is not empty.
> Key:iceberg_test_db_hive2/.hive-staging_hive_2026-02-09_19-42-25_275_4928242460862214784-9/_task_tmp.-ext-10002
> :
> [S3Error(Key=iceberg_test_db_hive2/.hive-staging_hive_2026-02-09_19-42-25_275_4928242460862214784-9/_task_tmp.-ext-10002/,
> Code=InternalError, Message=Directory is not empty.
> Key:iceberg_test_db_hive2/.hive-staging_hive_2026-02-09_19-42-25_275_4928242460862214784-9/_task_tmp.-ext-10002)]
> at
> org.apache.hadoop.fs.s3a.impl.MultiObjectDeleteException.translateException(MultiObjectDeleteException.java:101)
> at
> org.apache.hadoop.fs.s3a.S3AUtils.translateException(S3AUtils.java:347)
> at org.apache.hadoop.fs.s3a.Invoker.once(Invoker.java:124)
> at org.apache.hadoop.fs.s3a.Invoker.once(Invoker.java:163)
> at
> org.apache.hadoop.fs.s3a.impl.DeleteOperation.asyncDeleteAction(DeleteOperation.java:443)
> at
> org.apache.hadoop.fs.s3a.impl.DeleteOperation.lambda$submitDelete$2(DeleteOperation.java:401)
> at
> org.apache.hadoop.fs.store.audit.AuditingFunctions.lambda$callableWithinAuditSpan$3(AuditingFunctions.java:117)
> at
> org.apache.hadoop.fs.s3a.impl.CallableSupplier.get(CallableSupplier.java:88)
> at
> java.base/java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1700)
> at
> org.apache.hadoop.util.SemaphoredDelegatingExecutor$RunnableWithPermitRelease.run(SemaphoredDelegatingExecutor.java:226)
> at
> org.apache.hadoop.util.SemaphoredDelegatingExecutor$RunnableWithPermitRelease.run(SemaphoredDelegatingExecutor.java:226)
> ... 3 more
> Caused by: org.apache.hadoop.fs.s3a.impl.MultiObjectDeleteException:
> [S3Error(Key=iceberg_test_db_hive2/.hive-staging_hive_2026-02-09_19-42-25_275_4928242460862214784-9/_task_tmp.-ext-10002/,
> Code=InternalError, Message=Directory is not empty.
> Key:iceberg_test_db_hive2/.hive-staging_hive_2026-02-09_19-42-25_275_4928242460862214784-9/_task_tmp.-ext-10002)]
> at
> org.apache.hadoop.fs.s3a.S3AFileSystem.deleteObjects(S3AFileSystem.java:3233)
> at
> org.apache.hadoop.fs.s3a.S3AFileSystem.removeKeysS3(S3AFileSystem.java:3460)
> at
> org.apache.hadoop.fs.s3a.S3AFileSystem.removeKeys(S3AFileSystem.java:3530)
> at
> org.apache.hadoop.fs.s3a.S3AFileSystem$OperationCallbacksImpl.removeKeys(S3AFileSystem.java:2604)
> at
> org.apache.hadoop.fs.s3a.impl.DeleteOperation.lambda$asyncDeleteAction$8(DeleteOperation.java:445)
> at org.apache.hadoop.fs.s3a.Invoker.lambda$once$0(Invoker.java:165)
> at org.apache.hadoop.fs.s3a.Invoker.once(Invoker.java:122)
> ... 11 more
> {code}
> h2. Root cause analysis
> Hive initiates the call to {{fs.delete()}} on the dir with recursive set to
> true into S3A:
> {code:java|title=https://github.com/apache/hive/blob/98da62c93f198126c78d3352bf3ac6aeacefa53c/ql/src/java/org/apache/hadoop/hive/ql/exec/Utilities.java#L1535-L1536}
> Utilities.FILE_OP_LOGGER.trace("deleting taskTmpPath {}", taskTmpPath);
> fs.delete(taskTmpPath, true);
> {code}
> S3A would list and delete all keys under the dir if recursive=true:
> https://github.com/apache/hadoop/blob/e221231e81cdc4bc34ad69ca7d606a3efa8f79d1/hadoop-tools/hadoop-aws/src/main/java/org/apache/hadoop/fs/s3a/impl/DeleteOperation.java#L228
> (Thus even though Ozone S3 Gateway sets recursive=false when calling to OM,
> it would not become an issue at this point:
> https://github.com/apache/ozone/blob/9f9773df69302b0a8ee92a2c59515c37c6ac205d/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/endpoint/ObjectEndpoint.java#L720
> )
> After adding debug messages around and an attempt to repro the issue locally,
> it turns out {{OMFileRequest#checkSubDirectoryExists}} would still find the
> deleted child dir:
> {code}
> 2026-02-09 15:28:30,989 [main] DEBUG key.OMKeyDeleteRequestWithFSO
> (OMKeyDeleteRequestWithFSO.java:validateAndUpdateCache(168)) - DELETE_KEY:
> Recursive delete requested for directory. Key: parent/child, ObjectID:
> 1770679710931, Transaction: 1000
> 2026-02-09 15:28:30,991 [main] DEBUG key.OMKeyDeleteRequestWithFSO
> (OMKeyDeleteRequestWithFSO.java:validateAndUpdateCache(231)) - Key deleted.
> Volume:084ac152-cbf9-4571-a8dd-b6b40b1e7a8e,
> Bucket:1f5b5722-6fc3-4f6d-aef3-c0a9b500eabc, Key:parent/child
> 2026-02-09 15:28:30,991 [main] DEBUG key.OMKeyDeleteRequestWithFSO
> (OMKeyDeleteRequestWithFSO.java:validateAndUpdateCache(147)) - DELETE_KEY:
> Checking if directory is empty. Key: parent, ObjectID: 1770679710930,
> ParentObjectID: 1770679710919, Transaction: 1001
> 2026-02-09 15:28:30,991 [main] DEBUG file.OMFileRequest
> (OMFileRequest.java:hasChildren(871)) - hasChildren: Checking for children.
> Key: parent, ObjectID: 1770679710930, ParentObjectID: 1770679710919, Volume:
> 084ac152-cbf9-4571-a8dd-b6b40b1e7a8e, Bucket:
> 1f5b5722-6fc3-4f6d-aef3-c0a9b500eabc
> 2026-02-09 15:28:30,991 [main] DEBUG file.OMFileRequest
> (OMFileRequest.java:checkSubDirectoryExists(925)) - checkSubDirectoryExists:
> No children in cache. Key: parent, ObjectID: 1770679710930, Cache entries
> checked: 2
> 2026-02-09 15:28:30,991 [main] DEBUG file.OMFileRequest
> (OMFileRequest.java:checkSubDirectoryExists(936)) - checkSubDirectoryExists:
> Checking DB with seekKey: /1770679710884/1770679710919/1770679710930/
> 2026-02-09 15:28:30,995 [main] WARN file.OMFileRequest
> (OMFileRequest.java:checkSubDirectoryExists(950)) - checkSubDirectoryExists:
> Found child directory in DB. Parent Key: parent, Parent ObjectID:
> 1770679710930, Child Name: child, Child ObjectID: 1770679710931, Child
> ParentObjectID: 1770679710930, DB Key:
> /1770679710884/1770679710919/1770679710930/child
> 2026-02-09 15:28:30,995 [main] WARN file.OMFileRequest
> (OMFileRequest.java:hasChildren(879)) - hasChildren: Found subdirectories.
> Key: parent, ObjectID: 1770679710930
> 2026-02-09 15:28:30,995 [main] WARN key.OMKeyDeleteRequestWithFSO
> (OMKeyDeleteRequestWithFSO.java:validateAndUpdateCache(155)) - DELETE_KEY:
> Directory not empty check FAILED. Key: parent, ObjectID: 1770679710930,
> ParentObjectID: 1770679710919, recursive: false, Transaction: 1001,
> ozonePathKey: /1770679710884/1770679710919/1770679710919/parent
> 2026-02-09 15:28:31,004 [main] ERROR key.OMKeyDeleteRequestWithFSO
> (OMKeyDeleteRequestWithFSO.java:validateAndUpdateCache(236)) - Key delete
> failed. Volume:084ac152-cbf9-4571-a8dd-b6b40b1e7a8e,
> Bucket:1f5b5722-6fc3-4f6d-aef3-c0a9b500eabc, Key:parent.
> DIRECTORY_NOT_EMPTY org.apache.hadoop.ozone.om.exceptions.OMException:
> Directory is not empty. Key:parent
> at
> org.apache.hadoop.ozone.om.request.key.OMKeyDeleteRequestWithFSO.validateAndUpdateCache(OMKeyDeleteRequestWithFSO.java:160)
> at
> org.apache.hadoop.ozone.om.request.OMClientRequest.validateAndUpdateCache(OMClientRequest.java:145)
> at
> org.apache.hadoop.ozone.om.request.key.TestOMKeyDeleteRequestWithFSO.testDeleteParentAfterChildrenDeleted(TestOMKeyDeleteRequestWithFSO.java:414)
> {code}
> At this point, it is clear enough that this most likely is a cache-related
> issue. It didn't take long after that to find that
> {{checkSubDirectoryExists}} (and in extension, {{checkSubFileExists}}) didn't
> properly check for deleted dir/file tombstones in cache.
> h2. Repro
> Proper unit test and integration test would be added in the PR, below is just
> for illustration:
> {code:java}
> Path parent = new Path("/parent");
> Path child = new Path(parent, "child");
> fs.mkdirs(parent);
> fs.mkdirs(child);
> fs.delete(child, false); // Succeeds
> fs.delete(parent, false); // Fails with "Directory is not empty" when double
> buffer didn't flush fast enough after the immediately previous delete() call
> {code}
--
This message was sent by Atlassian Jira
(v8.20.10#820010)
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]