diff --git a/Dockerfile-orioledb-17 b/Dockerfile-orioledb-17 index b796e75b21..2b0f8e9fd4 100644 --- a/Dockerfile-orioledb-17 +++ b/Dockerfile-orioledb-17 @@ -157,14 +157,6 @@ RUN sed -i 's/ timescaledb,//g;' "/etc/postgresql/postgresql.conf" && \ RUN sed -i 's/\(shared_preload_libraries.*\)'\''\(.*\)$/\1, orioledb'\''\2/' "/etc/postgresql/postgresql.conf" && \ echo "default_table_access_method = 'orioledb'" >> "/etc/postgresql/postgresql.conf" -# OrioleDB rewind configuration -# Enables time-based rewind capability for up to 20 minutes (1200 seconds) -# Buffer size: 1280 buffers * 8KB = 10MB for transaction retention -RUN echo "orioledb.enable_rewind = true" >> "/etc/postgresql/postgresql.conf" && \ - echo "orioledb.rewind_max_time = 1200" >> "/etc/postgresql/postgresql.conf" && \ - echo "orioledb.rewind_max_transactions = 100000" >> "/etc/postgresql/postgresql.conf" && \ - echo "orioledb.rewind_buffers = 1280" >> "/etc/postgresql/postgresql.conf" - # Include schema migrations COPY migrations/db /docker-entrypoint-initdb.d/ COPY ansible/files/pgbouncer_config/pgbouncer_auth_schema.sql /docker-entrypoint-initdb.d/init-scripts/00-schema.sql diff --git a/ansible/tasks/stage2-setup-postgres.yml b/ansible/tasks/stage2-setup-postgres.yml index 9adef6f68f..d935d24473 100644 --- a/ansible/tasks/stage2-setup-postgres.yml +++ b/ansible/tasks/stage2-setup-postgres.yml @@ -52,38 +52,6 @@ path: '/etc/postgresql/postgresql.conf' state: 'present' - - name: Enable OrioleDB rewind feature - ansible.builtin.lineinfile: - path: /etc/postgresql/postgresql.conf - line: "orioledb.enable_rewind = true" - state: present - when: is_psql_oriole and stage2_nix - become: yes - - - name: Set OrioleDB rewind max time (20 minutes) - ansible.builtin.lineinfile: - path: /etc/postgresql/postgresql.conf - line: "orioledb.rewind_max_time = 1200" - state: present - when: is_psql_oriole and stage2_nix - become: yes - - - name: Set OrioleDB rewind max transactions - ansible.builtin.lineinfile: - path: /etc/postgresql/postgresql.conf - line: "orioledb.rewind_max_transactions = 100000" - state: present - when: is_psql_oriole and stage2_nix - become: yes - - - name: Set OrioleDB rewind buffers (1280 buffers = 10MB) - ansible.builtin.lineinfile: - path: /etc/postgresql/postgresql.conf - line: "orioledb.rewind_buffers = 1280" - state: present - when: is_psql_oriole and stage2_nix - become: yes - - name: Add ORIOLEDB_ENABLED environment variable ansible.builtin.lineinfile: line: 'ORIOLEDB_ENABLED=true' diff --git a/ansible/vars.yml b/ansible/vars.yml index 8a0c6649e7..aa7f5c63ed 100644 --- a/ansible/vars.yml +++ b/ansible/vars.yml @@ -10,9 +10,9 @@ postgres_major: # Full version strings for each major version postgres_release: - postgresorioledb-17: "17.6.0.043-orioledb" - postgres17: "17.6.1.086" - postgres15: "15.14.1.086" + postgresorioledb-17: "17.6.0.044-orioledb" + postgres17: "17.6.1.087" + postgres15: "15.14.1.087" # Non Postgres Extensions pgbouncer_release: 1.25.1 diff --git a/nix/config.nix b/nix/config.nix index ca8a841f53..e61683674c 100644 --- a/nix/config.nix +++ b/nix/config.nix @@ -56,8 +56,8 @@ in }; orioledb = { "17" = { - version = "17_15"; - hash = "sha256-1v3FGIN0UW+E4ilLwbsV3nXvef3n9O8bVmgyjRFEJsU="; + version = "17_16"; + hash = "sha256-Xm9IUsvmlcayNQH8TCvHoIV23xkt/WQV0Oy4CiJkywc="; }; }; }; diff --git a/nix/ext/orioledb.nix b/nix/ext/orioledb.nix index a9170a9d05..e338a3a27b 100644 --- a/nix/ext/orioledb.nix +++ b/nix/ext/orioledb.nix @@ -15,10 +15,10 @@ stdenv.mkDerivation rec { src = fetchFromGitHub { owner = "orioledb"; repo = "orioledb"; - rev = "beta13"; - sha256 = "sha256-80RQHOgkEC7Hq3+N1VhsuKEUL+SNT/WfDN5vmXpaQG4="; + rev = "982e11ae62c9e00c0d74f9f8de31d99ff383fd02"; + sha256 = "sha256-Vz3vfmTGRW+O9aXZxqixHC2CpqZJf/1UCQWoENbAak4="; }; - version = "beta13"; + version = "982e11ae62c9e00c0d74f9f8de31d99ff383fd02"; buildInputs = [ curl libkrb5 @@ -27,7 +27,7 @@ stdenv.mkDerivation rec { openssl ]; buildPhase = '' - make USE_PGXS=1 ORIOLEDB_PATCHSET_VERSION=15 + make USE_PGXS=1 ORIOLEDB_PATCHSET_VERSION=16 ''; installPhase = '' runHook preInstall diff --git a/nix/ext/tests/lib.nix b/nix/ext/tests/lib.nix index a07b838e57..d278333062 100644 --- a/nix/ext/tests/lib.nix +++ b/nix/ext/tests/lib.nix @@ -120,10 +120,6 @@ let # OrioleDB: append orioledb to shared_preload_libraries sed -i "s/\(shared_preload_libraries.*\)'\(.*\)$/\1, orioledb'\2/" $out/postgresql.conf echo "default_table_access_method = 'orioledb'" >> $out/postgresql.conf - echo "orioledb.enable_rewind = true" >> $out/postgresql.conf - echo "orioledb.rewind_max_time = 1200" >> $out/postgresql.conf - echo "orioledb.rewind_max_transactions = 100000" >> $out/postgresql.conf - echo "orioledb.rewind_buffers = 1280" >> $out/postgresql.conf '' else "" @@ -417,6 +413,7 @@ let makeOrioledbSpecialisation = { postgresPort ? defaultPort, + extraConfig ? "", }: let orioledbPkg = self.packages.${system}."psql_orioledb-17/bin"; @@ -446,35 +443,42 @@ let # Runs as postgres: initdb with OrioleDB-specific args, config deployment, validation initScript = pkgs.pkgsLinux.writeShellScript "postgresql-orioledb-init" '' - set -euo pipefail - DATA_DIR="${newDataDir}" - - if [ ! -f "$DATA_DIR/PG_VERSION" ]; then - echo "Initializing OrioleDB database at $DATA_DIR" - ${orioledbPkg}/bin/initdb \ - --allow-group-access --data-checksums \ - --locale-provider=icu --encoding=UTF-8 --icu-locale=en_US.UTF-8 \ - -U supabase_admin -D "$DATA_DIR" - fi - - # Deploy processed config files with @dataDir@ substituted - for f in postgresql.conf pg_hba.conf pg_ident.conf supautils.conf read-replica.conf; do - sed "s|@dataDir@|$DATA_DIR|g" ${processedConfig}/$f > "$DATA_DIR/$f" - done - - # Copy conf.d directory - rm -rf "$DATA_DIR/conf.d" - cp -r ${processedConfig}/conf.d "$DATA_DIR/conf.d" - chmod -R u+w "$DATA_DIR/conf.d" - - # Copy extension-custom-scripts directory - rm -rf "$DATA_DIR/extension-custom-scripts" - cp -r ${processedConfig}/extension-custom-scripts "$DATA_DIR/extension-custom-scripts" - chmod -R u+w "$DATA_DIR/extension-custom-scripts" - - # Validate config - echo "Validating PostgreSQL configuration..." - ${orioledbPkg}/bin/postgres -C shared_preload_libraries -D "$DATA_DIR" + set -euo pipefail + DATA_DIR="${newDataDir}" + + if [ ! -f "$DATA_DIR/PG_VERSION" ]; then + echo "Initializing OrioleDB database at $DATA_DIR" + ${orioledbPkg}/bin/initdb \ + --allow-group-access --data-checksums \ + --locale-provider=icu --encoding=UTF-8 --icu-locale=en_US.UTF-8 \ + -U supabase_admin -D "$DATA_DIR" + fi + + # Deploy processed config files with @dataDir@ substituted + for f in postgresql.conf pg_hba.conf pg_ident.conf supautils.conf read-replica.conf; do + sed "s|@dataDir@|$DATA_DIR|g" ${processedConfig}/$f > "$DATA_DIR/$f" + done + + # Append any extra configuration + if [ -n '${extraConfig}' ]; then + cat >> "$DATA_DIR/postgresql.conf" << 'EXTRA_CONFIG_EOF' + ${extraConfig} + EXTRA_CONFIG_EOF + fi + + # Copy conf.d directory + rm -rf "$DATA_DIR/conf.d" + cp -r ${processedConfig}/conf.d "$DATA_DIR/conf.d" + chmod -R u+w "$DATA_DIR/conf.d" + + # Copy extension-custom-scripts directory + rm -rf "$DATA_DIR/extension-custom-scripts" + cp -r ${processedConfig}/extension-custom-scripts "$DATA_DIR/extension-custom-scripts" + chmod -R u+w "$DATA_DIR/extension-custom-scripts" + + # Validate config + echo "Validating PostgreSQL configuration..." + ${orioledbPkg}/bin/postgres -C shared_preload_libraries -D "$DATA_DIR" ''; # Full db init: CREATE EXTENSION orioledb first, then init-scripts + migrations @@ -549,6 +553,7 @@ let }; # Override postgresql: new package, new data dir, new ExecStartPre for orioledb initdb + # Restart settings match production: ansible/files/postgresql_config/postgresql.service systemd.services.postgresql = { after = [ "postgresql-migrate.service" ]; requires = [ "postgresql-migrate.service" ]; @@ -558,6 +563,8 @@ let initScript ]; ExecStart = lib.mkForce "${orioledbPkg}/bin/postgres -D ${newDataDir}"; + Restart = "always"; + RestartSec = "5"; }; environment = { GRN_PLUGINS_DIR = lib.mkForce "${groongaPackage}/lib/groonga/plugins"; diff --git a/nix/ext/tests/orioledb-rewind.nix b/nix/ext/tests/orioledb-rewind.nix new file mode 100644 index 0000000000..ef1a86f078 --- /dev/null +++ b/nix/ext/tests/orioledb-rewind.nix @@ -0,0 +1,205 @@ +{ self, pkgs }: +let + pname = "orioledb-rewind"; + testLib = import ./lib.nix { inherit self pkgs; }; +in +pkgs.testers.runNixOSTest { + name = pname; + nodes.server = + { ... }: + { + imports = [ + (testLib.makeSupabaseTestConfig { + majorVersion = "15"; + }) + ]; + + specialisation.orioledb17.configuration = testLib.makeOrioledbSpecialisation { + extraConfig = '' + orioledb.enable_rewind = true + orioledb.main_buffers = 1280 + orioledb.rewind_max_time = 1200 + orioledb.rewind_max_transactions = 100000 + ''; + }; + }; + testScript = + { nodes, ... }: + let + orioledb17-configuration = "${nodes.server.system.build.toplevel}/specialisation/orioledb17"; + in + '' + import time + + orioledb17_configuration = "${orioledb17-configuration}" + + start_all() + + # Wait for full Supabase initialization on PG 15 + server.wait_for_unit("supabase-db-init.service") + + with subtest("Switch to OrioleDB and show rewind config"): + server.succeed( + f"{orioledb17_configuration}/bin/switch-to-configuration test >&2" + ) + server.wait_for_unit("supabase-db-init.service") + + # Verify OrioleDB is running + installed_extensions = server.succeed( + "psql -U supabase_admin -d postgres -t -A -c \"SELECT extname FROM pg_extension WHERE extname = 'orioledb';\"" + ).strip() + assert "orioledb" in installed_extensions, ( + f"Expected orioledb extension to be installed, got: {installed_extensions}" + ) + + # Show all rewind-related settings + rewind_settings = server.succeed( + "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;\"" + ).strip() + print(f"OrioleDB rewind settings:\n{rewind_settings}") + + # Assert rewind is enabled + rewind_enabled = server.succeed( + "psql -U supabase_admin -d postgres -t -A -c \"SHOW orioledb.enable_rewind;\"" + ).strip() + assert rewind_enabled == "on", ( + f"Expected orioledb.enable_rewind = on, got: {rewind_enabled}" + ) + + # Print rewind queue/evicted lengths + queue_len = server.succeed( + "psql -U supabase_admin -d postgres -t -A -c \"SELECT orioledb_get_rewind_queue_length();\"" + ).strip() + evicted_len = server.succeed( + "psql -U supabase_admin -d postgres -t -A -c \"SELECT orioledb_get_rewind_evicted_length();\"" + ).strip() + print(f"Initial rewind queue length: {queue_len}") + print(f"Initial rewind evicted length: {evicted_len}") + + with subtest("Basic rewind"): + # Phase 1: Setup — matches bash script exactly + server.succeed( + "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);\"" + ) + + # Capture xid, oxid, and hash in a single query — matches bash script + ids = server.succeed( + "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;\"" + ).strip() + parts = ids.split("|") + xid = parts[0] + oxid = parts[1] + pre_hash = parts[2] + print(f"Checkpoint: xid={xid} oxid={oxid} hash={pre_hash}") + + # Phase 2: Dirty the state — matches bash script + server.succeed( + "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);\"" + ) + dirty_count = server.succeed( + "psql -U supabase_admin -d postgres -t -A -c \"SELECT count(*) FROM rewind_test;\"" + ).strip() + print(f"Rows before rewind: {dirty_count}") + queue_len = server.succeed( + "psql -U supabase_admin -d postgres -t -A -c \"SELECT orioledb_get_rewind_queue_length();\"" + ).strip() + evicted_len = server.succeed( + "psql -U supabase_admin -d postgres -t -A -c \"SELECT orioledb_get_rewind_evicted_length();\"" + ).strip() + print(f"Queue length: {queue_len}, evicted length: {evicted_len}") + + # Phase 3: Rewind — the function crashes postgres, || true absorbs psql error + print(f"Calling orioledb_rewind_to_transaction({xid}, {oxid})...") + server.succeed( + f"psql -U supabase_admin -d postgres -c \"SELECT orioledb_rewind_to_transaction({xid}, {oxid});\" 2>&1 || true" + ) + + # Phase 4: Wait for server restart (systemd Restart=always brings it back) + print("Waiting for server restart...") + time.sleep(5) + server.succeed( + "until psql -U supabase_admin -d postgres -t -A -c 'SELECT 1' 2>/dev/null; do sleep 1; done" + ) + print("Server is back up") + + # Verify + post_hash = server.succeed( + "psql -U supabase_admin -d postgres -t -A -c \"SELECT md5(string_agg(x::text, '.' ORDER BY x)) FROM rewind_test;\"" + ).strip() + post_count = server.succeed( + "psql -U supabase_admin -d postgres -t -A -c \"SELECT count(*) FROM rewind_test;\"" + ).strip() + print(f"Rows: {post_count} (expect 100)") + print(f"Hash before: {pre_hash}") + print(f"Hash after: {post_hash}") + match = "YES" if pre_hash == post_hash else "NO" + print(f"Match: {match}") + assert post_count == "100", f"Expected 100 rows after rewind, got: {post_count}" + assert pre_hash == post_hash, f"Hash mismatch: {pre_hash} != {post_hash}" + print("Basic rewind test PASSED") + + with subtest("Rewind under buffer pressure"): + # Create a new table for buffer pressure test + server.succeed( + "psql -U supabase_admin -d postgres -c \"DROP TABLE IF EXISTS pressure_test; CREATE TABLE pressure_test(x serial) USING orioledb;\"" + ) + + # Insert data in 50 batches of 100 rows each (5000 rows across 50 transactions) + for batch in range(50): + server.succeed( + "psql -U supabase_admin -d postgres -c \"INSERT INTO pressure_test SELECT FROM generate_series(1, 100);\"" + ) + + # Capture checkpoint state in a single query + cp_ids = server.succeed( + "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;\"" + ).strip() + cp_parts = cp_ids.split("|") + cp_xid = cp_parts[0] + cp_oxid = cp_parts[1] + cp_count = cp_parts[2] + print(f"Buffer pressure checkpoint: xid={cp_xid}, oxid={cp_oxid}, count={cp_count}") + + # Insert 10 more batches after checkpoint + for batch in range(10): + server.succeed( + "psql -U supabase_admin -d postgres -c \"INSERT INTO pressure_test SELECT FROM generate_series(1, 100);\"" + ) + + after_count = server.succeed( + "psql -U supabase_admin -d postgres -t -A -c \"SELECT count(*) FROM pressure_test;\"" + ).strip() + print(f"After additional inserts: count={after_count}") + + # Print queue/evicted lengths to show buffer state + queue_len = server.succeed( + "psql -U supabase_admin -d postgres -t -A -c \"SELECT orioledb_get_rewind_queue_length();\"" + ).strip() + evicted_len = server.succeed( + "psql -U supabase_admin -d postgres -t -A -c \"SELECT orioledb_get_rewind_evicted_length();\"" + ).strip() + print(f"Buffer pressure state - queue length: {queue_len}, evicted length: {evicted_len}") + + # Rewind — function crashes postgres + print(f"Calling orioledb_rewind_to_transaction({cp_xid}, {cp_oxid})...") + server.succeed( + f"psql -U supabase_admin -d postgres -c \"SELECT orioledb_rewind_to_transaction({cp_xid}, {cp_oxid});\" 2>&1 || true" + ) + + # Wait for server restart + time.sleep(5) + server.succeed( + "until psql -U supabase_admin -d postgres -t -A -c 'SELECT 1' 2>/dev/null; do sleep 1; done" + ) + + # Verify rewind restored checkpoint state + post_pressure_count = server.succeed( + "psql -U supabase_admin -d postgres -t -A -c \"SELECT count(*) FROM pressure_test;\"" + ).strip() + print(f"After buffer pressure rewind: count={post_pressure_count} (expect {cp_count})") + assert post_pressure_count == cp_count, ( + f"Expected {cp_count} rows after buffer pressure rewind, got: {post_pressure_count}" + ) + print("Buffer pressure rewind test PASSED") + ''; +} diff --git a/nix/tests/expected/z_orioledb-17_ext_interface.out b/nix/tests/expected/z_orioledb-17_ext_interface.out index 916ddba005..050e81bd66 100644 --- a/nix/tests/expected/z_orioledb-17_ext_interface.out +++ b/nix/tests/expected/z_orioledb-17_ext_interface.out @@ -1121,6 +1121,7 @@ order by orioledb | extensions | orioledb_version | | text orioledb | extensions | orioledb_write_pages | relid oid | void orioledb | extensions | pg_stopevent_reset | eventname text | boolean + orioledb | extensions | pg_stopevent_set | eventname text, condition jsonpath, flags text | void orioledb | extensions | pg_stopevent_set | eventname text, condition jsonpath | void orioledb | extensions | pg_stopevents | OUT stopevent text, OUT condition jsonpath, OUT waiter_pids integer[] | SETOF record pageinspect | public | brin_metapage_info | page bytea, OUT magic text, OUT version integer, OUT pagesperrange integer, OUT lastrevmappage bigint | record @@ -4987,7 +4988,7 @@ order by xml2 | public | xpath_table | text, text, text, text, text | SETOF record xml2 | public | xslt_process | text, text | text xml2 | public | xslt_process | text, text, text | text -(4827 rows) +(4828 rows) /* diff --git a/nix/tools/run-server.sh.in b/nix/tools/run-server.sh.in index ea66b6f29f..333f062bc7 100644 --- a/nix/tools/run-server.sh.in +++ b/nix/tools/run-server.sh.in @@ -256,11 +256,6 @@ orioledb_config_items() { sed -i 's/ timescaledb,//g; s/ plv8,//g; s/ pgjwt,//g;' "$DATDIR/supautils.conf" sed -i 's/\(shared_preload_libraries.*\)'\''\(.*\)$/\1, orioledb'\''\2/' "$DATDIR/postgresql.conf" echo "default_table_access_method = 'orioledb'" >> "$DATDIR/postgresql.conf" - # OrioleDB rewind configuration (20 minute window, 10MB buffer) - echo "orioledb.enable_rewind = true" >> "$DATDIR/postgresql.conf" - echo "orioledb.rewind_max_time = 1200" >> "$DATDIR/postgresql.conf" - echo "orioledb.rewind_max_transactions = 100000" >> "$DATDIR/postgresql.conf" - echo "orioledb.rewind_buffers = 1280" >> "$DATDIR/postgresql.conf" elif [[ "$1" = "orioledb-17" && "$CURRENT_SYSTEM" = "aarch64-darwin" ]]; then # macOS specific configuration echo "macOS detected, applying macOS specific configuration" @@ -276,11 +271,6 @@ orioledb_config_items() { perl -pi -e 's/(shared_preload_libraries\s*=\s*'\''.*?)'\''/\1, orioledb'\''/' "$DATDIR/postgresql.conf" echo "default_table_access_method = 'orioledb'" >> "$DATDIR/postgresql.conf" - # OrioleDB rewind configuration (20 minute window, 10MB buffer) - echo "orioledb.enable_rewind = true" >> "$DATDIR/postgresql.conf" - echo "orioledb.rewind_max_time = 1200" >> "$DATDIR/postgresql.conf" - echo "orioledb.rewind_max_transactions = 100000" >> "$DATDIR/postgresql.conf" - echo "orioledb.rewind_buffers = 1280" >> "$DATDIR/postgresql.conf" elif [[ "$VERSION" == "17" && "$CURRENT_SYSTEM" != "aarch64-darwin" ]]; then echo "non-macos pg 17 conf" sed -i 's/ timescaledb,//g;' "$DATDIR/postgresql.conf"