要約

  • RFC 10022 でクライアントが指定する件数は、各 UID 区間が含み得る実在メッセージ数の上限である。正確な件数ではなく、サーバーは少ない区間を返せるうえ、区間端の UID が実在しないこともある。
  • OK UIDBATCHES completed が閉じるのは区間計算だけである。運用上の完了には、メールボックスと UIDVALIDITY、計画時点、変更通知、後続コマンドが実際に対象とした UID、消滅・新着・未確定の処置を同じ記録で照合する必要がある。

空だったのはメールボックスではなく、質問の窓だった

7,000 件のメッセージを 2,000 件ずつに分ければ、存在するバッチは四つである。クライアントがバッチ 6:8 を求めると、サーバーは範囲を一つも含まない UIDBATCHES 応答を返し、コマンドを OK で終える。

この応答を「メールボックスは空」と記録すれば、プロトコル上正しい結果が、運用上の誤報に変わる。空なのは指定したバッチ窓であって、選択中のメールボックスではない。

意味を保存するには、応答本文だけでは足りない。アカウント、選択中のメールボックス、UIDVALIDITY、コマンドタグ、要求したバッチサイズ、バッチ番号の窓、観測時刻が必要になる。RFC 10022 が応答にタグ相関子を必須とするのは、同時に進む複数の要求のうち、どの問いへの答えかを失わないためである。

最初の教訓は、OK を「仕事の成功」と読まないことだ。ここで成功したのは、妥当な要求に対する区間計算である。FETCH も STORE も COPY も MOVE も、まだ一件も実行されていない。

バッチサイズは片側だけ硬い

UIDBATCHES 2000 と指定した場合、返された一つの区間に 2,000 件を超える実在メッセージが含まれてはならない。この上限は厳格である。

しかし、2,000 件ちょうどを返す義務はない。実装が大幅に単純または効率的になる場合、あるいは計算中にメールボックスが変化した場合、特に expunge が起きた場合、サーバーは少ない件数の区間を返せる。可能なら要求値の 90% 以上を目指すべきだが、これは絶対的な下限ではない。

この非対称性は欠陥ではなく、役割分担である。クライアントは一単位の最大負荷を決める。サーバーは自らの格納構造と現在状態に合う境界を選ぶ。後続処理は実際に見つかったメッセージを数える。計画値と観測値を同じ列に入れなければ、三者の責任は混ざらない。

要求には 500 件という最小値もある。それ未満なら TOOFEW で拒否される。この制約は計算負荷だけでなく、UIDONLY の意味も守る。UIDONLY はメッセージシーケンス番号を使えなくする。もし一件単位の UIDBATCHES が許されれば、別経路から細かな位置を再構成できてしまう。

UIDBATCHES は作業を粗く分ける機能であって、位置情報を復活させる機能ではない。

境界 UID はメッセージの存在証明ではない

メールボックス世代の中で UID は増加するが、連続して埋まるとは限らない。削除は穴を残す。サーバーは効率のよい数値境界を選ぶこともできる。そのため RFC 10022 は、返した区間の先頭や末尾の UID に、実在するメッセージがなくてもよいとしている。

たとえば 163886:99703 は、二つのメッセージを指すのではなく、その UID 空間に現在存在するメッセージを後続コマンドの候補にする。最古の区間を UID 1 まで延ばすこともできる。実際の最小 UID が 302 でも、1 は「これより古いバッチはない」と明確にする境界として働く。

この性質はデータ設計で壊れやすい。区間の両端をメッセージ行への外部キーにしてはいけない。数値幅から件数を推定してはいけない。画面で端点を「発見済みメッセージ」と表示してはいけない。

永続的な参照の基本は、メールボックス名、UIDVALIDITY、UID の組である。UIDBATCHES はさらに計画世代を加えるが、その基本を置き換えない。UID が安定していても内容を認証するわけではなく、UIDVALIDITY が変われば古い権限は失われる。

新着は上に積もり、削除は古い帯を薄くする

返却済みの UID 区間の中に、後から新着メッセージが割り込むことはない。新しい UID は以前の高水位より上に割り当てられる。この性質により、古い区間の形は保たれる。

一方、区間の人口は減る。EXPUNGE や VANISHED が発生すれば、後続 FETCH が見つける件数は計画時より少なくなる。区間は妥当なままでも、「このバッチで 2,000 件を処理した」という記述は妥当でなくなる。

新着は古い計画の外側に新しい帯を作る。09:00 時点のバックアップなら次の世代に回せる。常時同期なら新しいバッチをすぐ開く。どちらが正しいかはサービスの目的で決まり、RFC の共通構文では決まらない。

再計算にも節度がある。別のメールボックスを選択した、半バッチを超えるメッセージが expunge された、または半バッチを超える新着があった場合を除き、クライアントは UIDBATCHES を再送してはならない。サーバーは違反を追跡し、LIMIT で拒否できる。

この半バッチ基準はサーバー資源を守るための共通線である。法的保存、移行完了、検索インデックスの鮮度を決める線ではない。技術的に再利用できる計画が、事業上の約束には古すぎることはあり得る。

エラーコードは修正権限を分ける

TOOFEW は粒度を上げるべきことを示す。TOOMANY は、指定窓または全件計画が広すぎることを示す。LIMIT は再計算頻度を下げるべきことを示す。バッチ番号の窓を 4:1 のように逆順で書けば、CLIENTBUG を伴う BAD になり得る。

これらを一括して「ページング失敗」と表示すると、回復の責任が曖昧になる。クライアントの構文を直すのか、窓を狭めるのか、バッチを大きくするのか、状態変化を待つのかが分からなくなる。

明確な失敗状態は、標準化の実用的な価値である。異なる製品でも、運用者が同じ原因分類に基づいてローカルな判断を下せる。標準がその判断を中央で行う必要はない。

100,000 件は共通能力の床である

明示的なバッチ窓は、バッチ数とサイズの積で 100,000 件を超えてはならない。サーバーは少なくとも 100,000 件を覆う UID 区間を返せる必要がある。ただし、極端に大きいメールボックスですべての範囲を一度に求めれば、TOOMANY で拒否されてもよい。

クライアントは窓を分けて進められる。メールボックスが窓と窓の間で変化するため、RFC 10022 は 1:100、100:200 のように境界バッチを重ねる方法を示す。二つの計算で同じバッチが違えば、変化または不整合を観測できる。

重複はロックではない。どちらの結果を採用すべきかを自動決定せず、その後の削除も防がない。重複の目的は、変化を隠さず目に見える比較対象を残すことにある。

比較前に重複を消去すれば、追加コストだけ払い、証拠を捨てることになる。応答時刻、重複部分、観測した変更、採用判断を一緒に保存して初めて、窓分割は監査可能になる。

似た拡張でも、完了させる動詞が違う

UIDONLY はシーケンス番号を排除し、expunge の通知を VANISHED にする。UIDBATCHES は粗い UID 境界を提供するが、メッセージごとの位置権限を戻さない。

PARTIAL は実際の SEARCH 結果をページ化し、または実際の UID FETCH の返却範囲を制限する。UIDBATCHES は、それらのコマンドより前に再利用可能な作業境界を作る。一方は実行結果の一部、他方は未実行の計画である。

SEARCHRES の $ は検索結果を保存する。UIDBATCHES は SEARCH ではないため、RFC 10022 は $ に保存してはならないとする。近似区間を、暗黙のメッセージ集合へ昇格させない境界である。

QRESYNC と CONDSTORE は変更シーケンスや VANISHED を通じてドリフトを観測しやすくする。ただし、古い計画を現在のスナップショットへ書き換えるものではない。

MESSAGELIMIT は、後続の SEARCH、FETCH、STORE、COPY、MOVE などが処理できる件数を宣言する。両拡張があるなら、クライアントはこの実行上限を超えないバッチサイズを選ぶべきである。2,000 件の計画が合法でも、実行上限が 1,000 件なら一回の FETCH に 2,000 件を渡す権限はない。

CAPABILITY の行は、能力名の勲章一覧ではない。実行可能な単位は、各契約と現在状態の積み重なりではなく、交差部分で決まる。

完了率より、七つの集合を照合する

一つの進捗率ではなく、次の人口を分けると判断が明確になる。

集合 確認する事実
P この仕事の方針とメールボックス世代に属するメッセージは何か
B 計画時に返却区間から到達可能だった実在メッセージは何か
A 後続コマンドが実際に対象にしたメッセージは何か
C 受理可能な終端結果を得たメッセージは何か
X 対象だったが expunge または vanish を観測したメッセージは何か
N 旧高水位より上に到着した新着は何か
U 結果不明または再試行可能なメッセージは何か

時点固定のエクスポートなら、P = C ∪ X、U は空、X には個別理由、N は次世代、という完了条件を選べる。継続同期なら N を即時に新しいバッチへ入れられる。どちらも RFC の外側にある正当なローカル決定である。

件数だけの一致は危険だ。一件が消え、一件が新着して処理されれば総数は合うが、対象の同一性は違う。照合にはメールボックス、UIDVALIDITY、UID、仕事世代が必要になる。

共通層をこの程度に薄く保つことは、Heng Lu の最小初期仕様とローカルな将来判断の考え方に合う。標準は相互検証可能な境界を与え、各運用者は自らの効果に責任を持つ。

公開文書から言えないこと

RFC 10022 は、特定のメールサービスが UIDBATCHES を採用したこと、特定クライアントが再計算規律を守ること、ある実装が 90% の目安に達することを示さない。本稿の空区間や消滅メッセージは運用試験であり、実在インシデントの報告ではない。

IANA 登録は UIDBATCHES、TOOFEW、TOOMANY の意味を共有させる。実行中サーバーを検査せず、後続処理を完了させない。宣言、計画状態、観測効果は別の現実層である。

動くコードを優先するとは、仕様を無視することではない。仕様に従った区間が存在しても、実際の結果が U を残すなら「完了」という組織の表現を訂正できなければならない、という意味である。

出典