Mercurial > hg > Papers > 2014 > nobuyasu-master
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 に分散実装を行った後の問題としてデータ衝突がある. |