view slide/thesis.md @ 43:9067e6c32410 default tip

add backCover
author ichikitakahiro <e165713@ie.u-ryukyu.ac.jp>
date Mon, 28 Feb 2022 22:32:44 +0900
parents ec3761cbbe24
children
line wrap: on
line source

title: GearsOSの分散ファイルシステムの設計
author: Takahiro Ikki, Shinji Kono
profile: 琉球大学理工学研究科情報工学専攻
lang: Japanese
code-engine: coderay


## GearsOSのファイルシステムの設計と実装
- DataGearとCodeGearという単位を用いるOS
- DataGear単位のTransactionとしてファイルシステムを設計
  - 従来のOSのファイルシステムには型とTransactionが無い
- APIとしてTake/Put/Peekを採用した
- 通信としてもDBアクセスとしても使える(メモリからSSDへの通信に見える)
- 本研究ではsocket baseな通信とWordCountの例題を作成した


## GearsOSの基本単位
- CodeGear
  - 実行Codeの単位
  - 入力DataGearと出力DataGearを持つ
  - goto文(jump命令)を使って遷移する
  - 実行単位は途中で割り込まれたりしない(Atmocity)
- DataGear
  - Cの構造体に相当する
  - ノーマルレベルでは変更されない(関数型プログラミング)
- C言語を拡張する形でCbC言語により実装される


## CodeGearとDataGear
- InputDataGearを受け取って、CodeGearが処理し、OutputDataGearを出力する
- OutputDataGearは次のCodeGearのInputDataGearとなる
- ファイルシステムではDataGearをkeyで待ち合わせる
<div style="text-align: center;">
   <img src="images/cg-dg.pdf" alt=cgdgの関係図 width="600">
</div>

## GearsOSのInterface
- JavaのInterfaceに相当する
- APIとなるCodeGearの名前と型を書く(__next(...)が継続)
- 引数渡しの構造体として使う(引数はすべてここに定義される必要がある)
```
typedef struct Tree<>{
    union Data* tree;
    struct Node* node;
    __code put(Impl* tree,Type* node, __code next(...));
    __code get(Impl* tree, Type* node, __code next(...));
    __code remove(Impl* tree,Type* node, __code next(...));
    __code next(...);
} Tree;
```


## Interfaceの呼び出し
- createで作成する(通常の関数呼び出し)
- DataGearとして作成する場合はnewを使う
- gotoでputAPIを呼び出す(nextは継続)
- InterfaceなどのDataGearは、プロセスに相当するContextにすべて格納される
```
struct Queue* queue = createSychronizedQueue(context);
struct Task* task = new Task();
goto queue->put(task, next(...));
```


## Interfaceの実装
- Interfaceの実装に使われるデータ構造を、記述するImplementがある
- 実装で使われるDataGearを記述する(ヒープに確保される)
- create時にAPIを実装するCodeGearが、Interfaceの構造体に代入される
```
typedef struct SynchronizedQueue <> impl Queue {
  struct Element* top;
  struct Element* last;
  struct Atomic* atomic;
} SynchronizedQueue;
```



## CodeGearとDataGearにはメタレベルなものが存在する
- メタレベルな記述はトランスコンパイラにより自動生成される(記述することも可能)
- CodeGearの前後にMetaなCodeGearが挿入される
<div style="text-align: center;">
 <img src="images/meta-cg-dg.pdf" alt="ノーマルレベルとメタレベルの視点からのGearの関係" width="800">
</div>

## stubCodeGearとgoto meta
- ContextからInputDataGearを取り出す(stubCodeGear)
- OutputDataGearをContextに書き込み、次のCodeGearを呼び出す(goto meta)
- stubCodeGear/goto metaは変更可能(メタプログラミング)
<div style="text-align: center;">
 <img src="images/meta-cg-dg.pdf" alt="ノーマルレベルとメタレベルの視点からのGearの関係" width="800">
</div>

## GearsOSのファイルシステムの設計
- DataGearの単位でデータを操作したい
- ファイルは通信データに対応した複数のストリームを持つ
- Transactionとしてatomicに操作したい
  - 従来のファイルシステムのTransactionはUserレベルで実装される
- ファイル操作と通信を同じAPIで実現する
  - Take/Put/Peek
  - ChristieのDataGearManagerを参考にする


## Take/Put/Peek
- ファイルはQueueで構成される
- putでQueueに追加
- takeでQueueからの取り出し
- peekでQueueから取り出さない読み出し
  - 次にTakeされるDataGearを先読みする
<div style="text-align: center;">
   <img src="images/QueueElement.pdf" alt=Queueの構造 width="800">
</div>

## GearsFSのトランザクション
- GearsOSのCodeGear操作はatomicなので割り込まれない
  - atomicityはOSが保証する
  - これによりTake/Put/PeekがTransactionであることを保証する

## QueueによるGearsOSのファイル
- GearsOSのファイルはDataGearを保持するQueueとなる
- オンメモリのファイルに相当する
- Queueをデバイスにcopyして持続性を実現する
- 書き込み先はDataGearManagerで選択する

## PutのImplementation
- QueueのElementをnewで作成する
  - Elementには任意の型のDataGearが格納されている
- Queueのリンクを構築する
- 継続nextに跳ぶ

```
__code putSingleLinkedQueue(struct SingleLinkedQueue* queue, union Data* data, __code next(...)) {
    Element* element = new Element();
    element->data = data;
    element->next = NULL;
    queue->last->next  = element;
    queue->last = element;
    goto next(...);
}
```

## TakeのImplementation
- QueueからElement経由でDataGearを取り出す
- Queueのリンクを修正し、取り出されるデータをnextへ引き渡す
```
__code takeSingleLinkedQueue(struct SingleLinkedQueue* queue, __code next(union Data* data, ...)) {
    printf("take\n");
    struct Element* top = queue->top;
    struct Element* nextElement = top->next;
    if (queue->top == queue->last) {
        data = NULL;
    } else {
        queue->top = nextElement;
        data = nextElement->data;
    }
    goto next(data, ...);
}
```



## GearsOSのDataGearManager
- Take/Put/PeekはDataGearManagerに対して行う
- LocalDGM:メモリ上のQueue
- RemoteDGM:他のノードやプロセスあるいはストレージデバイスをあらわす
  - RemoteDGMは対応する相手のLocalDGMと接続される
- DataGearManager上には複数のQueueがあり、keyで識別する
- Take/Peekは書き込みを待ち合わせる
- 複数のTakeを待ち合わせることができる

## DataGearManagerによる通信構成
- 任意の相手のRemoteDGMを作成することでTopologyが形成される
- RemoteDGMはproxy(RemoteDGMに書き込むと相手のLocalDGMに書き込める)
- この構成は分散フレームワークChristie(当研究室作成)と同じ
<div style="text-align: center;">
 <img src="images/Remote_DataGearManager.pdf" alt="RemoteDGMの関係図" width="550">
</div>


## socket通信によるRemoteDGMの実装
- GearsOSはUnix上の言語フレームワークとして実装されている
- Unixのsocket通信を使ってQueueのputを実装する(send/recvはUnixのAPI)
- proxy側はQueueにputされたDataをsocketで送信する
```
__code sendDataRemoteDGMQueue(struct RemoteDGMQueue* cQueue, union Data* data, __code next(...), __code whenError(...)){
    char recv_buf;
    int send_size, recv_size;

    send_size = send(cQueue->socket, data, sizeof(union Data), 0);
    recv_size = recv(cQueue->socket, &recv_buf, 1, 0);
    //error処理は省略
    goto next(...);
}
```

## 受信側の実装
- ファイル本体(Local側)はsocketからDataを取り出す
- 取り出されたデータはQueueにputされる
```
__code getDataLocalDGMQueue(struct LocalDGMQueue* cQueue, __code next(...), __code whenError(...)){
    int recv_size, send_size;
    char send_buf;

    union Data* recv_data;
    recv_size = recv(cQueue->socket, recv_data, sizeof(union Data), 0);

    //error処理は省略
    Gearef(context, cQueue)->data = recv_data;
    goto putLocalDGMQueue(recv_data, next);
}
```

## 複数のストリームから構成されるファイル
- 入力されるデータに応じた個別のstreamを備えたい
- Streamはkey nameを持ち、keyでアクセスを行う
- Queueのリストとして赤黒木を用いる
- DataのTake/Put時には必ずkey nameの指定が必要となる

<div style="text-align: center;">
 <img src="images/newGearsFile.pdf" alt="複数ストリームの設計" width="300">
</div>

## wordCountの例題
- ファイル内の文字列を1行づつ受け取り、文字列,行数をカウントする例題
- 文字列送信側とCount側を別ノード上で行うことで、ファイルの呼び出しと通信処理が構成できる
<div style="text-align: center;">
 <img src="images/slideGearsWC.pdf" alt="リモートDGMによるWordCount" width="550">
</div>

## wordCountの例題
- 二つのDataGearManagerのペアで構成される
- acknowledgeを逆方向のRemoteDGMによる通信で実現する(現在は直接送信)
<div style="text-align: center;">
 <img src="images/slideGearsWC.pdf" alt="リモートDGMによるWordCount" width="550">
</div>


## 現在のGearsFile APIの開発状況
- 実装ずみ
  - API:put/takeに対応したファイル通信
    - 単一のQueueによる通信の記述をした
  - QueueのリストとなるTree(赤黒木)
  - atomicな操作が行えるQueue(SynchronizedQueue)
    - 複数からのアクセス時にデータ整合を保つ
- 実装中
  - key指定による任意なstreamの操作が行えるファイル
  - ファイル単位での通信の記述(Queue単体でない)


## 結論
- GearsOSのファイルの設計を行った
  - ファイルの構造の設計
    - DataGear単位での操作が行える
  - socketによる通信部分の実装
    - GearsOS上でのソケット通信の記述
  - APIの段階的な設計記述
    - Proxyによるファイル通信
- Queue(stream)単位でない、ファイル単位の通信

## 将来的な課題
- TopoplogyManagerの設計
  - 参加したノードを任意の形のTopologyに接続する機能
  - ファイルシステム向けの機能を追加したい
    - DNS
    - 中枢としてのTopologyノード監視
- Securityシステムの追加
  - ファイルpermission
  - 分散ファイルシステムへの不正なアクセスの防止



## GearsOSの生成形の問題点
- GearsOSのメタレベルの処理の記述はトランスコンパイラにより行われる
- 場合によりメタレベルの記述を行わなくてはならない
  - 他のInterfaceを継承したオブジェクトからのDataGear継承
    - 例)Queueからのデータ取り出し
    - トランスコンパイラはどのInterfaceに記述されたDataGearを参照するべきか判断が難しい

## トランスコンパイラのバグの例
- ContextからのDataGearの取り出し方が間違っている

```
__code Task3(TQueue* localDGMQueue, FileString* string){
    goto Task4();
}

__code Task3_stub(struct Context* context){   //正しいstub
  TQueue* localDGMQueue = (struct TQueue*)Gearef(context, TQueue)->tQueue;
  FileString* string = Gearef(context, TQueue)->data;
  goto Task3(context, localDGMQueue, string);
}

__code Task3_stub(struct Context* context) {  //自動生成されたErrorなstub
	TQueue* localDGMQueue = Gearef(context, TQueue);
	FileString* string = Gearef(context, FileString);
	goto Task3(context, localDGMQueue, string);
}
```

## 並列処理構文par gotoが持つ問題
- par gotoとはGearsOSに実装された並列処理構文である
- StreamQueueに対するput/takeの並列処理の実装をpar goto構文で試みた
- par gotoはトランスコンパイラへの依存性が高い
  - stubCodeGearのように任意な書き換えが行えない
- 特定のCodeGearの宣言のみでしか正常な処理が生成されない
  - Interfaceに記述されたAPICodeGearではバグが生じる
  - par gotoでの使用を前提としたCodeGearを書かなくてはならない
- 処理が重いという問題点も存在する

##  GearsFile APIによるWordCount(1/3)
- FileOpen側(NodeA)とWordCount側(NodeB)でノードが別れる
- (手順1)FileOpen側はFilePloxyにDataRecordをputする
- (手順2)WordCount側は処理の後、ackを返信する
<div style="text-align: center;">
   <img src="images/slideGearsWC.pdf" alt=ChristieAPIによるWordCount width="800">
</div>

##  GearsFile APIによるWordCount(2/3)
- (手順3)1,2をループし、FileOpen側はEoFならフラグを送信する
<div style="text-align: center;">
   <img src="images/slideGearsWC.pdf" alt=ChristieAPIによるWordCount width="800">
</div>

##  GearsFile APIによるWordCount(3/3)
- (手順4)EoFを受信したWordCountは結果を返信し、双方の処理を終了させる
<div style="text-align: center;">
   <img src="images/slideGearsWC.pdf" alt=ChristieAPIによるWordCount width="800">
</div>

## 以下返答用

## PeekのImplementation
- QueueからElement経由でDataGearを取り出す
- Takeとは異なり、Queueのリンクを修正せずに、取り出されるデータをnextへ引き渡す
```
__code peekSingleLinkedQueue(struct SingleLinkedQueue* queue, __code next(union Data* data, ...)) {
    struct Element* top = queue->top;
    struct Element* nextElement = top->next;
    if (queue->top == queue->last) {
        data = NULL;
    } else {
        data = nextElement->data;
    }
    goto next(data, ...);
}
```

## Take/Put/Peek
- PeekはReadOnly (最新の設定を読みこむなど)
- Take/PutはDataGearが一つならUpdateに相当する
- 書き込みが単一スレッドなら順序は保証される
- 書き込みが複数の場合、Putの順序は保証されない
- データベースとの違い
  - putがQueueとして蓄積される
  - Keyが一つしかない(通信路として使える)

## __code next(int ret, ...)の意味
- 軽量継続を表す
- nextは引数として渡されたCodeGear
- int ret は返す値
- ...は軽量継続の呼び出された時の値渡しのInterface
- 一段の呼び出しStackのような役割になる

## CodeGearと再帰呼び出し
- 再起呼び出ししなければ関数呼び出し的に使える(末尾再起)
- 再帰呼び出ししたい場合、明示的に自分でStackを作る
- ...はContextにすべて置かれている
- Processはすべて異なるContextを持っている
- Context自体は共有されない

## DataGearの型
- union Data は一つのプロセス(Context)で使われるすべてのDataGearのUnion
- GearsOSはメタ部分に型に対応する番号を持っている
- 番号を使って型を識別することができる
- 任意の型を格納できるQueueやStackを作成することが可能
- メタレベルではunion Dataを使ってDataGearの詳細に立ち入らず処理できる

## RemoteDGMとacknowledge
- Take/Put/Peekのコマンドは TCP上でacknowledgeを使って通信されている
  - これとは別に自分と相手のCodeGearどうしのacknowledgeが必要
- RemoteDataGearManager経由でacknowledgeを返すのが正しい
  - acknowledgeが重複してしまう
  - メタプログラミングを利用してこの重複を消すことは可能
    - 煩雑な処理

## 複数のストリームによる利点
- 例えばUSBは複数のチャネルを持つ
  - メタデータの取り出しは別streamになる
- 複数の通信によりファイル通信の制御を行う場合がある
  - 通信の停止などのための通信
- 通信として使う場合に複数のプロトコルがある方が良い(FTP)