第4話「眠れない夜の計算式」
異変は、深夜に起きた。
管理層には昼も夜もないが、地上の時間はダッシュボードで見える。大陸の東から闇が広がり、街の灯りが消え、住人の活動を示す光の点が静まっていく。深夜。世界が眠る時間。
だが、ダッシュボードの一角だけが騒がしかった。
『アラート:レベルアップ永続化バッチ — 処理停止(CRITICAL)』
また赤いアラートだ。管理人になって数日。もう慣れてきた自分が少し怖い。
「ノード、レベルアップの永続化バッチって何だ」
「えーと、住人が昼間に戦ったり修行したりして得た成長の記録を、深夜にまとめて正式に書き込む処理のことです」
あのステータス障害のときに見た構造と同じだ。昼間の活動はまず手元の一時記録に仮反映される。住人はすぐに「強くなった」と実感できる。だが、それはまだ仮の数字だ。
深夜になると、一日分の仮の数字を集めて、本体のデータに正式に書き込むバッチが走る。
この深夜のバッチが、止まっている。
アラートの詳細を開くと、見慣れない文字列が並んでいた。
『停止理由:相互待機状態により処理続行不能』
相互待機。
二つの処理が、お互いの完了を待ち合って、どちらも先に進めなくなっている。
前の世界では「デッドロック」と呼ばれていた。食卓で二人が同時にナイフとフォークを取ろうとして、一方がナイフを、もう一方がフォークを掴み、互いに「もう片方をよこせ」と言い合ったまま食事が始まらない――そんな状態だ。
「管理人さん! 管理人さん!」
背後から、聞き慣れない声がした。
振り返ると、細身のメガネの青年が駆け寄ってきた。きっちりしたシャツにベスト。体の周囲に数式のようなものがぼんやりと浮かんでいるが、その数式がぐちゃぐちゃに乱れている。手には、そろばんのようなデータ計算ツールを握りしめていた。
「あなたが新しい管理人さんですか!? ノードさんから聞きました! お願いです、助けてください!」
「……お前は?」
「僕はカルク! 経験値とレベルの計算を担当しているプロセスです!」
ノードとは違う。こいつは世界の基盤の一部が、人の姿を取った存在のようだ。こんなのもいるのか。
「計算が合わないんです! 昼間の仮計算は全部正しいのに、永続化バッチが止まっちゃって、書き込みができなくて――」
カルクの目に涙が浮かんでいる。手のそろばんが、カタカタと震えていた。体の周囲の数式はぐちゃぐちゃに絡まって、見ているだけで目が回りそうだった。
「バッチが、バッチが詰まって……僕はただ、正しい数字を出したいだけなのに……!」
パニック状態だ。だが、言っていることは技術的に正確だった。
「落ち着け。状況は把握した」
俺はダッシュボードに向き直り、バッチ処理の詳細画面を開いた。
まず止まった時刻を確認する。深夜一刻。バッチが走り始めてから約1時間後、処理の途中で止まっている。
影響範囲を見る。今夜の書き込み対象は280万余名。昼間に戦闘や修行をした住人だけではない。地上の魔物まで含めた、この世界で今日何かと戦ったすべての存在の記録だ。全員分が、本体への書き込みを待ったまま宙ぶらりんになっている。このまま朝になれば、住人たちは「昨日の戦闘でレベルが上がったはずなのに」と首を傾げることになる。実害はすぐには出ないが、次のバッチが走るまでに直さなければ、今夜分の記録も積み上がる。
次に、止まった理由を掘る。
処理の流れが見える。住人Aの経験値を正式に書き込もうとする処理と、住人Bの経験値を書き込もうとする処理。この二つが、同じデータの領域を互い違いに掴んでいた。
Aの処理が「住人Aのデータ」をロックし、次に「共有の計算テーブル」にアクセスしようとしている。
Bの処理が「共有の計算テーブル」をロックし、次に「住人Aのデータ」にアクセスしようとしている。
AはBが持っている領域を待ち、BはAが持っている領域を待つ。永遠に。
古典的な問題だった。ただし厄介なことに、どちらも悪意を持っていない。AもBも、自分のやるべき処理を懸命にこなそうとしているだけだ。それぞれが正しく動こうとした結果、互いが互いの邪魔になっている。誰かを責められる問題じゃない。
「カルク、この二つの処理が同じ領域を掴む順番は、いつから今の順番になってる?」
「えっと……ずっと前からです。前任の方が作ったときからだと思います」
また太古の設計か。
「昔は問題なかったのか?」
「はい! 住人が少なかった頃は、同時に書き込みが走ることが滅多になくて……でも最近、住人が増えて、戦闘も増えて、深夜のバッチで同時に処理される件数が多くなって……」
数千年前は住人が少なく、処理が衝突する確率が低かった。だが世界が発展して住人が増え、処理の同時実行数が上がったことで、ついに衝突が頻発するようになった。
あのステータス障害も、勇者のスキル停止も、根は同じだ。太古の設計が、現代の負荷に耐えられなくなっている。
解決策は明確だった。
「カルク、処理がデータの領域を掴む順番を統一する。全部の処理が必ず同じ順番で領域を掴むようにすれば、互い違いになることはなくなる」
「それで直るんですか!? 順番を変えるだけで……?」
「今はAが"住人データ"を先に掴んで、Bが"共有テーブル"を先に掴んでいる。だから互い違いになる。でも全部の処理を"住人データ→共有テーブル"の順に統一すれば、先に動き始めたほうが住人データを掴んだとき、共有テーブルはまだ誰も触っていない。先に掴んだほうが両方の作業を終えてから、次のほうが動き始める」
「……あっ」カルクが目を丸くした。「交差しなくなる」
「そうだ」
「直る。ただし――」
俺はバッチの処理ロジックを開いた。処理の手順が記述されている。
「この処理、どこまで書き込んだか記録してないな。途中で失敗したらどうなる?」
「え……全部やり直しになります。最初から」
「どこで止まったかわからないから、最初から数え直す、ということか」
「……はい」
カルクが、少し顔を歪めた。
280万件を順番に処理していく。100万件目まで終わったところで、デッドロックが起きる。バッチは止まる。そして再起動すると――また0件目から始める。記録がないから、どこまで終わったかわからない。100万件分の作業はなかったことになる。
次も同じ箇所でデッドロックが起きれば、また最初から。その繰り返しだ。
前の世界なら、こんな設計は初日にレビューで弾かれる。だが数千年間、誰もレビューしなかった。
「掴む順番を統一した上で、もう一つ仕組みを入れる。処理が失敗しても、失敗した分だけをやり直せるようにする。全部最初からではなく、途中から再開できる仕組みだ」
前の世界では、こうした仕組みを「リトライ戦略」と呼んでいた。失敗を前提にして、賢く再試行する設計。
俺はバッチのロジックを書き換えていった。
まず掴む順番の統一。住人データを先に、共有テーブルは後。それだけのルールを、全処理に書き込む。
次に件数の分割。280万件超を一括で処理していたのを、1,000件ずつのかたまりに小分けにする。2,800回に分ければ、失敗しても巻き戻るのは最大1,000件分だけだ。280万件まるごとやり直しとは、わけが違う。一かたまりが終わったら、どこまで完了したかを記録する。
最後に、失敗時の挙動。失敗が起きたら、最初からではなく「記録した続き」から再開する。全部をやり直す必要はない。
作業の途中で、カルクが後ろからそっと覗き込んできた。
「えっ……その行って、変えても大丈夫なんですか? 計算式が崩れたりしません?」
「お前が出す数字は変わらない。データの掴み方を変えるだけだ」
「そうなんですか……」
カルクは半信半疑のまま、それでもずっとそこに立っていた。黙ったまま、手のそろばんをそっと胸に抱いて。
書き換えの途中で、処理ロジックの片隅に、古い書き込みを見つけた。
`// TODO: いつか直す`
コメント。この処理を作った人間が残した、メモ書き。
前の世界でも、こういうコメントは山ほど見た。「いつか直す」と書いて、結局直されないまま何年も残り続けるコメント。エンジニアなら誰でも知っている。
だが、ここでは「いつか」が数千年だった。
書いたのはエルディアス。この世界を作った前任の神。
――いつか直す。
その「いつか」は来なかった。お前は直す前にいなくなった。
俺は黙ってコメントの下に処理を書き加え、修正を完了した。
『レベルアップ永続化バッチ — 処理再開』
ダッシュボードの画面に、数字が流れ始めた。住人たちの経験値が、一件ずつ正式にデータへ書き込まれていく。
カルクが食い入るように画面を見つめていた。
「計算が……合ってる。数字が、全部合ってる……!」
体の周囲の数式が、乱れた状態から美しい配列に整っていく。カルクの目から涙がこぼれた。
「正しい計算ができた……! ずっとずっと、合わなくて、どうしようもなくて……でも今、全部合ってる……!」
「……大げさだな」
「大げさじゃないですよ! 僕にとっては、正しい数字が出ることが、世界で一番大事なことなんです!」
カルクが涙を拭きながら笑った。数式が踊るように体の周りを回っている。
俺は少しだけ、口元が緩むのを感じた。
「あの」 カルクが、しぼり出すような声で言った。
「……ありがとうございます。本当に、ありがとうございます」
「礼はいい」
「でも言わせてください」 カルクはメガネを外し、袖で目を拭いた。「僕、ずっとひとりで詰まっていて。何とかしようとしても、何もできなくて……」
カルクの目が、今度は真っ直ぐにこちらを向いていた。涙が引いて、その目は透き通っていた。
「正しい計算ができる。それだけで、十分です」
俺は何も言わなかった。
ただ、前の世界でも、鳴り止まない警報の前でひとりだった夜のことを、少し思い出した。
「ノード」
「はい?」
「この世界の基盤の中に、こういうサブプロセスは他にもいるのか?」
「えーと……ダンジョンを管理しているダンジさんとか、天候を管理しているセレスさんとか、何人かいますけど……みんな、ちょっとずつ調子が悪くて……」
「具体的には?」
「ダンジさんは……ダンジョンの部屋が自動で作れなくなってきていて、手作業で補ってるんですけど、追いつかなくなってきているみたいで。セレスさんは、天候の計算が少しずつずれていて……北の山岳地帯が今週から雪になっているのも、本当は秋のはずなんですけど」
「……なるほど」
調子が悪い担当者が、あちこちにいる。
俺はダッシュボードに目を戻した。緑に変わったバッチのアラートの横に、まだ黄色い警告がいくつも並んでいる。
そして、さっき見つけたコメントが頭から離れなかった。
`// TODO: いつか直す`
この世界の基盤を作った神は、自分の仕事が不完全だと知っていた。直すつもりだった。でも、直さなかった。
なぜ直さなかったのか。なぜいなくなったのか。
その答えは、まだどこにもない。
お読みいただきありがとうございます。
【今回のIT用語】
デッドロック:二つの処理がお互いの完了を待ち合って、どちらも先に進めなくなる状態。食卓でナイフとフォークを取り合う例えがよく使われます。
リトライ戦略:処理が失敗したとき、賢く再試行する仕組み。「全部やり直し」ではなく「失敗した分だけやり直す」のがポイントです。
次話「迷宮が暴走する日」もよろしくお願いします。
感想・ブックマークいただけると励みになります。




