diff --git a/src/backend/access/gin/gininsert.c b/src/backend/access/gin/gininsert.c index 4d33e986c40..c1a15dd6b97 100644 --- a/src/backend/access/gin/gininsert.c +++ b/src/backend/access/gin/gininsert.c @@ -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); diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index b60cdbb627e..2288811108f 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -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); @@ -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]); diff --git a/src/backend/access/spgist/spginsert.c b/src/backend/access/spgist/spginsert.c index 7484149cbb7..5b74949fccb 100644 --- a/src/backend/access/spgist/spginsert.c +++ b/src/backend/access/spgist/spginsert.c @@ -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); diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 150534b847f..1053bada0b6 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -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; @@ -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, @@ -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. @@ -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; @@ -4539,8 +4517,8 @@ GetActiveWalLevelOnStandby(void) return ControlFile->wal_level; } -static Size -XLOGCtlShmemSize(void) +Size +XLOGShmemSize(void) { Size size; @@ -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) { @@ -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 *) @@ -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) @@ -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) { diff --git a/src/backend/catalog/storage.c b/src/backend/catalog/storage.c index 9b0e20c60bb..62cfbf53502 100644 --- a/src/backend/catalog/storage.c +++ b/src/backend/catalog/storage.c @@ -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); } /* diff --git a/src/backend/commands/dbcommands.c b/src/backend/commands/dbcommands.c index 12cf85368b4..d7cd2003204 100644 --- a/src/backend/commands/dbcommands.c +++ b/src/backend/commands/dbcommands.c @@ -1464,7 +1464,8 @@ createdb(ParseState *pstate, const CreatedbStmt *stmt) /* * Update global last written LSN after wal-logging create database command */ - SetLastWrittenLSNForDatabase(XactLastRecEnd); + if (set_lwlsn_db_hook) + set_lwlsn_db_hook(XactLastRecEnd); /* * Close pg_database, but keep lock till commit. @@ -2131,7 +2132,8 @@ movedb(const char *dbname, const char *tblspcname) lsn = XLogInsert(RM_DBASE_ID, XLOG_DBASE_CREATE_FILE_COPY | XLR_SPECIAL_REL_UPDATE); // TODO: Do we really need to set the LSN here? - SetLastWrittenLSNForDatabase(lsn); + if (set_lwlsn_db_hook) + set_lwlsn_db_hook(lsn); } /* @@ -3285,10 +3287,8 @@ dbase_redo(XLogReaderState *record) * Make sure any future requests to the page server see the new * database. */ - { - XLogRecPtr lsn = record->EndRecPtr; - SetLastWrittenLSNForDatabase(lsn); - } + if (set_lwlsn_db_hook) + set_lwlsn_db_hook(record->EndRecPtr); pfree(src_path); pfree(dst_path); @@ -3315,10 +3315,8 @@ dbase_redo(XLogReaderState *record) * Make sure any future requests to the page server see the new * database. */ - { - XLogRecPtr lsn = record->EndRecPtr; - SetLastWrittenLSNForDatabase(lsn); - } + if (set_lwlsn_db_hook) + set_lwlsn_db_hook(record->EndRecPtr); pfree(dbpath); } diff --git a/src/backend/utils/misc/guc_tables.c b/src/backend/utils/misc/guc_tables.c index 03c65ea536f..83333d7d26e 100644 --- a/src/backend/utils/misc/guc_tables.c +++ b/src/backend/utils/misc/guc_tables.c @@ -2306,16 +2306,6 @@ struct config_int ConfigureNamesInt[] = NULL, NULL, NULL }, - { - {"lsn_cache_size", PGC_POSTMASTER, UNGROUPED, - gettext_noop("Size of last written LSN cache used by Neon."), - NULL - }, - &lastWrittenLsnCacheSize, - 128*1024, 1024, INT_MAX, - NULL, NULL, NULL - }, - { {"temp_buffers", PGC_USERSET, RESOURCES_MEM, gettext_noop("Sets the maximum number of temporary buffers used by each session."), diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index add1ad6d77c..0e90a3c22d6 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -65,7 +65,6 @@ extern PGDLLIMPORT bool track_wal_io_timing; extern PGDLLIMPORT int wal_decode_buffer_size; extern PGDLLIMPORT int CheckPointSegments; -extern int lastWrittenLsnCacheSize; /* Archive modes */ @@ -262,11 +261,20 @@ extern XLogRecPtr GetLastImportantRecPtr(void); /* neon specifics */ -extern XLogRecPtr SetLastWrittenLSNForBlock(XLogRecPtr lsn, RelFileLocator relfilenode, ForkNumber forknum, BlockNumber blkno); -extern XLogRecPtr SetLastWrittenLSNForBlockRange(XLogRecPtr lsn, RelFileLocator relfilenode, ForkNumber forknum, BlockNumber from, BlockNumber n_blocks); -extern XLogRecPtr SetLastWrittenLSNForDatabase(XLogRecPtr lsn); -extern XLogRecPtr SetLastWrittenLSNForRelation(XLogRecPtr lsn, RelFileLocator relfilenode, ForkNumber forknum); -extern XLogRecPtr GetLastWrittenLSN(RelFileLocator relfilenode, ForkNumber forknum, BlockNumber blkno); +/* Hooks for LwLSN */ +typedef XLogRecPtr (*set_lwlsn_block_hook_type)(XLogRecPtr lsn, RelFileLocator relfilenode, ForkNumber forknum, BlockNumber blkno); +typedef XLogRecPtr (*set_lwlsn_block_range_hook_type)(XLogRecPtr lsn, RelFileLocator relfilenode, ForkNumber forknum, BlockNumber from, BlockNumber n_blocks); +typedef XLogRecPtr (*set_lwlsn_block_v_hook_type)(const XLogRecPtr *lsns, RelFileLocator relfilenode, ForkNumber forknum, BlockNumber blockno, int nblocks); +typedef XLogRecPtr (*set_lwlsn_db_hook_type)(XLogRecPtr lsn); +typedef XLogRecPtr (*set_lwlsn_relation_hook_type)(XLogRecPtr lsn, RelFileLocator relfilenode, ForkNumber forknum); +typedef void (*set_max_lwlsn_hook_type) (XLogRecPtr lsn); + +extern set_lwlsn_block_hook_type set_lwlsn_block_hook; +extern set_lwlsn_block_range_hook_type set_lwlsn_block_range_hook; +extern set_lwlsn_block_v_hook_type set_lwlsn_block_v_hook; +extern set_lwlsn_db_hook_type set_lwlsn_db_hook; +extern set_lwlsn_relation_hook_type set_lwlsn_relation_hook; +extern set_max_lwlsn_hook_type set_max_lwlsn_hook; extern void SetRedoStartLsn(XLogRecPtr RedoStartLSN); extern XLogRecPtr GetRedoStartLsn(void);