清掃工場で生ゴミの処理がストップしている

カードを削除後,アプリ終了してゴミ箱の中身を処分する段階で,「生ゴミだ!」というエラーが出ている.「生ゴミ」というのは,UNDOでバックアップしたオブジェクト・イメージが未処理の状態で残っていることを意味する.生ゴミはCOUPLING::EraseFamilyTreeでReleaseShadowによって処理されているはずだが,どうもそれが機能していないようだ.昨日のログでは「始業時バックアップではこのようなエラーは出ていない」としているが,これは事実誤認で,その前日2020/12/10の始業時バックアップでもすでにこの現象は出ている.

2020/12/09には「ここまでの修正をすべて現状でフィックスしておく」として仕掛りになっているすべてのOPTIONSを一掃してしまっているので,これ以前のバージョンに戻ることは難しい※.UNDOの論理は結構複雑で動作の解析も難しいが,「後戻りしない」と決めたのだから,このまま進むしかない.※⇒【2020/12/08の始業時バックアップでも同じ現象が出る.】⇒nodule::ReleaseShadowで

if (nod->Shadow && !nod->Shadowed()) {

の論理を逆転して,

if (nod->Shadow && nod->Shadowed()) {

のように変えたら,エラーは解消した.どうもShadowed()という関数の意味を逆に解釈しているのではないかという気がする.ただし,この修正を行うことでTRASHCAN::ThrowCanはエラーなしに終わるが,その後の delete Coupling でUNDOSYSTEMを解体するところでsetNringのエラーが発生する.どちらにしてもこのエラーはUNDOSYSTEMを解析しないと対処できないので,少し調べてみよう.

image

この図面は縦長なので,タブレットを90度回転させて撮ってやろうと思ったのだが,タブレットにはゼルコバの木を一度もインストールしたことがない.最新リリース版は一度VAIOにインストールしているので,簡単に終わるはずだったのにエラーになってしまった.そう言えばVAIOのときにも何かあったなと思い出してログを引っ張りだ出そうとしたが,あいにく現状ではOpen Live Writerの全文検索ができない.

しかし,それほど昔の話ではないのでサイトで検索することにした.ChromeのウェブストアにGoogle検索を使ったプラグインがあったので使ってみた.サイト内検索ができるというのはかなり有り難い.結局,VS2017に対応する再配布パッケージが必要ということがわかったので,Visual C++ 2017 Redistributable (x86)をマイクロソフトサイトからダウンロードしてインストール,これでZTもインストールできた.

UNDOでは何かコマンドを実行しようとするときには,事前に更新の予測されるオブジェクトのイメージのバックアップを取って保全する.ただし,事前と事後という区分けはややあいまいで,あるコマンドの事後は次のコマンドの事前でもあるから,コマンド実行後にも変化があればそのイメージが保存される.事前に予測して保全するというのはややムダのある動作※だから本来ならコマンド処理の中でデータが更新される直前にその部分だけをバックアップすればよいのだが,そうなるとコマンド処理とUNDO処理の境界が消えてとんでもなくややこしいものになってしまう虞があるため,現行のような仕様になっている.

※多分現行では事後に保全データをチェックして変化なしの場合にはそのデータを破棄していたはずだ.

UNDOSYSUTEMは一つのコマンドに対して一つのUNDOCHAINノードが対応したコマンドのチェーンを持っている.一つのUNDOCHAINはそのコマンドで保全された個別オブジェクトの複製イメージを保持するUNDONODEのチェーンを持っている.ここで問題なのはこのオブジェクトのイメージはどういうデータ構造になっているのか?という点だ.複製ノードをすべてNODULEオブジェクトとして生成することは可能だが,コストが掛かり過ぎる.それではどうしているのか?

オブジェクトの複製はfreeblockで必要サイズのメモリを確保し,そこにオブジェクトのイメージを転記している.freeblockはEraseFamilyTreeの中でまとめてパージされている.また,複製イメージへのリンクはベタ参照なので参照管理とは無関係に削除できる.UNDONODEはチェーンを構成するためのzenpoUndoとkohoUndoという2つのリンクスロットの他,実ノードの物理アドレスを指すaddressと複製ノードへのべた参照を格納するshadowを持っている.

オブジェクトは生成から消滅までの間に物理アドレスが変化することはないので,UNDONODEから実ノードへのaddress参照は状態に関わらずつねに有効だ.UNDONODEと複製ノードは1対1に対応しているが,一つのオブジェクトが複数の複製ノードを持つ場合があり得る.つまり,実ノードと複製ノードの関係は1対多であるため,NODULEのShadowという特殊スロットでチェーンを構成し,これを管理している.

オブジェクトは複製ノードを持っている間,つまり,Shadowが空でない間は削除されないということになっている.従って,削除されてもゴミ箱には入らず,フロート状態でNringに繋がっていると考えられる.(実際にそうなっているかどうかは分からない.前にゴミ箱とNringに二重登録されているという話があった)さて,これで大体のイメージは掴めたので,実際にどういう動作になっているのかを確かめてみよう.

まず,削除などの操作を一切行わず,ファイルを開いて閉じるだけの動作を確認しておこう.⇒アプリ終了時,CallSetCouplingPtrの入口ではアクティブオブジェクト 32(19クラス)というコア骨格木と呼んでいる状態になっている.ゴミ箱には10003個(20クラス)の廃棄オブジェクトが入っている.カードを3枚削除して終了した場合を見てみよう.⇒Nringには,281個(25クラス)のオブジェクトが入っている.オブジェクト数で249,クラス数で6増加している.内訳で見ると,

  • nodule 114
  • UNDOCHAIN 2
  • UNDONODE 53
  • MARGLINK 10
  • NODEREFLIST 55
  • CARDLINK 15

となっている.これらはすべてUNDOに関わりのあるノードと思われる.UNDOチェーンをパージするコマンドがあったはずなので探してみよう.UNDOSYSTEM::resetUndoChainという関数がある.これを実行したらどうなるか?⇒完全にコア骨格木を復元できた.ただし,その分ゴミ箱の中身は増えて10410個(22クラス)に変化している.何もしないときのオブジェクト総数は10032,3カード削除したときには407個増加して10410.仕様的にはこれで動作は完全と言えるところだが,なぜ生ゴミが出るのか,ないし,なぜReleaseShadowは機能していないのかというナゾはまだ解き明かされていないので調べておこう.

EraseFamilyTreeでfreeblockをパージする前の状態を見ると,Nringの中身はコア骨格木の状態,freeblockはゼロ,ゴミ箱の中身は空だ.しかし,これでは辻褄が合わない.1万個近いオブジェクトがどこかに消えてしまっている.そんなバカな… ⇒アプリ開始から終了までの間にEraseFamilyTreeは複数回呼び出されている.初回がまったくの空であるのは当然だ.アプリ終了時,freeblock解放の直前では,Nringは1396個(21クラス),ゴミ箱8639個(19クラス)だ.Nring1396個のうち,1361はNODEREFLISTで,3個がfreeblock,残り32個がスケルトンだ.この3個のfreeblockがUNDOで生成された複製ノードと思われる.

いや,違う.上の数字は「何もしていない」ときの数字だ.このfreeblock3個が何の用途で作られているのかは分からないが,UNDOの複製ノードでないことは確かだ.実際,この3個を除けばトータル10032となり何もしないときのオブジェクト総数と一致する.freeblockはReleaseFreeBlockでメモリから完全にパージされてしまうので,ゴミ箱にも残らない※.カードを3つ削除した結果を見てみよう.Nringには1648個(26クラス)のオブジェクトが残っている.ゴミ箱には8819個(19クラス)入っている.※⇒【間違っている.ENDOFAPPLICATIONフェーズまではメモリからはパージされず,ゴミ箱に残っている.】

Nring上のfreeblockの個数は3で変化していない.UNDOCHAIN x 2, UNDONODE x 53がUNDOチェーンのために追加されている.目に付くのはCARDLINK x 15,MARGLINK x 10 が入っているという点だ.ゴミ箱にはCARDLINK x 189,MARGLINK x 88 が入っているが,これらは現物の人名リンクと結婚リンクと考えられるので,Nringに入っているのはすべてUNDOのために新たに生成されたもののように思われる.複製はfreeblockのメモリ上にコピーされたものと思っていたが,どうも現物のコピーを使っているようだ.

実行されたコマンドは「カード削除」の1件だけだが,UNDOCHAINは2個生成されている.これは「カード削除」の前と後が保全されているためで,UNDOCHAINは存在するとすればつねに2個以上になる.CARDLINK 15, MARGLINK 10 が複製ノードだとしても,UNDONODE 53 をカバーすることはできない.プリミティブなオブジェクトとして無名のnoduleが114個もあるので,これらの中にそれらが含まれている可能性はあるが,どうやってそれを分離することができるだろう?

ゴミ箱にはfreeblockが39個入っている.これらがすべてUNDOの複製ノードであるとすると,CARDLINK 15, MARGLINK 10と合わせて64個となり,今度はUNDONODE 53 を超過してしまう.どうやったらこの帳尻を合わせることができるのだろう?ゴミ箱とNringのダブリは25でこの数字はDELETEDがNRING_INVALIDATEであるノードの個数と同じだ.この数はNring上のCARDLINKとMARGLINKの総数に等しい.つまり,これらはすべてNRING_INVALIDATEとされるようなノードということになる.整理してみよう.

  1. Nring上のノード総数 1648 
  2. ゴミ箱上のノード総数 8819
  3. Nringとゴミ箱の二重登録 25 ー非アクティブノード
  4. Nring上のCARDLINK 15 + MARGLINK 10 = 25 =(3)
  5. Nringとゴミ箱の合計(ダブリを除く)10442
  6. アプリ終了時のノード総数 10442

これで一応帳尻は合った.問題はUNDONODEの53という数字の内訳だ.⇒内訳もわかった.CARDLINK x 30, MARGLINK x 18, PARTIALNAME x 3, longtable x 2だ.

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA