[背景]
ここのところWindows環境は64bitと32bitの環境が混在している。この状況はまだしばらくは続きそうだ。
32bitは資産が豊富だが、64bitネイティブなプログラムのパフォーマンスも欲しい。
ここで統合アーカイバAPI仕様について考えると、各種DLLは32bit用だ。
将来的には統合アーカイバフロントエンドは64bitネイティブになっていくだろうと思う。
しかしWindows上で32bit-64bitのThunkは無いようなので、フロントエンドとバックエンドは全部64bitか全部32bitで統一しないといけない。
とはいえ、古いプログラム/アルゴリズムだと64bit化を考えていないものもあるだろうし、いずれにしても移植が済むまで時間がかかるだろうから、しばらく統一は無理そうだ。
統合アーカイバ仕様はいずれ64bit化しなければいけないが、どうせ64bit化するなら、この機会に仕様を変更してもいいのではないかと思って、そのたたき台を考えてみた。
誰かやってみませんか?
[やりたいこと]
・32bitの資源と64bitのパフォーマンスの恩恵を受けたい。
・万人にとって、できるだけ32bit->64bitの移行を楽に、混乱無く行いたい。
・仕様を変更するついでに、コマンドなどを統一してプログラムしやすくしたい。
[提案]
・従来通り、フロントエンドとバックエンドの組み合わせとする
・バックエンドはGUIを持たず、完全なエンジンに徹する
→GUIはフロントエンドの役目
・バックエンド、フロントエンドともに単体の実行ファイルとする
→exeに特定のコマンドラインを与えたときのみバックエンドモード、それ以外はどんな挙動でもかまわない
・バックエンドとフロントエンドの通信はOS標準のパイプとする
→HTTP通信を参考に?
・一つのバックエンドを同時に複数実行するときは、複数のプロセスとして起動する
→バックエンドに対してマルチスレッド処理の制約がない
・バックエンド操作はすべて文字列コマンドで行う。コマンドはすべて規格化(基本/拡張Lv.など)しておく
→基本的には1回1コマンド。コマンドラインの解析を可能な限り単純化する。
→バックエンドはステートを持ち、OpenGLのglEnable()のように個別のコマンドで1回の呼び出しにつき1つのステートを変更する。
→バイナリデータの送信は別パイプ(名前付きがよいか?)を開く。手順的には
(Front)データ送信 to data pipe→
(Front)完了通知 from cmd pipe→
(Back)読み込み from data pipe→
(Back)完了通知 to cmd pipe
・通信に使う文字列は少なくともUTF-16を扱えることを必須とする
→アーカイブ中ファイル名文字コードを制約するものではない
→当面大丈夫だと思うが、文字コードを変更できるようにしておくべき
→正規化や非UTF-16に変換するときの規格外文字置き換えのルールも設定できるようにする
・空白や記号('"','\'等)を含む文字列のエスケープ方法を規定する
→現行の統合アーカイバ仕様におけるパスワード設定の混乱を避けたい
・バックエンドは自分の持つ能力を詳細に返答する
→*QueryFunctionList()よりも詳細に
→アーカイブ名や形式名を与えて、扱える文字コードや複数ファイルの格納可能性などを文字列として返答する
・フロントエンドが全ての入出力を行う
→メモリからの直接圧縮/展開などの利用を念頭に
→おそらくファイルポインタのシークのためのコマンドが必要になる
→ただしバックエンドが部分的または全ての入出力を行っても良い
→モード切替でこの動作を変更できるようにする
・他に考えたいこと
→言語ロケールの影響排除
→バックエンドに割り振るスレッド数を設定できるようになるとうれしい
[メリット]
バックエンドを単体のExeとすることで、通常のコマンドラインツールと統合アーカイババックエンドを共通化することもできる。
→特定のコマンドを与えたときのみ統合アーカイババックエンドとして動作するため
また、伝統的なコマンドライン(人間用)と統一されたコマンド(フロントエンド用)が無理なく共存できるため、両者の利点を享受できる。
最終的には従来仕様と比べて単純化できると思われる。
フロントエンドとバックエンドのbit数が一致しなくても良くなる。
32bit/64bitの混在が可能になるほか、要求ランタイムのバージョン違いに起因するトラブルを回避できる。
(.Net CLRにこの種の問題があった気がする。http://blogs.msdn.com/b/oldnewthing/archive/2006/12/18/1317290.aspx)
バックエンドとフロントエンドのプロセスが分離されることで、メモリ空間が保護される。
バックエンドをプロセスにすることで、バックエンド側でマルチスレッド対応などを考える必要なく並行処理が可能となり、バックエンドが簡略化される。
標準的なOSに実装されているパイプを用いて通信を行うことにより、OSの違いによる影響を最小限にできる。
他のOS用の実装も可能だろうし、フロントエンドをスクリプト言語で仕上げる事もできるだろう。
さらにバックエンドがフロントエンドと同じマシンで実行される必要がない。
つまり、理論上は(十分な帯域を持つ)ネットワーク上のマシンに圧縮作業を丸投げする事もできる。
[デメリット]
統合アーカイバプロジェクトの資産があまり生かせない
→多少無理はあるが、統合アーカイバDLLにラッパをかぶせるとよいかもしれない
フロントエンドの処理が複雑になる
→ラッパライブラリをかぶせることで対応可能(データベース用のラッパに近い感じになる)
DLLと比べてパフォーマンスが悪化するかも
[コマンド案]
凡例:
> command from frontend
> process.initialize
< 120 Hello
> process.setmode compress <-圧縮モード
< 100 OK <-バックエンドからの返答;コードは仮
> process.method tar+xz <-圧縮メソッド
< 100 OK
> process.option level 6
< 100 OK
> output.mode file
< 100 OK
> output.filename C:\temp\test.tar.xz <-ファイル名エンコードは未定
< 100 OK
> input.mode pipe
< 100 OK
> input.pipe FOO <-入出力に使うパイプ名
< 100 OK
> process.begin
< 100 OK
> input.item.time.create 123456789.01 <-epochからの経過秒数;GMT
< 100 OK
> input.item.time.upadte 123456789.01
< 100 OK
> input.item.attribute readonly <-ファイル属性(仮);パーミッションは?
< 100 OK
> input.beginitem data0.txt
< 100 OK
(ここでFOOにデータ送信)
> input.sent 3271 <-送信バイト数
< 200 3271 Received <-返答コード+受信バイト数+メッセージ
> input.enditem
< 400 1621 Compressed <-現在の圧縮後ファイルサイズ
> input.item.time.create 123456789.01
< 100 OK
> input.item.time.upadte 123456789.01
< 100 OK
> input.item.attribute readonly system
< 100 OK
> input.beginitem video.bin
< 100 OK
(データ送信)
> input.sent 40960 <-複数回の送信
< 200 40960 Received
< 400 27330 Compressed
(データ送信)
> input.sent 40960
< 200 40960 Received
> output.state
< 400 57658 Compressed
< 410 85191 Received
> input.enditem
< 400 57658 Compressed
> process.end
< 100 OK
> process.finish
< 110 Bye
エラー例
> process.initialize
< 120 Hello
> process.setmode compress
< 100 OK
> process.method invalid-method-name
< 500 error unknown method
> process.method tar+some-method
< 100 OK
> process.option level 6
< 510 error option not supported
> output.mode file
< 100 OK
> output.filename C:\temp\test.tar.xz
< 600 error access denied
> input.mode pipe
< 100 OK
> input.pipe FOO
< 700 error already exists
> input.pipe BAR
< 100 OK
> process.begin
< 100 OK
> input.beginitem data0.txt
< 800 warning supplemental information missing <-更新日時などの設定前にbeginitemを呼び出した
> input.item.time.create 123456789.01
< 810 warning supplemental information ignored <-enditemとbeginitemの間に呼び出す必要がある
(データ送信)
> input.sent 3271
< 820 3200 error unexpected end of data <-一部受信できていない
> process.abort
< 100 OK
> process.finish
< 110 Bye