C++ 用 Windows Azure ストレージ クライアント ライブラリのプレビュー版をリリース
このポストは、12 月 20 日に Windows Azure Storage Team が投稿した Windows Azure Storage Client Library for C++ Preview の翻訳です。
マイクロソフトは、C++ 用 Windows Azure ストレージ クライアント ライブラリを新たにリリースしました。現時点ではプレビュー リリースですので、このライブラリは本番環境のコードでは使用しないでください。また、一般提供版のインターフェイスの改良および変更に活用するため、皆様にお試しいただき、フィードバックをお寄せいただけますと幸いです。この記事では、ライブラリの概要について説明します。
Windows Azure ストレージについての詳細は、「SOSP 論文 - Windows Azure Storage: 強力な一貫性を持つ高可用性クラウド ストレージ サービス (英語)」を参照してください。
エミュレーターについての案内
このライブラリでは 2013-08-15 REST バージョンを使用していますが、このバージョンはまだストレージ エミュレーターではサポートされていません。Windows Azure ストレージ エミュレーターの更新版が来月中にリリースされる予定です。こちらでは、新機能が完全にサポートされます。現行バージョンのストレージ エミュレーターで開発を行うと、暫定的に Bad Request エラーが返されます。新しいエミュレーターのリリースまでは、2013-08-15 REST バージョンの新機能を使用するには Windows Azure ストレージ アカウントで開発、テストを行う必要があります。
サポート対象のプラットフォーム
今回のリリースでは、Visual Studio 2012 (v110) と Visual Studio 2013 (v120) の両方のプラットフォームのツールセットで、x64 と x86 のバージョンを提供します。このため、パッケージには次の 8 個のビルドが含まれています。
- リリース、x64、v120
- デバッグ、x64、v120
- リリース、Win32、v120
- デバッグ、Win32、v120
- リリース、x64、v110
- デバッグ、x64、v110
- リリース、Win32、v110
- デバッグ、Win32、v110
配布場所
このライブラリは NuGet (英語) からダウンロードできます。また、完全なソース コードは GitHub (英語) で入手できます。NuGet パッケージは CoApp ツール (英語) を使用して作成されており、次の 3 つのパッケージで構成されています。
- wastorage.0.2.0-preview.nupkg: このパッケージには、アプリケーションの開発に必要な、ヘッダーと LIB ファイルが含まれています。ユーザーはこのパッケージをインストールする必要があり、これには redist パッケージとの依存関係が設定されているため、自動的に redist パッケージが NuGet から自動的にインストールされます。
- wastorage.redist.0.2.0-preview.nupkg: このパッケージには、アプリケーションの実行と再配布に必要な DLL ファイルが含まれています。
- wastorage.symbols.0.2.0-preview.nupkg: このパッケージには、各 DLL ファイルに対応したシンボルが含まれています。オプションのパッケージです。
パッケージは C++ REST SDK (英語) とも依存関係があり、こちらも自動的に NuGet からインストールされます。C++ REST SDK (コードネーム “Casablanca”) (英語) は、クライアントとサーバー間のクラウドベースの通信をネイティブ コードで実行するためのマイクロソフトのプロジェクトであり、非同期 C++ バインディングを HTTP、JSON、および URI に提供することで、複数のプラットフォームでネイティブ コードから REST サービスへのアクセスをサポートしています。Windows Azure ストレージ クライアント ライブラリではこれを使用して、Windows Azure ストレージ BLOB、キュー、およびテーブルの各サービスと通信しています。
使用可能な機能
ここでは、REST API と直接通信するのではなく Windows Azure ストレージ クライアント ライブラリを使用することによって実現される機能について、概要を説明します。
- Windows Azure ストレージ REST API 2013-08-15 バージョン全体を簡単に使用可能な形で実装
- 特定の要求が失敗したときの再試行に指数または線形のバック オフ アルゴリズムを使用する再試行ポリシーを導入
- 認証モデルを合理化し、共有鍵と共有認証署名の両方をサポート
- 操作コンテキストと ETW のログを使用して、要求の詳細と結果を確認
- BLOB のサイズや種類を問わず、ユーザーの構成に応じてブロックまたはページ単位で BLOB を並列アップロード
- 特定のアップロード用またはダウンロード用 API に対応していなくても BLOB の読み取りおよび書き込みが可能な BLOB ストリーム
- BLOB のアップロード用とダウンロード用のすべての API で MD5 を完全にサポート
- 2013 年 11 月に新たに Windows Azure ストレージでのサポートが開始された JSON (英語) を使用したテーブル層
- エンティティ グループ トランザクションがテーブル サービスでサポートされ、1 つのトランザクションで複数の操作が可能に
読み取りアクセス地理冗長ストレージのサポート
今回のリリースでは、セカンダリ拠点に存在するストレージ アカウント データへの読み取りアクセスが完全にサポートされました。この機能を使用するには、管理ポータルから特定のストレージ アカウントに対して有効化する必要があります。読み取りアクセス地理冗長ストレージの詳細については、こちらのページを参照してください。
使用方法
NuGet パッケージをインストールすると、使用する必要があるヘッダー ファイルはすべて “was” (Windows Azure Storage の略) という名前のフォルダーに格納されます。このフォルダー内にあるヘッダー ファイルのうち、次のものは特に重要です。
- blob.h: BLOB サービスに関連するすべての型の宣言に使用します。
- queue.h: キュー サービスに関連するすべての型の宣言に使用します。
- table.h: テーブル サービスに関連するすべての型の宣言に使用します。
- storage_account.h: cloud_storage_account 型を宣言します。この型を使用すると、アカウント名と鍵の組み合わせ、または接続文字列を使用してサービスのクライアント オブジェクトを簡単に作成できます。
- retry_policies.h: すべての操作で使用可能な再試行ポリシーを個別に宣言します。
これらを使用する際は、まず、使用するヘッダーをインクルードします。
#include "was/storage_account.h"
#include "was/queue.h"
#include "was/table.h"
#include "was/blob.h"
ここでは、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"));
BLOB
ここでは、まず BLOB コンテナーを作成します。さらに、「何らかのテキスト」を追加して、それをダウンロードし、最後にコンテナー内のすべての BLOB をリスト表示します。
// BLOB コンテナーを作成
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();
// BLOB をアップロード
wa::storage::cloud_block_blob blob1 = container.get_block_blob_reference(U("myblob"));
blob1.upload_text(U("some text"));
// BLOB をダウンロード
wa::storage::cloud_block_blob blob2 = container.get_block_blob_reference(U("myblob"));
utility::string_t text = blob2.download_text();
// BLOB をリスト表示
wa::storage::blob_result_segment blobs = container.list_blobs_segmented(wa::storage::blob_continuation_token());
テーブル
次に示すサンプルでは、まずテーブルを作成し、異なる型のプロパティを複数持つエンティティを挿入し、最後にそのエンティティを取得します。取得操作の最初に、ポイント クエリを実行して特定のエンティティを取得します。このクエリ操作では、PartitionKey が “partition” と等しく、RowKey が “m” 以上のすべてのエンティティに対してクエリを実行します。これにより、最終的に、サンプルで挿入した元のエンティティが取得されます。
Windows Azure テーブルについての詳細は、「テーブル サービス データ モデルについて」および「Windows Azure テーブルの活用方法 (英語)」の記事を参照してください。
// テーブルを作成
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();
// テーブル エンティティを挿入
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);
// テーブル エンティティを取得
wa::storage::table_operation operation2 = wa::storage::table_operation::retrieve_entity(U("partition"), U("row"));
wa::storage::table_result result = table.execute(operation2);
// テーブル エンティティのクエリを実行
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);
キュー
最後のサンプルでは、まずキューを作成し、メッセージを追加し、そのメッセージを取得して、最後にこれを更新します。
// キューを作成
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();
// キューにメッセージを追加
wa::storage::cloud_queue_message message1(U("mymessage"));
queue.add_message(message1);
// キューのメッセージを取得
wa::storage::cloud_queue_message message2 = queue.get_message();
// キューのメッセージを更新
message2.set_content(U("changedmessage"));
queue.update_message(message2, std::chrono::seconds(30), true);
デバッグ方法
何らかの問題が発生した場合、呼び出しのいずれかから例外が発生したことが通知されます。この例外は wa::storage::storage_exception という型で、発生した問題に関する詳細な情報を含んでいます。次のコードをご覧ください。
try
{
blob1.download_attributes();
}
catch (const wa::storage::storage_exception& e)
{
std::cout << "例外: " << e.what() << std::endl;
ucout << U("開始時刻: ") << e.result().start_time().to_string() << U("終了時刻: ") << e.result().end_time().to_string() << U(" の要求で、HTTP ステータス コード ") << e.result().http_status_code() << U(" が返されました。サーバーから報告された要求 ID : ") << e.result().service_request_id() << std::endl;
}
存在しない BLOB で実行しようとした場合、このコードでは次のような文字列が記録されます。
例外: The specified blob does not exist.
開始時刻: Fri, 13 Dec 2013 18:31:11 GMT、終了時刻: Fri, 13 Dec 2013 18:31:11 GMT の要求で、HTTP ステータス コード 404 が返されました。サーバーから報告された要求 ID: 5de65ae4-9a71-4b1d-9c99-cc4225e714c6
このライブラリでは 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("次の宛先に要求を送信中: ") << 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("理由メッセージ: ") << 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 << "例外: " << e.what() << std::endl;
}
ucout << U("この操作で ") << context.request_results().size() << U(" 個の要求が実行されました。最後の要求のステータス コード: ") << context.request_results().back().http_status_code() << std::endl;
先ほどと同様に、存在しない BLOB で実行しようとした場合、このコードでは次のような文字列が記録されます。
次の宛先に要求を送信中: https://myaccount.blob.core.windows.net/mycontainer/myblob?timeout=90
理由メッセージ: The specified blob does not exist.
例外: The specified blob does not exist.
この操作で 1 個の要求が実行されました。最後の要求のステータス コード: 404
サンプル
マイクロソフトは、GitHub でサンプル プロジェクトを配布 (英語) しています。各抽象化ストレージのセットアップと実行の際にお役立てください。またその他に、主要なシナリオのサンプルが複数用意されています。サンプル プロジェクトはすべて “samples” という名前のフォルダーに格納されます。
Visual Studio の場合、サンプル ソリューションのファイル名は “Microsoft.WindowsAzure.Storage.Samples.sln” です。Microsoft.WindowsAzure.Storage.SamplesCommon プロジェクトの samples_common.h ファイルで、ユーザーのストレージ アカウントの認証情報を更新します。ソリューション エクスプローラーのウィンドウに移動し、実行するサンプル プロジェクト (Microsoft.WindowsAzure.Storage.BlobsGettingStarted など) を選択します。次に、[Project] メニューで [Set as StartUp Project] を選択 (またはプロジェクトを右クリックしてコンテキスト メニューから同オプションを選択) します。
まとめ
マイクロソフトは皆様からのフィードバックをお待ちしております、ページ下部のコメント欄、フォーラム、または GitHub (英語) までお気軽にお寄せください。また、不具合を発見した場合は、GitHub まで報告していただくと、後から解決策が確認できます。
Serdar Ozler、Mike Fisher、Joe Giardino
参照資料