Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitaa903cf

Browse files
committed
Remove pg_vlock locking from VACUUM, allowing multiple VACUUMs to run in
parallel --- and, not incidentally, removing a common reason for needingmanual cleanup by the DB admin after a crash. Remove initial globaldelete of pg_statistics rows in VACUUM ANALYZE; this was not only badfor performance of other backends that had to run without stats for awhile, but it was fundamentally broken because it was done outside anytransaction. Surprising we didn't see more consequences of that.Detect attempt to run VACUUM inside a transaction block. Check forquery cancel request before starting vacuum of each table. Clean upvacuum's private portal storage if vacuum is aborted.
1 parentd2914c3 commitaa903cf

File tree

1 file changed

+68
-96
lines changed

1 file changed

+68
-96
lines changed

‎src/backend/commands/vacuum.c

Lines changed: 68 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
*
88
*
99
* IDENTIFICATION
10-
* $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.126 1999/11/25 00:15:57 momjian Exp $
10+
* $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.127 1999/11/28 02:10:01 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -21,6 +21,7 @@
2121

2222
#include"access/genam.h"
2323
#include"access/heapam.h"
24+
#include"access/xact.h"
2425
#include"catalog/catalog.h"
2526
#include"catalog/catname.h"
2627
#include"catalog/index.h"
@@ -33,6 +34,7 @@
3334
#include"parser/parse_oper.h"
3435
#include"storage/sinval.h"
3536
#include"storage/smgr.h"
37+
#include"tcop/tcopprot.h"
3638
#include"utils/builtins.h"
3739
#include"utils/inval.h"
3840
#include"utils/portal.h"
@@ -46,7 +48,6 @@
4648
#include<sys/resource.h>
4749
#endif
4850

49-
/* #include <port-protos.h> *//* Why? */
5051

5152
boolVacuumRunning= false;
5253

@@ -80,11 +81,10 @@ static void vc_scanoneind(Relation indrel, int num_tuples);
8081
staticvoidvc_attrstats(Relationonerel,VRelStats*vacrelstats,HeapTupletuple);
8182
staticvoidvc_bucketcpy(Form_pg_attributeattr,Datumvalue,Datum*bucket,int*bucket_len);
8283
staticvoidvc_updstats(Oidrelid,intnum_pages,intnum_tuples,boolhasindex,VRelStats*vacrelstats);
83-
staticvoidvc_delhilowstats(Oidrelid,intattcnt,int*attnums);
84+
staticvoidvc_delstats(Oidrelid,intattcnt,int*attnums);
8485
staticVPageDescrvc_tidreapped(ItemPointeritemptr,VPageListvpl);
8586
staticvoidvc_reappage(VPageListvpl,VPageDescrvpc);
8687
staticvoidvc_vpinsert(VPageListvpl,VPageDescrvpnew);
87-
staticvoidvc_free(VRelListvrl);
8888
staticvoidvc_getindices(Oidrelid,int*nindices,Relation**Irel);
8989
staticvoidvc_clsindices(intnindices,Relation*Irel);
9090
staticvoidvc_mkindesc(Relationonerel,intnindices,Relation*Irel,IndDesc**Idesc);
@@ -98,76 +98,73 @@ static bool vc_enough_space(VPageDescr vpd, Size len);
9898
void
9999
vacuum(char*vacrel,boolverbose,boolanalyze,List*va_spec)
100100
{
101-
char*pname;
102-
MemoryContextold;
103-
PortalVariableMemorypmem;
104101
NameDataVacRel;
102+
PortalVariableMemorypmem;
103+
MemoryContextold;
105104
List*le;
106105
List*va_cols=NIL;
107106

107+
if (va_spec!=NIL&& !analyze)
108+
elog(ERROR,"Can't vacuum columns, only tables. You can 'vacuum analyze' columns.");
109+
108110
/*
109-
* Create a portal for safe memory across transctions.We need to
110-
* palloc the name space for it because our hash function expects the
111-
* name to be on a longword boundary. CreatePortal copies the name to
112-
* safe storage for us.
111+
* We cannot run VACUUM inside a user transaction block; if we were
112+
* inside a transaction, then our commit- and start-transaction-command
113+
* calls would not have the intended effect! Furthermore, the forced
114+
* commit that occurs before truncating the relation's file would have
115+
* the effect of committing the rest of the user's transaction too,
116+
* which would certainly not be the desired behavior.
113117
*/
114-
pname= (char*)palloc(strlen(VACPNAME)+1);
115-
strcpy(pname,VACPNAME);
116-
vc_portal=CreatePortal(pname);
117-
pfree(pname);
118+
if (IsTransactionBlock())
119+
elog(ERROR,"VACUUM cannot run inside a BEGIN/END block");
120+
121+
/* initialize vacuum cleaner, particularly vc_portal */
122+
vc_init();
118123

119124
if (verbose)
120125
MESSAGE_LEVEL=NOTICE;
121126
else
122127
MESSAGE_LEVEL=DEBUG;
123128

124-
/* vacrel gets de-allocated on transaction commit */
129+
/* vacrel gets de-allocated on transaction commit, so copy it */
125130
if (vacrel)
126131
strcpy(NameStr(VacRel),vacrel);
127132

133+
/* must also copy the column list, if any, to safe storage */
128134
pmem=PortalGetVariableMemory(vc_portal);
129135
old=MemoryContextSwitchTo((MemoryContext)pmem);
130-
131-
if (va_spec!=NIL&& !analyze)
132-
elog(ERROR,"Can't vacuum columns, only tables. You can 'vacuum analyze' columns.");
133-
134136
foreach(le,va_spec)
135137
{
136138
char*col= (char*)lfirst(le);
137-
char*dest;
138139

139-
dest= (char*)palloc(strlen(col)+1);
140-
strcpy(dest,col);
141-
va_cols=lappend(va_cols,dest);
140+
va_cols=lappend(va_cols,pstrdup(col));
142141
}
143142
MemoryContextSwitchTo(old);
144143

145-
/* initialize vacuum cleaner */
146-
vc_init();
147-
148144
/* vacuum the database */
149145
if (vacrel)
150146
vc_vacuum(&VacRel,analyze,va_cols);
151147
else
152148
vc_vacuum(NULL,analyze,NIL);
153149

154-
PortalDestroy(&vc_portal);
155-
156150
/* clean up */
157151
vc_shutdown();
158152
}
159153

160154
/*
161155
*vc_init(), vc_shutdown() -- start up and shut down the vacuum cleaner.
162156
*
163-
*We run exactly one vacuum cleaner at a time. We use the file system
164-
*to guarantee an exclusive lock on vacuuming, since a single vacuum
165-
*cleaner instantiation crosses transaction boundaries, and we'd lose
166-
*postgres-style locks at the end of every transaction.
157+
*Formerly, there was code here to prevent more than one VACUUM from
158+
*executing concurrently in the same database. However, there's no
159+
*good reason to prevent that, and manually removing lockfiles after
160+
*a vacuum crash was a pain for dbadmins. So, forget about lockfiles,
161+
*and just rely on the exclusive lock we grab on each target table
162+
*to ensure that there aren't two VACUUMs running on the same table
163+
*at the same time.
167164
*
168165
*The strangeness with committing and starting transactions in the
169166
*init and shutdown routines is due to the fact that the vacuum cleaner
170-
*is invoked viaa sql command, and so is already executing inside
167+
*is invoked viaan SQL command, and so is already executing inside
171168
*a transaction.We need to leave ourselves in a predictable state
172169
*on entry and exit to the vacuum cleaner. We commit the transaction
173170
*started in PostgresMain() inside vc_init(), and start one in
@@ -177,27 +174,23 @@ vacuum(char *vacrel, bool verbose, bool analyze, List *va_spec)
177174
staticvoid
178175
vc_init()
179176
{
180-
intfd;
177+
char*pname;
181178

182-
#ifndef__CYGWIN32__
183-
if ((fd=open("pg_vlock",O_CREAT |O_EXCL,0600))<0)
184-
#else
185-
if ((fd=open("pg_vlock",O_CREAT |O_EXCL |O_BINARY,0600))<0)
186-
#endif
187-
{
188-
elog(ERROR,"Can't create lock file. Is another vacuum cleaner running?\n\
189-
\tIf not, you may remove the pg_vlock file in the %s\n\
190-
\tdirectory",DatabasePath);
191-
}
192-
close(fd);
179+
/*
180+
* Create a portal for safe memory across transactions. We need to
181+
* palloc the name space for it because our hash function expects the
182+
* name to be on a longword boundary. CreatePortal copies the name to
183+
* safe storage for us.
184+
*/
185+
pname=pstrdup(VACPNAME);
186+
vc_portal=CreatePortal(pname);
187+
pfree(pname);
193188

194189
/*
195-
* By here, exclusive open on the lock file succeeded.If we abort
196-
* for any reason during vacuuming, we need to remove the lock file.
190+
* Set flag to indicate that vc_portal must be removed after an error.
197191
* This global variable is checked in the transaction manager on xact
198192
* abort, and the routine vc_abort() is called if necessary.
199193
*/
200-
201194
VacuumRunning= true;
202195

203196
/* matches the StartTransaction in PostgresMain() */
@@ -221,25 +214,28 @@ vc_shutdown()
221214
*/
222215
unlink(RELCACHE_INIT_FILENAME);
223216

224-
/* remove the vacuum cleaner lock file */
225-
if (unlink("pg_vlock")<0)
226-
elog(ERROR,"vacuum: can't destroy lock file!");
217+
/*
218+
* Release our portal for cross-transaction memory.
219+
*/
220+
PortalDestroy(&vc_portal);
227221

228222
/* okay, we're done */
229223
VacuumRunning= false;
230224

231225
/* matches the CommitTransaction in PostgresMain() */
232226
StartTransactionCommand();
233-
234227
}
235228

236229
void
237230
vc_abort()
238231
{
239-
/* on abort, remove the vacuum cleaner lock file */
240-
unlink("pg_vlock");
241-
232+
/* Clear flag first, to avoid recursion if PortalDestroy elog's */
242233
VacuumRunning= false;
234+
235+
/*
236+
* Release our portal for cross-transaction memory.
237+
*/
238+
PortalDestroy(&vc_portal);
243239
}
244240

245241
/*
@@ -259,14 +255,9 @@ vc_vacuum(NameData *VacRelP, bool analyze, List *va_cols)
259255
/* get list of relations */
260256
vrl=vc_getrels(VacRelP);
261257

262-
if (analyze&&VacRelP==NULL&&vrl!=NULL)
263-
vc_delhilowstats(InvalidOid,0,NULL);
264-
265258
/* vacuum each heap relation */
266259
for (cur=vrl;cur!= (VRelList)NULL;cur=cur->vrl_next)
267260
vc_vacone(cur->vrl_relid,analyze,va_cols);
268-
269-
vc_free(vrl);
270261
}
271262

272263
staticVRelList
@@ -381,6 +372,13 @@ vc_vacone(Oid relid, bool analyze, List *va_cols)
381372

382373
StartTransactionCommand();
383374

375+
/*
376+
* Check for user-requested abort. Note we want this to be inside
377+
* a transaction, so xact.c doesn't issue useless NOTICE.
378+
*/
379+
if (QueryCancel)
380+
CancelQuery();
381+
384382
/*
385383
* Race condition -- if the pg_class tuple has gone away since the
386384
* last time we saw it, we don't need to vacuum it.
@@ -500,7 +498,8 @@ vc_vacone(Oid relid, bool analyze, List *va_cols)
500498
stats->outfunc=InvalidOid;
501499
}
502500
vacrelstats->va_natts=attr_cnt;
503-
vc_delhilowstats(relid, ((attnums) ?attr_cnt :0),attnums);
501+
/* delete existing pg_statistics rows for relation */
502+
vc_delstats(relid, ((attnums) ?attr_cnt :0),attnums);
504503
if (attnums)
505504
pfree(attnums);
506505
}
@@ -2453,7 +2452,7 @@ vc_updstats(Oid relid, int num_pages, int num_tuples, bool hasindex, VRelStats *
24532452
CatalogIndexInsert(irelations,Num_pg_statistic_indices,sd,stup);
24542453
CatalogCloseIndices(Num_pg_statistic_indices,irelations);
24552454
}
2456-
2455+
24572456
/* release allocated space */
24582457
pfree(DatumGetPointer(values[Anum_pg_statistic_stacommonval-1]));
24592458
pfree(DatumGetPointer(values[Anum_pg_statistic_staloval-1]));
@@ -2478,11 +2477,12 @@ vc_updstats(Oid relid, int num_pages, int num_tuples, bool hasindex, VRelStats *
24782477
}
24792478

24802479
/*
2481-
*vc_delhilowstats() -- delete pg_statistics rows
2480+
*vc_delstats() -- delete pg_statistics rows for a relation
24822481
*
2482+
*If a list of attribute numbers is given, only zap stats for those attrs.
24832483
*/
24842484
staticvoid
2485-
vc_delhilowstats(Oidrelid,intattcnt,int*attnums)
2485+
vc_delstats(Oidrelid,intattcnt,int*attnums)
24862486
{
24872487
Relationpgstatistic;
24882488
HeapScanDescscan;
@@ -2491,15 +2491,9 @@ vc_delhilowstats(Oid relid, int attcnt, int *attnums)
24912491

24922492
pgstatistic=heap_openr(StatisticRelationName,RowExclusiveLock);
24932493

2494-
if (relid!=InvalidOid)
2495-
{
2496-
ScanKeyEntryInitialize(&key,0x0,Anum_pg_statistic_starelid,
2497-
F_OIDEQ,
2498-
ObjectIdGetDatum(relid));
2499-
scan=heap_beginscan(pgstatistic, false,SnapshotNow,1,&key);
2500-
}
2501-
else
2502-
scan=heap_beginscan(pgstatistic, false,SnapshotNow,0,NULL);
2494+
ScanKeyEntryInitialize(&key,0x0,Anum_pg_statistic_starelid,
2495+
F_OIDEQ,ObjectIdGetDatum(relid));
2496+
scan=heap_beginscan(pgstatistic, false,SnapshotNow,1,&key);
25032497

25042498
while (HeapTupleIsValid(tuple=heap_getnext(scan,0)))
25052499
{
@@ -2572,28 +2566,6 @@ vc_vpinsert(VPageList vpl, VPageDescr vpnew)
25722566

25732567
}
25742568

2575-
staticvoid
2576-
vc_free(VRelListvrl)
2577-
{
2578-
VRelListp_vrl;
2579-
MemoryContextold;
2580-
PortalVariableMemorypmem;
2581-
2582-
pmem=PortalGetVariableMemory(vc_portal);
2583-
old=MemoryContextSwitchTo((MemoryContext)pmem);
2584-
2585-
while (vrl!= (VRelList)NULL)
2586-
{
2587-
2588-
/* free rel list entry */
2589-
p_vrl=vrl;
2590-
vrl=vrl->vrl_next;
2591-
pfree(p_vrl);
2592-
}
2593-
2594-
MemoryContextSwitchTo(old);
2595-
}
2596-
25972569
staticvoid*
25982570
vc_find_eq(void*bot,intnelem,intsize,void*elm,
25992571
int (*compar) (constvoid*,constvoid*))

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp