官术网_书友最值得收藏!

Uploading a VHD into a page blob

An instance of a Windows Azure role comprises several virtual disks (VHD) deployed into a virtual machine. One VHD contains the Guest OS; another contains the role package, while the third is a writable VHD containing the local resources of the instance.

Windows Azure provides the Azure Drive feature whereby an arbitrary VHD, contained in a page blob, can be attached to an instance and then accessed as an NTFS drive. This VHD must be an NTFS-formatted, fixed-size VHD. The VHD can be created directly as a page blob or uploaded like any other page blob.

The Disk Management snap-in for the Microsoft Management Console (MMC) can be used to create and format a VHD on a local system. Once attached to the local system, files can be copied to, or created on the file system of the VHD just as they can with any hard drive. The VHD can then be detached from the local system and uploaded as a page blob to the Windows Azure Blob Service.

A page blob, which may have a maximum size of 1 TB, comprises a sequence of 512-byte pages. All writes to a page blob must be aligned with a page boundary. There is no charge for an empty page in a page blob. There is no need to upload empty pages in the VHD, which means that bandwidth need not be wasted uploading empty pages. The Blob service identifies these empty pages when a download of one of them is requested and it merely injects a page full of 0x0 bytes into the response stream.

Uploads to block blobs comprise a two-step process: upload the blocks and commit the blocks to the blob. Uploading a page blob is a single step process: write one or more 512-byte pages to the blob. Once uploaded, these pages immediately form part of the blob. This can cause problems if multiple writers are writing to the page blob simultaneously. The Windows Azure Storage Service REST API provides support for a sequence number that can be used to control which writer wins a contest to write to a single page. This functionality is not exposed in the Windows Azure Storage Client library.

In the Storage Client library, the CloudPageBlob class provides various methods supporting page blob uploads. CloudPageBlob is derived from CloudBlob. Note that the upload methods in CloudBlob class are not supported for CloudPageBlob. Instead, CloudPageBlob provides synchronous and asynchronous WritePages() methods specifically for uploading page blobs. Additionally, there are synchronous and asynchronous forms of the GetPageRanges() method that returns an IEnumerable<PageRange> of the non-empty page ranges in the blob.

In this recipe, we will learn how to upload a VHD into a page blob.

Getting ready

We use the disk management snap-in to create and format a VHD on the local system that we will upload with the recipe. There is more documentation on the disk management snap-in at http://technet.microsoft.com/en-us/library/dd979539(WS.10).aspx.

We launch disk management by clicking on Start, typing diskmgmt.msc in the Search box, and then pressing Enter. The Create VHD and Attach VHD operations are on the Actions menu.

We use the disk management snap-in for the following tasks:

  • Creating VHD—as "fixed size" with a specified size in the specified location
  • Initializing disk with a master boot record
  • Creating a "new simple volume" formatted with NTFS with a specified drive letter
  • Copying files and directories to the specified drive
  • Detaching VHD

If the VHD already exists, then we use the disk management snap-in for the following tasks:

  • Attaching the VHD
  • Copying files and directories to the specified drive
  • Detaching VHD

How to do it...

We are going to create a page blob and upload a VHD into it. We do this as follows:

  1. Add a new class named UploadVhdExample to the project.
  2. Set the Target Framework for the project to .NET Framework 4.
  3. Add the following assembly references to the project:
    Microsoft.WindowsAzure.StorageClient
    System.Configuration
  4. Add the following using statements to the top of the class file:
    using Microsoft.WindowsAzure;
    using Microsoft.WindowsAzure.StorageClient;
    using System.Configuration;
    using System.IO;
  5. Add the following members to the class:
    private const Int32 pageSize = 0x200; // 512 bytes
    private const Int32 uploadSize = 0x100000; // 1MBytes
    private CloudBlobClient cloudBlobClient;
  6. Add the following constructor to the class:
    public UploadVhdExample()
    {
      CloudStorageAccount cloudStorageAccount =CloudStorageAccount.Parse(ConfigurationManager.AppSettings["DataConnectionString"]);
      cloudBlobClient =cloudStorageAccount.CreateCloudBlobClient();
    }
  7. Add the following method, uploading a VHD, to the class:
    private void UploadCloudDrive(String containerName, String blobName, String vhdPath)
    {
      CloudBlobContainer cloudBlobContainer =cloudBlobClient.GetContainerReference(containerName);
      cloudBlobContainer.CreateIfNotExist();
    
      CloudPageBlob cloudPageBlob =cloudBlobContainer.GetPageBlobReference(blobName);
      cloudPageBlob.Properties.ContentType ="binary/octet-stream";
    
      using (FileStream fileStream =new FileStream(vhdPath, FileMode.Open))
      {
        Int32 blobSize = (Int32)fileStream.Length;
        if ((blobSize % pageSize) != 0)
        {
          throw new ApplicationException("Page blob size must be a multiple of page size");
        }
        cloudPageBlob.Create(blobSize);
    
        Int32 pageBlobOffset = 0;
        Int32 numberIterations = blobSize / uploadSize;
        for (Int32 i = 0; i < numberIterations; i++)
        {
          pageBlobOffset = UploadPages(fileStream, cloudPageBlob, pageBlobOffset);
        }
    
        pageBlobOffset = UploadFooter(fileStream, cloudPageBlob, pageBlobOffset);
      }
    }
  8. Add the following method, uploading pages to a page blob, to the class:
    private Int32 UploadPages(FileStream fileStream,CloudPageBlob cloudPageBlob, Int32 pageBlobOffset)
    {
      Byte[] buffer = new Byte[uploadSize];
      Int32 countBytesRead = fileStream.Read(buffer, 0, uploadSize);
      Int32 countBytesUploaded = 0;
      Int32 bufferOffset = 0;
      Int32 rangeStart = 0;
      Int32 rangeSize = 0;
      while (bufferOffset < uploadSize)
      {
        Boolean nextPageIsLast =bufferOffset + pageSize >= uploadSize;
        Boolean nextPageHasData =NextPageHasData(buffer, bufferOffset);
        if (nextPageHasData)
        {
          if (rangeSize == 0)
          {
            rangeStart = bufferOffset;
          }
          rangeSize += pageSize;
        }
    
        if ((rangeSize > 0) && (!nextPageHasData ||nextPageIsLast))
        {
          using (MemoryStream memoryStream =new MemoryStream(buffer, rangeStart, rangeSize))
          {
            cloudPageBlob.WritePages(memoryStream, pageBlobOffset + rangeStart);
            countBytesUploaded += rangeSize;
            rangeSize = 0;
          }
        }
        bufferOffset += pageSize;
      }
      pageBlobOffset += uploadSize;
    
      return pageBlobOffset;
    }
  9. Add the following method, uploading the VHD footer, to the class:
    private Int32 UploadFooter(FileStream fileStream,CloudPageBlob cloudPageBlob, Int32 pageBlobOffset)
    {
      const Int32 numberFooterBytes = 512;
      Byte[] footerBytes = new Byte[numberFooterBytes];
      Int32 countBytesRead = fileStream.Read(footerBytes, 0, numberFooterBytes);
      using (MemoryStream memoryStream =new MemoryStream(footerBytes))
      {
        cloudPageBlob.WritePages(memoryStream, pageBlobOffset);
        pageBlobOffset += numberFooterBytes;
      }
      return pageBlobOffset;
    }
  10. Add the following method, verifying a page contains data, to the class:
    private Boolean NextPageHasData(Byte[] buffer,Int32 bufferOffset)
    {
      for (Int32 i = bufferOffset; i < bufferOffset + pageSize; i++)
      {
        if (buffer[i] != 0x0)
        {
          return true;
        }
      }
      return false;
    }
  11. Add the following method, using the methods added earlier, to the class:
    public static void UseUploadVhdExample()
    {
      String containerName = "{CONTAINER_NAME}";
      String blobName = "{BLOB_NAME}";
      String pathName = @"{PATH_TO_THE_VHD}";
      UploadVhdExample example = new UploadVhdExample();
      example.UploadCloudDrive(containerName, blobName, pathName);
    }
  12. Add the following to the configuration section of app.config:
    <appSettings>
      <add key="DataConnectionString" value="DefaultEndpointsProtocol=http;AccountName={ACCOUNT_NAME};AccountKey={ACCOUNT_KEY}"/> 
    </appSettings>
    

How it works...

In steps 1 through 4, we set up the class. In step 5, we define various constants and the CloudBlobClient we use to access the Blob service. We initialize this in the constructor we add in step 6.

In step 7, we add the method that controls the upload process. We open a FileStream on the VHD and create a page blob the same size as the VHD. We then iterate over the VHD file in increments of 1 MB, invoking UploadPages() to upload the data in each 1 MB window. Finally, we invoke UploadFooter() to upload the VHD footer.

In step 8, we add the UploadPages() method to upload non-empty pages to the page blob. We read the VHD into a buffer in 1 MB chunks. We then look for ranges of 512-byte pages containing some data and upload only these ranges. Remember, we do not need to upload empty pages. The tricky part of this process is identifying the end of a range when we come across an empty page or reach the end of the buffer.

In step 9, we add the UploadFooter() method to upload the 512-byte VHD footer. We simply load the footer into a Byte[] buffer and create a MemoryStream on it. We then invoke WritePages() to upload this to the page blob.

In Step 10, we add a method that returns false if every byte of a specified 512-byte page of a buffer is 0x0; otherwise, NextPageHasData() returns true.

In step 11, we add a method to use the methods added earlier. We must replace {CONTAINER_NAME} and {BLOB_KEY} with actual values for account name and access key. We must also replace {PATH_TO_THE_VHD} with the actual path to a VHD.

In step 12, we add the connection string to the app.config configuration file. We must replace {ACCOUNT_NAME} and {ACCOUNT_KEY} with actual values for the account name and access key.

There's more...

When uploading an arbitrary file that—unlike the VHD—is not an integral multiple of the upload buffer, we need to handle correctly the final chunk that is smaller than the size of the upload buffer.

See also

  • See the Uploading blocks to a block blob recipe to see how to upload a block blob.
主站蜘蛛池模板: 林甸县| 青河县| 敦煌市| 武冈市| 景泰县| 大城县| 黔西县| 全南县| 伽师县| 孟津县| 白沙| 年辖:市辖区| 陆丰市| 睢宁县| 滦南县| 合江县| 甘谷县| 尉氏县| 沭阳县| 西乌珠穆沁旗| 郸城县| 长春市| 乐山市| 辉南县| 泰兴市| 全州县| 兴仁县| 仪陇县| 榆社县| 寿阳县| 勃利县| 桦川县| 曲麻莱县| 岳阳县| 安陆市| 齐河县| 绩溪县| 灵石县| 深圳市| 邯郸市| 沧州市|