view final_main/chapter4/chapter4.tex @ 13:117794d50054

update
author akahori
date Tue, 19 Feb 2019 21:49:55 +0900
parents bb0c2543c456
children 38f2c997bb93
line wrap: on
line source

%\input{/Users/e155753/.tex/setup}

%%文書開始****************************
\begin{document} 
%%**************************************
\chapter{Christieについて}

Christieは当研究室で開発している分散フレームワークである. Christieには分散プログラムを簡潔に書くための工夫が複数ある.
本章ではChristieについて述べる.
\section{Christieとは}
ChristieはJavaで書かれた分散フレームワークである. Christieは当研究室で開発している GearsOSに組み込まれる予定がある. そのため, GearsOS を構成する言語 Continuation based C と似た概念がある. Christie に存在する概念として次のようなものがある.

\begin{itemize}
\item CodeGear(以下 CG)
\item DataGear(以下 DG)
\item CodeGearManager(以下 CGM)
\item DataGearManager(以下 DGM)
\end{itemize}

CGはクラス, スレッドに相当し, javaの継承を用いて記述する. DGは変数データに相当し, CG内でアノテーションを用いて変数データを取り出せる. CGM はノードであり, DGM, CG, DG を管理する. DGM は DG を管理するものであり, put という操作により変数データ, つまり DG を格納できる.
DGMのput操作を行う際にはLocalとRemoteと2つのどちらかを選び, 変数のkeyとデータを引数に書く. Localであれば,  Local のCGMが管理しているDGMに対し, DGを格納していく. Remoteであれば接続したRemote先の CGMのDGMにDGを格納できる. put操作を行ったあとは, 対象のDGMの中にqueueとして保管される. 
DGを取り出す際には, CG内で宣言した変数データにアノテーションをつける. DGのアノテーションにはTake, Peek, TakeFrom, PeekFromの4つがある. 
\begin{description}
\item[Take] 先頭のDGを読み込み, そのDGを削除する. DGが複数ある場合, この動作を用いる.
\item[Peek] 先頭のDGを読み込むが, DGが削除されない. そのため, 特に操作をしない場合は同じデータを参照し続ける. 
\item[TakeFrom(Remote DGM name)] Takeと似ているが, Remote DGM nameを指定することで, その接続先(Remote)のDGMからTake操作を行える.
\item[PeekFrom(Remote DGM name)] Peekと似ているが, Remote DGM nameを指定することで, その接続先(Remote)のDGMからPeek操作を行える.
\end{description}

以上が, Christieの概要である.

\section{プログラミングの例}
ここでは, Christieで実際にプログラムを記述する例を述べる.
CGMを作り, setup(new CodeGear)を動かすことにより, DGを待ち合わせ, DGが揃った場合にCodeGearが実行される. CGMを作る方法はStartCodeGear(以下SCG)を継承したものからcreateCGM(port) methodを実行することにより, CGMが作られる. SCGのコードの例をソースコード\ref{code:StartHelloWorld}に示す.

\lstinputlisting[caption=StartHelloWorld,label=code:StartHelloWorld]{./src/HelloWorld/StartHelloWorld.java}


\section{TopologyManagerの実装}
Christieは当研究室で開発されたAliceを改良した分散フレームワークである. しかしAliceの機能を全て移行したわけではない. TopologyManagerは最たる例であり, 分散プログラムを簡潔に書くために必要である. そのため, ChristieにTopologyManagerを実装した.

ここでは, TopologyManagerとはどのようなものかを述べる. そして, TopologyManagerを実装する際に, Christie自身のコードを変更する必要があったため, TopologyManagerでどのような問題が起こり, Christieの基本機能をどのような変更したかも述べる.

TopologyManagerとは, Topologyを形成するため, 参加を表明したノード, TopologyNodeに名前を与え, 必要があればノード同士の配線も行うノードである. TopologyManagerのTopology形成方法として, 静的Topologyと動的Topologyがある. 静的Topologyはソースコード\ref{code:dot-example}のようなdotファイルを与えることで, ノードの関係を図\ref{fig:dot-example}のようにさせる. 静的Topologyはdotファイルのノード数と同等のTopologyNodeがあって初めて, CodeGearが実行される. 

\lstinputlisting[caption=ring.dot,label=code:dot-example]{./src/ring.dot}

\begin{figure}[H]
\centering
  \fbox{
   \includegraphics[scale=1]{./images/ring.pdf}
  }
\caption{ソースコード\ref{code:dot-example}, ring.dotを図にしたもの}
\label{fig:dot-example}
\end{figure}



動的Topologyは参加を表明したノードに対し, 動的にノード同士の関係を作る. 例えばTreeを構成する場合, 参加を表明したノードから順に, rootに近い位置の役割を与える. また, CodeGearはノードが参加し, parentに接続したあとに実行される.

TopologyManagerを実装するに当たって, 以下の2つの問題点が出た.

\begin{itemize}
\item Take, Peek操作でSuperClassの型を持ったデータを取り出す際にNullPointerExceptionが表示される.
\item ノード間で繋がる前にput操作を行うとデータが送られない.
\end{itemize}

Take, Peek操作でSuperClassの型を持ったデータを取り出す際にNullPointerExceptionが表示される問題に対しては, DataGearでdataを代入する際にSuperClass, interfacesまで比較するように書き換えた. また, 型の不一致が起こった際は例外を投げるようにした. その修正後のコードをソースコード\ref{code:datagear}に示す.

\begin{lstlisting}[caption=修正後のDataGearのソースコード,label=code:datagear]
public class DataGear<T>{
   
    ...
   
    public void setData(T data) {
        Class dataClazz = data.getClass();

        if(dataClazz == this.clazz){
            this.data = data; return;
        }

        Class dataSuperClazz = dataClazz.getSuperclass();
        while (dataSuperClazz != null) {
            if(dataSuperClazz == this.clazz) {
                this.data = data; return;
            }
            dataSuperClazz = dataSuperClazz.getSuperclass();
        }

        Class<?>[] interfaces = dataClazz.getInterfaces();
        for (Class<?> interfaze : interfaces) {
            if(interfaze == this.clazz) {
                this.data = data; return;
            }
        }

        throw new ClassCastException("datagear cannot set class from " + dataClazz.getName() + " to " + clazz.getName());

    }

}
\end{lstlisting}

TopologyNodeにおいて, 実行するCodeGearをputしておき, 参加するノードがすべて揃ったら, そのCodeGearを実行する. しかし, 実際には実行するCodeGearはCodeGearを継承したものである. Christieは, putされたdataのクラスとTakeされるデータのクラスが一致したならば, dataを代入するという処理を行っている. つまり, SuperClass, interfacesの型までは比較をしない. そのため, 型の不一致が起こり, dataの代入をしないため, NullPointerExceptionが表示されていた. 




ノード間で繋がる前にput操作を行うとデータが送られない問題に対しては, waitを付け加えた. そのコードをソースコード\ref{code:rdg}に示す. この問題は, ノードが繋がる前にputを行うため, 相手のDataGearに書き込みが行われないために起きた. そのため, 相手とDataGearがつながるまでputメソッドをwaitしておき, つながってからput操作を行うように書き換えた.

\begin{lstlisting}[caption=修正後のDataGearのソースコード,label=code:datagear]
public class RemoteDataGearManager extends DataGearManager{
    boolean connect = false;
    Object lock = new Object();

    public RemoteDataGearManager(final String dgmName, final String address, final int port, CodeGearManager cgm) {
        this.cgm = cgm;
        RemoteDataGearManager manager = this;
        new Thread("Connect-" + dgmName) {
            public void run() {
                do {
                    try {
                        SocketChannel sc = SocketChannel.open(new InetSocketAddress(address, port));
                        connection = new Connection(sc.socket(), cgm);
                        connection.name = dgmName;
                        connection.socket.setTcpNoDelay(true);
                        
                        // add lock
                        synchronized (lock){
                            connect = true;
                            lock.notify();
                        }
                    } catch (IOException e) {
                        try {
                            Thread.sleep(50);
                        } catch (InterruptedException e1) {
                            e1.printStackTrace();
                        }
                    }
                } while (!connect);
                IncomingTcpConnection in = new IncomingTcpConnection(connection);
                in.setManager(manager);
                in.setName(dgmName+"-IncomingTcp");
                in.setPriority(MAX_PRIORITY);
                in.start();
                OutboundTcpConnection out = new OutboundTcpConnection(connection);
                out.setName(dgmName + "-OutboundTcp");
                out.setPriority(MAX_PRIORITY);
                out.start();
            }
        }.start();

    }
    
    ...

    @Override
    public void put(String key, Object data) {

        Command cm = new PutCommand(0, null, key, new DataGear(data));
        
        if(!connect) connectWait(); // add wait

        connection.write(cm);
    }
    
    // add method
    public void connectWait(){
        synchronized (lock){
            while(!connect){
                try {
                    lock.wait();
                } catch (InterruptedException e) {
                }
            }
        }
    }
}
\end{lstlisting}

\section{Aliceと比較したChristieの良い点, 悪い点}
Christieの元となった分散フレームワークAliceと比較し, Christieの良い点, 悪い点をそれぞれ述べる.

良い点としては次のようなことが挙げられる.

\begin{itemize}
\item ソースコードの可読性が上がった. Aliceでは動的にDataGearのKeyを変更できるため, 実際に使われているクラスと別のところでKeyが変更されている場合も多かった. しかし, Christieでは変数の名前がKeyとなる. そのため, put操作した変数がどこで使われているかがわかりやすくなった.
\item データの取り出しが簡単. アノテーションを用いることで, データを簡単に取り出すことができる. また, Aliceでは型をコード内で再定義しなければならなかったが, その操作がなくなった.

\item DGMの操作がわかりやすくなった. 
\end{itemize}


悪い点としては次のようなことが挙げられる
\begin{itemize}
\item TakeFrom, PeekFromの使い方が難しい. TakeFrom, PeekFromは引数でDGM nameを指定する. しかし, DGMの名前を静的に与えるよりも, 動的に与えたい場合が多かった.
\item デバッグが難しい. cgm.setupでCodeGearが実行されるが, keyの待ち合わせで止まり, どこで止まっているかわからないことが多かった. 例えば, putするkeyのスペルミスなどでコードの待ち合わせが起こり, CodeGearが実行されず, エラーなども表示されずにwaitすることがあり, どこで止まっているかわからない事があった.
\end{itemize}

\section{Christieにおけるブロックチェーンの実装の利点と欠点}

Christieにおいてブロック, トランザクション, Paxos, Proof of Workを実装した. 
その際, Christieで実装した場合の便利な点を述べる.

\begin{itemize}
\item ブロック, トランザクションを送るのが簡単. ChristieはDataGearという単位でデータを保持する. そのため, ブロックやトランザクションはDataGearに包めばいい.
\item TopologyManagerでのテストが便利. dotファイルが有れば, TopologyManagerが任意の形でTopologyを作れる. そのため, ノードの配置については理想の環境を作れるため, 理想のテスト環境を作ることができる. 
\item 機能ごとにファイルが実装できるため, 見通しが良い. ChristieはCbCのgotoと同じように関数が終わるとsetupによって別の関数に移動する. そのため自然に機能ごとにファイルを作るため, 見通しが良くなる.
\end{itemize}

不便な点を以下に述べる.

\begin{itemize}
\item デバッグが難しい. 4.4の「Christieの良い点, 悪い点」で述べたが, keyのスペルミスなどが起こると, CodeGearが実行されず, waitされる問題が出る.
\item Takeの待ち合わせでCGが実行されない. 2つのCGで同じ変数をTakeしようとすると, setupされた時点で変数がロックされる. このとき, 片方のCGはDGがすべて揃っているのに, すべての変数が揃っていないもう片方のCGに同名の変数がロックされ, 実行されない場合がある. 
\end{itemize}




\newpage

%%文書終了****************************
\end{document}