Skip to content

スナップショットの世代がグループを跨ぐたびに増え、3 世代の保持枠を奪い合う(同じグループの履歴が短くなる) #248

Description

@takemi-ohama

何を見つけたか

アカウントグループの違うプロジェクトを行き来すると、起動のたびに新しい世代が作られ、そのたびに全体のバックアップ(full.tar.zst)を取り直す。 保持は 3 世代なので、2 つのグループを交互に使うと、同じグループの履歴が 3 世代の枠から押し出される。

世代を分ける判定は、直前の 1 世代のボリュームの組との比較だけで行っている。

# lib/devbase/snapshot/manager.py:504-508
snap_dir = self.backups_dir / latest.get('name', '')
if snap_dir.is_dir() and self.snapshot_volumes(snap_dir) != self.volumes:
    logger.info("対象ボリュームの構成が変わったため新しい世代を作成します ...")

self.volumes は devbase_home_ubuntu と devbase_home_<group> の組で、後者は起動するプロジェクトのグループで決まる。グループが違えば組が変わるため、必ず新世代になる。

実測(2026-09-23、この端末)

backups/snapshot.yml と du の実測。

世代 作成 対象ボリューム 差分数 サイズ
20260915-231738 09-15 23:18 ubuntu, default 9 37 GB
20260920-212546 09-20 21:26 ubuntu, with 0 1.8 GB
20260923-081407 09-23 08:15 ubuntu, default 0 3.9 GB

backups/ の合計は 42 GB。

  • 09-20 21:26 は with-ai-dev の起動(コンテナ with-ai-dev-dev-1 の作成が 21:26:02)
  • 09-23 08:15 は ai-plugins の起動(コンテナ ai-plugins-dev-1 の作成が 08:16:33)。ai-plugins 自身は default で、グループの指定はどこにも無い

利用者から見えるのは次の 1 行だけで、なぜ with が出てくるのかが読み取れない。直前の世代を作ったのが別のグループのプロジェクトだった、という文脈が文言に無い。

対象ボリュームの構成が変わったため新しい世代を作成します (旧: devbase_home_ubuntu, devbase_home_with / 新: devbase_home_ubuntu, devbase_home_default)

なぜ起きるか

世代の系列が 1 本しかない。 should_start_new_generation は「最新の 1 世代」とだけ比べ、rotate は世代の一覧の末尾から DEFAULT_MAX_GENERATIONS = 3 件を残して古い順に消す(manager.py:36, 451-479)。ボリュームの組ごとに系列を持つ仕組みが無いため、

  1. グループを跨ぐたびに full.tar.zst を取り直す(差分が積めない。09-23 の世代は 3.9 GB)
  2. 3 世代の枠を、グループの違う世代が奪い合う

2 が本体の実害である。 default → with → default → with と 4 回切り替えると、保持される 3 世代のうち default の履歴は 1〜2 世代しか残らない。devbase snapshot restore で戻せる範囲が、切り替えの回数だけ短くなる。

世代を分けること自体は正しい(コメントのとおり、別のレイアウトの snapshot.snar へ差分を積むと全ファイルが移動した扱いになって差分が壊れる)。問題は分けた後の保持の単位である。

直さないと何が起きるか

  • 複数のアカウントグループを使う端末(この端末は default / with / kkg の 3 つ)で、バックアップの履歴が黙って短くなる。切り替えの頻度が上がるほど短くなり、気づく手段が無い
  • 切り替えのたびに全体のバックアップを取り直すため、起動が遅くなりディスクを食う
  • 文言から原因が読み取れないため、今回のように「関係ないはずのグループ名が出る」ことの説明に調査が要る

修正レイヤー

現象レイヤー: lib/devbase/snapshot/manager.py の should_start_new_generation(:482-512)と rotate(:451-479)。

修正レイヤー: 世代の保持の単位。いまは「全世代を 1 本の列として新しい順に 3 件」だが、ボリュームの組(= グループ)ごとに系列を持ち、系列ごとに保持数を数えるのが責務の位置である。backups/snapshot.yml は既に世代ごとに volumes を持っているので、読み取りの側を変えれば足りる見込み。

採る手: 分割(系列の導入)。should_start_new_generation は「最新の 1 世代」ではなく「同じボリュームの組を持つ最新の世代」と比べ、差分を積めるならそこへ積む。rotate は組ごとに keep 件を残す。

決めること

  • 保持の数をグループごとに数えるか、全体の上限も併せて持つか(3 グループ × 3 世代 = 最大 9 世代がディスクに載る。この端末では 37 GB の世代があるため、全体の上限も要るかもしれない)
  • 同じ組の古い世代へ差分を積み直せるか(snapshot.snar は世代ごとに持っているので積めるはずだが、間に別のグループの起動を挟んだ場合にボリュームの中身が変わっている可能性をどう扱うか)
  • 文言に「直前の世代を作ったプロジェクト / グループ」を添えるか(今回の混乱はこれが無いことによる)

由来

v3.7.0 の作業中、ai-plugins(default)を起動したときに devbase_home_with が出てきた理由の調査。

進行

モード: standard / 作業ツリー: .worktrees/feature/plan68-snapshot-series / 計画: issues/PLAN68_snapshot-series.md

  • 要求と受け入れ条件 — 2026-09-24 10:29
  • 作業場所の用意 — 2026-09-24 10:31
  • 設計 — 2026-09-24 10:31
  • 素材の収集と出典の確定
  • ドキュメント再構成 — 2026-09-24 10:37
  • ドキュメントレビュー — 2026-09-24 10:38
  • 計画 — 2026-09-24 11:54
  • 実装 — 2026-09-24 11:55
  • 構造改善 — 2026-09-24 12:03
  • 実装レビュー — 2026-09-24 13:10
  • 完了判定 — 2026-09-24 13:46
  • Pull Request — 2026-09-24 14:17
  • 確定仕様化 — 2026-09-24 18:52
  • 後片付け — 2026-09-24 11:54
  • 配布 — 2026-09-24 19:18
  • 体裁レビュー
  • リリース後テスト — 2026-09-24 19:19
  • 振り返り — 2026-09-24 19:29

振り返り: #262 (comment)

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions