comparison paper/chapter4.tex @ 102:6f73e05d5024

Fixed chapter4.tex
author Nobuyasu Oshiro <dimolto@cr.ie.u-ryukyu.ac.jp>
date Sat, 15 Feb 2014 06:00:54 +0900
parents 4e8bfd65768f
children d116e59fc8a2
comparison
equal deleted inserted replaced
101:1d5736ae832f 102:6f73e05d5024
1 \chapter{木構造データベースJungleの分散実装} 1 \chapter{木構造データベースJungleの分散実装}
2 前章では Jungle のアーキテクチャと分散設計について説明した. 2  前章では Jungle のアーキテクチャと分散設計について説明した.
3 トポロジーの形成と他サーバノードのデータのアクセス方法には Alice を使用する. 3 トポロジーの形成と他サーバノードのデータのアクセス方法には Alice を使用する.
4 また, Jungle ではデータ編集のログとして TreeOperationLog がある. 4 また, Jungle ではデータ編集のログとして TreeOperationLog がある.
5 この TreeOperationLog を Alice により他サーバノードへ送ることでデータの分散を行う. 5 この TreeOperationLog を Alice により他サーバノードへ送ることでデータの分散を行う.
6 6
7 本章では Jungle に行った分散実装について述べる. 7 本章では Jungle に行った分散実装について述べる.
15 15
16 \section{Alice のトポロジーマネージャーの利用} 16 \section{Alice のトポロジーマネージャーの利用}
17 17
18 \subsection{トポロジーマネージャーの起動} 18 \subsection{トポロジーマネージャーの起動}
19 Alice を用いてサーバノードでトポロジーの形成を行う方法を述べる. 19 Alice を用いてサーバノードでトポロジーの形成を行う方法を述べる.
20 Alice のトポロジーマネージャーの起動は\ref{src:alice_ntm_run}の様に行う. 20 Alice のトポロジーマネージャーの起動はソースコード\ref{src:alice_ntm_run}の様に行う.
21 \begin{lstlisting}[frame=lrbt,label=src:alice_ntm_run,caption=Alice によるネットワークトポロジーマネージャーの起動,numbers=left] 21 \begin{lstlisting}[frame=lrbt,label=src:alice_ntm_run,caption=Alice によるネットワークトポロジーマネージャーの起動,numbers=left]
22 % java -cp Alice.jar alice.topology.manager.TopologyManager -p 10000 -conf ./topology/tree5.dot 22 % java -cp Alice.jar alice.topology.manager.TopologyManager -p 10000 -conf ./topology/tree5.dot
23 \end{lstlisting} 23 \end{lstlisting}
24 -p オプションはトポロジーマネージャーが開くポートの番号, -conf オプションには dot ファイルのパスを渡す. 24 -p オプションはトポロジーマネージャーが開くポートの番号, -conf オプションには dot ファイルのパスを渡す.
25 25
26 ポート番号は Alice により記述された並列分散プログラムの起動時に渡す必要がある. 26 ポート番号は Alice により記述された並列分散プログラムの起動時に渡す必要がある.
27 dot ファイルには, トポロジーをどのように形成するかが書かれている. 27 dot ファイルには, トポロジーをどのように形成するかが書かれている.
28 以下に, サーバノード数5で, 2分木ツリー構造を形成する dot ファイルの例を示す(\ref{src:alice_dot}). 28 以下に, サーバノード数5で, 2分木ツリー構造を形成する dot ファイルの例を示す(ソースコード\ref{src:alice_dot}).
29 \newpage 29 \newpage
30 \begin{lstlisting}[frame=lrbt,label=src:alice_dot,caption=ネットワークトポロジー設定用 dot ファイル,numbers=left] 30 \begin{lstlisting}[frame=lrbt,label=src:alice_dot,caption=ネットワークトポロジー設定用 dot ファイル,numbers=left]
31 % cat tree5.dot 31 % cat tree5.dot
32 digraph test { 32 digraph test {
33 node0 -> node1 [label="child1"] 33 node0 -> node1 [label="child1"]
69 %"child1", "child2", "parent" というキーを使うことで別のサーバノードにあるデータを取得することができる. 69 %"child1", "child2", "parent" というキーを使うことで別のサーバノードにあるデータを取得することができる.
70 %これでトポロジーマネージャーが起動される. 70 %これでトポロジーマネージャーが起動される.
71 71
72 \subsection{アプリケーション側の記述} 72 \subsection{アプリケーション側の記述}
73 次は Jungle 側のプログラムが最初に Alice のトポロジーノードと通信を行うようにする. 73 次は Jungle 側のプログラムが最初に Alice のトポロジーノードと通信を行うようにする.
74 そのためには Alice の TopologyNode クラスに必要な情報を渡してインスタンスを生成する(\ref{src:app_start}). 74 そのためには Alice の TopologyNode クラスに必要な情報を渡してインスタンスを生成する(ソースコード\ref{src:app_start}).
75 \begin{lstlisting}[frame=lrbt,label=src:app_start,caption=アプリケーションの起動,numbers=left] 75 \begin{lstlisting}[frame=lrbt,label=src:app_start,caption=アプリケーションの起動,numbers=left]
76 public static void main( String[] args ) throws Exception 76 public static void main( String[] args ) throws Exception
77 { 77 {
78 RemoteConfig conf = new RemoteConfig(args); 78 RemoteConfig conf = new RemoteConfig(args);
79 new TopologyNode(conf, new StartJungleCodeSegment(args, conf.bbsPort)); 79 new TopologyNode(conf, new StartJungleCodeSegment(args, conf.bbsPort));
86 StartJungleCodeSegment には通常のアプリケーションの処理が書かれる. 86 StartJungleCodeSegment には通常のアプリケーションの処理が書かれる.
87 87
88 アプリケーションの起動時にはコンフィグの情報として, トポロジーマネージャーが動いているサーバのドメインとポート番号を 88 アプリケーションの起動時にはコンフィグの情報として, トポロジーマネージャーが動いているサーバのドメインとポート番号を
89 渡す必要がある. 89 渡す必要がある.
90 例えば, mass00.cs.ie.u-ryukyu.ac.jp というサーバ上でポート番号10000を指定してトポロジーマネージャーを 90 例えば, mass00.cs.ie.u-ryukyu.ac.jp というサーバ上でポート番号10000を指定してトポロジーマネージャーを
91 起動した場合は次のようになる(\ref{src:run_program}). 91 起動した場合は次のようになる(ソースコード\ref{src:run_program}).
92 \begin{lstlisting}[frame=lrbt,label=src:run_program,caption=トポロジーマネージャーの利用,numbers=left] 92 \begin{lstlisting}[frame=lrbt,label=src:run_program,caption=トポロジーマネージャーの利用,numbers=left]
93 % java Program -host mass00.cs.ie.u-ryukyu.ac.jp -port 10000 93 % java Program -host mass00.cs.ie.u-ryukyu.ac.jp -port 10000
94 \end{lstlisting} 94 \end{lstlisting}
95 95
96 \section{Alice を用いての分散実装} 96 \section{Alice を用いての分散実装}
97 Aliceのポロジー形成と他のサーバのデータへのアクセスする機構を用いるためには, Aliceが 97 Aliceのポロジー形成と他のサーバのデータへのアクセスする機構を用いるためには, Aliceが
98 提供するプログラミングスタイルに沿わなければならない. 98 提供するプログラミングスタイルに沿わなければならない.
99 それはDataSegment(データ)とCodeSegment(タスク)によるプログラムである. 99 それはDataSegment(データ)とCodeSegment(タスク)によるプログラムである.
100 ここではまずDataSegmentとCodeSegmentによるプログラムの方法について説明し, 他サーバとの 100 ここではまず, DataSegmentとCodeSegmentによるプログラムの方法について説明し, 他サーバとの
101 通信部分の実装について述べる. 101 通信部分の実装について述べる.
102 102
103 \subsection{Alice によるプログラミング} 103 \subsection{Alice によるプログラミング}
104 AliceはDataSegment(データ)とCodeSegment(タスク)単位でプログラミングを行うことを述べた. 104 AliceはDataSegment(データ)とCodeSegment(タスク)単位でプログラミングを行うことを述べた.
105 CodeSegmentには計算に必要なDataSegmentが登録される. 105 CodeSegmentには計算に必要なDataSegmentが登録される.
106 そしてDataSegmentが準備され次第CodeSegmentによる計算が実行される. 106 そしてDataSegmentが準備され次第CodeSegmentによる計算が実行される.
107 DataSegmentの取得は文字列のキーを使うことで行える. 107 DataSegmentの取得は文字列のキーを使うことで行える.
108 コード\ref{src:cs_sample}にCodeSegmentの例を示す. 108 ソースコード\ref{src:cs_sample}にCodeSegmentの例を示す.
109 \newpage 109 \newpage
110 \begin{lstlisting}[frame=lrbt,label=src:cs_sample,caption=CodeSegmentの実行,numbers=left] 110 \begin{lstlisting}[frame=lrbt,label=src:cs_sample,caption=CodeSegmentの実行,numbers=left]
111 public class TestCodeSegment extends CodeSegment { 111 public class TestCodeSegment extends CodeSegment {
112 public Receiver arg1 = ids.create(CommandType.TAKE); 112 public Receiver arg1 = ids.create(CommandType.TAKE);
113 113
145 上記のコード19行目ではputにより"count"をキーとして数値の0を登録している. 145 上記のコード19行目ではputにより"count"をキーとして数値の0を登録している.
146 putがされるとcsの計算が始まり別スレッドにより8行目からの処理が行われる. 146 putがされるとcsの計算が始まり別スレッドにより8行目からの処理が行われる.
147 147
148 putによりキー"count"に登録された数値0はReceiverであるdsを使って取ることができる. 148 putによりキー"count"に登録された数値0はReceiverであるdsを使って取ることができる.
149 7行目から13行目では\verb|ds.asInteger()|により, "count"に登録したデータの中身を受け取りインクリメントし出力する. 149 7行目から13行目では\verb|ds.asInteger()|により, "count"に登録したデータの中身を受け取りインクリメントし出力する.
150 そして最後には\verb|ods.put|を行っている. 150 そして, 最後には\verb|ods.put|を行っている.
151 新たなTestCodeSegmentも生成しており, これはインクリメントされた"count"がputされることで実行される. 151 新たなTestCodeSegmentも生成しており, これはインクリメントされた"count"がputされることで実行される.
152 この一連の処理を"count"の数値が10以上になるまで行う. 152 この一連の処理を"count"の数値が10以上になるまで行う.
153 153
154 DataSegmentへデータの追加とCodeSegmentの実行について表した図\ref{fig:testcodesegment}になる. 154 DataSegmentへデータの追加とCodeSegmentの実行について表した図\ref{fig:testcodesegment}になる.
155 \begin{figure}[htpb] 155 \begin{figure}[htpb]
180 ネットワークを介したDataSegmentへのアクセスはそのサーバノードを示す 180 ネットワークを介したDataSegmentへのアクセスはそのサーバノードを示す
181 文字列のキーを追加することで行える. 181 文字列のキーを追加することで行える.
182 他サーバノードを示す文字列のキーとは図\ref{fig:remote_cs}に矢印の隣に書かれている文字列 182 他サーバノードを示す文字列のキーとは図\ref{fig:remote_cs}に矢印の隣に書かれている文字列
183 "parent", "child1", "child2" のことを指す. 183 "parent", "child1", "child2" のことを指す.
184 例えば, server node0 が server node1のDataSegmentに入っている"count"というデータを 184 例えば, server node0 が server node1のDataSegmentに入っている"count"というデータを
185 を使用したい場合は, 次のようにsetKeyを行えばよい(\ref{src:remote_cs1}). 185 を使用したい場合は, 次のようにsetKeyを行えばよい(ソースコード\ref{src:remote_cs1}).
186 \begin{lstlisting}[frame=lrbt,label=src:remote_cs1,caption=CodeSegmentで他サーバノードのDataSegmentを使用する,numbers=left] 186 \begin{lstlisting}[frame=lrbt,label=src:remote_cs1,caption=CodeSegmentで他サーバノードのDataSegmentを使用する,numbers=left]
187 CodeSegment cs = new RemoteCodeSegment(); 187 CodeSegment cs = new RemoteCodeSegment();
188 cs.arg1.setKey("child1", "count"); 188 cs.arg1.setKey("child1", "count");
189 \end{lstlisting} 189 \end{lstlisting}
190 また, 他サーバノードのDataSegmentにデータを送りたい場合は, putを行うときにサーバノードへのキーを 190  また, 他サーバノードのDataSegmentにデータを送りたい場合は, putを行うときにサーバノードへのキーを
191 追加すればよい. 191 追加すればよい.
192 例として, server node1やserver node2がserver node0のDataSegmentに"message"というキーでデータを追加したい場合 192 例として, server node1やserver node2がserver node0のDataSegmentに"message"というキーでデータを追加したい場合は, 次のようになる(ソースコード\ref{src:remote_cs2}).
193 次のようになる(\ref{src:remote_cs2}).
194 \begin{lstlisting}[frame=lrbt,label=src:remote_cs2,caption=他サーバーノードのDatasSegmentにデータを追加する,numbers=left] 193 \begin{lstlisting}[frame=lrbt,label=src:remote_cs2,caption=他サーバーノードのDatasSegmentにデータを追加する,numbers=left]
195 ods.put("parent", "message", "Hello parent"); 194 ods.put("parent", "message", "Hello parent");
196 \end{lstlisting} 195 \end{lstlisting}
197 196
198 \subsection{独自クラスのインスタンスの送受信} 197 \subsection{独自クラスのインスタンスの送受信}
203 扱うことができる. 202 扱うことができる.
204 203
205 MessagePackによりシリアライズとなるクラスはいくつか制限がある. 204 MessagePackによりシリアライズとなるクラスはいくつか制限がある.
206 それはそのクラスに@Messageアノテーションを付けることと, そのクラスが保持するフィールドが 205 それはそのクラスに@Messageアノテーションを付けることと, そのクラスが保持するフィールドが
207 MessagePackによりシリアライズ可能であることである. 206 MessagePackによりシリアライズ可能であることである.
208 例えば次のようなクラスである. 207 例えば次のようなクラスである(ソースコード\ref{src:msgpack1}).
209 \begin{lstlisting}[frame=lrbt,label=src:msgpack1,caption=MessagePackによりシリアライズ可能なクラス1,numbers=left] 208 \begin{lstlisting}[frame=lrbt,label=src:msgpack1,caption=MessagePackによりシリアライズ可能なクラス1,numbers=left]
210 import org.msgpack.annotation.Message 209 import org.msgpack.annotation.Message
211 210
212 @Message 211 @Message
213 public class Student { 212 public class Student {
214 String name; 213 String name;
215 int age; 214 int age;
216 } 215 }
217 \end{lstlisting} 216 \end{lstlisting}
218 上記のStudentクラスはプリミティブ型しか保持していない. 217  上記のStudentクラスはプリミティブ型しか保持していない.
219 そのためシリアライズが可能である 218 そのためシリアライズが可能である
220 また, 次のようなクラスもシリアライズ可能な型となる. 219 また, 次のようなクラスもシリアライズ可能な型となる(ソースコード\ref{src:msgpack2}).
221 \begin{lstlisting}[frame=lrbt,label=src:msgpack2,caption=MessagePackによりシリアライズ可能なクラス2,numbers=left] 220 \begin{lstlisting}[frame=lrbt,label=src:msgpack2,caption=MessagePackによりシリアライズ可能なクラス2,numbers=left]
222 import org.msgpack.annotation.Message 221 import org.msgpack.annotation.Message
223 222
224 @Message 223 @Message
225 public class Class { 224 public class Class {
226 List<Student> studentList; 225 List<Student> studentList;
227 } 226 }
228 \end{lstlisting} 227 \end{lstlisting}
229 この場合, フィールドはプリミティブな型でないStudentクラスのフィールドを保持している. 228  この場合, フィールドはプリミティブな型でないStudentクラスのフィールドを保持している.
230 しかし, Studentクラスはシリアライズ可能な形で作成しているため, クラスのフィールドとして 229 しかし, Studentクラスはシリアライズ可能な形で作成しているため, クラスのフィールドとして
231 保持しても問題はない. 230 保持しても問題はない.
232 231
233 これらの制約にそった形で作成しDataSegmentにネットワークを介してクラスのインスタンス 232 これらの制約にそった形で作成しDataSegmentにネットワークを介してクラスのインスタンス
234 をputすることができる. 233 をputすることができる.
235 DataSegmentから受け取ったデータはそのままではシリアライズされたものため, 一度手元で 234 DataSegmentから受け取ったデータはそのままではシリアライズされたものため, 一度手元で
236 元のクラスにコンバートすることで扱う. 235 元のクラスにコンバートすることで扱う.
237 例として, AliceにおけるStudenクラス(Listing\ref{src:msgpack1})のコンバートを次に示す. 236 例として, AliceにおけるStudenクラスのコンバートを次に示す(ソースコード\ref{src:msgpack1}).
238 \begin{lstlisting}[frame=lrbt,label=src:msgpack3,caption=DataSegment,numbers=left] 237 \begin{lstlisting}[frame=lrbt,label=src:msgpack3,caption=DataSegment,numbers=left]
239 // public Receiver arg1 = ids.create(CommandType.PEEK); 238 // public Receiver arg1 = ids.create(CommandType.PEEK);
240 Student s = arg1.asClass(Student.class); 239 Student s = arg1.asClass(Student.class);
241 \end{lstlisting} 240 \end{lstlisting}
242 MessagePackでシリアライズ可能な形としているためDataSegmentはネットワークを介して 241  MessagePackでシリアライズ可能な形としているためDataSegmentはネットワークを介して
243 送受信が可能である. 242 送受信が可能である.
244 243
245 244
246 \section{ログのシリアライズ} 245 \section{ログのシリアライズ}
247 Jungleの具体的な分散実装について述べる. 246 Jungleの具体的な分散実装について述べる.
270 % TreeOperationLog に木の名前の情報がない 269 % TreeOperationLog に木の名前の情報がない
271 % そのため木の名前を追加して持たせた 270 % そのため木の名前を追加して持たせた
272 % 木がなければそのばでつくるようにした 271 % 木がなければそのばでつくるようにした
273 272
274 \subsection{NetworkTreeOperationLogの実装} 273 \subsection{NetworkTreeOperationLogの実装}
275 NetworkTreeOperationLogの実装の一部を以下(\ref{src:netlog})に示す. 274 NetworkTreeOperationLogの実装の一部を以下(図\ref{src:netlog})に示す.
276 \begin{lstlisting}[frame=lrbt,label=src:netlog,caption=NetworkTreeOperationが持つフィールド,numbers=left] 275 \begin{lstlisting}[frame=lrbt,label=src:netlog,caption=NetworkTreeOperationが持つフィールド,numbers=left]
277 @Message 276 @Message
278 public class NetworkTreeOperationLog implements TreeOperationLog 277 public class NetworkTreeOperationLog implements TreeOperationLog
279 { 278 {
280 public LinkedList<NetworkTreeOperation> list; 279 public LinkedList<NetworkTreeOperation> list;
295 しかし, この時気をつけなければならないことがある. 294 しかし, この時気をつけなければならないことがある.
296 それは, \verb|ods.put|の処理をレスポンスを返すスレッドの中で行うと, レスポンスが悪くなる可能性が 295 それは, \verb|ods.put|の処理をレスポンスを返すスレッドの中で行うと, レスポンスが悪くなる可能性が
297 あることだ. 296 あることだ.
298 そのため, \verb|ods.put|を行うのは別のThreadにしたほうがよい. 297 そのため, \verb|ods.put|を行うのは別のThreadにしたほうがよい.
299 以下のコードはcommitに成功した後に, NetworkTreeOperationへと変換したログを別スレッドに渡し 298 以下のコードはcommitに成功した後に, NetworkTreeOperationへと変換したログを別スレッドに渡し
300 て処理させるコードである. 299 て処理させるコードである(ソースコード\ref{src:logconvert_and_execute}).
301 \begin{lstlisting}[frame=lrbt,label=src:logconvert_and_execute,caption=NetworkTreeOperationをputするために別スレッドを立ち上げる,numbers=left] 300 \begin{lstlisting}[frame=lrbt,label=src:logconvert_and_execute,caption=NetworkTreeOperationをputするために別スレッドを立ち上げる,numbers=left]
302 NetworkTreeOperationLog netLog = new NetworkTreeOperationLog(_uuid, _treeName,newLog); 301 NetworkTreeOperationLog netLog = new NetworkTreeOperationLog(_uuid, _treeName,newLog);
303 CodeSegment cs = new LogPutCodeSegment(netLog); 302 CodeSegment cs = new LogPutCodeSegment(netLog);
304 cs.execute(); 303 cs.execute();
305 \end{lstlisting} 304 \end{lstlisting}
306 305
307 LogPutCodeSegmentの実装は次のようになっている. 306 LogPutCodeSegmentの実装は次のようになっている(ソースコード\ref{src:logputcs}).
308 \begin{lstlisting}[frame=lrbt,label=src:,caption=putを行うためだけのCodeSegmentの用意,numbers=left] 307 \begin{lstlisting}[frame=lrbt,label=src:logputcs,caption=putを行うためだけのCodeSegmentの用意,numbers=left]
309 public class LogPutCodeSegment extends CodeSegment{ 308 public class LogPutCodeSegment extends CodeSegment{
310 NetworkTreeOperationLog log; 309 NetworkTreeOperationLog log;
311 public LogPutCodeSegment(NetworkTreeOperationLog _log) { 310 public LogPutCodeSegment(NetworkTreeOperationLog _log) {
312 log = _log; 311 log = _log;
313 } 312 }
315 public void run() { 314 public void run() {
316 ods.put("log", log); 315 ods.put("log", log);
317 } 316 }
318 } 317 }
319 \end{lstlisting} 318 \end{lstlisting}
320 上で述べた問題は, ベンチマークテストなど, 大量の負荷をかけたさいに発生する. 319  上で述べた問題は, ベンチマークテストなど, 大量の負荷をかけたさいに発生する.
321 負荷とはJungleのデータに変更が加わることである. 320 負荷とはJungleのデータに変更が加わることである.
322 多数のデータの変更により大量のログが生成される. 321 多数のデータの変更により大量のログが生成される.
323 そのため, \verb|ods.put|によりDataSegmentの"log"にアクセスが集中してしまい, レスポンスが 322 そのため, \verb|ods.put|によりDataSegmentの"log"にアクセスが集中してしまい, レスポンスが
324 悪くなっていた. 323 悪くなっていた.
325 \verb|ods.put|を行うタイミングには気をつけなければず, 上記のコードにしても改良の余地はある. 324 \verb|ods.put|を行うタイミングには気をつけなければず, 上記のコードにしても改良の余地はある.
329 次はこのデータを他サーバノードへ送る部分の実装を行う. 328 次はこのデータを他サーバノードへ送る部分の実装を行う.
330 329
331 他サーバノードに対してデータを送るときに必要なことは, そのサーバノードのDataSegmentにアクセスする 330 他サーバノードに対してデータを送るときに必要なことは, そのサーバノードのDataSegmentにアクセスする
332 キーである. 331 キーである.
333 Aliceでは接続を行っている相手のDataSegmentのキーのリストは"\_CLIST"キーを使うことで取得することができる. 332 Aliceでは接続を行っている相手のDataSegmentのキーのリストは"\_CLIST"キーを使うことで取得することができる.
334 "\_CLIST"キーで得られるリストを使って他サーバノードへとデータをputするコードを次に示す. 333 "\_CLIST"キーで得られるリストを使って他サーバノードへとデータをputするコードを次に示す(ソースコード\ref{src:log_put}).
335 334
336 \newpage 335 \newpage
337 \begin{lstlisting}[frame=lrbt,label=src:log_put,caption=他サーバノードへのログの送信部分,numbers=left] 336 \begin{lstlisting}[frame=lrbt,label=src:log_put,caption=他サーバノードへのログの送信部分,numbers=left]
338 public class LogUpdateCodeSegment extends CodeSegment { 337 public class LogUpdateCodeSegment extends CodeSegment {
339 Receiver log = ids.create(CommandType.TAKE); 338 Receiver log = ids.create(CommandType.TAKE);
348 for (String node : list) { 347 for (String node : list) {
349 ods.put(node, log.key, log.getVal()); // Send datasegment to other node 348 ods.put(node, log.key, log.getVal()); // Send datasegment to other node
350 } 349 }
351 : 350 :
352 \end{lstlisting} 351 \end{lstlisting}
353 12行目の\verb|ods.put(node, log.key, log.getVal())|が他サーバノードへデータを送る部分になる. 352 12行目の\verb|ods.put(node, log.key, log.getVal())|が他サーバノードへデータを送る部分になる.
354 変数logにはNetworTreeOperationLogが入っている. 353 変数logにはNetworTreeOperationLogが入っている.
355 変数listには"\_CLIST"により得られたデータが入っている. 354 変数listには"\_CLIST"により得られたデータが入っている.
356 それは文字列のListとなっている. 355 それは文字列のListとなっている.
357 listの中身を1つずつ受け取り, \verb|ods.put|する際に引数として渡してやることで, 他サーバノードの 356 listの中身を1つずつ受け取り, \verb|ods.put|する際に引数として渡してやることで, 他サーバノードの
358 DataSegmentにアクセスが行える. 357 DataSegmentにアクセスが行える.
359 358
360 listの具体的な内容は, 図\ref{fig:tree_topology}で組まれたトポロジーでいうところの, "parent", "child1", "child2" 359 listの具体的な内容は, 図\ref{fig:tree_topology}で組まれたトポロジーでいうところの, "parent", "child1", "child2"
361 の文字列のListとなっている. 360 の文字列のListとなっている.
362 もし子どもとなるサーバノードがないときは"parent"だけがListには入れられる. 361 もし子どもとなるサーバノードがないときは"parent"だけがListには入れられる.
363 362
364
365 \subsection{ログの受信とデータ反映} 363 \subsection{ログの受信とデータ反映}
366 次は受け取ったログからデータの編集を行う部分の実装を行う. 364 次は受け取ったログからデータの編集を行う部分の実装を行う.
367 Jungleはのデータを変更する手段として木構造データ毎にTreeEditorクラスが提供される. 365 Jungleはのデータを変更する手段として木構造データ毎にTreeEditorクラスが提供される.
368 このTreeEditorを使用し, ログに入っているTreeOperationを1つ1つ取り出し同じ編集を行わせる. 366 このTreeEditorを使用し, ログに入っているTreeOperationを1つ1つ取り出し同じ編集を行わせる.
369 例えば次のようになる. 367 例えば次のようになる(ソースコード\ref{src:data_edit}).
370 \begin{lstlisting}[frame=lrbt,label=src:data_edit,caption=ログを受け取ってのデータの反映,numbers=left] 368 \begin{lstlisting}[frame=lrbt,label=src:data_edit,caption=ログを受け取ってのデータの反映,numbers=left]
371 // Receiver log <- "log"キーから取得できるデータが入っている 369 // Receiver log <- "log"キーから取得できるデータが入っている
372 // Jungle jugnle 370 // Jungle jugnle
373 NetworkTreeOperationLog netLog = log.asClass(NetworkTreeOperationLog.class); 371 NetworkTreeOperationLog netLog = log.asClass(NetworkTreeOperationLog.class);
374 String treeName = netLog.getTreeName(); 372 String treeName = netLog.getTreeName();
382 // エラー処理.編集失敗 380 // エラー処理.編集失敗
383 } 381 }
384 editor = either.b(); 382 editor = either.b();
385 } 383 }
386 \end{lstlisting} 384 \end{lstlisting}
387 7行目で取り出されたTreeOperationからさらにNodePathとNodeOperationを取り出しているのが8行目と9行目になる. 385  7行目で取り出されたTreeOperationからさらにNodePathとNodeOperationを取り出しているのが8行目と9行目になる.
388 最後にedit関数にTreeEditorとNodePath, それとNodeOpeartionを引き渡している. 386 最後にedit関数にTreeEditorとNodePath, それとNodeOpeartionを引き渡している.
389 edit関数は次のようになる. 387 edit関数は次のようになる(ソースコード\ref{src:data_edit2}).
390 \begin{lstlisting}[frame=lrbt,label=src:data_edit2,caption=edit関数の実装,numbers=left] 388 \begin{lstlisting}[frame=lrbt,label=src:data_edit2,caption=edit関数の実装,numbers=left]
391 Either<Error, JungleTreeEditor> edit(JungleTreeEditor editor, NodePath path, 389 Either<Error, JungleTreeEditor> edit(JungleTreeEditor editor, NodePath path,
392 NodeOperation nodeOp, int pos) { 390 NodeOperation nodeOp, int pos) {
393 String key = ""; 391 String key = "";
394 Command c = nodeOp.getCommand(); 392 Command c = nodeOp.getCommand();
404 return editor.addNewChildAt(path, pos); 402 return editor.addNewChildAt(path, pos);
405 case DELETE_CHILD: 403 case DELETE_CHILD:
406 return editor.deleteChildAt(path, 0); 404 return editor.deleteChildAt(path, 0);
407 } 405 }
408 \end{lstlisting} 406 \end{lstlisting}
409 NodeOperationのAPIの種類(Command)毎に使用するTreeEditorのAPIを変えている. 407  NodeOperationのAPIの種類(Command)毎に使用するTreeEditorのAPIを変えている.
410 もしNodeOperationのAPIの種類を増えるようなことが合っても, 上記のコードのように 408 もしNodeOperationのAPIの種類を増えるようなことが合っても, 上記のコードのように
411 対応するTreeEditorのAPIを書くことで対応できる. 409 対応するTreeEditorのAPIを書くことで対応できる.
412 410
413 %\subsection{ローカルのデータ編集専用のTreeEditorの用意} 411 %\subsection{ローカルのデータ編集専用のTreeEditorの用意}
414 %データ編集が行われ, 412 %データ編集が行われ,
421 今回の実装ではログであるTreeOperationLogを書き出す. 419 今回の実装ではログであるTreeOperationLogを書き出す.
422 また, TreeOperationLogの情報を保持しつつ, MessagePackでシリアライズできるクラスとして 420 また, TreeOperationLogの情報を保持しつつ, MessagePackでシリアライズできるクラスとして
423 NetworkTreeOperationLogの実装を行った. 421 NetworkTreeOperationLogの実装を行った.
424 422
425 つまり, WriterでNetworkTreeOperationLogを書き出すようにすればよい. 423 つまり, WriterでNetworkTreeOperationLogを書き出すようにすればよい.
426 以下にログをディスクへ書き出すためのクラスPersistentChangeListWriterの実装を示す. 424 以下にログをディスクへ書き出すためのクラスPersistentChangeListWriterの実装を示す(ソースコード\ref{src:writer}).
427 \begin{lstlisting}[frame=lrbt,label=src:writer,caption=NetworkTreeOperationをディスクへ書き出す,numbers=left] 425 \begin{lstlisting}[frame=lrbt,label=src:writer,caption=NetworkTreeOperationをディスクへ書き出す,numbers=left]
428 public class PersistentChangeListWriter implements ChangeListWriter { 426 public class PersistentChangeListWriter implements ChangeListWriter {
429 427
430 MessagePack msgpack; 428 MessagePack msgpack;
431 OutputStream out; 429 OutputStream out;
447 // エラー処理 445 // エラー処理
448 } 446 }
449 return Result.FAILED; 447 return Result.FAILED;
450 } 448 }
451 \end{lstlisting} 449 \end{lstlisting}
452 write関数はJungleのデータ編集が完了すると呼び出される関数である. 450  write関数はJungleのデータ編集が完了すると呼び出される関数である.
453 引数として渡されているChangeListはTreeOperationLogと同じく\verb|Iterable<TreeOperation>|を継承している. 451 引数として渡されているChangeListはTreeOperationLogと同じく\verb|Iterable<TreeOperation>|を継承している.
454 またUUIDや木の名前も取得することができる. 452 またUUIDや木の名前も取得することができる.
455 そのため, NetworkTreeOperationLogへと変換が行える. 453 そのため, NetworkTreeOperationLogへと変換が行える.
456 454
457 ログの書き出しを行いたいときはこのPersistentChangeListWriterを設定することで行えるようになった. 455 ログの書き出しを行いたいときはこのPersistentChangeListWriterを設定することで行えるようになった.
458 これにより木の編集が行われるたびにNetworkTreeOperationLogが書き込まれていく. 456 これにより木の編集が行われるたびにNetworkTreeOperationLogが書き込まれていく.
459 読み込みたいときはMessagePackを使ってディスクから読み込み, データ分散実装と同じの方法で木の編集を行っていく 457 読み込みたいときはMessagePackを使ってディスクから読み込み, データ分散実装と同じの方法で木の編集を行っていく
460 ことができる(Listing\ref{src:data_edit}, \ref{src:data_edit2}). 458 ことができる(ソースコード\ref{src:data_edit}, \ref{src:data_edit2}).
461 459
462 460
463 \newpage 461 \newpage
464 \section{Mergeの実装} 462 \section{Mergeの実装}
465 Jungle に分散実装を行った後の問題としてデータ衝突がある. 463 Jungle に分散実装を行った後の問題としてデータ衝突がある.