Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions src/backend/access/gin/gininsert.c
Original file line number Diff line number Diff line change
Expand Up @@ -421,8 +421,10 @@ ginbuild(Relation heap, Relation index, IndexInfo *indexInfo)
log_newpage_range(index, MAIN_FORKNUM,
0, RelationGetNumberOfBlocks(index),
true);
SetLastWrittenLSNForBlockRange(XactLastRecEnd, index->rd_smgr->smgr_rlocator.locator, MAIN_FORKNUM, 0, RelationGetNumberOfBlocks(index));
SetLastWrittenLSNForRelation(XactLastRecEnd, index->rd_smgr->smgr_rlocator.locator, MAIN_FORKNUM);
if (set_lwlsn_block_range_hook)
set_lwlsn_block_range_hook(XactLastRecEnd, index->rd_smgr->smgr_rlocator.locator, MAIN_FORKNUM, 0, RelationGetNumberOfBlocks(index));
if (set_lwlsn_relation_hook)
set_lwlsn_relation_hook(XactLastRecEnd, index->rd_smgr->smgr_rlocator.locator, MAIN_FORKNUM);
}

smgr_end_unlogged_build(index->rd_smgr);
Expand Down
18 changes: 11 additions & 7 deletions src/backend/access/gist/gistbuild.c
Original file line number Diff line number Diff line change
Expand Up @@ -343,10 +343,12 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo)
log_newpage_range(index, MAIN_FORKNUM,
0, RelationGetNumberOfBlocks(index),
true);
SetLastWrittenLSNForBlockRange(XactLastRecEnd,
index->rd_smgr->smgr_rlocator.locator,
MAIN_FORKNUM, 0, RelationGetNumberOfBlocks(index));
SetLastWrittenLSNForRelation(XactLastRecEnd, index->rd_smgr->smgr_rlocator.locator, MAIN_FORKNUM);
if (set_lwlsn_block_range_hook)
set_lwlsn_block_range_hook(XactLastRecEnd,
index->rd_smgr->smgr_rlocator.locator,
MAIN_FORKNUM, 0, RelationGetNumberOfBlocks(index));
if (set_lwlsn_relation_hook)
set_lwlsn_relation_hook(XactLastRecEnd, index->rd_smgr->smgr_rlocator.locator, MAIN_FORKNUM);
}

smgr_end_unlogged_build(index->rd_smgr);
Expand Down Expand Up @@ -480,9 +482,11 @@ gist_indexsortbuild(GISTBuildState *state)
lsn = log_newpage(&state->indexrel->rd_locator, MAIN_FORKNUM, GIST_ROOT_BLKNO,
levelstate->pages[0], true);

SetLastWrittenLSNForBlock(lsn, state->indexrel->rd_smgr->smgr_rlocator.locator,
MAIN_FORKNUM, GIST_ROOT_BLKNO);
SetLastWrittenLSNForRelation(lsn, state->indexrel->rd_smgr->smgr_rlocator.locator, MAIN_FORKNUM);
if (set_lwlsn_block_hook)
set_lwlsn_block_hook(lsn, state->indexrel->rd_smgr->smgr_rlocator.locator,
MAIN_FORKNUM, GIST_ROOT_BLKNO);
if (set_lwlsn_relation_hook)
set_lwlsn_relation_hook(lsn, state->indexrel->rd_smgr->smgr_rlocator.locator, MAIN_FORKNUM);
}

pfree(levelstate->pages[0]);
Expand Down
8 changes: 5 additions & 3 deletions src/backend/access/spgist/spginsert.c
Original file line number Diff line number Diff line change
Expand Up @@ -144,9 +144,11 @@ spgbuild(Relation heap, Relation index, IndexInfo *indexInfo)
log_newpage_range(index, MAIN_FORKNUM,
0, RelationGetNumberOfBlocks(index),
true);
SetLastWrittenLSNForBlockRange(XactLastRecEnd, index->rd_smgr->smgr_rlocator.locator,
MAIN_FORKNUM, 0, RelationGetNumberOfBlocks(index));
SetLastWrittenLSNForRelation(XactLastRecEnd, index->rd_smgr->smgr_rlocator.locator, MAIN_FORKNUM);
if (set_lwlsn_block_range_hook)
set_lwlsn_block_range_hook(XactLastRecEnd, index->rd_smgr->smgr_rlocator.locator,
MAIN_FORKNUM, 0, RelationGetNumberOfBlocks(index));
if (set_lwlsn_relation_hook)
set_lwlsn_relation_hook(XactLastRecEnd, index->rd_smgr->smgr_rlocator.locator, MAIN_FORKNUM);
}

smgr_end_unlogged_build(index->rd_smgr);
Expand Down
227 changes: 14 additions & 213 deletions src/backend/access/transam/xlog.c
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,6 @@ int max_slot_wal_keep_size_mb = -1;
int wal_decode_buffer_size = 512 * 1024;
bool track_wal_io_timing = false;
uint64 predefined_sysidentifier;
int lastWrittenLsnCacheSize;

#ifdef WAL_DEBUG
bool XLOG_DEBUG = false;
Expand All @@ -152,6 +151,14 @@ int wal_segment_size = DEFAULT_XLOG_SEG_SIZE;
/* NEON: Hook to allow the neon extension to restore running-xacts from CLOG at replica startup */
restore_running_xacts_callback_t restore_running_xacts_callback;

/* NEON: Hook Definitions that enabled the moving of LastWrittenLSN Cache to the neon extension*/
set_lwlsn_block_hook_type set_lwlsn_block_hook = NULL;
set_lwlsn_block_range_hook_type set_lwlsn_block_range_hook = NULL;
set_lwlsn_block_v_hook_type set_lwlsn_block_v_hook = NULL;
set_lwlsn_db_hook_type set_lwlsn_db_hook = NULL;
set_lwlsn_relation_hook_type set_lwlsn_relation_hook = NULL;
set_max_lwlsn_hook_type set_max_lwlsn_hook = NULL;

/*
* Number of WAL insertion locks to use. A higher value allows more insertions
* to happen concurrently, but adds some CPU overhead to flushing the WAL,
Expand Down Expand Up @@ -211,24 +218,6 @@ const struct config_enum_entry archive_mode_options[] = {
{NULL, 0, false}
};

typedef struct LastWrittenLsnCacheEntry
{
BufferTag key;
XLogRecPtr lsn;
/* double linked list for LRU replacement algorithm */
dlist_node lru_node;
} LastWrittenLsnCacheEntry;


/*
* Cache of last written LSN for each relation page.
* Also to provide request LSN for smgrnblocks, smgrexists there is pseudokey=InvalidBlockId which stores LSN of last
* relation metadata update.
* Size of the cache is limited by GUC variable lastWrittenLsnCacheSize ("lsn_cache_size"),
* pages are replaced using LRU algorithm, based on L2-list.
* Access to this cache is protected by 'LastWrittenLsnLock'.
*/
static HTAB *lastWrittenLsnCache;

/*
* Statistics for current checkpoint are collected in this global struct.
Expand Down Expand Up @@ -582,17 +571,6 @@ typedef struct XLogCtlData
*/
XLogRecPtr lastFpwDisableRecPtr;

/*
* Maximal last written LSN for pages not present in lastWrittenLsnCache
*/
XLogRecPtr maxLastWrittenLsn;

/*
* Double linked list to implement LRU replacement policy for last written LSN cache.
* Access to this list as well as to last written LSN cache is protected by 'LastWrittenLsnLock'.
*/
dlist_head lastWrittenLsnLRU;

/* neon: copy of startup's RedoStartLSN for walproposer's use */
XLogRecPtr RedoStartLSN;

Expand Down Expand Up @@ -4539,8 +4517,8 @@ GetActiveWalLevelOnStandby(void)
return ControlFile->wal_level;
}

static Size
XLOGCtlShmemSize(void)
Size
XLOGShmemSize(void)
{
Size size;

Expand Down Expand Up @@ -4589,16 +4567,6 @@ XLOGCtlShmemSize(void)
return size;
}

/*
* Initialization of shared memory for XLOG
*/
Size
XLOGShmemSize(void)
{
return XLOGCtlShmemSize() +
hash_estimate_size(lastWrittenLsnCacheSize, sizeof(LastWrittenLsnCacheEntry));
}

void
XLOGShmemInit(void)
{
Expand Down Expand Up @@ -4626,18 +4594,7 @@ XLOGShmemInit(void)


XLogCtl = (XLogCtlData *)
ShmemInitStruct("XLOG Ctl", XLOGCtlShmemSize(), &foundXLog);

if (lastWrittenLsnCacheSize > 0)
{
static HASHCTL info;
info.keysize = sizeof(BufferTag);
info.entrysize = sizeof(LastWrittenLsnCacheEntry);
lastWrittenLsnCache = ShmemInitHash("last_written_lsn_cache",
lastWrittenLsnCacheSize, lastWrittenLsnCacheSize,
&info,
HASH_ELEM | HASH_BLOBS);
}
ShmemInitStruct("XLOG Ctl", XLOGShmemSize(), &foundXLog);

localControlFile = ControlFile;
ControlFile = (ControlFileData *)
Expand Down Expand Up @@ -5453,13 +5410,9 @@ StartupXLOG(void)
RedoRecPtr = XLogCtl->RedoRecPtr = XLogCtl->Insert.RedoRecPtr = checkPoint.redo;
doPageWrites = lastFullPageWrites;

/*
* Setup last written lsn cache, max written LSN.
* Starting from here, we could be modifying pages through REDO, which requires
* the existance of maxLwLsn + LwLsn LRU.
*/
XLogCtl->maxLastWrittenLsn = RedoRecPtr;
dlist_init(&XLogCtl->lastWrittenLsnLRU);
if (set_max_lwlsn_hook)
set_max_lwlsn_hook(RedoRecPtr);


/* REDO */
if (InRecovery)
Expand Down Expand Up @@ -6298,158 +6251,6 @@ GetInsertRecPtr(void)
return recptr;
}

/*
* GetLastWrittenLSN -- Returns maximal LSN of written page.
* It returns an upper bound for the last written LSN of a given page,
* either from a cached last written LSN or a global maximum last written LSN.
* If rnode is InvalidOid then we calculate maximum among all cached LSN and maxLastWrittenLsn.
* If cache is large enough, iterating through all hash items may be rather expensive.
* But GetLastWrittenLSN(InvalidOid) is used only by zenith_dbsize which is not performance critical.
*/
XLogRecPtr
GetLastWrittenLSN(RelFileLocator rlocator, ForkNumber forknum, BlockNumber blkno)
{
XLogRecPtr lsn;
LastWrittenLsnCacheEntry* entry;

Assert(lastWrittenLsnCacheSize != 0);

LWLockAcquire(LastWrittenLsnLock, LW_SHARED);

/* Maximal last written LSN among all non-cached pages */
lsn = XLogCtl->maxLastWrittenLsn;

if (rlocator.relNumber != InvalidOid)
{
BufferTag key;
key.spcOid = rlocator.spcOid;
key.dbOid = rlocator.dbOid;
key.relNumber = rlocator.relNumber;
key.forkNum = forknum;
key.blockNum = blkno;
entry = hash_search(lastWrittenLsnCache, &key, HASH_FIND, NULL);
if (entry != NULL)
lsn = entry->lsn;
else
{
LWLockRelease(LastWrittenLsnLock);
return SetLastWrittenLSNForBlock(lsn, rlocator, forknum, blkno);
}
}
else
{
HASH_SEQ_STATUS seq;
/* Find maximum of all cached LSNs */
hash_seq_init(&seq, lastWrittenLsnCache);
while ((entry = (LastWrittenLsnCacheEntry *) hash_seq_search(&seq)) != NULL)
{
if (entry->lsn > lsn)
lsn = entry->lsn;
}
}
LWLockRelease(LastWrittenLsnLock);

return lsn;
}

/*
* SetLastWrittenLSNForBlockRange -- Set maximal LSN of written page range.
* We maintain cache of last written LSNs with limited size and LRU replacement
* policy. Keeping last written LSN for each page allows to use old LSN when
* requesting pages of unchanged or appended relations. Also it is critical for
* efficient work of prefetch in case massive update operations (like vacuum or remove).
*
* rlocator.relNumber can be InvalidOid, in this case maxLastWrittenLsn is updated.
* SetLastWrittenLsn with dummy rlocator is used by createdb and dbase_redo functions.
*/
XLogRecPtr
SetLastWrittenLSNForBlockRange(XLogRecPtr lsn, RelFileLocator rlocator, ForkNumber forknum, BlockNumber from, BlockNumber n_blocks)
{
if (lsn == InvalidXLogRecPtr || n_blocks == 0 || lastWrittenLsnCacheSize == 0)
return lsn;

LWLockAcquire(LastWrittenLsnLock, LW_EXCLUSIVE);
if (rlocator.relNumber == InvalidOid)
{
if (lsn > XLogCtl->maxLastWrittenLsn)
XLogCtl->maxLastWrittenLsn = lsn;
else
lsn = XLogCtl->maxLastWrittenLsn;
}
else
{
LastWrittenLsnCacheEntry* entry;
BufferTag key;
bool found;
BlockNumber i;

key.spcOid = rlocator.spcOid;
key.dbOid = rlocator.dbOid;
key.relNumber = rlocator.relNumber;
key.forkNum = forknum;
for (i = 0; i < n_blocks; i++)
{
key.blockNum = from + i;
entry = hash_search(lastWrittenLsnCache, &key, HASH_ENTER, &found);
if (found)
{
if (lsn > entry->lsn)
entry->lsn = lsn;
else
lsn = entry->lsn;
/* Unlink from LRU list */
dlist_delete(&entry->lru_node);
}
else
{
entry->lsn = lsn;
if (hash_get_num_entries(lastWrittenLsnCache) > lastWrittenLsnCacheSize)
{
/* Replace least recently used entry */
LastWrittenLsnCacheEntry* victim = dlist_container(LastWrittenLsnCacheEntry, lru_node, dlist_pop_head_node(&XLogCtl->lastWrittenLsnLRU));
/* Adjust max LSN for not cached relations/chunks if needed */
if (victim->lsn > XLogCtl->maxLastWrittenLsn)
XLogCtl->maxLastWrittenLsn = victim->lsn;

hash_search(lastWrittenLsnCache, victim, HASH_REMOVE, NULL);
}
}
/* Link to the end of LRU list */
dlist_push_tail(&XLogCtl->lastWrittenLsnLRU, &entry->lru_node);
}
}
LWLockRelease(LastWrittenLsnLock);
return lsn;
}

/*
* SetLastWrittenLSNForBlock -- Set maximal LSN for block
*/
XLogRecPtr
SetLastWrittenLSNForBlock(XLogRecPtr lsn, RelFileLocator rlocator, ForkNumber forknum, BlockNumber blkno)
{
return SetLastWrittenLSNForBlockRange(lsn, rlocator, forknum, blkno, 1);
}

/*
* SetLastWrittenLSNForRelation -- Set maximal LSN for relation metadata
*/
XLogRecPtr
SetLastWrittenLSNForRelation(XLogRecPtr lsn, RelFileLocator rlocator, ForkNumber forknum)
{
return SetLastWrittenLSNForBlock(lsn, rlocator, forknum, REL_METADATA_PSEUDO_BLOCKNO);
}

/*
* SetLastWrittenLSNForDatabase -- Set maximal LSN for the whole database
*/
XLogRecPtr
SetLastWrittenLSNForDatabase(XLogRecPtr lsn)
{
RelFileLocator dummyNode = {InvalidOid, InvalidOid, InvalidOid};
return SetLastWrittenLSNForBlock(lsn, dummyNode, MAIN_FORKNUM, 0);
}

void
SetRedoStartLsn(XLogRecPtr RedoStartLSN)
{
Expand Down
3 changes: 2 additions & 1 deletion src/backend/catalog/storage.c
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,8 @@ log_smgrcreate(const RelFileLocator *rlocator, ForkNumber forkNum)
XLogBeginInsert();
XLogRegisterData((char *) &xlrec, sizeof(xlrec));
lsn = XLogInsert(RM_SMGR_ID, XLOG_SMGR_CREATE | XLR_SPECIAL_REL_UPDATE);
SetLastWrittenLSNForRelation(lsn, *rlocator, forkNum);
if (set_lwlsn_relation_hook)
set_lwlsn_relation_hook(lsn, *rlocator, forkNum);
}

/*
Expand Down
Loading