Mercurial > hg > Papers > 2014 > nobuyasu-master
comparison paper/chapter4.tex @ 63:d770a2b534b3
Writed description of persistent
author | Nobuyasu Oshiro <dimolto@cr.ie.u-ryukyu.ac.jp> |
---|---|
date | Sat, 01 Feb 2014 15:59:14 +0900 |
parents | 2cb5ac9282b0 |
children | 4f31182c8244 |
comparison
equal
deleted
inserted
replaced
62:2cb5ac9282b0 | 63:d770a2b534b3 |
---|---|
58 dot ファイル\ref{src:alice_dot}により形成されるトポロジーを図\ref{fig:tree_topology}に示す. | 58 dot ファイル\ref{src:alice_dot}により形成されるトポロジーを図\ref{fig:tree_topology}に示す. |
59 | 59 |
60 | 60 |
61 \begin{figure}[htpb] | 61 \begin{figure}[htpb] |
62 \begin{center} | 62 \begin{center} |
63 \includegraphics[scale=0.70]{figures/tree_topology.pdf} | 63 \includegraphics[scale=0.70]{figures/tree_topology_noarrow.pdf} |
64 \caption{Alice によるネットワークトポロジー形成} | 64 \caption{Alice によるネットワークトポロジー形成} |
65 \label{fig:tree_topology} | 65 \label{fig:tree_topology} |
66 \end{center} | 66 \end{center} |
67 \end{figure} | 67 \end{figure} |
68 | 68 |
69 矢印に書かれている文字列は, 相手のデータにアクセスするキーを示す. | 69 %矢印に書かれている文字列は, 相手のデータにアクセスするキーを示す. |
70 "child1", "child2", "parent" というキーを使うことで別のサーバノードにあるデータを取得することができる. | 70 %"child1", "child2", "parent" というキーを使うことで別のサーバノードにあるデータを取得することができる. |
71 %子共となるノードは "parent" キーにより親の DSM (Remote DSM) にアクセスすることができる. | 71 %これでトポロジーマネージャーが起動される. |
72 %また, 親も子供となるノードの DSM に対して "child1" や "child2" キーによりアクセスすることが可能となる. | |
73 これでトポロジーマネージャーが起動される. | |
74 | 72 |
75 \subsection{アプリケーション側の記述} | 73 \subsection{アプリケーション側の記述} |
76 次は Jungle 側のプログラムが最初に Alice のトポロジーノードと通信を行うようにする. | 74 次は Jungle 側のプログラムが最初に Alice のトポロジーノードと通信を行うようにする. |
77 そのためには Alice の TopologyNode クラスに必要な情報を渡してインスタンスを生成する(\ref{src:app_start}). | 75 そのためには Alice の TopologyNode クラスに必要な情報を渡してインスタンスを生成する(\ref{src:app_start}). |
78 \begin{lstlisting}[frame=lrbt,label=src:app_start,caption=アプリケーションの起動,numbers=left] | 76 \begin{lstlisting}[frame=lrbt,label=src:app_start,caption=アプリケーションの起動,numbers=left] |
168 \subsection{他サーバノードのDataSegmentへアクセス} | 166 \subsection{他サーバノードのDataSegmentへアクセス} |
169 Aliceにおける基本的なプログラミングは述べた. | 167 Aliceにおける基本的なプログラミングは述べた. |
170 次はネットワークを介して他サーバノードのDataSegmentにアクセスするプログラムについて述べる. | 168 次はネットワークを介して他サーバノードのDataSegmentにアクセスするプログラムについて述べる. |
171 | 169 |
172 まず, Aliceにより2分木3ノードのトポロジーが形成された場合を想定する. | 170 まず, Aliceにより2分木3ノードのトポロジーが形成された場合を想定する. |
173 その時に実際に作られるトポロジーを図\ref{fig:remote_cs}に示す. | 171 その時に実際に作られるトポロジーは図\ref{fig:remote_cs}となる. |
174 \begin{figure}[htpb] | 172 \begin{figure}[htpb] |
175 \begin{center} | 173 \begin{center} |
176 \includegraphics[scale=0.70]{figures/remote_codesegment.pdf} | 174 \includegraphics[scale=0.70]{figures/remote_codesegment.pdf} |
177 \caption{トポロジーの形成} | 175 \caption{トポロジーの形成} |
178 \label{fig:remote_cs} | 176 \label{fig:remote_cs} |
286 Listにより保持しているNetworkTreeOperationはTreeOperationをシリアライズ可能な形にしたものである. | 284 Listにより保持しているNetworkTreeOperationはTreeOperationをシリアライズ可能な形にしたものである. |
287 TreeOperationLogをimplementsし, 木の名前とtimestampをを保持する. | 285 TreeOperationLogをimplementsし, 木の名前とtimestampをを保持する. |
288 他サーバノードへ伝える必要のある情報が増えた場合, このようにNetworkTreeOperationLogに情報を付与することで | 286 他サーバノードへ伝える必要のある情報が増えた場合, このようにNetworkTreeOperationLogに情報を付与することで |
289 対応することができる. | 287 対応することができる. |
290 | 288 |
291 \subsection{ログの送信} | 289 \subsection{ログの送信部分} |
292 ログを送信するタイミングはいつ行うか. | 290 ログを送信するタイミングはいつ行うか. |
293 それは, 木の編集が成功した時である. | 291 それは, 木の編集が成功した時である. |
294 木の編集が成功した結果得られるTreeOperationLogをNetworkTreeOperationLogに変換し, \verb|ods.put|を使って | 292 木の編集が成功した結果得られるTreeOperationLogをNetworkTreeOperationLogに変換し, \verb|ods.put|を使って |
295 CodeSegment側から利用できるようにする. | 293 CodeSegment側から利用できるようにする. |
296 | 294 |
317 @Override | 315 @Override |
318 public void run() { | 316 public void run() { |
319 ods.put("log", log); | 317 ods.put("log", log); |
320 } | 318 } |
321 \end{lstlisting} | 319 \end{lstlisting} |
322 上で述べた問題は, 通常のアプリケーションとして使用する分には発生しない. | 320 上で述べた問題は, ベンチマークテストなど, 大量の負荷をかけたさいに発生する. |
323 だが, ベンチマークテストなど, 大量の負荷をかけた際に発生する. | 321 負荷とはJungleのデータに変更を加わることである. |
324 ベンチマークテストでは大量のログが生成される. | 322 データの変更により大量のログが生成される. |
325 そのため, \verb|ods.put|によりDataSegmentの"log"にアクセスが集中してしまい, レスポンスが | 323 そのため, \verb|ods.put|によりDataSegmentの"log"にアクセスが集中してしまい, レスポンスが |
326 悪くなっていた. | 324 悪くなっていた. |
327 \verb|ods.put|を行うタイミングには気をつけなければず, 上記のコードにしても改良の余地はある. | 325 \verb|ods.put|を行うタイミングには気をつけなければず, 上記のコードにしても改良の余地はある. |
328 | 326 |
329 | 327 \subsection{他サーバノードへのログの送信} |
330 | 328 上記の実装によりDataSegmentの"log"キーにアクセスすることでTreeOperationLogを取得できるようになった. |
331 \begin{lstlisting}[frame=lrbt,label=src:,caption=,numbers=left] | 329 次はこのデータを他サーバノードへ送る部分の実装を行う. |
332 | 330 |
333 \end{lstlisting} | 331 他サーバノードに対してデータを送るときに必要なことは, そのサーバノードのDataSegmentにアクセスする |
334 | 332 キーである. |
335 | 333 Aliceでは接続を行っている相手のDataSegmentのキーのリストは"\_CLIST"キーを使うことで取得することができる. |
336 \begin{lstlisting}[frame=lrbt,label=src:,caption=,numbers=left] | 334 "\_CLIST"キーで得られるリストを使って他サーバノードへとデータをputするコードを次に示す. |
337 | 335 |
338 \end{lstlisting} | 336 \begin{lstlisting}[frame=lrbt,label=src:log_put,caption=他サーバノードへのログの送信部分,numbers=left] |
339 | 337 public class LogUpdateCodeSegment extends CodeSegment { |
340 | 338 Receiver log = ids.create(CommandType.TAKE); |
341 | 339 Receiver clist = ids.create(CommandType.PEEK); |
342 \subsection{local専用の編集の用意} | 340 |
343 | 341 public LogUpdateCodeSegment() { |
344 | 342 log.setKey("log"); |
343 clist.setKey("_CLIST");; | |
344 } | |
345 | |
346 List<String> list = clist.asClass(List.class); | |
347 for (String node : list) { | |
348 ods.put(node, log.key, log.getVal()); | |
349 } | |
350 : | |
351 \end{lstlisting} | |
352 変数logはNetworTreeOperationLogが入っている. | |
353 変数listには"\_CLIST"により得られたデータが入っている. | |
354 それは文字列のListとなっている. | |
355 listの中身を1つずつ受け取り, \verb|ods.put|する際に引数として渡してやることで, 他サーバノードの | |
356 DataSegmentにアクセスが行える. | |
357 | |
358 listの具体的な内容は, 図\ref{fig:tree_topology}で組まれたトポロジーでいうところの, "parent", "child1", "child2" | |
359 の文字列となっている. | |
360 もし子どもとなるサーバノードがないときは"parent"だけがListには入れられる. | |
361 | |
362 | |
363 \subsection{ログの受信とデータ反映} | |
364 次は受け取ったログからデータの編集を行う部分の実装を行う. | |
365 Jungleはのデータを変更する手段として木構造データ毎にTreeEditorクラスが提供される. | |
366 このTreeEditorを使用し, ログに入っているTreeOperationを1つ1つ取り出し同じ編集を行わせる. | |
367 例えば次のようになる. | |
368 \begin{lstlisting}[frame=lrbt,label=src:data_edit,caption=ログを受け取ってのデータの反映,numbers=left] | |
369 // Receiver log <- "log"キーから取得できるデータが張っている | |
370 // Jungle jugnle | |
371 NetworkTreeOperationLog netLog = log.asClass(NetworkTreeOperationLog.class); // NetworkTreeOperationLogへのコンバート | |
372 String treeName = netLog.getTreeName(); | |
373 JungleTree tree = jungle.getTreeByName(treeName); | |
374 TreeEditor editor = tree.getLocalTreeEditor(); // Editor の取得 | |
375 for (TreeOperation op : netlog) { | |
376 NodePath path = op.getNodePath(); | |
377 NodeOperation nodeOp = op.getNodeOperation(); | |
378 either = edit(editor, path, nodeOp, nodeOp.getPosition()); // データの編集を行う. | |
379 if(either.isA()) { | |
380 // エラー処理.編集失敗 | |
381 } | |
382 editor = either.b(); | |
383 } | |
384 \end{lstlisting} | |
385 7行目で取り出されたTreeOperationからさらにNodePathとNodeOperationを取り出しているのが8行目と9行目になる. | |
386 最後にedit関数にTreeEditorとNodePath, それとNodeOpeartionを引き渡している. | |
387 edit関数は次のようになる. | |
388 \begin{lstlisting}[frame=lrbt,label=src:data_edito2,caption=edit関数の実装,numbers=left] | |
389 Either<Error, JungleTreeEditor> edit(JungleTreeEditor editor, NodePath path, | |
390 NodeOperation nodeOp, int pos) { | |
391 String key = "; | |
392 Command c = nodeOp.getCommand(); | |
393 switch (c) { | |
394 case PUT_ATTRIBUTE: | |
395 key = nodeOp.getKey(); | |
396 ByteBuffer value = nodeOp.getValue(); | |
397 return editor.putAttribute(path, key, value); | |
398 case DELETE_ATTRIBUTE: | |
399 key = nodeOp.getKey(); | |
400 return editor.deleteAttribute(path, key); | |
401 case APPEND_CHILD: | |
402 return editor.addNewChildAt(path, pos); | |
403 case DELETE_CHILD: | |
404 return editor.deleteChildAt(path, 0); | |
405 } | |
406 \end{lstlisting} | |
407 NodeOperationのAPIの種類(Command)毎に使用するTreeEditorのAPIを変えている. | |
408 もしNodeOperationのAPIの種類を増えるようなことが合っても, 上記のコードのように | |
409 対応するTreeEditorのAPIを書くことで対応できる. | |
410 | |
411 %\subsection{ローカルのデータ編集専用のTreeEditorの用意} | |
412 %データ編集が行われ, | |
413 | |
414 \section{永続性の実装} | |
415 次は, ログの書き出しによる永続性の実装について述べる. | |
416 第3章でJungleはWriterいう永続性実装のための機能が元々用意されていることを述べた. | |
417 永続性で考えなければならないことは, どのようなデータをどんなデータ表現で書き込むかということである. | |
418 今回の実装ではログであるTreeOperationLogを書き出す. | |
419 また, TreeOperationLogの情報を保持しつつ, MessagePackでシリアライズできるクラスとして | |
420 NetworkTreeOperationLogの実装を行った. | |
421 | |
422 つまり, WriterでNetworkTreeOperationLogを書き出すようにすればよい. | |
423 以下にログをディスクへ書き出すためのクラスPersistentChangeListWriterの実装を示す. | |
424 \begin{lstlisting}[frame=lrbt,label=src:,caption=NetworkTreeOperationをディスクへ書き出す,numbers=left] | |
425 public class PersistentChangeListWriter implements ChangeListWriter { | |
426 | |
427 MessagePack msgpack; | |
428 OutputStream out; | |
429 | |
430 public PersistentChangeListWriter(OutputStream _out, MessagePack _msgpack) { | |
431 out = _out; | |
432 msgpack = _msgpack; | |
433 } | |
434 @Override | |
435 public Result write(ChangeList cs) | |
436 { | |
437 NetworkTreeOperationLog log | |
438 = new NetworkTreeOperationLog(cs.uuid(), cs.getTreeName(), cs); | |
439 try { | |
440 msgpack.write(out, log); | |
441 out.flush(); | |
442 return Result.SUCCESS; | |
443 } catch (IOException e) { | |
444 // エラー処理 | |
445 } | |
446 return Result.FAILED; | |
447 } | |
448 \end{lstlisting} | |
449 write関数はJungleのデータ編集が完了すると呼び出される関数である. | |
450 引数として渡されているChangeListはTreeOperationLogと同じく\verb|Iterable<TreeOperation>|を継承している. | |
451 またUUIDや木の名前も取得することができる. | |
452 そのため, NetworkTreeOperationLogへと変換が行える. | |
453 | |
454 ログの書き出しを行いたいときはこのPersistentChangeListWriterを設定することで行えるようになった. | |
455 これにより木の編集が行われるたびにNetworkTreeOperationLogが書き込まれていく. | |
456 読み込みたいときはMessagePackを使ってディスクから読み込み, データ分散実装と同じの方法で木の編集を行っていく | |
457 ことができる(Listing\ref{src:data_edit}, \ref{src:data_edit2}). | |
345 | 458 |
346 | 459 |
347 \section{掲示板プログラムにおけるマージの実装} | 460 \section{掲示板プログラムにおけるマージの実装} |
348 Jungle に分散実装を行った後の問題としてデータ衝突がある. | 461 Jungle に分散実装を行った後の問題としてデータ衝突がある. |
349 他のサーバノードから送られてくるデータが既に手元で変更を加えた木構造を対象とした | 462 他のサーバノードから送られてくるデータが既に手元で変更を加えた木構造を対象とした |
395 | 508 |
396 %単一サーバで動いている時の Jungle はただ子ノードとして後ろに追加するだけだが, 分散 | 509 %単一サーバで動いている時の Jungle はただ子ノードとして後ろに追加するだけだが, 分散 |
397 %環境下においては timestamp に従い子ノードを追加する位置を決めるようにする. | 510 %環境下においては timestamp に従い子ノードを追加する位置を決めるようにする. |
398 | 511 |
399 | 512 |
400 | |
401 |