Remove old-style VACUUM FULL (which was known for a little while as
VACUUM FULL INPLACE), along with a boatload of subsidiary code and complexity. Per discussion, the use case for this method of vacuuming is no longer large enough to justify maintaining it; not to mention that we don't wish to invest the work that would be needed to make it play nicely with Hot Standby. Aside from the code directly related to old-style VACUUM FULL, this commit removes support for certain WAL record types that could only be generated within VACUUM FULL, redirect-pointer removal in heap_page_prune, and nontransactional generation of cache invalidation sinval messages (the last being the sticking point for Hot Standby). We still have to retain all code that copes with finding HEAP_MOVED_OFF and HEAP_MOVED_IN flag bits on existing tuples. This can't be removed as long as we want to support in-place update from pre-9.0 databases.
This commit is contained in:
parent
1ddc2703a9
commit
0a469c8769
|
@ -1,4 +1,4 @@
|
|||
<!-- $PostgreSQL: pgsql/doc/src/sgml/indexam.sgml,v 2.32 2010/01/01 21:53:49 tgl Exp $ -->
|
||||
<!-- $PostgreSQL: pgsql/doc/src/sgml/indexam.sgml,v 2.33 2010/02/08 04:33:51 tgl Exp $ -->
|
||||
|
||||
<chapter id="indexam">
|
||||
<title>Index Access Method Interface Definition</title>
|
||||
|
@ -577,11 +577,10 @@ amrestrpos (IndexScanDesc scan);
|
|||
The core <productname>PostgreSQL</productname> system obtains
|
||||
<literal>AccessShareLock</> on the index during an index scan, and
|
||||
<literal>RowExclusiveLock</> when updating the index (including plain
|
||||
<command>VACUUM</>). Since these lock
|
||||
types do not conflict, the access method is responsible for handling any
|
||||
fine-grained locking it might need. An exclusive lock on the index as a whole
|
||||
will be taken only during index creation, destruction,
|
||||
<command>REINDEX</>, or <command>VACUUM FULL</>.
|
||||
<command>VACUUM</>). Since these lock types do not conflict, the access
|
||||
method is responsible for handling any fine-grained locking it might need.
|
||||
An exclusive lock on the index as a whole will be taken only during index
|
||||
creation, destruction, or <command>REINDEX</>.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<!-- $PostgreSQL: pgsql/doc/src/sgml/maintenance.sgml,v 1.98 2010/02/03 17:25:05 momjian Exp $ -->
|
||||
<!-- $PostgreSQL: pgsql/doc/src/sgml/maintenance.sgml,v 1.99 2010/02/08 04:33:51 tgl Exp $ -->
|
||||
|
||||
<chapter id="maintenance">
|
||||
<title>Routine Database Maintenance Tasks</title>
|
||||
|
@ -123,9 +123,7 @@
|
|||
<command>ALTER TABLE</command> while it is being vacuumed.)
|
||||
<command>VACUUM FULL</> requires exclusive lock on the table it is
|
||||
working on, and therefore cannot be done in parallel with other use
|
||||
of the table. Another disadvantage of <command>VACUUM FULL</> is that
|
||||
while it reduces table size, it does not reduce index size proportionally;
|
||||
in fact it can make indexes <emphasis>larger</>. Generally, therefore,
|
||||
of the table. Generally, therefore,
|
||||
administrators should strive to use standard <command>VACUUM</> and
|
||||
avoid <command>VACUUM FULL</>.
|
||||
</para>
|
||||
|
@ -166,13 +164,10 @@
|
|||
system, except in the special case where one or more pages at the
|
||||
end of a table become entirely free and an exclusive table lock can be
|
||||
easily obtained. In contrast, <command>VACUUM FULL</> actively compacts
|
||||
tables by moving row versions to earlier pages. It is thus able to
|
||||
force pages at the end of the table to become entirely free, whereupon
|
||||
it will return them to the operating system. However, if many rows
|
||||
must be moved, this can take a long time. Also, moving a row requires
|
||||
transiently making duplicate index entries for it (the entry pointing
|
||||
to its new location must be made before the old entry can be removed);
|
||||
so moving a lot of rows this way causes severe index bloat.
|
||||
tables by writing a complete new version of the table file with no dead
|
||||
space. This minimizes the size of the table, but can take a long time.
|
||||
It also requires extra disk space for the new copy of the table, until
|
||||
the operation completes.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
|
@ -220,20 +215,19 @@
|
|||
|
||||
<tip>
|
||||
<para>
|
||||
Neither form of <command>VACUUM</> is entirely satisfactory when
|
||||
Plain <command>VACUUM</> may not be satisfactory when
|
||||
a table contains large numbers of dead row versions as a result of
|
||||
massive update or delete activity. If you have such a table and
|
||||
you need to reclaim the excess disk space it occupies, the best
|
||||
way is to use <xref linkend="sql-cluster" endterm="sql-cluster-title">
|
||||
you need to reclaim the excess disk space it occupies, you will need
|
||||
to use <command>VACUUM FULL</>, or alternatively
|
||||
<xref linkend="sql-cluster" endterm="sql-cluster-title">
|
||||
or one of the table-rewriting variants of
|
||||
<xref linkend="sql-altertable" endterm="sql-altertable-title">.
|
||||
These commands rewrite an entire new copy of the table and build
|
||||
new indexes for it. Like <command>VACUUM FULL</>, they require
|
||||
exclusive lock. Note that they also temporarily use extra disk
|
||||
space, since the old copies of the table and indexes can't be
|
||||
released until the new ones are complete. In the worst case where
|
||||
your disk is nearly full, <command>VACUUM FULL</> may be the only
|
||||
workable alternative.
|
||||
new indexes for it. All these options require exclusive lock. Note that
|
||||
they also temporarily use extra disk space approximately equal to the size
|
||||
of the table, since the old copies of the table and indexes can't be
|
||||
released until the new ones are complete.
|
||||
</para>
|
||||
</tip>
|
||||
|
||||
|
@ -579,22 +573,22 @@ HINT: Stop the postmaster and use a standalone backend to VACUUM in "mydb".
|
|||
<firstterm>autovacuum launcher</firstterm>, which is in charge of starting
|
||||
<firstterm>autovacuum worker</firstterm> processes for all databases. The
|
||||
launcher will distribute the work across time, attempting to start one
|
||||
worker on each database every <xref linkend="guc-autovacuum-naptime">
|
||||
seconds. One worker will be launched for each database, with a maximum
|
||||
of <xref linkend="guc-autovacuum-max-workers"> processes running at the
|
||||
same time. If there are more than
|
||||
<xref linkend="guc-autovacuum-max-workers"> databases to be processed,
|
||||
worker within each database every <xref linkend="guc-autovacuum-naptime">
|
||||
seconds. (Therefore, if the installation has <replaceable>N</> databases,
|
||||
a new worker will be launched every
|
||||
<varname>autovacuum_naptime</>/<replaceable>N</> seconds.)
|
||||
A maximum of <xref linkend="guc-autovacuum-max-workers"> worker processes
|
||||
are allowed to run at the same time. If there are more than
|
||||
<varname>autovacuum_max_workers</> databases to be processed,
|
||||
the next database will be processed as soon as the first worker finishes.
|
||||
Each worker process will check each table within its database and
|
||||
execute <command>VACUUM</> and/or <command>ANALYZE</> as needed.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The <xref linkend="guc-autovacuum-max-workers"> setting limits how many
|
||||
workers may be running at any time. If several large tables all become
|
||||
eligible for vacuuming in a short amount of time, all autovacuum workers
|
||||
might become occupied with vacuuming those tables for a long period.
|
||||
This would result
|
||||
If several large tables all become eligible for vacuuming in a short
|
||||
amount of time, all autovacuum workers might become occupied with
|
||||
vacuuming those tables for a long period. This would result
|
||||
in other tables and databases not being vacuumed until a worker became
|
||||
available. There is no limit on how many workers might be in a
|
||||
single database, but workers do try to avoid repeating work that has
|
||||
|
@ -700,8 +694,8 @@ analyze threshold = analyze base threshold + analyze scale factor * number of tu
|
|||
</para>
|
||||
|
||||
<para>
|
||||
Index pages that have become
|
||||
completely empty are reclaimed for re-use. However, here is still the possibility
|
||||
B-tree index pages that have become completely empty are reclaimed for
|
||||
re-use. However, there is still a possibility
|
||||
of inefficient use of space: if all but a few index keys on a page have
|
||||
been deleted, the page remains allocated. Therefore, a usage
|
||||
pattern in which most, but not all, keys in each range are eventually
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<!--
|
||||
$PostgreSQL: pgsql/doc/src/sgml/ref/vacuum.sgml,v 1.57 2010/01/06 05:31:13 itagaki Exp $
|
||||
$PostgreSQL: pgsql/doc/src/sgml/ref/vacuum.sgml,v 1.58 2010/02/08 04:33:51 tgl Exp $
|
||||
PostgreSQL documentation
|
||||
-->
|
||||
|
||||
|
@ -21,7 +21,7 @@ PostgreSQL documentation
|
|||
|
||||
<refsynopsisdiv>
|
||||
<synopsis>
|
||||
VACUUM [ ( { FULL [ INPLACE ] | FREEZE | VERBOSE | ANALYZE } [, ...] ) ] [ <replaceable class="PARAMETER">table</replaceable> [ (<replaceable class="PARAMETER">column</replaceable> [, ...] ) ] ]
|
||||
VACUUM [ ( { FULL | FREEZE | VERBOSE | ANALYZE } [, ...] ) ] [ <replaceable class="PARAMETER">table</replaceable> [ (<replaceable class="PARAMETER">column</replaceable> [, ...] ) ] ]
|
||||
VACUUM [ FULL ] [ FREEZE ] [ VERBOSE ] [ <replaceable class="PARAMETER">table</replaceable> ]
|
||||
VACUUM [ FULL ] [ FREEZE ] [ VERBOSE ] ANALYZE [ <replaceable class="PARAMETER">table</replaceable> [ (<replaceable class="PARAMETER">column</replaceable> [, ...] ) ] ]
|
||||
</synopsis>
|
||||
|
@ -58,11 +58,12 @@ VACUUM [ FULL ] [ FREEZE ] [ VERBOSE ] ANALYZE [ <replaceable class="PARAMETER">
|
|||
space and makes it
|
||||
available for re-use. This form of the command can operate in parallel
|
||||
with normal reading and writing of the table, as an exclusive lock
|
||||
is not obtained. <command>VACUUM
|
||||
FULL</command> does more extensive processing, including moving of tuples
|
||||
across blocks to try to compact the table to the minimum number of disk
|
||||
blocks. This form is much slower and requires an exclusive lock on each
|
||||
table while it is being processed.
|
||||
is not obtained. However, extra space is not returned to the operating
|
||||
system (in most cases); it's just kept available for re-use within the
|
||||
same table. <command>VACUUM FULL</command> rewrites the entire contents
|
||||
of the table into a new disk file with no extra space, allowing unused
|
||||
space to be returned to the operating system. This form is much slower and
|
||||
requires an exclusive lock on each table while it is being processed.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
|
@ -85,27 +86,10 @@ VACUUM [ FULL ] [ FREEZE ] [ VERBOSE ] ANALYZE [ <replaceable class="PARAMETER">
|
|||
<para>
|
||||
Selects <quote>full</quote> vacuum, which can reclaim more
|
||||
space, but takes much longer and exclusively locks the table.
|
||||
</para>
|
||||
<para>
|
||||
For user tables, all table data and indexes are rewritten. This
|
||||
method requires extra disk space in which to write the new data,
|
||||
and is generally useful when a significant amount of space needs
|
||||
to be reclaimed from within the table.
|
||||
</para>
|
||||
<para>
|
||||
For system tables, all table data and indexes are modified in
|
||||
place to reclaim space. This method may require less disk space
|
||||
for the table data than <command>VACUUM FULL</command> on a
|
||||
comparable user table, but the indexes will grow which may
|
||||
counteract that benefit. Additionally, the operation is often
|
||||
slower than <command>VACUUM FULL</command> on a comparable user
|
||||
table.
|
||||
</para>
|
||||
<para>
|
||||
If <literal>FULL INPLACE</literal> is specified, the space is
|
||||
reclaimed in the same manner as a system table, even if it is a
|
||||
user table. Specifying <literal>INPLACE</literal> explicitly is
|
||||
rarely useful.
|
||||
This method also requires extra disk space, since it writes a
|
||||
new copy of the table and doesn't release the old copy until
|
||||
the operation is complete. Usually this should only be used when a
|
||||
significant amount of space needs to be reclaimed from within the table.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
@ -217,10 +201,7 @@ VACUUM [ FULL ] [ FREEZE ] [ VERBOSE ] ANALYZE [ <replaceable class="PARAMETER">
|
|||
or updated most of the rows in a table and would like the table to
|
||||
physically shrink to occupy less disk space and allow faster table
|
||||
scans. <command>VACUUM FULL</command> will usually shrink the table
|
||||
more than a plain <command>VACUUM</command> would. The
|
||||
<option>FULL</option> option does not shrink indexes; a periodic
|
||||
<command>REINDEX</> is still recommended. In fact, it is often faster
|
||||
to drop all indexes, <command>VACUUM FULL</>, and recreate the indexes.
|
||||
more than a plain <command>VACUUM</command> would.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<!--
|
||||
$PostgreSQL: pgsql/doc/src/sgml/ref/vacuumdb.sgml,v 1.49 2010/01/07 14:35:44 momjian Exp $
|
||||
$PostgreSQL: pgsql/doc/src/sgml/ref/vacuumdb.sgml,v 1.50 2010/02/08 04:33:51 tgl Exp $
|
||||
PostgreSQL documentation
|
||||
-->
|
||||
|
||||
|
@ -24,7 +24,6 @@ PostgreSQL documentation
|
|||
<command>vacuumdb</command>
|
||||
<arg rep="repeat"><replaceable>connection-option</replaceable></arg>
|
||||
<group><arg>--full</arg><arg>-f</arg></group>
|
||||
<group><arg>--inplace</arg><arg>-i</arg></group>
|
||||
<group><arg>--freeze</arg><arg>-F</arg></group>
|
||||
<group><arg>--verbose</arg><arg>-v</arg></group>
|
||||
<group><arg>--analyze</arg><arg>-z</arg></group>
|
||||
|
@ -38,14 +37,12 @@ PostgreSQL documentation
|
|||
<arg rep="repeat"><replaceable>connection-options</replaceable></arg>
|
||||
<group><arg>--all</arg><arg>-a</arg></group>
|
||||
<group><arg>--full</arg><arg>-f</arg></group>
|
||||
<group><arg>--inplace</arg><arg>-i</arg></group>
|
||||
<group><arg>--freeze</arg><arg>-F</arg></group>
|
||||
<group><arg>--verbose</arg><arg>-v</arg></group>
|
||||
<group><arg>--analyze</arg><arg>-z</arg></group>
|
||||
<group><arg>--analyze-only</arg><arg>-Z</arg></group>
|
||||
</cmdsynopsis>
|
||||
</refsynopsisdiv>
|
||||
|
||||
|
||||
<refsect1>
|
||||
<title>Description</title>
|
||||
|
@ -60,8 +57,8 @@ PostgreSQL documentation
|
|||
<para>
|
||||
<application>vacuumdb</application> is a wrapper around the SQL
|
||||
command <xref linkend="SQL-VACUUM" endterm="SQL-VACUUM-title">.
|
||||
There is no effective difference between vacuuming and analyzing
|
||||
databases via this utility and via other methods for accessing the
|
||||
There is no effective difference between vacuuming and analyzing
|
||||
databases via this utility and via other methods for accessing the
|
||||
server.
|
||||
</para>
|
||||
|
||||
|
@ -73,7 +70,6 @@ PostgreSQL documentation
|
|||
|
||||
<para>
|
||||
<application>vacuumdb</application> accepts the following command-line arguments:
|
||||
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term><option>-a</option></term>
|
||||
|
@ -131,16 +127,6 @@ PostgreSQL documentation
|
|||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>-i</option></term>
|
||||
<term><option>--inplace</option></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Perform <quote>full inplace</quote> vacuuming.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>-Z</option></term>
|
||||
<term><option>--analyze-only</option></term>
|
||||
|
@ -203,18 +189,16 @@ PostgreSQL documentation
|
|||
</para>
|
||||
|
||||
<para>
|
||||
<application>vacuumdb</application> also accepts
|
||||
<application>vacuumdb</application> also accepts
|
||||
the following command-line arguments for connection parameters:
|
||||
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term><option>-h <replaceable class="parameter">host</replaceable></></term>
|
||||
<term><option>--host <replaceable class="parameter">host</replaceable></></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Specifies the host name of the machine on which the
|
||||
server
|
||||
is running. If the value begins with a slash, it is used
|
||||
Specifies the host name of the machine on which the server
|
||||
is running. If the value begins with a slash, it is used
|
||||
as the directory for the Unix domain socket.
|
||||
</para>
|
||||
</listitem>
|
||||
|
@ -225,7 +209,7 @@ PostgreSQL documentation
|
|||
<term><option>--port <replaceable class="parameter">port</replaceable></></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Specifies the TCP port or local Unix domain socket file
|
||||
Specifies the TCP port or local Unix domain socket file
|
||||
extension on which the server
|
||||
is listening for connections.
|
||||
</para>
|
||||
|
@ -263,7 +247,7 @@ PostgreSQL documentation
|
|||
<listitem>
|
||||
<para>
|
||||
Force <application>vacuumdb</application> to prompt for a
|
||||
password before connecting to a database.
|
||||
password before connecting to a database.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
$PostgreSQL: pgsql/src/backend/access/gin/README,v 1.6 2008/07/08 03:25:42 neilc Exp $
|
||||
$PostgreSQL: pgsql/src/backend/access/gin/README,v 1.7 2010/02/08 04:33:52 tgl Exp $
|
||||
|
||||
Gin for PostgreSQL
|
||||
==================
|
||||
|
@ -98,13 +98,6 @@ We appreciate any comments, help and suggestions.
|
|||
* Teach optimizer/executor that GIN is intrinsically clustered. i.e., it
|
||||
always returns ItemPointer in ascending order.
|
||||
* Tweak gincostestimate.
|
||||
* GIN stores several ItemPointer to heap tuple, so VACUUM FULL produces
|
||||
this warning message:
|
||||
|
||||
WARNING: index "idx" contains 88395 row versions, but table contains
|
||||
51812 row versions
|
||||
HINT: Rebuild the index with REINDEX.
|
||||
**** Workaround added
|
||||
|
||||
TODO
|
||||
----
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/gin/ginvacuum.c,v 1.32 2010/01/02 16:57:33 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/gin/ginvacuum.c,v 1.33 2010/02/08 04:33:52 tgl Exp $
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
@ -745,13 +745,9 @@ ginvacuumcleanup(PG_FUNCTION_ARGS)
|
|||
stats->estimated_count = info->estimated_count;
|
||||
|
||||
/*
|
||||
* If vacuum full, we already have exclusive lock on the index. Otherwise,
|
||||
* need lock unless it's local to this backend.
|
||||
* Need lock unless it's local to this backend.
|
||||
*/
|
||||
if (info->vacuum_full)
|
||||
needLock = false;
|
||||
else
|
||||
needLock = !RELATION_IS_LOCAL(index);
|
||||
needLock = !RELATION_IS_LOCAL(index);
|
||||
|
||||
if (needLock)
|
||||
LockRelationForExtension(index, ExclusiveLock);
|
||||
|
@ -785,15 +781,6 @@ ginvacuumcleanup(PG_FUNCTION_ARGS)
|
|||
}
|
||||
lastBlock = npages - 1;
|
||||
|
||||
if (info->vacuum_full && lastBlock > lastFilledBlock)
|
||||
{
|
||||
/* try to truncate index */
|
||||
RelationTruncate(index, lastFilledBlock + 1);
|
||||
|
||||
stats->pages_removed = lastBlock - lastFilledBlock;
|
||||
totFreePages = totFreePages - stats->pages_removed;
|
||||
}
|
||||
|
||||
/* Finally, vacuum the FSM */
|
||||
IndexFreeSpaceMapVacuum(info->index);
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/gist/gistvacuum.c,v 1.46 2010/01/02 16:57:34 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/gist/gistvacuum.c,v 1.47 2010/02/08 04:33:52 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -29,7 +29,7 @@
|
|||
typedef struct GistBulkDeleteResult
|
||||
{
|
||||
IndexBulkDeleteResult std; /* common state */
|
||||
bool needFullVacuum;
|
||||
bool needReindex;
|
||||
} GistBulkDeleteResult;
|
||||
|
||||
typedef struct
|
||||
|
@ -496,12 +496,8 @@ gistVacuumUpdate(GistVacuum *gv, BlockNumber blkno, bool needunion)
|
|||
}
|
||||
|
||||
/*
|
||||
* For usual vacuum just update FSM, for full vacuum
|
||||
* reforms parent tuples if some of childs was deleted or changed,
|
||||
* update invalid tuples (they can exist from last crash recovery only),
|
||||
* tries to get smaller index
|
||||
* VACUUM cleanup: update FSM
|
||||
*/
|
||||
|
||||
Datum
|
||||
gistvacuumcleanup(PG_FUNCTION_ARGS)
|
||||
{
|
||||
|
@ -533,47 +529,15 @@ gistvacuumcleanup(PG_FUNCTION_ARGS)
|
|||
*/
|
||||
}
|
||||
|
||||
/* gistVacuumUpdate may cause hard work */
|
||||
if (info->vacuum_full)
|
||||
{
|
||||
GistVacuum gv;
|
||||
ArrayTuple res;
|
||||
|
||||
/* note: vacuum.c already acquired AccessExclusiveLock on index */
|
||||
|
||||
gv.index = rel;
|
||||
initGISTstate(&(gv.giststate), rel);
|
||||
gv.opCtx = createTempGistContext();
|
||||
gv.result = stats;
|
||||
gv.strategy = info->strategy;
|
||||
|
||||
/* walk through the entire index for update tuples */
|
||||
res = gistVacuumUpdate(&gv, GIST_ROOT_BLKNO, false);
|
||||
/* cleanup */
|
||||
if (res.itup)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < res.ituplen; i++)
|
||||
pfree(res.itup[i]);
|
||||
pfree(res.itup);
|
||||
}
|
||||
freeGISTstate(&(gv.giststate));
|
||||
MemoryContextDelete(gv.opCtx);
|
||||
}
|
||||
else if (stats->needFullVacuum)
|
||||
if (stats->needReindex)
|
||||
ereport(NOTICE,
|
||||
(errmsg("index \"%s\" needs VACUUM FULL or REINDEX to finish crash recovery",
|
||||
RelationGetRelationName(rel))));
|
||||
|
||||
/*
|
||||
* If vacuum full, we already have exclusive lock on the index. Otherwise,
|
||||
* need lock unless it's local to this backend.
|
||||
* Need lock unless it's local to this backend.
|
||||
*/
|
||||
if (info->vacuum_full)
|
||||
needLock = false;
|
||||
else
|
||||
needLock = !RELATION_IS_LOCAL(rel);
|
||||
needLock = !RELATION_IS_LOCAL(rel);
|
||||
|
||||
/* try to find deleted pages */
|
||||
if (needLock)
|
||||
|
@ -606,14 +570,6 @@ gistvacuumcleanup(PG_FUNCTION_ARGS)
|
|||
}
|
||||
lastBlock = npages - 1;
|
||||
|
||||
if (info->vacuum_full && lastFilledBlock < lastBlock)
|
||||
{ /* try to truncate index */
|
||||
RelationTruncate(rel, lastFilledBlock + 1);
|
||||
|
||||
stats->std.pages_removed = lastBlock - lastFilledBlock;
|
||||
totFreePages = totFreePages - stats->std.pages_removed;
|
||||
}
|
||||
|
||||
/* Finally, vacuum the FSM */
|
||||
IndexFreeSpaceMapVacuum(info->index);
|
||||
|
||||
|
@ -799,7 +755,7 @@ gistbulkdelete(PG_FUNCTION_ARGS)
|
|||
stack->next = ptr;
|
||||
|
||||
if (GistTupleIsInvalid(idxtuple))
|
||||
stats->needFullVacuum = true;
|
||||
stats->needReindex = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
$PostgreSQL: pgsql/src/backend/access/heap/README.HOT,v 1.4 2008/10/02 20:59:31 momjian Exp $
|
||||
$PostgreSQL: pgsql/src/backend/access/heap/README.HOT,v 1.5 2010/02/08 04:33:52 tgl Exp $
|
||||
|
||||
Heap Only Tuples (HOT)
|
||||
======================
|
||||
|
@ -255,27 +255,6 @@ dead heap-only tuples, and cleans up any dead line pointers as if they were
|
|||
regular dead tuples.
|
||||
|
||||
|
||||
VACUUM FULL
|
||||
-----------
|
||||
|
||||
VACUUM FULL performs an extra operation of collapsing out redirecting line
|
||||
pointers, by moving the first non-DEAD tuple of each HOT chain to the root
|
||||
position and clearing its heap-only-tuple flag. This effectively changes
|
||||
the user-visible CTID of that tuple. This would be completely unsafe
|
||||
during normal concurrent operation, but since VACUUM FULL takes full
|
||||
exclusive lock on the table, it should be OK. (Note that VACUUM FULL has
|
||||
always felt free to change tuples' CTIDs by moving them across pages.)
|
||||
Eliminating redirection links means that the main body of VACUUM FULL
|
||||
doesn't have to deal with them, which seems a good thing since VACUUM FULL
|
||||
is horrendously complex already.
|
||||
|
||||
When VACUUM FULL tries to move tuple chains, it does not distinguish regular
|
||||
and heap-only tuples, but just moves both types the same. This is OK because
|
||||
it will move the entire non-DEAD tail of an update chain and remove index
|
||||
entries for each item moved. At worst, we'll uselessly search for index
|
||||
entries matching the heap-only tuples included in the move.
|
||||
|
||||
|
||||
Statistics
|
||||
----------
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/heap/heapam.c,v 1.285 2010/02/03 10:01:29 heikki Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/heap/heapam.c,v 1.286 2010/02/08 04:33:52 tgl Exp $
|
||||
*
|
||||
*
|
||||
* INTERFACE ROUTINES
|
||||
|
@ -79,7 +79,7 @@ static HeapScanDesc heap_beginscan_internal(Relation relation,
|
|||
bool allow_strat, bool allow_sync,
|
||||
bool is_bitmapscan);
|
||||
static XLogRecPtr log_heap_update(Relation reln, Buffer oldbuf,
|
||||
ItemPointerData from, Buffer newbuf, HeapTuple newtup, bool move,
|
||||
ItemPointerData from, Buffer newbuf, HeapTuple newtup,
|
||||
bool all_visible_cleared, bool new_all_visible_cleared);
|
||||
static bool HeapSatisfiesHOTUpdate(Relation relation, Bitmapset *hot_attrs,
|
||||
HeapTuple oldtup, HeapTuple newtup);
|
||||
|
@ -2785,7 +2785,7 @@ l2:
|
|||
if (!relation->rd_istemp)
|
||||
{
|
||||
XLogRecPtr recptr = log_heap_update(relation, buffer, oldtup.t_self,
|
||||
newbuf, heaptup, false,
|
||||
newbuf, heaptup,
|
||||
all_visible_cleared,
|
||||
all_visible_cleared_new);
|
||||
|
||||
|
@ -3664,9 +3664,13 @@ recheck_xmax:
|
|||
}
|
||||
|
||||
/*
|
||||
* Although xvac per se could only be set by VACUUM, it shares physical
|
||||
* storage space with cmax, and so could be wiped out by someone setting
|
||||
* xmax. Hence recheck after changing lock, same as for xmax itself.
|
||||
* Although xvac per se could only be set by old-style VACUUM FULL, it
|
||||
* shares physical storage space with cmax, and so could be wiped out by
|
||||
* someone setting xmax. Hence recheck after changing lock, same as for
|
||||
* xmax itself.
|
||||
*
|
||||
* Old-style VACUUM FULL is gone, but we have to keep this code as long
|
||||
* as we support having MOVED_OFF/MOVED_IN tuples in the database.
|
||||
*/
|
||||
recheck_xvac:
|
||||
if (tuple->t_infomask & HEAP_MOVED)
|
||||
|
@ -3785,8 +3789,7 @@ HeapTupleHeaderAdvanceLatestRemovedXid(HeapTupleHeader tuple,
|
|||
TransactionId xmax = HeapTupleHeaderGetXmax(tuple);
|
||||
TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
|
||||
|
||||
if (tuple->t_infomask & HEAP_MOVED_OFF ||
|
||||
tuple->t_infomask & HEAP_MOVED_IN)
|
||||
if (tuple->t_infomask & HEAP_MOVED)
|
||||
{
|
||||
if (TransactionIdPrecedes(*latestRemovedXid, xvac))
|
||||
*latestRemovedXid = xvac;
|
||||
|
@ -3844,7 +3847,7 @@ log_heap_clean(Relation reln, Buffer buffer,
|
|||
OffsetNumber *redirected, int nredirected,
|
||||
OffsetNumber *nowdead, int ndead,
|
||||
OffsetNumber *nowunused, int nunused,
|
||||
TransactionId latestRemovedXid, bool redirect_move)
|
||||
TransactionId latestRemovedXid)
|
||||
{
|
||||
xl_heap_clean xlrec;
|
||||
uint8 info;
|
||||
|
@ -3915,7 +3918,7 @@ log_heap_clean(Relation reln, Buffer buffer,
|
|||
rdata[3].buffer_std = true;
|
||||
rdata[3].next = NULL;
|
||||
|
||||
info = redirect_move ? XLOG_HEAP2_CLEAN_MOVE : XLOG_HEAP2_CLEAN;
|
||||
info = XLOG_HEAP2_CLEAN;
|
||||
recptr = XLogInsert(RM_HEAP2_ID, info, rdata);
|
||||
|
||||
return recptr;
|
||||
|
@ -3970,23 +3973,11 @@ log_heap_freeze(Relation reln, Buffer buffer,
|
|||
*/
|
||||
static XLogRecPtr
|
||||
log_heap_update(Relation reln, Buffer oldbuf, ItemPointerData from,
|
||||
Buffer newbuf, HeapTuple newtup, bool move,
|
||||
Buffer newbuf, HeapTuple newtup,
|
||||
bool all_visible_cleared, bool new_all_visible_cleared)
|
||||
{
|
||||
/*
|
||||
* Note: xlhdr is declared to have adequate size and correct alignment for
|
||||
* an xl_heap_header. However the two tids, if present at all, will be
|
||||
* packed in with no wasted space after the xl_heap_header; they aren't
|
||||
* necessarily aligned as implied by this struct declaration.
|
||||
*/
|
||||
struct
|
||||
{
|
||||
xl_heap_header hdr;
|
||||
TransactionId tid1;
|
||||
TransactionId tid2;
|
||||
} xlhdr;
|
||||
int hsize = SizeOfHeapHeader;
|
||||
xl_heap_update xlrec;
|
||||
xl_heap_header xlhdr;
|
||||
uint8 info;
|
||||
XLogRecPtr recptr;
|
||||
XLogRecData rdata[4];
|
||||
|
@ -3995,12 +3986,7 @@ log_heap_update(Relation reln, Buffer oldbuf, ItemPointerData from,
|
|||
/* Caller should not call me on a temp relation */
|
||||
Assert(!reln->rd_istemp);
|
||||
|
||||
if (move)
|
||||
{
|
||||
Assert(!HeapTupleIsHeapOnly(newtup));
|
||||
info = XLOG_HEAP_MOVE;
|
||||
}
|
||||
else if (HeapTupleIsHeapOnly(newtup))
|
||||
if (HeapTupleIsHeapOnly(newtup))
|
||||
info = XLOG_HEAP_HOT_UPDATE;
|
||||
else
|
||||
info = XLOG_HEAP_UPDATE;
|
||||
|
@ -4022,30 +4008,16 @@ log_heap_update(Relation reln, Buffer oldbuf, ItemPointerData from,
|
|||
rdata[1].buffer_std = true;
|
||||
rdata[1].next = &(rdata[2]);
|
||||
|
||||
xlhdr.hdr.t_infomask2 = newtup->t_data->t_infomask2;
|
||||
xlhdr.hdr.t_infomask = newtup->t_data->t_infomask;
|
||||
xlhdr.hdr.t_hoff = newtup->t_data->t_hoff;
|
||||
if (move) /* remember xmax & xmin */
|
||||
{
|
||||
TransactionId xid[2]; /* xmax, xmin */
|
||||
|
||||
if (newtup->t_data->t_infomask & (HEAP_XMAX_INVALID | HEAP_IS_LOCKED))
|
||||
xid[0] = InvalidTransactionId;
|
||||
else
|
||||
xid[0] = HeapTupleHeaderGetXmax(newtup->t_data);
|
||||
xid[1] = HeapTupleHeaderGetXmin(newtup->t_data);
|
||||
memcpy((char *) &xlhdr + hsize,
|
||||
(char *) xid,
|
||||
2 * sizeof(TransactionId));
|
||||
hsize += 2 * sizeof(TransactionId);
|
||||
}
|
||||
xlhdr.t_infomask2 = newtup->t_data->t_infomask2;
|
||||
xlhdr.t_infomask = newtup->t_data->t_infomask;
|
||||
xlhdr.t_hoff = newtup->t_data->t_hoff;
|
||||
|
||||
/*
|
||||
* As with insert records, we need not store the rdata[2] segment if we
|
||||
* decide to store the whole buffer instead.
|
||||
*/
|
||||
rdata[2].data = (char *) &xlhdr;
|
||||
rdata[2].len = hsize;
|
||||
rdata[2].len = SizeOfHeapHeader;
|
||||
rdata[2].buffer = newbuf;
|
||||
rdata[2].buffer_std = true;
|
||||
rdata[2].next = &(rdata[3]);
|
||||
|
@ -4070,19 +4042,6 @@ log_heap_update(Relation reln, Buffer oldbuf, ItemPointerData from,
|
|||
return recptr;
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform XLogInsert for a heap-move operation. Caller must already
|
||||
* have modified the buffers and marked them dirty.
|
||||
*/
|
||||
XLogRecPtr
|
||||
log_heap_move(Relation reln, Buffer oldbuf, ItemPointerData from,
|
||||
Buffer newbuf, HeapTuple newtup,
|
||||
bool all_visible_cleared, bool new_all_visible_cleared)
|
||||
{
|
||||
return log_heap_update(reln, oldbuf, from, newbuf, newtup, true,
|
||||
all_visible_cleared, new_all_visible_cleared);
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform XLogInsert of a HEAP_NEWPAGE record to WAL. Caller is responsible
|
||||
* for writing the page to disk after calling this routine.
|
||||
|
@ -4149,10 +4108,10 @@ heap_xlog_cleanup_info(XLogRecPtr lsn, XLogRecord *record)
|
|||
}
|
||||
|
||||
/*
|
||||
* Handles CLEAN and CLEAN_MOVE record types
|
||||
* Handles HEAP_CLEAN record type
|
||||
*/
|
||||
static void
|
||||
heap_xlog_clean(XLogRecPtr lsn, XLogRecord *record, bool clean_move)
|
||||
heap_xlog_clean(XLogRecPtr lsn, XLogRecord *record)
|
||||
{
|
||||
xl_heap_clean *xlrec = (xl_heap_clean *) XLogRecGetData(record);
|
||||
Buffer buffer;
|
||||
|
@ -4171,7 +4130,8 @@ heap_xlog_clean(XLogRecPtr lsn, XLogRecord *record, bool clean_move)
|
|||
* no queries running for which the removed tuples are still visible.
|
||||
*/
|
||||
if (InHotStandby)
|
||||
ResolveRecoveryConflictWithSnapshot(xlrec->latestRemovedXid, xlrec->node);
|
||||
ResolveRecoveryConflictWithSnapshot(xlrec->latestRemovedXid,
|
||||
xlrec->node);
|
||||
|
||||
RestoreBkpBlocks(lsn, record, true);
|
||||
|
||||
|
@ -4203,8 +4163,7 @@ heap_xlog_clean(XLogRecPtr lsn, XLogRecord *record, bool clean_move)
|
|||
heap_page_prune_execute(buffer,
|
||||
redirected, nredirected,
|
||||
nowdead, ndead,
|
||||
nowunused, nunused,
|
||||
clean_move);
|
||||
nowunused, nunused);
|
||||
|
||||
freespace = PageGetHeapFreeSpace(page); /* needed to update FSM below */
|
||||
|
||||
|
@ -4489,10 +4448,10 @@ heap_xlog_insert(XLogRecPtr lsn, XLogRecord *record)
|
|||
}
|
||||
|
||||
/*
|
||||
* Handles UPDATE, HOT_UPDATE & MOVE
|
||||
* Handles UPDATE and HOT_UPDATE
|
||||
*/
|
||||
static void
|
||||
heap_xlog_update(XLogRecPtr lsn, XLogRecord *record, bool move, bool hot_update)
|
||||
heap_xlog_update(XLogRecPtr lsn, XLogRecord *record, bool hot_update)
|
||||
{
|
||||
xl_heap_update *xlrec = (xl_heap_update *) XLogRecGetData(record);
|
||||
Buffer buffer;
|
||||
|
@ -4558,33 +4517,19 @@ heap_xlog_update(XLogRecPtr lsn, XLogRecord *record, bool move, bool hot_update)
|
|||
|
||||
htup = (HeapTupleHeader) PageGetItem(page, lp);
|
||||
|
||||
if (move)
|
||||
{
|
||||
htup->t_infomask &= ~(HEAP_XMIN_COMMITTED |
|
||||
HEAP_XMIN_INVALID |
|
||||
HEAP_MOVED_IN);
|
||||
htup->t_infomask |= HEAP_MOVED_OFF;
|
||||
HeapTupleHeaderClearHotUpdated(htup);
|
||||
HeapTupleHeaderSetXvac(htup, record->xl_xid);
|
||||
/* Make sure there is no forward chain link in t_ctid */
|
||||
htup->t_ctid = xlrec->target.tid;
|
||||
}
|
||||
htup->t_infomask &= ~(HEAP_XMAX_COMMITTED |
|
||||
HEAP_XMAX_INVALID |
|
||||
HEAP_XMAX_IS_MULTI |
|
||||
HEAP_IS_LOCKED |
|
||||
HEAP_MOVED);
|
||||
if (hot_update)
|
||||
HeapTupleHeaderSetHotUpdated(htup);
|
||||
else
|
||||
{
|
||||
htup->t_infomask &= ~(HEAP_XMAX_COMMITTED |
|
||||
HEAP_XMAX_INVALID |
|
||||
HEAP_XMAX_IS_MULTI |
|
||||
HEAP_IS_LOCKED |
|
||||
HEAP_MOVED);
|
||||
if (hot_update)
|
||||
HeapTupleHeaderSetHotUpdated(htup);
|
||||
else
|
||||
HeapTupleHeaderClearHotUpdated(htup);
|
||||
HeapTupleHeaderSetXmax(htup, record->xl_xid);
|
||||
HeapTupleHeaderSetCmax(htup, FirstCommandId, false);
|
||||
/* Set forward chain link in t_ctid */
|
||||
htup->t_ctid = xlrec->newtid;
|
||||
}
|
||||
HeapTupleHeaderClearHotUpdated(htup);
|
||||
HeapTupleHeaderSetXmax(htup, record->xl_xid);
|
||||
HeapTupleHeaderSetCmax(htup, FirstCommandId, false);
|
||||
/* Set forward chain link in t_ctid */
|
||||
htup->t_ctid = xlrec->newtid;
|
||||
|
||||
/* Mark the page as a candidate for pruning */
|
||||
PageSetPrunable(page, record->xl_xid);
|
||||
|
@ -4655,8 +4600,6 @@ newsame:;
|
|||
elog(PANIC, "heap_update_redo: invalid max offset number");
|
||||
|
||||
hsize = SizeOfHeapUpdate + SizeOfHeapHeader;
|
||||
if (move)
|
||||
hsize += (2 * sizeof(TransactionId));
|
||||
|
||||
newlen = record->xl_len - hsize;
|
||||
Assert(newlen <= MaxHeapTupleSize);
|
||||
|
@ -4674,22 +4617,8 @@ newsame:;
|
|||
htup->t_infomask = xlhdr.t_infomask;
|
||||
htup->t_hoff = xlhdr.t_hoff;
|
||||
|
||||
if (move)
|
||||
{
|
||||
TransactionId xid[2]; /* xmax, xmin */
|
||||
|
||||
memcpy((char *) xid,
|
||||
(char *) xlrec + SizeOfHeapUpdate + SizeOfHeapHeader,
|
||||
2 * sizeof(TransactionId));
|
||||
HeapTupleHeaderSetXmin(htup, xid[1]);
|
||||
HeapTupleHeaderSetXmax(htup, xid[0]);
|
||||
HeapTupleHeaderSetXvac(htup, record->xl_xid);
|
||||
}
|
||||
else
|
||||
{
|
||||
HeapTupleHeaderSetXmin(htup, record->xl_xid);
|
||||
HeapTupleHeaderSetCmin(htup, FirstCommandId);
|
||||
}
|
||||
HeapTupleHeaderSetXmin(htup, record->xl_xid);
|
||||
HeapTupleHeaderSetCmin(htup, FirstCommandId);
|
||||
/* Make sure there is no forward chain link in t_ctid */
|
||||
htup->t_ctid = xlrec->newtid;
|
||||
|
||||
|
@ -4857,13 +4786,10 @@ heap_redo(XLogRecPtr lsn, XLogRecord *record)
|
|||
heap_xlog_delete(lsn, record);
|
||||
break;
|
||||
case XLOG_HEAP_UPDATE:
|
||||
heap_xlog_update(lsn, record, false, false);
|
||||
break;
|
||||
case XLOG_HEAP_MOVE:
|
||||
heap_xlog_update(lsn, record, true, false);
|
||||
heap_xlog_update(lsn, record, false);
|
||||
break;
|
||||
case XLOG_HEAP_HOT_UPDATE:
|
||||
heap_xlog_update(lsn, record, false, true);
|
||||
heap_xlog_update(lsn, record, true);
|
||||
break;
|
||||
case XLOG_HEAP_NEWPAGE:
|
||||
heap_xlog_newpage(lsn, record);
|
||||
|
@ -4895,10 +4821,7 @@ heap2_redo(XLogRecPtr lsn, XLogRecord *record)
|
|||
heap_xlog_freeze(lsn, record);
|
||||
break;
|
||||
case XLOG_HEAP2_CLEAN:
|
||||
heap_xlog_clean(lsn, record, false);
|
||||
break;
|
||||
case XLOG_HEAP2_CLEAN_MOVE:
|
||||
heap_xlog_clean(lsn, record, true);
|
||||
heap_xlog_clean(lsn, record);
|
||||
break;
|
||||
case XLOG_HEAP2_CLEANUP_INFO:
|
||||
heap_xlog_cleanup_info(lsn, record);
|
||||
|
@ -4953,19 +4876,6 @@ heap_desc(StringInfo buf, uint8 xl_info, char *rec)
|
|||
ItemPointerGetBlockNumber(&(xlrec->newtid)),
|
||||
ItemPointerGetOffsetNumber(&(xlrec->newtid)));
|
||||
}
|
||||
else if (info == XLOG_HEAP_MOVE)
|
||||
{
|
||||
xl_heap_update *xlrec = (xl_heap_update *) rec;
|
||||
|
||||
if (xl_info & XLOG_HEAP_INIT_PAGE)
|
||||
appendStringInfo(buf, "move(init): ");
|
||||
else
|
||||
appendStringInfo(buf, "move: ");
|
||||
out_target(buf, &(xlrec->target));
|
||||
appendStringInfo(buf, "; new %u/%u",
|
||||
ItemPointerGetBlockNumber(&(xlrec->newtid)),
|
||||
ItemPointerGetOffsetNumber(&(xlrec->newtid)));
|
||||
}
|
||||
else if (info == XLOG_HEAP_HOT_UPDATE)
|
||||
{
|
||||
xl_heap_update *xlrec = (xl_heap_update *) rec;
|
||||
|
@ -5037,15 +4947,6 @@ heap2_desc(StringInfo buf, uint8 xl_info, char *rec)
|
|||
xlrec->node.relNode, xlrec->block,
|
||||
xlrec->latestRemovedXid);
|
||||
}
|
||||
else if (info == XLOG_HEAP2_CLEAN_MOVE)
|
||||
{
|
||||
xl_heap_clean *xlrec = (xl_heap_clean *) rec;
|
||||
|
||||
appendStringInfo(buf, "clean_move: rel %u/%u/%u; blk %u remxid %u",
|
||||
xlrec->node.spcNode, xlrec->node.dbNode,
|
||||
xlrec->node.relNode, xlrec->block,
|
||||
xlrec->latestRemovedXid);
|
||||
}
|
||||
else if (info == XLOG_HEAP2_CLEANUP_INFO)
|
||||
{
|
||||
xl_heap_cleanup_info *xlrec = (xl_heap_cleanup_info *) rec;
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/heap/pruneheap.c,v 1.20 2010/01/02 16:57:34 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/heap/pruneheap.c,v 1.21 2010/02/08 04:33:53 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -21,7 +21,6 @@
|
|||
#include "pgstat.h"
|
||||
#include "storage/bufmgr.h"
|
||||
#include "storage/off.h"
|
||||
#include "utils/inval.h"
|
||||
#include "utils/rel.h"
|
||||
#include "utils/tqual.h"
|
||||
|
||||
|
@ -46,8 +45,7 @@ typedef struct
|
|||
static int heap_prune_chain(Relation relation, Buffer buffer,
|
||||
OffsetNumber rootoffnum,
|
||||
TransactionId OldestXmin,
|
||||
PruneState *prstate,
|
||||
bool redirect_move);
|
||||
PruneState *prstate);
|
||||
static void heap_prune_record_prunable(PruneState *prstate, TransactionId xid);
|
||||
static void heap_prune_record_redirect(PruneState *prstate,
|
||||
OffsetNumber offnum, OffsetNumber rdoffnum);
|
||||
|
@ -123,8 +121,8 @@ heap_page_prune_opt(Relation relation, Buffer buffer, TransactionId OldestXmin)
|
|||
*/
|
||||
if (PageIsFull(page) || PageGetHeapFreeSpace(page) < minfree)
|
||||
{
|
||||
/* OK to prune (though not to remove redirects) */
|
||||
(void) heap_page_prune(relation, buffer, OldestXmin, false, true);
|
||||
/* OK to prune */
|
||||
(void) heap_page_prune(relation, buffer, OldestXmin, true);
|
||||
}
|
||||
|
||||
/* And release buffer lock */
|
||||
|
@ -141,14 +139,6 @@ heap_page_prune_opt(Relation relation, Buffer buffer, TransactionId OldestXmin)
|
|||
* OldestXmin is the cutoff XID used to distinguish whether tuples are DEAD
|
||||
* or RECENTLY_DEAD (see HeapTupleSatisfiesVacuum).
|
||||
*
|
||||
* If redirect_move is set, we remove redirecting line pointers by
|
||||
* updating the root line pointer to point directly to the first non-dead
|
||||
* tuple in the chain. NOTE: eliminating the redirect changes the first
|
||||
* tuple's effective CTID, and is therefore unsafe except within VACUUM FULL.
|
||||
* The only reason we support this capability at all is that by using it,
|
||||
* VACUUM FULL need not cope with LP_REDIRECT items at all; which seems a
|
||||
* good thing since VACUUM FULL is overly complicated already.
|
||||
*
|
||||
* If report_stats is true then we send the number of reclaimed heap-only
|
||||
* tuples to pgstats. (This must be FALSE during vacuum, since vacuum will
|
||||
* send its own new total to pgstats, and we don't want this delta applied
|
||||
|
@ -158,7 +148,7 @@ heap_page_prune_opt(Relation relation, Buffer buffer, TransactionId OldestXmin)
|
|||
*/
|
||||
int
|
||||
heap_page_prune(Relation relation, Buffer buffer, TransactionId OldestXmin,
|
||||
bool redirect_move, bool report_stats)
|
||||
bool report_stats)
|
||||
{
|
||||
int ndeleted = 0;
|
||||
Page page = BufferGetPage(buffer);
|
||||
|
@ -172,17 +162,10 @@ heap_page_prune(Relation relation, Buffer buffer, TransactionId OldestXmin,
|
|||
* logic as possible out of the critical section, and also ensures that
|
||||
* WAL replay will work the same as the normal case.
|
||||
*
|
||||
* First, inform inval.c that upcoming CacheInvalidateHeapTuple calls are
|
||||
* nontransactional.
|
||||
*/
|
||||
if (redirect_move)
|
||||
BeginNonTransactionalInvalidation();
|
||||
|
||||
/*
|
||||
* Initialize the new pd_prune_xid value to zero (indicating no prunable
|
||||
* tuples). If we find any tuples which may soon become prunable, we will
|
||||
* save the lowest relevant XID in new_prune_xid. Also initialize the rest
|
||||
* of our working state.
|
||||
* First, initialize the new pd_prune_xid value to zero (indicating no
|
||||
* prunable tuples). If we find any tuples which may soon become
|
||||
* prunable, we will save the lowest relevant XID in new_prune_xid.
|
||||
* Also initialize the rest of our working state.
|
||||
*/
|
||||
prstate.new_prune_xid = InvalidTransactionId;
|
||||
prstate.latestRemovedXid = InvalidTransactionId;
|
||||
|
@ -209,22 +192,9 @@ heap_page_prune(Relation relation, Buffer buffer, TransactionId OldestXmin,
|
|||
/* Process this item or chain of items */
|
||||
ndeleted += heap_prune_chain(relation, buffer, offnum,
|
||||
OldestXmin,
|
||||
&prstate,
|
||||
redirect_move);
|
||||
&prstate);
|
||||
}
|
||||
|
||||
/*
|
||||
* Send invalidation messages for any tuples we are about to move. It is
|
||||
* safe to do this now, even though we could theoretically still fail
|
||||
* before making the actual page update, because a useless cache
|
||||
* invalidation doesn't hurt anything. Also, no one else can reload the
|
||||
* tuples while we have exclusive buffer lock, so it's not too early to
|
||||
* send the invals. This avoids sending the invals while inside the
|
||||
* critical section, which is a good thing for robustness.
|
||||
*/
|
||||
if (redirect_move)
|
||||
EndNonTransactionalInvalidation();
|
||||
|
||||
/* Any error while applying the changes is critical */
|
||||
START_CRIT_SECTION();
|
||||
|
||||
|
@ -238,8 +208,7 @@ heap_page_prune(Relation relation, Buffer buffer, TransactionId OldestXmin,
|
|||
heap_page_prune_execute(buffer,
|
||||
prstate.redirected, prstate.nredirected,
|
||||
prstate.nowdead, prstate.ndead,
|
||||
prstate.nowunused, prstate.nunused,
|
||||
redirect_move);
|
||||
prstate.nowunused, prstate.nunused);
|
||||
|
||||
/*
|
||||
* Update the page's pd_prune_xid field to either zero, or the lowest
|
||||
|
@ -257,7 +226,7 @@ heap_page_prune(Relation relation, Buffer buffer, TransactionId OldestXmin,
|
|||
MarkBufferDirty(buffer);
|
||||
|
||||
/*
|
||||
* Emit a WAL HEAP_CLEAN or HEAP_CLEAN_MOVE record showing what we did
|
||||
* Emit a WAL HEAP_CLEAN record showing what we did
|
||||
*/
|
||||
if (!relation->rd_istemp)
|
||||
{
|
||||
|
@ -267,7 +236,7 @@ heap_page_prune(Relation relation, Buffer buffer, TransactionId OldestXmin,
|
|||
prstate.redirected, prstate.nredirected,
|
||||
prstate.nowdead, prstate.ndead,
|
||||
prstate.nowunused, prstate.nunused,
|
||||
prstate.latestRemovedXid, redirect_move);
|
||||
prstate.latestRemovedXid);
|
||||
|
||||
PageSetLSN(BufferGetPage(buffer), recptr);
|
||||
PageSetTLI(BufferGetPage(buffer), ThisTimeLineID);
|
||||
|
@ -349,16 +318,12 @@ heap_page_prune(Relation relation, Buffer buffer, TransactionId OldestXmin,
|
|||
* LP_DEAD state are added to nowdead[]; and items to be set to LP_UNUSED
|
||||
* state are added to nowunused[].
|
||||
*
|
||||
* If redirect_move is true, we intend to get rid of redirecting line pointers,
|
||||
* not just make redirection entries.
|
||||
*
|
||||
* Returns the number of tuples (to be) deleted from the page.
|
||||
*/
|
||||
static int
|
||||
heap_prune_chain(Relation relation, Buffer buffer, OffsetNumber rootoffnum,
|
||||
TransactionId OldestXmin,
|
||||
PruneState *prstate,
|
||||
bool redirect_move)
|
||||
PruneState *prstate)
|
||||
{
|
||||
int ndeleted = 0;
|
||||
Page dp = (Page) BufferGetPage(buffer);
|
||||
|
@ -366,7 +331,6 @@ heap_prune_chain(Relation relation, Buffer buffer, OffsetNumber rootoffnum,
|
|||
ItemId rootlp;
|
||||
HeapTupleHeader htup;
|
||||
OffsetNumber latestdead = InvalidOffsetNumber,
|
||||
redirect_target = InvalidOffsetNumber,
|
||||
maxoff = PageGetMaxOffsetNumber(dp),
|
||||
offnum;
|
||||
OffsetNumber chainitems[MaxHeapTuplesPerPage];
|
||||
|
@ -592,12 +556,7 @@ heap_prune_chain(Relation relation, Buffer buffer, OffsetNumber rootoffnum,
|
|||
if (i >= nchain)
|
||||
heap_prune_record_dead(prstate, rootoffnum);
|
||||
else
|
||||
{
|
||||
heap_prune_record_redirect(prstate, rootoffnum, chainitems[i]);
|
||||
/* If the redirection will be a move, need more processing */
|
||||
if (redirect_move)
|
||||
redirect_target = chainitems[i];
|
||||
}
|
||||
}
|
||||
else if (nchain < 2 && ItemIdIsRedirected(rootlp))
|
||||
{
|
||||
|
@ -610,42 +569,6 @@ heap_prune_chain(Relation relation, Buffer buffer, OffsetNumber rootoffnum,
|
|||
*/
|
||||
heap_prune_record_dead(prstate, rootoffnum);
|
||||
}
|
||||
else if (redirect_move && ItemIdIsRedirected(rootlp))
|
||||
{
|
||||
/*
|
||||
* If we desire to eliminate LP_REDIRECT items by moving tuples, make
|
||||
* a redirection entry for each redirected root item; this will cause
|
||||
* heap_page_prune_execute to actually do the move. (We get here only
|
||||
* when there are no DEAD tuples in the chain; otherwise the
|
||||
* redirection entry was made above.)
|
||||
*/
|
||||
heap_prune_record_redirect(prstate, rootoffnum, chainitems[1]);
|
||||
redirect_target = chainitems[1];
|
||||
}
|
||||
|
||||
/*
|
||||
* If we are going to implement a redirect by moving tuples, we have to
|
||||
* issue a cache invalidation against the redirection target tuple,
|
||||
* because its CTID will be effectively changed by the move. Note that
|
||||
* CacheInvalidateHeapTuple only queues the request, it doesn't send it;
|
||||
* if we fail before reaching EndNonTransactionalInvalidation, nothing
|
||||
* happens and no harm is done.
|
||||
*/
|
||||
if (OffsetNumberIsValid(redirect_target))
|
||||
{
|
||||
ItemId firstlp = PageGetItemId(dp, redirect_target);
|
||||
HeapTupleData firsttup;
|
||||
|
||||
Assert(ItemIdIsNormal(firstlp));
|
||||
/* Set up firsttup to reference the tuple at its existing CTID */
|
||||
firsttup.t_data = (HeapTupleHeader) PageGetItem(dp, firstlp);
|
||||
firsttup.t_len = ItemIdGetLength(firstlp);
|
||||
ItemPointerSet(&firsttup.t_self,
|
||||
BufferGetBlockNumber(buffer),
|
||||
redirect_target);
|
||||
firsttup.t_tableOid = RelationGetRelid(relation);
|
||||
CacheInvalidateHeapTuple(relation, &firsttup);
|
||||
}
|
||||
|
||||
return ndeleted;
|
||||
}
|
||||
|
@ -715,14 +638,13 @@ void
|
|||
heap_page_prune_execute(Buffer buffer,
|
||||
OffsetNumber *redirected, int nredirected,
|
||||
OffsetNumber *nowdead, int ndead,
|
||||
OffsetNumber *nowunused, int nunused,
|
||||
bool redirect_move)
|
||||
OffsetNumber *nowunused, int nunused)
|
||||
{
|
||||
Page page = (Page) BufferGetPage(buffer);
|
||||
OffsetNumber *offnum;
|
||||
int i;
|
||||
|
||||
/* Update all redirected or moved line pointers */
|
||||
/* Update all redirected line pointers */
|
||||
offnum = redirected;
|
||||
for (i = 0; i < nredirected; i++)
|
||||
{
|
||||
|
@ -730,30 +652,7 @@ heap_page_prune_execute(Buffer buffer,
|
|||
OffsetNumber tooff = *offnum++;
|
||||
ItemId fromlp = PageGetItemId(page, fromoff);
|
||||
|
||||
if (redirect_move)
|
||||
{
|
||||
/* Physically move the "to" item to the "from" slot */
|
||||
ItemId tolp = PageGetItemId(page, tooff);
|
||||
HeapTupleHeader htup;
|
||||
|
||||
*fromlp = *tolp;
|
||||
ItemIdSetUnused(tolp);
|
||||
|
||||
/*
|
||||
* Change heap-only status of the tuple because after the line
|
||||
* pointer manipulation, it's no longer a heap-only tuple, but is
|
||||
* directly pointed to by index entries.
|
||||
*/
|
||||
Assert(ItemIdIsNormal(fromlp));
|
||||
htup = (HeapTupleHeader) PageGetItem(page, fromlp);
|
||||
Assert(HeapTupleHeaderIsHeapOnly(htup));
|
||||
HeapTupleHeaderClearHeapOnly(htup);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Just insert a REDIRECT link at fromoff */
|
||||
ItemIdSetRedirect(fromlp, tooff);
|
||||
}
|
||||
ItemIdSetRedirect(fromlp, tooff);
|
||||
}
|
||||
|
||||
/* Update all now-dead line pointers */
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
$PostgreSQL: pgsql/src/backend/access/nbtree/README,v 1.21 2009/12/19 01:32:32 sriggs Exp $
|
||||
$PostgreSQL: pgsql/src/backend/access/nbtree/README,v 1.22 2010/02/08 04:33:53 tgl Exp $
|
||||
|
||||
Btree Indexing
|
||||
==============
|
||||
|
@ -171,9 +171,9 @@ We consider deleting an entire page from the btree only when it's become
|
|||
completely empty of items. (Merging partly-full pages would allow better
|
||||
space reuse, but it seems impractical to move existing data items left or
|
||||
right to make this happen --- a scan moving in the opposite direction
|
||||
might miss the items if so. We could do it during VACUUM FULL, though.)
|
||||
Also, we *never* delete the rightmost page on a tree level (this
|
||||
restriction simplifies the traversal algorithms, as explained below).
|
||||
might miss the items if so.) Also, we *never* delete the rightmost page
|
||||
on a tree level (this restriction simplifies the traversal algorithms, as
|
||||
explained below).
|
||||
|
||||
To delete an empty page, we acquire write lock on its left sibling (if
|
||||
any), the target page itself, the right sibling (there must be one), and
|
||||
|
@ -266,8 +266,7 @@ transactions that were running at the time of deletion are dead; which is
|
|||
overly strong, but is simple to implement within Postgres. When marked
|
||||
dead, a deleted page is labeled with the next-transaction counter value.
|
||||
VACUUM can reclaim the page for re-use when this transaction number is
|
||||
older than the oldest open transaction. (NOTE: VACUUM FULL can reclaim
|
||||
such pages immediately.)
|
||||
older than the oldest open transaction.
|
||||
|
||||
Reclaiming a page doesn't actually change its state on disk --- we simply
|
||||
record it in the shared-memory free space map, from which it will be
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/nbtree/nbtpage.c,v 1.117 2010/02/01 13:40:28 sriggs Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/nbtree/nbtpage.c,v 1.118 2010/02/08 04:33:53 tgl Exp $
|
||||
*
|
||||
* NOTES
|
||||
* Postgres btree pages look like ordinary relation pages. The opaque
|
||||
|
@ -877,7 +877,7 @@ _bt_parent_deletion_safe(Relation rel, BlockNumber target, BTStack stack)
|
|||
* frequently.
|
||||
*/
|
||||
int
|
||||
_bt_pagedel(Relation rel, Buffer buf, BTStack stack, bool vacuum_full)
|
||||
_bt_pagedel(Relation rel, Buffer buf, BTStack stack)
|
||||
{
|
||||
int result;
|
||||
BlockNumber target,
|
||||
|
@ -1207,14 +1207,13 @@ _bt_pagedel(Relation rel, Buffer buf, BTStack stack, bool vacuum_full)
|
|||
|
||||
/*
|
||||
* Mark the page itself deleted. It can be recycled when all current
|
||||
* transactions are gone; or immediately if we're doing VACUUM FULL.
|
||||
* transactions are gone.
|
||||
*/
|
||||
page = BufferGetPage(buf);
|
||||
opaque = (BTPageOpaque) PageGetSpecialPointer(page);
|
||||
opaque->btpo_flags &= ~BTP_HALF_DEAD;
|
||||
opaque->btpo_flags |= BTP_DELETED;
|
||||
opaque->btpo.xact =
|
||||
vacuum_full ? FrozenTransactionId : ReadNewTransactionId();
|
||||
opaque->btpo.xact = ReadNewTransactionId();
|
||||
|
||||
/* And update the metapage, if needed */
|
||||
if (BufferIsValid(metabuf))
|
||||
|
@ -1350,7 +1349,7 @@ _bt_pagedel(Relation rel, Buffer buf, BTStack stack, bool vacuum_full)
|
|||
{
|
||||
/* recursive call will release pbuf */
|
||||
_bt_relbuf(rel, rbuf);
|
||||
result = _bt_pagedel(rel, pbuf, stack->bts_parent, vacuum_full) + 1;
|
||||
result = _bt_pagedel(rel, pbuf, stack->bts_parent) + 1;
|
||||
_bt_relbuf(rel, buf);
|
||||
}
|
||||
else if (parent_one_child && rightsib_empty)
|
||||
|
@ -1358,7 +1357,7 @@ _bt_pagedel(Relation rel, Buffer buf, BTStack stack, bool vacuum_full)
|
|||
_bt_relbuf(rel, pbuf);
|
||||
_bt_relbuf(rel, buf);
|
||||
/* recursive call will release rbuf */
|
||||
result = _bt_pagedel(rel, rbuf, stack, vacuum_full) + 1;
|
||||
result = _bt_pagedel(rel, rbuf, stack) + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/nbtree/nbtree.c,v 1.174 2010/01/02 16:57:35 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/nbtree/nbtree.c,v 1.175 2010/02/08 04:33:53 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -579,12 +579,12 @@ btvacuumcleanup(PG_FUNCTION_ARGS)
|
|||
IndexFreeSpaceMapVacuum(info->index);
|
||||
|
||||
/*
|
||||
* During a non-FULL vacuum it's quite possible for us to be fooled by
|
||||
* concurrent page splits into double-counting some index tuples, so
|
||||
* disbelieve any total that exceeds the underlying heap's count ... if we
|
||||
* know that accurately. Otherwise this might just make matters worse.
|
||||
* It's quite possible for us to be fooled by concurrent page splits into
|
||||
* double-counting some index tuples, so disbelieve any total that exceeds
|
||||
* the underlying heap's count ... if we know that accurately. Otherwise
|
||||
* this might just make matters worse.
|
||||
*/
|
||||
if (!info->vacuum_full && !info->estimated_count)
|
||||
if (!info->estimated_count)
|
||||
{
|
||||
if (stats->num_index_tuples > info->num_heap_tuples)
|
||||
stats->num_index_tuples = info->num_heap_tuples;
|
||||
|
@ -686,27 +686,6 @@ btvacuumscan(IndexVacuumInfo *info, IndexBulkDeleteResult *stats,
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* During VACUUM FULL, we truncate off any recyclable pages at the end of
|
||||
* the index. In a normal vacuum it'd be unsafe to do this except by
|
||||
* acquiring exclusive lock on the index and then rechecking all the
|
||||
* pages; doesn't seem worth it.
|
||||
*/
|
||||
if (info->vacuum_full && vstate.lastUsedPage < num_pages - 1)
|
||||
{
|
||||
BlockNumber new_pages = vstate.lastUsedPage + 1;
|
||||
|
||||
/*
|
||||
* Okay to truncate.
|
||||
*/
|
||||
RelationTruncate(rel, new_pages);
|
||||
|
||||
/* update statistics */
|
||||
stats->pages_removed += num_pages - new_pages;
|
||||
vstate.totFreePages -= (num_pages - new_pages);
|
||||
num_pages = new_pages;
|
||||
}
|
||||
|
||||
/*
|
||||
* InHotStandby we need to scan right up to the end of the index for
|
||||
* correct locking, so we may need to write a WAL record for the final
|
||||
|
@ -963,26 +942,12 @@ restart:
|
|||
MemoryContextReset(vstate->pagedelcontext);
|
||||
oldcontext = MemoryContextSwitchTo(vstate->pagedelcontext);
|
||||
|
||||
ndel = _bt_pagedel(rel, buf, NULL, info->vacuum_full);
|
||||
ndel = _bt_pagedel(rel, buf, NULL);
|
||||
|
||||
/* count only this page, else may double-count parent */
|
||||
if (ndel)
|
||||
stats->pages_deleted++;
|
||||
|
||||
/*
|
||||
* During VACUUM FULL it's okay to recycle deleted pages immediately,
|
||||
* since there can be no other transactions scanning the index. Note
|
||||
* that we will only recycle the current page and not any parent pages
|
||||
* that _bt_pagedel might have recursed to; this seems reasonable in
|
||||
* the name of simplicity. (Trying to do otherwise would mean we'd
|
||||
* have to sort the list of recyclable pages we're building.)
|
||||
*/
|
||||
if (ndel && info->vacuum_full)
|
||||
{
|
||||
RecordFreeIndexPage(rel, blkno);
|
||||
vstate->totFreePages++;
|
||||
}
|
||||
|
||||
MemoryContextSwitchTo(oldcontext);
|
||||
/* pagedel released buffer, so we shouldn't */
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/nbtree/nbtxlog.c,v 1.59 2010/01/29 17:10:05 sriggs Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/nbtree/nbtxlog.c,v 1.60 2010/02/08 04:33:53 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -1079,8 +1079,8 @@ btree_xlog_cleanup(void)
|
|||
Relation reln;
|
||||
|
||||
reln = CreateFakeRelcacheEntry(action->node);
|
||||
if (_bt_pagedel(reln, buf, NULL, true) == 0)
|
||||
elog(PANIC, "btree_xlog_cleanup: _bt_pagdel failed");
|
||||
if (_bt_pagedel(reln, buf, NULL) == 0)
|
||||
elog(PANIC, "btree_xlog_cleanup: _bt_pagedel failed");
|
||||
FreeFakeRelcacheEntry(reln);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.283 2010/02/07 20:48:09 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.284 2010/02/08 04:33:53 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -881,11 +881,9 @@ AtSubStart_ResourceOwner(void)
|
|||
*
|
||||
* Returns latest XID among xact and its children, or InvalidTransactionId
|
||||
* if the xact has no XID. (We compute that here just because it's easier.)
|
||||
*
|
||||
* This is exported only to support an ugly hack in VACUUM FULL.
|
||||
*/
|
||||
TransactionId
|
||||
RecordTransactionCommit(bool isVacuumFull)
|
||||
static TransactionId
|
||||
RecordTransactionCommit(void)
|
||||
{
|
||||
TransactionId xid = GetTopTransactionIdIfAny();
|
||||
bool markXidCommitted = TransactionIdIsValid(xid);
|
||||
|
@ -950,8 +948,6 @@ RecordTransactionCommit(bool isVacuumFull)
|
|||
xlrec.xinfo = 0;
|
||||
if (RelcacheInitFileInval)
|
||||
xlrec.xinfo |= XACT_COMPLETION_UPDATE_RELCACHE_FILE;
|
||||
if (isVacuumFull)
|
||||
xlrec.xinfo |= XACT_COMPLETION_VACUUM_FULL;
|
||||
if (forceSyncCommit)
|
||||
xlrec.xinfo |= XACT_COMPLETION_FORCE_SYNC_COMMIT;
|
||||
|
||||
|
@ -1755,7 +1751,7 @@ CommitTransaction(void)
|
|||
/*
|
||||
* Here is where we really truly commit.
|
||||
*/
|
||||
latestXid = RecordTransactionCommit(false);
|
||||
latestXid = RecordTransactionCommit();
|
||||
|
||||
TRACE_POSTGRESQL_TRANSACTION_COMMIT(MyProc->lxid);
|
||||
|
||||
|
@ -4374,28 +4370,23 @@ xact_redo_commit(xl_xact_commit *xlrec, TransactionId xid, XLogRecPtr lsn)
|
|||
LWLockRelease(XidGenLock);
|
||||
}
|
||||
|
||||
if (!InHotStandby || XactCompletionVacuumFull(xlrec))
|
||||
if (!InHotStandby)
|
||||
{
|
||||
/*
|
||||
* Mark the transaction committed in pg_clog.
|
||||
*
|
||||
* If InHotStandby and this is the first commit of a VACUUM FULL INPLACE
|
||||
* we perform only the actual commit to clog. Strangely, there are two
|
||||
* commits that share the same xid for every VFI, so we need to skip
|
||||
* some steps for the first commit. It's OK to repeat the clog update
|
||||
* when we see the second commit on a VFI.
|
||||
*/
|
||||
TransactionIdCommitTree(xid, xlrec->nsubxacts, sub_xids);
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* If a transaction completion record arrives that has as-yet unobserved
|
||||
* subtransactions then this will not have been fully handled by the call
|
||||
* to RecordKnownAssignedTransactionIds() in the main recovery loop in
|
||||
* xlog.c. So we need to do bookkeeping again to cover that case. This is
|
||||
* confusing and it is easy to think this call is irrelevant, which has
|
||||
* happened three times in development already. Leave it in.
|
||||
* If a transaction completion record arrives that has as-yet
|
||||
* unobserved subtransactions then this will not have been fully
|
||||
* handled by the call to RecordKnownAssignedTransactionIds() in the
|
||||
* main recovery loop in xlog.c. So we need to do bookkeeping again to
|
||||
* cover that case. This is confusing and it is easy to think this
|
||||
* call is irrelevant, which has happened three times in development
|
||||
* already. Leave it in.
|
||||
*/
|
||||
RecordKnownAssignedTransactionIds(max_xid);
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
* Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/backend/access/transam/xlog.c,v 1.367 2010/02/07 20:48:09 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/transam/xlog.c,v 1.368 2010/02/08 04:33:53 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -2106,32 +2106,6 @@ XLogBackgroundFlush(void)
|
|||
END_CRIT_SECTION();
|
||||
}
|
||||
|
||||
/*
|
||||
* Flush any previous asynchronously-committed transactions' commit records.
|
||||
*
|
||||
* NOTE: it is unwise to assume that this provides any strong guarantees.
|
||||
* In particular, because of the inexact LSN bookkeeping used by clog.c,
|
||||
* we cannot assume that hint bits will be settable for these transactions.
|
||||
*/
|
||||
void
|
||||
XLogAsyncCommitFlush(void)
|
||||
{
|
||||
XLogRecPtr WriteRqstPtr;
|
||||
|
||||
/* use volatile pointer to prevent code rearrangement */
|
||||
volatile XLogCtlData *xlogctl = XLogCtl;
|
||||
|
||||
/* There's no asynchronously committed transactions during recovery */
|
||||
if (RecoveryInProgress())
|
||||
return;
|
||||
|
||||
SpinLockAcquire(&xlogctl->info_lck);
|
||||
WriteRqstPtr = xlogctl->asyncCommitLSN;
|
||||
SpinLockRelease(&xlogctl->info_lck);
|
||||
|
||||
XLogFlush(WriteRqstPtr);
|
||||
}
|
||||
|
||||
/*
|
||||
* Test whether XLOG data has been flushed up to (at least) the given position.
|
||||
*
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/catalog/index.c,v 1.334 2010/02/07 22:40:33 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/catalog/index.c,v 1.335 2010/02/08 04:33:53 tgl Exp $
|
||||
*
|
||||
*
|
||||
* INTERFACE ROUTINES
|
||||
|
@ -2107,7 +2107,6 @@ validate_index(Oid heapId, Oid indexId, Snapshot snapshot)
|
|||
* Scan the index and gather up all the TIDs into a tuplesort object.
|
||||
*/
|
||||
ivinfo.index = indexRelation;
|
||||
ivinfo.vacuum_full = false;
|
||||
ivinfo.analyze_only = false;
|
||||
ivinfo.estimated_count = true;
|
||||
ivinfo.message_level = DEBUG2;
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/commands/analyze.c,v 1.149 2010/02/01 19:28:56 rhaas Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/commands/analyze.c,v 1.150 2010/02/08 04:33:53 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -595,7 +595,6 @@ cleanup:
|
|||
IndexVacuumInfo ivinfo;
|
||||
|
||||
ivinfo.index = Irel[ind];
|
||||
ivinfo.vacuum_full = false;
|
||||
ivinfo.analyze_only = true;
|
||||
ivinfo.estimated_count = true;
|
||||
ivinfo.message_level = elevel;
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/commands/copy.c,v 1.323 2010/02/03 10:01:29 heikki Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/commands/copy.c,v 1.324 2010/02/08 04:33:53 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -2166,7 +2166,7 @@ CopyFrom(CopyState cstate)
|
|||
|
||||
if (resultRelInfo->ri_NumIndices > 0)
|
||||
recheckIndexes = ExecInsertIndexTuples(slot, &(tuple->t_self),
|
||||
estate, false);
|
||||
estate);
|
||||
|
||||
/* AFTER ROW INSERT Triggers */
|
||||
ExecARInsertTriggers(estate, resultRelInfo, tuple,
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -29,7 +29,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/commands/vacuumlazy.c,v 1.128 2010/01/28 07:31:42 heikki Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/commands/vacuumlazy.c,v 1.129 2010/02/08 04:33:54 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -501,8 +501,7 @@ lazy_scan_heap(Relation onerel, LVRelStats *vacrelstats,
|
|||
*
|
||||
* We count tuples removed by the pruning step as removed by VACUUM.
|
||||
*/
|
||||
tups_vacuumed += heap_page_prune(onerel, buf, OldestXmin,
|
||||
false, false);
|
||||
tups_vacuumed += heap_page_prune(onerel, buf, OldestXmin, false);
|
||||
|
||||
/*
|
||||
* Now scan the page to collect vacuumable items and check for tuples
|
||||
|
@ -907,7 +906,7 @@ lazy_vacuum_page(Relation onerel, BlockNumber blkno, Buffer buffer,
|
|||
recptr = log_heap_clean(onerel, buffer,
|
||||
NULL, 0, NULL, 0,
|
||||
unused, uncnt,
|
||||
vacrelstats->latestRemovedXid, false);
|
||||
vacrelstats->latestRemovedXid);
|
||||
PageSetLSN(page, recptr);
|
||||
PageSetTLI(page, ThisTimeLineID);
|
||||
}
|
||||
|
@ -934,7 +933,6 @@ lazy_vacuum_index(Relation indrel,
|
|||
pg_rusage_init(&ru0);
|
||||
|
||||
ivinfo.index = indrel;
|
||||
ivinfo.vacuum_full = false;
|
||||
ivinfo.analyze_only = false;
|
||||
ivinfo.estimated_count = true;
|
||||
ivinfo.message_level = elevel;
|
||||
|
@ -966,7 +964,6 @@ lazy_cleanup_index(Relation indrel,
|
|||
pg_rusage_init(&ru0);
|
||||
|
||||
ivinfo.index = indrel;
|
||||
ivinfo.vacuum_full = false;
|
||||
ivinfo.analyze_only = false;
|
||||
ivinfo.estimated_count = !vacrelstats->scanned_all;
|
||||
ivinfo.message_level = elevel;
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/executor/execUtils.c,v 1.169 2010/01/02 17:53:56 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/executor/execUtils.c,v 1.170 2010/02/08 04:33:54 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -977,8 +977,7 @@ ExecCloseIndices(ResultRelInfo *resultRelInfo)
|
|||
List *
|
||||
ExecInsertIndexTuples(TupleTableSlot *slot,
|
||||
ItemPointer tupleid,
|
||||
EState *estate,
|
||||
bool is_vacuum_full)
|
||||
EState *estate)
|
||||
{
|
||||
List *result = NIL;
|
||||
ResultRelInfo *resultRelInfo;
|
||||
|
@ -1070,12 +1069,8 @@ ExecInsertIndexTuples(TupleTableSlot *slot,
|
|||
* For a deferrable unique index, we tell the index AM to just detect
|
||||
* possible non-uniqueness, and we add the index OID to the result
|
||||
* list if further checking is needed.
|
||||
*
|
||||
* Special hack: we suppress unique-index checks if we are being
|
||||
* called from VACUUM FULL, since VACUUM FULL may need to move dead
|
||||
* tuples that have the same keys as live ones.
|
||||
*/
|
||||
if (is_vacuum_full || !indexRelation->rd_index->indisunique)
|
||||
if (!indexRelation->rd_index->indisunique)
|
||||
checkUnique = UNIQUE_CHECK_NO;
|
||||
else if (indexRelation->rd_index->indimmediate)
|
||||
checkUnique = UNIQUE_CHECK_YES;
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/executor/nodeModifyTable.c,v 1.5 2010/01/31 18:15:39 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/executor/nodeModifyTable.c,v 1.6 2010/02/08 04:33:54 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -249,7 +249,7 @@ ExecInsert(TupleTableSlot *slot,
|
|||
*/
|
||||
if (resultRelInfo->ri_NumIndices > 0)
|
||||
recheckIndexes = ExecInsertIndexTuples(slot, &(tuple->t_self),
|
||||
estate, false);
|
||||
estate);
|
||||
|
||||
/* AFTER ROW INSERT Triggers */
|
||||
ExecARInsertTriggers(estate, resultRelInfo, tuple, recheckIndexes);
|
||||
|
@ -566,7 +566,7 @@ lreplace:;
|
|||
*/
|
||||
if (resultRelInfo->ri_NumIndices > 0 && !HeapTupleIsHeapOnly(tuple))
|
||||
recheckIndexes = ExecInsertIndexTuples(slot, &(tuple->t_self),
|
||||
estate, false);
|
||||
estate);
|
||||
|
||||
/* AFTER ROW UPDATE Triggers */
|
||||
ExecARUpdateTriggers(estate, resultRelInfo, tupleid, tuple,
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.706 2010/01/28 23:21:12 petere Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.707 2010/02/08 04:33:54 tgl Exp $
|
||||
*
|
||||
* HISTORY
|
||||
* AUTHOR DATE MAJOR EVENT
|
||||
|
@ -491,7 +491,7 @@ static TypeName *TableFuncTypeName(List *columns);
|
|||
|
||||
IDENTITY_P IF_P ILIKE IMMEDIATE IMMUTABLE IMPLICIT_P IN_P
|
||||
INCLUDING INCREMENT INDEX INDEXES INHERIT INHERITS INITIALLY INLINE_P
|
||||
INNER_P INOUT INPLACE INPUT_P INSENSITIVE INSERT INSTEAD INT_P INTEGER
|
||||
INNER_P INOUT INPUT_P INSENSITIVE INSERT INSTEAD INT_P INTEGER
|
||||
INTERSECT INTERVAL INTO INVOKER IS ISNULL ISOLATION
|
||||
|
||||
JOIN
|
||||
|
@ -6830,7 +6830,6 @@ vacuum_option_elem:
|
|||
| VERBOSE { $$ = VACOPT_VERBOSE; }
|
||||
| FREEZE { $$ = VACOPT_FREEZE; }
|
||||
| FULL { $$ = VACOPT_FULL; }
|
||||
| FULL INPLACE { $$ = VACOPT_FULL | VACOPT_INPLACE; }
|
||||
;
|
||||
|
||||
AnalyzeStmt:
|
||||
|
@ -10822,7 +10821,6 @@ unreserved_keyword:
|
|||
| INHERIT
|
||||
| INHERITS
|
||||
| INLINE_P
|
||||
| INPLACE
|
||||
| INPUT_P
|
||||
| INSENSITIVE
|
||||
| INSERT
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/storage/lmgr/proc.c,v 1.214 2010/01/23 16:37:12 sriggs Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/storage/lmgr/proc.c,v 1.215 2010/02/08 04:33:54 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -617,8 +617,7 @@ LockWaitCancel(void)
|
|||
* at main transaction commit or abort
|
||||
*
|
||||
* At main transaction commit, we release all locks except session locks.
|
||||
* At main transaction abort, we release all locks including session locks;
|
||||
* this lets us clean up after a VACUUM FULL failure.
|
||||
* At main transaction abort, we release all locks including session locks.
|
||||
*
|
||||
* At subtransaction commit, we don't release any locks (so this func is not
|
||||
* needed at all); we will defer the releasing to the parent transaction.
|
||||
|
|
|
@ -80,7 +80,7 @@
|
|||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/utils/cache/inval.c,v 1.94 2010/02/07 20:48:10 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/utils/cache/inval.c,v 1.95 2010/02/08 04:33:54 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -1112,103 +1112,6 @@ CommandEndInvalidationMessages(void)
|
|||
}
|
||||
|
||||
|
||||
/*
|
||||
* BeginNonTransactionalInvalidation
|
||||
* Prepare for invalidation messages for nontransactional updates.
|
||||
*
|
||||
* A nontransactional invalidation is one that must be sent whether or not
|
||||
* the current transaction eventually commits. We arrange for all invals
|
||||
* queued between this call and EndNonTransactionalInvalidation() to be sent
|
||||
* immediately when the latter is called.
|
||||
*
|
||||
* Currently, this is only used by heap_page_prune(), and only when it is
|
||||
* invoked during VACUUM FULL's first pass over a table. We expect therefore
|
||||
* that we are not inside a subtransaction and there are no already-pending
|
||||
* invalidations. This could be relaxed by setting up a new nesting level of
|
||||
* invalidation data, but for now there's no need. Note that heap_page_prune
|
||||
* knows that this function does not change any state, and therefore there's
|
||||
* no need to worry about cleaning up if there's an elog(ERROR) before
|
||||
* reaching EndNonTransactionalInvalidation (the invals will just be thrown
|
||||
* away if that happens).
|
||||
*
|
||||
* Note that these are not replayed in standby mode.
|
||||
*/
|
||||
void
|
||||
BeginNonTransactionalInvalidation(void)
|
||||
{
|
||||
/* Must be at top of stack */
|
||||
Assert(transInvalInfo != NULL && transInvalInfo->parent == NULL);
|
||||
|
||||
/* Must not have any previously-queued activity */
|
||||
Assert(transInvalInfo->PriorCmdInvalidMsgs.cclist == NULL);
|
||||
Assert(transInvalInfo->PriorCmdInvalidMsgs.rclist == NULL);
|
||||
Assert(transInvalInfo->CurrentCmdInvalidMsgs.cclist == NULL);
|
||||
Assert(transInvalInfo->CurrentCmdInvalidMsgs.rclist == NULL);
|
||||
Assert(transInvalInfo->RelcacheInitFileInval == false);
|
||||
|
||||
SharedInvalidMessagesArray = NULL;
|
||||
numSharedInvalidMessagesArray = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* EndNonTransactionalInvalidation
|
||||
* Process queued-up invalidation messages for nontransactional updates.
|
||||
*
|
||||
* We expect to find messages in CurrentCmdInvalidMsgs only (else there
|
||||
* was a CommandCounterIncrement within the "nontransactional" update).
|
||||
* We must process them locally and send them out to the shared invalidation
|
||||
* message queue.
|
||||
*
|
||||
* We must also reset the lists to empty and explicitly free memory (we can't
|
||||
* rely on end-of-transaction cleanup for that).
|
||||
*/
|
||||
void
|
||||
EndNonTransactionalInvalidation(void)
|
||||
{
|
||||
InvalidationChunk *chunk;
|
||||
InvalidationChunk *next;
|
||||
|
||||
/* Must be at top of stack */
|
||||
Assert(transInvalInfo != NULL && transInvalInfo->parent == NULL);
|
||||
|
||||
/* Must not have any prior-command messages */
|
||||
Assert(transInvalInfo->PriorCmdInvalidMsgs.cclist == NULL);
|
||||
Assert(transInvalInfo->PriorCmdInvalidMsgs.rclist == NULL);
|
||||
|
||||
/*
|
||||
* At present, this function is only used for CTID-changing updates; since
|
||||
* the relcache init file doesn't store any tuple CTIDs, we don't have to
|
||||
* invalidate it. That might not be true forever though, in which case
|
||||
* we'd need code similar to AtEOXact_Inval.
|
||||
*/
|
||||
|
||||
/* Send out the invals */
|
||||
ProcessInvalidationMessages(&transInvalInfo->CurrentCmdInvalidMsgs,
|
||||
LocalExecuteInvalidationMessage);
|
||||
ProcessInvalidationMessagesMulti(&transInvalInfo->CurrentCmdInvalidMsgs,
|
||||
SendSharedInvalidMessages);
|
||||
|
||||
/* Clean up and release memory */
|
||||
for (chunk = transInvalInfo->CurrentCmdInvalidMsgs.cclist;
|
||||
chunk != NULL;
|
||||
chunk = next)
|
||||
{
|
||||
next = chunk->next;
|
||||
pfree(chunk);
|
||||
}
|
||||
for (chunk = transInvalInfo->CurrentCmdInvalidMsgs.rclist;
|
||||
chunk != NULL;
|
||||
chunk = next)
|
||||
{
|
||||
next = chunk->next;
|
||||
pfree(chunk);
|
||||
}
|
||||
transInvalInfo->CurrentCmdInvalidMsgs.cclist = NULL;
|
||||
transInvalInfo->CurrentCmdInvalidMsgs.rclist = NULL;
|
||||
transInvalInfo->RelcacheInitFileInval = false;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* CacheInvalidateHeapTuple
|
||||
* Register the given tuple for invalidation at end of command
|
||||
|
|
|
@ -50,7 +50,7 @@
|
|||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/utils/time/tqual.c,v 1.115 2010/01/02 16:57:58 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/utils/time/tqual.c,v 1.116 2010/02/08 04:33:54 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -91,9 +91,12 @@ static bool XidInMVCCSnapshot(TransactionId xid, Snapshot snapshot);
|
|||
* code in heapam.c relies on that!)
|
||||
*
|
||||
* Also, if we are cleaning up HEAP_MOVED_IN or HEAP_MOVED_OFF entries, then
|
||||
* we can always set the hint bits, since VACUUM FULL always uses synchronous
|
||||
* commits and doesn't move tuples that weren't previously hinted. (This is
|
||||
* not known by this subroutine, but is applied by its callers.)
|
||||
* we can always set the hint bits, since old-style VACUUM FULL always used
|
||||
* synchronous commits and didn't move tuples that weren't previously
|
||||
* hinted. (This is not known by this subroutine, but is applied by its
|
||||
* callers.) Note: old-style VACUUM FULL is gone, but we have to keep this
|
||||
* module's support for MOVED_OFF/MOVED_IN flag bits for as long as we
|
||||
* support in-place update from pre-9.0 databases.
|
||||
*
|
||||
* Normal commits may be asynchronous, so for those we need to get the LSN
|
||||
* of the transaction and then check whether this is flushed.
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/bin/scripts/vacuumdb.c,v 1.33 2010/01/07 14:35:44 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/bin/scripts/vacuumdb.c,v 1.34 2010/02/08 04:33:54 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -14,12 +14,12 @@
|
|||
#include "common.h"
|
||||
|
||||
|
||||
static void vacuum_one_database(const char *dbname, bool full, bool inplace, bool verbose,
|
||||
static void vacuum_one_database(const char *dbname, bool full, bool verbose,
|
||||
bool and_analyze, bool analyze_only, bool freeze,
|
||||
const char *table, const char *host, const char *port,
|
||||
const char *username, enum trivalue prompt_password,
|
||||
const char *progname, bool echo);
|
||||
static void vacuum_all_databases(bool full, bool inplace, bool verbose, bool and_analyze,
|
||||
static void vacuum_all_databases(bool full, bool verbose, bool and_analyze,
|
||||
bool analyze_only, bool freeze,
|
||||
const char *host, const char *port,
|
||||
const char *username, enum trivalue prompt_password,
|
||||
|
@ -47,7 +47,6 @@ main(int argc, char *argv[])
|
|||
{"table", required_argument, NULL, 't'},
|
||||
{"full", no_argument, NULL, 'f'},
|
||||
{"verbose", no_argument, NULL, 'v'},
|
||||
{"inplace", no_argument, NULL, 'i'},
|
||||
{NULL, 0, NULL, 0}
|
||||
};
|
||||
|
||||
|
@ -69,14 +68,13 @@ main(int argc, char *argv[])
|
|||
char *table = NULL;
|
||||
bool full = false;
|
||||
bool verbose = false;
|
||||
bool inplace = false;
|
||||
|
||||
progname = get_progname(argv[0]);
|
||||
set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pgscripts"));
|
||||
|
||||
handle_help_version_opts(argc, argv, "vacuumdb", help);
|
||||
|
||||
while ((c = getopt_long(argc, argv, "h:p:U:wWeqd:zaFt:fiv", long_options, &optindex)) != -1)
|
||||
while ((c = getopt_long(argc, argv, "h:p:U:wWeqd:zaFt:fv", long_options, &optindex)) != -1)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
|
@ -122,9 +120,6 @@ main(int argc, char *argv[])
|
|||
case 'f':
|
||||
full = true;
|
||||
break;
|
||||
case 'i':
|
||||
inplace = true;
|
||||
break;
|
||||
case 'v':
|
||||
verbose = true;
|
||||
break;
|
||||
|
@ -148,13 +143,6 @@ main(int argc, char *argv[])
|
|||
exit(1);
|
||||
}
|
||||
|
||||
if (inplace && !full)
|
||||
{
|
||||
fprintf(stderr, _("%s: cannot use the \"inplace\" option when performing full vacuum\n"),
|
||||
progname);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (analyze_only)
|
||||
{
|
||||
if (full)
|
||||
|
@ -189,7 +177,7 @@ main(int argc, char *argv[])
|
|||
exit(1);
|
||||
}
|
||||
|
||||
vacuum_all_databases(full, inplace, verbose, and_analyze, analyze_only, freeze,
|
||||
vacuum_all_databases(full, verbose, and_analyze, analyze_only, freeze,
|
||||
host, port, username, prompt_password,
|
||||
progname, echo, quiet);
|
||||
}
|
||||
|
@ -205,7 +193,7 @@ main(int argc, char *argv[])
|
|||
dbname = get_user_name(progname);
|
||||
}
|
||||
|
||||
vacuum_one_database(dbname, full, inplace, verbose, and_analyze, analyze_only,
|
||||
vacuum_one_database(dbname, full, verbose, and_analyze, analyze_only,
|
||||
freeze, table,
|
||||
host, port, username, prompt_password,
|
||||
progname, echo);
|
||||
|
@ -216,7 +204,7 @@ main(int argc, char *argv[])
|
|||
|
||||
|
||||
static void
|
||||
vacuum_one_database(const char *dbname, bool full, bool inplace, bool verbose, bool and_analyze,
|
||||
vacuum_one_database(const char *dbname, bool full, bool verbose, bool and_analyze,
|
||||
bool analyze_only, bool freeze, const char *table,
|
||||
const char *host, const char *port,
|
||||
const char *username, enum trivalue prompt_password,
|
||||
|
@ -247,8 +235,7 @@ vacuum_one_database(const char *dbname, bool full, bool inplace, bool verbose, b
|
|||
|
||||
if (full)
|
||||
{
|
||||
appendPQExpBuffer(&sql, "%sFULL%s", sep,
|
||||
inplace ? " INPLACE" : "");
|
||||
appendPQExpBuffer(&sql, "%sFULL", sep);
|
||||
sep = comma;
|
||||
}
|
||||
if (freeze)
|
||||
|
@ -271,10 +258,6 @@ vacuum_one_database(const char *dbname, bool full, bool inplace, bool verbose, b
|
|||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* On older servers, VACUUM FULL is equivalent to VACUUM (FULL
|
||||
* INPLACE) on newer servers, so we can ignore 'inplace'.
|
||||
*/
|
||||
if (full)
|
||||
appendPQExpBuffer(&sql, " FULL");
|
||||
if (freeze)
|
||||
|
@ -306,7 +289,7 @@ vacuum_one_database(const char *dbname, bool full, bool inplace, bool verbose, b
|
|||
|
||||
|
||||
static void
|
||||
vacuum_all_databases(bool full, bool inplace, bool verbose, bool and_analyze, bool analyze_only,
|
||||
vacuum_all_databases(bool full, bool verbose, bool and_analyze, bool analyze_only,
|
||||
bool freeze, const char *host, const char *port,
|
||||
const char *username, enum trivalue prompt_password,
|
||||
const char *progname, bool echo, bool quiet)
|
||||
|
@ -329,7 +312,7 @@ vacuum_all_databases(bool full, bool inplace, bool verbose, bool and_analyze, bo
|
|||
fflush(stdout);
|
||||
}
|
||||
|
||||
vacuum_one_database(dbname, full, inplace, verbose, and_analyze, analyze_only,
|
||||
vacuum_one_database(dbname, full, verbose, and_analyze, analyze_only,
|
||||
freeze, NULL, host, port, username, prompt_password,
|
||||
progname, echo);
|
||||
}
|
||||
|
@ -350,7 +333,6 @@ help(const char *progname)
|
|||
printf(_(" -e, --echo show the commands being sent to the server\n"));
|
||||
printf(_(" -f, --full do full vacuuming\n"));
|
||||
printf(_(" -F, --freeze freeze row transaction information\n"));
|
||||
printf(_(" -i, --inplace do full inplace vacuuming\n"));
|
||||
printf(_(" -q, --quiet don't write any messages\n"));
|
||||
printf(_(" -t, --table='TABLE[(COLUMNS)]' vacuum specific table only\n"));
|
||||
printf(_(" -v, --verbose write a lot of output\n"));
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
* Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/include/access/genam.h,v 1.82 2010/01/02 16:58:00 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/include/access/genam.h,v 1.83 2010/02/08 04:33:54 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -42,7 +42,6 @@ typedef struct IndexBuildResult
|
|||
typedef struct IndexVacuumInfo
|
||||
{
|
||||
Relation index; /* the index being vacuumed */
|
||||
bool vacuum_full; /* VACUUM FULL (we have exclusive lock) */
|
||||
bool analyze_only; /* ANALYZE (without any actual vacuum) */
|
||||
bool estimated_count; /* num_heap_tuples is an estimate */
|
||||
int message_level; /* ereport level for progress messages */
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
* Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/include/access/heapam.h,v 1.146 2010/01/02 16:58:00 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/include/access/heapam.h,v 1.147 2010/02/08 04:33:54 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -126,17 +126,13 @@ extern void heap_desc(StringInfo buf, uint8 xl_info, char *rec);
|
|||
extern void heap2_redo(XLogRecPtr lsn, XLogRecord *rptr);
|
||||
extern void heap2_desc(StringInfo buf, uint8 xl_info, char *rec);
|
||||
|
||||
extern XLogRecPtr log_heap_move(Relation reln, Buffer oldbuf,
|
||||
ItemPointerData from,
|
||||
Buffer newbuf, HeapTuple newtup,
|
||||
bool all_visible_cleared, bool new_all_visible_cleared);
|
||||
extern XLogRecPtr log_heap_cleanup_info(RelFileNode rnode,
|
||||
TransactionId latestRemovedXid);
|
||||
extern XLogRecPtr log_heap_clean(Relation reln, Buffer buffer,
|
||||
OffsetNumber *redirected, int nredirected,
|
||||
OffsetNumber *nowdead, int ndead,
|
||||
OffsetNumber *nowunused, int nunused,
|
||||
TransactionId latestRemovedXid, bool redirect_move);
|
||||
TransactionId latestRemovedXid);
|
||||
extern XLogRecPtr log_heap_freeze(Relation reln, Buffer buffer,
|
||||
TransactionId cutoff_xid,
|
||||
OffsetNumber *offsets, int offcnt);
|
||||
|
@ -148,12 +144,11 @@ extern void heap_page_prune_opt(Relation relation, Buffer buffer,
|
|||
TransactionId OldestXmin);
|
||||
extern int heap_page_prune(Relation relation, Buffer buffer,
|
||||
TransactionId OldestXmin,
|
||||
bool redirect_move, bool report_stats);
|
||||
bool report_stats);
|
||||
extern void heap_page_prune_execute(Buffer buffer,
|
||||
OffsetNumber *redirected, int nredirected,
|
||||
OffsetNumber *nowdead, int ndead,
|
||||
OffsetNumber *nowunused, int nunused,
|
||||
bool redirect_move);
|
||||
OffsetNumber *nowunused, int nunused);
|
||||
extern void heap_get_root_tuples(Page page, OffsetNumber *root_offsets);
|
||||
|
||||
/* in heap/syncscan.c */
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
* Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/include/access/htup.h,v 1.110 2010/01/10 04:26:36 rhaas Exp $
|
||||
* $PostgreSQL: pgsql/src/include/access/htup.h,v 1.111 2010/02/08 04:33:54 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -74,11 +74,11 @@
|
|||
* transaction respectively. If a tuple is inserted and deleted in the same
|
||||
* transaction, we store a "combo" command id that can be mapped to the real
|
||||
* cmin and cmax, but only by use of local state within the originating
|
||||
* backend. See combocid.c for more details. Meanwhile, Xvac is only set
|
||||
* by VACUUM FULL, which does not have any command sub-structure and so does
|
||||
* not need either Cmin or Cmax. (This requires that VACUUM FULL never try
|
||||
* to move a tuple whose Cmin or Cmax is still interesting, ie, an insert-
|
||||
* in-progress or delete-in-progress tuple.)
|
||||
* backend. See combocid.c for more details. Meanwhile, Xvac is only set by
|
||||
* old-style VACUUM FULL, which does not have any command sub-structure and so
|
||||
* does not need either Cmin or Cmax. (This requires that old-style VACUUM
|
||||
* FULL never try to move a tuple whose Cmin or Cmax is still interesting,
|
||||
* ie, an insert-in-progress or delete-in-progress tuple.)
|
||||
*
|
||||
* A word about t_ctid: whenever a new tuple is stored on disk, its t_ctid
|
||||
* is initialized with its own TID (location). If the tuple is ever updated,
|
||||
|
@ -111,7 +111,7 @@ typedef struct HeapTupleFields
|
|||
union
|
||||
{
|
||||
CommandId t_cid; /* inserting or deleting command ID, or both */
|
||||
TransactionId t_xvac; /* VACUUM FULL xact ID */
|
||||
TransactionId t_xvac; /* old-style VACUUM FULL xact ID */
|
||||
} t_field3;
|
||||
} HeapTupleFields;
|
||||
|
||||
|
@ -175,10 +175,10 @@ typedef HeapTupleHeaderData *HeapTupleHeader;
|
|||
#define HEAP_XMAX_INVALID 0x0800 /* t_xmax invalid/aborted */
|
||||
#define HEAP_XMAX_IS_MULTI 0x1000 /* t_xmax is a MultiXactId */
|
||||
#define HEAP_UPDATED 0x2000 /* this is UPDATEd version of row */
|
||||
#define HEAP_MOVED_OFF 0x4000 /* moved to another place by VACUUM
|
||||
* FULL */
|
||||
#define HEAP_MOVED_IN 0x8000 /* moved from another place by VACUUM
|
||||
* FULL */
|
||||
#define HEAP_MOVED_OFF 0x4000 /* moved to another place by
|
||||
* old-style VACUUM FULL */
|
||||
#define HEAP_MOVED_IN 0x8000 /* moved from another place by
|
||||
* old-style VACUUM FULL */
|
||||
#define HEAP_MOVED (HEAP_MOVED_OFF | HEAP_MOVED_IN)
|
||||
|
||||
#define HEAP_XACT_MASK 0xFFE0 /* visibility-related bits */
|
||||
|
@ -559,7 +559,7 @@ typedef HeapTupleData *HeapTuple;
|
|||
#define XLOG_HEAP_INSERT 0x00
|
||||
#define XLOG_HEAP_DELETE 0x10
|
||||
#define XLOG_HEAP_UPDATE 0x20
|
||||
#define XLOG_HEAP_MOVE 0x30
|
||||
/* 0x030 is free, was XLOG_HEAP_MOVE */
|
||||
#define XLOG_HEAP_HOT_UPDATE 0x40
|
||||
#define XLOG_HEAP_NEWPAGE 0x50
|
||||
#define XLOG_HEAP_LOCK 0x60
|
||||
|
@ -579,7 +579,7 @@ typedef HeapTupleData *HeapTuple;
|
|||
*/
|
||||
#define XLOG_HEAP2_FREEZE 0x00
|
||||
#define XLOG_HEAP2_CLEAN 0x10
|
||||
#define XLOG_HEAP2_CLEAN_MOVE 0x20
|
||||
/* 0x20 is free, was XLOG_HEAP2_CLEAN_MOVE */
|
||||
#define XLOG_HEAP2_CLEANUP_INFO 0x30
|
||||
|
||||
/*
|
||||
|
@ -634,15 +634,14 @@ typedef struct xl_heap_insert
|
|||
|
||||
#define SizeOfHeapInsert (offsetof(xl_heap_insert, all_visible_cleared) + sizeof(bool))
|
||||
|
||||
/* This is what we need to know about update|move|hot_update */
|
||||
/* This is what we need to know about update|hot_update */
|
||||
typedef struct xl_heap_update
|
||||
{
|
||||
xl_heaptid target; /* deleted tuple id */
|
||||
ItemPointerData newtid; /* new inserted tuple id */
|
||||
bool all_visible_cleared; /* PD_ALL_VISIBLE was cleared */
|
||||
bool new_all_visible_cleared; /* same for the page of newtid */
|
||||
/* NEW TUPLE xl_heap_header (PLUS xmax & xmin IF MOVE OP) */
|
||||
/* and TUPLE DATA FOLLOWS AT END OF STRUCT */
|
||||
bool new_all_visible_cleared; /* same for the page of newtid */
|
||||
/* NEW TUPLE xl_heap_header AND TUPLE DATA FOLLOWS AT END OF STRUCT */
|
||||
} xl_heap_update;
|
||||
|
||||
#define SizeOfHeapUpdate (offsetof(xl_heap_update, new_all_visible_cleared) + sizeof(bool))
|
||||
|
@ -657,13 +656,6 @@ typedef struct xl_heap_update
|
|||
* The total number of OffsetNumbers is therefore 2*nredirected+ndead+nunused.
|
||||
* Note that nunused is not explicitly stored, but may be found by reference
|
||||
* to the total record length.
|
||||
*
|
||||
* If the opcode is CLEAN_MOVE instead of CLEAN, then each redirection pair
|
||||
* should be interpreted as physically moving the "to" item pointer to the
|
||||
* "from" slot, rather than placing a redirection item in the "from" slot.
|
||||
* The moved pointers should be replaced by LP_UNUSED items (there will not
|
||||
* be explicit entries in the "now-unused" list for this). Also, the
|
||||
* HEAP_ONLY bit in the moved tuples must be turned off.
|
||||
*/
|
||||
typedef struct xl_heap_clean
|
||||
{
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
* Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/include/access/nbtree.h,v 1.127 2010/01/02 16:58:00 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/include/access/nbtree.h,v 1.128 2010/02/08 04:33:54 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -577,8 +577,7 @@ extern bool _bt_page_recyclable(Page page);
|
|||
extern void _bt_delitems(Relation rel, Buffer buf,
|
||||
OffsetNumber *itemnos, int nitems, bool isVacuum,
|
||||
BlockNumber lastBlockVacuumed);
|
||||
extern int _bt_pagedel(Relation rel, Buffer buf,
|
||||
BTStack stack, bool vacuum_full);
|
||||
extern int _bt_pagedel(Relation rel, Buffer buf, BTStack stack);
|
||||
|
||||
/*
|
||||
* prototypes for functions in nbtsearch.c
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
* Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/include/access/xact.h,v 1.100 2010/01/02 16:58:00 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/include/access/xact.h,v 1.101 2010/02/08 04:33:54 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -119,12 +119,10 @@ typedef struct xl_xact_commit
|
|||
* transaction completion.
|
||||
*/
|
||||
#define XACT_COMPLETION_UPDATE_RELCACHE_FILE 0x01
|
||||
#define XACT_COMPLETION_VACUUM_FULL 0x02
|
||||
#define XACT_COMPLETION_FORCE_SYNC_COMMIT 0x04
|
||||
|
||||
/* Access macros for above flags */
|
||||
#define XactCompletionRelcacheInitFileInval(xlrec) ((xlrec)->xinfo & XACT_COMPLETION_UPDATE_RELCACHE_FILE)
|
||||
#define XactCompletionVacuumFull(xlrec) ((xlrec)->xinfo & XACT_COMPLETION_VACUUM_FULL)
|
||||
#define XactCompletionForceSyncCommit(xlrec) ((xlrec)->xinfo & XACT_COMPLETION_FORCE_SYNC_COMMIT)
|
||||
|
||||
typedef struct xl_xact_abort
|
||||
|
@ -212,8 +210,6 @@ extern void UnregisterXactCallback(XactCallback callback, void *arg);
|
|||
extern void RegisterSubXactCallback(SubXactCallback callback, void *arg);
|
||||
extern void UnregisterSubXactCallback(SubXactCallback callback, void *arg);
|
||||
|
||||
extern TransactionId RecordTransactionCommit(bool isVacuumFull);
|
||||
|
||||
extern int xactGetCommittedChildren(TransactionId **ptr);
|
||||
|
||||
extern void xact_redo(XLogRecPtr lsn, XLogRecord *record);
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/include/access/xlog.h,v 1.101 2010/02/01 13:40:28 sriggs Exp $
|
||||
* $PostgreSQL: pgsql/src/include/access/xlog.h,v 1.102 2010/02/08 04:33:54 tgl Exp $
|
||||
*/
|
||||
#ifndef XLOG_H
|
||||
#define XLOG_H
|
||||
|
@ -249,7 +249,6 @@ extern char *TriggerFile;
|
|||
extern XLogRecPtr XLogInsert(RmgrId rmid, uint8 info, XLogRecData *rdata);
|
||||
extern void XLogFlush(XLogRecPtr RecPtr);
|
||||
extern void XLogBackgroundFlush(void);
|
||||
extern void XLogAsyncCommitFlush(void);
|
||||
extern bool XLogNeedsFlush(XLogRecPtr RecPtr);
|
||||
extern int XLogFileInit(uint32 log, uint32 seg,
|
||||
bool *use_existent, bool use_lock);
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
* Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/include/commands/vacuum.h,v 1.87 2010/01/02 16:58:03 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/include/commands/vacuum.h,v 1.88 2010/02/08 04:33:54 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -142,7 +142,6 @@ extern void vacuum_set_xid_limits(int freeze_min_age, int freeze_table_age,
|
|||
TransactionId *freezeLimit,
|
||||
TransactionId *freezeTableLimit);
|
||||
extern void vac_update_datfrozenxid(void);
|
||||
extern bool vac_is_partial_index(Relation indrel);
|
||||
extern void vacuum_delay_point(void);
|
||||
|
||||
/* in commands/vacuumlazy.c */
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
* Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/include/executor/executor.h,v 1.166 2010/01/02 16:58:03 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/include/executor/executor.h,v 1.167 2010/02/08 04:33:54 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -320,7 +320,7 @@ extern void ExecCloseScanRelation(Relation scanrel);
|
|||
extern void ExecOpenIndices(ResultRelInfo *resultRelInfo);
|
||||
extern void ExecCloseIndices(ResultRelInfo *resultRelInfo);
|
||||
extern List *ExecInsertIndexTuples(TupleTableSlot *slot, ItemPointer tupleid,
|
||||
EState *estate, bool is_vacuum_full);
|
||||
EState *estate);
|
||||
extern bool check_exclusion_constraint(Relation heap, Relation index,
|
||||
IndexInfo *indexInfo,
|
||||
ItemPointer tupleid,
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
* Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.427 2010/01/28 23:21:13 petere Exp $
|
||||
* $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.428 2010/02/08 04:33:54 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -2246,8 +2246,7 @@ typedef enum VacuumOption
|
|||
VACOPT_ANALYZE = 1 << 1, /* do ANALYZE */
|
||||
VACOPT_VERBOSE = 1 << 2, /* print progress info */
|
||||
VACOPT_FREEZE = 1 << 3, /* FREEZE option */
|
||||
VACOPT_FULL = 1 << 4, /* FULL (non-concurrent) vacuum */
|
||||
VACOPT_INPLACE = 1 << 5 /* traditional FULL INPLACE vacuum */
|
||||
VACOPT_FULL = 1 << 4 /* FULL (non-concurrent) vacuum */
|
||||
} VacuumOption;
|
||||
|
||||
typedef struct VacuumStmt
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/include/parser/kwlist.h,v 1.10 2010/01/06 05:31:14 itagaki Exp $
|
||||
* $PostgreSQL: pgsql/src/include/parser/kwlist.h,v 1.11 2010/02/08 04:33:55 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -193,7 +193,6 @@ PG_KEYWORD("initially", INITIALLY, RESERVED_KEYWORD)
|
|||
PG_KEYWORD("inline", INLINE_P, UNRESERVED_KEYWORD)
|
||||
PG_KEYWORD("inner", INNER_P, TYPE_FUNC_NAME_KEYWORD)
|
||||
PG_KEYWORD("inout", INOUT, COL_NAME_KEYWORD)
|
||||
PG_KEYWORD("inplace", INPLACE, UNRESERVED_KEYWORD)
|
||||
PG_KEYWORD("input", INPUT_P, UNRESERVED_KEYWORD)
|
||||
PG_KEYWORD("insensitive", INSENSITIVE, UNRESERVED_KEYWORD)
|
||||
PG_KEYWORD("insert", INSERT, UNRESERVED_KEYWORD)
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
* Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/include/utils/inval.h,v 1.48 2010/02/07 20:48:13 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/include/utils/inval.h,v 1.49 2010/02/08 04:33:55 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -39,10 +39,6 @@ extern void PostPrepare_Inval(void);
|
|||
|
||||
extern void CommandEndInvalidationMessages(void);
|
||||
|
||||
extern void BeginNonTransactionalInvalidation(void);
|
||||
|
||||
extern void EndNonTransactionalInvalidation(void);
|
||||
|
||||
extern void CacheInvalidateHeapTuple(Relation relation, HeapTuple tuple);
|
||||
|
||||
extern void CacheInvalidateCatalog(Oid catalogId);
|
||||
|
|
|
@ -57,65 +57,16 @@ SELECT * FROM vactst;
|
|||
(0 rows)
|
||||
|
||||
VACUUM (FULL, FREEZE) vactst;
|
||||
VACUUM (ANALYZE, FULL INPLACE) vactst;
|
||||
VACUUM (ANALYZE, FULL) vactst;
|
||||
CREATE TABLE vaccluster (i INT PRIMARY KEY);
|
||||
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "vaccluster_pkey" for table "vaccluster"
|
||||
ALTER TABLE vaccluster CLUSTER ON vaccluster_pkey;
|
||||
INSERT INTO vaccluster SELECT * FROM vactst;
|
||||
CREATE TEMP TABLE vacid (
|
||||
relid regclass,
|
||||
filenode_0 oid,
|
||||
filenode_1 oid,
|
||||
filenode_2 oid,
|
||||
filenode_3 oid
|
||||
);
|
||||
INSERT INTO vacid (relid, filenode_0)
|
||||
SELECT oid, relfilenode FROM pg_class WHERE oid::regclass IN (
|
||||
'pg_am', -- normal catalog
|
||||
'pg_class', -- fundamental catalog
|
||||
'pg_database', -- shared catalog
|
||||
'vaccluster' , -- clustered table
|
||||
'vacid', -- temp table
|
||||
'vactst' -- normal table
|
||||
);
|
||||
-- only clusterd table should be changed
|
||||
CLUSTER vaccluster;
|
||||
UPDATE vacid SET filenode_1 = relfilenode
|
||||
FROM pg_class WHERE oid = relid;
|
||||
-- all tables should not be changed
|
||||
VACUUM (FULL INPLACE) pg_am;
|
||||
VACUUM (FULL INPLACE) pg_class;
|
||||
VACUUM (FULL INPLACE) pg_database;
|
||||
VACUUM (FULL INPLACE) vaccluster;
|
||||
VACUUM (FULL INPLACE) vacid;
|
||||
VACUUM (FULL INPLACE) vactst;
|
||||
UPDATE vacid SET filenode_2 = relfilenode
|
||||
FROM pg_class WHERE oid = relid;
|
||||
-- only non-system tables should be changed
|
||||
VACUUM FULL pg_am;
|
||||
VACUUM FULL pg_class;
|
||||
VACUUM FULL pg_database;
|
||||
VACUUM FULL vaccluster;
|
||||
VACUUM FULL vacid;
|
||||
VACUUM FULL vactst;
|
||||
UPDATE vacid SET filenode_3 = relfilenode
|
||||
FROM pg_class WHERE oid = relid;
|
||||
SELECT relid,
|
||||
filenode_0 = filenode_1 AS cluster,
|
||||
filenode_1 = filenode_2 AS full_inplace,
|
||||
filenode_2 = filenode_3 AS full
|
||||
FROM vacid
|
||||
ORDER BY relid::text;
|
||||
relid | cluster | full_inplace | full
|
||||
-------------+---------+--------------+------
|
||||
pg_am | t | t | f
|
||||
pg_class | t | t | t
|
||||
pg_database | t | t | t
|
||||
vaccluster | f | t | f
|
||||
vacid | t | t | f
|
||||
vactst | t | t | f
|
||||
(6 rows)
|
||||
|
||||
DROP TABLE vaccluster;
|
||||
DROP TABLE vacid;
|
||||
DROP TABLE vactst;
|
||||
|
|
|
@ -40,62 +40,18 @@ DELETE FROM vactst;
|
|||
SELECT * FROM vactst;
|
||||
|
||||
VACUUM (FULL, FREEZE) vactst;
|
||||
VACUUM (ANALYZE, FULL INPLACE) vactst;
|
||||
VACUUM (ANALYZE, FULL) vactst;
|
||||
|
||||
CREATE TABLE vaccluster (i INT PRIMARY KEY);
|
||||
ALTER TABLE vaccluster CLUSTER ON vaccluster_pkey;
|
||||
INSERT INTO vaccluster SELECT * FROM vactst;
|
||||
|
||||
CREATE TEMP TABLE vacid (
|
||||
relid regclass,
|
||||
filenode_0 oid,
|
||||
filenode_1 oid,
|
||||
filenode_2 oid,
|
||||
filenode_3 oid
|
||||
);
|
||||
|
||||
INSERT INTO vacid (relid, filenode_0)
|
||||
SELECT oid, relfilenode FROM pg_class WHERE oid::regclass IN (
|
||||
'pg_am', -- normal catalog
|
||||
'pg_class', -- fundamental catalog
|
||||
'pg_database', -- shared catalog
|
||||
'vaccluster' , -- clustered table
|
||||
'vacid', -- temp table
|
||||
'vactst' -- normal table
|
||||
);
|
||||
|
||||
-- only clusterd table should be changed
|
||||
CLUSTER vaccluster;
|
||||
UPDATE vacid SET filenode_1 = relfilenode
|
||||
FROM pg_class WHERE oid = relid;
|
||||
|
||||
-- all tables should not be changed
|
||||
VACUUM (FULL INPLACE) pg_am;
|
||||
VACUUM (FULL INPLACE) pg_class;
|
||||
VACUUM (FULL INPLACE) pg_database;
|
||||
VACUUM (FULL INPLACE) vaccluster;
|
||||
VACUUM (FULL INPLACE) vacid;
|
||||
VACUUM (FULL INPLACE) vactst;
|
||||
UPDATE vacid SET filenode_2 = relfilenode
|
||||
FROM pg_class WHERE oid = relid;
|
||||
|
||||
-- only non-system tables should be changed
|
||||
VACUUM FULL pg_am;
|
||||
VACUUM FULL pg_class;
|
||||
VACUUM FULL pg_database;
|
||||
VACUUM FULL vaccluster;
|
||||
VACUUM FULL vacid;
|
||||
VACUUM FULL vactst;
|
||||
UPDATE vacid SET filenode_3 = relfilenode
|
||||
FROM pg_class WHERE oid = relid;
|
||||
|
||||
SELECT relid,
|
||||
filenode_0 = filenode_1 AS cluster,
|
||||
filenode_1 = filenode_2 AS full_inplace,
|
||||
filenode_2 = filenode_3 AS full
|
||||
FROM vacid
|
||||
ORDER BY relid::text;
|
||||
|
||||
DROP TABLE vaccluster;
|
||||
DROP TABLE vacid;
|
||||
DROP TABLE vactst;
|
||||
|
|
Loading…
Reference in New Issue