Windows Azure Storage Client Library for C++ Preview

Windows Azure Storage Client Library for C++ Preview がリリースされました

待望のC++用のライブラリです。

以下にざっくりと訳します。

抄訳 Windows Azure Storage Client Library for C++ Preview

これは、Preview release です、まだ puroduction codeでは使用しないでください(should not be used in your production code)。 その代わり、ざっと目を通して試してみて、あなたがGAに必要だと考える拡張・変更のフィードバックを下さい。

Windows Azure Storage に付いての詳しい情報は、SOSP PaperWindows Azure Storage: A Highly Available Cloud Storage Service with Strong Consistency[1]を参照してください。

Emulator Guidance

このライブラリが使う2013-08-15 RESTは、現在のAzure SDK(2.2)のStorage Emulatorでサポートされていません。これらの全ての機能をサポートしたAzure Storage Emulatorのアップデートを来月には出せる見込みです。(An updated Windows Azure Storage Emulator is expected to ship with full support of these new features in the next month)Storage Emulatorの現在のバージョンを使って開発しようとすると不正な要求エラーを受け取ることになります。アップデートが出るまでは、新機能を使用したいユーザーは、Windows Azure Storage Account (本番環境)を使ってテストをして下さい。[2]

サポートされるプラットフォーム

今回のリリースでは、Visual Studio 2012 (v110) と Visual Studio 2013 (v120) platform toolsets 用ライブラリの x64およびx86バージョンを提供します。パッケージには、8 build flavors が含まれます。

  1. Release, x64, v120
  2. Debug, x64, v120
  3. Release, Win32, v120
  4. Debug, Win32, v120
  5. Release, x64, v110
  6. Debug, x64, v110
  7. Release, Win32, v110
  8. Debug, Win32, v110

入手方法

ライブラリは、NuGetから、完全なソースコードはGitHubからダウンロードできます。NuGet packageは、CoApp toolsを使って作成され、3つのpackage として構成されています。

  • wastorage.0.2.0-preview.nupkg:このパッケージには、アプリケーションの開発に必要なヘッダーとLIBファイルが含まれています。これは、再配布(redist) package に依存します。NuGet は、自動的にredist packageのインストールを行います。
  • wastorage.redist.0.2.0-preview.nupkg:このパッケージを実行し、アプリケーションを再配布するために必要なDLLファイルが含まれています。
  • wastorage.symbols.0.2.0-preview.nupkg:このパッケージには、それぞれのDLLファイルのシンボルが含まれています。オプションのパッケージです。

パッケージは、C++ REST SDKに依存しており、それもNuGetで自動的にインストールされます。C++ REST SDK (codename “Casablanca”)は、native code の cloud-based client-server communication のための Microsoft のプロジェクトです。これは、native code の REST services アクセスを、multiple platforms で非同期な HTTP, JSON, URIs の C++ bindings として提供します。Windows Azure Storage Client Library では、このライブラリを Windows Azure Storage Blob, Queue, Table services との通信で利用しています。

できること

ここでは、REST API に付いて話をする代わりに、Windows Azure Storage Client Library の概要を説明します。

  • Windows Azure Storage REST API version2013-08-15全体を簡単に使えるようにする実装
  • Retry policies: リクエストが失敗した場合の再試行ロジックとして、exponential や linear back off algorithm を実装
  • Streamlined authentication model: 共有鍵と共有認証署名の両方をサポート
  • 操作コンテキストとETWのログを使用して要求の詳細と結果に潜り込む能力
  • サイズや、Blob typeに関係の無い、ユーザー設定による、parallel block/page アップロード
  • 特定のupload/download APIに対応しなくても、読み取りまたはBLOBへの書き込みを許可するBLOB Stream
  • すべてのBlob uploadおよびdownload での完全なMD5のサポート
  • Table layerでは、Azure Storage Table の新しいJSON サポートを利用
  • Table service の、Entity Group Transaction サポート。(Entity Group Transactionでは、単一トランザクションで複数操作が可能)

Read Access Geo Redundant Storage (RA-GRS) サポート

このリリースでは、storage account のsecondary region データへの読込アクセスをフルサポートしています。 この機能は、Portalで有効にしないと利用できません、詳しくは、RA-GRSを参照[3]して下さい。

How to use it?

NuGet package を入れると、was(Windows Azure Storageの略) のフォルダーに全てのヘッダー が入ります。 このディレクトリでは下記のheader ファイルが重要です。

  • blob.h: Blob service 関連の全ての宣言
  • queue.h: Queue service 関連の全ての宣言
  • table.h: Table service 関連の全ての宣言
  • storage_account.h: account の name/key 、あるいは connection string から、service client のオブジェクトを簡単に作成するための cloud_storage_account type の宣言
  • retry_policies.h: 全ての操作で使われる、幾つかの retry policies の宣言

下記のように使います

#include "was/storage_account.h"
#include "was/queue.h"
#include "was/table.h"
#include "was/blob.h"

その後、我々は作成されますcloud_storage_accountコードの後半でサービス·クライアント·オブジェクトを作成するために私達を可能にするオブジェクトを、。私たちは安全な接続のために以下のHTTPSを使用しているが、アプリケーションをデバッグするときに、HTTPは非常に便利であることに注意してください。

その後、下記のコードでcloud_storage_account オブジェクトを作成します。 ここでは、セキュアな接続のため https を使っていますが、デバックする場合は http が非常に便利です。

wa::storage::cloud_storage_account storage_account = wa::storage::cloud_storage_account::parse(U("AccountName=<account_name>;AccountKey=<account_key>;DefaultEndpointsProtocol=https"));

Blobs

ここでは、blob container を作成し、”some text” と入ったblobを作って、それを download 、そして container 内のblobをリストします。

// Create a blob container
wa::storage::cloud_blob_client blob_client = storage_account.create_cloud_blob_client();
wa::storage::cloud_blob_container container = blob_client.get_container_reference(U("mycontainer"));
container.create_if_not_exists();

// Upload a blob
wa::storage::cloud_block_blob blob1 = container.get_block_blob_reference(U("myblob"));
blob1.upload_text(U("some text"));

// Download a blob
wa::storage::cloud_block_blob blob2 = container.get_block_blob_reference(U("myblob"));
utility::string_t text = blob2.download_text();

// List blobs
wa::storage::blob_result_segment blobs = container.list_blobs_segmented(wa::storage::blob_continuation_token());

Tables

以下のサンプルでは、 Tableを作成し、様々な型のプロパティの組をエンティティに挿入し、最終的にはその指定したエンティティを取得します。最初の検索操作では、ポイント·クエリを実行し、特定のエンティティを取得します。一方クエリ操作では、PartitionKeyが“partition”に等しく、かつ、RowKey が、“m”より大きいすべてのエンティティを照会します。これは、結果的にinsertした全てのエンティティになります。

Windows Azure Tables に関する詳しい情報は、Understanding the Table Service Data Modelの記事と、How to get most out of Windows Azure Tablesの blog post を見て下さい。

// Create a table
wa::storage::cloud_table_client table_client = storage_account.create_cloud_table_client();
wa::storage::cloud_table table = table_client.get_table_reference(U("mytable"));
table.create_if_not_exists();

// Insert a table entity
wa::storage::table_entity entity(U("partition"), U("row"));
entity.properties().insert(wa::storage::table_entity::property_type(U("PropertyA"), wa::storage::table_entity_property(U("some string"))));
entity.properties().insert(wa::storage::table_entity::property_type(U("PropertyB"), wa::storage::table_entity_property(utility::datetime::utc_now())));
entity.properties().insert(wa::storage::table_entity::property_type(U("PropertyC"), wa::storage::table_entity_property(utility::new_uuid())));
wa::storage::table_operation operation1 = wa::storage::table_operation::insert_or_replace_entity(entity);
wa::storage::table_result table_result = table.execute(operation1);

// Retrieve a table entity
wa::storage::table_operation operation2 = wa::storage::table_operation::retrieve_entity(U("partition"), U("row"));
wa::storage::table_result result = table.execute(operation2);

// Query table entities
wa::storage::table_query query;
query.set_filter_string(wa::storage::table_query::combine_filter_conditions(
    wa::storage::table_query::generate_filter_condition(U("PartitionKey"), wa::storage::query_comparison_operator::equal, U("partition")), 
    wa::storage::query_logical_operator::and, 
    wa::storage::table_query::generate_filter_condition(U("RowKey"), wa::storage::query_comparison_operator::greater_than_or_equal, U("m"))));
std::vector<wa::storage::table_entity> results = table.execute_query(query);

Queues

最後の例では、Queueを作成します、それにmessageを追加、同じmessageを取得し、最終的にそれを更新します。

// Create a queue
wa::storage::cloud_queue_client queue_client = storage_account.create_cloud_queue_client();
wa::storage::cloud_queue queue = queue_client.get_queue_reference(U("myqueue"));
queue.create_if_not_exists();

// Add a queue message
wa::storage::cloud_queue_message message1(U("mymessage"));
queue.add_message(message1);

// Get a queue message
wa::storage::cloud_queue_message message2 = queue.get_message();

// Update a queue message
message2.set_content(U("changedmessage"));
queue.update_message(message2, std::chrono::seconds(30), true);

デバック方法

なにか上手く行っていない場合、exception で帰ってきます。この exception は、wa::storage::storage_exception の型で、なにか問題なのかの詳細な情報を含んでいます。次のコードを見て下さい。

try
{
    blob1.download_attributes();
}
catch (const wa::storage::storage_exception& e)
{
    std::cout << "Exception: " << e.what() << std::endl;
    ucout << U("The request that started at ") << e.result().start_time().to_string() << U(" and ended at ") << e.result().end_time().to_string() << U(" resulted in HTTP status code ") << e.result().http_status_code() << U(" and the request ID reported by the server was ") << e.result().service_request_id() << std::endl;
}

blobが存在しない場合, このコードは下記のような結果になります。

Exception: The specified blob does not exist.

The request that started at Fri, 13 Dec 2013 18:31:11 GMT and ended at Fri, 13 Dec 2013 18:31:11 GMT resulted in HTTP status code 404 and the request ID reported by the server was 5de65ae4-9a71-4b1d-9c99-cc4225e714c6

ライブラリでは、type wa::storage::operation_context を提供しています。これは、全てのAPIでサポートされ、操作中に行われていることについてより多くの情報を取得するために使います。次のコードを見て下さい。

wa::storage::operation_context context; 

context.set_sending_request([] (web::http::http_request& request, wa::storage::operation_context) 
{ 
  ucout << U("The request is being sent to ") << request.request_uri().to_string() << std::endl; 
});

context.set_response_received([] (web::http::http_request&, const web::http::http_response& response, wa::storage::operation_context) 
{ 
  ucout << U("The reason phrase is ") << response.reason_phrase() << std::endl; 
});

try 
{ 
  blob1.download_attributes(wa::storage::access_condition(), wa::storage::blob_request_options(), context); 
} 
catch (const wa::storage::storage_exception& e) 
{ 
  std::cout << "Exception: " << e.what() << std::endl; 
} 

ucout << U("Executed ") << context.request_results().size() << U(" request(s) to perform this operation and the last request's status code was ") << context.request_results().back().http_status_code() << std::endl;

もう一度、blobが存在しない状況で動かします。すると下記のような結果になります。

wa::storage::operation_context context; 

context.set_sending_request([] (web::http::http_request& request, wa::storage::operation_context) 
{ 
  ucout << U("The request is being sent to ") << request.request_uri().to_string() << std::endl; 
});

context.set_response_received([] (web::http::http_request&, const web::http::http_response& response, wa::storage::operation_context) 
{ 
  ucout << U("The reason phrase is ") << response.reason_phrase() << std::endl; 
});

try 
{ 
  blob1.download_attributes(wa::storage::access_condition(), wa::storage::blob_request_options(), context); 
} 
catch (const wa::storage::storage_exception& e) 
{ 
  std::cout << "Exception: " << e.what() << std::endl; 
} 

ucout << U("Executed ") << context.request_results().size() << U(" request(s) to perform this operation and the last request's status code was ") << context.request_results().back().http_status_code() << std::endl;

Samples

github 上のプロジェクトのサンプルフォルダの中に、幾つかの重要なシナリを説明する コードがあります。

Visual Studioで「Microsoft.WindowsAzure.Storage.Samples.sln」という名前のサンプルのソリューションファイルを開きます。Microsoft.WindowsAzure.Storage.SamplesCommonプロジェクトの下samples_common.hファイルの、ストレージのアカウント情報を更新します。Solution Explorer のウィンドウに移動し、(例えば、Microsoft.WindowsAzure.Storage.BlobsGettingStarted)実行したいサンプルプロジェクトを選択してStartUp Projectにするか、コンテキストメニューから実行します。

Summary

コメント欄 (原文)、フォーラム、あるいはGitHubでのフィードバックをお待ちしています。BUGに当たった場合、GitHubに上げてもらえると、その後の解決策などをトラックすることができるようになります。

Serdar Ozler, Mike Fisher, and Joe Giardino

まとめ

C++用のクライアントは良いですね、やっぱり欲しい。

その他に、今回CoApp toolsが気になりました。native code をnugetでpackege化して配布するプロジェクトです。 Windows にapt-getみたいな位置づけに機能を盛り込むのを狙っているようで、期待できます。[4]これで、python、ruby、node.js で Windows パッケージのバイナリコードのビルドに引っかかる問題も、このレポジトリを参照することで解決できると良いなあと思いますが、今のところプロジェクトのターゲットに入っていないようで、そこはちょっと残念です。

もう一つ、http://casablanca.codeplex.com/は、MSDN C++ REST SDK (Codename “Casablanca”)に割りとしっかりしたドキュメントが上がっていて、nugetでは、production 扱いなので、使っても良さそうな感じです。C++ REST SDK 1.4.0今年の4月からパッケージとしては上がっていたようですが、気が付きませんでした。

nugetを見てみたところ、C++ REST SDK も、SDK、 Redist、Symbols の3本立てになってました。でも、SDKが1.4.0なのに他が1.3.1のままですね。

パッケージマネージャー関連は、nuget を中心に、整備が進んでいるようで、いろいろ期待できますね。



[1]日本語訳SOSP 論文 Windows Azure ストレージ: 高可用性と強い一貫を両立する クラウド ストレージ サービス
[2]Windows Azure Storage Client Library for Java v. 0.5.0では、An updated Windows Azure Storage Emulator is expected to ship with full support of these new features in the next couple of months.になっていました。数ヶ月先って話だったので、来月だとすると良い知らせですね。
[3]日本語訳Windows Azure ストレージの冗長オプションと読み取りアクセス地理冗長ストレージ
[4]The State of CoApp