昨日のログでは「保留」としていた「不正 UndoNumber」に対処.
▲複数カードの削除を2回以上実行した後,Undoで最初の状態まで戻り,そこで再度複数カードを削除すると,SetUndoListで(object->UndoNumber > UndoNumber)という「不正UndoNumber」エラーが発生する.⇒object->UndoNumber が0になっていれば,このエラーは発生しないので,PergeZenpoChainで前方コマンドチェーンをカットするときに,始末しておけばよいのではないか?
オブジェクトへのリンクはUNDONODE::addressにベタ参照として入っている.UNDONODEのデストラクタでaddress->UndoNumberをリセットしてやればよいのではないだろうか?⇒実オブジェクトはShadowチェーンを構成している.⇒Shadowはオブジェクトのバックアップされたイメージだ.この中にはバックアップ時のUndoNumberも含まれている.従って,ここでUndoNumberをリセットしても,オブジェクトのUndoNumberはつねに正当な値を保持していると言える.⇒対処した.
▲setmaxrefnumで最終レコード番号をmaxrefnumに代入している.⇒最終レコード番号=maxrefnumという決め付けは危険だ.⇒setmaxrefnumがつねに危険という訳ではない.引数で「レコード番号」を渡しているケースを拾い出す必要がある.maxrefnumはリンクを生成するか,削除した場合以外には変化しないと考えられるから,これらのケースに漏れ落ちがなければ,それ以外の場所でmaxrefnumを更新する必要はない.まず,setmaxrefnumで同じ値を設定しようとしたときに停止するようにしてみよう.⇒さっぱりヒットしない.おそらく,処理の冒頭でmaxrefnumを初期化しているのだろう.
▲テーブルで行選択してカード削除しようとすると,対象カードが変化してしまう.⇒カード画面でカード番号欄が4桁しか見えないため,数字が隠れてしまう.⇒カード削除パネルに出てくるカード番号が間違っている.カード画面の主選択カードは正しい.⇒操作を間違えていた.「番号列セル」のクリックでは選択状態は変わらず,「現参照カード」のみ変化する.「現参照カード」というのは,カード画面上に表示されたカードだ.これまではこれを「主選択カード」と呼んできたが,「選択操作」と独立に操作できるようになっていることを忘れていた.というか,そうなっていることを知らなかった!
newlinkでもレコード番号をmaxrefnumに格納している.⇒setmaxrefnumの参照箇所は15箇所ある.結婚リンクの場合,MARGTABLE::makenewlinkでは親のスロット番号をそのまま参照番号としている.CARDTABLE::makelinkでも実質,レコード番号をセットしている.COUPLING::InitLinkTableでは,参照番号をレコード番号とみなしてテーブルを構築lしている.従って,参照番号=レコード番号が本則であると考えるべきである.ただし,参照番号は論理番号であり,レコード番号は物理番号であるから,つねに両者が一致していると仮定すべきではない.実際,ファイルロード時には参照番号の付け替えは行われていないから,古いファイルの中には一致していないものが多数あると考えるべきだ.少し,整理する必要がある.
①getmaxrecnではつねにテーブルサイズを返している.②テーブルは一般にはスパースであると考えられるが,最大レコード番号がカウントされていない.③maxrecnum(以前のmaxrecn)はlookupテーブルのレコードカウントであり,②の最大レコード番号ではない.④maxrecnumをrecordcountとリネームし,maxrecordという変数を新設して,ここに②の最大レコード番号を格納する.⑤getmaxrecnでは④のmaxrecordを返すようにする.⑥recordcountをメンテナンスする関数の中で,maxrecordを更新する.
▲delrecnを廃止する@20221226をフィックス,longtableのaddを使う@20221226をフィックス
maxrecordは単調に増加するものとし,テーブルの縮小は行わない.maxrecordの参照関数をmaxRecordとする._maxrecnをリネームしてrecordCountとする.MakingLookUpは17箇所から呼び出されている.UNDOではUndoEndとUndoProcessでMakingLookUpを実行しているので,DEFINEUNDOSYSTEMは多くの場合,省略できるのではないか?CommandStartFlagがオンの場合はすべてパスするようにしてみよう.
▲BUG3000-1906.ZELを開いて,1906-543=1363点を削除→基準ソート→UndoでTREEVIEW::CheckSelectListのエラーが発生した.selectcardlist->countと実カウントの不一致1が起きている.⇒何かやり損なったのだろうか?再描画が掛かってこない.どうも,バックアップに戻って作り直しするしかなさそうだ.修正手順を記録しながら進めることにする.最初にまずいくつかの過去の修正をフィックスしておこう.ただし,定義文はコメントとして残しておく.
- delrecnを廃止する@20221226をフィックス
- longtableのaddを使う@20221226をフィックス
- getmaxrecnを廃止@20221226をフィックス
- setmaxrefnumでレコード番号を禁止@20221227をフィックス
やはり,ダメだ.CheckSelectListのエラーが発生するほか,Undo→ Undo→ Redo→ Redo→ Undoで,参照カウント 不一致が大量に発生する.ここまでは単純に修正をフィックスしただけなので,バックアップに戻っても同じだと思う.このままシューティングするしかない.もう少し小さなサンプルでテストすることにする.極小反例307.ZEL(66点)でやってみよう.⇒再現する.手順は,①カードを大量一括削除,②基準ソート,③Undo→ Undo→ Redo→ Redo→ Undoだ.
テーブル並び替えの時点では選択カードは1点という状態になっている.最初のUndoでCheckSelectListのエラーになる.selectcardlist->countは1だが,selectflagはすべて落ちている.そもそも,UNDOでは選択状態を保全していたのだろうか?⇒保全している.いや,selectcardlistそのものは保全していないが,カードの保持するselectflagから復元している.⇒どうも,かなりおかしい.lookup.countが307もある.いや,この時点ではそれで正しい.
元々の論理ではUNDO時には,選択はすべて解除するということになっていたものと思われる.ただし,冒頭でカウントをリセットする処理が(意図的に外されていたため)不整合が発生していたものと思われる.いろいろな意味でUNDO時に選択状態を維持するというのは無理があると思われるので,「UNDO時はつねに無選択状態」ということにしたい.⇒いや,selectflagから復元するという方式で動作しているようだ.これでもよいのではないか?
UNDO中はつねにカードリンクが保持するselectflagからselectcardlistを復元できるので,基本的に選択状態は維持可能と思われる.ただし,これは選択状態が復元できるという意味ではない.選択領域全体をキープしようとしたら,コマンドのたびにすべてのカードリンクをバックアップしなくてはならなくなってしまう.それはおよそ不可能だ.
「被参照カウント不一致」の問題に移ろう.これはかなり,手強いと思う.再現手順は,基準ソート→Undo→Redo→Undoだ.その後は,RedoでもUndoでも同じになる.手順から見ると,Redoで壊しているように思われるのだが… 障害が発生しているのはCARDLINKとMARGLINKで,これらはバックアップとは無縁のように思われるのだが… ⇒いや,2回目のUndoで起きているようだ.UNDOコマンドのリングを巡回処理中に不良が起きている.ここで実行されているのは,RestoreShadowとUndoRestoreくらいだが… ⇒UndoRestoreが元凶だ.