実装
それでは、実際にコードを書いていきましょう。
今回は、ソースコードの量も多くなっているので、GitHubにソースコードを上げています(※2)。こちらをベースに説明をしていきたいと思います。
今回使用するTableを、HBase shellで以下のように作成しておきます。
$ bin/hbase shell hbase(main):001:0> create "graph", {NAME => "g"} 0 row(s) in 1.1500 seconds
前回までのサンプルコードも載せています。https://github.com/brfrn169/codezineのREADMEをご覧ください。
ノードの作成
まずは、ノードを作成するコードです。GitHub上では以下のURLです。
ノードのRowにプロパティ、作成時間、更新時間をColumnとして入れています(58~61行目)。
最後にcheckAndPutをしてノードをPutしています(64行目)。
checkAndPutの第4引数にnullを指定していますが、これは指定したValueが存在しない、あるいは空のバイト配列のときに、指定したPutを実行するという意味です。もし、すでにノードが存在している場合はfalseが返ってきます。
ノードのプロパティの取得
以下のURLは、ノードのプロパティを取得するコードです。
このコードは、単純にノードのRowをGetしてプロパティを取得しているだけになります(260~267行目)。
その際に、プロパティのColumnに限定して取得しています(264行目)。
ノードのプロパティの追加・更新・削除
次は、ノードのプロパティを追加・更新・削除するコードです。
ノードのプロパティを追加・更新・削除するコードの流れは、以下のようになります。
- 指定のノードの現在の更新時間、プロパティを取り出す(379~395行目)
- 新しい更新時間、新しいプロパティを生成(397~415行目)(新しい更新時間は必ず、現在の更新時間より後になるようにする)
- 更新時間に対するcheckAndDeleteを行う(423行目)。falseが返ってきたら、(1)に戻る(PutのTimestampには新しい更新時間を指定する)
ノードのプロパティは1つのValueにすべて入っているため、更新をする場合は一度すべてのプロパティを取得してから、それに対して更新をしてPutする必要があります。
ただし、普通にPutするだけでは、ノードのプロパティの変更リクエストが同時に来た際に不整合が発生してしまいます。
そこで、悲観的ロックをかけるというアプローチもありますが、HBaseにCAS操作(checkAndPut、chechAndDelete)ができるという特徴を利用して、楽観的ロックをかけています。
今回は更新時間に対するcheckAndPutを行っています。checkAndPutに失敗した場合は、リトライをします。また、更新時間に対してcheckAndPutをしているので、更新時間は更新のたびに単調増加している必要があります。
ノードの削除
次は、ノードの削除についてです。
ノードを削除するコードの流れは以下のようになります。
- 指定のノードの現在の更新時間を取り出す(143~156行目)
- 削除時間を生成(159~163行目)(削除時間は必ず、現在の更新時間より後になるようにする)
- 更新時間に対するcheckAndDeleteを行う(169行目)。falseが返ってきたら、(1)に戻る(DeleteのTimestampには削除時間を指定する)
checkAndDelete操作でノードを削除しています。
これは、同時にノードの削除リクエストが来た場合に、どちらかしか成功しないことを意味します。また、ノードを削除した際に、そのノードに紐づくリレーションシップを削除する処理が必要ですが、今回は省略しています。