Skip to content

Commit 4fcc209

Browse files
authored
Added support to lock on version in BlobInputStream (Azure#17908)
1 parent 52cf661 commit 4fcc209

File tree

24 files changed

+4010
-147
lines changed

24 files changed

+4010
-147
lines changed

sdk/storage/azure-storage-blob/CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
# Release History
22

33
## 12.11.0-beta.1 (Unreleased)
4+
- Added support to lock on version id by specifying a consistent read control when opening a BlobInputStream.
45
- Removed a deep copy in the general upload path to reduce memory consumption and increase perf
56
- Added a deep copy immediately after calling BlobOutputStream.write to prevent overwriting data in the case of reusing a single buffer to write to an output stream
67

78
## 12.10.0 (2021-01-14)
89
- GA release
910

10-
1111
## 12.10.0-beta.1 (2020-12-07)
1212
- Exposed ClientOptions on all client builders, allowing users to set a custom application id and custom headers.
1313
- Added ability to get container client from blob clients and service client from container clients
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
package com.azure.storage.blob.models;
5+
6+
import com.azure.storage.blob.BlobClient;
7+
8+
/**
9+
* Defines values to indicate what strategy the SDK should use when reading from a blob to ensure the view of the data
10+
* is consistent and not changed during the read.
11+
* {@link #NONE}
12+
* {@link #ETAG}
13+
* {@link #VERSION_ID}
14+
*/
15+
public enum ConsistentReadControl {
16+
/**
17+
* No consistent read control. The client will honor user provided {@link BlobRequestConditions#getIfMatch()} and
18+
* {@link BlobClient#getVersionId()}.
19+
*/
20+
NONE,
21+
22+
/**
23+
* Default value. Consistent read control based on eTag.
24+
* If {@link BlobRequestConditions#getIfMatch()} is set, the client will honor this value.
25+
* Otherwise, {@link BlobRequestConditions#getIfMatch()} is set to the latest eTag.
26+
* Note: Modification of the base blob will result in an {@code IOException} or a {@code BlobStorageException} if
27+
* eTag is the only form of consistent read control being employed.
28+
*/
29+
ETAG,
30+
31+
/**
32+
* Consistent control based on versionId. Note: Versioning must be supported by the account to use this value.
33+
* If {@link BlobClient#getVersionId()} is set, the client will honor this value.
34+
* Otherwise, {@link BlobClient#getVersionId()} is set to the latest versionId.
35+
* Note: Modification of the base blob will not result in an {@code Exception} and allow you to continue reading the
36+
* entirety of the appropriate version of the blob determined at the time of opening the {@code InputStream} but it
37+
* may no longer be the latest data.
38+
*/
39+
VERSION_ID
40+
}

sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/options/BlobInputStreamOptions.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import com.azure.core.annotation.Fluent;
77
import com.azure.storage.blob.models.BlobRange;
88
import com.azure.storage.blob.models.BlobRequestConditions;
9+
import com.azure.storage.blob.models.ConsistentReadControl;
910

1011
/**
1112
* Extended options that may be passed when opening a blob input stream.
@@ -16,6 +17,7 @@ public class BlobInputStreamOptions {
1617
private BlobRange range;
1718
private BlobRequestConditions requestConditions;
1819
private Integer blockSize;
20+
private ConsistentReadControl consistentReadControl;
1921

2022
/**
2123
* @return {@link BlobRange}
@@ -68,4 +70,20 @@ public BlobInputStreamOptions setBlockSize(Integer blockSize) {
6870
this.blockSize = blockSize;
6971
return this;
7072
}
73+
74+
/**
75+
* @return {@link ConsistentReadControl} Default is E-Tag.
76+
*/
77+
public ConsistentReadControl getConsistentReadControl() {
78+
return consistentReadControl;
79+
}
80+
81+
/**
82+
* @param consistentReadControl {@link ConsistentReadControl} Default is E-Tag.
83+
* @return The updated options.
84+
*/
85+
public BlobInputStreamOptions setConsistentReadControl(ConsistentReadControl consistentReadControl) {
86+
this.consistentReadControl = consistentReadControl;
87+
return this;
88+
}
7189
}

sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/specialized/BlobClientBase.java

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import com.azure.storage.blob.BlobContainerClient;
1616
import com.azure.storage.blob.BlobServiceClient;
1717
import com.azure.storage.blob.implementation.util.ModelHelper;
18+
import com.azure.storage.blob.models.ConsistentReadControl;
1819
import com.azure.storage.blob.options.BlobBeginCopyOptions;
1920
import com.azure.storage.blob.options.BlobCopyFromUrlOptions;
2021
import com.azure.storage.blob.models.BlobProperties;
@@ -261,17 +262,43 @@ public final BlobInputStream openInputStream(BlobRange range, BlobRequestConditi
261262
*/
262263
public BlobInputStream openInputStream(BlobInputStreamOptions options) {
263264
options = options == null ? new BlobInputStreamOptions() : options;
265+
ConsistentReadControl consistentReadControl = options.getConsistentReadControl() == null
266+
? ConsistentReadControl.ETAG : options.getConsistentReadControl();
264267

265-
BlobProperties properties = getProperties();
268+
BlobProperties properties = getPropertiesWithResponse(options.getRequestConditions(), null, null).getValue();
269+
String eTag = properties.getETag();
270+
String versionId = properties.getVersionId();
266271

267272
BlobRange range = options.getRange() == null ? new BlobRange(0) : options.getRange();
268273
int chunkSize = options.getBlockSize() == null ? 4 * Constants.MB : options.getBlockSize();
269274

270275
BlobRequestConditions requestConditions = options.getRequestConditions() == null
271276
? new BlobRequestConditions() : options.getRequestConditions();
272-
// Target the user specified version by default. If not provided, target the latest version.
273-
if (requestConditions.getIfMatch() == null) {
274-
requestConditions.setIfMatch(properties.getETag());
277+
BlobAsyncClientBase client = this.client;
278+
279+
switch (consistentReadControl) {
280+
case NONE:
281+
break;
282+
case ETAG:
283+
// Target the user specified eTag by default. If not provided, target the latest eTag.
284+
if (requestConditions.getIfMatch() == null) {
285+
requestConditions.setIfMatch(eTag);
286+
}
287+
break;
288+
case VERSION_ID:
289+
if (versionId == null) {
290+
throw logger.logExceptionAsError(
291+
new UnsupportedOperationException("Versioning is not supported on this account."));
292+
} else {
293+
// Target the user specified version by default. If not provided, target the latest version.
294+
if (this.client.getVersionId() == null) {
295+
client = this.client.getVersionClient(versionId);
296+
}
297+
}
298+
break;
299+
default:
300+
throw logger.logExceptionAsError(new IllegalArgumentException("Concurrency control type not "
301+
+ "supported."));
275302
}
276303

277304
return new BlobInputStream(client, range.getOffset(), range.getCount(), chunkSize,

0 commit comments

Comments
 (0)