-- Inserts land in write buffers, promotion and merge turn them into immutable ones, -- VACUUM clears liveness bits; verify checks every stage. The maintenance worker may promote -- on its own, so segment counts are only checked after merge. CREATE EXTENSION pg_sift; CREATE TABLE ml (id serial PRIMARY KEY, body text); CREATE INDEX ml_idx ON ml USING sift (body) WITH (write_buffer_limit = 64); CREATE FUNCTION ml_state() RETURNS TABLE (alpha bigint, late bigint, huge bigint, extra bigint) LANGUAGE sql AS $$ SELECT count(*) FILTER (WHERE body @@> 'alpha'), count(*) FILTER (WHERE body @@> 'late'), count(*) FILTER (WHERE body @@> 'bigword2999'), count(*) FILTER (WHERE body @@> 'extra') FROM ml $$; SET enable_seqscan = off; SET enable_indexscan = off; -- the large doc spans many write buffer pages INSERT INTO ml (body) SELECT 'alpha beta word' || (i % 50) || ' gamma' FROM generate_series(1, 2000) i; INSERT INTO ml (body) SELECT string_agg('bigword' || g, ' ') FROM generate_series(1, 3000) g; SELECT * FROM ml_state(); alpha | late | huge | extra -------+------+------+------- 2000 | 0 | 1 | 0 (1 row) SELECT sift.verify('ml_idx', true); verify -------- (1 row) SELECT sift.promote('ml_idx') IS NOT NULL AS promoted; promoted ---------- t (1 row) SELECT * FROM ml_state(); alpha | late | huge | extra -------+------+------+------- 2000 | 0 | 1 | 0 (1 row) SELECT sift.verify('ml_idx', true); verify -------- (1 row) -- deletes and updates, then VACUUM DELETE FROM ml WHERE id % 3 = 0; UPDATE ml SET body = body || ' extra' WHERE id % 5 = 0; SELECT * FROM ml_state(); alpha | late | huge | extra -------+------+------+------- 1334 | 0 | 0 | 267 (1 row) VACUUM ml; SELECT * FROM ml_state(); alpha | late | huge | extra -------+------+------+------- 1334 | 0 | 0 | 267 (1 row) SELECT sift.verify('ml_idx', true); verify -------- (1 row) INSERT INTO ml (body) SELECT 'alpha late' FROM generate_series(1, 300); SELECT * FROM ml_state(); alpha | late | huge | extra -------+------+------+------- 1634 | 300 | 0 | 267 (1 row) SELECT sift.promote('ml_idx') IS NOT NULL AS promoted; promoted ---------- t (1 row) SELECT sift.merge('ml_idx', true) IS NOT NULL AS merged; merged -------- t (1 row) SELECT count(*) FILTER (WHERE kind = 'immutable') AS immutable, sum(ndocs) FILTER (WHERE kind = 'immutable') AS ndocs FROM sift.segments('ml_idx'); immutable | ndocs -----------+------- 1 | 1634 (1 row) SELECT * FROM ml_state(); alpha | late | huge | extra -------+------+------+------- 1634 | 300 | 0 | 267 (1 row) SELECT sift.verify('ml_idx', true); verify -------- (1 row) -- heap slots freed by VACUUM are reused: a dead doc and a live one share a key across segments CREATE TABLE ru (id int, body text); CREATE INDEX ru_idx ON ru USING sift (body); INSERT INTO ru SELECT i, 'reuse old' FROM generate_series(1, 20) i; SELECT sift.promote('ru_idx') IS NOT NULL AS promoted; promoted ---------- t (1 row) DELETE FROM ru; VACUUM ru; INSERT INTO ru SELECT i, 'reuse new' FROM generate_series(1, 20) i; SELECT sift.promote('ru_idx') IS NOT NULL AS promoted; promoted ---------- t (1 row) SELECT count(*) FILTER (WHERE body @@> 'old') AS old, count(*) FILTER (WHERE body @@> 'new') AS new FROM ru; old | new -----+----- 0 | 20 (1 row) SELECT sift.verify('ru_idx', true); verify -------- (1 row) DROP TABLE ml, ru; DROP FUNCTION ml_state(); DROP EXTENSION pg_sift;