Developing Cloud Applications with Windows Azure Storage: Blobs

  • 3/15/2013

Blob snapshots

Blob storage supports a very powerful feature called snapshots. Like the name might imply, snapshots operate in a manner similar to photographs. You can take as many snapshots of a family member over time as you want. The resulting set of photographic snapshots form a chronology of the changes to your subject over time. Likewise, a snapshot in blob storage is a record of a blob’s state at a particular point in time. To maintain efficient use of storage, Windows Azure storage stores only the delta between the previous version and the current version of the blob. Although snapshots may be deleted, they are immutable and provide an audit trail of the changes as well as a convenient mechanism for rolling back changes.

This powerful feature provides a rich and cost-effective versioning mechanism for your documents, images, and other artifacts. Consider the number of times that business documents such as sales orders, purchase orders, or contracts might be revised before being agreed to. Consider also the desire that business people may have to keep snapshots of those documents for use in mitigating disputes.

In the RESTful API of Windows Azure storage, snapshots are identified by using an opaque value supplied as a query string parameter to the blob’s URI. Although the documentation states that this is an opaque value and can therefore be changed without notice, it sure looks a lot like a time stamp! The following shows an example.

http://.../cotnr/blob.dat?snapshot=2011-05-14T18:25:53.6230000Z

Creating the original blob

To create the blob in storage for this example, issue an HTTP PUT request against blob storage as follows.

PUT http://azureinsiders.blob.core.windows.net/demo/Original.txt?timeout=90 HTTP/1.1
x-ms-version: 2012-02-12
User-Agent: WA-Storage/2.0.0
x-ms-blob-type: BlockBlob
Content-MD5: vfup6ZfBE05+wonANUivGw==
x-ms-date: Mon, 31 Dec 2012 08:13:20 GMT
Authorization: SharedKey azureinsiders:7NDtxB5cV0SveodezKGFTe8NFWXGgIHgs294Aq6IrdI=
Host: azureinsiders.blob.core.windows.net
Content-Length: 13

Original data

Windows Azure storage will respond with an HTTP status code of 201 (Created) to confirm the successful upload of your data.

HTTP/1.1 201 Created
Transfer-Encoding: chunked
Content-MD5: vfup6ZfBE05+wonANUivGw==
Last-Modified: Mon, 31 Dec 2012 08:13:22 GMT
ETag: "0x8CFB545D5F2B219"
Server: Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0
x-ms-request-id: 579553cf-d37b-46aa-b1ed-8e4841993c02
x-ms-version: 2012-02-12
Date: Mon, 31 Dec 2012 08:13:20 GMT

0

You can perform this action using the Windows Azure client library by uploading contents into blob storage after acquiring a reference to the blob, as shown here.

// Create the original page blob (512 1s & 2s):
CloudBlob origBlob = container.GetBlobReference("Original.txt");
origBlob.UploadText("Original data");

Creating the blob’s snapshot

The value of the SnapshotTime property contains the date and time the snapshot was taken. The following code retrieves the SnapshotTime value, which you can use to identify this specific blob snapshot later on.

PUT http://azureinsiders.blob.core.windows.net/demo/Original.txt
    ?comp=snapshot&timeout=90 HTTP/1.1
x-ms-version: 2012-02-12
User-Agent: WA-Storage/2.0.0
x-ms-date: Mon, 31 Dec 2012 08:13:20 GMT
Authorization: SharedKey azureinsiders:h164Br8QbritWbEiDG8OBnUjH8B/hxiFCQ1+ZIPqwRQ=
Host: azureinsiders.blob.core.windows.net
Content-Length: 0

Windows Azure responds to your snapshot request by returning another HTTP 201 (Created) status code similar to the following.

HTTP/1.1 201 Created
Transfer-Encoding: chunked
Last-Modified: Mon, 31 Dec 2012 08:13:22 GMT
ETag: "0x8CFB545D5F2B219"
Server: Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0
x-ms-request-id: 6e88ae98-a68a-46e5-a734-25a76a55e92e
x-ms-version: 2012-02-12
x-ms-snapshot: 2012-12-31T08:13:23.0482586Z
Date: Mon, 31 Dec 2012 08:13:21 GMT

0

You can perform the same action with the client library by calling the blob’s CreateSnapshot method, which returns a cloud blob reference, and then caching the snapshot’s SnapshotTime property (which returns the value of the HTTP ETag header).

// Create a snapshot of the original blob & save its timestamp:
CloudBlob snapshotBlob = origBlob.CreateSnapshot();
DateTime? snapshotTime = snapshotBlob.SnapshotTime;

You can prove that the snapshot cannot be updated by attempting to upload new data into it and noting that it fails.

// Try to write to the snapshot blob:
try { snapshotBlob.UploadText("Fails"); }
catch (ArgumentException ex) { Console.WriteLine(ex.Message); }

A similar attempt to upload data into the original blob, however, succeeds.

PUT http://azureinsiders.blob.core.windows.net/demo/Original.txt?timeout=90 HTTP/1.1
x-ms-version: 2012-02-12
User-Agent: WA-Storage/2.0.0
x-ms-blob-type: BlockBlob
Content-MD5: zgYkAjIEXVBppjaEcT9nLg==
x-ms-date: Mon, 31 Dec 2012 08:13:21 GMT
Authorization: SharedKey azureinsiders:sRxSV/eOIdHBsOHSQU6QMmfY1pMZl5LsqNPuQGaQkVs=
Host: azureinsiders.blob.core.windows.net
Content-Length: 8

New data

Resulting in another HTTP result status code of 201 (Created):

HTTP/1.1 201 Created
Transfer-Encoding: chunked
Content-MD5: zgYkAjIEXVBppjaEcT9nLg==
Last-Modified: Mon, 31 Dec 2012 08:13:23 GMT
ETag: "0x8CFB545D6138160"
Server: Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0
x-ms-request-id: f9e86330-6de5-402a-b592-0e65abb75c03
x-ms-version: 2012-02-12
Date: Mon, 31 Dec 2012 08:13:21 GMT

0

Of course, you can perform this same operation using the client library. You can also add code to perform a comparison of the two normal and snapshot blobs for additional verification.

// Modify the original blob & show it:
origBlob.UploadText("New data");
Console.WriteLine(origBlob.DownloadText());      // New data
Console.WriteLine();

// Show snapshot blob via original blob URI & snapshot time:
snapshotBlob = container.GetBlockBlobReference(
"Original.txt", snapshotTime);
Console.WriteLine(snapshotBlob.DownloadText());  // Original data


// Show all blobs in the container with their snapshots:
foreach (ICloudBlob b in
    container.ListBlobs(null, true, BlobListingDetails.Snapshots)) {
    Console.WriteLine("Uri={0}, Snapshot={1}", b.Uri, b.SnapshotTime);
}

Listing snapshots

If you’re using snapshots, you might find it necessary in your application to obtain a list of all of the snapshots that exist for your blobs. To retrieve a list of all blobs in the container, issue an HTTP GET command against the resource, passing the query string parameters restype=container&comp=list& include=snapshots&timeout=90.

GET http://azureinsiders.blob.core.windows.net/demo
    ?restype=container&comp=list&include=snapshots&timeout=90 HTTP/1.1
x-ms-version: 2012-02-12
User-Agent: WA-Storage/2.0.0
x-ms-date: Mon, 31 Dec 2012 08:13:21 GMT
Authorization: SharedKey azureinsiders:xEkszk1RQ+WTGa7nfZfbP9QDQz8JWh7Fh7fPplxIvuE=
Host: azureinsiders.blob.core.windows.net

HTTP/1.1 200 OK
Transfer-Encoding: chunked
Content-Type: application/xml
Server: Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0
x-ms-request-id: 3f3d3919-aef4-4289-97c7-4fad8d655747
x-ms-version: 2012-02-12
Date: Mon, 31 Dec 2012 08:13:21 GMT

4D2
<?xml version="1.0" encoding="utf-8"?>
<EnumerationResults ContainerName="http://azureinsiders.blob.core.windows.net/demo">
  <Blobs>
    <Blob>
      <Name>Original.txt</Name>
      <Snapshot>2012-12-31T08:13:23.0482586Z</Snapshot>
      <Url>http://azureinsiders.blob.core.windows.net/demo/Original.txt
          ?snapshot=2012-12-31T08%3a13%3a23.0482586Z</Url>
      <Properties>
        <Last-Modified>Mon, 31 Dec 2012 08:13:22 GMT</Last-Modified>
        <Etag>0x8CFB545D5F2B219</Etag>
        <Content-Length>13</Content-Length>
        <Content-Type>application/octet-stream</Content-Type>
        <Content-Encoding />
        <Content-Language />
        <Content-MD5>vfup6ZfBE05+wonANUivGw==</Content-MD5>
        <Cache-Control />
        <BlobType>BlockBlob</BlobType>
      </Properties>
    </Blob>
    <Blob>
      <Name>Original.txt</Name>
      <Url>http://azureinsiders.blob.core.windows.net/demo/Original.txt</Url>
      <Properties>
        <Last-Modified>Mon, 31 Dec 2012 08:13:23 GMT</Last-Modified>
        <Etag>0x8CFB545D6138160</Etag>
        <Content-Length>8</Content-Length>
        <Content-Type>application/octet-stream</Content-Type>
        <Content-Encoding />
        <Content-Language />
        <Content-MD5>zgYkAjIEXVBppjaEcT9nLg==</Content-MD5>
        <Cache-Control />
        <BlobType>BlockBlob</BlobType>
        <LeaseStatus>unlocked</LeaseStatus>
        <LeaseState>available</LeaseState>
      </Properties>
    </Blob>
  </Blobs>
<NextMarker />
</EnumerationResults>
0

To retrieve a listing of blob snapshots in a container by using the Windows Azure client library, set an instance of the BlobRequestOptions class’s BlobListingDetails property equal to BlobListingDetails.Snapshots, which is passed to the ListBlobs method of your blob container, as shown in the following code snippet.

// Show all blobs in the container with their snapshots:
foreach (ICloudBlob b in container.ListBlobs(null, true, BlobListingDetails.Snapshots))
{
    Console.WriteLine("Uri={0}, Snapshot={1}", b.Uri, b.SnapshotTime);
}

Running the preceding code produces the following output.

Original data
Uri=http://azureinsiders.blob.core.windows.net/demo/Original.txt,
    Snapshot=12/31/2012 8:13:23 AM +00:00
Uri=http://azureinsiders.blob.core.windows.net/demo/Original.txt, Snapshot=
Original data

As stated earlier, snapshots are an immutable record of your data taken at a given point in time. Snapshots, like photographs, may be read, copied, or deleted, but not altered. And just as you might produce an altered copy of an original photograph with a photo editing program, you can produce an altered copy of a blob with blob snapshots. Although you cannot update a blob snapshot, you can clone the snapshot to make another writeable blob that can then be modified. There is an efficiency implemented in the Windows Azure REST API through the use of an HTTP header. This efficiency allows creation of the snapshot clone to be done as a single transactional request; this avoids the requirement of one trip to fetch the source data and another to create the clone. To use this feature, the destination URI establishes the target resource to be updated, and the x-ms-copy-source header establishes the source of the data to be copied. The following HTTP PUT request shows an example of cloning the Original.txt blob to a blob called Copy.txt:

PUT http://azureinsiders.blob.core.windows.net/demo/Copy.txt?timeout=90 HTTP/1.1
x-ms-version: 2012-02-12
User-Agent: WA-Storage/2.0.0
x-ms-copy-source: http://azureinsiders.blob.core.windows.net/demo/Original.txt
    ?snapshot=2012-12-31T08%3A13%3A23.0482586Z
x-ms-date: Mon, 31 Dec 2012 08:13:21 GMT
Authorization: SharedKey azureinsiders:TEhQVnfZF/kLbbTVYCpzQlCn5UHrF9QRBzSWKB0ohz8=
Host: azureinsiders.blob.core.windows.net
Content-Length: 0

Upon successful execution of the PUT operation, Windows Azure returns an HTTP status code 201 (Created).

HTTP/1.1 202 Accepted
Transfer-Encoding: chunked
Last-Modified: Mon, 31 Dec 2012 08:13:23 GMT
ETag: "0x8CFB545D63BA3D7"
Server: Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0
x-ms-request-id: 2b087f91-b3eb-4cc6-844f-b45e4de85aeb
x-ms-version: 2012-02-12
x-ms-copy-id: ebe42e0e-4094-4aff-a244-32a951f00562
x-ms-copy-status: success
Date: Mon, 31 Dec 2012 08:13:21 GMT

0

Using the Windows Azure client library, you can clone a snapshot of the blob by creating the target blob (in this case, Copy.txt), and then calling the CopyFromBlob method, passing an instance of the snapshot blob in as an argument. The following code demonstrates this technique.

// Create writable blob from the snapshot:
CloudBlockBlob writableBlob = container.GetBlockBlobReference("Copy.txt");
writableBlob.StartCopyFromBlob(snapshotBlob);
Console.WriteLine(writableBlob.DownloadText());
writableBlob.UploadText("Success");
Console.WriteLine(writableBlob.DownloadText());

Deleting snapshots

You can delete a blob and all of its snapshots, or you can delete individual snapshots from a blob; however, you are not allowed to delete a blob without also deleting all of its snapshots.

DELETE http://azureinsiders.blob.core.windows.net/demo/Original.txt?timeout=90 HTTP/1.1
x-ms-version: 2012-02-12
User-Agent: WA-Storage/2.0.0
x-ms-delete-snapshots: include
x-ms-date: Mon, 31 Dec 2012 08:13:21 GMT
Authorization: SharedKey azureinsiders:IAOrqcWDrjJUTBkM6jg+YKC6gL0CJvTTBVFai+wC8mQ=
Host: azureinsiders.blob.core.windows.net

Upon successful deletion of your blob and all of its snapshots, the Windows Azure storage service returns an HTTP status code 202 (Accepted) response.

HTTP/1.1 202 Accepted
Transfer-Encoding: chunked
Server: Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0
x-ms-request-id: f2c4f4a4-0319-4c27-a16a-e9bb28078fd6
x-ms-version: 2012-02-12
Date: Mon, 31 Dec 2012 08:13:21 GMT

0

When using the Windows Azure client library, snapshot deletion behavior is controlled by the DeleteSnapshotsOption property of an instance of the BlobRequestOptions class, which is passed as an argument to the Delete method of the blob to be deleted. An example of deleting a blob and its snapshots follows.

// DeleteSnapshotsOption: None (blob only; throws StorageException if snapshots exist),
// IncludeSnapshots, DeleteSnapshotsOnly
origBlob.Delete(DeleteSnapshotsOption.IncludeSnapshots);