From eed8f484a2d9173f2aba730681d52a5b1950e97e Mon Sep 17 00:00:00 2001 From: Masatoshi SEKI Date: Fri, 1 Jul 2011 07:39:11 +0900 Subject: [PATCH] no comment --- drip.txt | 42 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/drip.txt b/drip.txt index 295cb11..5c9fe3d 100644 --- a/drip.txt +++ b/drip.txt @@ -276,13 +276,51 @@ drip_s.rbが一度終了しても内容が失われてないことが確認で **APIの設計指針 -Dripはストレージに関する一連の習作の経験から、「作りすぎない」ことに留意しました。「作る」ことは楽しいので、OSSのプロジェクトでは請われるままに機能を増やしてしまうことがしばしば起こります(私はそういう経験があります)。Dripのポリシーを明確にして、機能を増やしてしまう誘惑と戦いました。 - DripはdRubyと組み合わせて使うのを前提としてAPIを設計しました。dRubyの弱点はいくつかありますが、特に苦手なのはサーバ側のオブジェクトの寿命と排他制御の管理、そしてRMIの遅さです。サーバ側に状態をもつオブジェクトを作らないこと、RMIの回数を減らすことはAPIの選択の指針となります。 さきほどのreadメソッドに与えるキーについて、もう一度よく見てみましょう。readのキーは、データベース中の視点、カーソル、ページといった概念に近いものです。よくあるデータベースのAPIでは「カーソル」はコンテキストの中に隠されています。例えばRubyのFileオブジェクトは現在の位置を覚えていて、ファイル中のその位置から読んだり、その位置へ書いたりします。これに対し、DripではFileオブジェクトのような状態/コンテキストをもつオブジェクトを用いません。Dripへの質問は状態の変化を伴わない、関数のようになっています。位置などのコンテキストを管理するオブジェクトの代わりに、注目点となるキーを使うのです。このAPIを選択した理由は、コンテキストを管理するオブジェクトをDripサーバの中で生成しないためです。DripはdRubyを経由したRMIで利用されることを前提としています。生成と消滅(beginとend、openとclose)があるようなコンテキストを導入すると、その寿命をサーバが気にする必要が生まれます。分散環境でのGCといった難しい問題に向かい合わなくてはなりません。このため、Dripではそのような面倒を嫌ってInteger(キー)だけの付き合いとなるようにAPIを設計しました。 この節で示した通り、コンテキストを管理するオブジェクトを使う代わりに、readのたびに返されるキーを使ってアクセスすることで、同様な操作を実現できます。もしこのAPIでの操作が面倒と感じるなら、ローカルなプロセスの中でキーを隠すようなコンテキストを準備することを勧めます。間違ってDripサーバ側にコンテキストを用意しないよう注意して下さいね。 +readでは、自分の知らない情報を一度に最大n個、少なくともm個を返せ、と指示します。n回のreadで構成すると、RMIの回数が増えてしまいますが、このように一度に転送すればRMIの回数を削減できます。応答時間よりも処理時間が重要なバッチ処理などのケースで有効です。「少なくともm個」を指定することで、イベントの(データの)発生の都度RMIを発生させずにすみます。ほどほどにデータがたまるのを待って一度に転送することができるからです。 + +Dripはストレージに関する一連の習作の経験から、「作りすぎない」ことに留意しました。「作る」ことは楽しいので、請われるままに機能を増やしてしまうことがしばしば起こります(私はそういう経験があります)。Dripのポリシーを明確にして、機能を増やしてしまう誘惑と戦いました。 + +**タグとその他のread系API + +writeの際につけたタグを使って、読み出す情報をフィルタすることができます。writeでは、一つの情報に複数のタグをつけることができ、read_tagはタグを一つ指定してそのタグを持つ要素だけを読み出すことができます。その他の引数はreadと同じです。 + +>|ruby| +read_tag(key, tag, n=1, at_least=1, timeout=nil) +||< + +Dripでは全ての要素は一直線のストリームとして管理されます。要素はキーと値、複数のタグで構成されて、キーの順に並んでいます。readやread_tagは小さいキーから大きいキーの順にアクセスします。キーはwriteされた時刻を元に計算され、たいてい連続していません。readやread_tagの際に、存在しないキーを与えても問題ありません。そのキーよりも大きなキーを持つ、直近の要素からアクセスを開始します。readは与えたキーよりも大きなキーを持つ、直近の要素を返します。read_tagも同様に直近の要素を返しますが、タグがマッチしない要素はスキップされ、マッチした要素だけが返されます。タグを使うと一つのDripをタグで分類されたたくさんのDripのように見立てることもできます。 +また、readとread_tagのキーは共通ですから二つを組み合わせることもできます。例えば、read_tagで狙ったタグを持つ要素を取得して、それ以降の要素をreadで順に全て集める、といった操作です。 + +read_tagもreadと同様に要素が取り出せない場合に、ブロックして新しい要素の到着を待つことができます。 + +read系のAPIは他にも用意されています。 + +>|ruby| +older(key, tag=nil) + +head(n=1, tag=nil) +||< + +readやread_tagは過去から未来へ走査するAPIですが、olderとheadは過去方向への操作を補助するAPIです。 +olderはkeyで指定した要素の一つ旧い要素を返します。tagを使って要素をフィルタすることもできます。keyにnilを与えると最新を指定したことになります。older(nil)は最新の要素を一つ返します。 + +headはolderを使ったコンビニエンスメソッドです。一番新しい要素までのn個を返します。tagを使って要素をフィルタすることも可能です。nが1の場合、一番新しい要素だけが入ったArrayを返します。nが2の場合には、一番新しい要素の一つ旧い要素と、一番新しい要素の入ったArrayを返します。Arrayの中は旧いから新しいものへと並んでいます。 + +過去へ向かってのアクセスはブロックすることはありません。なぜなら、過去には情報が追加できないからです。(要素が増えるのは未来方向のみ) + +コンビニエンスメソッドとしてはolderの対になるnewerもあります。 + +>|ruby| +newer(key, tag=nil) +||< + +これは単なるread/read_tagのラッパーで、read(key, 1, 0)[0]あるいはread_tag(key, tag, 1, 0)[0]を簡単に呼べるようにしたものです。 + **とりあえず使ってみる