Skip to content

MinioAsyncClient#uploadSnowballObjects may close RandomAccessFile before asynchronous upload completes when using stagingFilename #1718

Description

@MILK597

SDK Version

minio-java 9.0.3

Description

When stagingFilename is used, uploadSnowballObjects() opens the generated TAR file with RandomAccessFile inside a try-with-resources block:

try (RandomAccessFile file = new RandomAccessFile(args.stagingFilename(), "r")) {
  return putObject(new PutObjectAPIArgs(args, file, length, headers));
}

However, putObject() returns a CompletableFuture, and the HTTP request is executed asynchronously.

This means the RandomAccessFile may be closed immediately after putObject() returns, while the HTTP request is still reading from it.

Potential sequence:

    open `RandomAccessFile`
            ↓
    `putObject()` enqueues async HTTP request
            ↓
   ` putObject()` returns `CompletableFuture`
            ↓
    try-with-resources closes `RandomAccessFile`
            ↓
    HTTP request tries to read from the closed file

Reproduction

  MinioClient client =
      MinioClient.builder()
              .credentials("minio", "Minio@123")
              .endpoint("http://192.168.1.10:9000")
              .build();

  client
          .uploadSnowballObjects(
                  UploadSnowballObjectsArgs
                          .builder()
                          .bucket("migration")
                          .objects(
                                  List.of(
                                          new SnowballObject("test/test.docx", "/tmp/output.docx")
                                  )
                          )
                          .stagingFilename("/tmp/test.tar")
                          .build()
          );

Result

The upload may fail while OkHttp is reading the request body because the underlying RandomAccessFile has already been closed.

For example, an exception similar to the following may occur:

Exception in thread "main" io.minio.errors.MinioException: java.io.IOException: Stream Closed
	at io.minio.Http$RequestBody.<init>(Http.java:1046)
	at io.minio.Http$Body.toRequestBody(Http.java:994)
	at io.minio.Http$S3Request.toRequest(Http.java:1798)
	at io.minio.Http$S3Request.toRequest(Http.java:1859)
	at io.minio.BaseS3Client.executeAsync(BaseS3Client.java:345)
	at io.minio.BaseS3Client.lambda$executeAsync$1(BaseS3Client.java:519)
	at java.base/java.util.concurrent.CompletableFuture$UniCompose.tryFire(CompletableFuture.java:1150)
	at java.base/java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:510)
	at java.base/java.util.concurrent.CompletableFuture.complete(CompletableFuture.java:2147)
	at io.minio.BaseS3Client$1.onResponse(BaseS3Client.java:381)
	at io.minio.BaseS3Client$1.onResponse(BaseS3Client.java:367)
	at okhttp3.internal.connection.RealCall$AsyncCall.run(RealCall.kt:519)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
	at java.base/java.lang.Thread.run(Thread.java:842)
Caused by: java.io.IOException: Stream Closed
	at java.base/java.io.RandomAccessFile.getFilePointer(Native Method)
	at io.minio.Http$RequestBody.<init>(Http.java:1044)

Expected Behavior

The RandomAccessFile should remain open until the asynchronous upload completes.

Could you please confirm whether this is a resource lifecycle issue in MinioAsyncClient#uploadSnowballObjects()?

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions