[Windows Azure][IT鐵人賽系列] Day 17 - Storage Service (4): Drive Storage

Drive Storage是Windows Azure SDK特別為.NET的開發人員所準備的一個儲存格式,它只存在於Windows Azure SDK的組件和API中,它並沒有對外的REST APIs,除了使用Windows Azure SDK外,沒有別的方法可以使用,它本身是基於Page-BLOB為主的儲存服務,但將它模擬成一個獨立的磁碟機供應用程式使用...

Drive Storage是Windows Azure SDK特別為.NET的開發人員所準備的一個儲存格式,它只存在於Windows Azure SDK的組件和API中,它並沒有對外的REST APIs,除了使用Windows Azure SDK外,沒有別的方法可以使用,它本身是基於Page-BLOB為主的儲存服務,但將它模擬成一個獨立的磁碟機供應用程式使用,據微軟的官方文件說明,這個磁碟機是VHD(Virtual Hard Drive)格式,就如同附掛在Hyper-V上的VHD一樣,在生成時會格式化為一個NTFS檔案系統的磁碟,然後回傳給應用程式一個磁碟代號,應用程式即可利用這個磁碟代號對它進行存取,舉凡Win32 I/O API或是System.IO命名空間內的檔案API都可以順利執行,等於是將它當成一部實體的磁碟機看待即可。

在使用Drive Storage之前,必須要先將它掛載到虛擬機器的作業系統內,就像是Unix作業系統將一個磁碟掛在作業系統上,此程序稱為Mount,在執行Mount時,Drive APIs會登錄一個抽象層的介面(Drive Emulator APIs),並傳回一個磁碟機代號,所有應用程式的Win32 API即可使用這個磁碟機代號,它會決定資料的存取呼叫是否要傳給已登錄在BLOB儲存服務上的分頁式BLOB儲存區中,亦或是向本機快取(Local Cache)來要求資料。讀取時若發現資料已經有一份在本機快取時,會由本機快取讀取資料,否則會向分頁型BLOB要求資料,同時將該資料的副本寫入到本機快取中。當應用程式將資料寫入Drive Storage時,會寫入兩份資料,一份給分頁式BLOB實體的儲存區,另一份會保存到本機快取區,若舊資料在本地快取區有一份副本時,更新資料的寫入也會一併更新在本地快取的資料,以確保兩邊資料的同步性。所有針對Drive存取的呼叫若需要向分頁型BLOB要求資料時,會由Storage API Redirector來將API呼叫轉換成分頁型BLOB的REST API呼叫,再傳送給BLOB儲存服務。

clip_image002[4]

Drive Storage的功能均來自Windows Azure SDK的Microsoft.WindowsAzure.CloudDrive.dll組件,命名空間一樣是Microsoft.WindowsAzure.StorageClient,而入口則是CloudDrive,我們必須要先在應用程式起始時對Drive Storage初始化以建立Drive Emulator,而這個工作必須要設定Local Storage,所以在使用它之前,要事先在專案的屬性中加入Local Storage的設定才行。

image

接著,使用CloudBlobContainer.GetPageBlobReference()產生一個新的VHD檔案,代表Page-BLOB的檔案入口,再使用這個CloudPageBlob產生新的CloudDrive,最後再將它Mount起來即可在程式中使用。

public override bool OnStart()
{
    // ...

    CloudStorageAccount storageAccount = CloudStorageAccount.FromConfigurationSetting("FileDataSource");
    LocalResource driveCacheStorage = RoleEnvironment.GetLocalResource("DriveCache");
    CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
    CloudBlobContainer container = blobClient.GetContainerReference("newcontainer");
    CloudDrive.InitializeCache(driveCacheStorage.RootPath, driveCacheStorage.MaximumSizeInMegabytes);

    CloudPageBlob drivePageBlob = container.GetPageBlobReference("MyTestData.vhd");

    try
    {
        drivePageBlob.Create(driveCacheStorage.MaximumSizeInMegabytes * 1048576);
    }
    catch (CloudDriveException)
    {
        // reserved for blob is exist.
    }

    CloudDrive drive = new CloudDrive(drivePageBlob.Uri, storageAccount.Credentials);

    try
    {
        drive.Create(driveCacheStorage.MaximumSizeInMegabytes);
    }
    catch (CloudDriveException)
    {
        // file is exist.
    }

    drive.Mount(driveCacheStorage.MaximumSizeInMegabytes, DriveMountOptions.None);
    return base.OnStart();
}

在程式處理上,除了要透過CloudDrive.GetMonutedDrives()取得已被Mount的磁碟機代號外,其他的就只需要利用System.IO命名空間內的類別,將它當作一般的磁碟機處理即可。

private void LoadDriveTree()
{
    this.tvContainerView.Nodes.Clear();

    string driveLetter = CloudDrive.GetMountedDrives().First().Key;
    DirectoryInfo directoryInfo = new DirectoryInfo(driveLetter);

    TreeNode node = new TreeNode("Root");
    node.Value = directoryInfo.FullName;

    DirectoryInfo[] directories = directoryInfo.GetDirectories();

    if (directories != null && directories.Length > 0)
    {
        foreach (DirectoryInfo directory in directories)
            this.LoadDriveTree(ref node, directory);
    }

    this.tvContainerView.Nodes.Add(node);

    this.cmdAddContainer.Enabled = (string.IsNullOrEmpty(this.tvContainerView.SelectedValue));
    this.cmdUpload.Enabled = (!string.IsNullOrEmpty(this.tvContainerView.SelectedValue));
}

private void LoadDriveTree(ref TreeNode ParentNode, DirectoryInfo Directory)
{
    TreeNode nodeDir = new TreeNode(Directory.Name);
    nodeDir.Value = Directory.FullName;

    DirectoryInfo[] directories = Directory.GetDirectories();

    if (directories != null && directories.Length > 0)
    {
        foreach (DirectoryInfo directory in directories)
            this.LoadDriveTree(ref nodeDir, directory);
    }

    ParentNode.ChildNodes.Add(nodeDir);
}

private void LoadFiles()
{
    DirectoryInfo directory = null;

    if (string.IsNullOrEmpty(this.tvContainerView.SelectedValue))
        directory = new DirectoryInfo(CloudDrive.GetMountedDrives().First().Key);
    else
        directory = new DirectoryInfo(this.tvContainerView.SelectedValue);

    FileInfo[] files = directory.GetFiles();

    this.gvBlobList.DataSource = files;
    this.gvBlobList.DataBind();
}

private void LoadDriveTree()
{
    this.tvContainerView.Nodes.Clear();

    string driveLetter = CloudDrive.GetMountedDrives().First().Key;
    DirectoryInfo directoryInfo = new DirectoryInfo(driveLetter);

    TreeNode node = new TreeNode("Root");
    node.Value = directoryInfo.FullName;

    DirectoryInfo[] directories = directoryInfo.GetDirectories();

    if (directories != null && directories.Length > 0)
    {
        foreach (DirectoryInfo directory in directories)
            this.LoadDriveTree(ref node, directory);
    }

    this.tvContainerView.Nodes.Add(node);

    this.cmdAddContainer.Enabled = (string.IsNullOrEmpty(this.tvContainerView.SelectedValue));
    this.cmdUpload.Enabled = (!string.IsNullOrEmpty(this.tvContainerView.SelectedValue));
}

private void LoadDriveTree(ref TreeNode ParentNode, DirectoryInfo Directory)
{
    TreeNode nodeDir = new TreeNode(Directory.Name);
    nodeDir.Value = Directory.FullName;

    DirectoryInfo[] directories = Directory.GetDirectories();

    if (directories != null && directories.Length > 0)
    {
        foreach (DirectoryInfo directory in directories)
            this.LoadDriveTree(ref nodeDir, directory);
    }

    ParentNode.ChildNodes.Add(nodeDir);
}

private void LoadFiles()
{
    DirectoryInfo directory = null;

    if (string.IsNullOrEmpty(this.tvContainerView.SelectedValue))
        directory = new DirectoryInfo(CloudDrive.GetMountedDrives().First().Key);
    else
        directory = new DirectoryInfo(this.tvContainerView.SelectedValue);

    FileInfo[] files = directory.GetFiles();

    this.gvBlobList.DataSource = files;
    this.gvBlobList.DataBind();
}

雖然我們說Drive Storage只能被Windows Azure SDK的用戶端程式取用,不過透過一些方法,還是可以在其他開發平台(如PHP)使用,只是要透過IIS掛載一小部份的.NET程式,才可以達成這個目的(欲知詳情可參考Reference的第二項)。

Reference:

http://msdn.microsoft.com/en-us/wazplatformtrainingcourse_exploringwindowsazurestoragevs2010_topic6#_Toc303848603

http://blog.maartenballiauw.be/post/2010/04/09/Using-Windows-Azure-Drive-in-PHP-(or-Ruby).aspx