diff --git a/contrib/bloom/blinsert.c b/contrib/bloom/blinsert.c
new file mode 100644
index 330d7fd..4e3fe2f
*** a/contrib/bloom/blinsert.c
--- b/contrib/bloom/blinsert.c
*************** flushCachedPage(Relation index, BloomBui
*** 49,55 ****
GenericXLogState *state;
state = GenericXLogStart(index);
! page = GenericXLogRegister(state, buffer, true);
memcpy(page, buildstate->data, BLCKSZ);
GenericXLogFinish(state);
UnlockReleaseBuffer(buffer);
--- 49,55 ----
GenericXLogState *state;
state = GenericXLogStart(index);
! page = GenericXLogRegisterBuffer(state, buffer, GENERIC_XLOG_FULL_IMAGE);
memcpy(page, buildstate->data, BLCKSZ);
GenericXLogFinish(state);
UnlockReleaseBuffer(buffer);
*************** blinsert(Relation index, Datum *values,
*** 221,227 ****
LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
state = GenericXLogStart(index);
! page = GenericXLogRegister(state, buffer, false);
if (BloomPageAddItem(&blstate, page, itup))
{
--- 221,227 ----
LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
state = GenericXLogStart(index);
! page = GenericXLogRegisterBuffer(state, buffer, 0);
if (BloomPageAddItem(&blstate, page, itup))
{
*************** blinsert(Relation index, Datum *values,
*** 268,274 ****
state = GenericXLogStart(index);
/* get modifiable copy of metapage */
! metaPage = GenericXLogRegister(state, metaBuffer, false);
metaData = BloomPageGetMeta(metaPage);
if (nStart >= metaData->nEnd)
--- 268,274 ----
state = GenericXLogStart(index);
/* get modifiable copy of metapage */
! metaPage = GenericXLogRegisterBuffer(state, metaBuffer, 0);
metaData = BloomPageGetMeta(metaPage);
if (nStart >= metaData->nEnd)
*************** blinsert(Relation index, Datum *values,
*** 279,285 ****
buffer = ReadBuffer(index, blkno);
LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
! page = GenericXLogRegister(state, buffer, false);
if (BloomPageAddItem(&blstate, page, itup))
{
--- 279,285 ----
buffer = ReadBuffer(index, blkno);
LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
! page = GenericXLogRegisterBuffer(state, buffer, 0);
if (BloomPageAddItem(&blstate, page, itup))
{
*************** blinsert(Relation index, Datum *values,
*** 305,311 ****
*/
buffer = BloomNewBuffer(index);
! page = GenericXLogRegister(state, buffer, true);
BloomInitPage(page, 0);
if (!BloomPageAddItem(&blstate, page, itup))
--- 305,311 ----
*/
buffer = BloomNewBuffer(index);
! page = GenericXLogRegisterBuffer(state, buffer, GENERIC_XLOG_FULL_IMAGE);
BloomInitPage(page, 0);
if (!BloomPageAddItem(&blstate, page, itup))
diff --git a/contrib/bloom/blutils.c b/contrib/bloom/blutils.c
new file mode 100644
index 6c7dc1d..a3605f0
*** a/contrib/bloom/blutils.c
--- b/contrib/bloom/blutils.c
*************** BloomInitMetapage(Relation index)
*** 417,423 ****
/* Initialize contents of meta page */
state = GenericXLogStart(index);
! metaPage = GenericXLogRegister(state, metaBuffer, true);
BloomInitPage(metaPage, BLOOM_META);
metadata = BloomPageGetMeta(metaPage);
--- 417,424 ----
/* Initialize contents of meta page */
state = GenericXLogStart(index);
! metaPage = GenericXLogRegisterBuffer(state, metaBuffer,
! GENERIC_XLOG_FULL_IMAGE);
BloomInitPage(metaPage, BLOOM_META);
metadata = BloomPageGetMeta(metaPage);
diff --git a/contrib/bloom/blvacuum.c b/contrib/bloom/blvacuum.c
new file mode 100644
index ee40ebb..7467afb
*** a/contrib/bloom/blvacuum.c
--- b/contrib/bloom/blvacuum.c
*************** blbulkdelete(IndexVacuumInfo *info, Inde
*** 65,71 ****
LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
gxlogState = GenericXLogStart(index);
! page = GenericXLogRegister(gxlogState, buffer, false);
if (BloomPageIsDeleted(page))
{
--- 65,71 ----
LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
gxlogState = GenericXLogStart(index);
! page = GenericXLogRegisterBuffer(gxlogState, buffer, 0);
if (BloomPageIsDeleted(page))
{
*************** blbulkdelete(IndexVacuumInfo *info, Inde
*** 145,151 ****
LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
gxlogState = GenericXLogStart(index);
! page = GenericXLogRegister(gxlogState, buffer, false);
metaData = BloomPageGetMeta(page);
memcpy(metaData->notFullPage, notFullPage, sizeof(BlockNumber) * countPage);
--- 145,151 ----
LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
gxlogState = GenericXLogStart(index);
! page = GenericXLogRegisterBuffer(gxlogState, buffer, 0);
metaData = BloomPageGetMeta(page);
memcpy(metaData->notFullPage, notFullPage, sizeof(BlockNumber) * countPage);
diff --git a/doc/src/sgml/generic-wal.sgml b/doc/src/sgml/generic-wal.sgml
new file mode 100644
index 2398d86..b644bfb
*** a/doc/src/sgml/generic-wal.sgml
--- b/doc/src/sgml/generic-wal.sgml
***************
*** 31,45 ****
! page = GenericXLogRegister(state, buffer, isNew)> —
! register a buffer to be modified within the current generic WAL
record. This function returns a pointer to a temporary copy of the
buffer's page, where modifications should be made. (Do not modify the
! buffer's contents directly.) The third argument indicates if the page
! is new; if true, this will result in a full-page image rather than a
! delta update being included in the WAL record.
! GenericXLogRegister> can be repeated if the WAL-logged
! action needs to modify multiple pages.
--- 31,46 ----
! page = GenericXLogRegisterBuffer(state, buffer, flags)>
! — register a buffer to be modified within the current generic WAL
record. This function returns a pointer to a temporary copy of the
buffer's page, where modifications should be made. (Do not modify the
! buffer's contents directly.) The third argument contains set of flags
! indicating how buffer should be logged. When
! GENERIC_XLOG_FULL_IMAGE> is set then a full-page image rather
! than a delta update being included in the WAL record. There could appear
! more flags in future. GenericXLogRegisterBuffer> can be
! repeated if the WAL-logged action needs to modify multiple pages.
***************
*** 71,83 ****
! No direct modifications of buffers are allowed! All modifications
! must be done in copies acquired from GenericXLogRegister()>.
In other words, code that makes generic WAL records should never call
BufferGetPage()> for itself. However, it remains the
caller's responsibility to pin/unpin and lock/unlock the buffers at
appropriate times. Exclusive lock must be held on each target buffer
! from before GenericXLogRegister()> until after
GenericXLogFinish()>.
--- 72,84 ----
! No direct modifications of buffers are allowed! All modifications must
! be done in copies acquired from GenericXLogRegisterBuffer()>.
In other words, code that makes generic WAL records should never call
BufferGetPage()> for itself. However, it remains the
caller's responsibility to pin/unpin and lock/unlock the buffers at
appropriate times. Exclusive lock must be held on each target buffer
! from before GenericXLogRegisterBuffer()> until after
GenericXLogFinish()>.
diff --git a/src/backend/access/transam/generic_xlog.c b/src/backend/access/transam/generic_xlog.c
new file mode 100644
index 072838a..d2fc910
*** a/src/backend/access/transam/generic_xlog.c
--- b/src/backend/access/transam/generic_xlog.c
***************
*** 50,56 ****
typedef struct
{
Buffer buffer; /* registered buffer */
! bool fullImage; /* are we taking a full image of this page? */
int deltaLen; /* space consumed in delta field */
char image[BLCKSZ]; /* copy of page image for modification */
char delta[MAX_DELTA_SIZE]; /* delta between page images */
--- 50,56 ----
typedef struct
{
Buffer buffer; /* registered buffer */
! uint32 flags; /* buffer flags */
int deltaLen; /* space consumed in delta field */
char image[BLCKSZ]; /* copy of page image for modification */
char delta[MAX_DELTA_SIZE]; /* delta between page images */
*************** GenericXLogStart(Relation relation)
*** 282,288 ****
* If the buffer is already registered, just return its existing entry.
*/
Page
! GenericXLogRegister(GenericXLogState *state, Buffer buffer, bool isNew)
{
int block_id;
--- 282,288 ----
* If the buffer is already registered, just return its existing entry.
*/
Page
! GenericXLogRegisterBuffer(GenericXLogState *state, Buffer buffer, uint16 flags)
{
int block_id;
*************** GenericXLogRegister(GenericXLogState *st
*** 295,301 ****
{
/* Empty slot, so use it (there cannot be a match later) */
page->buffer = buffer;
! page->fullImage = isNew;
memcpy(page->image,
BufferGetPage(buffer, NULL, NULL, BGP_NO_SNAPSHOT_TEST),
BLCKSZ);
--- 295,301 ----
{
/* Empty slot, so use it (there cannot be a match later) */
page->buffer = buffer;
! page->flags = flags;
memcpy(page->image,
BufferGetPage(buffer, NULL, NULL, BGP_NO_SNAPSHOT_TEST),
BLCKSZ);
*************** GenericXLogFinish(GenericXLogState *stat
*** 345,351 ****
page = BufferGetPage(pageData->buffer, NULL, NULL,
BGP_NO_SNAPSHOT_TEST);
! if (pageData->fullImage)
{
/* A full page image does not require anything special */
memcpy(page, pageData->image, BLCKSZ);
--- 345,351 ----
page = BufferGetPage(pageData->buffer, NULL, NULL,
BGP_NO_SNAPSHOT_TEST);
! if (pageData->flags & GENERIC_XLOG_FULL_IMAGE)
{
/* A full page image does not require anything special */
memcpy(page, pageData->image, BLCKSZ);
diff --git a/src/include/access/generic_xlog.h b/src/include/access/generic_xlog.h
new file mode 100644
index 01743e3..c422955
*** a/src/include/access/generic_xlog.h
--- b/src/include/access/generic_xlog.h
***************
*** 22,35 ****
#define MAX_GENERIC_XLOG_PAGES XLR_NORMAL_MAX_BLOCK_ID
/* state of generic xlog record construction */
struct GenericXLogState;
typedef struct GenericXLogState GenericXLogState;
/* API for construction of generic xlog records */
extern GenericXLogState *GenericXLogStart(Relation relation);
! extern Page GenericXLogRegister(GenericXLogState *state, Buffer buffer,
! bool isNew);
extern XLogRecPtr GenericXLogFinish(GenericXLogState *state);
extern void GenericXLogAbort(GenericXLogState *state);
--- 22,38 ----
#define MAX_GENERIC_XLOG_PAGES XLR_NORMAL_MAX_BLOCK_ID
+ /* Flags for GenericXLogRegisterBuffer */
+ #define GENERIC_XLOG_FULL_IMAGE 1
+
/* state of generic xlog record construction */
struct GenericXLogState;
typedef struct GenericXLogState GenericXLogState;
/* API for construction of generic xlog records */
extern GenericXLogState *GenericXLogStart(Relation relation);
! extern Page GenericXLogRegisterBuffer(GenericXLogState *state, Buffer buffer,
! uint16 flags);
extern XLogRecPtr GenericXLogFinish(GenericXLogState *state);
extern void GenericXLogAbort(GenericXLogState *state);