Managing Blob Snapshots in Windows Azure Storage

Introduction

One of the great features in the Azure Storage Blobs Service is the ability to create snapshots for a given blob.

Snapshots add robustness to the application by providing a “transaction” like behavior when manipulating the blob data (upon point of failure rollback to the base blob version). Another useful case is to create a snapshot to a cloud drive (you can mount an NTFS drive to a blob) and restore to the blob drive.

Blob Snapshots in Azure Storage

Snapshots are basically offer version control capabilities in the Azure cloud.
Snapshots can be created on the fly and treated like a regular blob but with an exception,
Snapshot created for a given blob are a read only blob therefore any attempt to modify the snapshot will fail.

Snapshots created is linked with base blob data as well as with the base blob metadata and the other blob properties (such as content type, length etc..).

Currently there is not straight forwards way for getting all the snapshots for a given blob.
You will need to use the following fields in the snapshot type blobs:

  1. DateTime property named SnapshotTime – on snapshot blob this property is not null.
    The property represents the snapshot creation time so you can filter relevant snapshots based on this field.
  2. Blob snapshot URI – we can use it to verify that the snapshot has the same URI as our base blob.

Below I will demonstrate how to exploit those fields in order to traverse the snapshots for a given blob.

Before diving into the code you may be wondering how you are charged for the snapshot blobs ?
Duplicating a blob could affect the monthly bill. i.e. a block blob can reach up 200 GB and with rate of 0.14$ per month each snapshot could cost 28$!!!.

Since snapshots only hold the blob pages that are different from the original blob, you are charged only for those unique pages or blocks in the snapshot blob and any identical pages/blocks are shared among the blob’s snapshots.

Using the code

(Code is available for download below)

We would like to accomplish the following tasks on snapshots:

  1. Create a snapshot for a blob
  2. Retrieving a specific snapshot
  3. List all snapshots for a blob
  4. Restoring from a snapshot

please note that in order to manage snapshots and other blobs api’s will be using the Microsoft.WindowsAzure.StorageClient namespace.

Creating a snapshot

First let’s connect to the azure storage service using the storage client API’s

string connectionString = String.Format (“DefaultEndpointsProtocol=https; AccountName={0};AccountKey={1}”, storageName, privateKey);
CloudStorageAccount account = CloudStorageAccount.Parse(connectionString);
blobClient = account.CreateCloudBlobClient();

Now lets create a blob container that is populated with simple text file.

// Create a blob container CloudBlobContainer testcontainer = new CloudBlobContainer(“testcontainer”, blobClient);
testcontainer.CreateIfNotExist(new BlobRequestOptions() { UseFlatBlobListing = true });
// Upload a blob to the storage service, populate under the current container var blobRef = testcontainer.GetBlobReference(“testblob”);
blobRef.DeleteIfExists(new BlobRequestOptions() {
// need to specify this option in order to
// delete blob with snapshots DeleteSnapshotsOption = DeleteSnapshotsOption.IncludeSnapshots
});

blobRef.UploadFile(@”..\..\..\TestBlobSnapshots\Files\simpleText.txt”);
blobRef.Metadata.Add(“first”, “1”); blobRef.SetMetadata();

By default, you cannot delete a blob that has associated snapshots unless explicitly forcing deletion.

Lets view the blob we created using using Cloud Storage Manager:

Now we are now ready to create a snapshot.
I’ve added a small verification to check that the metadata of the snapshot was copied from the base blob as well.

// Create a snapshot for the blob
CloudBlob snapshotRef1 = blobRef.CreateSnapshot();
Assert.IsTrue(snapshotRef1.Metadata != null && snapshotRef1.Metadata.Count > 0 && snapshotRef1.Metadata[“first”].Equals(blobRef.Metadata[“first”]));

Retrieving a specific snapshot

As mentioned above, when creating a snapshot, the blob returned holds a SnapshotTime property of type DateTime.
I can use this property in order to get a reference for a specific blob snapshot.

// Retrieve specific snapshot for the base blob
CloudBlob snapshotRef2 = new CloudBlob(blobRef.Uri.AbsoluteUri, snapshotRef1.SnapshotTime, blobClient);
try {
// Test if the snapshot exist snapshotRef2.FetchAttributes();
} catch (Exception e)
{
Assert.Fail(“snapshot does not exist {0}”, e.Message);
}

List all snapshot for a blob

Getting all the snapshot for given blob is a bit more tricky since the api does not expose a method that get all the snapshots for a given blob.
The only hint is the property SnapshotTime as discuss earlier in the CloudBlob object that can indicate if the blob is snapshot or not.
So lets use this field and also check that the blob snapshot referred to my base blob by comparing its URI address.

// List all snapshots
var snapshots = testcontainer.ListBlobs(new BlobRequestOptions() {
BlobListingDetails = BlobListingDetails.Snapshots, UseFlatBlobListing = true })
.Where(item => ((CloudBlob)item).SnapshotTime.HasValue && item.Uri.Equals(blobRef.Uri)).ToList<IListBlobItem>();
Assert.IsTrue(snapshots.Count == 1, “snapshot was not created”);
snapshots.ForEach(item => Console.WriteLine(String.Format(“{0} {1}”,  ((CloudBlob)item).Name, ((CloudBlob)item).SnapshotTime)));

Lets see the snapshot created using Cloud Storage Manger

Restoring from a snapshot

Restoring can be easily achieved by using the CopyFromBlob method (CloudBlob class).
I will only need to specify the snapshot as the source.

// Modify base snapshot
blobRef.UploadText(“blob test was modified”);
// Restore from snapshot
blobRef.CopyFromBlob(snapshotRef1);
// Verify that restore was made
Assert.IsFalse(blobRef.DownloadText() == “blob test was modified”);

This posting is provided ‘AS IS’ with no warranties, and confers no rights.