=== Applying patches on top of PostgreSQL commit ID fe7ede45f125af271fb3fef3cc5ee507d4c40d87 === /etc/rc.d/jail: WARNING: Per-jail configuration via jail_* variables is obsolete. Please consider migrating to /etc/jail.conf. Mon Dec 15 00:31:21 UTC 2025 On branch cf/6101 nothing to commit, working tree clean === using 'git am' to apply patch ./v2-0001-prepare-bufmgr-for-simd.patch === Applying: prepare bufmgr for simd Using index info to reconstruct a base tree... M src/backend/storage/buffer/bufmgr.c Falling back to patching base and 3-way merge... Auto-merging src/backend/storage/buffer/bufmgr.c CONFLICT (content): Merge conflict in src/backend/storage/buffer/bufmgr.c error: Failed to merge in the changes. hint: Use 'git am --show-current-patch=diff' to see the failed patch Patch failed at 0001 prepare bufmgr for simd When you have resolved this problem, run "git am --continue". If you prefer to skip this patch, run "git am --skip" instead. To restore the original branch and stop patching, run "git am --abort". Unstaged changes after reset: M src/backend/storage/buffer/bufmgr.c === using patch(1) to apply patch ./v2-0001-prepare-bufmgr-for-simd.patch === patching file src/backend/storage/buffer/bufmgr.c Hunk #1 FAILED at 213. Hunk #2 FAILED at 267. Hunk #3 FAILED at 296. Hunk #4 FAILED at 312. Hunk #5 FAILED at 335. Hunk #6 FAILED at 351. Hunk #7 FAILED at 360. Hunk #8 FAILED at 404. Hunk #9 FAILED at 460. Hunk #10 FAILED at 3993. 10 out of 10 hunks FAILED -- saving rejects to file src/backend/storage/buffer/bufmgr.c.rej Removing src/backend/storage/buffer/bufmgr.c.rej === using 'git apply' to apply patch ./v2-0001-prepare-bufmgr-for-simd.patch === Applied patch to 'src/backend/storage/buffer/bufmgr.c' with conflicts. U src/backend/storage/buffer/bufmgr.c diff --cc src/backend/storage/buffer/bufmgr.c index a768fb129ae,14222516237..00000000000 --- a/src/backend/storage/buffer/bufmgr.c +++ b/src/backend/storage/buffer/bufmgr.c @@@ -235,13 -212,13 +235,19 @@@ static BufferDesc *PinCountWaitBuf = NU * memory allocations in NewPrivateRefCountEntry() which can be important * because in some scenarios it's called with a spinlock held... */ +static Buffer PrivateRefCountArrayKeys[REFCOUNT_ARRAY_ENTRIES]; static struct PrivateRefCountEntry PrivateRefCountArray[REFCOUNT_ARRAY_ENTRIES]; + static Buffer PrivateRefCountArrayBuffers[REFCOUNT_ARRAY_ENTRIES]; static HTAB *PrivateRefCountHash = NULL; static int32 PrivateRefCountOverflowed = 0; static uint32 PrivateRefCountClock = 0; ++<<<<<<< ours +static int ReservedRefCountSlot = -1; +static int PrivateRefCountEntryLast = -1; ++======= + static PrivateRefCountEntry *ReservedRefCountEntry = NULL; + static int ReservedRefCountEntryIdx; ++>>>>>>> theirs static uint32 MaxProportionalPins; @@@ -292,23 -269,15 +298,29 @@@ ReservePrivateRefCountEntry(void * majority of cases. */ { - int i; - - for (i = 0; i < REFCOUNT_ARRAY_ENTRIES; i++) + for (int i = 0; i < REFCOUNT_ARRAY_ENTRIES; i++) { ++<<<<<<< ours + if (PrivateRefCountArrayKeys[i] == InvalidBuffer) + { + ReservedRefCountSlot = i; + + /* + * We could return immediately, but iterating till the end of + * the array allows compiler-autovectorization. + */ ++======= + if (PrivateRefCountArrayBuffers[i] == InvalidBuffer) + { + ReservedRefCountEntry = &PrivateRefCountArray[i]; + ReservedRefCountEntryIdx = i; + return; ++>>>>>>> theirs } } + + if (ReservedRefCountSlot != -1) + return; } /* @@@ -326,14 -293,11 +338,19 @@@ bool found; /* select victim slot */ ++<<<<<<< ours + victim_slot = PrivateRefCountClock++ % REFCOUNT_ARRAY_ENTRIES; + victim_entry = &PrivateRefCountArray[victim_slot]; + ReservedRefCountSlot = victim_slot; ++======= + ReservedRefCountEntryIdx = PrivateRefCountClock++ % REFCOUNT_ARRAY_ENTRIES; + ReservedRefCountEntry = &PrivateRefCountArray[ReservedRefCountEntryIdx]; ++>>>>>>> theirs /* Better be used, otherwise we shouldn't get here. */ - Assert(ReservedRefCountEntry->buffer != InvalidBuffer); + Assert(PrivateRefCountArrayKeys[victim_slot] != InvalidBuffer); + Assert(PrivateRefCountArray[victim_slot].buffer != InvalidBuffer); + Assert(PrivateRefCountArrayKeys[victim_slot] == PrivateRefCountArray[victim_slot].buffer); /* enter victim array entry into hashtable */ hashent = hash_search(PrivateRefCountHash, @@@ -341,16 -305,12 +358,22 @@@ HASH_ENTER, &found); Assert(!found); - hashent->refcount = ReservedRefCountEntry->refcount; + /* move data from the entry in the array to the hash entry */ + hashent->data = victim_entry->data; /* clear the now free array slot */ ++<<<<<<< ours + PrivateRefCountArrayKeys[victim_slot] = InvalidBuffer; + victim_entry->buffer = InvalidBuffer; + + /* clear the whole data member, just for future proofing */ + memset(&victim_entry->data, 0, sizeof(victim_entry->data)); + victim_entry->data.refcount = 0; ++======= + ReservedRefCountEntry->buffer = InvalidBuffer; + PrivateRefCountArrayBuffers[ReservedRefCountEntryIdx] = InvalidBuffer; + ReservedRefCountEntry->refcount = 0; ++>>>>>>> theirs PrivateRefCountOverflowed++; } @@@ -365,56 -325,43 +388,69 @@@ NewPrivateRefCountEntry(Buffer buffer PrivateRefCountEntry *res; /* only allowed to be called when a reservation has been made */ - Assert(ReservedRefCountEntry != NULL); + Assert(ReservedRefCountSlot != -1); /* use up the reserved entry */ - res = ReservedRefCountEntry; - ReservedRefCountEntry = NULL; + res = &PrivateRefCountArray[ReservedRefCountSlot]; /* and fill it */ + PrivateRefCountArrayKeys[ReservedRefCountSlot] = buffer; res->buffer = buffer; ++<<<<<<< ours + res->data.refcount = 0; + + /* update cache for the next lookup */ + PrivateRefCountEntryLast = ReservedRefCountSlot; + + ReservedRefCountSlot = -1; ++======= + PrivateRefCountArrayBuffers[ReservedRefCountEntryIdx] = buffer; + res->refcount = 0; ++>>>>>>> theirs return res; } /* - * Return the PrivateRefCount entry for the passed buffer. - * - * Returns NULL if a buffer doesn't have a refcount entry. Otherwise, if - * do_move is true, and the entry resides in the hashtable the entry is - * optimized for frequent access by moving it to the array. + * Slow-path for GetPrivateRefCountEntry(). This is big enough to not be worth + * inlining. This particularly seems to be true if the compiler is capable of + * auto-vectorizing the code, as that imposes additional stack-alignment + * requirements etc. */ -static PrivateRefCountEntry * -GetPrivateRefCountEntry(Buffer buffer, bool do_move) +static pg_noinline PrivateRefCountEntry * +GetPrivateRefCountEntrySlow(Buffer buffer, bool do_move) { PrivateRefCountEntry *res; - - Assert(BufferIsValid(buffer)); - Assert(!BufferIsLocal(buffer)); ++<<<<<<< ours + int match = -1; + int i; ++======= ++>>>>>>> theirs /* * First search for references in the array, that'll be sufficient in the * majority of cases. */ - for (i = 0; i < REFCOUNT_ARRAY_ENTRIES; i++) + for (int i = 0; i < REFCOUNT_ARRAY_ENTRIES; i++) { ++<<<<<<< ours + if (PrivateRefCountArrayKeys[i] == buffer) + { + match = i; + /* see ReservePrivateRefCountEntry() for why we don't return */ + } + } + + if (likely(match != -1)) + { + /* update cache for the next lookup */ + PrivateRefCountEntryLast = match; + + return &PrivateRefCountArray[match]; ++======= + if (PrivateRefCountArrayBuffers[i] == buffer) + return &PrivateRefCountArray[i]; ++>>>>>>> theirs } /* @@@ -453,13 -400,8 +489,18 @@@ /* and fill it */ free->buffer = buffer; ++<<<<<<< ours + free->data = res->data; + PrivateRefCountArrayKeys[ReservedRefCountSlot] = buffer; + /* update cache for the next lookup */ + PrivateRefCountEntryLast = match; + + ReservedRefCountSlot = -1; + ++======= + PrivateRefCountArrayBuffers[ReservedRefCountEntryIdx] = buffer; + free->refcount = res->refcount; ++>>>>>>> theirs /* delete from hashtable */ hash_search(PrivateRefCountHash, &buffer, HASH_REMOVE, &found); @@@ -553,7 -456,10 +594,14 @@@ ForgetPrivateRefCountEntry(PrivateRefCo * allows us to avoid ever having to search the array/hash for free * entries. */ ++<<<<<<< ours + ReservedRefCountSlot = ref - PrivateRefCountArray; ++======= + ReservedRefCountEntry = ref; + + ReservedRefCountEntryIdx = ref - &PrivateRefCountArray[0]; + PrivateRefCountArrayBuffers[ReservedRefCountEntryIdx] = InvalidBuffer; ++>>>>>>> theirs } else { @@@ -4112,9 -3993,9 +4160,13 @@@ InitBufferManagerAccess(void MaxProportionalPins = NBuffers / (MaxBackends + NUM_AUXILIARY_PROCS); memset(&PrivateRefCountArray, 0, sizeof(PrivateRefCountArray)); ++<<<<<<< ours + memset(&PrivateRefCountArrayKeys, 0, sizeof(PrivateRefCountArrayKeys)); ++======= + memset(&PrivateRefCountArrayBuffers, InvalidBuffer, sizeof(PrivateRefCountArrayBuffers)); ++>>>>>>> theirs - hash_ctl.keysize = sizeof(int32); + hash_ctl.keysize = sizeof(Buffer); hash_ctl.entrysize = sizeof(PrivateRefCountEntry); PrivateRefCountHash = hash_create("PrivateRefCount", 100, &hash_ctl,