分散フレームワークChristieを用いたリモートエディタの実装

分散フレームワークChristieを用いたリモートエディタの実装

author: Takahiro Ikki, Shinji Kono profile: 琉球大学 lang: Japanese code-engine: coderay

# 研究目的, 背景

  • リモートエディタとは別マシン上から同時に複数人が一つのファイルを編集することができる。
    • ペアプログラミングやリモートワークに特に有効である。
  • 完全同期式の既存のリモートエディタアプリケーションにはVisual Stdio Codeのlive share機能がある。
    • 同時編集するには編集環境を統一しなくてはならない。
  • 編集に参加するユーザーがそれぞれ好きなエディタが使えるアプリケーションを作成する。
  • 本研究室で開発している分散フレームワークChristieを使って開発する。
    • ChristieはGearというプログラミング概念の性質上、リモートエディタと相性がよい。

# リモートエディタの概要説明

  • 通信接続の構成や更新のやり取りはChristieが基盤となる。
  • サーバーとノードに別れ、サーバーが編集ファイルの正しい状態を保持する。
  • ノードはサーバーのファイルを手元で開き編集を行える。
    • ノードが起こしたファイルへの変更を、命令コマンドとして接続しているサーバー(ハブ)へ送信&実行させる。
  • 命令コマンドはサーバーへ集められ、サーバーは受け取ったコマンドを他の接続ノードへ送信し、実行させる。

# テスト用テキストエディタ

  • Christieはjava言語で作成されている
  • 基本構成のために、javaのswingを用いてテキストエディタを制作した。
  • エディタ部分の入力、削除の取得はDocument Listenerクラスを使った。
    • insertUpdate、removeUpdateメソッドがそれぞれ挿入、削除を検知した時に動作する。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
textArea = new JTextArea();
textArea.getDocument().addDocumentListener(new MyDocumentListener());

public class MyDocumentListener implements DocumentListener {
    @Override
    public void insertUpdate(DocumentEvent e) {
    
    }
    
    @Override
    public void removeUpdate(DocumentEvent e) {

    }
    @Override
    public void changedUpdate(DocumentEvent e) {
    
    }
}

# Christie

  • Christieは当研究室で開発している分散フレームワークである.
  • ChristieではデータをGearという単位で分割して記述を行う。
    • Codegear、DataGear、CodeGearManager、DagaGearManagerの四種類が存在しする。
    • CodeGear = スレッド、クラス
    • DataGear = 変数データ
    • CodeGearManager = ノード
    • DataGearManager = データベースプール

# CodeGear(以下CG)

  • 設定されたkeyに全てのDGが格納されると動作し、DGを参照しながらクラス部分を実行できる。

# DataGear(以下DG)

  • CGに指定されたkeyに差し込まれる。
  • アノテーションを使って記述する。
  • ノードの同士がこのDGを差し込み合うことで通信を構成する。

# CodeGearManager(以下CGM)

  • CGを指定してsetupすることでCGを動かすことができる。
  • putという操作でDGを対応したDGMに格納する。

# DataGearManager(以下DGM)

  • CGMが所持している。
  • プールになっておりputされたDGが保存され、keyとデータが結び付けられる。

# Christieのコード例

1
2
3
4
5
6
7
8
9
public class StartHelloWorld extends StartCodeGear {

    public static void main(String[] args){
        CodeGearManager cgm = createCGM(10000);
        cgm.setup(new HelloWorldCodeGear());
        cgm.getLocalDGM().put("helloWorld","hello");
        cgm.getLocalDGM().put("helloWorld","world");
    }
}
1
hello world

# DGのアノテーション

  • DGを取り出す際にはCG内で宣言した変数にアノテーションをつける。
  • DGアノテーションにはTake、Peek、TakeFrom、PeekFrom、の4つがある。
    • Take
      • DGMに保管された先頭のDGを読み込み、そのDGを削除する。
    • Peek
      • DGMに保管された先頭のDGを読み込むが、DGが消去されない。そのため特に操作をしない場合、同じデータを参照し続ける。
    • TakeFrom
      • Remote DGM nameを指定することで、その接続先のDGM からTake操作をおこえる。
    • PeekFrom
      • Remote DGM nameを指定することで、その接続先のDGM からPeek操作をおこえる。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
public class HelloWorldCodeGear extends CodeGear {

    @Take
    String helloWorld;

    @Override
    protected void run(CodeGearManager cgm) {
        System.out.print(helloWorld + " ");
        cgm.setup(new HelloWorldCodeGear());
    }
}

# LocalDGMとRemoteDGM

  • CGMはDGをputという操作を使って、自身や他ノードのDGMにDGを書き込ませる。
  • DGMにはLocalDGMとRemoteDGMが存在する。
    • LocalDGMは各ノード固有のデータベースである。
    • RemoteDGMは他ノードのLocalDGMに対応するプールであり、接続しているノードの数だけ存在する。
  • DGMのput操作を行う際にはLocalとRemoteのどちらかを選ぶ.
    • Localであれば、LocalのCGMが管理するDGMに対しDGを格納。
    • RemoteDGMを指定してputすることで、接続している任意のノードにDGを差し込ませることができる。
1
cgm.getDGM("nodeB").put("Command" , cmd);

# TopologyManager

  • 通信形成をより簡潔に行ってくれる機能である。
    • Topologyに参加を表明したノードを自動的に配線する。
    • 自動的に接続しているノードに相対的にラベルをつける。
  • 静的Topology形成
    • dotファイルを与えることノード関係の構築を行う。
    • ノード数が想定と一致しないと動作しない。
  • 動的Topology形成
    • 参加を表明したノードに対し、動的にノード同士の関係を作る。
    • 例えばTreeを構成する場合、参加したノードから順にrootに近い役割を与える。
1
2
3
4
5
digraph test {
	node0 -> node1 [label="right"]
	node1 -> node2 [label="right"]
	node2 -> node0 [label="right"]
}

# コマンドパターンの解説

  • コマンドパターンとは命令を一つのオブジェクトとして表現するプログラム手法である。
  • 命令を表すクラスを作成し、インスタンスを作成と同時に命令の中身を入力することで命令を作成する。
  • 以下のプログラムの場合、三つの変数決定しつつインスタンスを作成する、これが命令コマンドとなる。
    • DGとして相手ノードのRemoteDGMにputすれば通信が行える。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
  import org.msgpack.annotation.Message;

  @Message
  class RTCommand {
      public String line;
      public String cmd;
      public int offset;
      
      public RTCommand(String cmd, String line, int i) {
          this.cmd = cmd;
          this.line = line;
          this.offset = i;
      }
  }

# コマンドパターン実装の際に起こった問題

  • クラスを他ノードに送信するためには、クラスをシリアライズして送信する必要がある。
    • コマンドの送信にはmsgpackクラスとjavassistを利用している。
  • しかし、送信がうまく行えなかった。
    • javaのバージョン進行のため、msgpackバージョン0.6.12が非対称となっていた。
    • msgpackの最新バージョン0.8.20はシリアライズ機能がうまく機能しなくなっていた。

# コマンドパターンを実装するための修正

  • 以上の原因に対処するため以下の対処を行った。
    • javassistのバージョンを最新版へ変更した。
    • シリアライズする命令クラスに対し、クラスをpublicに変更した。
  • 自身でシリアライズ機能をChristieに内蔵してしまえば、これらのパッケージは不要になる。

# デモンストレーション

# 編集位置の相違

  • 同期編集のセッションでは命令コマンドの送信のすれ違いにより、ノードごとのファイル状態が異なってしまうことがある。
  • EditorAとnodeはそれぞれの命令を自身のエディタバッファに施してから命令を送信する
    • 結果バッファ状態が異なる状態で受け取った命令を実行してしまう。

# 編集の相違の解消

  • 同期編集のセッションはスター型の通信接続で行うため、サーバー対複数ノードの通信間で相違が発生する。
  • 編集の相違を防ぐためには二つの処理を行う必要がある。
    • サーバーとノード間の命令のすれ違いが発生したことを検知する。
    • すれ違いが発生した際に、オフセットのズレを修正する。
  • サーバーが正しいファイルの状態を保持するためサーバーの状態にノードが合わせる必要がある。

# スター型通信

  • 同期通信はスター型での接続を行う。
  • スター型通信の利点は
    • サーバーが正しいファイル状態を保持するため、整合性を保つことができる。
    • どこかのノードが切断されても、障害の範囲をそのノードのみに抑えることができる。
    • 新しいノードが参加した、もしくは復帰の際にはサーバーのファイル状況を参照するのみで参加、復帰ができる。

# まとめとこれから

  • 本研究発表ではリモートエディタの開発とそれに伴う技術について述べた。
  • コマンドパターンを実装し、通信の大部分はChristieが行ってくれる。
  • 現時点では最低限のセッションを動かすまでの最低限の実装は終わっていない。
  • これから取り組まなければならない課題として以下が挙げられる。
    • 編集するファイルの共有方法
      • ファイルをそのまま送信すると、負担が大きいと予想される。
    • 既存のエディタを同期通信に対応させる。
  • 以上の課題の課題に取り組み、これからも実装を続けていきたい。
Licensed under CC BY-NC-SA 4.0
comments powered by Disqus
Built with Hugo
Theme Stack designed by Jimmy