1
0
mirror of https://github.com/postgres/postgres.git synced 2025-11-09 06:21:09 +03:00

Add doubly linked count list implementation

We have various requirements when using a dlist_head to keep track of the
number of items in the list.  This, traditionally, has been done by
maintaining a counter variable in the calling code.  Here we tidy this up
by adding "dclist", which is very similar to dlist but also keeps track of
the number of items stored in the list.

Callers may use the new dclist_count() function when they need to know how
many items are stored. Obtaining the count is an O(1) operation.

For simplicity reasons, dclist and dlist both use dlist_node as their node
type and dlist_iter/dlist_mutable_iter as their iterator type. dclists
have all of the same functionality as dlists except there is no function
named dclist_delete().  To remove an item from a list dclist_delete_from()
must be used.  This requires knowing which dclist the given item is stored
in.

Additionally, here we also convert some dlists where additional code
exists to keep track of the number of items stored and to make these use
dclists instead.

Author: David Rowley
Reviewed-by: Bharath Rupireddy, Aleksander Alekseev
Discussion: https://postgr.es/m/CAApHDvrtVxr+FXEX0VbViCFKDGxA3tWDgw9oFewNXCJMmwLjLg@mail.gmail.com
This commit is contained in:
David Rowley
2022-11-02 14:06:05 +13:00
parent 451d1164b9
commit 7c335b7a20
11 changed files with 448 additions and 109 deletions

View File

@@ -196,8 +196,7 @@ typedef struct RewriteMappingFile
TransactionId xid; /* xid that might need to see the row */
int vfd; /* fd of mappings file */
off_t off; /* how far have we written yet */
uint32 num_mappings; /* number of in-memory mappings */
dlist_head mappings; /* list of in-memory mappings */
dclist_head mappings; /* list of in-memory mappings */
char path[MAXPGPATH]; /* path, for error messages */
} RewriteMappingFile;
@@ -864,9 +863,10 @@ logical_heap_rewrite_flush_mappings(RewriteState state)
Oid dboid;
uint32 len;
int written;
uint32 num_mappings = dclist_count(&src->mappings);
/* this file hasn't got any new mappings */
if (src->num_mappings == 0)
if (num_mappings == 0)
continue;
if (state->rs_old_rel->rd_rel->relisshared)
@@ -874,7 +874,7 @@ logical_heap_rewrite_flush_mappings(RewriteState state)
else
dboid = MyDatabaseId;
xlrec.num_mappings = src->num_mappings;
xlrec.num_mappings = num_mappings;
xlrec.mapped_rel = RelationGetRelid(state->rs_old_rel);
xlrec.mapped_xid = src->xid;
xlrec.mapped_db = dboid;
@@ -882,31 +882,30 @@ logical_heap_rewrite_flush_mappings(RewriteState state)
xlrec.start_lsn = state->rs_begin_lsn;
/* write all mappings consecutively */
len = src->num_mappings * sizeof(LogicalRewriteMappingData);
len = num_mappings * sizeof(LogicalRewriteMappingData);
waldata_start = waldata = palloc(len);
/*
* collect data we need to write out, but don't modify ondisk data yet
*/
dlist_foreach_modify(iter, &src->mappings)
dclist_foreach_modify(iter, &src->mappings)
{
RewriteMappingDataEntry *pmap;
pmap = dlist_container(RewriteMappingDataEntry, node, iter.cur);
pmap = dclist_container(RewriteMappingDataEntry, node, iter.cur);
memcpy(waldata, &pmap->map, sizeof(pmap->map));
waldata += sizeof(pmap->map);
/* remove from the list and free */
dlist_delete(&pmap->node);
dclist_delete_from(&src->mappings, &pmap->node);
pfree(pmap);
/* update bookkeeping */
state->rs_num_rewrite_mappings--;
src->num_mappings--;
}
Assert(src->num_mappings == 0);
Assert(dclist_count(&src->mappings) == 0);
Assert(waldata == waldata_start + len);
/*
@@ -1002,8 +1001,7 @@ logical_rewrite_log_mapping(RewriteState state, TransactionId xid,
LSN_FORMAT_ARGS(state->rs_begin_lsn),
xid, GetCurrentTransactionId());
dlist_init(&src->mappings);
src->num_mappings = 0;
dclist_init(&src->mappings);
src->off = 0;
memcpy(src->path, path, sizeof(path));
src->vfd = PathNameOpenFile(path,
@@ -1017,8 +1015,7 @@ logical_rewrite_log_mapping(RewriteState state, TransactionId xid,
pmap = MemoryContextAlloc(state->rs_cxt,
sizeof(RewriteMappingDataEntry));
memcpy(&pmap->map, map, sizeof(LogicalRewriteMappingData));
dlist_push_tail(&src->mappings, &pmap->node);
src->num_mappings++;
dclist_push_tail(&src->mappings, &pmap->node);
state->rs_num_rewrite_mappings++;
/*

View File

@@ -319,8 +319,7 @@ typedef struct mXactCacheEnt
} mXactCacheEnt;
#define MAX_CACHE_ENTRIES 256
static dlist_head MXactCache = DLIST_STATIC_INIT(MXactCache);
static int MXactCacheMembers = 0;
static dclist_head MXactCache = DCLIST_STATIC_INIT(MXactCache);
static MemoryContext MXactContext = NULL;
#ifdef MULTIXACT_DEBUG
@@ -1504,9 +1503,10 @@ mXactCacheGetBySet(int nmembers, MultiXactMember *members)
/* sort the array so comparison is easy */
qsort(members, nmembers, sizeof(MultiXactMember), mxactMemberComparator);
dlist_foreach(iter, &MXactCache)
dclist_foreach(iter, &MXactCache)
{
mXactCacheEnt *entry = dlist_container(mXactCacheEnt, node, iter.cur);
mXactCacheEnt *entry = dclist_container(mXactCacheEnt, node,
iter.cur);
if (entry->nmembers != nmembers)
continue;
@@ -1518,7 +1518,7 @@ mXactCacheGetBySet(int nmembers, MultiXactMember *members)
if (memcmp(members, entry->members, nmembers * sizeof(MultiXactMember)) == 0)
{
debug_elog3(DEBUG2, "CacheGet: found %u", entry->multi);
dlist_move_head(&MXactCache, iter.cur);
dclist_move_head(&MXactCache, iter.cur);
return entry->multi;
}
}
@@ -1542,9 +1542,10 @@ mXactCacheGetById(MultiXactId multi, MultiXactMember **members)
debug_elog3(DEBUG2, "CacheGet: looking for %u", multi);
dlist_foreach(iter, &MXactCache)
dclist_foreach(iter, &MXactCache)
{
mXactCacheEnt *entry = dlist_container(mXactCacheEnt, node, iter.cur);
mXactCacheEnt *entry = dclist_container(mXactCacheEnt, node,
iter.cur);
if (entry->multi == multi)
{
@@ -1566,7 +1567,7 @@ mXactCacheGetById(MultiXactId multi, MultiXactMember **members)
* This is acceptable only because we exit the iteration
* immediately afterwards.
*/
dlist_move_head(&MXactCache, iter.cur);
dclist_move_head(&MXactCache, iter.cur);
*members = ptr;
return entry->nmembers;
@@ -1610,16 +1611,15 @@ mXactCachePut(MultiXactId multi, int nmembers, MultiXactMember *members)
/* mXactCacheGetBySet assumes the entries are sorted, so sort them */
qsort(entry->members, nmembers, sizeof(MultiXactMember), mxactMemberComparator);
dlist_push_head(&MXactCache, &entry->node);
if (MXactCacheMembers++ >= MAX_CACHE_ENTRIES)
dclist_push_head(&MXactCache, &entry->node);
if (dclist_count(&MXactCache) > MAX_CACHE_ENTRIES)
{
dlist_node *node;
node = dlist_tail_node(&MXactCache);
dlist_delete(node);
MXactCacheMembers--;
node = dclist_tail_node(&MXactCache);
dclist_delete_from(&MXactCache, node);
entry = dlist_container(mXactCacheEnt, node, node);
entry = dclist_container(mXactCacheEnt, node, node);
debug_elog3(DEBUG2, "CachePut: pruning cached multi %u",
entry->multi);
@@ -1699,8 +1699,7 @@ AtEOXact_MultiXact(void)
* a child of TopTransactionContext, we needn't delete it explicitly.
*/
MXactContext = NULL;
dlist_init(&MXactCache);
MXactCacheMembers = 0;
dclist_init(&MXactCache);
}
/*
@@ -1766,8 +1765,7 @@ PostPrepare_MultiXact(TransactionId xid)
* Discard the local MultiXactId cache like in AtEOXact_MultiXact.
*/
MXactContext = NULL;
dlist_init(&MXactCache);
MXactCacheMembers = 0;
dclist_init(&MXactCache);
}
/*