Skip to content

Commit 7d727fb

Browse files
committed
tests: passing rewind oriole teest
1 parent 4f78fb8 commit 7d727fb

2 files changed

Lines changed: 245 additions & 29 deletions

File tree

nix/ext/tests/lib.nix

Lines changed: 40 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -413,6 +413,7 @@ let
413413
makeOrioledbSpecialisation =
414414
{
415415
postgresPort ? defaultPort,
416+
extraConfig ? "",
416417
}:
417418
let
418419
orioledbPkg = self.packages.${system}."psql_orioledb-17/bin";
@@ -442,35 +443,42 @@ let
442443

443444
# Runs as postgres: initdb with OrioleDB-specific args, config deployment, validation
444445
initScript = pkgs.pkgsLinux.writeShellScript "postgresql-orioledb-init" ''
445-
set -euo pipefail
446-
DATA_DIR="${newDataDir}"
447-
448-
if [ ! -f "$DATA_DIR/PG_VERSION" ]; then
449-
echo "Initializing OrioleDB database at $DATA_DIR"
450-
${orioledbPkg}/bin/initdb \
451-
--allow-group-access --data-checksums \
452-
--locale-provider=icu --encoding=UTF-8 --icu-locale=en_US.UTF-8 \
453-
-U supabase_admin -D "$DATA_DIR"
454-
fi
455-
456-
# Deploy processed config files with @dataDir@ substituted
457-
for f in postgresql.conf pg_hba.conf pg_ident.conf supautils.conf read-replica.conf; do
458-
sed "s|@dataDir@|$DATA_DIR|g" ${processedConfig}/$f > "$DATA_DIR/$f"
459-
done
460-
461-
# Copy conf.d directory
462-
rm -rf "$DATA_DIR/conf.d"
463-
cp -r ${processedConfig}/conf.d "$DATA_DIR/conf.d"
464-
chmod -R u+w "$DATA_DIR/conf.d"
465-
466-
# Copy extension-custom-scripts directory
467-
rm -rf "$DATA_DIR/extension-custom-scripts"
468-
cp -r ${processedConfig}/extension-custom-scripts "$DATA_DIR/extension-custom-scripts"
469-
chmod -R u+w "$DATA_DIR/extension-custom-scripts"
470-
471-
# Validate config
472-
echo "Validating PostgreSQL configuration..."
473-
${orioledbPkg}/bin/postgres -C shared_preload_libraries -D "$DATA_DIR"
446+
set -euo pipefail
447+
DATA_DIR="${newDataDir}"
448+
449+
if [ ! -f "$DATA_DIR/PG_VERSION" ]; then
450+
echo "Initializing OrioleDB database at $DATA_DIR"
451+
${orioledbPkg}/bin/initdb \
452+
--allow-group-access --data-checksums \
453+
--locale-provider=icu --encoding=UTF-8 --icu-locale=en_US.UTF-8 \
454+
-U supabase_admin -D "$DATA_DIR"
455+
fi
456+
457+
# Deploy processed config files with @dataDir@ substituted
458+
for f in postgresql.conf pg_hba.conf pg_ident.conf supautils.conf read-replica.conf; do
459+
sed "s|@dataDir@|$DATA_DIR|g" ${processedConfig}/$f > "$DATA_DIR/$f"
460+
done
461+
462+
# Append any extra configuration
463+
if [ -n '${extraConfig}' ]; then
464+
cat >> "$DATA_DIR/postgresql.conf" << 'EXTRA_CONFIG_EOF'
465+
${extraConfig}
466+
EXTRA_CONFIG_EOF
467+
fi
468+
469+
# Copy conf.d directory
470+
rm -rf "$DATA_DIR/conf.d"
471+
cp -r ${processedConfig}/conf.d "$DATA_DIR/conf.d"
472+
chmod -R u+w "$DATA_DIR/conf.d"
473+
474+
# Copy extension-custom-scripts directory
475+
rm -rf "$DATA_DIR/extension-custom-scripts"
476+
cp -r ${processedConfig}/extension-custom-scripts "$DATA_DIR/extension-custom-scripts"
477+
chmod -R u+w "$DATA_DIR/extension-custom-scripts"
478+
479+
# Validate config
480+
echo "Validating PostgreSQL configuration..."
481+
${orioledbPkg}/bin/postgres -C shared_preload_libraries -D "$DATA_DIR"
474482
'';
475483

476484
# Full db init: CREATE EXTENSION orioledb first, then init-scripts + migrations
@@ -545,6 +553,7 @@ let
545553
};
546554

547555
# Override postgresql: new package, new data dir, new ExecStartPre for orioledb initdb
556+
# Restart settings match production: ansible/files/postgresql_config/postgresql.service
548557
systemd.services.postgresql = {
549558
after = [ "postgresql-migrate.service" ];
550559
requires = [ "postgresql-migrate.service" ];
@@ -554,6 +563,8 @@ let
554563
initScript
555564
];
556565
ExecStart = lib.mkForce "${orioledbPkg}/bin/postgres -D ${newDataDir}";
566+
Restart = "always";
567+
RestartSec = "5";
557568
};
558569
environment = {
559570
GRN_PLUGINS_DIR = lib.mkForce "${groongaPackage}/lib/groonga/plugins";

nix/ext/tests/orioledb-rewind.nix

Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
{ self, pkgs }:
2+
let
3+
pname = "orioledb-rewind";
4+
testLib = import ./lib.nix { inherit self pkgs; };
5+
in
6+
pkgs.testers.runNixOSTest {
7+
name = pname;
8+
nodes.server =
9+
{ ... }:
10+
{
11+
imports = [
12+
(testLib.makeSupabaseTestConfig {
13+
majorVersion = "15";
14+
})
15+
];
16+
17+
specialisation.orioledb17.configuration = testLib.makeOrioledbSpecialisation {
18+
extraConfig = ''
19+
orioledb.enable_rewind = true
20+
orioledb.main_buffers = 1280
21+
orioledb.rewind_max_time = 1200
22+
orioledb.rewind_max_transactions = 100000
23+
'';
24+
};
25+
};
26+
testScript =
27+
{ nodes, ... }:
28+
let
29+
orioledb17-configuration = "${nodes.server.system.build.toplevel}/specialisation/orioledb17";
30+
in
31+
''
32+
import time
33+
34+
orioledb17_configuration = "${orioledb17-configuration}"
35+
36+
start_all()
37+
38+
# Wait for full Supabase initialization on PG 15
39+
server.wait_for_unit("supabase-db-init.service")
40+
41+
with subtest("Switch to OrioleDB and show rewind config"):
42+
server.succeed(
43+
f"{orioledb17_configuration}/bin/switch-to-configuration test >&2"
44+
)
45+
server.wait_for_unit("supabase-db-init.service")
46+
47+
# Verify OrioleDB is running
48+
installed_extensions = server.succeed(
49+
"psql -U supabase_admin -d postgres -t -A -c \"SELECT extname FROM pg_extension WHERE extname = 'orioledb';\""
50+
).strip()
51+
assert "orioledb" in installed_extensions, (
52+
f"Expected orioledb extension to be installed, got: {installed_extensions}"
53+
)
54+
55+
# Show all rewind-related settings
56+
rewind_settings = server.succeed(
57+
"psql -U supabase_admin -d postgres -t -A -c \"SELECT name || ' = ' || setting FROM pg_settings WHERE name LIKE 'orioledb.%rewind%' OR name LIKE 'orioledb.%main_buffers%' ORDER BY name;\""
58+
).strip()
59+
print(f"OrioleDB rewind settings:\n{rewind_settings}")
60+
61+
# Assert rewind is enabled
62+
rewind_enabled = server.succeed(
63+
"psql -U supabase_admin -d postgres -t -A -c \"SHOW orioledb.enable_rewind;\""
64+
).strip()
65+
assert rewind_enabled == "on", (
66+
f"Expected orioledb.enable_rewind = on, got: {rewind_enabled}"
67+
)
68+
69+
# Print rewind queue/evicted lengths
70+
queue_len = server.succeed(
71+
"psql -U supabase_admin -d postgres -t -A -c \"SELECT orioledb_get_rewind_queue_length();\""
72+
).strip()
73+
evicted_len = server.succeed(
74+
"psql -U supabase_admin -d postgres -t -A -c \"SELECT orioledb_get_rewind_evicted_length();\""
75+
).strip()
76+
print(f"Initial rewind queue length: {queue_len}")
77+
print(f"Initial rewind evicted length: {evicted_len}")
78+
79+
with subtest("Basic rewind"):
80+
# Phase 1: Setup — matches bash script exactly
81+
server.succeed(
82+
"psql -U supabase_admin -d postgres -c \"DROP TABLE IF EXISTS rewind_test; CREATE TABLE rewind_test(x serial) USING orioledb; INSERT INTO rewind_test SELECT FROM generate_series(1, 100);\""
83+
)
84+
85+
# Capture xid, oxid, and hash in a single query — matches bash script
86+
ids = server.succeed(
87+
"psql -U supabase_admin -d postgres -t -A -c \"SELECT pg_current_xact_id()::text::int4, orioledb_get_current_oxid()::int8, md5(string_agg(x::text, '.' ORDER BY x)) FROM rewind_test;\""
88+
).strip()
89+
parts = ids.split("|")
90+
xid = parts[0]
91+
oxid = parts[1]
92+
pre_hash = parts[2]
93+
print(f"Checkpoint: xid={xid} oxid={oxid} hash={pre_hash}")
94+
95+
# Phase 2: Dirty the state — matches bash script
96+
server.succeed(
97+
"psql -U supabase_admin -d postgres -c \"INSERT INTO rewind_test SELECT FROM generate_series(1, 10); INSERT INTO rewind_test SELECT FROM generate_series(1, 10); INSERT INTO rewind_test SELECT FROM generate_series(1, 10); INSERT INTO rewind_test SELECT FROM generate_series(1, 10);\""
98+
)
99+
dirty_count = server.succeed(
100+
"psql -U supabase_admin -d postgres -t -A -c \"SELECT count(*) FROM rewind_test;\""
101+
).strip()
102+
print(f"Rows before rewind: {dirty_count}")
103+
queue_len = server.succeed(
104+
"psql -U supabase_admin -d postgres -t -A -c \"SELECT orioledb_get_rewind_queue_length();\""
105+
).strip()
106+
evicted_len = server.succeed(
107+
"psql -U supabase_admin -d postgres -t -A -c \"SELECT orioledb_get_rewind_evicted_length();\""
108+
).strip()
109+
print(f"Queue length: {queue_len}, evicted length: {evicted_len}")
110+
111+
# Phase 3: Rewind — the function crashes postgres, || true absorbs psql error
112+
print(f"Calling orioledb_rewind_to_transaction({xid}, {oxid})...")
113+
server.succeed(
114+
f"psql -U supabase_admin -d postgres -c \"SELECT orioledb_rewind_to_transaction({xid}, {oxid});\" 2>&1 || true"
115+
)
116+
117+
# Phase 4: Wait for server restart (systemd Restart=always brings it back)
118+
print("Waiting for server restart...")
119+
time.sleep(5)
120+
server.succeed(
121+
"until psql -U supabase_admin -d postgres -t -A -c 'SELECT 1' 2>/dev/null; do sleep 1; done"
122+
)
123+
print("Server is back up")
124+
125+
# Verify
126+
post_hash = server.succeed(
127+
"psql -U supabase_admin -d postgres -t -A -c \"SELECT md5(string_agg(x::text, '.' ORDER BY x)) FROM rewind_test;\""
128+
).strip()
129+
post_count = server.succeed(
130+
"psql -U supabase_admin -d postgres -t -A -c \"SELECT count(*) FROM rewind_test;\""
131+
).strip()
132+
print(f"Rows: {post_count} (expect 100)")
133+
print(f"Hash before: {pre_hash}")
134+
print(f"Hash after: {post_hash}")
135+
match = "YES" if pre_hash == post_hash else "NO"
136+
print(f"Match: {match}")
137+
assert post_count == "100", f"Expected 100 rows after rewind, got: {post_count}"
138+
assert pre_hash == post_hash, f"Hash mismatch: {pre_hash} != {post_hash}"
139+
print("Basic rewind test PASSED")
140+
141+
with subtest("Rewind under buffer pressure"):
142+
# Create a new table for buffer pressure test
143+
server.succeed(
144+
"psql -U supabase_admin -d postgres -c \"DROP TABLE IF EXISTS pressure_test; CREATE TABLE pressure_test(x serial) USING orioledb;\""
145+
)
146+
147+
# Insert data in 50 batches of 100 rows each (5000 rows across 50 transactions)
148+
for batch in range(50):
149+
server.succeed(
150+
"psql -U supabase_admin -d postgres -c \"INSERT INTO pressure_test SELECT FROM generate_series(1, 100);\""
151+
)
152+
153+
# Capture checkpoint state in a single query
154+
cp_ids = server.succeed(
155+
"psql -U supabase_admin -d postgres -t -A -c \"SELECT pg_current_xact_id()::text::int4, orioledb_get_current_oxid()::int8, count(*) FROM pressure_test;\""
156+
).strip()
157+
cp_parts = cp_ids.split("|")
158+
cp_xid = cp_parts[0]
159+
cp_oxid = cp_parts[1]
160+
cp_count = cp_parts[2]
161+
print(f"Buffer pressure checkpoint: xid={cp_xid}, oxid={cp_oxid}, count={cp_count}")
162+
163+
# Insert 10 more batches after checkpoint
164+
for batch in range(10):
165+
server.succeed(
166+
"psql -U supabase_admin -d postgres -c \"INSERT INTO pressure_test SELECT FROM generate_series(1, 100);\""
167+
)
168+
169+
after_count = server.succeed(
170+
"psql -U supabase_admin -d postgres -t -A -c \"SELECT count(*) FROM pressure_test;\""
171+
).strip()
172+
print(f"After additional inserts: count={after_count}")
173+
174+
# Print queue/evicted lengths to show buffer state
175+
queue_len = server.succeed(
176+
"psql -U supabase_admin -d postgres -t -A -c \"SELECT orioledb_get_rewind_queue_length();\""
177+
).strip()
178+
evicted_len = server.succeed(
179+
"psql -U supabase_admin -d postgres -t -A -c \"SELECT orioledb_get_rewind_evicted_length();\""
180+
).strip()
181+
print(f"Buffer pressure state - queue length: {queue_len}, evicted length: {evicted_len}")
182+
183+
# Rewind — function crashes postgres
184+
print(f"Calling orioledb_rewind_to_transaction({cp_xid}, {cp_oxid})...")
185+
server.succeed(
186+
f"psql -U supabase_admin -d postgres -c \"SELECT orioledb_rewind_to_transaction({cp_xid}, {cp_oxid});\" 2>&1 || true"
187+
)
188+
189+
# Wait for server restart
190+
time.sleep(5)
191+
server.succeed(
192+
"until psql -U supabase_admin -d postgres -t -A -c 'SELECT 1' 2>/dev/null; do sleep 1; done"
193+
)
194+
195+
# Verify rewind restored checkpoint state
196+
post_pressure_count = server.succeed(
197+
"psql -U supabase_admin -d postgres -t -A -c \"SELECT count(*) FROM pressure_test;\""
198+
).strip()
199+
print(f"After buffer pressure rewind: count={post_pressure_count} (expect {cp_count})")
200+
assert post_pressure_count == cp_count, (
201+
f"Expected {cp_count} rows after buffer pressure rewind, got: {post_pressure_count}"
202+
)
203+
print("Buffer pressure rewind test PASSED")
204+
'';
205+
}

0 commit comments

Comments
 (0)