研究目的

我々が扱っている知識は木構造であることが多い

RDBに木構造のデータを格納する際は表変換を行う必要があり、データ構造が煩雑になりやすい

当研究室では木構造をそのまま格納できる分散木構造データベースJungleの開発を行っている

当研究ではJungle上に組織の許認可管理アプリケーションmaTrixを実装しデータベースの表現力、機能の十分性、実用的な性能実証実験を行う

分散木構造データベースJungle

Jungleとは、並列信頼研で開発されているデータベース

非破壊であるため、新しい木構造を作成することでデータの編集を行う

非破壊的木構造の利点

非破壊的木構造は通常の木構造である破壊的木構造に比べ、以下のような利点を持つ

ロックが少なく、いつでもコピーが可能なことから、非破壊的木構造はスケーラブルなシステムに有用となる

組織の中の許認可管理アプリケーションmaTrix

maTrixとはSymphony社が開発しているアカウント管理、許諾判定システム

人、組織、役割等の情報を木構造として保持しており、Idでお互いに参照し組織構造を表現している

またそれらの組織構造は構成情報という名前で版管理されている。

許認可の判断は、ポリシーファイルに記述されたルールにそって行われる

ポリシーファイルは組織構造を参照するため木に対する参照機能が必要になる

Jungle上でのmaTrixのデータ構造の表現

以下のXMLは、maTrixの人物Treeの一部である。

<Persons>
  <Person id="p:1" type="Person">
    <PersonData></PersonData>
  </Person>
  <Person id="p:2" type="Person">
    <PersonData></PersonData>
  </Person>
</Persons>

この様にJungleでは木構造のデータを読み込み、木同士の参照はIdの検索を用いて表現する。

組織構造の版管理

maTrixは、組織構造を構成情報モデルとして表現し版管理している。

構成情報モデルはversion毎に存在し、各versionに対応した組織構造を構成する木構造の集合を保持している。

maTrixは全ての変更を構成情報として保持し、いつでもアクセス可能である。

Jungle上での組織構造の版管理

JungleのTreeは、全てのversionのTreeで単一なrevisionIdを保持しているため、過去のTreeにアクセスするためには、revisionIdを保持していればアクセスできる。

それを利用し、Jungle上での過去の変更履歴を保持する構成情報モデルの表現は、構成情報モデルのversionと、各Treeのversionを保持し、関連付ける構成情報モデルTreeを作成し表現した

アクセスしたいversionのノードから対応するTreeのrevisionIdを取得し、そのIdに対応するTreeにアクセスすれば良い。

maTrixでの許認可管理

maTrixを用いた許認可は、組織構造だけでは判断されない

アクセス可能な時間等のアクセスルールは組織構造では表現できないからである。

そこでアクセスルールを定義できるXACML形式で記述したポリシーファイルを用いて許認可管理を行う

XACMLは、subject(誰が)、Resource(何を)、Action(どうするか)を記述する。

以下に許認可管理の流れを示す

Jungleはデータベースであるため、許認可判断を行うためにはデータを参照する関数を実装すれば良い

検索機能の実装

maTrixの組織構造を表現する為には、Idでの検索機能が必要であるため実装を行った。

JungleのTreeに対する検索は、java8の新機能であるlambda式を用いてfind関数を実装した。lambda式を使用することで、匿名クラスを使う時より簡潔にコードを記述できるようになった。

public Iterator<TreeNode> find(Query query,String key, String searchValue);
find関数は引数にQuery、String key、String valueの3つの引数を取り、条件に一致したNodeのIteratorを返す。 第一引数には、探索の条件を記述する関数boolean comdition(TreeNode)を定義したQueryを。 第二、第三引数の、String key、String valueはIndexの取得を行うために使用する。
public interface Query {
   boolean condition(TreeNode _node);
}

find関数の使い方と流れ

Iterator<TreeNode> pairPersonIterator = traverser.find((TreeNode node) -> {
 String element = node.getAttributes().getString("element");
 if (element == null)
  return false;
 if (element.equals("Person"))
  return true;
 return false;
}, "element", "Person");
  • find関数の処理の流れは、まず、第2、第3引数のString key,String valueを用いて、これらの値に対応したIndexが登 録されているかを調べる。Indexがある場合はIndexを使用し値を返す。Indexがない場合は、Treeから深さ優先でTreeNodeを取得していく。
  • TreeNodeを取得したら、boolean Query.condition(TreeNode)を実行する。このconditionは実際にfindを使用する際にlambda式で記述する。
  • conditionの中では、TreeNodeのAttributeに対してgetを行い探索対象のデータをTreeNodeが保持しているかを調べる。データを持っていた場合はTrueを、持っていなかった場合はFalseを返す
  • conditionの返り値が、Trueだった場合取得したTreeNodeを返す。Falseだった場合は次のTreeNodeを探索します。
  • Indexの実装

    Jungleの探索はTreeを全探索するので、探索の計算量はO(n)である。

    Indexを使用することで効率よく探索を行えるようにする。

    Jungleは過去のTreeを全て保持しているため、Treeのversion毎にIndexを持っていることが望ましい。 そこで、メモリの消費量を抑え、各versionのTreeにIndexをもたせる方法として、FunctionalJavaのTreeMapを使用したIndexの実装を提案する

    FunctionalJavaのTreeMapは、データの更新が行われた際に、一度作られたTreeに対して更新を行わず過去のTreeを再利用し、更新後のTreeMap新しく返すため、メモリの使用量を抑えつつ複数のversionでIndexを保持できる。

    Indexの実装2

    TreeMap<String key,TreeMap<String value,List<TreeNode>>>

    最初のTreeMap<String key,TreeMap>はIndexを格納するTreeMapである。

    このTreeMapに対しkeyでgetを行うと、keyに対応するIndexが登録されている場合、Indexを取得できる。

    取得したIndexに対しvalueでgetを行うと、valueの値を持つNodeのListが返ってくる。

    ParentIndexの実装

    TreeNodeでgetを行うと、親Nodeを返すParentIndexを実装した。
    TreeMap<TreeNode,TreeNode>

    TreeのNodeの編集には、編集を行いたいNodeへのPathが必要である。

    ParentIndex実装前は、Indexを使って検索したNodeを編集するために返り値はList<Pair<TreeNode,NodePath>>になっていた。

    JungleのNodeへのPathは不変ではない

    よってTreeに変更が加わる度にIndexの中のPathを更新する必要があり、そこがネックだった

    ParentIndexを実装することでTreeNodeさえあれば、Pathが取得できるようになった。

    過去のTreeに対するアクセス

    Treeは、version毎に固有のrevisionIdを持っている

    アクセスしたいTreeのrevisionIdを引数に取り、対応する過去のTreeを返すgetOldTree(long)を実装した。

    XACMLInterpreter

    データの参照関数と、組織構造の表現が出来たため実際にポリシーファイルを読み込んで許認可判断を行いたい

    ポリシーファイルを読み込んでJungleのデータを参照し、許認可を判断するInterpreterを実装した

    これで実際にJungleの上で許認可判断が行えるようになった

    今後の課題

    push/popの実装

  • Jungleの新しい子のInsert処理の計算量は木の深さであるため、最悪計算量はO(n) となる。しかし、Treeの根の部分に子を追加するpush/popを実装することでInsertの計算量が、非破壊の性質を維持しながらO(1)で行えるようになる
  • IndexのIncrementalUpdate

  • 今JungleのIndexは木の更新が行われる度に新しく作りなおされているため、メモリの消費が大きい。 しかし、新しく作り直さず、木の更新時に差分更新を行うことでメモリの消費を抑えて各versionのTreeにIndexを保持するこ とが可能になる。
  • differencialList

  • Tree の葉部分に、更新可能な未定義ノードを付加しておくことで、ルートまでのコピーを行わずにノードの追加を行えるようになるので、更新処理が短くなる。
  • exponential backoff

  • Jungle は書き込みが競合し、書き込みに失敗した場合すぐに再度書き込みを行うため、 書き込みが集中した際失敗を繰り返すことがある。しかし、書き込みが失敗する度に一定時間待機してから再度書き込みを行うことで、競合を避ける事が出来る。