62
62
import software .amazon .awssdk .services .s3 .model .UploadPartRequest ;
63
63
import software .amazon .awssdk .services .s3 .model .UploadPartResponse ;
64
64
import software .amazon .awssdk .services .s3 .paginators .ListObjectsV2Iterable ;
65
+ import software .amazon .awssdk .utils .CollectionUtils ;
65
66
66
67
import org .apache .logging .log4j .LogManager ;
67
68
import org .apache .logging .log4j .Logger ;
77
78
import org .opensearch .common .blobstore .BlobPath ;
78
79
import org .opensearch .common .blobstore .BlobStoreException ;
79
80
import org .opensearch .common .blobstore .DeleteResult ;
81
+ import org .opensearch .common .blobstore .FetchBlobResult ;
80
82
import org .opensearch .common .blobstore .stream .read .ReadContext ;
81
83
import org .opensearch .common .blobstore .stream .write .WriteContext ;
82
84
import org .opensearch .common .blobstore .stream .write .WritePriority ;
@@ -139,6 +141,13 @@ public boolean blobExists(String blobName) {
139
141
}
140
142
}
141
143
144
+ @ ExperimentalApi
145
+ @ Override
146
+ public FetchBlobResult readBlobWithMetadata (String blobName ) throws IOException {
147
+ S3RetryingInputStream s3RetryingInputStream = new S3RetryingInputStream (blobStore , buildKey (blobName ));
148
+ return new FetchBlobResult (s3RetryingInputStream , s3RetryingInputStream .getMetadata ());
149
+ }
150
+
142
151
@ Override
143
152
public InputStream readBlob (String blobName ) throws IOException {
144
153
return new S3RetryingInputStream (blobStore , buildKey (blobName ));
@@ -170,12 +179,27 @@ public long readBlobPreferredLength() {
170
179
*/
171
180
@ Override
172
181
public void writeBlob (String blobName , InputStream inputStream , long blobSize , boolean failIfAlreadyExists ) throws IOException {
182
+ writeBlobWithMetadata (blobName , inputStream , blobSize , failIfAlreadyExists , null );
183
+ }
184
+
185
+ /**
186
+ * Write blob with its object metadata.
187
+ */
188
+ @ ExperimentalApi
189
+ @ Override
190
+ public void writeBlobWithMetadata (
191
+ String blobName ,
192
+ InputStream inputStream ,
193
+ long blobSize ,
194
+ boolean failIfAlreadyExists ,
195
+ @ Nullable Map <String , String > metadata
196
+ ) throws IOException {
173
197
assert inputStream .markSupported () : "No mark support on inputStream breaks the S3 SDK's ability to retry requests" ;
174
198
SocketAccess .doPrivilegedIOException (() -> {
175
199
if (blobSize <= getLargeBlobThresholdInBytes ()) {
176
- executeSingleUpload (blobStore , buildKey (blobName ), inputStream , blobSize );
200
+ executeSingleUpload (blobStore , buildKey (blobName ), inputStream , blobSize , metadata );
177
201
} else {
178
- executeMultipartUpload (blobStore , buildKey (blobName ), inputStream , blobSize );
202
+ executeMultipartUpload (blobStore , buildKey (blobName ), inputStream , blobSize , metadata );
179
203
}
180
204
return null ;
181
205
});
@@ -191,7 +215,8 @@ public void asyncBlobUpload(WriteContext writeContext, ActionListener<Void> comp
191
215
writeContext .getUploadFinalizer (),
192
216
writeContext .doRemoteDataIntegrityCheck (),
193
217
writeContext .getExpectedChecksum (),
194
- blobStore .isUploadRetryEnabled ()
218
+ blobStore .isUploadRetryEnabled (),
219
+ writeContext .getMetadata ()
195
220
);
196
221
try {
197
222
// If file size is greater than the queue capacity than SizeBasedBlockingQ will always reject the upload.
@@ -211,7 +236,8 @@ public void asyncBlobUpload(WriteContext writeContext, ActionListener<Void> comp
211
236
blobStore ,
212
237
uploadRequest .getKey (),
213
238
inputStream .getInputStream (),
214
- uploadRequest .getContentLength ()
239
+ uploadRequest .getContentLength (),
240
+ uploadRequest .getMetadata ()
215
241
);
216
242
completionListener .onResponse (null );
217
243
} catch (Exception ex ) {
@@ -582,8 +608,13 @@ private String buildKey(String blobName) {
582
608
/**
583
609
* Uploads a blob using a single upload request
584
610
*/
585
- void executeSingleUpload (final S3BlobStore blobStore , final String blobName , final InputStream input , final long blobSize )
586
- throws IOException {
611
+ void executeSingleUpload (
612
+ final S3BlobStore blobStore ,
613
+ final String blobName ,
614
+ final InputStream input ,
615
+ final long blobSize ,
616
+ final Map <String , String > metadata
617
+ ) throws IOException {
587
618
588
619
// Extra safety checks
589
620
if (blobSize > MAX_FILE_SIZE .getBytes ()) {
@@ -600,6 +631,10 @@ void executeSingleUpload(final S3BlobStore blobStore, final String blobName, fin
600
631
.storageClass (blobStore .getStorageClass ())
601
632
.acl (blobStore .getCannedACL ())
602
633
.overrideConfiguration (o -> o .addMetricPublisher (blobStore .getStatsMetricPublisher ().putObjectMetricPublisher ));
634
+
635
+ if (CollectionUtils .isNotEmpty (metadata )) {
636
+ putObjectRequestBuilder = putObjectRequestBuilder .metadata (metadata );
637
+ }
603
638
if (blobStore .serverSideEncryption ()) {
604
639
putObjectRequestBuilder .serverSideEncryption (ServerSideEncryption .AES256 );
605
640
}
@@ -623,8 +658,13 @@ void executeSingleUpload(final S3BlobStore blobStore, final String blobName, fin
623
658
/**
624
659
* Uploads a blob using multipart upload requests.
625
660
*/
626
- void executeMultipartUpload (final S3BlobStore blobStore , final String blobName , final InputStream input , final long blobSize )
627
- throws IOException {
661
+ void executeMultipartUpload (
662
+ final S3BlobStore blobStore ,
663
+ final String blobName ,
664
+ final InputStream input ,
665
+ final long blobSize ,
666
+ final Map <String , String > metadata
667
+ ) throws IOException {
628
668
629
669
ensureMultiPartUploadSize (blobSize );
630
670
final long partSize = blobStore .bufferSizeInBytes ();
@@ -649,6 +689,10 @@ void executeMultipartUpload(final S3BlobStore blobStore, final String blobName,
649
689
.acl (blobStore .getCannedACL ())
650
690
.overrideConfiguration (o -> o .addMetricPublisher (blobStore .getStatsMetricPublisher ().multipartUploadMetricCollector ));
651
691
692
+ if (CollectionUtils .isNotEmpty (metadata )) {
693
+ createMultipartUploadRequestBuilder .metadata (metadata );
694
+ }
695
+
652
696
if (blobStore .serverSideEncryption ()) {
653
697
createMultipartUploadRequestBuilder .serverSideEncryption (ServerSideEncryption .AES256 );
654
698
}
0 commit comments