diff options
Diffstat (limited to 'src/backend')
| -rw-r--r-- | src/backend/lib/Makefile | 2 | ||||
| -rw-r--r-- | src/backend/lib/dllist.c | 214 | ||||
| -rw-r--r-- | src/backend/lib/ilist.c | 109 | ||||
| -rw-r--r-- | src/backend/postmaster/autovacuum.c | 214 | ||||
| -rw-r--r-- | src/backend/postmaster/postmaster.c | 57 | ||||
| -rw-r--r-- | src/backend/utils/cache/catcache.c | 142 |
6 files changed, 302 insertions, 436 deletions
diff --git a/src/backend/lib/Makefile b/src/backend/lib/Makefile index 2e1061e24a..98ce3d7e4a 100644 --- a/src/backend/lib/Makefile +++ b/src/backend/lib/Makefile @@ -12,6 +12,6 @@ subdir = src/backend/lib top_builddir = ../../.. include $(top_builddir)/src/Makefile.global -OBJS = dllist.o stringinfo.o +OBJS = ilist.o stringinfo.o include $(top_srcdir)/src/backend/common.mk diff --git a/src/backend/lib/dllist.c b/src/backend/lib/dllist.c deleted file mode 100644 index 52af56a079..0000000000 --- a/src/backend/lib/dllist.c +++ /dev/null @@ -1,214 +0,0 @@ -/*------------------------------------------------------------------------- - * - * dllist.c - * this is a simple doubly linked list implementation - * the elements of the lists are void* - * - * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group - * Portions Copyright (c) 1994, Regents of the University of California - * - * - * IDENTIFICATION - * src/backend/lib/dllist.c - * - *------------------------------------------------------------------------- - */ -#include "postgres.h" - -#include "lib/dllist.h" - - -Dllist * -DLNewList(void) -{ - Dllist *l; - - l = (Dllist *) palloc(sizeof(Dllist)); - - l->dll_head = NULL; - l->dll_tail = NULL; - - return l; -} - -void -DLInitList(Dllist *list) -{ - list->dll_head = NULL; - list->dll_tail = NULL; -} - -/* - * free up a list and all the nodes in it --- but *not* whatever the nodes - * might point to! - */ -void -DLFreeList(Dllist *list) -{ - Dlelem *curr; - - while ((curr = DLRemHead(list)) != NULL) - pfree(curr); - - pfree(list); -} - -Dlelem * -DLNewElem(void *val) -{ - Dlelem *e; - - e = (Dlelem *) palloc(sizeof(Dlelem)); - - e->dle_next = NULL; - e->dle_prev = NULL; - e->dle_val = val; - e->dle_list = NULL; - return e; -} - -void -DLInitElem(Dlelem *e, void *val) -{ - e->dle_next = NULL; - e->dle_prev = NULL; - e->dle_val = val; - e->dle_list = NULL; -} - -void -DLFreeElem(Dlelem *e) -{ - pfree(e); -} - -void -DLRemove(Dlelem *e) -{ - Dllist *l = e->dle_list; - - if (e->dle_prev) - e->dle_prev->dle_next = e->dle_next; - else - { - /* must be the head element */ - Assert(e == l->dll_head); - l->dll_head = e->dle_next; - } - if (e->dle_next) - e->dle_next->dle_prev = e->dle_prev; - else - { - /* must be the tail element */ - Assert(e == l->dll_tail); - l->dll_tail = e->dle_prev; - } - - e->dle_next = NULL; - e->dle_prev = NULL; - e->dle_list = NULL; -} - -void -DLAddHead(Dllist *l, Dlelem *e) -{ - e->dle_list = l; - - if (l->dll_head) - l->dll_head->dle_prev = e; - e->dle_next = l->dll_head; - e->dle_prev = NULL; - l->dll_head = e; - - if (l->dll_tail == NULL) /* if this is first element added */ - l->dll_tail = e; -} - -void -DLAddTail(Dllist *l, Dlelem *e) -{ - e->dle_list = l; - - if (l->dll_tail) - l->dll_tail->dle_next = e; - e->dle_prev = l->dll_tail; - e->dle_next = NULL; - l->dll_tail = e; - - if (l->dll_head == NULL) /* if this is first element added */ - l->dll_head = e; -} - -Dlelem * -DLRemHead(Dllist *l) -{ - /* remove and return the head */ - Dlelem *result = l->dll_head; - - if (result == NULL) - return result; - - if (result->dle_next) - result->dle_next->dle_prev = NULL; - - l->dll_head = result->dle_next; - - if (result == l->dll_tail) /* if the head is also the tail */ - l->dll_tail = NULL; - - result->dle_next = NULL; - result->dle_list = NULL; - - return result; -} - -Dlelem * -DLRemTail(Dllist *l) -{ - /* remove and return the tail */ - Dlelem *result = l->dll_tail; - - if (result == NULL) - return result; - - if (result->dle_prev) - result->dle_prev->dle_next = NULL; - - l->dll_tail = result->dle_prev; - - if (result == l->dll_head) /* if the tail is also the head */ - l->dll_head = NULL; - - result->dle_prev = NULL; - result->dle_list = NULL; - - return result; -} - -/* Same as DLRemove followed by DLAddHead, but faster */ -void -DLMoveToFront(Dlelem *e) -{ - Dllist *l = e->dle_list; - - if (l->dll_head == e) - return; /* Fast path if already at front */ - - Assert(e->dle_prev != NULL); /* since it's not the head */ - e->dle_prev->dle_next = e->dle_next; - - if (e->dle_next) - e->dle_next->dle_prev = e->dle_prev; - else - { - /* must be the tail element */ - Assert(e == l->dll_tail); - l->dll_tail = e->dle_prev; - } - - l->dll_head->dle_prev = e; - e->dle_next = l->dll_head; - e->dle_prev = NULL; - l->dll_head = e; - /* We need not check dll_tail, since there must have been > 1 entry */ -} diff --git a/src/backend/lib/ilist.c b/src/backend/lib/ilist.c new file mode 100644 index 0000000000..c5831acd67 --- /dev/null +++ b/src/backend/lib/ilist.c @@ -0,0 +1,109 @@ +/*------------------------------------------------------------------------- + * + * ilist.c + * support for integrated/inline doubly- and singly- linked lists + * + * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * src/backend/lib/ilist.c + * + * NOTES + * This file only contains functions that are too big to be considered + * for inlining. See ilist.h for most of the goodies. + * + *------------------------------------------------------------------------- + */ +#include "postgres.h" + +/* See ilist.h */ +#define ILIST_INCLUDE_DEFINITIONS + +#include "lib/ilist.h" + +/* + * removes a node from a list + * + * Attention: O(n) + */ +void +slist_delete(slist_head *head, slist_node *node) +{ + slist_node *last = &head->head; + slist_node *cur; + bool found PG_USED_FOR_ASSERTS_ONLY = false; + + while ((cur = last->next) != NULL) + { + if (cur == node) + { + last->next = cur->next; +#ifdef USE_ASSERT_CHECKING + found = true; +#endif + break; + } + last = cur; + } + + slist_check(head); + Assert(found); +} + +#ifdef ILIST_DEBUG +/* + * Verify integrity of a doubly linked list + */ +void +dlist_check(dlist_head *head) +{ + dlist_node *cur; + + if (head == NULL || !(&head->head)) + elog(ERROR, "doubly linked list head is not properly initialized"); + + /* iterate in forward direction */ + for (cur = head->head.next; cur != &head->head; cur = cur->next) + { + if (cur == NULL || + cur->next == NULL || + cur->prev == NULL || + cur->prev->next != cur || + cur->next->prev != cur) + elog(ERROR, "doubly linked list is corrupted"); + } + + /* iterate in backward direction */ + for (cur = head->head.prev; cur != &head->head; cur = cur->prev) + { + if (cur == NULL || + cur->next == NULL || + cur->prev == NULL || + cur->prev->next != cur || + cur->next->prev != cur) + elog(ERROR, "doubly linked list is corrupted"); + } +} + +/* + * Verify integrity of a singly linked list + */ +void +slist_check(slist_head *head) +{ + slist_node *cur; + + if (head == NULL) + elog(ERROR, "singly linked is NULL"); + + /* + * there isn't much we can test in a singly linked list other that it + * actually ends sometime, i.e. hasn't introduced a cycle or similar + */ + for (cur = head->head.next; cur != NULL; cur = cur->next) + ; +} + +#endif /* ILIST_DEBUG */ diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c index 74db821387..afd15aac97 100644 --- a/src/backend/postmaster/autovacuum.c +++ b/src/backend/postmaster/autovacuum.c @@ -77,7 +77,7 @@ #include "catalog/pg_database.h" #include "commands/dbcommands.h" #include "commands/vacuum.h" -#include "lib/dllist.h" +#include "lib/ilist.h" #include "libpq/pqsignal.h" #include "miscadmin.h" #include "pgstat.h" @@ -152,6 +152,7 @@ typedef struct avl_dbase Oid adl_datid; /* hash key -- must be first */ TimestampTz adl_next_worker; int adl_score; + dlist_node adl_node; } avl_dbase; /* struct to keep track of databases in worker */ @@ -208,7 +209,7 @@ typedef struct autovac_table */ typedef struct WorkerInfoData { - SHM_QUEUE wi_links; + dlist_node wi_links; Oid wi_dboid; Oid wi_tableoid; PGPROC *wi_proc; @@ -251,15 +252,18 @@ typedef struct { sig_atomic_t av_signal[AutoVacNumSignals]; pid_t av_launcherpid; - WorkerInfo av_freeWorkers; - SHM_QUEUE av_runningWorkers; + dlist_head av_freeWorkers; + dlist_head av_runningWorkers; WorkerInfo av_startingWorker; } AutoVacuumShmemStruct; static AutoVacuumShmemStruct *AutoVacuumShmem; -/* the database list in the launcher, and the context that contains it */ -static Dllist *DatabaseList = NULL; +/* + * the database list (of avl_dbase elements) in the launcher, and the context + * that contains it + */ +static dlist_head DatabaseList = DLIST_STATIC_INIT(DatabaseList); static MemoryContext DatabaseListCxt = NULL; /* Pointer to my own WorkerInfo, valid on each worker */ @@ -508,7 +512,7 @@ AutoVacLauncherMain(int argc, char *argv[]) /* don't leave dangling pointers to freed memory */ DatabaseListCxt = NULL; - DatabaseList = NULL; + dlist_init(&DatabaseList); /* * Make sure pgstat also considers our stat data as gone. Note: we @@ -576,7 +580,7 @@ AutoVacLauncherMain(int argc, char *argv[]) struct timeval nap; TimestampTz current_time = 0; bool can_launch; - Dlelem *elem; + avl_dbase *avdb; int rc; /* @@ -586,7 +590,7 @@ AutoVacLauncherMain(int argc, char *argv[]) * wakening conditions. */ - launcher_determine_sleep((AutoVacuumShmem->av_freeWorkers != NULL), + launcher_determine_sleep(!dlist_is_empty(&AutoVacuumShmem->av_freeWorkers), false, &nap); /* Allow sinval catchup interrupts while sleeping */ @@ -679,7 +683,7 @@ AutoVacLauncherMain(int argc, char *argv[]) current_time = GetCurrentTimestamp(); LWLockAcquire(AutovacuumLock, LW_SHARED); - can_launch = (AutoVacuumShmem->av_freeWorkers != NULL); + can_launch = !dlist_is_empty(&AutoVacuumShmem->av_freeWorkers); if (AutoVacuumShmem->av_startingWorker != NULL) { @@ -721,8 +725,7 @@ AutoVacLauncherMain(int argc, char *argv[]) worker->wi_tableoid = InvalidOid; worker->wi_proc = NULL; worker->wi_launchtime = 0; - worker->wi_links.next = (SHM_QUEUE *) AutoVacuumShmem->av_freeWorkers; - AutoVacuumShmem->av_freeWorkers = worker; + dlist_push_head(&AutoVacuumShmem->av_freeWorkers, &worker->wi_links); AutoVacuumShmem->av_startingWorker = NULL; elog(WARNING, "worker took too long to start; canceled"); } @@ -738,20 +741,7 @@ AutoVacLauncherMain(int argc, char *argv[]) /* We're OK to start a new worker */ - elem = DLGetTail(DatabaseList); - if (elem != NULL) - { - avl_dbase *avdb = DLE_VAL(elem); - - /* - * launch a worker if next_worker is right now or it is in the - * past - */ - if (TimestampDifferenceExceeds(avdb->adl_next_worker, - current_time, 0)) - launch_worker(current_time); - } - else + if (dlist_is_empty(&DatabaseList)) { /* * Special case when the list is empty: start a worker right away. @@ -763,6 +753,23 @@ AutoVacLauncherMain(int argc, char *argv[]) */ launch_worker(current_time); } + else + { + /* + * because rebuild_database_list constructs a list with most + * distant adl_next_worker first, we obtain our database from the + * tail of the list. + */ + avdb = dlist_tail_element(avl_dbase, adl_node, &DatabaseList); + + /* + * launch a worker if next_worker is right now or it is in the + * past + */ + if (TimestampDifferenceExceeds(avdb->adl_next_worker, + current_time, 0)) + launch_worker(current_time); + } } /* Normal exit from the autovac launcher is here */ @@ -783,7 +790,7 @@ AutoVacLauncherMain(int argc, char *argv[]) static void launcher_determine_sleep(bool canlaunch, bool recursing, struct timeval * nap) { - Dlelem *elem; + avl_dbase *avdb; /* * We sleep until the next scheduled vacuum. We trust that when the @@ -796,14 +803,15 @@ launcher_determine_sleep(bool canlaunch, bool recursing, struct timeval * nap) nap->tv_sec = autovacuum_naptime; nap->tv_usec = 0; } - else if ((elem = DLGetTail(DatabaseList)) != NULL) + else if (!dlist_is_empty(&DatabaseList)) { - avl_dbase *avdb = DLE_VAL(elem); TimestampTz current_time = GetCurrentTimestamp(); TimestampTz next_wakeup; long secs; int usecs; + avdb = dlist_tail_element(avl_dbase, adl_node, &DatabaseList); + next_wakeup = avdb->adl_next_worker; TimestampDifference(current_time, next_wakeup, &secs, &usecs); @@ -867,6 +875,7 @@ rebuild_database_list(Oid newdb) int score; int nelems; HTAB *dbhash; + dlist_iter iter; /* use fresh stats */ autovac_refresh_stats(); @@ -927,36 +936,28 @@ rebuild_database_list(Oid newdb) } /* Now insert the databases from the existing list */ - if (DatabaseList != NULL) + dlist_foreach(iter, &DatabaseList) { - Dlelem *elem; - - elem = DLGetHead(DatabaseList); - while (elem != NULL) - { - avl_dbase *avdb = DLE_VAL(elem); - avl_dbase *db; - bool found; - PgStat_StatDBEntry *entry; - - elem = DLGetSucc(elem); + avl_dbase *avdb = dlist_container(avl_dbase, adl_node, iter.cur); + avl_dbase *db; + bool found; + PgStat_StatDBEntry *entry; - /* - * skip databases with no stat entries -- in particular, this gets - * rid of dropped databases - */ - entry = pgstat_fetch_stat_dbentry(avdb->adl_datid); - if (entry == NULL) - continue; + /* + * skip databases with no stat entries -- in particular, this gets + * rid of dropped databases + */ + entry = pgstat_fetch_stat_dbentry(avdb->adl_datid); + if (entry == NULL) + continue; - db = hash_search(dbhash, &(avdb->adl_datid), HASH_ENTER, &found); + db = hash_search(dbhash, &(avdb->adl_datid), HASH_ENTER, &found); - if (!found) - { - /* hash_search already filled in the key */ - db->adl_score = score++; - /* next_worker is filled in later */ - } + if (!found) + { + /* hash_search already filled in the key */ + db->adl_score = score++; + /* next_worker is filled in later */ } } @@ -987,7 +988,7 @@ rebuild_database_list(Oid newdb) /* from here on, the allocated memory belongs to the new list */ MemoryContextSwitchTo(newcxt); - DatabaseList = DLNewList(); + dlist_init(&DatabaseList); if (nelems > 0) { @@ -1029,15 +1030,13 @@ rebuild_database_list(Oid newdb) for (i = 0; i < nelems; i++) { avl_dbase *db = &(dbary[i]); - Dlelem *elem; current_time = TimestampTzPlusMilliseconds(current_time, millis_increment); db->adl_next_worker = current_time; - elem = DLNewElem(db); /* later elements should go closer to the head of the list */ - DLAddHead(DatabaseList, elem); + dlist_push_head(&DatabaseList, &db->adl_node); } } @@ -1086,7 +1085,7 @@ do_start_worker(void) /* return quickly when there are no free workers */ LWLockAcquire(AutovacuumLock, LW_SHARED); - if (AutoVacuumShmem->av_freeWorkers == NULL) + if (dlist_is_empty(&AutoVacuumShmem->av_freeWorkers)) { LWLockRelease(AutovacuumLock); return InvalidOid; @@ -1147,7 +1146,7 @@ do_start_worker(void) foreach(cell, dblist) { avw_dbase *tmp = lfirst(cell); - Dlelem *elem; + dlist_iter iter; /* Check to see if this one is at risk of wraparound */ if (TransactionIdPrecedes(tmp->adw_frozenxid, xidForceLimit)) @@ -1179,11 +1178,10 @@ do_start_worker(void) * autovacuum time yet. */ skipit = false; - elem = DatabaseList ? DLGetTail(DatabaseList) : NULL; - while (elem != NULL) + dlist_reverse_foreach(iter, &DatabaseList) { - avl_dbase *dbp = DLE_VAL(elem); + avl_dbase *dbp = dlist_container(avl_dbase, adl_node, iter.cur); if (dbp->adl_datid == tmp->adw_datid) { @@ -1200,7 +1198,6 @@ do_start_worker(void) break; } - elem = DLGetPred(elem); } if (skipit) continue; @@ -1218,20 +1215,17 @@ do_start_worker(void) if (avdb != NULL) { WorkerInfo worker; + dlist_node *wptr; LWLockAcquire(AutovacuumLock, LW_EXCLUSIVE); /* * Get a worker entry from the freelist. We checked above, so there - * really should be a free slot -- complain very loudly if there - * isn't. + * really should be a free slot. */ - worker = AutoVacuumShmem->av_freeWorkers; - if (worker == NULL) - elog(FATAL, "no free worker found"); - - AutoVacuumShmem->av_freeWorkers = (WorkerInfo) worker->wi_links.next; + wptr = dlist_pop_head_node(&AutoVacuumShmem->av_freeWorkers); + worker = dlist_container(WorkerInfoData, wi_links, wptr); worker->wi_dboid = avdb->adw_datid; worker->wi_proc = NULL; worker->wi_launchtime = GetCurrentTimestamp(); @@ -1274,22 +1268,25 @@ static void launch_worker(TimestampTz now) { Oid dbid; - Dlelem *elem; + dlist_iter iter; dbid = do_start_worker(); if (OidIsValid(dbid)) { + bool found = false; + /* * Walk the database list and update the corresponding entry. If the * database is not on the list, we'll recreate the list. */ - elem = (DatabaseList == NULL) ? NULL : DLGetHead(DatabaseList); - while (elem != NULL) + dlist_foreach(iter, &DatabaseList) { - avl_dbase *avdb = DLE_VAL(elem); + avl_dbase *avdb = dlist_container(avl_dbase, adl_node, iter.cur); if (avdb->adl_datid == dbid) { + found = true; + /* * add autovacuum_naptime seconds to the current time, and use * that as the new "next_worker" field for this database. @@ -1297,10 +1294,9 @@ launch_worker(TimestampTz now) avdb->adl_next_worker = TimestampTzPlusMilliseconds(now, autovacuum_naptime * 1000); - DLMoveToFront(elem); + dlist_move_head(&DatabaseList, iter.cur); break; } - elem = DLGetSucc(elem); } /* @@ -1310,7 +1306,7 @@ launch_worker(TimestampTz now) * pgstat entry, but this is not a problem because we don't want to * schedule workers regularly into those in any case. */ - if (elem == NULL) + if (!found) rebuild_database_list(dbid); } } @@ -1590,8 +1586,8 @@ AutoVacWorkerMain(int argc, char *argv[]) MyWorkerInfo->wi_proc = MyProc; /* insert into the running list */ - SHMQueueInsertBefore(&AutoVacuumShmem->av_runningWorkers, - &MyWorkerInfo->wi_links); + dlist_push_head(&AutoVacuumShmem->av_runningWorkers, + &MyWorkerInfo->wi_links); /* * remove from the "starting" pointer, so that the launcher can start @@ -1681,8 +1677,7 @@ FreeWorkerInfo(int code, Datum arg) */ AutovacuumLauncherPid = AutoVacuumShmem->av_launcherpid; - SHMQueueDelete(&MyWorkerInfo->wi_links); - MyWorkerInfo->wi_links.next = (SHM_QUEUE *) AutoVacuumShmem->av_freeWorkers; + dlist_delete(&AutoVacuumShmem->av_runningWorkers, &MyWorkerInfo->wi_links); MyWorkerInfo->wi_dboid = InvalidOid; MyWorkerInfo->wi_tableoid = InvalidOid; MyWorkerInfo->wi_proc = NULL; @@ -1690,7 +1685,7 @@ FreeWorkerInfo(int code, Datum arg) MyWorkerInfo->wi_cost_delay = 0; MyWorkerInfo->wi_cost_limit = 0; MyWorkerInfo->wi_cost_limit_base = 0; - AutoVacuumShmem->av_freeWorkers = MyWorkerInfo; + dlist_push_head(&AutoVacuumShmem->av_freeWorkers, &MyWorkerInfo->wi_links); /* not mine anymore */ MyWorkerInfo = NULL; @@ -1740,7 +1735,7 @@ autovac_balance_cost(void) autovacuum_vac_cost_delay : VacuumCostDelay); double cost_total; double cost_avail; - WorkerInfo worker; + dlist_iter iter; /* not set? nothing to do */ if (vac_cost_limit <= 0 || vac_cost_delay <= 0) @@ -1748,19 +1743,14 @@ autovac_balance_cost(void) /* caculate the total base cost limit of active workers */ cost_total = 0.0; - worker = (WorkerInfo) SHMQueueNext(&AutoVacuumShmem->av_runningWorkers, - &AutoVacuumShmem->av_runningWorkers, - offsetof(WorkerInfoData, wi_links)); - while (worker) + dlist_foreach(iter, &AutoVacuumShmem->av_runningWorkers) { + WorkerInfo worker = dlist_container(WorkerInfoData, wi_links, iter.cur); + if (worker->wi_proc != NULL && worker->wi_cost_limit_base > 0 && worker->wi_cost_delay > 0) cost_total += (double) worker->wi_cost_limit_base / worker->wi_cost_delay; - - worker = (WorkerInfo) SHMQueueNext(&AutoVacuumShmem->av_runningWorkers, - &worker->wi_links, - offsetof(WorkerInfoData, wi_links)); } /* there are no cost limits -- nothing to do */ if (cost_total <= 0) @@ -1771,11 +1761,10 @@ autovac_balance_cost(void) * limit to autovacuum_vacuum_cost_limit. */ cost_avail = (double) vac_cost_limit / vac_cost_delay; - worker = (WorkerInfo) SHMQueueNext(&AutoVacuumShmem->av_runningWorkers, - &AutoVacuumShmem->av_runningWorkers, - offsetof(WorkerInfoData, wi_links)); - while (worker) + dlist_foreach(iter, &AutoVacuumShmem->av_runningWorkers) { + WorkerInfo worker = dlist_container(WorkerInfoData, wi_links, iter.cur); + if (worker->wi_proc != NULL && worker->wi_cost_limit_base > 0 && worker->wi_cost_delay > 0) { @@ -1797,10 +1786,6 @@ autovac_balance_cost(void) worker->wi_cost_limit, worker->wi_cost_limit_base, worker->wi_cost_delay); } - - worker = (WorkerInfo) SHMQueueNext(&AutoVacuumShmem->av_runningWorkers, - &worker->wi_links, - offsetof(WorkerInfoData, wi_links)); } } @@ -2177,10 +2162,10 @@ do_autovacuum(void) { Oid relid = lfirst_oid(cell); autovac_table *tab; - WorkerInfo worker; bool skipit; int stdVacuumCostDelay; int stdVacuumCostLimit; + dlist_iter iter; CHECK_FOR_INTERRUPTS(); @@ -2197,29 +2182,23 @@ do_autovacuum(void) * worker. */ skipit = false; - worker = (WorkerInfo) SHMQueueNext(&AutoVacuumShmem->av_runningWorkers, - &AutoVacuumShmem->av_runningWorkers, - offsetof(WorkerInfoData, wi_links)); - while (worker) + dlist_foreach(iter, &AutoVacuumShmem->av_runningWorkers) { + WorkerInfo worker = dlist_container(WorkerInfoData, wi_links, iter.cur); + /* ignore myself */ if (worker == MyWorkerInfo) - goto next_worker; + continue; /* ignore workers in other databases */ if (worker->wi_dboid != MyDatabaseId) - goto next_worker; + continue; if (worker->wi_tableoid == relid) { skipit = true; break; } - - next_worker: - worker = (WorkerInfo) SHMQueueNext(&AutoVacuumShmem->av_runningWorkers, - &worker->wi_links, - offsetof(WorkerInfoData, wi_links)); } LWLockRelease(AutovacuumLock); if (skipit) @@ -2875,8 +2854,8 @@ AutoVacuumShmemInit(void) Assert(!found); AutoVacuumShmem->av_launcherpid = 0; - AutoVacuumShmem->av_freeWorkers = NULL; - SHMQueueInit(&AutoVacuumShmem->av_runningWorkers); + dlist_init(&AutoVacuumShmem->av_freeWorkers); + dlist_init(&AutoVacuumShmem->av_runningWorkers); AutoVacuumShmem->av_startingWorker = NULL; worker = (WorkerInfo) ((char *) AutoVacuumShmem + @@ -2884,10 +2863,7 @@ AutoVacuumShmemInit(void) /* initialize the WorkerInfo free list */ for (i = 0; i < autovacuum_max_workers; i++) - { - worker[i].wi_links.next = (SHM_QUEUE *) AutoVacuumShmem->av_freeWorkers; - AutoVacuumShmem->av_freeWorkers = &worker[i]; - } + dlist_push_head(&AutoVacuumShmem->av_freeWorkers, &worker[i].wi_links); } else Assert(found); diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c index dfe40492d2..c8a80f038c 100644 --- a/src/backend/postmaster/postmaster.c +++ b/src/backend/postmaster/postmaster.c @@ -95,7 +95,7 @@ #include "access/xlog.h" #include "bootstrap/bootstrap.h" #include "catalog/pg_control.h" -#include "lib/dllist.h" +#include "lib/ilist.h" #include "libpq/auth.h" #include "libpq/ip.h" #include "libpq/libpq.h" @@ -146,10 +146,10 @@ typedef struct bkend int child_slot; /* PMChildSlot for this backend, if any */ bool is_autovacuum; /* is it an autovacuum process? */ bool dead_end; /* is it going to send an error and quit? */ - Dlelem elem; /* list link in BackendList */ + dlist_node elem; /* list link in BackendList */ } Backend; -static Dllist *BackendList; +static dlist_head BackendList = DLIST_STATIC_INIT(BackendList); #ifdef EXEC_BACKEND static Backend *ShmemBackendArray; @@ -1028,11 +1028,6 @@ PostmasterMain(int argc, char *argv[]) set_stack_base(); /* - * Initialize the list of active backends. - */ - BackendList = DLNewList(); - - /* * Initialize pipe (or process handle on Windows) that allows children to * wake up from sleep on postmaster death. */ @@ -1872,7 +1867,7 @@ processCancelRequest(Port *port, void *pkt) Backend *bp; #ifndef EXEC_BACKEND - Dlelem *curr; + dlist_iter iter; #else int i; #endif @@ -1886,9 +1881,9 @@ processCancelRequest(Port *port, void *pkt) * duplicate array in shared memory. */ #ifndef EXEC_BACKEND - for (curr = DLGetHead(BackendList); curr; curr = DLGetSucc(curr)) + dlist_foreach(iter, &BackendList) { - bp = (Backend *) DLE_VAL(curr); + bp = dlist_container(Backend, elem, iter.cur); #else for (i = MaxLivePostmasterChildren() - 1; i >= 0; i--) { @@ -2648,7 +2643,7 @@ static void CleanupBackend(int pid, int exitstatus) /* child's exit status. */ { - Dlelem *curr; + dlist_mutable_iter iter; LogChildExit(DEBUG2, _("server process"), pid, exitstatus); @@ -2680,9 +2675,9 @@ CleanupBackend(int pid, return; } - for (curr = DLGetHead(BackendList); curr; curr = DLGetSucc(curr)) + dlist_foreach_modify(iter, &BackendList) { - Backend *bp = (Backend *) DLE_VAL(curr); + Backend *bp = dlist_container(Backend, elem, iter.cur); if (bp->pid == pid) { @@ -2701,7 +2696,7 @@ CleanupBackend(int pid, ShmemBackendArrayRemove(bp); #endif } - DLRemove(curr); + dlist_delete(&BackendList, iter.cur); free(bp); break; } @@ -2718,8 +2713,7 @@ CleanupBackend(int pid, static void HandleChildCrash(int pid, int exitstatus, const char *procname) { - Dlelem *curr, - *next; + dlist_mutable_iter iter; Backend *bp; /* @@ -2734,10 +2728,10 @@ HandleChildCrash(int pid, int exitstatus, const char *procname) } /* Process regular backends */ - for (curr = DLGetHead(BackendList); curr; curr = next) + dlist_foreach_modify(iter, &BackendList) { - next = DLGetSucc(curr); - bp = (Backend *) DLE_VAL(curr); + bp = dlist_container(Backend, elem, iter.cur); + if (bp->pid == pid) { /* @@ -2750,7 +2744,7 @@ HandleChildCrash(int pid, int exitstatus, const char *procname) ShmemBackendArrayRemove(bp); #endif } - DLRemove(curr); + dlist_delete(&BackendList, iter.cur); free(bp); /* Keep looping so we can signal remaining backends */ } @@ -3113,7 +3107,7 @@ PostmasterStateMachine(void) * normal state transition leading up to PM_WAIT_DEAD_END, or during * FatalError processing. */ - if (DLGetHead(BackendList) == NULL && + if (dlist_is_empty(&BackendList) && PgArchPID == 0 && PgStatPID == 0) { /* These other guys should be dead already */ @@ -3239,12 +3233,12 @@ signal_child(pid_t pid, int signal) static bool SignalSomeChildren(int signal, int target) { - Dlelem *curr; + dlist_iter iter; bool signaled = false; - for (curr = DLGetHead(BackendList); curr; curr = DLGetSucc(curr)) + dlist_foreach(iter, &BackendList) { - Backend *bp = (Backend *) DLE_VAL(curr); + Backend *bp = dlist_container(Backend, elem, iter.cur); if (bp->dead_end) continue; @@ -3382,8 +3376,8 @@ BackendStartup(Port *port) */ bn->pid = pid; bn->is_autovacuum = false; - DLInitElem(&bn->elem, bn); - DLAddHead(BackendList, &bn->elem); + dlist_push_head(&BackendList, &bn->elem); + #ifdef EXEC_BACKEND if (!bn->dead_end) ShmemBackendArrayAdd(bn); @@ -4491,12 +4485,12 @@ PostmasterRandom(void) static int CountChildren(int target) { - Dlelem *curr; + dlist_iter iter; int cnt = 0; - for (curr = DLGetHead(BackendList); curr; curr = DLGetSucc(curr)) + dlist_foreach(iter, &BackendList) { - Backend *bp = (Backend *) DLE_VAL(curr); + Backend *bp = dlist_container(Backend, elem, iter.cur); if (bp->dead_end) continue; @@ -4675,8 +4669,7 @@ StartAutovacuumWorker(void) if (bn->pid > 0) { bn->is_autovacuum = true; - DLInitElem(&bn->elem, bn); - DLAddHead(BackendList, &bn->elem); + dlist_push_head(&BackendList, &bn->elem); #ifdef EXEC_BACKEND ShmemBackendArrayAdd(bn); #endif diff --git a/src/backend/utils/cache/catcache.c b/src/backend/utils/cache/catcache.c index d6f6b1c0de..05ceff51cd 100644 --- a/src/backend/utils/cache/catcache.c +++ b/src/backend/utils/cache/catcache.c @@ -291,7 +291,7 @@ CatalogCacheComputeTupleHashValue(CatCache *cache, HeapTuple tuple) static void CatCachePrintStats(int code, Datum arg) { - CatCache *cache; + slist_iter iter; long cc_searches = 0; long cc_hits = 0; long cc_neg_hits = 0; @@ -300,8 +300,10 @@ CatCachePrintStats(int code, Datum arg) long cc_lsearches = 0; long cc_lhits = 0; - for (cache = CacheHdr->ch_caches; cache; cache = cache->cc_next) + slist_foreach(iter, &CacheHdr->ch_caches) { + CatCache *cache = slist_container(CatCache, cc_next, iter.cur); + if (cache->cc_ntup == 0 && cache->cc_searches == 0) continue; /* don't print unused caches */ elog(DEBUG2, "catcache %s/%u: %d tup, %ld srch, %ld+%ld=%ld hits, %ld+%ld=%ld loads, %ld invals, %ld lsrch, %ld lhits", @@ -368,8 +370,7 @@ CatCacheRemoveCTup(CatCache *cache, CatCTup *ct) return; /* nothing left to do */ } - /* delink from linked list */ - DLRemove(&ct->cache_elem); + dlist_delete(ct->cache_bucket, &ct->cache_elem); /* free associated tuple data */ if (ct->tuple.t_data != NULL) @@ -412,7 +413,7 @@ CatCacheRemoveCList(CatCache *cache, CatCList *cl) } /* delink from linked list */ - DLRemove(&cl->cache_elem); + dlist_delete(&cache->cc_lists, &cl->cache_elem); /* free associated tuple data */ if (cl->tuple.t_data != NULL) @@ -442,18 +443,18 @@ CatCacheRemoveCList(CatCache *cache, CatCList *cl) void CatalogCacheIdInvalidate(int cacheId, uint32 hashValue) { - CatCache *ccp; + slist_iter cache_iter; CACHE1_elog(DEBUG2, "CatalogCacheIdInvalidate: called"); /* * inspect caches to find the proper cache */ - for (ccp = CacheHdr->ch_caches; ccp; ccp = ccp->cc_next) + slist_foreach(cache_iter, &CacheHdr->ch_caches) { Index hashIndex; - Dlelem *elt, - *nextelt; + dlist_mutable_iter iter; + CatCache *ccp = slist_container(CatCache, cc_next, cache_iter.cur); if (cacheId != ccp->id) continue; @@ -468,11 +469,9 @@ CatalogCacheIdInvalidate(int cacheId, uint32 hashValue) * Invalidate *all* CatCLists in this cache; it's too hard to tell * which searches might still be correct, so just zap 'em all. */ - for (elt = DLGetHead(&ccp->cc_lists); elt; elt = nextelt) + dlist_foreach_modify(iter, &ccp->cc_lists) { - CatCList *cl = (CatCList *) DLE_VAL(elt); - - nextelt = DLGetSucc(elt); + CatCList *cl = dlist_container(CatCList, cache_elem, iter.cur); if (cl->refcount > 0) cl->dead = true; @@ -484,12 +483,9 @@ CatalogCacheIdInvalidate(int cacheId, uint32 hashValue) * inspect the proper hash bucket for tuple matches */ hashIndex = HASH_INDEX(hashValue, ccp->cc_nbuckets); - - for (elt = DLGetHead(&ccp->cc_bucket[hashIndex]); elt; elt = nextelt) + dlist_foreach_modify(iter, &ccp->cc_bucket[hashIndex]) { - CatCTup *ct = (CatCTup *) DLE_VAL(elt); - - nextelt = DLGetSucc(elt); + CatCTup *ct = dlist_container(CatCTup, cache_elem, iter.cur); if (hashValue == ct->hash_value) { @@ -557,17 +553,18 @@ AtEOXact_CatCache(bool isCommit) #ifdef USE_ASSERT_CHECKING if (assert_enabled) { - CatCache *ccp; + slist_iter cache_iter; - for (ccp = CacheHdr->ch_caches; ccp; ccp = ccp->cc_next) + slist_foreach(cache_iter, &(CacheHdr->ch_caches)) { - Dlelem *elt; + CatCache *ccp = slist_container(CatCache, cc_next, cache_iter.cur); + dlist_iter iter; int i; /* Check CatCLists */ - for (elt = DLGetHead(&ccp->cc_lists); elt; elt = DLGetSucc(elt)) + dlist_foreach(iter, &ccp->cc_lists) { - CatCList *cl = (CatCList *) DLE_VAL(elt); + CatCList *cl = dlist_container(CatCList, cache_elem, iter.cur); Assert(cl->cl_magic == CL_MAGIC); Assert(cl->refcount == 0); @@ -577,11 +574,11 @@ AtEOXact_CatCache(bool isCommit) /* Check individual tuples */ for (i = 0; i < ccp->cc_nbuckets; i++) { - for (elt = DLGetHead(&ccp->cc_bucket[i]); - elt; - elt = DLGetSucc(elt)) + dlist_head *bucket = &ccp->cc_bucket[i]; + + dlist_foreach(iter, bucket) { - CatCTup *ct = (CatCTup *) DLE_VAL(elt); + CatCTup *ct = dlist_container(CatCTup, cache_elem, iter.cur); Assert(ct->ct_magic == CT_MAGIC); Assert(ct->refcount == 0); @@ -604,16 +601,13 @@ AtEOXact_CatCache(bool isCommit) static void ResetCatalogCache(CatCache *cache) { - Dlelem *elt, - *nextelt; + dlist_mutable_iter iter; int i; /* Remove each list in this cache, or at least mark it dead */ - for (elt = DLGetHead(&cache->cc_lists); elt; elt = nextelt) + dlist_foreach_modify(iter, &cache->cc_lists) { - CatCList *cl = (CatCList *) DLE_VAL(elt); - - nextelt = DLGetSucc(elt); + CatCList *cl = dlist_container(CatCList, cache_elem, iter.cur); if (cl->refcount > 0) cl->dead = true; @@ -624,11 +618,11 @@ ResetCatalogCache(CatCache *cache) /* Remove each tuple in this cache, or at least mark it dead */ for (i = 0; i < cache->cc_nbuckets; i++) { - for (elt = DLGetHead(&cache->cc_bucket[i]); elt; elt = nextelt) - { - CatCTup *ct = (CatCTup *) DLE_VAL(elt); + dlist_head *bucket = &cache->cc_bucket[i]; - nextelt = DLGetSucc(elt); + dlist_foreach_modify(iter, bucket) + { + CatCTup *ct = dlist_container(CatCTup, cache_elem, iter.cur); if (ct->refcount > 0 || (ct->c_list && ct->c_list->refcount > 0)) @@ -654,12 +648,16 @@ ResetCatalogCache(CatCache *cache) void ResetCatalogCaches(void) { - CatCache *cache; + slist_iter iter; CACHE1_elog(DEBUG2, "ResetCatalogCaches called"); - for (cache = CacheHdr->ch_caches; cache; cache = cache->cc_next) + slist_foreach(iter, &CacheHdr->ch_caches) + { + CatCache *cache = slist_container(CatCache, cc_next, iter.cur); + ResetCatalogCache(cache); + } CACHE1_elog(DEBUG2, "end of ResetCatalogCaches call"); } @@ -680,12 +678,14 @@ ResetCatalogCaches(void) void CatalogCacheFlushCatalog(Oid catId) { - CatCache *cache; + slist_iter iter; CACHE2_elog(DEBUG2, "CatalogCacheFlushCatalog called for %u", catId); - for (cache = CacheHdr->ch_caches; cache; cache = cache->cc_next) + slist_foreach(iter, &(CacheHdr->ch_caches)) { + CatCache *cache = slist_container(CatCache, cc_next, iter.cur); + /* Does this cache store tuples of the target catalog? */ if (cache->cc_reloid == catId) { @@ -760,7 +760,7 @@ InitCatCache(int id, if (CacheHdr == NULL) { CacheHdr = (CatCacheHeader *) palloc(sizeof(CatCacheHeader)); - CacheHdr->ch_caches = NULL; + slist_init(&CacheHdr->ch_caches); CacheHdr->ch_ntup = 0; #ifdef CATCACHE_STATS /* set up to dump stats at backend exit */ @@ -770,10 +770,8 @@ InitCatCache(int id, /* * allocate a new cache structure - * - * Note: we assume zeroing initializes the Dllist headers correctly */ - cp = (CatCache *) palloc0(sizeof(CatCache) + nbuckets * sizeof(Dllist)); + cp = (CatCache *) palloc0(sizeof(CatCache) + nbuckets * sizeof(dlist_node)); /* * initialize the cache's relation information for the relation @@ -792,6 +790,9 @@ InitCatCache(int id, for (i = 0; i < nkeys; ++i) cp->cc_key[i] = key[i]; + dlist_init(&cp->cc_lists); + MemSet(&cp->cc_bucket, 0, nbuckets * sizeof(dlist_head)); + /* * new cache is initialized as far as we can go for now. print some * debugging information, if appropriate. @@ -801,8 +802,7 @@ InitCatCache(int id, /* * add completed cache to top of group header's list */ - cp->cc_next = CacheHdr->ch_caches; - CacheHdr->ch_caches = cp; + slist_push_head(&CacheHdr->ch_caches, &cp->cc_next); /* * back to the old context before we return... @@ -1060,7 +1060,8 @@ SearchCatCache(CatCache *cache, ScanKeyData cur_skey[CATCACHE_MAXKEYS]; uint32 hashValue; Index hashIndex; - Dlelem *elt; + dlist_mutable_iter iter; + dlist_head *bucket; CatCTup *ct; Relation relation; SysScanDesc scandesc; @@ -1094,13 +1095,13 @@ SearchCatCache(CatCache *cache, /* * scan the hash bucket until we find a match or exhaust our tuples */ - for (elt = DLGetHead(&cache->cc_bucket[hashIndex]); - elt; - elt = DLGetSucc(elt)) + bucket = &cache->cc_bucket[hashIndex]; + + dlist_foreach_modify(iter, bucket) { bool res; - ct = (CatCTup *) DLE_VAL(elt); + ct = dlist_container(CatCTup, cache_elem, iter.cur); if (ct->dead) continue; /* ignore dead entries */ @@ -1125,7 +1126,7 @@ SearchCatCache(CatCache *cache, * most frequently accessed elements in any hashbucket will tend to be * near the front of the hashbucket's list.) */ - DLMoveToFront(&ct->cache_elem); + dlist_move_head(bucket, &ct->cache_elem); /* * If it's a positive entry, bump its refcount and return it. If it's @@ -1340,7 +1341,7 @@ SearchCatCacheList(CatCache *cache, { ScanKeyData cur_skey[CATCACHE_MAXKEYS]; uint32 lHashValue; - Dlelem *elt; + dlist_iter iter; CatCList *cl; CatCTup *ct; List *volatile ctlist; @@ -1382,13 +1383,11 @@ SearchCatCacheList(CatCache *cache, /* * scan the items until we find a match or exhaust our list */ - for (elt = DLGetHead(&cache->cc_lists); - elt; - elt = DLGetSucc(elt)) + dlist_foreach(iter, &cache->cc_lists) { bool res; - cl = (CatCList *) DLE_VAL(elt); + cl = dlist_container(CatCList, cache_elem, iter.cur); if (cl->dead) continue; /* ignore dead entries */ @@ -1416,7 +1415,7 @@ SearchCatCacheList(CatCache *cache, * since there's no point in that unless they are searched for * individually.) */ - DLMoveToFront(&cl->cache_elem); + dlist_move_head(&cache->cc_lists, &cl->cache_elem); /* Bump the list's refcount and return it */ ResourceOwnerEnlargeCatCacheListRefs(CurrentResourceOwner); @@ -1468,6 +1467,8 @@ SearchCatCacheList(CatCache *cache, { uint32 hashValue; Index hashIndex; + bool found = false; + dlist_head *bucket; /* * See if there's an entry for this tuple already. @@ -1476,11 +1477,10 @@ SearchCatCacheList(CatCache *cache, hashValue = CatalogCacheComputeTupleHashValue(cache, ntp); hashIndex = HASH_INDEX(hashValue, cache->cc_nbuckets); - for (elt = DLGetHead(&cache->cc_bucket[hashIndex]); - elt; - elt = DLGetSucc(elt)) + bucket = &cache->cc_bucket[hashIndex]; + dlist_foreach(iter, bucket) { - ct = (CatCTup *) DLE_VAL(elt); + ct = dlist_container(CatCTup, cache_elem, iter.cur); if (ct->dead || ct->negative) continue; /* ignore dead and negative entries */ @@ -1498,10 +1498,11 @@ SearchCatCacheList(CatCache *cache, if (ct->c_list) continue; + found = true; break; /* A-OK */ } - if (elt == NULL) + if (!found) { /* We didn't find a usable entry, so make a new one */ ct = CatalogCacheCreateEntry(cache, ntp, @@ -1564,7 +1565,6 @@ SearchCatCacheList(CatCache *cache, cl->cl_magic = CL_MAGIC; cl->my_cache = cache; - DLInitElem(&cl->cache_elem, cl); cl->refcount = 0; /* for the moment */ cl->dead = false; cl->ordered = ordered; @@ -1587,7 +1587,7 @@ SearchCatCacheList(CatCache *cache, } Assert(i == nmembers); - DLAddHead(&cache->cc_lists, &cl->cache_elem); + dlist_push_head(&cache->cc_lists, &cl->cache_elem); /* Finally, bump the list's refcount and return it */ cl->refcount++; @@ -1664,14 +1664,15 @@ CatalogCacheCreateEntry(CatCache *cache, HeapTuple ntp, */ ct->ct_magic = CT_MAGIC; ct->my_cache = cache; - DLInitElem(&ct->cache_elem, (void *) ct); + ct->cache_bucket = &cache->cc_bucket[hashIndex]; + ct->c_list = NULL; ct->refcount = 0; /* for the moment */ ct->dead = false; ct->negative = negative; ct->hash_value = hashValue; - DLAddHead(&cache->cc_bucket[hashIndex], &ct->cache_elem); + dlist_push_head(ct->cache_bucket, &ct->cache_elem); cache->cc_ntup++; CacheHdr->ch_ntup++; @@ -1785,7 +1786,7 @@ PrepareToInvalidateCacheTuple(Relation relation, HeapTuple newtuple, void (*function) (int, uint32, Oid)) { - CatCache *ccp; + slist_iter iter; Oid reloid; CACHE1_elog(DEBUG2, "PrepareToInvalidateCacheTuple: called"); @@ -1808,10 +1809,11 @@ PrepareToInvalidateCacheTuple(Relation relation, * ---------------- */ - for (ccp = CacheHdr->ch_caches; ccp; ccp = ccp->cc_next) + slist_foreach(iter, &(CacheHdr->ch_caches)) { uint32 hashvalue; Oid dbid; + CatCache *ccp = slist_container(CatCache, cc_next, iter.cur); if (ccp->cc_reloid != reloid) continue; |
