Azure Blob: "The condition specified using HTTP conditional header(s) is not met"
Bufff... mistery solved!
Well, when you do a CloudBlob.OpenRead()
, the client library is doing two operations:
First, get the blob block list:
GET /devstoreaccount1/etagtest/test2.txt?comp=blocklist&blocklisttype=Committed&timeout=90 HTTP/1.1
x-ms-version: 2009-09-19
User-Agent: WA-Storage/6.0.6002.18006
x-ms-date: Wed, 23 Feb 2011 22:21:01 GMT
Authorization: SharedKey devstoreaccount1:SPOBe/IUrZJvoPXnAdD/Twnppvu37+qrUbHnaBHJY24=
Host: 127.0.0.1:10000
HTTP/1.1 200 OK
Transfer-Encoding: chunked
Content-Type: application/xml
Last-Modified: Wed, 23 Feb 2011 22:20:33 GMT
ETag: 0x8CDA1BF0593B660
Server: Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0
x-ms-request-id: ecffddf2-137f-403c-9595-c8fc2847c9d0
x-ms-version: 2009-09-19
x-ms-blob-content-length: 4
Date: Wed, 23 Feb 2011 22:21:02 GMT
Attention to the ETag in the response.
Second, I guess that start to retrieve it, and now attention to the ETag in the request:
GET /devstoreaccount1/etagtest/test2.txt?timeout=90 HTTP/1.1
x-ms-version: 2009-09-19
User-Agent: WA-Storage/6.0.6002.18006
x-ms-range: bytes=0-525311
If-Match: 0x8CDA1BF0593B660
x-ms-date: Wed, 23 Feb 2011 22:21:02 GMT
Authorization: SharedKey devstoreaccount1:WXzXRv5e9+p0SzlHUAd7iv7jRHXvf+27t9tO4nrhY5Q=
Host: 127.0.0.1:10000
HTTP/1.1 206 Partial Content
Content-Length: 4
Content-Type: text/plain
Content-Range: bytes 0-3/4
Last-Modified: Wed, 23 Feb 2011 22:20:33 GMT
ETag: 0x8CDA1BF0593B660
Server: Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0
x-ms-request-id: db1e221d-fc61-4837-a255-28b1547cb5d7
x-ms-version: 2009-09-19
x-ms-lease-status: unlocked
x-ms-blob-type: BlockBlob
Date: Wed, 23 Feb 2011 22:21:02 GMT
What happen if another WebRole do something in the blob between call? YES a race condition.
Solution: Use CloudBlob.DownloadToStream()
, that method only issues one call:
GET /devstoreaccount1/etagtestxx/test2.txt?timeout=90 HTTP/1.1
x-ms-version: 2009-09-19
User-Agent: WA-Storage/6.0.6002.18006
x-ms-date: Wed, 23 Feb 2011 22:34:02 GMT
Authorization: SharedKey devstoreaccount1:VjXIO2kbjCIP4UeiXPtxDxmFLeoYAKOqiRv4SV3bZno=
Host: 127.0.0.1:10000
HTTP/1.1 200 OK
Content-Length: 4
Content-Type: text/plain
Last-Modified: Wed, 23 Feb 2011 22:33:47 GMT
ETag: 0x8CDA1C0DEB562D0
Server: Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0
x-ms-request-id: 183a05bb-ea47-4811-8768-6a62195cdb64
x-ms-version: 2009-09-19
x-ms-lease-status: unlocked
x-ms-blob-type: BlockBlob
Date: Wed, 23 Feb 2011 22:34:02 GMT
I will put this on practice tomorrow morning at work and see what happen.
You can still use OpenRead, you need to pass OperationContext instance like below code:
// cloudBlob instance of CloudPageBlob
OperationContext context = new OperationContext();
context.SendingRequest += (sender, e) => {
e.Request.Headers["if-match"] = "*";
};
using (AutoResetEvent waitHandle = new AutoResetEvent(false))
{
cloudBlob.StreamMinimumReadSizeInBytes = 16385;
var result = cloudBlob.BeginOpenRead(null, null, context,
ar => waitHandle.Set(),
null);
waitHandle.WaitOne();
using (Stream blobStream = vhd.EndOpenRead(result))
{
var k = blobStream.ReadByte();
}
}