要約
- RFC 9738 では、SEARCH、FETCH、STORE、MOVE、UID EXPUNGE が高い UID から最大 N 件を処理し、
OKとMESSAGELIMITを同時に返せる。成功した範囲と未処理範囲は別の状態である。 - COPY と MULTIAPPEND は上限超過時に何も実行しない原子的拒否を守るが、MOVE などは実際の部分効果を残すため、再開方法をコマンドごとに管理しなければならない。
- 広告値はクライアントが守る協調上限であり、現在の厳格な強制値、メールボックスの大きさ、全クライアントの対応、利用者が見た最終結果を証明しない。
UID MOVE で 18,000 から 21,000 までを移そうとする。サーバーは高い UID 側の千件を移動し、送信元から expunge した後、OK [MESSAGELIMIT 1000 20001] を返す。クライアントは同じ UID 集合をもう一度送れる。すでに移動した UID は送信元に存在しないので、次の呼び出しは残りに進む。
これは有用な再開性である。しかし、一回目と二回目の間に障害が起きれば、全体を一括で元に戻す保証はない。送信元と宛先にはすでに効果がある。RFC 9738 が与えるのは、部分効果を隠さず続きを組み立てる材料であって、複数回の MOVE を一つの原子的操作に変える魔法ではない。
N はメールボックスの件数ではない
サーバーは CAPABILITY に MESSAGELIMIT=N を載せ、SEARCH、FETCH、STORE、COPY、MOVE と UID 版、APPEND、UID EXPUNGE が一回に処理できる最大件数を示す。COPY と APPEND 系だけを制限する場合は SAVELIMIT=N を使う。広告値は千未満にしないことが推奨される。
この数字はメールボックス容量ではない。保存期間、ストレージ quota、一通のサイズ上限でもない。あくまで一つのコマンドが処理する件数である。
SEARCH では一致件数ではなく、調べた件数が上限に数えられる。千件を評価して十件だけが条件に合った場合、十件は正しい結果だが、より古い範囲に一致がないとは言えない。全件カウントに使うなら、次の範囲へ進む必要がある。
MESSAGELIMIT を返すとき、サーバーは高い UID から低い UID へ処理しなければならない。応答中の LastUID は今回処理した最小 UID である。再開位置を計算する手掛かりだが、未処理件数でも snapshot token でもない。途中で到着や expunge が起こり、UIDVALIDITY が変われば、古い境界を新しい世代へ持ち越せない。
成功状態と完了状態を分ける
FETCH は千件分のデータを返し、最後に OK [MESSAGELIMIT …] と応答できる。SEARCH は調査済み範囲の一致 UID を返す。STORE ならその範囲の flag がすでに変わっている。MOVE なら宛先への copy と送信元からの expunge が起きている。UID EXPUNGE なら対象範囲の削除が完了している。
この OK を失敗扱いするのは、実際の効果を無視することになる。全体完了扱いするのは、残りを無視することになる。必要なのは、呼び出しの成功と元の意図の消化を別々に記録することである。
再開規則も同じではない。UID STORE は返された最小 UID を除くよう範囲を更新する。UID MOVE は同じ UID 集合を再送できる。一方、sequence number による MOVE は expunge で番号が詰まるため、対象を再計算しなければならない。UID EXPUNGE は同じ UID 引数を繰り返し、限界コードが消えるか明示的失敗に達するまで進められる。
すべてを「cursor を一つ減らして retry」と実装すれば、UID と sequence number の違いが消える。重複、取りこぼし、別メッセージへの作用が起きても、各コマンドは形式上成功し得る。
応答の読み方にも罠がある。EXPUNGEISSUED も必要な場合、それは tagged OK に置かれ、MESSAGELIMIT は untagged NO に置かれる。最後の tagged 行だけ読む実装は、未完了を示すコードを捨てる。tag、untagged response、返されたデータ、response code、最終状態を一つの transcript として保存する必要がある。
COPY と MOVE は同じ上限でも違う
COPY と UID COPY は原子的である。対象が上限を超えれば tagged NO を返し、一通も copy してはならない。MULTIAPPEND も同様で、過大なグループの先頭だけを append することはない。
MOVE は原子的である必要がなく、処理済みの一部を残す。STORE と UID EXPUNGE も部分効果を持てる。同じ MESSAGELIMIT が現れても、前者は「効果なしの拒否」、後者は「効果ありの部分成功」である。運用記録からコマンド種別を落とせば、復旧方針を決められない。
さらに EXPUNGE、CLOSE、STATUS UNSEEN にはこの件数上限を課してはならない。これらは全体の意味を保つ。ただし、その OK がストレージ耐久性、別クライアントの同期、利用者の閲覧まで証明するわけではない。
RFC 9394 の PARTIAL は別の契約を作る。明示した PARTIAL 範囲が N より大きければ、サーバーは何もせず拒否する。PARTIAL を使わない同等の FETCH は暗黙の一部を返せる。明示した page とサーバー側の切り詰めは、どちらも小分けに見えても失敗時の効果が異なる。
保存結果は欠落も保存する
SEARCHRES は SEARCH の結果を $ に保存できる。元の SEARCH が限界に達した場合、RFC 9738 は $ も切り詰めるよう求める。変数は調べ終えた範囲内の一致を正しく保持するが、元の全範囲の一致ではない。
後続の STORE や COPY が $ に対して完全成功すると、前段の欠落が見えにくくなる。後続 transcript に MESSAGELIMIT がなくても、入力集合の由来は部分的なままである。正しい処理を何段重ねても、最初に外れた範囲は自動では戻らない。
保存結果には、選択 mailbox、UIDVALIDITY、検索条件、元範囲、上限、最小処理 UID、時刻、完了フラグを結び付けるべきである。$ は便利な参照であり、網羅性証明ではない。
UIDAFTER と UIDBEFORE は次の SEARCH を表しやすくする。しかし、到着を止めず、消えた UID を復元せず、世代変更を越えない。複数コマンドを一つの snapshot にするものではない。
広告してから強制する
RFC 9738 は、非対応クライアントへの移行コストを隠していない。大きな mailbox に上限を急に強制すれば、古いクライアントは最新 N 件しか取得できず、SEARCH の count を誤り、COPY を完了できない。利用者から見れば壊れたサーバーになる。
そこで、まず上限を広告しながら強制しない方法が示される。対応クライアントは自主的に小さいコマンドへ移り、負荷を下げる。古いクライアントは当面動き続ける。その後、広告値を千、非公開の hard limit を一万とする段階も可能である。広告値超過を log に残せば、強制を厳しくする前に適応状況を観察できる。
CAPABILITY の文字列は導入の出発点であり、導入率の測定値ではない。広告値は対応クライアントが守る値、hard limit はサーバーが実際に切る値である。両者を同じ metric にすると、移行中の旧クライアントと仕様を無視する新クライアントを区別できない。
段階導入の強さは、非対応を道徳的な違反にせず、具体的な互換性問題として扱う点にある。動いている接続を観察し、影響を測り、厳格化する。宣言だけで現実が変わったことにしない。
一連の処理を閉じる台帳
全 mailbox を対象とする job は、最初の意図を保持しなければならない。mailbox と UIDVALIDITY、元の対象、コマンド、原子性分類、観測した capability、返却 UID、実効果、untagged response、最終 status、限界値、LastUID を各回について記録する。
終了時には、開始時に対象だった集合、実際に調査・変更した集合、途中で消えた集合、開始後に到着して対象外だった集合を照合する。説明できない差分は未解決として残す。最後の一回に限界コードがなかっただけでは、動的 mailbox 全体の snapshot は得られない。
UIDBATCHES は範囲を計画し、PARTIAL は page を要求し、MESSAGELIMIT は実行中に当たった上限を報告し、SEARCHRES は結果を保存する。それぞれを一つの「batch」機能へ平らにすれば、どこで何が保証されたか追えなくなる。
同じ UID 集合を再送できることは便利である。しかし本当に重要なのは、その間ずっと元の意図と各部分効果を結び付けることである。処理を完結させるのは再送そのものではなく、境界を引き継いで最後の差分まで説明するクライアントだ。
出典
- https://www.rfc-editor.org/rfc/rfc9738.html
- https://www.rfc-editor.org/rfc/rfc9738.txt
- https://www.rfc-editor.org/info/rfc9738/
- https://datatracker.ietf.org/doc/rfc9738/
- https://datatracker.ietf.org/doc/rfc9738/history/
- https://www.rfc-editor.org/errata/rfc9738
- https://www.rfc-editor.org/rfc/rfc9051.html
- https://www.rfc-editor.org/info/rfc9051/
- https://www.rfc-editor.org/rfc/rfc9394.html
- https://www.rfc-editor.org/info/rfc9394/
- https://www.rfc-editor.org/rfc/rfc5182.html
- https://www.rfc-editor.org/info/rfc5182/
- https://www.rfc-editor.org/rfc/rfc5256.html
- https://www.rfc-editor.org/info/rfc5256/
- https://www.rfc-editor.org/rfc/rfc3502.html
- https://www.rfc-editor.org/info/rfc3502/
- https://www.rfc-editor.org/rfc/rfc6851.html
- https://www.rfc-editor.org/info/rfc6851/
- https://www.rfc-editor.org/rfc/rfc4315.html
- https://www.rfc-editor.org/info/rfc4315/
- https://www.iana.org/assignments/imap-capabilities/
- https://datatracker.ietf.org/doc/draft-ietf-extra-imap-messagelimit/
- https://heng.lu/running-code-primary-the-patch-needed-to-preserve-the-internet-original-design/
- https://heng.lu/minimum-initial-specification-localized-future-decision-voluntary-adoption-internet-coordination-system/
会員向け解説
プロフィールの詳細
適切な会員レベルでログインすると、解説全文と出典メモをご覧いただけます。
Strategic Circle 限定
Strategic Circle
すべての読者に公開されています。参加してログインすると プロフィール解説 を閲覧できます。
Strategic Circle に参加Leadership Alliance 会員限定
Leadership Alliance
対象となる IP 資産の所有者・管理者向けです。ログインすると Leadership Alliance の解説を閲覧できます。
Leadership Alliance に参加
