Mercurial > hg > Papers > 2014 > toma-master
annotate paper/chapter3.tex @ 48:88b11a3afb93
describe deos
author | Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp> |
---|---|
date | Fri, 07 Feb 2014 01:02:26 +0900 |
parents | e32c9a53310c |
children | 0a8d66c9ccd1 |
rev | line source |
---|---|
43 | 1 \chapter{Haskellによる\\並列データベースの実装}\label{ch:impl} |
48 | 2 本章では, 並列データベース Jungle の実装について述べる. |
10 | 3 |
4 \section{木構造データベース Jungle} | |
47 | 5 非破壊的木構造データベース Jungle は, Haskell で実装された並列データベースである. |
6 非破壊的木構造の方法に則った関数を提供する. | |
23 | 7 |
47 | 8 % 本研究では, HTTP サーバ Warp と組み合わせて掲示板システムとして利用しているが, 他のシステムに組み込むことも可能である. |
9 Jungle の基本的な使い方の手順について説明する. | |
23 | 10 \begin{enumerate} |
40
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
11 \item{木構造を保持する Jungle を作成する} |
23 | 12 \item{Jungle 内に新しい木を名前をつけて作成する} |
47 | 13 \item{木の名前を用いて, ルートノードの取得を行い, データを参照する} |
14 \item{もしくは, 木の名前を用いて, ルートノードの更新を行う} | |
23 | 15 \end{enumerate} |
16 | |
40
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
17 \subsubsection{Jungle が持つデータ型} |
47 | 18 Jungle が持つのデータ型を表\ref{tab:components}に表す. |
19 木構造の集まりを表現する Jungle, 単体の木構造を表現する Tree がある. | |
20 Node は子と属性を任意の数持てる. | |
21 データ型として定義することで, データ内部の型の整合性が保たれ, また型検査でエラーがないか検出することができる. | |
22 Jungle のデータ型について, ひとつずつ説明する. | |
35 | 23 |
34 | 24 \begin{table}[!htbp] |
25 \label{tab:components} | |
26 \begin{center} | |
48 | 27 \begin{tabular}{|c||c|c|} \hline |
28 型名 & 概要 \\ \hline | |
29 Jungle & 木の作成・取得を担当する. \\ \hline | |
30 Tree & 木の名前とルートノードの情報を保持している. \\ \hline | |
31 Node & 基本的なデータ構造, 子と属性を任意の数持てる. \\ \hline | |
34 | 32 \end{tabular} |
33 \end{center} | |
40
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
34 \caption{Jungle が持つデータ型} |
34 | 35 \end{table} |
36 | |
48 | 37 \begin{table}[!htbp] |
38 \label{tab:components} | |
39 \begin{center} | |
40 \begin{tabular}{|c||c|} \hline | |
41 型名 & データ構造 \\ \hline | |
42 Jungle & Jungle (TVar (Map String Tree)) \\ \hline | |
43 Tree & Tree (TVar Node) String \\ \hline | |
44 Node & Node (Map Int Node) (Map String ByteString) \\ \hline | |
45 \end{tabular} | |
46 \end{center} | |
47 \caption{データ型のデータ構造} | |
48 \end{table} | |
49 | |
40
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
50 \subsection{Jungle} |
47 | 51 Jungle は木構造の集まりを表現する. |
52 木には名前がついており, Tree の情報と一緒に保持している. | |
35 | 53 |
40
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
54 \begin{lstlisting}[caption=Jungleのデータ型の定義] |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
55 data Jungle = Jungle { getJungleMap :: (TVar (Map String Tree)) } |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
56 \end{lstlisting} |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
57 |
47 | 58 Jungle のデータ構造は, Jungle (TVar (Map String Tree)) である. |
59 getJungleMap :: というのは, Haskell のレコード構文である. | |
40
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
60 |
47 | 61 レコード構文は, データ構造へのアクセサを提供する. |
62 getJungleMap は関数で, 以下のような型を持つ. | |
63 これは, Jungleを受け取って, TVar (Map String Tree)を返す関数である. | |
40
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
64 |
47 | 65 レコード構文はデータ型を受け取って, :: の右側の型の値を取り出せる関数を作成すると思えば良い. |
40
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
66 |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
67 \begin{lstlisting}[caption=getJungleMap] |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
68 getJungleMap :: Jungle -> TVar (Map String Tree) |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
69 \end{lstlisting} |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
70 |
47 | 71 Jungle の木の取り扱いには, Haskell の Data.Map を利用している. |
72 型名は, Map である. | |
73 Map は, 連想配列を扱うことのできるデータ構造である. | |
74 平衡木を用いて, 挿入や参照が O (log n)で済むように設計されている. | |
75 Data.Mapを理解するためにはリストで考えると分かりやすい. | |
40
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
76 |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
77 \begin{lstlisting}[caption=getJungleMap] |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
78 data Map k a = Map [(k,a)] |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
79 |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
80 lookup' :: Eq k => k -> Map k a -> Maybe a |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
81 lookup' k (Map []) = Nothing |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
82 lookup' k (Map ((k',a):xs)) = if k == k' |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
83 then Just a |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
84 else lookup k xs |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
85 |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
86 |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
87 insert :: k -> a -> Map k a -> Map k a |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
88 insert k a (Map x) = Map ((k,a):x) |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
89 |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
90 test = Map [("key","value"),("fizz","buzz")] |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
91 \end{lstlisting} |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
92 |
47 | 93 Map は, キーと値のペアのリストだと考えることができる. |
94 キーが一致する値を探す場合, lookup'を用いる. | |
95 Maybe モナドを用いて, データがなければ Nothing, データがあれば Just に包んで返す. | |
96 $=>$ の前にある, Eq kは, 型クラスの制約である. | |
97 内部で k と k' の同値性をテストしているため, k は同値性をチェックできる型クラス Eq に属している型である必要がある. | |
40
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
98 |
47 | 99 新たにキーと値のペアを, Mapに追加するには insertを用いる. |
100 Haskell では, 受け取った引数を変更することができないため, ペアを追加した新しい Map を返す. | |
40
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
101 |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
102 |
47 | 103 木の取り扱いには Haskell のソフトウェア・トランザクショナル・メモリ (STM) を利用して状態を持たせ, スレッド間で共有できるようにしてある. |
104 これは, 各スレッドから木構造を新たに作成できるようにするためである. | |
105 STM は, スレッド間でデータを共有するためのツールである. STM を利用することでロック忘れによる競合状態や, デッドロックといった問題から解放される. | |
106 Jungle のデータ構造の Map の前に付いている TVar というのは, Transactional variablesの略で, STM で管理する変数に対して利用する. | |
34 | 107 |
23 | 108 \subsubsection{Jungle と木の作成} |
48 | 109 Jungle は, 複数の非破壊的木構造を持つため、Map で木を管理している(図\ref{fig:jungle}). |
10 | 110 |
23 | 111 \begin{figure}[!htbp] |
112 \begin{center} | |
113 \includegraphics[scale=0.7]{./images/jungle.pdf} | |
114 \end{center} | |
115 \caption{複数の木を扱えるJungle} | |
116 \label{fig:jungle} | |
117 \end{figure} | |
10 | 118 |
47 | 119 木構造の識別, つまり Map の キー にはString を利用する. |
120 String は Haskell の文字列の型で, Char のリスト [Char] の別名である. | |
40
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
121 |
47 | 122 Jungle を作成するには, createJungle を用いる. |
123 empty は空のMapを作成する関数である. | |
40
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
124 |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
125 \begin{lstlisting}[caption=createJungle] |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
126 createJungle :: IO Jungle |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
127 createJungle = atomically $ do |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
128 map <- newTVar empty |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
129 return (Jungle map) |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
130 \end{lstlisting} |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
131 |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
132 \begin{lstlisting}[caption=STMの関数] |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
133 newTVar :: a -> STM (TVar a) |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
134 readTVar :: TVar a -> STM a |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
135 writeTVar :: TVar a -> a -> STM () |
23 | 136 |
40
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
137 atomically :: STM a -> IO a |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
138 \end{lstlisting} |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
139 |
47 | 140 createJungleは, 新たにSTMの変数を作成する newTVar を実行する. |
141 newTVar などの STM の操作は STM モナド内で行う. | |
142 最後にatomicallyを行うことで, do 構文内がトランザクションとして実行される. | |
40
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
143 |
47 | 144 atomically の隣にある \$ は関数適用演算子である. |
145 \$ 関数は最も低い優先順位を持っており, 右結合である. | |
146 括弧を減らすのに使う. \$ を使わない場合は以下の様に記述することになる. | |
40
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
147 |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
148 \begin{lstlisting}[caption=STMの関数] |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
149 createJungle :: IO Jungle |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
150 createJungle = atomically (do |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
151 map <- newTVar empty |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
152 return (Jungle map)) |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
153 \end{lstlisting} |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
154 |
47 | 155 createJungle は, IOを返すため使う際には main に関連付ける必要がある. |
23 | 156 |
40
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
157 \subsection{Tree} |
47 | 158 Jungleが保持する木の情報は, 内部的には Tree というデータ型で保持している. |
159 Tree は木の名前と, ルートノードの情報を持っている. | |
160 実際にユーザがJungleを利用する際は, Jungle と木の名前を使ってルートノードを取ってくるため, Tree という構造は見えない. | |
40
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
161 |
47 | 162 ルートノードの情報はスレッド間で状態を共有する必要がある. |
163 スレッドセーフに取り扱う必要があるため, この情報も Haskell の ソフトウェア・トランザクショナル・メモリ (STM) を用いて管理している. | |
40
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
164 |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
165 \begin{lstlisting}[caption=Treeのデータ型の定義] |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
166 data Tree = Tree |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
167 { rootNode :: (TVar Node) |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
168 , treeName :: String } |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
169 \end{lstlisting} |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
170 |
47 | 171 新たな非破壊的木構造を作るには, createTree を用いる. |
172 createTree は, createJungleで作成した Jungle と木の名前を String で受け取る. | |
10 | 173 |
40
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
174 \begin{lstlisting}[caption=createTree] |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
175 createTree :: Jungle -> String -> IO () |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
176 createTree (Jungle tmap) tree_name = atomically $ do |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
177 map <- readTVar tmap |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
178 tree <- emptyTree tree_name |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
179 writeTVar tmap (insert tree_name tree map) |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
180 |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
181 emptyTree :: String -> STM Tree |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
182 emptyTree tree_name = do |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
183 node <- newTVar emptyNode |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
184 return (Tree node tree_name) |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
185 |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
186 emptyNode :: Node |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
187 emptyNode = Node (empty) (empty) |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
188 \end{lstlisting} |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
189 |
47 | 190 createJungleも STM を操作するため IOを返す. |
191 Jungle の持つ, tmapをreadTVarで取得し, 複数の木構造を管理するためのMapを取得する. | |
192 STM の変数をもった Tree を作成し, Map に insert する. | |
193 writeTVar は更新する先の変数と, 更新内容の2つを受け取る STM の関数である. | |
40
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
194 |
47 | 195 実際にcreateJungleとcreateTreeを使う時は以下のように記述する. |
34 | 196 |
10 | 197 \begin{lstlisting}[caption=データベースと木の作成] |
40
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
198 main = do |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
199 jungle <- createJungle |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
200 createTree jungle "name of new tree here" |
10 | 201 \end{lstlisting} |
202 | |
40
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
203 |
10 | 204 \subsubsection{ルートノード} |
47 | 205 非破壊的木構造データベース Jungle では, 木の最新の状態を更新・参照するのにルートノードを使う. |
206 ルートノードは, 最新の木構造の根がどれかの情報を保持している(図\ref{fig:getrootnode}). | |
23 | 207 |
208 \begin{figure}[!htbp] | |
209 \begin{center} | |
210 \includegraphics[scale=0.7]{./images/get_root_node.pdf} | |
211 \end{center} | |
212 \caption{ルートノード} | |
213 \label{fig:getrootnode} | |
214 \end{figure} | |
215 | |
47 | 216 ルートノードに関する関数を説明する. |
10 | 217 |
47 | 218 getRootNode は, 最新のルートノードを取得できる. |
219 データベースと木の名前を渡すことで利用できる. | |
220 例えば, 図\ref{fig:getrootnode}の状態の時は, B というルートノードが取得できる. | |
10 | 221 |
222 \begin{lstlisting}[caption=最新のルートノードの取得] | |
34 | 223 getRootNode :: Jungle -> String -> IO Node |
40
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
224 getRootNode (Jungle tmap) tree_name = atomically $ do |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
225 map <- readTVar tmap |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
226 readTVar (root_node map) |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
227 where |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
228 root_node map = case lookup tree_name map of |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
229 Just x -> rootNode x |
10 | 230 \end{lstlisting} |
231 | |
47 | 232 まず, readTVarでJungleが持つmapを参照する. |
233 Haskell の where キーワードは, 計算の中間結果に名前をつけるために用いられる. | |
234 今回は, root\_node という map を受け取る関数を定義している. | |
235 root\_node map では, Jungle が持つ Map をみて取得しようとしている名前の木構造があるかどうか調べている. | |
236 木構造があった場合, rootNodeというTreeに定義されているレコード構文のアクセサ関数を使って, (TVar Node)を取得する. | |
237 最後に, (TVar Node)に対して, readTVarを行うことで最新のルートノードが取得できる. | |
10 | 238 |
47 | 239 木構造を編集する関数は全て Node を受け取って Node を返す. |
240 その返ってきた Node をルートノードとして登録することで, 木構造の最新のルートノードが更新される. | |
241 updateRootNode は, データベースと木の名前, 変更して返ってきた木構造の 3 つを渡す. | |
242 updateRootNodeをした後は, getRootNodeで取得できるルートノードが更新された状態になっている. | |
10 | 243 |
244 \begin{lstlisting}[caption=ルートノードの更新] | |
34 | 245 updateRootNode :: Jungle -> String -> Node -> IO () |
40
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
246 updateRootNode (Jungle tmap) tree_name node = |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
247 atomically $ do |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
248 map <- readTVar tmap |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
249 writeTVar (root_node map) node |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
250 where |
41 | 251 root_node map = case lookup tree_name map of |
40
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
252 Just x -> rootNode x |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
253 \end{lstlisting} |
34 | 254 |
47 | 255 updateRootNodeWithは, ノードを更新する関数とデータベース, 木の名前を渡して利用する. |
256 ノードを更新する関数とは, ノードを受け取ってノードを返す関数である. (Node $->$ Node) がそれにあたる. | |
257 このupdateRootNodeWithを利用することで, getRootNodeをした後に編集しupdateRootNodeを行う一連の操作がatomicallyに行われることが保証される. | |
40
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
258 |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
259 \begin{lstlisting}[caption=ルートノードの更新] |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
260 updateRootNodeWith :: (Node -> Node) -> Jungle -> String -> IO () |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
261 updateRootNodeWith f (Jungle tmap) tree_name = |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
262 atomically $ do |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
263 map <- readTVar tmap |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
264 n <- readTVar (root_node map) |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
265 writeTVar (root_node map) (f n) |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
266 where |
41 | 267 root_node map = case lookup tree_name map of |
40
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
268 Just x -> rootNode x |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
269 \end{lstlisting} |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
270 |
47 | 271 並列データベース Jungle で他のスレッドと状態を共有する操作は, |
272 createJungle, createTree, getRootNode, updateRootNode, updateRootNodeWith | |
273 で全てである. | |
274 並列データベース Jungle では, なるべく状態を共有しないようにすることで並列実行時の性能の向上を実現する. | |
275 ソフトウェアトランザクショナルメモリは書き込み時に他から変更があった場合にやり直しという操作はあるものの, 読み込みに関してはロックなしで高速に読み込める. | |
40
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
276 |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
277 \subsection{Node} |
47 | 278 Node は木構造を表現するデータ構造である. |
279 再帰的に定義されている. | |
280 各ノードは children として子ノードを複数持つことができる(図\ref{fig:node_components}). | |
40
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
281 |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
282 \begin{figure}[!htbp] |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
283 \begin{center} |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
284 \includegraphics[width=110mm]{./images/node_component.pdf} |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
285 \end{center} |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
286 \caption{Nodeの構成要素} |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
287 \label{fig:node_components} |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
288 \end{figure} |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
289 |
47 | 290 children および attributes も Data.Map を用いて定義されている(ソースコード \ref{src:node}). |
40
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
291 |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
292 \begin{lstlisting}[label=src:node, caption=Nodeのデータ型の定義] |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
293 data Node = Node |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
294 { children :: (Map Int Node) |
bd30d93097da
describe Jungle and Tree
Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
parents:
35
diff
changeset
|
295 , attributes :: (Map String ByteString) } |
10 | 296 \end{lstlisting} |
297 | |
298 \subsubsection{木の編集} | |
47 | 299 木の編集には, Node を使う. |
300 木の編集に用いる関数は全て Node を受け取って Node を返す. | |
301 非破壊的木構造を利用しているため, getRootNode などで取得してきた Node は他のスレッドと干渉することなく自由に参照, 編集できる. | |
302 これらの編集のための関数は, 編集後updateRootNodeするか, ひとつの関数にまとめてupdateRootNodeWithをすることで木構造に反映させることができる. | |
10 | 303 |
47 | 304 編集対象のノードを指定するには, NodePath を利用する. |
305 NodePath は, ルートノードからスタートし, ノードの子どもの場所を次々に指定したものである. | |
306 Haskell の基本データ構造であるリストを利用している. | |
10 | 307 |
308 \begin{figure}[!htbp] | |
309 \begin{center} | |
310 \includegraphics[width=100mm]{./images/nodepath.pdf} | |
311 \end{center} | |
312 \caption{NodePath} | |
313 \label{fig:nodepath} | |
314 \end{figure} | |
315 | |
47 | 316 木の編集を行う関数を紹介する. |
34 | 317 |
41 | 318 \begin{lstlisting}[caption=木の編集を行う関数] |
319 addNewChildAt :: Node -> Path -> Node | |
34 | 320 deleteChildAt :: Node -> Path -> Position -> Node |
41 | 321 putAttribute :: Node -> Path -> String -> ByteString -> Node |
322 deleteAttribute :: Node -> Path -> String -> Node | |
10 | 323 \end{lstlisting} |
324 | |
47 | 325 addNewChildAt で, ノードに新しい子を追加できる. |
326 Node と NodePath を渡す必要がある. | |
327 子には Position という場所の情報があるが, インクリメントしながら自動的に指定される. | |
41 | 328 |
47 | 329 deleteChildAt で, ノードの子を削除できる. |
330 Node と NodePath, 削除したい子のPositionを指定する. | |
41 | 331 |
47 | 332 putAttribute で, ノードに属性を追加できる. |
333 Node と NodePath, キー, 値を渡す. | |
334 キーは String, 値は, ByteString である. | |
41 | 335 |
47 | 336 deleteAttribute で, ノードの属性を削除できる. |
337 Node と NodePath, キーを渡す. | |
41 | 338 |
47 | 339 これらの関数は, ほぼ同一の関数で定義できる. |
340 addNewChildAtを用いて説明する. | |
23 | 341 |
41 | 342 \begin{lstlisting}[caption=木の編集を行う関数] |
343 addNewChildAt :: Node -> Path -> Node | |
344 addNewChildAt parent [] = addChildAt parent emptyNode | |
345 addNewChildAt parent (x:xs) = addChild parent x $ addNewChildAt x_node xs | |
346 where | |
347 map = children parent | |
348 x_node = case lookup x map of | |
349 Just x -> x | |
34 | 350 |
41 | 351 addChild :: Node -> Position -> Node -> Node |
352 addChild node pos child = Node new_child attr | |
353 where | |
354 map = children node | |
355 new_child = insert pos child map | |
356 attr = attributes node | |
357 | |
358 addChildAt :: Node -> Node -> Node | |
359 addChildAt node child = Node new_child attr | |
360 where | |
361 map = children node | |
362 pos = (size map) + 1 | |
363 new_child = insert pos child map | |
364 attr = attributes node | |
10 | 365 \end{lstlisting} |
366 | |
47 | 367 非破壊的木構造の編集は再帰で定義できる. |
368 左結合となる\$を使い, 対象のノードに到達するまで, addChildを繰り返す. | |
369 addChildは, 引数として子となるノードが必要である. | |
370 そのため, 下の階層から徐々に上に作られていく. | |
23 | 371 |
47 | 372 addNewChildAt, deleteChildAt, putAttribute, deleteAttributeといった, |
373 非破壊的木構造の編集は, 対象のノードに対する操作以外は全て同じである. | |
374 Pathのリストが空になる, すなわち対象のノードに到達した時の操作だけが異なる. | |
375 新しい子を追加するのが addNewChildAt, 指定されたポジションの子を削除するのが deleteChildAt, | |
376 指定されたキーと値を追加するのが putAttribute, 指定されたキーの値を削除するのが deleteAttributeである. | |
10 | 377 |
378 | |
379 \subsubsection{木の参照} | |
47 | 380 木の参照にも Node を用いる. |
381 様々な参照の関数があるため, ひとつずつ紹介していく. | |
23 | 382 |
10 | 383 \begin{lstlisting}[caption=属性の取得] |
34 | 384 getAttributes :: Node -> Path -> String -> Maybe ByteString |
41 | 385 getAttributes node path key = lookup key map |
386 where | |
387 target = getNode node path | |
388 map = attributes target | |
34 | 389 |
41 | 390 getChildren :: Node -> Path -> [Node] |
391 getChildren node path = elems map | |
392 where | |
393 target = getNode node path | |
394 map = children target | |
395 | |
396 assocsChildren :: Node -> Path -> [(Int, Node)] | |
397 assocsChildren node path = assocs map | |
398 where | |
399 target = getNode node path | |
400 map = children target | |
2 | 401 |
41 | 402 assocs :: Node -> Path -> [(String, ByteString)] |
403 assocs node path = assocs map | |
404 where | |
405 target = getNode node path | |
406 map = attributes target | |
23 | 407 |
41 | 408 numOfChild :: Node -> Path -> Int |
409 numOfChild node path = size map | |
410 where | |
411 target = getNode node path | |
412 map = children target | |
34 | 413 |
41 | 414 currentChild :: Node -> Path -> Maybe Node |
415 currentChild node path = lookup pos map | |
416 where | |
417 target = getNode node path | |
418 map = children target | |
419 pos = size map | |
10 | 420 \end{lstlisting} |
421 | |
47 | 422 elems, assocs, sizeなどはData.Mapの関数である. |
23 | 423 |
47 | 424 getAttributes は, 対象の Path に存在する属性を Key を用いて参照できる. |
34 | 425 |
47 | 426 getChildren は, 対象の Node が持つ全ての子を Node のリストとして返す. |
427 あるNodeに存在する全ての子に対して, 参照を行いたい場合に利用する. | |
23 | 428 |
47 | 429 assocsChildren は, 対象の Node が持つ全ての子を Position とのタプルにし, そのタプルのリストを返す. |
430 あるNodeに存在する全ての子に対して, 子のPositionを取得しながら参照を行いたい場合に利用する. | |
34 | 431 |
47 | 432 assocsAttribute は, 対象の Node が持つ全ての属性を, キーと値のペアとし, そのペアのリストを返す. |
433 あるNodeに存在する全ての属性に対して, 参照を行いたい場合に利用する. | |
10 | 434 |
47 | 435 numOfChild では, 対象の Node が持つ子どもの数を取得できる. |
23 | 436 |
47 | 437 currentChild では, 対象の Node が持つ最新の子を取得できる. |
23 | 438 |
10 | 439 |
23 | 440 \subsubsection{並列実行} |
47 | 441 木構造データベース Jungle は, 並列に実行することができる. |
442 アプリケーション側で, データベースを参照や変更する際に各スレッドから呼び出しても問題ない. | |
443 利用方法も, シングルスレッドで実行する場合と同じである. | |
23 | 444 |
10 | 445 \section{Haskell の生産性} |
47 | 446 Java を用いた Jungle の実装と比較して, コード行数が約 3000 行から約 300 行へと短くなった. |
10 | 447 |
47 | 448 Haskell では, 独自のデータ型を作成することができる. |
449 再帰的なデータ構造の定義も容易である. | |
450 また, Haskellは参照透過性を持つため, コードの再利用が行い易く, 関数同士の結合も簡単である. | |
10 | 451 |
47 | 452 同じような機能を実装する場合でも, Java と比較してコード行数が短くなり生産性が向上する. |