Skip to content

Commit 25c8ba8

Browse files
BlobLeaseCLient updates itself (Azure#20799)
* BlobLeaseCLient updates itself BlobLeaseClient will always update its internal leaseId field to match the value from the last service response it recieved. This makes it possible to use changeLease without needing to discard a lease client in favor of a new one. * Datalake tests for lease client changes * Checkstyle suppression and volatile lease id * Removed line specificatino on checkstyle suppression * lease id .map() to .doOnSuccess() * changelog Co-authored-by: jschrepp-MSFT <[email protected]>
1 parent c7f1426 commit 25c8ba8

File tree

5 files changed

+105
-30
lines changed

5 files changed

+105
-30
lines changed

eng/code-quality-reports/src/main/resources/checkstyle/checkstyle-suppressions.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,9 @@ the main ServiceBusClientBuilder. -->
134134
files="com.azure.storage.blob.BlobAsyncClient.java"/>
135135
<suppress checks="com.azure.tools.checkstyle.checks.ServiceClientCheck"
136136
files="com.azure.storage.blob.BlobClient.java"/>
137+
<!-- Suppress client mutability check since LeaseClients need to update a changing lease ID -->
138+
<suppress checks="com.azure.tools.checkstyle.checks.ServiceClientCheck"
139+
files="com.azure.storage.blob.specialized.BlobLeaseAsyncClient.java"/>
137140

138141
<!-- Any code in any package, it should never be a 'throw' keyword in the client library codebase except for in the client logger -->
139142
<suppress checks="com.azure.tools.checkstyle.checks.ThrowFromClientLoggerCheck"

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

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -61,10 +61,11 @@ public final class BlobLeaseAsyncClient {
6161
private final String containerName;
6262
private final String blobName;
6363
private final boolean isBlob;
64-
private final String leaseId;
6564
private final AzureBlobStorageImpl client;
6665
private final String accountName;
6766

67+
private volatile String leaseId;
68+
6869
BlobLeaseAsyncClient(HttpPipeline pipeline, String url, String containerName, String blobName, String leaseId,
6970
boolean isBlob, String accountName, String serviceVersion) {
7071
this.isBlob = isBlob;
@@ -174,19 +175,24 @@ Mono<Response<String>> acquireLeaseWithResponse(BlobAcquireLeaseOptions options,
174175
BlobLeaseRequestConditions requestConditions = (options.getRequestConditions() == null)
175176
? new BlobLeaseRequestConditions() : options.getRequestConditions();
176177
context = context == null ? Context.NONE : context;
178+
179+
Mono<Response<String>> response;
177180
if (this.isBlob) {
178-
return this.client.getBlobs().acquireLeaseWithResponseAsync(containerName, blobName, null,
181+
response = this.client.getBlobs().acquireLeaseWithResponseAsync(containerName, blobName, null,
179182
options.getDuration(), this.leaseId, requestConditions.getIfModifiedSince(),
180183
requestConditions.getIfUnmodifiedSince(), requestConditions.getIfMatch(),
181184
requestConditions.getIfNoneMatch(), requestConditions.getTagsConditions(), null,
182185
context.addData(AZ_TRACING_NAMESPACE_KEY, STORAGE_TRACING_NAMESPACE_VALUE))
183186
.map(rb -> new SimpleResponse<>(rb, rb.getDeserializedHeaders().getXMsLeaseId()));
184187
} else {
185-
return this.client.getContainers().acquireLeaseWithResponseAsync(containerName, null,
188+
response = this.client.getContainers().acquireLeaseWithResponseAsync(containerName, null,
186189
options.getDuration(), this.leaseId, requestConditions.getIfModifiedSince(),
187190
requestConditions.getIfUnmodifiedSince(), null, context)
188191
.map(rb -> new SimpleResponse<>(rb, rb.getDeserializedHeaders().getXMsLeaseId()));
189192
}
193+
194+
response = response.doOnSuccess(r -> this.leaseId = r.getValue());
195+
return response;
190196
}
191197

192198
/**
@@ -254,19 +260,24 @@ Mono<Response<String>> renewLeaseWithResponse(BlobRenewLeaseOptions options, Con
254260
BlobLeaseRequestConditions requestConditions = (options.getRequestConditions() == null)
255261
? new BlobLeaseRequestConditions() : options.getRequestConditions();
256262
context = context == null ? Context.NONE : context;
263+
264+
Mono<Response<String>> response;
257265
if (this.isBlob) {
258-
return this.client.getBlobs().renewLeaseWithResponseAsync(containerName, blobName, this.leaseId, null,
266+
response = this.client.getBlobs().renewLeaseWithResponseAsync(containerName, blobName, this.leaseId, null,
259267
requestConditions.getIfModifiedSince(), requestConditions.getIfUnmodifiedSince(),
260268
requestConditions.getIfMatch(), requestConditions.getIfNoneMatch(),
261269
requestConditions.getTagsConditions(), null,
262270
context.addData(AZ_TRACING_NAMESPACE_KEY, STORAGE_TRACING_NAMESPACE_VALUE))
263271
.map(rb -> new SimpleResponse<>(rb, rb.getDeserializedHeaders().getXMsLeaseId()));
264272
} else {
265-
return this.client.getContainers().renewLeaseWithResponseAsync(containerName, this.leaseId, null,
273+
response = this.client.getContainers().renewLeaseWithResponseAsync(containerName, this.leaseId, null,
266274
requestConditions.getIfModifiedSince(), requestConditions.getIfUnmodifiedSince(),
267275
null, context.addData(AZ_TRACING_NAMESPACE_KEY, STORAGE_TRACING_NAMESPACE_VALUE))
268276
.map(rb -> new SimpleResponse<>(rb, rb.getDeserializedHeaders().getXMsLeaseId()));
269277
}
278+
279+
response = response.doOnSuccess(r -> this.leaseId = r.getValue());
280+
return response;
270281
}
271282

272283
/**
@@ -513,20 +524,25 @@ Mono<Response<String>> changeLeaseWithResponse(BlobChangeLeaseOptions options, C
513524
BlobLeaseRequestConditions requestConditions = (options.getRequestConditions() == null)
514525
? new BlobLeaseRequestConditions() : options.getRequestConditions();
515526
context = context == null ? Context.NONE : context;
527+
528+
Mono<Response<String>> response;
516529
if (this.isBlob) {
517-
return this.client.getBlobs().changeLeaseWithResponseAsync(containerName, blobName, this.leaseId,
530+
response = this.client.getBlobs().changeLeaseWithResponseAsync(containerName, blobName, this.leaseId,
518531
options.getProposedId(), null, requestConditions.getIfModifiedSince(),
519532
requestConditions.getIfUnmodifiedSince(), requestConditions.getIfMatch(),
520533
requestConditions.getIfNoneMatch(), requestConditions.getTagsConditions(), null,
521534
context.addData(AZ_TRACING_NAMESPACE_KEY, STORAGE_TRACING_NAMESPACE_VALUE))
522535
.map(rb -> new SimpleResponse<>(rb, rb.getDeserializedHeaders().getXMsLeaseId()));
523536
} else {
524-
return this.client.getContainers().changeLeaseWithResponseAsync(containerName, this.leaseId,
537+
response = this.client.getContainers().changeLeaseWithResponseAsync(containerName, this.leaseId,
525538
options.getProposedId(), null, requestConditions.getIfModifiedSince(),
526539
requestConditions.getIfUnmodifiedSince(), null,
527540
context.addData(AZ_TRACING_NAMESPACE_KEY, STORAGE_TRACING_NAMESPACE_VALUE))
528541
.map(rb -> new SimpleResponse<>(rb, rb.getDeserializedHeaders().getXMsLeaseId()));
529542
}
543+
544+
response = response.doOnSuccess(r -> this.leaseId = r.getValue());
545+
return response;
530546
}
531547

532548
/**

sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/specialized/LeaseAPITest.groovy

Lines changed: 46 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,17 @@ class LeaseAPITest extends APISpec {
3232
def bc = createBlobClient()
3333
def leaseClient = createLeaseClient(bc, proposedID)
3434

35+
expect:
36+
if (proposedID != null) {
37+
assert leaseClient.getLeaseId() == proposedID
38+
}
39+
3540
when:
3641
def leaseId = leaseClient.acquireLease(leaseTime)
3742

3843
then:
3944
leaseId != null
45+
leaseClient.getLeaseId() == leaseId
4046

4147
when:
4248
def response = bc.getPropertiesWithResponse(null, null, null)
@@ -152,15 +158,18 @@ class LeaseAPITest extends APISpec {
152158
setup:
153159
def bc = createBlobClient()
154160
def leaseID = setupBlobLeaseCondition(bc, receivedLeaseID)
161+
def leaseClient = createLeaseClient(bc, leaseID)
155162

163+
when:
156164
// If running in live mode wait for the lease to expire to ensure we are actually renewing it
157165
sleepIfRecord(16000)
158-
def renewLeaseResponse = createLeaseClient(bc, leaseID).renewLeaseWithResponse(new BlobRenewLeaseOptions(), null, null)
166+
def renewLeaseResponse = leaseClient.renewLeaseWithResponse(new BlobRenewLeaseOptions(), null, null)
159167

160-
expect:
168+
then:
161169
bc.getProperties().getLeaseState() == LeaseStateType.LEASED
162170
validateBasicHeaders(renewLeaseResponse.getHeaders())
163171
renewLeaseResponse.getValue() != null
172+
renewLeaseResponse.getValue() == leaseClient.getLeaseId()
164173
}
165174

166175
def "Renew blob lease min"() {
@@ -437,10 +446,19 @@ class LeaseAPITest extends APISpec {
437446
def bc = createBlobClient()
438447
def leaseClient = createLeaseClient(bc, getRandomUUID())
439448
leaseClient.acquireLease(15)
440-
def changeLeaseResponse = leaseClient.changeLeaseWithResponse(new BlobChangeLeaseOptions(getRandomUUID()), null, null)
449+
450+
when:
451+
def newLeaseId = getRandomUUID()
452+
def changeLeaseResponse = leaseClient.changeLeaseWithResponse(new BlobChangeLeaseOptions(newLeaseId), null, null)
453+
454+
then:
455+
changeLeaseResponse.getValue() == newLeaseId
456+
changeLeaseResponse.getValue() == leaseClient.getLeaseId()
457+
458+
when:
441459
def leaseClient2 = createLeaseClient(bc, changeLeaseResponse.getValue())
442460

443-
expect:
461+
then:
444462
leaseClient2.releaseLeaseWithResponse(new BlobReleaseLeaseOptions(), null, null).getStatusCode() == 200
445463
validateBasicHeaders(changeLeaseResponse.getHeaders())
446464
}
@@ -526,7 +544,13 @@ class LeaseAPITest extends APISpec {
526544
@Unroll
527545
def "Acquire container lease"() {
528546
setup:
529-
def leaseResponse = createLeaseClient(cc, proposedID).acquireLeaseWithResponse(new BlobAcquireLeaseOptions(leaseTime), null, null)
547+
def leaseClient = createLeaseClient(cc, proposedID)
548+
549+
when:
550+
def leaseResponse = leaseClient.acquireLeaseWithResponse(new BlobAcquireLeaseOptions(leaseTime), null, null)
551+
552+
then:
553+
leaseResponse.getValue() == leaseClient.getLeaseId()
530554

531555
when:
532556
def properties = cc.getProperties()
@@ -619,12 +643,15 @@ class LeaseAPITest extends APISpec {
619643
def "Renew container lease"() {
620644
setup:
621645
def leaseID = setupContainerLeaseCondition(cc, receivedLeaseID)
646+
def leaseClient = createLeaseClient(cc, leaseID)
622647

648+
when:
623649
// If running in live mode wait for the lease to expire to ensure we are actually renewing it
624650
sleepIfRecord(16000)
625-
def renewLeaseResponse = createLeaseClient(cc, leaseID).renewLeaseWithResponse(new BlobRenewLeaseOptions(), null, null)
651+
def renewLeaseResponse = leaseClient.renewLeaseWithResponse(new BlobRenewLeaseOptions(), null, null)
626652

627-
expect:
653+
then:
654+
renewLeaseResponse.getValue() == leaseClient.getLeaseId()
628655
cc.getProperties().getLeaseState() == LeaseStateType.LEASED
629656
validateBasicHeaders(renewLeaseResponse.getHeaders())
630657
}
@@ -880,12 +907,21 @@ class LeaseAPITest extends APISpec {
880907
setup:
881908
def leaseID = setupContainerLeaseCondition(cc, receivedLeaseID)
882909
def leaseClient = createLeaseClient(cc, leaseID)
883-
def changeLeaseResponse = leaseClient.changeLeaseWithResponse(new BlobChangeLeaseOptions(getRandomUUID()), null, null)
884-
leaseID = changeLeaseResponse.getValue()
885910

886911
expect:
887-
createLeaseClient(cc, leaseID).releaseLeaseWithResponse(new BlobReleaseLeaseOptions(), null, null).getStatusCode() == 200
912+
leaseClient.getLeaseId() == leaseID
913+
914+
when:
915+
def changeLeaseResponse = leaseClient.changeLeaseWithResponse(new BlobChangeLeaseOptions(getRandomUUID()), null, null)
916+
917+
then:
888918
validateBasicHeaders(changeLeaseResponse.getHeaders())
919+
def newLeaseId = changeLeaseResponse.getValue()
920+
newLeaseId == leaseClient.getLeaseId()
921+
newLeaseId != leaseID
922+
923+
expect:
924+
createLeaseClient(cc, newLeaseId).releaseLeaseWithResponse(new BlobReleaseLeaseOptions(), null, null).getStatusCode() == 200
889925
}
890926

891927
def "Change container lease min"() {

sdk/storage/azure-storage-file-datalake/src/test/java/com/azure/storage/file/datalake/specialized/LeaseAPITest.groovy

Lines changed: 32 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ class LeaseAPITest extends APISpec {
2929

3030
then:
3131
leaseId != null
32+
leaseId == leaseClient.getLeaseId()
3233

3334
when:
3435
def response = fc.getPropertiesWithResponse(null, null, null)
@@ -137,15 +138,18 @@ class LeaseAPITest extends APISpec {
137138
setup:
138139
def fc = createPathClient()
139140
def leaseID = setupPathLeaseCondition(fc, APISpec.receivedLeaseID)
141+
def leaseClient = createLeaseClient(fc, leaseID)
140142

143+
when:
141144
// If running in live mode wait for the lease to expire to ensure we are actually renewing it
142145
sleepIfRecord(16000)
143-
def renewLeaseResponse = createLeaseClient(fc, leaseID).renewLeaseWithResponse(null, null, null)
146+
def renewLeaseResponse = leaseClient.renewLeaseWithResponse(null, null, null)
144147

145-
expect:
148+
then:
146149
fc.getProperties().getLeaseState() == LeaseStateType.LEASED
147150
validateBasicHeaders(renewLeaseResponse.getHeaders())
148151
renewLeaseResponse.getValue() != null
152+
renewLeaseResponse.getValue() == leaseClient.getLeaseId()
149153
}
150154

151155
def "Renew file lease min"() {
@@ -401,12 +405,18 @@ class LeaseAPITest extends APISpec {
401405
def fc = createPathClient()
402406
def leaseClient = createLeaseClient(fc, getRandomUUID())
403407
leaseClient.acquireLease(15)
404-
def changeLeaseResponse = leaseClient.changeLeaseWithResponse(getRandomUUID(), null, null, null)
405-
def leaseClient2 = createLeaseClient(fc, changeLeaseResponse.getValue())
406408

407-
expect:
408-
leaseClient2.releaseLeaseWithResponse(null, null, null).getStatusCode() == 200
409+
when:
410+
def newLeaseId = getRandomUUID()
411+
def changeLeaseResponse = leaseClient.changeLeaseWithResponse(newLeaseId, null, null, null)
412+
413+
then:
409414
validateBasicHeaders(changeLeaseResponse.getHeaders())
415+
changeLeaseResponse.getValue() == leaseClient.getLeaseId()
416+
417+
expect:
418+
createLeaseClient(fc, changeLeaseResponse.getValue())
419+
.releaseLeaseWithResponse(null, null, null).getStatusCode() == 200
410420
}
411421

412422
def "Change file lease min"() {
@@ -483,14 +493,16 @@ class LeaseAPITest extends APISpec {
483493
@Unroll
484494
def "Acquire file system lease"() {
485495
setup:
486-
def leaseResponse = createLeaseClient(fsc, proposedID).acquireLeaseWithResponse(leaseTime, null, null, null)
496+
def leaseClient = createLeaseClient(fsc, proposedID)
497+
def leaseResponse = leaseClient.acquireLeaseWithResponse(leaseTime, null, null, null)
487498

488499
when:
489500
def properties = fsc.getProperties()
490501

491502
then:
492503
leaseResponse.getValue() != null
493504
validateBasicHeaders(leaseResponse.getHeaders())
505+
leaseResponse.getValue() == leaseClient.getLeaseId()
494506
properties.getLeaseState() == leaseState
495507
properties.getLeaseDuration() == leaseDuration
496508

@@ -576,14 +588,17 @@ class LeaseAPITest extends APISpec {
576588
def "Renew file system lease"() {
577589
setup:
578590
def leaseID = setupFileSystemLeaseCondition(fsc, APISpec.receivedLeaseID)
591+
def leaseClient = createLeaseClient(fsc, leaseID)
579592

593+
when:
580594
// If running in live mode wait for the lease to expire to ensure we are actually renewing it
581595
sleepIfRecord(16000)
582-
def renewLeaseResponse = createLeaseClient(fsc, leaseID).renewLeaseWithResponse(null, null, null)
596+
def renewLeaseResponse = leaseClient.renewLeaseWithResponse(null, null, null)
583597

584-
expect:
598+
then:
585599
fsc.getProperties().getLeaseState() == LeaseStateType.LEASED
586600
validateBasicHeaders(renewLeaseResponse.getHeaders())
601+
renewLeaseResponse.getValue() == leaseClient.getLeaseId()
587602
}
588603

589604
def "Renew file system lease min"() {
@@ -837,12 +852,17 @@ class LeaseAPITest extends APISpec {
837852
setup:
838853
def leaseID = setupFileSystemLeaseCondition(fsc, APISpec.receivedLeaseID)
839854
def leaseClient = createLeaseClient(fsc, leaseID)
855+
856+
when:
840857
def changeLeaseResponse = leaseClient.changeLeaseWithResponse(getRandomUUID(), null, null, null)
841-
leaseID = changeLeaseResponse.getValue()
858+
def newLeaseId = changeLeaseResponse.getValue()
842859

843-
expect:
844-
createLeaseClient(fsc, leaseID).releaseLeaseWithResponse(null, null, null).getStatusCode() == 200
860+
then:
845861
validateBasicHeaders(changeLeaseResponse.getHeaders())
862+
newLeaseId == leaseClient.getLeaseId()
863+
864+
expect:
865+
createLeaseClient(fsc, newLeaseId).releaseLeaseWithResponse(null, null, null).getStatusCode() == 200
846866
}
847867

848868
def "Change file system lease min"() {

sdk/storage/azure-storage-file-share/CHANGELOG.md

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

33
## 12.9.0-beta.4 (Unreleased)
4-
4+
- BlobLeaseClient now remembers the Lease ID after a lease change.
55

66
## 12.9.0-beta.3 (2021-04-16)
77
- Updated azure-storage-common dependencies.

0 commit comments

Comments
 (0)