|
65 | 65 | #include "commands/dbcommands.h"
|
66 | 66 | #include "commands/progress.h"
|
67 | 67 | #include "commands/vacuum.h"
|
| 68 | +#include "executor/instrument.h" |
68 | 69 | #include "miscadmin.h"
|
69 | 70 | #include "optimizer/paths.h"
|
70 | 71 | #include "pgstat.h"
|
|
137 | 138 | #define PARALLEL_VACUUM_KEY_SHARED 1
|
138 | 139 | #define PARALLEL_VACUUM_KEY_DEAD_TUPLES 2
|
139 | 140 | #define PARALLEL_VACUUM_KEY_QUERY_TEXT 3
|
| 141 | +#define PARALLEL_VACUUM_KEY_BUFFER_USAGE 4 |
140 | 142 |
|
141 | 143 | /*
|
142 | 144 | * Macro to check if we are in a parallel vacuum. If true, we are in the
|
@@ -270,6 +272,9 @@ typedef struct LVParallelState
|
270 | 272 | /* Shared information among parallel vacuum workers */
|
271 | 273 | LVShared *lvshared;
|
272 | 274 |
|
| 275 | + /* Points to buffer usage area in DSM */ |
| 276 | + BufferUsage *buffer_usage; |
| 277 | + |
273 | 278 | /*
|
274 | 279 | * The number of indexes that support parallel index bulk-deletion and
|
275 | 280 | * parallel index cleanup respectively.
|
@@ -2137,8 +2142,20 @@ lazy_parallel_vacuum_indexes(Relation *Irel, IndexBulkDeleteResult **stats,
|
2137 | 2142 | parallel_vacuum_index(Irel, stats, lps->lvshared,
|
2138 | 2143 | vacrelstats->dead_tuples, nindexes, vacrelstats);
|
2139 | 2144 |
|
2140 |
| - /* Wait for all vacuum workers to finish */ |
2141 |
| - WaitForParallelWorkersToFinish(lps->pcxt); |
| 2145 | + /* |
| 2146 | + * Next, accumulate buffer usage. (This must wait for the workers to |
| 2147 | + * finish, or we might get incomplete data.) |
| 2148 | + */ |
| 2149 | + if (nworkers > 0) |
| 2150 | + { |
| 2151 | + int i; |
| 2152 | + |
| 2153 | + /* Wait for all vacuum workers to finish */ |
| 2154 | + WaitForParallelWorkersToFinish(lps->pcxt); |
| 2155 | + |
| 2156 | + for (i = 0; i < lps->pcxt->nworkers_launched; i++) |
| 2157 | + InstrAccumParallelQuery(&lps->buffer_usage[i]); |
| 2158 | + } |
2142 | 2159 |
|
2143 | 2160 | /*
|
2144 | 2161 | * Carry the shared balance value to heap scan and disable shared costing
|
@@ -3153,6 +3170,7 @@ begin_parallel_vacuum(Oid relid, Relation *Irel, LVRelStats *vacrelstats,
|
3153 | 3170 | ParallelContext *pcxt;
|
3154 | 3171 | LVShared *shared;
|
3155 | 3172 | LVDeadTuples *dead_tuples;
|
| 3173 | + BufferUsage *buffer_usage; |
3156 | 3174 | bool *can_parallel_vacuum;
|
3157 | 3175 | long maxtuples;
|
3158 | 3176 | char *sharedquery;
|
@@ -3236,6 +3254,17 @@ begin_parallel_vacuum(Oid relid, Relation *Irel, LVRelStats *vacrelstats,
|
3236 | 3254 | shm_toc_estimate_chunk(&pcxt->estimator, est_deadtuples);
|
3237 | 3255 | shm_toc_estimate_keys(&pcxt->estimator, 1);
|
3238 | 3256 |
|
| 3257 | + /* |
| 3258 | + * Estimate space for BufferUsage -- PARALLEL_VACUUM_KEY_BUFFER_USAGE. |
| 3259 | + * |
| 3260 | + * If there are no extensions loaded that care, we could skip this. We |
| 3261 | + * have no way of knowing whether anyone's looking at pgBufferUsage, so do |
| 3262 | + * it unconditionally. |
| 3263 | + */ |
| 3264 | + shm_toc_estimate_chunk(&pcxt->estimator, |
| 3265 | + mul_size(sizeof(BufferUsage), pcxt->nworkers)); |
| 3266 | + shm_toc_estimate_keys(&pcxt->estimator, 1); |
| 3267 | + |
3239 | 3268 | /* Finally, estimate PARALLEL_VACUUM_KEY_QUERY_TEXT space */
|
3240 | 3269 | querylen = strlen(debug_query_string);
|
3241 | 3270 | shm_toc_estimate_chunk(&pcxt->estimator, querylen + 1);
|
@@ -3270,6 +3299,12 @@ begin_parallel_vacuum(Oid relid, Relation *Irel, LVRelStats *vacrelstats,
|
3270 | 3299 | shm_toc_insert(pcxt->toc, PARALLEL_VACUUM_KEY_DEAD_TUPLES, dead_tuples);
|
3271 | 3300 | vacrelstats->dead_tuples = dead_tuples;
|
3272 | 3301 |
|
| 3302 | + /* Allocate space for each worker's BufferUsage; no need to initialize */ |
| 3303 | + buffer_usage = shm_toc_allocate(pcxt->toc, |
| 3304 | + mul_size(sizeof(BufferUsage), pcxt->nworkers)); |
| 3305 | + shm_toc_insert(pcxt->toc, PARALLEL_VACUUM_KEY_BUFFER_USAGE, buffer_usage); |
| 3306 | + lps->buffer_usage = buffer_usage; |
| 3307 | + |
3273 | 3308 | /* Store query string for workers */
|
3274 | 3309 | sharedquery = (char *) shm_toc_allocate(pcxt->toc, querylen + 1);
|
3275 | 3310 | memcpy(sharedquery, debug_query_string, querylen + 1);
|
@@ -3399,6 +3434,7 @@ parallel_vacuum_main(dsm_segment *seg, shm_toc *toc)
|
3399 | 3434 | Relation *indrels;
|
3400 | 3435 | LVShared *lvshared;
|
3401 | 3436 | LVDeadTuples *dead_tuples;
|
| 3437 | + BufferUsage *buffer_usage; |
3402 | 3438 | int nindexes;
|
3403 | 3439 | char *sharedquery;
|
3404 | 3440 | IndexBulkDeleteResult **stats;
|
@@ -3468,10 +3504,17 @@ parallel_vacuum_main(dsm_segment *seg, shm_toc *toc)
|
3468 | 3504 | errcallback.previous = error_context_stack;
|
3469 | 3505 | error_context_stack = &errcallback;
|
3470 | 3506 |
|
| 3507 | + /* Prepare to track buffer usage during parallel execution */ |
| 3508 | + InstrStartParallelQuery(); |
| 3509 | + |
3471 | 3510 | /* Process indexes to perform vacuum/cleanup */
|
3472 | 3511 | parallel_vacuum_index(indrels, stats, lvshared, dead_tuples, nindexes,
|
3473 | 3512 | &vacrelstats);
|
3474 | 3513 |
|
| 3514 | + /* Report buffer usage during parallel execution */ |
| 3515 | + buffer_usage = shm_toc_lookup(toc, PARALLEL_VACUUM_KEY_BUFFER_USAGE, false); |
| 3516 | + InstrEndParallelQuery(&buffer_usage[ParallelWorkerNumber]); |
| 3517 | + |
3475 | 3518 | /* Pop the error context stack */
|
3476 | 3519 | error_context_stack = errcallback.previous;
|
3477 | 3520 |
|
|
0 commit comments