非同期なDatastoreService的なものとかつくってみた

うーん。結構悩ましいのですが、ノリと勢いでつくってみました。最近ブログさぼりがちだったので、ネタが欲しかったともいうかも。

#appnegineでは、api呼び出しをRPCで実装していて、すべてのサービス呼び出しはApiProxy.makeSyncCallを通って他ノードと通信を行っています。実はApiProxyにはmakeAsyncCallというのもあって、他ノードとの通信を非同期で行うこともできるようになってます。

この辺は、
http://d.hatena.ne.jp/marblejenka/20091125/1259169026
http://d.hatena.ne.jp/marblejenka/20091129/1259519548
http://d.hatena.ne.jp/marblejenka/20091204/1259941582

などを参照していただければ。


で、このmakeAsyncCallをどうにかすればAsyncDatastoreServiceをつくれるというのは昔から構想していたのですが、lower level apiを触りまくるのでバージョンアップすると死んじゃうとか、最近こみいったアルゴリズムをappengine上で実装しようとする試みがあり(koherさんのhttp://d.hatena.ne.jp/koherent/20100430/1272612664とか)永続化がネックになるなら非同期とかどう?とかおもったというので実装してみました。
あとはshin1ogawa氏がバージョンアップは気合いでどうにかしろといったから、今日が私のAsyncDatastoreService記念日、みたいな感じです。
あと、すぐに標準で出してくると思ったのですが、そうでもないっぽいので。appstats/jのことは忘れない。


そうそう、git/mavenに移行したので、google codeのコードは使わないかなーという感じになってます。
なんかgitのほうがナウでヤングな感じがするし、もしかしたら誰かフォークしてくれるかもしれないし。
mavenに移行したのは、これまでの構成管理が根本的にだめっぽかったからです。antとeclipse pluginの両方で管理してたので、バージョンアップについていけなくなり、調子のってscalaのプロジェクトも始めたのでこっちのバージョンもあれだし、antスクリプトはメンテ辛くなってくるし・・・というのが発端です。


実装はこんな感じです。
http://github.com/marblejenka/balmysundaycandy/blob/master/balmysundaycandy-low-level-api-extention/src/main/java/balmysundaycandy/extention/datastore/impl/AsyncDatastoreServiceImpl.java
http://github.com/marblejenka/balmysundaycandy/blob/master/balmysundaycandy-low-level-api-extention/src/test/java/balmysundaycandy/extention/datastore/impl/AsyncDatastoreServiceImplTest.java

いくつかコメントを。
・まだプロダクションでは動かしてませんが、過去いろいろ試した感じだとこの実装でだいたい動くはずです。土曜の#ahack4で時間があれば試してみようかと。kotoriも進化してるはずだし。
・ところでkotoriってmavenでつかえたりしないかな。
・DatastoreServiceImpleでは、スタック状にトランザクションを管理しており、トランザクション指定なしのapiではトランザクションをおこしたうえでスタックにおいて管理しています。いまのAsyncDatastoreServiceImplは、その管理をどうしたものかと決めかねているので、トランザクション指定なしのget/put/deleteでは即座にトランザクションを同期でコミットしにいってます。まあトランザクションはユーザー管理でいい気がします。
→追記:というか即座にコミットしにいったらだめじゃん(後述)。なんかテストたまに落ちると思ったら、自分で意識してて気づいてなかった!@ashigeruさんありがとうございます!
・pbの変換は一部さぼっているので、DatastoreServiceと動作が合わない可能性があります。
トランザクションの戻り値の実装は、インターフェイスを合わせにいってるので、Transactionの型で受け取れます。何かやろうとすると同期するようにしてます。
トランザクション指定ありのget/put/deleteの結果を非同期で受け取った後に、同期せずトランザクションをコミットしにいくとどうなるのかはよくわかりません。どうなるんだろね。たぶん、例外になるので、同期してからトランザクション制御しないとだめね。こわ。
・キュェリィーの実装は、めんどくさいのでまだやってません。インターフェイスをあわせにいくと結構めんどい。というか、インターフェイスあわせられん。


いろんな意味で危険なapiなので、appengineに詳しくない方の使用はお勧めしません。というか詳しくてもお勧めしませんが、要望があればもうちょっとがんばるかもしれません。