Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

PostgreSQL source code interpretation (236)-background process # 14 (autovacuum process # 2)

2025-04-09 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Database >

Share

Shulou(Shulou.com)06/01 Report--

This section briefly introduces the background process of PostgreSQL: autovacuum, and mainly analyzes the implementation logic of the launch_worker function.

I. data structure

AutoVacuumShmem

The main autovacuum shared memory structure is stored in shared memory, and WorkerInfo is also stored in it.

/ *-* The main autovacuum shmem struct. On shared memory we store this main * struct and the array of WorkerInfo structs. This struct keeps: * the main autovacuum shared memory structure is stored in shared memory, and WorkerInfo is also stored in it. * the structure includes: * * av_signal set by other processes to indicate various conditions * PID * av_freeWorkers the WorkerInfo freelist * WorkerInfo idle list set by other processes to prompt for different conditions * av_launcherpid the PID of the autovacuum launcher * autovacuum launcher * av_runningWorkers the WorkerInfo non-free queue * WorkerInfo non-idle queue * av_startingWorker pointer to WorkerInfo currently being started (cleared by * the worker itself As soon as it's up and running) * av_startingWorker points to the currently launched WorkerInfo * av_workItems work item array * av_workItems work item array * * This struct is protected by AutovacuumLock Except for av_signal and parts * of the worker list (see above). * except for part of the information of av_signal and worker list, the data structure is protected by AutovacuumLock * * / typedef struct {sig_atomic_t av_ entries [AutoVacNumSignals]; pid_t av_launcherpid; dlist_head av_freeWorkers; dlist_head av_runningWorkers; WorkerInfo av_startingWorker; AutoVacuumWorkItem av_ workitems [num _ WORKITEMS];} AutoVacuumShmemStruct;static AutoVacuumShmemStruct * AutoVacuumShmem

FullTransactionId

Transaction ID for 64 bit

/ * A 64 bit value that contains an epoch and a TransactionId. This is * wrapped in a struct to prevent implicit conversion to/from TransactionId. * Not all values represent valid normal XIDs. * protect the 64 bit values of epoch and TransactionId. Encapsulated in the structure to avoid implicit conversion to the transaction ID. Not all values represent a valid normal xid. * / typedef struct FullTransactionId {uint64 value;} FullTransactionId

Avw_dbase

The structure used to track the database in worker

/ * struct to keep track of databases in worker * / / the structure typedef struct avw_dbase {Oid adw_datid; char * adw_name; TransactionId adw_frozenxid; MultiXactId adw_minmulti; PgStat_StatDBEntry * adw_entry;} avw_dbase used to track the database in worker

WorkerInfo

/ * * Structure to hold info passed by _ beginthreadex () to the function it calls * via its single allowed argument. * / typedef struct {ArchiveHandle * AH; / * master database connection * / ParallelSlot * slot; / * this worker's parallel slot * /} WorkerInfo; II. Source code interpretation

The main implementation logic is in do_start_worker

/ * launch_worker * * Wrapper for starting a worker from the launcher. Besides actually starting * it, update the database list to reflect the next time that another one will * need to be started on the selected database. The actual database choice is * left to do_start_worker. * launch the wrapper for worker from autovacuum launcher. * in addition to actually starting it, update the database linked list to reflect the next time you need to start another worker on the selected database. * the actual database selection is left to do_start_worker. * This routine is also expected to insert an entry into the database list if * the selected database was previously absent from the list. * this routine also wants to insert a new entry in the database linked list if the selected database previously appeared in the linked list. * / static voidlaunch_worker (TimestampTz now) {Oid dbid; 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. * iterate through the database linked list and update the corresponding entries. * if the database is not in the linked list, rebuild the linked list. * / dlist_foreach (iter, & DatabaseList) {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. * add autovacuum_naptime to the current time, * and use that time as the value of the new next_worker field for the database. * / avdb- > adl_next_worker = TimestampTzPlusMilliseconds (now, autovacuum_naptime * 1000); dlist_move_head (& DatabaseList, iter.cur); break;}} / * * If the database was not present in the database list, we rebuild * the list. It's possible that the database does not get into the * list anyway, for example if it's a database that doesn't have a * pgstat entry, but this is not a problem because we don't want to * schedule workers regularly into those in any case. * if the database is not in the database linked list, rebuild the linked list. * it is possible that the database has not entered the linked list, for example, the database does not have a pgstat entry entry, * but this is not a problem, because we do not want to schedule to these databases under any circumstances. * / if (! found) rebuild_database_list (dbid);}}

Do_start_worker

Select a DB. The algorithm is as follows:

Select the DB with the least recent cleanup, or the DB that needs to be cleaned to prevent XID from rollback resulting in data loss.

If there is a DB with the risk of XID rollback, then choose the oldest DB of datfrozenxid, no matter how many times that DB has done autovacuum.

Automatically ignore DB that is not connected (statistics are empty).

/ * do_start_worker * * Bare-bones procedure for starting an autovacuum worker from the launcher. * It determines what database to work on, sets up shared memory stuff and * signals postmaster to start the worker. It fails gracefully if invoked when * autovacuum_workers are already active. * start autovacuum worker. * determine which library to process, configure shared memory, and notify postmaster to start worker. * if autovacuum_workers is already active, startup fails. * * Return value is the OID of the database that the worker is going to process, * or InvalidOid if no worker was actually started. * return the database OID that is being processed. If the worker startup is not successful, return InvalidOid. * / static Oiddo_start_worker (void) {List * dblist;// database linked list ListCell * cell;// temporary variable / / typedef uint32 TransactionId; TransactionId xidForceLimit;// transaction id, unsigned 32bit integer MultiXactId multiForceLimit;// bool for_xid_wrap; bool for_multi_wrap; avw_dbase * avdb; TimestampTz current_time;// current time bool skipit = false / / did you skip it? Oid retval = database OID MemoryContext tmpcxt returned by InvalidOid;//, oldcxt;// memory context / * return quickly when there are no free workers * / / if there is no free worker (AutoVacuumShmem data structure maintenance), exit LWLockAcquire (AutovacuumLock, LW_SHARED); if (dlist_is_empty (& AutoVacuumShmem- > av_freeWorkers)) {LWLockRelease (AutovacuumLock); return InvalidOid } LWLockRelease (AutovacuumLock); / * * Create and switch to a temporary context to avoid leaking the memory * allocated for the database list. * memory context switching * / tmpcxt = AllocSetContextCreate (CurrentMemoryContext, "Start worker tmpcxt", ALLOCSET_DEFAULT_SIZES); oldcxt = MemoryContextSwitchTo (tmpcxt); / * use fresh stats * / / Statistics refresh autovac_refresh_stats () / * Get a list of databases * / / get database linked list dblist = get_database_list (); / * Determine the oldest datfrozenxid/relfrozenxid that we will allow to * pass without forcing a vacuum. (This limit can be tightened for * particular tables, but not loosened.) * determine the oldest datfrozenxid/relfrozenxid to determine if you need to force vacuum * / recentXid = ReadNewTransactionId (); xidForceLimit = recentXid-autovacuum_freeze_max_age / * ensure it's a "normal" XID, else TransactionIdPrecedes misbehaves * / * this can cause the limit to go backwards by 3, but that's OK * / # define FirstNormalTransactionId ((TransactionId) 3) / / less than 3 (regular XID), then subtract 3 if (xidForceLimit)

< FirstNormalTransactionId) xidForceLimit -= FirstNormalTransactionId; /* Also determine the oldest datminmxid we will consider. */ //确定需要考虑的最老的datminmxid //从MultiXactState->

Get MultiXactId recentMulti = ReadNextMultiXactId () in nextMXact; multiForceLimit = recentMulti-MultiXactMemberFreezeThreshold (); if (multiForceLimit)

< FirstMultiXactId) multiForceLimit -= FirstMultiXactId; /* * Choose a database to connect to. We pick the database that was least * recently auto-vacuumed, or one that needs vacuuming to prevent Xid * wraparound-related data loss. If any db at risk of Xid wraparound is * found, we pick the one with oldest datfrozenxid, independently of * autovacuum times; similarly we pick the one with the oldest datminmxid * if any is in MultiXactId wraparound. Note that those in Xid wraparound * danger are given more priority than those in multi wraparound danger. * * Note that a database with no stats entry is not considered, except for * Xid wraparound purposes. The theory is that if no one has ever * connected to it since the stats were last initialized, it doesn't need * vacuuming. * * XXX This could be improved if we had more info about whether it needs * vacuuming before connecting to it. Perhaps look through the pgstats * data for the database's tables? One idea is to keep track of the * number of new and dead tuples per database in pgstats. However it * isn't clear how to construct a metric that measures that and not cause * starvation for less busy databases. * 选择一个DB. * 算法:选择最近最小清理的DB,或者需要清理以防止XID回卷导致数据丢失的DB. * 如果存在XID回卷风险的DB,那么选择datfrozenxid最老的DB,而不管该DB做了多少次autovacuum. * 自动忽略没有连接过(统计信息为空)的DB. */ avdb = NULL;//待清理的DB for_xid_wrap = false;//xid回卷 for_multi_wrap = false; current_time = GetCurrentTimestamp();//当前时间 foreach(cell, dblist)//循环db链表 { avw_dbase *tmp = lfirst(cell); dlist_iter iter; /* Check to see if this one is at risk of wraparound */ //判断是否存在回卷风险? //TransactionIdPrecedes --- is id1 logically < id2? if (TransactionIdPrecedes(tmp->

Adw_frozenxid, xidForceLimit) {if (avdb = = NULL | | TransactionIdPrecedes (tmp- > adw_frozenxid, avdb- > adw_frozenxid)) avdb = tmp;// choose the older for_xid_wrap = true; continue } else if (for_xid_wrap) continue; / * ignore not-at-risk DBs * / else if (MultiXactIdPrecedes (tmp- > adw_minmulti, multiForceLimit)) {if (avdb = = NULL | | MultiXactIdPrecedes (tmp- > adw_minmulti, avdb- > adw_minmulti)) avdb = tmp; for_multi_wrap = true Continue;} else if (for_multi_wrap) continue; / * ignore not-at-risk DBs * / / * Find pgstat entry if any * / tmp- > adw_entry = pgstat_fetch_stat_dbentry (tmp- > adw_datid); / * Skip a database with no pgstat entry; it means it hasn't seen any * activity. * if no statistics are available, skip * / if (! tmp- > adw_entry) continue; / * * Also, skip a database that appears on the database list as having * been processed recently (less than autovacuum_naptime seconds ago). * We do this so that we don't select a database which we just * selected, but that pgstat hasn't gotten around to updating the last * autovacuum time yet. * skip the processed DB that appears in the database linked list (previously less than autovacuum_naptime seconds) * perform this operation to avoid selecting the DB * / skipit = false; dlist_reverse_foreach (iter, & DatabaseList) {avl_dbase * dbp = dlist_container (avl_dbase, adl_node, iter.cur) that you just selected. If (dbp- > adl_datid = = tmp- > adw_datid) {/ * * Skip this database if its next_worker value falls between * the current time and the current time plus naptime. * time not exceeded (naptime definition) * / if (! TimestampDifferenceExceeds (dbp- > adl_next_worker, current_time, 0) & &! TimestampDifferenceExceeds (current_time, dbp- > adl_next_worker) Autovacuum_naptime * 1000)) skipit = true Break;} if (skipit) continue; / * * Remember the db with oldest autovac time. (If we are here, both * tmp- > entry and db- > entry must be non-null.) * / if (avdb = = NULL | | tmp- > adw_entry- > last_autovac_time

< avdb->

Adw_entry- > last_autovac_time) avdb = tmp;} / * Found a database-- process it * / 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. * get a worker * / wptr = dlist_pop_head_node (& AutoVacuumShmem- > av_freeWorkers) from the free list; worker = dlist_container (WorkerInfoData, wi_links, wptr); worker- > wi_dboid = avdb- > adw_datid; worker- > wi_proc = NULL; worker- > wi_launchtime = GetCurrentTimestamp (); AutoVacuumShmem- > av_startingWorker = worker; LWLockRelease (AutovacuumLock) SendPostmasterSignal (PMSIGNAL_START_AUTOVAC_WORKER); retval = avdb- > adw_datid;} else if (skipit) {/ * * If we skipped all databases on the list, rebuild it, because it * probably contains a dropped database. * / rebuild_database_list (InvalidOid);} MemoryContextSwitchTo (oldcxt); MemoryContextDelete (tmpcxt); return retval;} / * * For callers that just need the XID part of the next transaction ID. * / static inline TransactionIdReadNewTransactionId (void) {return XidFromFullTransactionId (ReadNextFullTransactionId ());} # define XidFromFullTransactionId (x) ((uint32) (x) .value) / * * Read nextFullXid but don't allocate it. * / FullTransactionIdReadNextFullTransactionId (void) {FullTransactionId fullXid; LWLockAcquire (XidGenLock, LW_SHARED); fullXid = ShmemVariableCache- > nextFullXid; LWLockRelease (XidGenLock); return fullXid;} III. Tracking analysis

Start gdb, set signal processing, set breakpoint

(gdb) handle SIGINT print nostop passSIGINT is used by the debugger.Are you sure you want to change it? (y or n) Please answer y or n.SIGINT is used by the debugger.Are you sure you want to change it? (y or n) ySignal Stop Print Pass to program DescriptionSIGINT No Yes Yes Interrupt (gdb) b autovacuum.c:launch_workerBreakpoint 1 at 0x82f3e7: file autovacuum.c, line 1338. (gdb) b autovacuum.c:783Breakpoint 2 at 0x82e8f0: file autovacuum.c, line 783. (gdb) cContinuing.

Perform operations such as updates in other session

[pg12@localhost test] $psql-c "update tbl set id = 1;" Expanded display is used automatically.UPDATE 2000000 [pg12@localhost test] $psql-c "update T1 set id = 1;" Expanded display is used automatically.UPDATE 20000 [pg12@localhost test] $psql-c "update T2 set id = 1;" Expanded display is used automatically.UPDATE 10000 [pg12@localhost test] $psql-c "select txid_current ();" Expanded display is used automatically. Txid_current-2917 (1 row)

Continue in gdb console after 60s

Breakpoint 2, AutoVacLauncherMain (argc=0, argv=0x0) at autovacuum.c:783783 if (dlist_is_empty (& DatabaseList)) (gdb) n804 avdb = dlist_tail_element (avl_dbase, adl_node, & DatabaseList); (gdb) n810 if (TimestampDifferenceExceeds (avdb- > adl_next_worker, (gdb) 812 launch_worker (current_time)) (gdb) p * avdb$1 = {adl_datid = 16384, adl_next_worker = 628852948486950, adl_score = 0, adl_node = {prev = 0xfd9880, next = 0xfd9880}} (gdb) stepBreakpoint 1, launch_worker (now=628853296722794) at autovacuum.c:13381338 dbid = do_start_worker ()

Enter do_start_worker

(gdb) stepdo_start_worker () at autovacuum.c:11281128 bool skipit = false; (gdb) n1129 Oid retval = InvalidOid; (gdb) 1134 LWLockAcquire (AutovacuumLock, LW_SHARED); (gdb) 1135 if (& AutoVacuumShmem- > av_freeWorkers))

View the AutoVacuumShmem structure

(gdb) p * AutoVacuumShmem$2 = {av_signal = {0,0}, av_launcherpid = 5476, av_freeWorkers = {head = {prev = 0x7f8ccf1a4938, next = 0x7f8ccf1a49b8}}, av_runningWorkers = {head = {prev = 0x7f8ccf1a3520, next = 0x7f8ccf1a3520}}, av_startingWorker = 0x0, av_workItems = {{avw_type = AVW_BRINSummarizeRange, avw_used = false, avw_active = false, avw_database = 0, avw_relation = 0, avw_blockNumber = 0}} (gdb) n1140 LWLockRelease (AutovacuumLock) (gdb) p AutoVacuumShmem- > av_runningWorkers$3 = {head = {prev = 0x7f8ccf1a3520, next = 0x7f8ccf1a3520}} (gdb) n

Find the database that needs vacuum

1146 tmpcxt = AllocSetContextCreate (CurrentMemoryContext, (gdb) 1149 oldcxt = MemoryContextSwitchTo (tmpcxt); (gdb) 1152 autovac_refresh_stats (); (gdb) n1155 dblist = get_database_list (); (gdb) 1162 recentXid = ReadNewTransactionId (); (gdb) p * dblist$8 = {type = T_List, length = 5, head = 0x2382d48, tail = 0x2382f90} (gdb) n1163 xidForceLimit = recentXid-autovacuum_freeze_max_age (gdb) p recentXid$9 = 2917 (gdb) p autovacuum_freeze_max_age$10 = 200000000 (gdb) n1166 if (xidForceLimit)

< FirstNormalTransactionId)(gdb) p xidForceLimit$11 = 4094970213(gdb) p FirstNormalTransactionId$12 = 3(gdb) n1170 recentMulti = ReadNextMultiXactId();(gdb) 1171 multiForceLimit = recentMulti - MultiXactMemberFreezeThreshold();(gdb) 1172 if (multiForceLimit < FirstMultiXactId)(gdb) p recentMulti$13 = 1(gdb) p MultiXactMemberFreezeThreshold()$14 = 400000000(gdb) n1196 avdb = NULL;(gdb) 1197 for_xid_wrap = false;(gdb) 1198 for_multi_wrap = false;(gdb) 1199 current_time = GetCurrentTimestamp();(gdb) 1200 foreach(cell, dblist)(gdb) 1202 avw_dbase *tmp = lfirst(cell);(gdb) 1206 if (TransactionIdPrecedes(tmp->

Adw_frozenxid, xidForceLimit) (gdb) p * tmp--> this is the postgres database $15 = {adw_datid = 13591, adw_name = 0x2382d20 "postgres", adw_frozenxid = 479, adw_minmulti = 1, adw_entry = 0x0} (gdb) n1215 else if (for_xid_wrap) (gdb) 1217 else if (MultiXactIdPrecedes (tmp- > adw_minmulti) MultiForceLimit) (gdb) 1225 else if (for_multi_wrap) (gdb) 1229 tmp- > adw_entry = pgstat_fetch_stat_dbentry (tmp- > adw_datid) (gdb) 1235 if (! tmp- > adw_entry) (gdb) 1236 continue; (gdb) 1200 foreach (cell, dblist) (gdb) 1202 avw_dbase * tmp = lfirst (cell) (gdb) 1206 if (TransactionIdPrecedes (tmp- > adw_frozenxid, xidForceLimit)) (gdb) p * tmp--> this is the testdb database $16 = {adw_datid = 16384, adw_name = 0x2382de0 "testdb", adw_frozenxid = 531, adw_minmulti = 1, adw_entry = 0x0} (gdb) p tmp- > adw_frozenxid$17 = 4094970213 (gdb) p xidForceLimit$18 = 4094970213 (gdb) n1215 else if (for_xid_wrap) (gdb) 1217 else if (MultiXactIdPrecedes (tmp- > adw_minmulti) MultiForceLimit) (gdb) 1225 else if (for_multi_wrap) (gdb) 1229 tmp- > adw_entry = pgstat_fetch_stat_dbentry (tmp- > adw_datid) (gdb) 1235 if (! tmp- > adw_entry) (gdb) 1245 skipit = false; (gdb) 1247 dlist_reverse_foreach (iter, & DatabaseList) (gdb) 1249 avl_dbase * dbp = dlist_container (avl_dbase, adl_node, iter.cur) (gdb) 1251 if (dbp- > adl_datid = = tmp- > adw_datid) (gdb) 1257 if (! TimestampDifferenceExceeds (dbp- > adl_next_worker, (gdb) 1267 if (skipit) (gdb) 1274 if (avdb = = NULL | | (gdb) 1276 avdb = tmp; (gdb) n1200 foreach (cell, dblist) (gdb) 1202 avw_dbase * tmp = lfirst (cell) (gdb) 1206 if (TransactionIdPrecedes (tmp- > adw_frozenxid, xidForceLimit)) (gdb) 1215 else if (for_xid_wrap) (gdb) p * tmp$19 = {adw_datid = 1, adw_name = 0x2382e60 "template1", adw_frozenxid = 479,adw_minmulti = 1, adw_entry = 0x0} (gdb) n1217 else if (MultiXactIdPrecedes (tmp- > adw_minmulti) MultiForceLimit) (gdb) 1225 else if (for_multi_wrap) (gdb) 1229 tmp- > adw_entry = pgstat_fetch_stat_dbentry (tmp- > adw_datid) (gdb) 1235 if (! tmp- > adw_entry) (gdb) 1236 continue;-- > if there is no statistical information, ignore (gdb) 1200 foreach (cell, dblist) (gdb) 1202 avw_dbase * tmp = lfirst (cell) (gdb) 1206 if (TransactionIdPrecedes (tmp- > adw_frozenxid, xidForceLimit)) (gdb) 1215 else if (for_xid_wrap) (gdb) 1217 else if (MultiXactIdPrecedes (tmp- > adw_minmulti, multiForceLimit)) (gdb) 1225 else if (for_multi_wrap) (gdb) 1229 tmp- > adw_entry = pgstat_fetch_stat_dbentry (tmp- > adw_datid) (gdb) 1235 if (! tmp- > adw_entry) (gdb) 1236 continue; (gdb) 1200 foreach (cell, dblist) (gdb) 1202 avw_dbase * tmp = lfirst (cell) (gdb) 1206 if (TransactionIdPrecedes (tmp- > adw_frozenxid, xidForceLimit)) (gdb) 1215 else if (for_xid_wrap) (gdb) 1217 else if (MultiXactIdPrecedes (tmp- > adw_minmulti, multiForceLimit)) (gdb) 1225 else if (for_multi_wrap) (gdb) 1229 tmp- > adw_entry = pgstat_fetch_stat_dbentry (tmp- > adw_datid) (gdb) 1235 if (! tmp- > adw_entry) (gdb) 1236 continue; (gdb) 1200 foreach (cell, dblist) (gdb)

After completing the db traversal and finding the database to be processed-> testdb, the next step is to find the free worker and start the worker to execute vacuum

1280 if (avdb! = NULL) (gdb) 1285 LWLockAcquire (AutovacuumLock, LW_EXCLUSIVE); (gdb) 1291 wptr = dlist_pop_head_node (& AutoVacuumShmem- > av_freeWorkers); (gdb) 1293 worker = dlist_container (WorkerInfoData, wi_links, wptr); (gdb) p * wptr$20 = {prev = 0x7f8ccf1a3510, next = 0x7f8ccf1a4978} (gdb) n1294 worker- > wi_dboid = avdb- > adw_datid (gdb) p * worker$21 = {wi_links = {prev = 0x7f8ccf1a3510, next = 0x7f8ccf1a4978}, wi_dboid = 0, wi_tableoid = 0, wi_proc = 0x0, wi_launchtime = 0, wi_dobalance = false, wi_sharedrel = false, wi_cost_delay = 0, wi_cost_limit = 0, wi_cost_limit_base = 0} (gdb) n1295 worker- > wi_proc = NULL; (gdb) 1296 worker- > wi_launchtime = GetCurrentTimestamp () (gdb) 1298 AutoVacuumShmem- > av_startingWorker = worker; (gdb) 1300 LWLockRelease (AutovacuumLock); (gdb) 1302 SendPostmasterSignal (PMSIGNAL_START_AUTOVAC_WORKER) (gdb) p * AutoVacuumShmem$22 = {av_signal = {0,0}, av_launcherpid = 5476, av_freeWorkers = {head = {prev = 0x7f8ccf1a4938, next = 0x7f8ccf1a4978}}, av_runningWorkers = {head = {prev = 0x7f8ccf1a3520, next = 0x7f8ccf1a3520}}, av_startingWorker = 0x7f8ccf1a49b8, av_workItems = {{avw_type = AVW_BRINSummarizeRange, avw_used = false, avw_active = false, avw_database = 0, avw_relation = 0 Avw_blockNumber = 0}} (gdb) n1304 retval = avdb- > adw_datid (gdb) Program received signal SIGUSR2, User defined signal 2.do_start_worker () at autovacuum.c:13041304 retval = avdb- > adw_datid; (gdb) avl_sigusr2_handler (postgres_signal_arg=32764) at autovacuum.c:14051405 {(gdb)

DONE!

IV. Reference materials

PG Source Code

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 219

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Database

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report