0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Cursor の state.vscdb が 8.9GB、バックアップも 8.9GB でした。VACUUM でどれだけ縮むかは、実行する前に計算できます

0
Posted at

Mac の空き容量を調べていたら、Cursor の ~/Library/Application Support/Cursor/User/globalStorage が 19GB ありました。中身のほとんどは、次の2つのファイルです。

8.9G  state.vscdb
8.9G  state.vscdb.backup

state.vscdb は SQLite のデータベースです。Cursor を終了してから sqlite3 state.vscdb "VACUUM;" を実行すると、使われていない領域を詰めて小さくできます。

VACUUM でどれだけ縮むかは、実行する前に計算できます。空いているページの数(freelist_count)にページの大きさ(page_size)を掛けた分が、縮む量の目安です。手元で 574MiB のデータベースを作り、3分の2を消してから VACUUM すると、計算どおり 191.5MiB になりました。

先に断っておくと、state.vscdb が大きくなる話は Cursor のフォーラムにいくつも投稿されています。Cursor を終了して VACUUM する手順も、そこで紹介されています。VACUUM が一時的に空き容量を使うことも、SQLite のドキュメントにあるとおりです。ここで書くのは、Cursor と同じ WAL モードのデータベースで、縮む量の計算と、VACUUM 中に使う空き容量を測った結果です。

state.vscdb と state.vscdb.backup

state.vscdb には、Cursor の設定や状態、エージェントとのチャットの履歴が入っています。手元のファイルの横には state.vscdb-wal と state.vscdb-shm もあったので、WAL モードで使われています。

state.vscdb.backup については、Cursor のフォーラムで「Cursor が自動で作るバックアップで、本体が小さくなれば、こちらも小さくなるはず」という回答がありました。いつ作られるのかは、書かれていません。

ファイルをそのまま消すと、チャットの履歴や状態が失われます。消すより先に、VACUUM で縮むかどうかを見ます。

縮む量を先に計算する

SQLite は、データを消しても、ファイルを小さくはしません。消したところは「空いているページ」として残り、次に書き込むときに使われます。VACUUM は、この空いているページを詰めて、ファイルを作り直します。

空いているページの数は、PRAGMA freelist_count で見られます。

cd ~/Library/Application\ Support/Cursor/User/globalStorage
sqlite3 state.vscdb "PRAGMA page_size; PRAGMA page_count; PRAGMA freelist_count;"

page_size × freelist_count が、VACUUM で縮む量の目安です。読むだけなので、Cursor を開いたままでも実行できます。

手元で、Cursor と同じ形のテーブル(ItemTable と cursorDiskKV)を持つ WAL モードのデータベースを作って確かめました。200KB の値を3,000件入れ、そのうち2,000件を消しています。

作成直後:     574.3 MiB
2/3 を削除後: 574.3 MiB   ← 消してもファイルは小さくならない

page_size      4096
page_count     147030
freelist_count 98017

4096 × 98017 は約 383MiB です。574.3MiB から引くと 191.4MiB になります。

VACUUM 後:    191.5 MiB

計算とほぼ同じでした。

何も消していないデータベースでは、freelist_count は 0 でした。VACUUM しても、574.3MiB のまま変わりません。freelist_count が小さければ、VACUUM しても縮みません。中身そのものが大きい、ということです。

VACUUM 中は、縮んだあとの大きさの2倍ほど空きが要る

VACUUM は、データベースを別の場所に作り直してから書き戻します。その間、空き容量を使います。

上の 574.3MiB のデータベースで VACUUM したとき、ディスクの使用量がいちばん増えたところで、始める前より 384MiB 多くなっていました。VACUUM 後の大きさ(191.5MiB)の、ほぼ2倍です。

内訳を見ると、WAL ファイル(-wal)が、いちばん大きいときで 192.6MiB まで育っていました。残りは、作り直すための一時ファイルと考えられます。一時ファイルは作られてすぐディレクトリから消されるので、du では見えませんでした。df の使用量の変化で測っています。

Cursor の 8.9GB のファイルが、あまり縮まなかった場合は、VACUUM の途中で十数 GB の空きが要ることになります。空き容量がぎりぎりのときは、先にほかのものを消して空きを作ってから実行します。

Cursor は終了してから実行する

開いている接続があるときの動きも確かめました。

ほかの接続の状態 VACUUM
接続を開いているだけ 成功
読み取りのトランザクション中 成功
書き込みのトランザクション中 Error: stepping, database is locked (5)

WAL モードでは、読み取り中の接続があっても VACUUM は通りました。止まるのは、書き込みの途中です。

Cursor は、使っている間にこのデータベースへ書き込みます。VACUUM の途中で Cursor が書き込もうとする場面も考えると、⌘Q で完全に終了してから実行するのが安全です。

手元での結果

Cursor を終了して VACUUM したあと、state.vscdb は【要記入:VACUUM 後の大きさ】になりました。Cursor を起動して、ふつうに使えることを確かめてから、state.vscdb.backup を消しています。

cd ~/Library/Application\ Support/Cursor/User/globalStorage
sqlite3 state.vscdb "VACUUM;"
du -sh state.vscdb
# Cursor を起動して確かめてから
rm state.vscdb.backup

VACUUM で縮まない場合、フォーラムでは、チャットの履歴にあたるキーを消してから VACUUM する方法も紹介されていました。こちらは履歴が見られなくなるので、試していません。

state.vscdb を小さくするときに見ておくこと

  • VACUUM で縮む量は、page_size × freelist_count で先に計算できる
  • freelist_count が小さければ、VACUUM しても縮まない
  • VACUUM の途中は、縮んだあとの大きさの2倍ほど、空き容量を使う
  • 書き込み中の接続があると database is locked で止まる。Cursor は終了してから実行する
  • state.vscdb.backup は、Cursor が動くことを確かめてから消す

あなたの globalStorage は、いま何 GB ありますか。

手元で試すコード

# mk.py:Cursor と同じ形の WAL モードのデータベースを作る
import sqlite3, os, sys
c = sqlite3.connect(sys.argv[1])
c.execute('pragma journal_mode=wal')
c.execute('create table ItemTable(key text unique on conflict replace, value blob)')
c.execute('create table cursorDiskKV(key text unique on conflict replace, value blob)')
b = os.urandom(200_000)
for i in range(3000):
    c.execute('insert into cursorDiskKV values(?,?)', (f'bubbleId:{i}', b))
c.commit()
c.execute('pragma wal_checkpoint(truncate)')
c.close()
python3 mk.py s.db
sqlite3 s.db "delete from cursorDiskKV where cast(substr(key,10) as int) % 3 != 0;
              pragma wal_checkpoint(truncate);"
sqlite3 s.db "pragma page_size; pragma page_count; pragma freelist_count;"
sqlite3 s.db "VACUUM;"
ls -l s.db

測った環境は Linux の SQLite 3.45.1 です。Mac の Cursor の実ファイルで、同じ数字になるとは限りません。

ふだんはraplsworks.comで、WordPressプラグイン開発やClaude Codeまわりのことを書いています。
https://raplsworks.com/

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?