Skip to content
This repository was archived by the owner on Jul 19, 2024. It is now read-only.

Commit b0e4667

Browse files
author
jofriedm-msft
authored
Merge pull request #74 from jofriedm-msft/dev
Dev
2 parents 5cd406b + aff76b9 commit b0e4667

File tree

7 files changed

+295
-51
lines changed

7 files changed

+295
-51
lines changed

ChangeLog.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
1+
2017.XX.XX Version X.X.X
2+
* Added ErrorReceivingResponseEvent which fires when a network error occurs before the responseReceivedEvent fires. If the responseReceivedEvent fires sucessfully, this new event will not fire.
3+
14
2017.06.21 Version 5.3.1
25
* Fixed a bug in specific upload case for block blobs. This only affects uploads greater than the max put blob threshold, that have increased the streamWriteSizeInBytes beyond the 4 MB and storeBlobContentMD5 has been disabled.
6+
* In some cases in the above mentioned upload path, fixed a bug where StorageExceptions were being thrown instead of IOExceptions.
37

48
2017.06.13 Version 5.3.0
59
* Fixed a bug where the transactional MD5 check would fail when downloading a range of blob or file and the recovery action is performed on a subsection of the range.

microsoft-azure-storage-test/src/com/microsoft/azure/storage/EventFiringTests.java

Lines changed: 100 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,18 +14,20 @@
1414
*/
1515
package com.microsoft.azure.storage;
1616

17-
import com.microsoft.azure.storage.blob.BlobRequestOptions;
18-
import com.microsoft.azure.storage.blob.CloudBlobClient;
19-
import com.microsoft.azure.storage.blob.CloudBlobContainer;
17+
import com.microsoft.azure.storage.blob.*;
2018
import com.microsoft.azure.storage.core.SR;
2119
import com.microsoft.azure.storage.TestRunners.CloudTests;
2220
import com.microsoft.azure.storage.TestRunners.DevFabricTests;
2321
import com.microsoft.azure.storage.TestRunners.DevStoreTests;
2422

23+
import org.apache.http.protocol.HTTP;
2524
import org.junit.Test;
2625
import org.junit.experimental.categories.Category;
2726

27+
import java.io.ByteArrayInputStream;
28+
import java.io.IOException;
2829
import java.net.HttpURLConnection;
30+
import java.net.SocketException;
2931
import java.net.URISyntaxException;
3032
import java.util.ArrayList;
3133

@@ -111,6 +113,22 @@ public void eventOccurred(ResponseReceivedEvent eventArg) {
111113
}
112114
});
113115

116+
eventContext.getErrorReceivingResponseEventHandler().addListener(new StorageEvent<ErrorReceivingResponseEvent>() {
117+
118+
@Override
119+
public void eventOccurred(ErrorReceivingResponseEvent eventArg) {
120+
fail("This event should not trigger");
121+
}
122+
});
123+
124+
OperationContext.getGlobalErrorReceivingResponseEventHandler().addListener(new StorageEvent<ErrorReceivingResponseEvent>() {
125+
126+
@Override
127+
public void eventOccurred(ErrorReceivingResponseEvent eventArg) {
128+
fail("This event should not trigger");
129+
}
130+
});
131+
114132
assertEquals(0, callList.size());
115133
assertEquals(0, globalCallList.size());
116134

@@ -138,6 +156,85 @@ public void eventOccurred(ResponseReceivedEvent eventArg) {
138156
assertEquals(2, globalCallList.size());
139157
}
140158

159+
@Test
160+
public void testErrorReceivingResponseEvent() throws URISyntaxException, StorageException {
161+
final ArrayList<Boolean> callList = new ArrayList<Boolean>();
162+
final ArrayList<Boolean> globalCallList = new ArrayList<Boolean>();
163+
164+
OperationContext eventContext = new OperationContext();
165+
BlobRequestOptions options = new BlobRequestOptions();
166+
options.setRetryPolicyFactory(new RetryNoRetry());
167+
168+
// setting the sending request event handler to trigger an exception.
169+
// this is a retryable exception
170+
eventContext.getSendingRequestEventHandler().addListener(new StorageEvent<SendingRequestEvent>() {
171+
@Override
172+
public void eventOccurred(SendingRequestEvent eventArg) {
173+
HttpURLConnection connection = (HttpURLConnection) eventArg.getConnectionObject();
174+
connection.setFixedLengthStreamingMode(0);
175+
}
176+
});
177+
178+
eventContext.getErrorReceivingResponseEventHandler().addListener(new StorageEvent<ErrorReceivingResponseEvent>() {
179+
@Override
180+
public void eventOccurred(ErrorReceivingResponseEvent eventArg) {
181+
assertEquals(eventArg.getRequestResult(), eventArg.getOpContext().getLastResult());
182+
callList.add(true);
183+
}
184+
});
185+
186+
OperationContext.getGlobalErrorReceivingResponseEventHandler().addListener(new StorageEvent<ErrorReceivingResponseEvent>() {
187+
@Override
188+
public void eventOccurred(ErrorReceivingResponseEvent eventArg) {
189+
assertEquals(eventArg.getRequestResult(), eventArg.getOpContext().getLastResult());
190+
globalCallList.add(true);
191+
}
192+
});
193+
194+
CloudBlobClient blobClient = TestHelper.createCloudBlobClient();
195+
CloudBlobContainer container = blobClient.getContainerReference("container1");
196+
container.createIfNotExists();
197+
198+
try {
199+
CloudBlockBlob blob1 = container.getBlockBlobReference("blob1");
200+
try {
201+
String blockID = String.format("%08d", 1);
202+
blob1.uploadBlock(blockID, BlobTestHelper.getRandomDataStream(10), 10, null, options, eventContext);
203+
} catch (Exception e) { }
204+
205+
// make sure both the local and globab context update
206+
assertEquals(1, callList.size());
207+
assertEquals(1, globalCallList.size());
208+
209+
// make sure only global updates by replacing the local with a no-op event
210+
eventContext
211+
.setErrorReceivingResponseEventHandler(new StorageEventMultiCaster<ErrorReceivingResponseEvent, StorageEvent<ErrorReceivingResponseEvent>>());
212+
try {
213+
String blockID2 = String.format("%08d", 2);
214+
blob1.uploadBlock(blockID2, BlobTestHelper.getRandomDataStream(10), 10, null, options, eventContext);
215+
} catch (Exception e) { }
216+
217+
assertEquals(1, callList.size());
218+
assertEquals(2, globalCallList.size());
219+
220+
// make sure global does not update by replacing the global with a no-op
221+
OperationContext
222+
.setGlobalErrorReceivingResponseEventHandler(new StorageEventMultiCaster<ErrorReceivingResponseEvent, StorageEvent<ErrorReceivingResponseEvent>>());
223+
224+
// make sure neither update
225+
try {
226+
String blockID3 = String.format("%08d", 3);
227+
blob1.uploadBlock(blockID3, BlobTestHelper.getRandomDataStream(10), 10, null, options, eventContext);
228+
} catch (Exception e) { }
229+
230+
assertEquals(1, callList.size());
231+
assertEquals(2, globalCallList.size());
232+
}
233+
finally {
234+
container.deleteIfExists();
235+
}
236+
}
237+
141238
@Test
142239
public void testRequestCompletedEvents() throws URISyntaxException, StorageException {
143240
final ArrayList<Boolean> callList = new ArrayList<Boolean>();

microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudPageBlobTests.java

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1200,4 +1200,36 @@ else if (overload == 2) {
12001200
assertNotNull(copy.properties.getCopyState().getCopyDestinationSnapshotID());
12011201
assertNotNull(copy.getCopyState().getCompletionTime());
12021202
}
1203+
1204+
@Test
1205+
public void testEightTBBlob() throws StorageException, URISyntaxException, IOException {
1206+
CloudPageBlob blob = this.container.getPageBlobReference("blob1");
1207+
CloudPageBlob blob2 = this.container.getPageBlobReference("blob1");
1208+
1209+
long eightTb = 8L * 1024L * 1024L * 1024L * 1024L;
1210+
blob.create(eightTb);
1211+
assertEquals(eightTb, blob.getProperties().getLength());
1212+
1213+
blob2.downloadAttributes();
1214+
assertEquals(eightTb, blob2.getProperties().getLength());
1215+
1216+
for (ListBlobItem listBlob : this.container.listBlobs()) {
1217+
CloudPageBlob listPageBlob = (CloudPageBlob)listBlob;
1218+
assertEquals(eightTb, listPageBlob.getProperties().getLength());
1219+
}
1220+
1221+
CloudPageBlob blob3 = this.container.getPageBlobReference("blob3");
1222+
blob3.create(1024);
1223+
blob3.resize(eightTb);
1224+
1225+
final Random randGenerator = new Random();
1226+
final byte[] buffer = new byte[1024];
1227+
randGenerator.nextBytes(buffer);
1228+
blob.uploadPages(new ByteArrayInputStream(buffer), eightTb - 512L, 512L);
1229+
1230+
ArrayList<PageRange> ranges = blob.downloadPageRanges();
1231+
assertEquals(1, ranges.size());
1232+
assertEquals(eightTb - 512L, ranges.get(0).getStartOffset());
1233+
assertEquals(eightTb - 1L, ranges.get(0).getEndOffset());
1234+
}
12031235
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/**
2+
* Copyright Microsoft Corporation
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS,
11+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the License for the specific language governing permissions and
13+
* limitations under the License.
14+
*/
15+
package com.microsoft.azure.storage;
16+
17+
/**
18+
* Represents an event that is fired when a network error occurs before the HTTP response status and headers are received.
19+
*/
20+
public final class ErrorReceivingResponseEvent extends BaseEvent {
21+
22+
/**
23+
* Creates an instance of the <code>BaseEvent</code> class that is fired when a network error occurs before the HTTP response status and headers are received.
24+
*
25+
* @param opContext
26+
* An {@link OperationContext} object that represents the context for the current operation. This object
27+
* is used to track requests to the storage service, and to provide additional runtime information about
28+
* the operation.
29+
* @param connectionObject
30+
* Represents a connection object. Currently only <code>java.net.HttpURLConnection</code> is supported as
31+
* a connection object.
32+
* @param requestResult
33+
* A {@link RequestResult} object that represents the current request result.
34+
*/
35+
public ErrorReceivingResponseEvent(OperationContext opContext, Object connectionObject, RequestResult requestResult) {
36+
super(opContext, connectionObject, requestResult);
37+
}
38+
}

microsoft-azure-storage/src/com/microsoft/azure/storage/OperationContext.java

Lines changed: 64 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,8 @@ public final class OperationContext {
8383
private HashMap<String, String> userHeaders;
8484

8585
/**
86-
* Represents an event that is triggered before sending a request.
86+
* Represents an event that is triggered before sending a
87+
* request.
8788
*
8889
* @see StorageEvent
8990
* @see StorageEventMultiCaster
@@ -92,15 +93,23 @@ public final class OperationContext {
9293
private static StorageEventMultiCaster<SendingRequestEvent, StorageEvent<SendingRequestEvent>> globalSendingRequestEventHandler = new StorageEventMultiCaster<SendingRequestEvent, StorageEvent<SendingRequestEvent>>();
9394

9495
/**
95-
* Represents an event that is triggered when a response is received from the storage service while processing a
96-
* request.
97-
*
96+
* Represents an event that is triggered when a response is received from the storage service while processing a request
97+
*
9898
* @see StorageEvent
9999
* @see StorageEventMultiCaster
100100
* @see ResponseReceivedEvent
101101
*/
102102
private static StorageEventMultiCaster<ResponseReceivedEvent, StorageEvent<ResponseReceivedEvent>> globalResponseReceivedEventHandler = new StorageEventMultiCaster<ResponseReceivedEvent, StorageEvent<ResponseReceivedEvent>>();
103103

104+
/**
105+
* Represents an event that is triggered when a network error occurs before the HTTP response status and headers are received.
106+
*
107+
* @see StorageEvent
108+
* @see StorageEventMultiCaster
109+
* @see ErrorReceivingResponseEvent
110+
*/
111+
private static StorageEventMultiCaster<ErrorReceivingResponseEvent, StorageEvent<ErrorReceivingResponseEvent>> globalErrorReceivingResponseEventHandler = new StorageEventMultiCaster<ErrorReceivingResponseEvent, StorageEvent<ErrorReceivingResponseEvent>>();
112+
104113
/**
105114
* Represents an event that is triggered when a response received from the service is fully processed.
106115
*
@@ -138,6 +147,15 @@ public final class OperationContext {
138147
*/
139148
private StorageEventMultiCaster<ResponseReceivedEvent, StorageEvent<ResponseReceivedEvent>> responseReceivedEventHandler = new StorageEventMultiCaster<ResponseReceivedEvent, StorageEvent<ResponseReceivedEvent>>();
140149

150+
/**
151+
* Represents an event that is triggered when a network error occurs before the HTTP response status and headers are received.
152+
*
153+
* @see StorageEvent
154+
* @see StorageEventMultiCaster
155+
* @see ErrorReceivingResponseEvent
156+
*/
157+
private StorageEventMultiCaster<ErrorReceivingResponseEvent, StorageEvent<ErrorReceivingResponseEvent>> errorReceivingResponseEventHandler = new StorageEventMultiCaster<ErrorReceivingResponseEvent, StorageEvent<ErrorReceivingResponseEvent>>();
158+
141159
/**
142160
* Represents an event that is triggered when a response received from the service is fully processed.
143161
*
@@ -285,6 +303,16 @@ public static StorageEventMultiCaster<ResponseReceivedEvent, StorageEvent<Respon
285303
return OperationContext.globalResponseReceivedEventHandler;
286304
}
287305

306+
/**
307+
* Gets a global event multi-caster that is triggered when a network error occurs before the HTTP response status and headers are received.
308+
* It allows event listeners to be dynamically added and removed.
309+
*
310+
* @return A {@link StorageEventMultiCaster} object for the <code>globabErrorReceivingResponseEventHandler</code>.
311+
*/
312+
public static StorageEventMultiCaster<ErrorReceivingResponseEvent, StorageEvent<ErrorReceivingResponseEvent>> getGlobalErrorReceivingResponseEventHandler() {
313+
return OperationContext.globalErrorReceivingResponseEventHandler;
314+
}
315+
288316
/**
289317
* Gets a global event multi-caster that is triggered when a request is completed. It allows event listeners to be
290318
* dynamically added and removed.
@@ -325,6 +353,16 @@ public StorageEventMultiCaster<ResponseReceivedEvent, StorageEvent<ResponseRecei
325353
return this.responseReceivedEventHandler;
326354
}
327355

356+
/**
357+
* Gets an event multi-caster that is triggered when a network error occurs before the HTTP response status and headers are received.
358+
* It allows event listeners to be dynamically added and removed.
359+
*
360+
* @return A {@link StorageEventMultiCaster} object for the <code>errorReceivingResponseEventHandler</code>.
361+
*/
362+
public StorageEventMultiCaster<ErrorReceivingResponseEvent, StorageEvent<ErrorReceivingResponseEvent>> getErrorReceivingResponseEventHandler() {
363+
return this.errorReceivingResponseEventHandler;
364+
}
365+
328366
/**
329367
* Gets an event multi-caster that is triggered when a request is completed. It allows event listeners to be
330368
* dynamically added and removed.
@@ -450,6 +488,17 @@ public static void setGlobalResponseReceivedEventHandler(
450488
OperationContext.globalResponseReceivedEventHandler = globalResponseReceivedEventHandler;
451489
}
452490

491+
/**
492+
* Sets a global event multi-caster that is triggered when a network error occurs before the HTTP response status and headers are received.
493+
*
494+
* @param globalErrorReceivingResponseEventHandler
495+
* The {@link StorageEventMultiCaster} object to set for the <code>globalErrorReceivingResponseEventHandler</code>.
496+
*/
497+
public static void setGlobalErrorReceivingResponseEventHandler(
498+
final StorageEventMultiCaster<ErrorReceivingResponseEvent, StorageEvent<ErrorReceivingResponseEvent>> globalErrorReceivingResponseEventHandler) {
499+
OperationContext.globalErrorReceivingResponseEventHandler = globalErrorReceivingResponseEventHandler;
500+
}
501+
453502
/**
454503
* Sets a global event multi-caster that is triggered when a request is completed.
455504
*
@@ -494,6 +543,17 @@ public void setResponseReceivedEventHandler(
494543
this.responseReceivedEventHandler = responseReceivedEventHandler;
495544
}
496545

546+
/**
547+
* Sets an event multi-caster that is triggered when a network error occurs before the HTTP response status and headers are received.
548+
*
549+
* @param errorReceivingResponseEventHandler
550+
* The {@link StorageEventMultiCaster} object to set for the <code>errorReceivingResponseEventHandler</code>.
551+
*/
552+
public void setErrorReceivingResponseEventHandler(
553+
final StorageEventMultiCaster<ErrorReceivingResponseEvent, StorageEvent<ErrorReceivingResponseEvent>> errorReceivingResponseEventHandler) {
554+
this.errorReceivingResponseEventHandler = errorReceivingResponseEventHandler;
555+
}
556+
497557
/**
498558
* Sets an event multi-caster that is triggered when a request is completed.
499559
*

0 commit comments

Comments
 (0)