Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
f571d51
ci: fork automation (upstream sync + OCR AI review)
gburd Sep 11, 2026
4678ff7
ci: move fork CI logic to gburd/ci-workflows
gburd Sep 11, 2026
b7667c1
Add a cluster-wide UNDO engine with records in the WAL stream
gburd Sep 14, 2026
2e632c0
Add transactional filesystem operations (FILEOPS) backed by UNDO
gburd Sep 14, 2026
ff17a21
Route filesystem mutations through FILEOPS
gburd Sep 14, 2026
f01f9ca
Add per-backend UNDO logs
gburd Sep 27, 2026
97b6513
Add the ATM, sLog, and logical revert worker
gburd Sep 27, 2026
69df3ed
nbtree: mark aborted index inserts dead via UNDO
gburd Sep 19, 2026
73911b2
hash: mark aborted index inserts dead via UNDO
gburd Sep 19, 2026
bf6ca10
nbtree: support in-place delete-marking for stable-TID UPDATE
gburd Sep 19, 2026
d27538d
tableam: let an AM declare that UPDATE keeps a row's TID
gburd Oct 12, 2026
b8625dd
executor: keep the pre-update row of an in-place UPDATE
gburd Oct 12, 2026
3509f06
EvalPlanQual: fetch an in-place AM's reference rows with the query sn…
gburd Oct 12, 2026
68c55bc
AFTER triggers: queue an in-place AM's row images with the event
gburd Oct 12, 2026
53ab3d8
logical replication: pre-check unique keys an in-place UPDATE changes
gburd Oct 12, 2026
be98739
tableam: SO_RETURN_DELETED, and update_deleted detection for any AM
gburd Oct 12, 2026
295fc01
tableam: let a block AM's size estimate use its own default fillfactor
gburd Oct 12, 2026
62d03b9
tableam: let REPACK (CONCURRENTLY) accept any AM whose changes are de…
gburd Oct 11, 2026
92801ac
vacuum: add parallel_vacuum_set_index_stats() and a bulkdel injection…
gburd Oct 10, 2026
46309e5
pg_visibility: refuse tables of other table AMs in the tuple checks
gburd Oct 11, 2026
95c2527
Add the FLUX in-place-MVCC table access method
gburd Sep 14, 2026
9883064
Benchmarks: HEAP vs FLUX
gburd Sep 14, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
18 changes: 18 additions & 0 deletions .github/workflows/fork-ocr-model-check.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Weekly check for a newer Claude Opus on Bedrock; opens/updates one issue here
# when OCR_BEDROCK_MODEL is behind. Notify-only (GITHUB_TOKEN cannot write
# Actions variables). Logic lives in gburd/ci-workflows.

name: OCR model self-check

on:
schedule:
- cron: '0 12 * * 1' # Mondays 12:00 UTC
workflow_dispatch:

jobs:
check:
uses: gburd/ci-workflows/.github/workflows/ocr-model-check.yml@v1
with:
aws_role_arn: ${{ vars.AWS_ROLE_ARN }}
aws_region: ${{ vars.AWS_REGION }}
bedrock_model: ${{ vars.OCR_BEDROCK_MODEL }}
43 changes: 43 additions & 0 deletions .github/workflows/fork-ocr-review.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# AI PR review (Claude Opus on Bedrock). Logic and review rules live in
# gburd/ci-workflows so this fork's master carries a stub instead of ~1000
# lines that have to be rebased onto upstream forever.
#
# Needs repo variables AWS_ROLE_ARN, AWS_REGION, OCR_BEDROCK_MODEL. Auth is
# GitHub OIDC; no static AWS keys. See the ci-workflows README.

name: OCR AI Review

on:
pull_request:
# Note: no draft filter — drafts are reviewed too.
types: [opened, synchronize, reopened, ready_for_review]
issue_comment:
types: [created]
workflow_dispatch:
inputs:
pr_number:
description: 'PR number to review'
required: true
type: number

# One review per PR; cancel superseded runs to save Bedrock spend.
concurrency:
group: ocr-review-${{ github.event.pull_request.number || github.event.issue.number || github.event.inputs.pr_number }}
cancel-in-progress: true

jobs:
review:
# Comment events only when the comment is on a PR and starts with the
# trigger keyword; PR events and manual dispatch always.
if: |
github.event_name == 'pull_request' ||
github.event_name == 'workflow_dispatch' ||
(github.event_name == 'issue_comment' && github.event.issue.pull_request &&
(startsWith(github.event.comment.body, '/open-code-review') ||
startsWith(github.event.comment.body, '@open-code-review') ||
startsWith(github.event.comment.body, '/pg-history')))
uses: gburd/ci-workflows/.github/workflows/ocr-review.yml@v1
with:
aws_role_arn: ${{ vars.AWS_ROLE_ARN }}
aws_region: ${{ vars.AWS_REGION }}
bedrock_model: ${{ vars.OCR_BEDROCK_MODEL }}
48 changes: 48 additions & 0 deletions .github/workflows/fork-sync-upstream.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Keep this fork's master rebased on postgres/postgres master, carrying only
# the fork-owned CI stubs (.github/workflows/fork-*.yml). The workflows they
# call, and the OCR review rules, live in gburd/ci-workflows.
#
# Requires the SYNC_TOKEN secret: a PAT with repo+workflow scope. The default
# GITHUB_TOKEN is not allowed to push commits that touch .github/workflows/,
# and every commit we carry does.

name: Sync from upstream

on:
schedule:
- cron: '17 */3 * * *'
workflow_dispatch:

concurrency:
group: fork-sync-upstream

permissions:
contents: read

jobs:
sync:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
token: ${{ secrets.SYNC_TOKEN }}

- name: Rebase master onto upstream
run: |
set -euo pipefail
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git remote add upstream https://github.com/postgres/postgres.git
git fetch --no-tags upstream master

# Master carries fork CI only. Anything else means work landed here
# that belongs on a branch; force-rebasing it on a timer would be wrong.
if git diff --name-only upstream/master...HEAD |
grep -v '^\.github/workflows/fork-'; then
echo "::error::master carries non-CI changes (listed above); move them to a branch"
exit 1
fi

git rebase upstream/master
git push --force-with-lease
42 changes: 41 additions & 1 deletion contrib/amcheck/verify_nbtree.c
Original file line number Diff line number Diff line change
Expand Up @@ -904,6 +904,16 @@ bt_entry_unique_check(BtreeCheckState *state, IndexTuple itup,

Assert(targetblock != P_NONE);

/*
* A delete-marked tombstone is not a live entry for its key: its row has
* moved to another key, or is moving there. Its heap TID is visible
* under the new key, so checking it here would report a live entry with
* the same key for another row as a duplicate. Skip it without touching
* lVis, so that live entries on either side are still compared.
*/
if (BTreeTupleIsDeleteMarked(itup))
return;

/*
* Current tuple has posting list. Report duplicate if TID of any posting
* list entry is visible and lVis->tid is valid.
Expand Down Expand Up @@ -1475,7 +1485,36 @@ bt_target_page_check(BtreeCheckState *state)
{
IndexTuple norm;

if (BTreeTupleIsPosting(itup))
if (BTreeTupleIsDeleteMarked(itup))
{
/*
* A delete-marked tombstone keeps a row reachable under a key
* it no longer has, for snapshots that still see that key.
* Such a snapshot -- possibly ours, since writers run
* concurrently -- derives exactly this (key, heap TID) from
* the heap, and the tombstone is the only entry that holds
* it. Fingerprint it in plain form: key, with the heap TID
* from the trailer in t_tid, as _bt_truncate demotes it. An
* extra fingerprint cannot cause a false report, since the
* heap is only probed against the index.
*/
TupleDesc itupdesc = RelationGetDescr(state->rel);
Datum vals[INDEX_MAX_KEYS];
bool nulls[INDEX_MAX_KEYS];
IndexTuple plain;

index_deform_tuple(itup, itupdesc, vals, nulls);
plain = index_form_tuple(itupdesc, vals, nulls);
plain->t_tid = *BTreeTupleGetHeapTID(itup);
norm = bt_normalize_tuple(state, plain);
bloom_add_element(state->filter, (unsigned char *) norm,
IndexTupleSize(norm));
/* Be tidy */
if (norm != plain)
pfree(norm);
pfree(plain);
}
else if (BTreeTupleIsPosting(itup))
{
/* Fingerprint all elements as distinct "plain" tuples */
for (int i = 0; i < BTreeTupleGetNPosting(itup); i++)
Expand Down Expand Up @@ -3026,6 +3065,7 @@ bt_rootdescend(BtreeCheckState *state, IndexTuple itup)
insertstate.itemsz = MAXALIGN(IndexTupleSize(itup));
insertstate.itup_key = key;
insertstate.postingoff = 0;
insertstate.nopostingsplit = false;
insertstate.bounds_valid = false;
insertstate.buf = lbuf;

Expand Down
11 changes: 11 additions & 0 deletions contrib/pg_visibility/pg_visibility.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "access/htup_details.h"
#include "access/visibilitymap.h"
#include "access/xloginsert.h"
#include "catalog/pg_am_d.h"
#include "catalog/pg_type.h"
#include "catalog/storage_xlog.h"
#include "funcapi.h"
Expand Down Expand Up @@ -711,6 +712,16 @@ collect_corrupt_items(Oid relid, bool all_visible, bool all_frozen)
/* Only some relkinds have a visibility map */
check_relation_relkind(rel);

/*
* The checks below read each item as a heap tuple. The visibility map
* functions read only the map and the page header, and work for any table
* AM.
*/
if (rel->rd_rel->relam != HEAP_TABLE_AM_OID)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("only heap AM is supported")));

if (all_visible)
OldestXmin = GetStrictOldestNonRemovableTransactionId(rel);

Expand Down
4 changes: 2 additions & 2 deletions contrib/test_decoding/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ PGFILEDESC = "test_decoding - example of a logical decoding output plugin"

REGRESS = ddl xact rewrite toast permissions decoding_in_xact \
decoding_into_rel binary prepared replorigin time messages \
repack spill slot truncate stream stats twophase twophase_stream
repack spill slot truncate stream stats twophase twophase_stream \
flux_outofplace

# slot_creation_error terminates another backend, whose FATAL message can be
# lost on Windows, making the test unstable there.
# See https://postgr.es/m/088AB35D-0860-494A-A9CF-8B301543AA51@yandex-team.ru
SLOT_CREATION_TST = $(if $(filter win32,$(PORTNAME)),,slot_creation_error)

ISOLATION = mxact delayed_startup ondisk_startup concurrent_ddl_dml \
oldest_xmin snapshot_transfer subxact_without_top concurrent_stream \
twophase_snapshot $(SLOT_CREATION_TST) catalog_change_snapshot \
Expand Down
Loading
Loading