保存処理を中断した後、再開できるようにする
前回ファイル保存中の編集操作について検討しましたが、同じ仕組みが「3.保存処理を中断した後、再開できること」でも応用可能です。
元ファイルと管理データ、そして更新データさえ残っていればいつでも再構築可能な形式なので。
つまり保存処理が中断された場合は、保存処理で使った管理データをファイルに保存しておき、更新データもファイルに書き出し消さずに取っておきます。
次回起動時にまずは保存で使った管理データを読み込み、保存スレッドを起動するだけで、保存処理を再開することができるでしょう。
エディタの方も同じ管理データを読み込み、コピーして表示と編集作業に使います。
これで前回の保存処理中断時と同じ状態になりました。
あとは、途中まで書き込んだのにまた最初から書き始めるのも馬鹿らしいので、この書き出した管理データに、どこまで書いたのかといったデータを追加で書き込んでおけば、そこから再開することも可能と思われます。
最小限の管理データと更新データを保存するだけで、中断した作業の継続ができるのであれば、やらない理由はありません。
中断した時にやり直せる、保存処理中でも、追加編集が可能というのは、原理や手順は同じなので、どちらかができるのであればもう一方もできるということになり、片方だけ実装する意味はありません。
ということで、なければないで支障ないですが、有って嬉しい花いちもんめな機能と言えるでしょう。
で、これまでの検討で「4.メモリ使用量が極小であること」「5.巨大な仮想記憶、その他作業用バッファを使用しないあるいは最小限に留めること」が期せずして片付きました。
というのも、実データは随時読み込みますし、更新データもファイルに書き出せば、メモリを使用せずに済み、管理データ自体を最小限の項目だけに止めれば、それだけでメモリ使用量が極小であることの要件を満たします。
元ファイルのすべてを読み込む必要がないし、更新データもファイルに書き出せばデータが追加されること以外は元ファイルと同じ扱いでいい。
管理データは流石にメモリ中にないとレスポンスの問題が出るでしょうし、編集や表示に使う分は最低限を読み込む必要があるでしょう。
とはいえそれだけあれば巨大な仮想記憶やテンポラリファイルはもちろん必要ありません。
元ファイルをや更新データの大きさに比べれば、管理データや作業用のバッファの大きさなんて、ごく小さいものになりますので。
でかいデータをコピペすると更新データファイルがガンガン増えますが、それはまあ必要なコストでしょう。
更新データファイルは保存が完了すれば消えるので、HDD等に十分な作業領域が残っていれば、作業に支障はないはずです。
問題は、ソートしたり大量に置換したりすると、管理データが爆発的に増えていくことですね。
こんな時は小さなPieceを一つにまとめて、それに紐づく実データは更新データとしてファイルにまとめればいいでしょう。
ガベージコレクションみたいなものでしょうか。
その場合更新データファイルが爆発的に増えるんですが、使わなくなったデータを除いて、新しい更新データファイルを作ってそちらに乗り換え、古いものは削除すればなんとかなるでしょう。
これにて大まかに各機能が実現可能であると予測が立てられ「6.エディタとして最低限の機能があること」も既存のAlice Builder IDEからエディタを引っ剥がすことで、まあなんとかなるでしょう。
エディタ部についてはほぼそのまま流用し、ファイルアクセス部分のみ新規作成します。
これまで全ファイル読み込んでいたところを、ファイルの一部だけに限定し、画面からカーソルが出そうになったら追加ロードして内部バッファに追加するとともに、同じだけの行数を削除して、不要なデータを開放することで余計なメモリーを使わないようにします。
修正した場合は、内部バッファデータとともに、Rope / PieceTable管理データを更新し、更新データファイルにも入力されたデータを追記していきます。
エディタの内部バッファと新たに設ける管理データとで二重管理にはなりますが、こうすることで最小限の修正でエディタとしての機能を実装可能になるものと思います。
ちなみにAlice Builderのエディタ部における内部バッファは双方向行リスト方式を採用していて、Rope / PieceTable管理データを直接アクセスできるようにバッファ形式を変更するとなるとエディタ部の修正量が増えるので、挿入削除書き換えなど、更新があったときのみ両方を更新します。
その他画面の表示など更新を伴わない処理にはメモリー中の内部バッファデータを使用し、レスポンスの高速化を図ります。
Rope / PieceTable管理データは内部にテキストデータを含みませんから、そのままですと画面表示でさえいちいちファイルアクセスが発生します。
メモリーを節約するためには全部この管理データ経由でアクセスするほうがいいのですが、頻繁にファイルアクセスを繰り返すとレスポンスが落ちます。
メモリーによる処理とディスクアクセスではその速度に雲泥の差がありますからね。
なので、どの程度のデータを予めメモリー中に読み込んでおくのがいいか、検証しバランス調整する必要があるでしょう。
またキャッシュなどと併用する方法も考えられます。
読み込んだデータは一定量、あるは一定数に達するまでメモリーに保存しておき、しきい値を超えたら、超えなくなるまでメモリーを開放していきます。
このキャッシュを大きくしすぎれば、メモリ使用量が極小であることの要件を満たさなくなりますし、実際のところOS本体にもディスクキャッシュがあるので、2重に確保するのは無駄です。
なので直近のデータ数個をキャッシュしておいて、キャッシュデータも参照渡しでデータコピーをしないことで、OSのディスクキャッシュより効率を高める必要があるかもしれません。
もっともOSのディスクキャッシュが思いの外優秀であれば、内部にキャッシュ処理を組み込まなくてもいいかもしれませんが。
ここらへんも要検証ですね。
以上を持ちまして最初の要件定義が妄想では無さそうだということが、おわかりいただけたかと思います。
まだ、ざっとどのようにアプローチしていくかを検討しただけですので、実験・実装段階に入れば様々な問題、予想外の出来事が起こり得るでしょう。
それを解決するために、要件の一部を犠牲にせざるを得ないケースも出てくるはずです。
諦めたらそこで試合は終了ですが、諦めなければ終了しません。
スポーツと違ってプログラマは死ぬまでプログラムが組めますw
高いモチベーションを保つためにも、応援していただけると幸いです。
次回は、要件にはありませんが行番号データの保持について検討していきたいと思います。