年越し蕎麦とお節の差し入れが届いた

姉からの年越し蕎麦とお節の差し入れが届いた.清酒の小瓶も付いている.灯油のストックもあるし,2方面の窓を,①ぷちぷち,②二重カーテン,③毛布/寝袋の三重層で断熱した.入口のドアの上のガラスにもプチプチを貼っているので,今年初めてほぼ完全な防寒の備えができた.姉から年末恒例の余ったカレンダーの横流しもいつか来なくなり,ダイソーで書き込みのできるカレンダーを買っていたが,今年はAMS(American Mathematics Society)から「Your Daily Epsilon of Math 2023」というのを取り寄せた.日替わりの諺の代わりに,小さな数学の問題が毎日提出される.(答えはその「日付」ということになっているので,考える前に回答できてしまうから,心配はいらない)

なんとか,今のバグをクリアして新年を迎えたいものだが,その前にあっけなく年を越してしまいそうだ.UNDOのからんだかなり難しい障害だが,ある意味でいよいよ年来の懸案を片付けるときが来ているのではないか?という気もする.年来の懸案とは,「完全な参照管理を確立すること」,言い換えれば,「超クリーンなシステムを構築すること」である.「超クリーンなシステム」は完全にコントロールされ,いかなる不安定要因も含まないような決定姓が保証されなくてはならない.現行プログラムはかなりのレベルまでそれに近いものになっているが,まだ「カオス的」な部分を残している.

ユーザとのやり取りでグラフのトポロジーが変化するようなデータ操作が行われたときには,系統並び替えを実行しなくてはならないが,このようなときにはフェーズを一旦INITIALIZED(=CHAOTICSTATE)に落として,INITIALIZED→ TOPOLOGICALSORT→ CLEARTABLEのように遷移し,画面要素をClearTableで初期化したあと,本番の系統並び替え処理を実行する.INITIALIZEDではCOUPLING::TopologicalSortでTREEVIEW::InitTreeViewとEraseTreeViewで描画要素のクリーンアップが実行されているので,CLEARTABLEフェーズでは参照エラーは無視されることになっている.このようなアナーキーな状態を払拭し,すべてのフェーズがシームレスに接続することが我々のプログラミングの最終目標であると言える.特にUNDOはこのような操作に関し,完全に透明でなくてはならないと考えられる

CARDLINK::CheckCardDataLinkで「カード参照番号の重複」というのが起きている.CheckCardDataLinkは副作用のある検査ルーチンで,SaveFamilyBase→ InitLinkTableで使われている.⇒CheckCardDataLinkとCheckMargDataLinkに引数testを設けて切り分けるようにした.

▲再現手順5の2回目のUndoで,UndoProcess→ TopologicalSort→ ClearTableの入口に置いた検査ルーチンで大量のエラーが検出される.特に,CheckDataLink→ CheckMargLinkの中でgetoyanumを実行して,結婚リンク中の子どもの参照番号から逆引きしたカードリンク不在が発生している.⇒基準ソート時に実行しているRenumberを停止してみたが,状況は変わらない.⇒TOPOLOGY::topologicalSortの入口ですでに,この状態になっている.ということは,UNDOSYSTEM::UndoProcess自体に欠陥があるということになる.

#3196のCARDLINKをUndoするところだ.参照番号は@1565.このノードは削除されていない実ノードと思われるが,更新を受けているようで,UndoRestoreが実行されている.UndoProcessのループ内で実行しているのは,基本的にUndoRestoreだけなので,これを調べなくてはならない.⇒UNDONODE::UndoCopyの中で不良が発生している.⇒@1565というリンクがテーブルの中でダブってしまうという不良だ.なぜ,そんなことが起きているのか?


「参照カウント不一致」は未解決だった

解決したと思っていた「参照カウント不一致」がまだ収まっていない.⇒どうも昨日の修正でバグを作り込んでしまったようだ.2022-12-29のバックアップでは再現手順による障害は発生しない.どうしたらよいか?⇒2022-12-29では,NODULE::slottypeの判定に従来の論理が使われている.まず,これを適用してみよう.⇒ダメだ.UndoCopyで参照元ノードリスト不記載が出てしまう.⇒2022-12-29-1の版ではすでに不良が発生している.どうしたらよいだろう?昨日の修正はかなり大規模なものだが,もう一度やり直しするしかない.⇒やってみよう.

NODULE::slottypeを修正版と差し替えたが問題なく動作している.「選択カードリストのカウント不一致」では停止しない,「並び替えではリンクテーブルは操作しない@20221228」でエラーを無視する修正を入れた他は,2022-12-29版のままだ.いや,確かに昨日のログでも,『これで一応「参照カウント不一致」エラーは発生しないようになった』とあり,一応落着していることが確認されている.ここでバックアップしておくのが賢明だろう.複数のパターンでテストしているので,再現手順を記録しておこう.

  1. 起動→ 基準ノードの@23を削除→ Undo で「被参照カウント不一致」
  2. 基準ソート→Undo→Redo→Undo
  3. カード一括削除→ 基準ソート→Undo→ Undo→ Redo→ Redo→ Undoで「被参照カウント不一致」
  4. 2回以上全削除を繰り返し,それらをすべてUndoした状態でそれに交叉する領域を一括削除する⇒SetUndoListで (object->UndoNumber && object->UndoNumber > UndoNumber)というエラーが起きる
  5. 基準ソート→ Undo→ 一括削除→ 基準ソート→Undo→ Undo⇒ClearTable→ ResetParentPageでSetOyapageのエラー

上記リストの1, 2のテストはパスしたが,3でエラーが起きた.TopologicalSort→ ClearTable→ ResetParentPage→ SetOyapageで(cardbase.oyanums[oya->getoyanum(j)] != oya->margbase.refnum)というエラーになった.⇒テスト3を単独実行しただけでは再現しない.テスト2→ テスト3で再現できる.つまり,基準ソート→ Undo→ 一括削除→ 基準ソート→Undo→ Undoで再現する.⇒これもリストに追加しておこう.テスト5のエラーは,UndoProcess内では発生していないので,ここでは一旦無視して先に進むことにする.

▲上記テスト5でUndoボタン押下→Undo処理から戻って,VBでGetNewTableを実行してKAKEIZU::makerecordの中で,「夫妻参照番号不整合」というのが発生した.この結婚の夫参照番号5845は,引数で与えられた参照番号395と一致しない.⇒リンクベースのOTTOには正しい値が入っているのだが,静的情報のottoが間違っている.makerecordはKAKEIZUクラスの関数なので,静的情報を返すという仕様になっているのだろう… 外部にはリンクは渡せないので,インタフェースはすべて静的情報に基づくものになるというのは間違いではないとは思われるが,静的情報とリンクデータをどこで同期させているのかが問題だ.

検査ルーチンを作っておく必要がある⇒CARDLINK:CheckCardDataLinkというテストルーチンがある.⇒このエラーはCheckCardDataLinkで検出できる.LINKTABLE:CheckDataLinkという包括テストルーチンがある.COUPLING:InitLinkTableではこのテストを通している.InitLinkTableはOpenFamilyBaseから呼び出される.

LINKTABLE::CheckDataLinkはMARGLINKとCARDLINKの検査を行っているが,CheckMargDataLinkではMakeCouplingの呼び出しで,副作用のある検査になっている.この関数の是非に付いては別途調べる必要があるが,一旦止めておこう.⇒引数で判別できるようにした.

▲ClearTableの出口に仕掛けたCheckDataLink→ CheckMargLinkで,夫と妻がどちらも空という結婚リンクが検出された.もし,検査ルーチンが誤動作しているのでなければ,これはかなり問題だ.どうもこのような結婚リンクが複数あるように思われる.

手順を間違えたのだろうか?今度は別のエラーが出た.ClearTable->ResetParentPage->setParentPageで(hubo->getrefnum() != cardbase.carddata.oyanum)というエラーになった.

CheckMargLinkの中でもMakeCouplingという実関数が呼び出されている.引数でパスできるようにしておこう.⇒LINKTABLE:CheckDataLinkの中から呼び出されているkodomosuという関数ではMarriageOrderingが実行されているが,この関数ではDeleteMarriageが実行されることがある.⇒どうも,CheckDataLinkにはまだ実動作が含まれているようだ.ClearTableの冒頭でCheckDataLinkを実行すると,「無効な結婚リンク」が47件も発生してしまう.

 

「参照カウント不一致」エラーは一応解決

UNDOにからんで「参照カウント不一致」という不良が出ている.参照とは,オブジェクトへのリンクを格納したスロットを言う.ゼルコバの木では処理効率の観点からリンクには生ポインタを使っているので,リンク先のオブジェクトの削除などで無効になったリンクにアクセスしようとすると,致命的な事故が発生することになるので,システムを安定運用するためには超厳密な参照管理が必須である.このために参照カウントというパラメータを保持しているが,現行システムにはそれを管理するためのREFERENCECONTROLという機構が組み込まれている.従って,このエラーの発生は決して許されない極めて深刻な障害と言える.

動作確認のために入れた仮修正によって別の障害が発生している.基準ソートを実行して,TOPOLOGY::ClearTableで結婚リンクの参照番号と親番号の不一致が起きている.⇒仕様的には結婚リンクの参照番号と親番号が一致するというのは仕様ではないはずだが,事実上そうなっていることは確かだろう.⇒暫定的にエラーで停止しないようにした.

スロットの接続種別を取り出すNODULE::slottypeで,親番号とスロット番号が一致しない場合でも,親参照が一致していればSLOT_LINKを返すように暫定修正して,参照カウント不一致は発生しないようになったが,いろいろ問題がある.

  1. ほとんどの場合はこれで問題なかったとしても,同じオブジェクトが接続しながら参照されているような場合を排除できない
  2. リンクテーブル内のリンクはすべて接続であるとして処理されるべきではないか?つまり,対象オブジェクトごとに個別対応する必要があるのではないか?
  3. 親番号とスロット番号の不一致は不良とみなされるべきであり,イメージをリストアした時点で対処されなくてはならないのでは?処理する場所はCountupReferenceでもよいのかもしれないが…
  4. カードリンクと結婚リンクはUNDOSYSTEM::RestoreShadowでInsertLinkされる.ただし,これは現物オブジェクトがEXISTINGでない場合に限られる.つまり,Nring上で延命している場合にのみ適用される
  5. UNDONODE::CountupReferenceとUndoCopyの2箇所で参照の復元を実施している.これは必要なのか?これらはいずれもUNDOSYSTEM:UndoRestoreの内部で呼ばれている.どちらかのみでよいような気もする.UNDOBASE:UndoRestoreでも同様処理になっている.⇒いや,やっていることは真逆だ.UndoCopyでは対象オブジェクトのすべての参照を解除している.逆にCountupReferenceは参照設定を実施している.この動作は正しいと思われる.

▲基準ソート→Undo→Redoの後,まとめて全削除→UndoしてUNDOSYSTEM::UndoProcessでRebuildCardListしたとき,(previous != treeview->selectcardlist->count)になった.previousは1で実カウントは77.⇒これはエラーではなくむしろノーマルな動作のように思われる.カード削除の前に戻ったとき,削除対象カードが選択状態になっているという方が正しい.従って,ここでは不一致をエラーとしないというのでよいと思われる.⇒いや,このエラーのタイミングでは選択リストはすでに復元されているはずなので,それと一致しないというのはおかしいのではないか?

全削除コマンドが実行されたとき,どのタイミングで選択カードリストが保全されたかが問題だ.コマンド実行後に更新されたオブジェクトがあれば上書き保全するということもやっているのではないか?カードの全削除は単点削除の反復として実装されているはずだから,削除完了時に1点選択の状態になっていてもおかしくない.⇒これはそれほど大きな問題ではないので保留とし,エラーで停止しないようにしておこう.

さて,これで一応「参照カウント不一致」エラーは発生しないようになったが,まだ,もう少し問題が残っている.対象リンクが参照でない場合(接続の場合),CountupReferenceでは何もしていないが,「親番号とスロット番号の不一致」が起こっているのではないか?⇒UNDONODE::CountupReferenceで「親番と枝番の不一致」が起きた場合には強制的に調整するようにした.

まだ,「参照カウント不一致」が収まっていない.UndoRedo→ TopologicalSort→ EraseTreeViewで起きている.基準ソート→Undo→Redo→Undoで起きる.⇒親ノードに接続している場合は,つねに接続リンクとして扱う以外ないということになった.

「オブジェクトが接続している親ノードからは参照されない」

というルールを公理化することができれば,これでもよいのだが… 果たしてそう断言できるだろうか?実質的にはこれに反するケースというのはおそらく存在しないのではないかとは思われるのだが… 安全のためには,やはり,オブジェクトの種別を特定して対応を変えるしかないような気がする.⇒人名テーブルと結婚テーブルについては,IsReferenceを使わないよう対処した.それ以外は既存論理で対応する.

ここで一度バックアップを取っておこう.レコード番号には,①リンクテーブルのレコード番号,②lookupテーブルのレコード番号の二種がある.これらを峻別しなくてはならない.特に①はprivateとし,外部からアクセスできないようにする必要がある.⇒maxrecnumとmaxrefnumは元々privateになっている.一旦破棄された一昨日の修正をログに従って復旧してみよう.⇒ZELKOVA 2022-12-27 BADというバックアップがあるので,参照しながら進めよう.

  1. maxrecnumをrecordcountにリネーム→有効レコードカウント
  2. recordcountは lookup テーブルの count に等しい
  3. maxrecordを新設し,最大(リンク)レコード番号を格納する
  4. recordcountの更新時に,maxrecordも更新する.
  5. maxrecordは単調に増加するものとし,(基準ソート時以外では)テーブルは縮小されない
  6. getmaxrecnではmaxrecordを返す
  7. maxrecordのアクセス関数をmaxRecordとする
  8. _maxrecnをリネームしてrecordCountとする
  9. getmaxrecnを廃止して,maxRecordに統一する

ダメだ!また,被参照カウント不一致が出てしまった.基準ソート→ Undo→ Redo→ Undo→ 一括削除→ Undoという手順だ.出ている時点は同じだが,今度はNAMEBOXのデストラクタで起きている.被参照カウントの残留も発生する.⇒CHECKREMAINSANSYOは一時止めておこう.⇒起動→ ルートノード削除→ Undoで再現する.これまで出ていなかったので,上の修正で作り込まれたものと思われる.⇒修正を一部戻してテストしてみたが同じだ.もう一度バックアップに戻るしかない.⇒いや,ダメだ.バックアップでも障害は起きている.

TREEVIEW::EraseTreeViewの入口ですでに不良は発生している.⇒UNDONODE::UndoCopy→ UNDOBASE::UndoCopyで起きているが,UndoCopyでは単にイメージを上書きしているだけなので,そうなることは避けられない.その部分はCountupReferenceで補正しているのだが,どうもそれだけではカバーできないということのようだ.最初の障害は#1540のCARDLINKで起きる.参照カウント不一致が起きているのは#80のMARGLINKだ.この結婚の夫が#1540で削除された@35のカードと思われる.⇒いや,読み違えている.

削除されたのは@23#1522のカードで,同時に#74のMARGLINKも削除されている.この2つは<再生>されているが,MARGLINK内の夫ないし子ノードのリンクは修復されていないようだ.

今日の来訪者数が568人になっている

こ,これはなんだ!?今日の来訪者数が568になっている.まだ,午後5時台だ.何が起きたのだろう?普段は行っても200を超えるくらいだ…

image

いま,見ると6時14分現在で625人に昇る.もし,これが本当なら,1日1000人も達成不可能な目標ではなくなる.にわかには信じ難い… 悪いことではないとは思うが… Googleアナリティックスの数字を見てみよう.こちらには,特に顕著な変化は現れていない.

image

All users=186という数字があるが,これは過去を含めたトータルの数字で山のピークでも40人だ.2つの統計の数字がかけ離れ過ぎているので,どちらも信頼できないという感じ… Googleアナリティックスにはコードを埋め込むという設定の仕方もあるようなので,いつかヒマになったらやってみることにしよう.

UNDOで「被参照カウント不一致」というエラーが出ている.CheckNringCountという検査ルーチンをベタ貼りして追跡し,UNDOSYSTEM::UndoRestoreが原因であることは(ほぼ)突き止めたが,まだ現場を押さえきれていない.

dump(char*)という関数の使い方を間違えていた.ほとんどのクラスではdump(char*)ではprintshortという関数の戻り値を返している.しかし,dumpで期待されているのは,引数のchar*にテキストを格納して復帰する動作である.⇒修正しなくてはならない.とんでもないしくじりがあったものだ… ⇒関係する箇所をすべて修正した.

参照カウント不一致がCountupReferenceによって引き起こされていることはほぼ間違いない.障害を起こしているのは,CARDTABLEとMARGTABLEと見られる.奇妙なのは,これらのテーブルに格納されているリンクはすべて接続であるはずなのに,参照とみなされているという点だ.⇒親番号が変化してしまっているためだ.基準ソートは実行しているが,カード並び替えではlookupを対象とする操作であり,リンクテーブルは操作していないはずなのだが… どこで変化してしまっているのだろう?SWOで追いかけてみよう.

snum=74のMARGLINKのpnumは1だが,snum=10のMARGTABLEのスロット9に入っている.ファイルはロードして基準ソートしただけなので,このオブジェクトは現物であると推定される.UndoRestoreの中でMARGTABLEがUndoCopyされた時点で不一致が生じている.つまり,Shadowのイメージではスロット10のオブジェクトのpnumが1ということになる.⇒確かに現物とイメージではまったく異なる内容になっている.現物ではスロット9には#129の結婚リンクが入っているが,イメージでは#74だ.前者は#1621→#2386で,後者は#1522→#1747だ.⇒NameNarabekaeの中でNAMESORT::SetNodeLinkというのをやっている.⇒いや,違う.「まず重みで昇順に並び替えを実施」した後に実施しているRenumberで書き換わっているようだ.しかし,これを実施しないとテーブルの整合性が崩れてしまう… この続きは明日やろう.


「不正 UndoNumber」に対処

昨日のログでは「保留」としていた「不正 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が起きている.⇒何かやり損なったのだろうか?再描画が掛かってこない.どうも,バックアップに戻って作り直しするしかなさそうだ.修正手順を記録しながら進めることにする.最初にまずいくつかの過去の修正をフィックスしておこう.ただし,定義文はコメントとして残しておく.

  1. delrecnを廃止する@20221226をフィックス
  2. longtableのaddを使う@20221226をフィックス
  3. getmaxrecnを廃止@20221226をフィックス
  4. 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が元凶だ.

Collatz12146.ZELを開けるようになった

Collatz12146.ZELをようやく安定的に開くことができるようになった.ただし,開くまでには相当な時間が掛かっている.どこがネックになっているのか,シューティングしたいところだが,それはもう少し落ち着いてからの課題としておこう.

巨大ファイルでメモリ不足が発生しないようになったのは,MAXPDBxMAXMDBという巨大配列の使用を一時的に止めたことが効いているのではないかと思う.DTおよびKTという名前のshort型の2元配列で,親等計算に使われている.とりあえず,親等を計算する必要はないので当面は停止で問題ない.親等計算は結構時間を消費するので,オプションで止められるようにしておいた方がよいかもしれない.

Collatz12146.ZELでは三極検定レッドラインオーバーが発生している.

image

上図では小さ過ぎて見えないが,図面の左上隅に#1のカードが取り残されている.その他にも何点か隔離された点が残っているが,おそらく,これらがレッドラインオーバーの原因になっているものと思われる.極小反例抽出というのは,この問題をシューティングする目的で始まったのだろう.⇒極小反例サンプルのコレクションがある.極小反例 371.zelが多分最小と思われるので,試しに開いてみよう.⇒開けてしまう.反例になっていない.⇒この問題は後からやることにしよう.

CARDTABLEとMARGTABLEにはRenumberという関数がある.これが使えるのではないだろうか?⇒NAMESORT::NameNarabekaeには元々その処理が入っている.基準ソート(参照番号による並び替え)では,PDBとMDBのRenumberを実行している.ただし,現行の「特注版」では基準ソートの代わりに番外として「カード番号によるソート」が実行されているため,適用されていない.⇒参照番号とカード番号はまったく同一なので,「特注版」として特に別扱いする理由はないような気がする.オプションを止めてみよう.⇒うまく行ったようだ.

テーブルサイズを16384まで拡大してCollatz12146.ZELを読み込んでみた.系統並び替えだけで16分掛かっている.テーブルのロードでもその位掛かるので,トータルでは20~30分くらい掛かっているのではないだろうか?パフォーマンスに関してはもっと後で取り組むことになるが,getnewRefnumの仮修正はフィックスしておいた方がよい.getnewRefnumのオリジナルバージョンではmaxrefnumの次の番号を返すようになっているが,暫定的に空スロットを見つけてその番号を返すようにしている.一般にはこちらの仕様の方が適していると考えられるので修正を戻しておくことにしよう.ただし,maxrefnumがテーブルサイズを超えた場合には,任意の空スロット番号を返すということにする.⇒いや,emptyrecn自体そういう作りになっている.

この関数はテーブルフルになった場合にはエラーコードを返しているのだが,それに対応するようになっているだろうか?⇒一応対処した.emptyrecnとgetnewRefnumの最大の違いはテーブルサイズオーバーのとき,エラーパネルを出すか出さないか?だ.emptyrecnでは,「%sデータベースの容量%d件を超えています.\nこれ以上%sリンクを追加することはできません.」のようなメッセージが表示される.これが頻発するというのは望ましくない.⇒emptyrecnに引数を一つ追加して切り分けるようにした.⇒いや,コンパイルが通らない.BASETABLEはテンプレートクラスなので,ヘッダファイルの中で初期化できない.

そもそも,このBASETABLE::emptyrecn自体間違っているのではないか?この関数は冒頭,max = getmaxrecn()で最大レコード番号を取り出しているが,現行ではgetmaxrecnはtablesizeを返すようになっている.従って,(max < tablesize)はつねに偽となり,つねに空スロットの探索という動作になってしまう.これはここで予定している動作になっていないのではないか?maxrecnというメンバー変数もある.この値はメンテナンスされているのだろうか?

_maxrecnという参照関数でアクセスするようになっている.この値は,MakingLookUpで更新される.また,delrecnという変数も持っているが,これはもう廃止してもよいのではないだろうか?また,incmaxrecn,decmaxrecnという関数も使われている.今度はCollatz3900-6165.ZELでテストしてみよう.このファイルのサイズはCollatz12146.ZELの半分くらいだ(6165点).⇒時間は掛かるが問題なく開けた.三極検定では30回ループを回している.

BASETABLE::getmaxrecnがつねにtablesizeを返しているとすると,getmaxrecnを呼び出しているところでは,つねにテーブルサイズ分のリンクをチェックしていることになる.これはあまりにタイムロスが大き過ぎる.lookupテーブルには前詰めしたリンクが入っているはずだ X.基本的にレコード単位にアクセスするときは,このテーブル(lookup)を使っているはずだが,全テーブルに直接アクセスしているところも無数にあるに違いない.lookupを使うためにはMakingLookUpが実行されている必要がある.getmaxrecnの呼び出しは194箇所もある.

とりあえず,delrecnを廃止しておこう.今度はBUG3000-1906.ZELを開いてみた(1906点).そこそこの時間で開けた.系統並び替えの所要時間は34秒.このサンプルはどうやって作ったのか分からないが,最小番号は15で,ルートは35になっている.

▲一覧画面を開いたとき,必ずカード番号の降順で初期表示されるのはなぜか?また,起動時には元の画面を復元してもらいたい.

一度バックアップを取ってから始めよう.lookupというのは,longtable型のオブジェクトで,テーブルサイズはMAXPDBに固定されている.結婚テーブルもlookupを持っているが,サイズ調整はしていない.通常,longtableには参照番号などの整数値が格納されるが,lookupの場合にはテーブルのインデックス(1発進)が入っている.この値はMakingLookUpで常時メンテナンスする必要がある.⇒チェックすれば死亡していることは確認できる… longtableにCountという参照関数を追加してcountを取り出せるようにしておこう.

lookupにアクセスしているところでは,getmaxrecnを使うのを止めて,この関数を使うことができる.⇒いや,MakingLookUpでlookup.countをmaxrecnumに格納しているので,この値を直接取り出すことにする.lookupは59箇所から参照されている.lookupを参照する関数として,getlinkとgetrefnumがある.テーブル並び替えはlookupを対象に実行されている.つまり,リンクテーブルは操作されない.

▲setmaxrefnumで最終レコード番号をmaxrefnumに代入している.⇒最終レコード番号=maxrefnumという決め付けは危険だ.

▲CommandStart~CommandEndではlookupは使用不可(MakingLookUpが実行されていない)⇒これは,フラグを見れば確認できるだろう.

▲getrecn(refnum)という関数は,リンクテーブルでアクセスした方が効率がよいが,ヒットしない場合はlookupを使った方が無駄が少ない.

効率にはほとんど影響しないが,多少なりコードを読みやすくするために,longtableにaddという関数を追加しておこう.

▲上記サンプルでツリーの裾の方をまとめて1304点全削除したところ,SetUndoListで (object->UndoNumber && object->UndoNumber > UndoNumber)というエラーになった.object->UndoNumberは3, UndoNumberは1.その前に複数のカード削除とUndo/Redoを実行している.この全削除はUndoで振り出しに戻ったところでやっているので,前方チェーンはすべて削除されているはずなのだが… オブジェクトのUndoNumberがリセットされていなかったのだろうか?⇒同じエラーが無数に起こるので,一旦終了する.

オブジェクトの輪切りを反復しても再現しない.おそらく,先行実行されたカード削除に関係するオブジェクトで削除対象ではないオブジェクトが存在し,Undoで復活した図面ではそのときに設定したUndoNumberが残っていたのではないだろうか?そのようなことは起こり得るように思われる.⇒UndoNumberを上書きしてやればそれまでだが,それではUndoNumberを導入した意味がなくなってしまうのではないか?⇒再現手順を確立しておこう.⇒少なくとも2回以上全削除を繰り返し,それらをすべてUndoした状態でそれに関係した領域をまとめて全削除すると発生する.⇒かなり難しいので一時保留としておこう.

同上サンプルで,ルートから底辺までの帯状の領域222点を全削除して,SetUndoListの出口で(object->UndoNumber != UndoCurptr->UndoNumber)が出た.object->UndoNumberは0,UndoCurptr->UndoNumberは1.CommandStart→ BackupPointData→ SetUndoListで発生している.objectはPARTIALNAME.⇒これは上記の「保留」に関わる修正ミスだ.

ようやく作業がルーチンで回り始めた

ようやく作業がルーチンで回り始めた.こうなれば,もう怖いものなしだ.今回作業再開の目的は一義的には「Sultanの論文の検証」だが,その前に「コラッツ木生成ツールの再構築」と「ゼルコバの木の増強」に取り組まなくてはならない.現在,ゼルコバの木は「コラッツ特注版」というかなり変則的な方向に進んでいるが,この方向性をむしろ「本則」として標準化する必要がある.

コラッツ木は単純な木であり,これを最大限・最高速で処理できるようにすることは,一般の系図を扱う上での前提であると考える.ゼルコバの木はこれまで,最大1000点というスケールの領域を扱ってきたが,これを機会に1万点を超えるデータを扱えるように仕立て直したい.かなりハードルは高いが,やっておく必要がある.

カードを2点削除した後で,Undoを2回行うと,UndoNumberの不一致が発生する. (UndoCurptr-> UndoNumber != UndoNumber)が起きている.UndoCurptr-> UndoNumber=1, UndoNumber=2だ.このエラーは初回だけで,その後の Redo,Undoでは収まってしまう.

UndoNumberという値は,①UNDOBASE,②UNDOCOMMAND,③noduleの各クラスで保持されている.UndoNumberは「重複バックアップの回避用」.UNDOBASE::MakeNewCommandでシステムとチェーンのUndoNumberの同期がなされている.SetUndoListではバックアップの対象となるオブジェクトに現UndoNumberが格納される.

UNDOBASE::CommandEndでは出口でUndoNumberの調整が行われる.⇒UndoStartでコマンドを開始する時点で,前方のコマンドチェーンがパージされる.このとき同期が一時的に崩れる場合がある.UndoCurptrが変更された場合には,つねにUndoNumberを更新する必要があるのではないか?UndoCurptrは以下で切り替えが発生する.

  1. UndoBase::UndoProcessの出口
  2. UndoSystem::UndoProcessの出口
  3. PergeZenpoChainの出口
  4. UNDOBASE::MakeNewCommandの出口
  5. UNDOBASE::CommandEndの出口で(UndoCount <= 2)のとき

UndoBase::UndoProcessは実質的には(ほぼ)使われていない.UndoBase::CommandEndで例外がキャッチされた場合にのみ,強制的にUNDOを実行して復帰するような作りになっているが,これが実行された試しはないと考えられる.

MAXUNDOCOUNT=5のとき,最大4コマンドまでしか保持できない.なぜか?⇒MakeNewCommandで(UndoCount >= MAXUNDOCOUNT)で打ち切っているためではないか?等号を外せば,MAXUNDOCOUNTまで作れるはずだ.⇒これでよい.

ここで一旦バックアップを取っておこう.

一覧画面の列ラベルをクリックしたときのテーブル並び替えが実行できないのはなぜか?⇒いや,動いている.セル項目をテキストしてソートしているので期待したような結果にならなかったためではないか?⇒カード番号は数値としてソートしているのに正しい並びになっている.見間違えだったのだろうか?まぁ,ともかく,これでよしとしよう.

少なくとも今当面の目的では,①カード番号,②氏名,③所属,④肩書きだけは数値としてソートしたい.⇒特注版の「数値で並び替え@20221225」オプションとして処理しておく.⇒うまく行った!

NAMESORT::NameNarabekaeのcheckがオンになっているとき,STOP文で止まらない(場合がある)のはなぜか?⇒ブレークポイントを置けば停止する.⇒STOP try {__asm { int 3} } catch (…){}を{ int 0}に書き換えたら毎回停止するようになった.

コラッツ木生成ツールから出力される隣接リストファイル(ADL)では,氏名欄にそのノードの値である巨大整数が入っている.カード番号はテーブルの範囲内であれば,その値をそのまま採用する場合もあるが,通常はオーバーフローしてしまうため,ハッシュして小さな数に変換している.ここで使っているハッシュ関数は単純なもので,すべてのビットが1であるようなある桁数の整数とANDを取っているだけだ.テーブルサイズを2のべき乗にしていたのはこのような事情による.

テーブルサイズが小さくなった場合はどういうことになるのか?現行では,0x1FFFという定数に固定されている.この値はテーブルサイズによって伸縮されるべきだと思う.カード番号のデータ型はlongなので,最大でもその範囲を超えることはできないが,テーブルサイズ AND FFFFFFFF まで使えるのではないだろうか?

▲発行されたカード番号が実際のテーブルサイズより大きくなる場合がある.テーブルサイズが1000のとき,最大#1097というカードが存在する.登録データはきっかり1000点だ.つまり,1000より小さい領域に97個分の穴が開いているということになるのだが… 実用的にはこれでも特に問題はないとも言えるが,参照番号はテーブルのレコード番号と一致するのがベストであるという観点からすれば,見直しの余地はあるのではないだろうか?⇒やってみることにしよう.

多少厄介なので,一度バックアップを取っておいた方がよいかもしれない.⇒どうも見ているところが違うようだ.カード番号はLINKTABLE::GetRefnumで決めていると思っていたが,通っていない.いや,いまテストしているのはADLファイルではなく,ZELファイルだ.⇒テーブルサイズを6000に拡大して読み込んだら,カード番号も振り直しされている.ただし,最大6000を超えるカードが97点ある.どこで振り直しをやっているのだろう?

カード番号が決定しないとテーブルは構成できない… COUPLING:InitLinkTable辺りでやっているのではないだろうか?⇒確かにそのようだ.参照番号が空スロットならばそこを使い,空いていないときは,空スロットを探してそこに居を定める論理になっている.BASETABLE:newlinkでは,まず指定番号のスロットが空いていればリンクを生成してそこにリンクする.空いていない場合は,makenewlinkを使って空スロットを探し,そこにリンクを(newlinkを使って)生成する.

しかし,この方式なら参照番号がテーブルサイズを超えることはないように思われるのだが… makenewlinkには2つのバージョンがあり,emptyrecnを使うパターンとgetnewRefnumを使うパターンがある.後者はmaxrefnumをインクリメントした番号を返すので増長してゆく可能性がある.⇒getnewRefnumの代わりにemptyrecnを使うようにしてみたが,効果なかった.⇒現行方式では参照番号の振り直しまでは実行していないので,テーブルサイズより大きなカード番号の存在は不可避である.⇒参照番号の振り直しというのがどこかにあったのではないか?

▲テーブル並び替えで系統並び替えが実行される.

テーブルサイズ8192(0x2000)でテストしてみた.最大で8289というカードがある.8289-8192=97でこの場合もはみ出しているカードのオーダーは同じだ.⇒MAXPDB=12300, MAXMDB=10300でCollatz12146.ZELを開くことができた.カード番号のはみ出しは解消した.ただし,三極検定でループカウントオーバーが発生している.

修正のフィックスでバグを作り込むとは

デバッグ作業が少し進み始めた.バグというのはとんでもないところに潜んでいるものだ.「デバッグにはいかなる予断も許されない」

UNDOBASE::SetUndoList→ で(!copynode->shadow)が発生

GetNewCard→ MakeNewCardで引数のrefnumが0のときは,mCreateCardで新規カードを作っている.mCreateCard→ CreateCard→ FAMILYTREE::getNewCard→ UNDOSYSTEM:CommandStart→ UNDOBASE::CommandStart→ BackupPointData→ SetUndoList→ で(!copynode->shadow)が発生している.⇒「生成したばかりでshadowを持つはずがない@20170823」というブロックが削除され,代わりに「1行削除@20220423」が入っている.この日付は2022-04-23だが,この修正は実際には2022-04-26-1で初めて入っている.この辺りのログを読んでみよう.

2022-04-29のログはそのものずばり,「UNDOBASE::SetUndoList で(!copynode->shadow)により停止した」となっている.⇒この記事では対処されていない.問題がメモリ不足の問題にすり替わっている.⇒2022-04-27で「UNDOに関する修正をフィックス」している.おそらく,ここで誤ったものと思われる.「UNDOのShadowをfreeblock化@20220423」2箇所 に該当するのではないか?

「UNDOのShadowをfreeblock化@20220423」というのがある.この日付が20220423となっているので,整合している.この定義はFIXED@20220426でフィックスされている.#ifndefのマクロで#elseが活きなくてはならないところを誤って削ってしまったのだろう.⇒復活させた.修正のフィックスでバグを作り込んでしまっていた.⇒別のエラーが出るようになった.

UNDOBASE::CommandEndでUndoCurptrが空になった.⇒PergeZenpoChainで空にしている.UNDOBASE::CommandEndは戻り値としてlongを返しているが,この値は初期値0のままで使われていない.⇒「ringTopが空のときはつねにPergeZenpoChainを実行する@20170515」となっているため,PergeZenpoChainが実行されている.UNDOSYSTEM::CommandEndには「UndoCurptrが空となる場合があり得る?@20220418」というコメントが付いている.この関数は外部で致命的エラーが発生したときには,fatalerrorを返している.

PergeZenpoChainでは,Undoチェーンの後方ノードが空,つまり,UndoCurptrが末尾ノードである場合は,UndoChain,UndoCurptr,UndoNumberをリセットしている.また,UndoCurptr=UndoChainの場合(UndoCurptrが先頭ノードの場合)も同様動作となる.従って,UndoCurptrが空となるのはノーマルな状態であると考えられる.

if (lret >= 0 && !UndoCurptr) STOP; あり得る@20220418 となっていたのだが,同日付であり得ないに変わっている.⇒lretにUndoNumberを格納してチェックを回避するように修正した.⇒どこかでハングしている.強制ブレーク→続行しようとして,以下のような見たこともないパネルが出た.

image

デバッグの中止もできない.どうも,このエラーは「Attempting to get the view from an adapter in state TextDocDataAvailable」はかなり始末が悪そうだ.ネット上にも情報はあるが,あまり役に立たない… デバッガに関係するものであるような気がするが…

PHASEがINITIALIZINGのままになっている.どこかで横道に逸れてしまっているのだろうか?エラーが発生しているのだろうか?CZelkovaCtrl3::TopologicalSortで-1017を返している.この値はCallSortLineageの戻り値だ.ERR_AUTOCORECTEDDATA(自動補正されたデータ:保存が必要)という通知だ.InitializeDisplayではUpdateFlagをオンにして対応しているが,Currefnumに0を格納しているため,動作がおかしくなっているのではないか?

Z.BaseRefnumには1が入っていて,GetRecordNumberでレコード番号を取り出そうとしているが,0が戻ってくる.Z.mSendRequest(4) ‘基準ノードの参照番号を請求する @@2016-10-22 というのがあるので,これで取り出してみてはどうか?⇒対処した.これで描画できるようになった.⇒この修正でGetNewCard→ MakeNewCard→ mCreateCard を通らなくなってしまったので,UNDOが掛からないようになっている.暫定修正を入れてもう一度動作確認してみよう.CommandEndの動作にはまだ少し疑問がある.

  1. (UndoCount <= 2)のときは,なぜUndoCurptrを繋ぎ変えてUndoChainに戻しているのか?
  2. なぜ,UndoCurptr->ringTopは空になっているのか?

FAMILYTREE::getNewCardは-10018を返している.⇒このエラーコードは「カード登録数がカードリンクテーブルのサイズを超えた」の意味だ.しかし,UNDOBASE::CommandEndにはアプリケーションの処理結果は一切入ってこない.⇒一手間かかってしまうが,アプリの処理結果をCommandEndに渡すようにしておいた方がよいのではないか?処理が失敗したときには,そのコマンドは破棄されるというのが当然の動作になるのではないかと思う.⇒一度バックアップを取ってから取り組むことにしよう.⇒ZELKOVA 2022-12-24 Aとして保全した.

「CommandEndに処理結果を渡す@20221224」で修正しておこう.⇒処理により,戻り値が結構あいまいな場合があるので,ケースバイケースで導入するものとし,今回はMAKENEWCARDにのみ限定適用とする.⇒PergeZenpoChainを実行して0復帰するようにした.UndoCurptr, UndoCount, UndoNumberはすべて初期化されている.

CommandEnd(DELCARD)では負値を返している.CommandEnd(DELALLCARD),CommandEnd(MERGECARDS)も同じ.これは別途チェックしておく必要がある.⇒UNDOBASE:CommandEndでは特に何もしていない.現行ではUndoNumberを返すようになっている.UNDOSYSTEM::CommandEndではTopologicalSortの結果を返すようになっている.致命的エラーが発生したときには,fatalerrorで復帰する.

UNDOSYSTEM::CommandEndで0復帰すると,画面が表示されない.なぜだろう?⇒GetNewCardで新規ファイルに失敗しただけで何も表示されないというのはかなりおかしい.⇒画面の更新はRefreshSubで実行されるが,更新のダブりを抑制するためのRefreshFlagはデータベースの読み込みが完了するまでは落ちない.このため,事実上UndoStatusの実行時にしか画面は更新されないようになっているが,これまでの論理ではZ.mUndoStatusがゼロの場合には画面の更新は実行されなかった.⇒UNDOSTAT.UPDATEDIAGRAM) <> 0 の場合はつねにZView.RefreshSubを呼び出すように修正した.

ここで一度バックアップを取っておこう.

▼MAXUNDOCOUNTに達したときの動作を確認する

Undoでテーブルが更新されていない.⇒UndoStatusに組み込んで動作するようになったが,呼び出し頻度が高過ぎる.⇒CardUndoRedoから呼び出すのが適切だ.⇒もともとこの位置から呼び出していた.

▲カードを1点づつ5点削除したあと,Undoを2回反復して,UndoProcessでUndoNumberの不一致 (UndoCurptr-> UndoNumber != UndoNumber)が発生.前者が7,後者が8.また,Undoで最初の50点まで戻れなくなる.

一覧画面が毎回同じ場所・サイズで開く.前回の場所を覚えていない.⇒現在位置は覚えているが,ファイルを閉じると忘れてしまうようだ.⇒ダブルクリックでオープンしたときは,DockingWindowFunc(False) が実行され,このときのウィンドウ位置を記憶するという動作になっている.⇒暫定的にこの動作を止めて任意の場所で開けるようになった.

▲テーブルをクリックしてCardTable_MouseClickが起動しない.⇒MouseClickというイベントが見当たらない.MouseDownというのはある.⇒MouseDownでも入ってこない.

▲CardGridView_CurrentCellChanged→EditTableEnd→…FAMILYTREE:GetCardBaseで(PHASE < DRAWSTAGE) で停止した.



MiniTool Partition Wizard でOSドライブの移行を試みる

アクセス解析プラグイン Site Kit でようやく詳細情報が出てきた.これで見ると,テント村の来訪者のプロフィールをまったく誤解していたようだ.STATISTICSで見ると最近の一日の来訪者は200人くらいになっているが,そのほとんどは検索エンジン経由で,URLでストレートにジャンプしてくるケースはごくわずかしかない.その検索ワードも,①regsvr32とか,②タイプ初期化子が例外をスローしました,③blend for visual studio, ④xoops 開発 終了など,ごく特殊なキーワードばかり.このようなキーワードについての記事を書いている訳ではないので,読んでもほとんど役に立っていないと思う.そんなことであれば,もう少し詳しい解説記事を書いた方がよいくらいだが,この辺りに関してはわたしもあまり専門的な知識を持ち合わせていない…

メール受信専用に使っているBlackHawkがメモリ不足で動作が悪いので,ディスククリーンアップの記事を探していたら,MiniTool Partition Wizard というのを見つけた.OSドライブを丸ごと引っ越しさせるという機能を持っている.ダウンロードに時間が掛かりそうなので,povo1.0の24時間使い放題220円を使ったが,ディスク容量不足で途中で中断してしまった.ただし,プログラムの本体はインストールされているようで,立ち上がってきた.無料評価版だが,果たして安全にOSドライブの移行が実行可能なのだろうか?失敗すればとんでもないことになる虞がある.⇒そもそも,それをやると移行先ディスクのデータはすべて消去される.もしやるとすれば移行先ドライブを空っぽにしてからでないと始められない.このドライブは238GBだが,うち,31GBが使用済みになっている.USBメモリに移せない容量ではないが…

このBlackHawkというマシンはかなり脆弱で外付けHDを接続できなかったのではないだろうか?確かにそのようだ.画面が不安定になって,おそらくどこかでクラッシュしてしまうだろう.⇒32GBのUSBメモリは装着できた.ここに一旦すべてのデータを退避させてみよう.残り時間20分となっているので,それほどの時間は掛からない.本体のMiniTool Partition Wizard と一緒にMiniTool ShadowMakerという別製品もインストールするようになっていたので,多分メモリ不足は後者のダウンロードで起きたのだろう.製品として購入すると8200円掛かる.⇒やってみよう.移行先ドライグを指定後,以下のパネルが出た.

image

よくわからないが,GPTでは2TB以上のドライブが扱える,UEFIというのはブートモードでWindows 11はUEFIにのみ対応という話なので,多分関係ないと思う.⇒移行した後,BIOSで起動ドライブを設定しなくてはならない.これができないとお釈迦になってしまう.試しておいた方がよいのではないか?⇒Windowsキー→設定→回復→今すぐ再起動→…→オプションの選択→トラブルシューティング→詳細オプション→UEFIファームウェアの設定→再起動→BIOS設定画面が起動という手順で起動できる.電源オンの直後にF2,ないしDelキーを押すということになっている.F2かDelかどちらかわからないがBIOS設定画面に出た.

移行先のSDDドライブはGPTディスクになっているようだ.⇒やはり,購入しないとOS移行はサポートされないようだ.8200円というのは買い切りではなく,年額だ.このソフトはかなりグレードが高いのでそれだけの価値はあると思うが… ここで8千円出費したら年が越せなくなるのではないか?そもそも,このマシンがあと1年持つのかさえ分からないというのに… とりあえず,ここは保留とするしかなさそうだ…

▲「メモリ描画環境用のメモリが不足しているため,生描画に切り替えます」が出て,モノクロに切り替えた後,倍率などを変えると同じメッセージが出て,生描画に戻ってしまう.

▲現行版では「氏名を表示」のみになっているのに,2行出ている.これはどういう設定になっているのか?

Collatz12146.ZELを開いて,例外が発生する.「ucrtbased.pdbは読み込まれていません」が出力画面に表示される.

image

続行で”Buffer too small”のエラーが起きる.

image

再試行でucrtbased.dllで停止するが,トレースはできない.⇒この障害は事前に大きめのファイルを2つ開いた後の読み込みで起きる.この後,「一部データに…修復されました」を表示してVBに制御が戻っているが,SetSingleSelection中にTREEVIEW::CheckSelectListのエラーが出る.selectcardlistのカウント1と現物カウント0で不一致が生じている.また,UNDOBASE::SetUndoListでcopynode->shadowが空で停止する.⇒この後,dp空で例外が発生するため,修正した.⇒ダメだ.”Buffer too small”がパスできなくなってしまった.⇒上で読み込めたというのは,「偶々」だったのだろうか?⇒コマンドライン引数で渡すようにしたら開けた.

見たことのないエラーが出た.

DataWarehouse ホストへの要求に失敗しました: ‘Invalid task token: 88802e77-79a6-4e8c-a1d0-60b392b93d34’

コマンドライン引数渡しも効果なかった.結局同じだ.

!ひどいバグがあった.CARDLINK::CheckCardLinkのダンプ文に一つ余分な引数が入っていた.⇒解決

SetSingleSelection中にTREEVIEW::CheckSelectListのエラーが出る.selectcardlistのカウント1と現物カウント0で不一致が生じている.⇒SetSingleSelectionは単選択を強制する関数なのだから,選択1でなくてはならないが,Currefnumがゼロとなっているため,選択されたカードが存在しない状態になっている.まず,これを一致させる必要がある.⇒対処した.⇒データベースのオープン関数ZView.Zelkova1.Openの戻り値をCurrefnumに格納する処理が落ちている.⇒修正した.⇒これで動作するようになった.

上記の「copynode->shadowが空で停止」も発生しないようになったが,なぜここでエラーが起きていたのかは別途調べておく必要がある.

GetNewCard→ MakeNewCardで引数のrefnumが0のときは,mCreateCardで新規カードを作っている.mCreateCard→ CreateCard→ FAMILYTREE::getNewCard→ UNDOSYSTEM::CommandStart→ UNDOBASE::CommandStart→ BackupPointData→ SetUndoList→ でエラーが発生している.この時点ではまだ新規カードは生成されていない.MAKENEWCARDではまず,partialmapを引数にSetUndoListが実行される.

アクセス解析ツールがようやく動き始めた

インストールしたアクセス解析ツールがようやく動き始めた.現在トータルユーザ36という表示が出ている.うちダイレクトアクセスは2人,それ以外はすべてOrganic Search,つまり検索エンジン経由ということになる.国別ではUSAから1人アクセスがあるようだ.テント村のサイドバーに出しているSTATISTICSでは今日の来訪者101,アクテイブ来訪者24となっているので,数字にはかなり開きがある.Site Kitの使い方はまだよくわからないので,調整が必要なのかもしれないが…

揚陸地点は決まった.ZELKOVA 再開発 2022-12-12,ここから始めるしかない.この版では人名テーブルと結婚テーブルのサイズはいずれも0x2000=8192となっている.

▲初期起動時,TREEVIEW::Refresh→…NAMEBOX::getGeneration中に(coordinate() == ABSOLUTE)で停止する.続行で新規ファイルになってしまう.この一行をコメントアウトすればファイルを開くことができる.DEBUG_NEVERというマクロはSTOPマクロを実行しているだけなので,動作に差の出る理由がよくわからない.

Refreshが呼び出されているということはすでに絶対座標系に切り替わっているはずなので,この位置でgetGenerationが呼び出されていることに問題があるように思われる.これは,「確定世代番号を導入する@20201121」という修正に関わるもので,Bobject::setabsoluteの中で,_generation = GetGeneration()が実行されている.ただし,GetGeneration関数の中で_generationを返しているので,この動作にはやや疑問がある.また,GetGenerationという関数があちこちで重複定義されている点も疑問だ.以下のクラスで再定義されている.

  1. GENEBOX
  2. PAIRBOX
  3. MARGBOX
  4. TRIBEBOX
  5. NAMEBOX
  6. TREEVIEW 相対座標系ではつねに0を返す
  7. TITLEBOX 相対座標系ではつねに0を返す

その理由はこの関数が仮想関数になっているためだろう.仮想関数にする必要があるのかどうか?というのがそもそも疑問だ._generation に値を代入しているのは,Bobject::setabsoluteだけで,この関数の中ではGetGenerationが呼び出されている.⇒MakeAbsoluteではSetAbsoluteを実行後にCOORDINATE = ABSOLUTEを実行しているので,これで問題ないのではないか?

getGenerationという関数は「常用世代番号」を返すことになっている.この関数をPrintParameterの中から呼び出しているところに問題があるのではないか?PrintParameterという関数は人名枠の中に付加情報として各種パラメータをプリントするための関数であり,絶対座標系以外では使われることはないのではないだろうか?

Collatz12146.ZELを開こうとすると,「登録リンク数が上限の8192を超えました」というエラーが二度発生したあと,「夫・妻リンクともに不在」が多量発生し,CARDLINK::CheckCardLink sc=3840 不正親番号の補正が実行された後,”Buffer too small”という例外が発生する.

image

今度は「データ不整合がありましたが…」を出したあと,描画できた.

image

ただし,以下のような複数の障害が発生している.

TREEVIEW::CheckSelectList

UNDOBASE::SetUndoList

UNDOBASE::UndoCopy

UNDONODE::Dispose

特にUNDOでポインタ空が発生しているというのは致命的だ.データ数は8192点まで削減されている.

image

まず,テーブルサイズを倍増(→16384)させて動作するかどうかを見てみよう.⇒リンカーでエラーになってしまった.

LINK : fatal error LNK1248: イメージ サイズ (823DC000) が最大許容サイズ (80000000) を超えています

「Win32 では1プロセスあたりのユーザーメモリ空間は 2GB」で0x80000000はその上限と思われる.これはWin32の制約なので,どうすることもできない.ちなみに現在の構成プロパティは,スタックサイズ2147483648,ヒープサイズ1073741824,ヒープコミットサイズ1048576に設定されている.現行では「テーブルサイズを2のべき乗にする@20220316」というオプションになっているので,8192点を超えることはできないということになってしまうのだが,「テーブルサイズを2のべき乗にする」というのはどういう効果があるのか?

いや,少なくともこの版では実効性はないようだ.ということは任意の値が取れるということなので,もう少し増やしてみよう.最終版では人名テーブル12300,結婚テーブル10300となっているが,この辺りがギリギリの範囲なのではないだろうか?