Developing Cloud Applications with Windows Azure Storage: Blobs
- 3/15/2013
- Blob basics
- Blob containers
- Blob addressing
- Business use cases
- Blob storage structure
- Navigating blob container hierarchies
- Storage Client library blob types
- Container and blob naming rules
- Performing create, read, update, and delete blob operations
- Shared Access Signatures and shared access policies
- Blob attributes and metadata
- Conditional operations
- Blob leases
- Using block blobs
- Using page blobs
- Blob snapshots
- Continuation tokens and blobs
- Conclusion
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);