mirror of
https://github.com/postgres/postgres.git
synced 2025-04-20 00:42:27 +03:00
pgindent run for release 9.3
This is the first run of the Perl-based pgindent script. Also update pgindent instructions.
This commit is contained in:
parent
07ab261ef3
commit
9af4159fce
@ -97,7 +97,6 @@ gbt_bit_xfrm(bytea *leaf)
|
|||||||
static GBT_VARKEY *
|
static GBT_VARKEY *
|
||||||
gbt_bit_l2n(GBT_VARKEY *leaf)
|
gbt_bit_l2n(GBT_VARKEY *leaf)
|
||||||
{
|
{
|
||||||
|
|
||||||
GBT_VARKEY *out = leaf;
|
GBT_VARKEY *out = leaf;
|
||||||
GBT_VARKEY_R r = gbt_var_key_readable(leaf);
|
GBT_VARKEY_R r = gbt_var_key_readable(leaf);
|
||||||
bytea *o;
|
bytea *o;
|
||||||
|
@ -121,7 +121,6 @@ gbt_text_compress(PG_FUNCTION_ARGS)
|
|||||||
Datum
|
Datum
|
||||||
gbt_bpchar_compress(PG_FUNCTION_ARGS)
|
gbt_bpchar_compress(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
|
|
||||||
GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
|
GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
|
||||||
GISTENTRY *retval;
|
GISTENTRY *retval;
|
||||||
|
|
||||||
|
@ -382,7 +382,6 @@ gbt_ts_union(PG_FUNCTION_ARGS)
|
|||||||
Datum
|
Datum
|
||||||
gbt_ts_penalty(PG_FUNCTION_ARGS)
|
gbt_ts_penalty(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
|
|
||||||
tsKEY *origentry = (tsKEY *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(0))->key);
|
tsKEY *origentry = (tsKEY *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(0))->key);
|
||||||
tsKEY *newentry = (tsKEY *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(1))->key);
|
tsKEY *newentry = (tsKEY *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(1))->key);
|
||||||
float *result = (float *) PG_GETARG_POINTER(2);
|
float *result = (float *) PG_GETARG_POINTER(2);
|
||||||
|
@ -137,7 +137,6 @@ gbt_num_union(GBT_NUMKEY *out, const GistEntryVector *entryvec, const gbtree_nin
|
|||||||
bool
|
bool
|
||||||
gbt_num_same(const GBT_NUMKEY *a, const GBT_NUMKEY *b, const gbtree_ninfo *tinfo)
|
gbt_num_same(const GBT_NUMKEY *a, const GBT_NUMKEY *b, const gbtree_ninfo *tinfo)
|
||||||
{
|
{
|
||||||
|
|
||||||
GBT_NUMKEY_R b1,
|
GBT_NUMKEY_R b1,
|
||||||
b2;
|
b2;
|
||||||
|
|
||||||
@ -159,7 +158,6 @@ gbt_num_same(const GBT_NUMKEY *a, const GBT_NUMKEY *b, const gbtree_ninfo *tinfo
|
|||||||
void
|
void
|
||||||
gbt_num_bin_union(Datum *u, GBT_NUMKEY *e, const gbtree_ninfo *tinfo)
|
gbt_num_bin_union(Datum *u, GBT_NUMKEY *e, const gbtree_ninfo *tinfo)
|
||||||
{
|
{
|
||||||
|
|
||||||
GBT_NUMKEY_R rd;
|
GBT_NUMKEY_R rd;
|
||||||
|
|
||||||
rd.lower = &e[0];
|
rd.lower = &e[0];
|
||||||
|
@ -56,7 +56,6 @@ gbt_var_decompress(PG_FUNCTION_ARGS)
|
|||||||
GBT_VARKEY_R
|
GBT_VARKEY_R
|
||||||
gbt_var_key_readable(const GBT_VARKEY *k)
|
gbt_var_key_readable(const GBT_VARKEY *k)
|
||||||
{
|
{
|
||||||
|
|
||||||
GBT_VARKEY_R r;
|
GBT_VARKEY_R r;
|
||||||
|
|
||||||
r.lower = (bytea *) &(((char *) k)[VARHDRSZ]);
|
r.lower = (bytea *) &(((char *) k)[VARHDRSZ]);
|
||||||
@ -270,7 +269,6 @@ gbt_var_bin_union(Datum *u, GBT_VARKEY *e, Oid collation,
|
|||||||
GISTENTRY *
|
GISTENTRY *
|
||||||
gbt_var_compress(GISTENTRY *entry, const gbtree_vinfo *tinfo)
|
gbt_var_compress(GISTENTRY *entry, const gbtree_vinfo *tinfo)
|
||||||
{
|
{
|
||||||
|
|
||||||
GISTENTRY *retval;
|
GISTENTRY *retval;
|
||||||
|
|
||||||
if (entry->leafkey)
|
if (entry->leafkey)
|
||||||
@ -299,7 +297,6 @@ GBT_VARKEY *
|
|||||||
gbt_var_union(const GistEntryVector *entryvec, int32 *size, Oid collation,
|
gbt_var_union(const GistEntryVector *entryvec, int32 *size, Oid collation,
|
||||||
const gbtree_vinfo *tinfo)
|
const gbtree_vinfo *tinfo)
|
||||||
{
|
{
|
||||||
|
|
||||||
int i = 0,
|
int i = 0,
|
||||||
numranges = entryvec->n;
|
numranges = entryvec->n;
|
||||||
GBT_VARKEY *cur;
|
GBT_VARKEY *cur;
|
||||||
|
@ -1984,9 +1984,9 @@ dblink_fdw_validator(PG_FUNCTION_ARGS)
|
|||||||
if (!is_valid_dblink_option(options, def->defname, context))
|
if (!is_valid_dblink_option(options, def->defname, context))
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Unknown option, or invalid option for the context specified,
|
* Unknown option, or invalid option for the context specified, so
|
||||||
* so complain about it. Provide a hint with list of valid
|
* complain about it. Provide a hint with list of valid options
|
||||||
* options for the context.
|
* for the context.
|
||||||
*/
|
*/
|
||||||
StringInfoData buf;
|
StringInfoData buf;
|
||||||
const PQconninfoOption *opt;
|
const PQconninfoOption *opt;
|
||||||
|
@ -299,8 +299,8 @@ main(int argc, char **argv)
|
|||||||
dryrun = true;
|
dryrun = true;
|
||||||
break;
|
break;
|
||||||
case 'x':
|
case 'x':
|
||||||
additional_ext = strdup(optarg); /* Extension to remove from
|
additional_ext = strdup(optarg); /* Extension to remove
|
||||||
* xlogfile names */
|
* from xlogfile names */
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
fprintf(stderr, "Try \"%s --help\" for more information.\n", progname);
|
fprintf(stderr, "Try \"%s --help\" for more information.\n", progname);
|
||||||
|
@ -110,8 +110,11 @@ test_timing(int32 duration)
|
|||||||
uint64 total_time;
|
uint64 total_time;
|
||||||
int64 time_elapsed = 0;
|
int64 time_elapsed = 0;
|
||||||
uint64 loop_count = 0;
|
uint64 loop_count = 0;
|
||||||
uint64 prev, cur;
|
uint64 prev,
|
||||||
instr_time start_time, end_time, temp;
|
cur;
|
||||||
|
instr_time start_time,
|
||||||
|
end_time,
|
||||||
|
temp;
|
||||||
|
|
||||||
total_time = duration > 0 ? duration * 1000000 : 0;
|
total_time = duration > 0 ? duration * 1000000 : 0;
|
||||||
|
|
||||||
@ -120,7 +123,8 @@ test_timing(int32 duration)
|
|||||||
|
|
||||||
while (time_elapsed < total_time)
|
while (time_elapsed < total_time)
|
||||||
{
|
{
|
||||||
int32 diff, bits = 0;
|
int32 diff,
|
||||||
|
bits = 0;
|
||||||
|
|
||||||
prev = cur;
|
prev = cur;
|
||||||
INSTR_TIME_SET_CURRENT(temp);
|
INSTR_TIME_SET_CURRENT(temp);
|
||||||
@ -163,7 +167,8 @@ test_timing(int32 duration)
|
|||||||
static void
|
static void
|
||||||
output(uint64 loop_count)
|
output(uint64 loop_count)
|
||||||
{
|
{
|
||||||
int64 max_bit = 31, i;
|
int64 max_bit = 31,
|
||||||
|
i;
|
||||||
|
|
||||||
/* find highest bit value */
|
/* find highest bit value */
|
||||||
while (max_bit > 0 && histogram[max_bit] == 0)
|
while (max_bit > 0 && histogram[max_bit] == 0)
|
||||||
|
@ -347,8 +347,8 @@ get_wildcard_part(const char *str, int lenstr,
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Back up endword to the escape character when stopping at
|
* Back up endword to the escape character when stopping at an
|
||||||
* an escaped char, so that subsequent get_wildcard_part will
|
* escaped char, so that subsequent get_wildcard_part will
|
||||||
* restart from the escape character. We assume here that
|
* restart from the escape character. We assume here that
|
||||||
* escape chars are single-byte.
|
* escape chars are single-byte.
|
||||||
*/
|
*/
|
||||||
|
@ -46,11 +46,9 @@ fix_path_separator(char *path)
|
|||||||
*c = '\\';
|
*c = '\\';
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
return path;
|
return path;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -164,9 +162,9 @@ check_new_cluster(void)
|
|||||||
"Old and new cluster install users have different values for pg_authid.oid.\n");
|
"Old and new cluster install users have different values for pg_authid.oid.\n");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We only allow the install user in the new cluster because other
|
* We only allow the install user in the new cluster because other defined
|
||||||
* defined users might match users defined in the old cluster and
|
* users might match users defined in the old cluster and generate an
|
||||||
* generate an error during pg_dump restore.
|
* error during pg_dump restore.
|
||||||
*/
|
*/
|
||||||
if (new_cluster.role_count != 1)
|
if (new_cluster.role_count != 1)
|
||||||
pg_log(PG_FATAL, "Only the install user can be defined in the new cluster.\n");
|
pg_log(PG_FATAL, "Only the install user can be defined in the new cluster.\n");
|
||||||
@ -366,9 +364,9 @@ set_locale_and_encoding(ClusterInfo *cluster)
|
|||||||
if (GET_MAJOR_VERSION(cluster->major_version) < 902)
|
if (GET_MAJOR_VERSION(cluster->major_version) < 902)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Pre-9.2 did not canonicalize the supplied locale names
|
* Pre-9.2 did not canonicalize the supplied locale names to match
|
||||||
* to match what the system returns, while 9.2+ does, so
|
* what the system returns, while 9.2+ does, so convert pre-9.2 to
|
||||||
* convert pre-9.2 to match.
|
* match.
|
||||||
*/
|
*/
|
||||||
ctrl->lc_collate = get_canonical_locale_name(LC_COLLATE,
|
ctrl->lc_collate = get_canonical_locale_name(LC_COLLATE,
|
||||||
pg_strdup(PQgetvalue(res, 0, i_datcollate)));
|
pg_strdup(PQgetvalue(res, 0, i_datcollate)));
|
||||||
@ -598,8 +596,8 @@ create_script_for_old_cluster_deletion(char **deletion_script_file_name)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Some users (oddly) create tablespaces inside the cluster data
|
* Some users (oddly) create tablespaces inside the cluster data
|
||||||
* directory. We can't create a proper old cluster delete script
|
* directory. We can't create a proper old cluster delete script in that
|
||||||
* in that case.
|
* case.
|
||||||
*/
|
*/
|
||||||
strlcpy(old_cluster_pgdata, old_cluster.pgdata, MAXPGPATH);
|
strlcpy(old_cluster_pgdata, old_cluster.pgdata, MAXPGPATH);
|
||||||
canonicalize_path(old_cluster_pgdata);
|
canonicalize_path(old_cluster_pgdata);
|
||||||
|
@ -472,10 +472,10 @@ get_control_data(ClusterInfo *cluster, bool live_check)
|
|||||||
pg_free(lc_messages);
|
pg_free(lc_messages);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Before 9.3, pg_resetxlog reported the xlogid and segno of the first
|
* Before 9.3, pg_resetxlog reported the xlogid and segno of the first log
|
||||||
* log file after reset as separate lines. Starting with 9.3, it reports
|
* file after reset as separate lines. Starting with 9.3, it reports the
|
||||||
* the WAL file name. If the old cluster is older than 9.3, we construct
|
* WAL file name. If the old cluster is older than 9.3, we construct the
|
||||||
* the WAL file name from the xlogid and segno.
|
* WAL file name from the xlogid and segno.
|
||||||
*/
|
*/
|
||||||
if (GET_MAJOR_VERSION(cluster->major_version) <= 902)
|
if (GET_MAJOR_VERSION(cluster->major_version) <= 902)
|
||||||
{
|
{
|
||||||
@ -621,7 +621,10 @@ check_control_data(ControlData *oldctrl,
|
|||||||
"options.\n");
|
"options.\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We might eventually allow upgrades from checksum to no-checksum clusters. */
|
/*
|
||||||
|
* We might eventually allow upgrades from checksum to no-checksum
|
||||||
|
* clusters.
|
||||||
|
*/
|
||||||
if (oldctrl->data_checksum_version != newctrl->data_checksum_version)
|
if (oldctrl->data_checksum_version != newctrl->data_checksum_version)
|
||||||
{
|
{
|
||||||
pg_log(PG_FATAL,
|
pg_log(PG_FATAL,
|
||||||
|
@ -44,6 +44,7 @@ exec_prog(const char *log_file, const char *opt_log_file,
|
|||||||
{
|
{
|
||||||
int result;
|
int result;
|
||||||
int written;
|
int written;
|
||||||
|
|
||||||
#define MAXCMDLEN (2 * MAXPGPATH)
|
#define MAXCMDLEN (2 * MAXPGPATH)
|
||||||
char cmd[MAXCMDLEN];
|
char cmd[MAXCMDLEN];
|
||||||
mode_t old_umask = 0;
|
mode_t old_umask = 0;
|
||||||
@ -68,14 +69,14 @@ exec_prog(const char *log_file, const char *opt_log_file,
|
|||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* "pg_ctl -w stop" might have reported that the server has
|
* "pg_ctl -w stop" might have reported that the server has stopped
|
||||||
* stopped because the postmaster.pid file has been removed,
|
* because the postmaster.pid file has been removed, but "pg_ctl -w
|
||||||
* but "pg_ctl -w start" might still be in the process of
|
* start" might still be in the process of closing and might still be
|
||||||
* closing and might still be holding its stdout and -l log
|
* holding its stdout and -l log file descriptors open. Therefore,
|
||||||
* file descriptors open. Therefore, try to open the log
|
* try to open the log file a few more times.
|
||||||
* file a few more times.
|
|
||||||
*/
|
*/
|
||||||
int iter;
|
int iter;
|
||||||
|
|
||||||
for (iter = 0; iter < 4 && log == NULL; iter++)
|
for (iter = 0; iter < 4 && log == NULL; iter++)
|
||||||
{
|
{
|
||||||
sleep(1);
|
sleep(1);
|
||||||
@ -122,10 +123,11 @@ exec_prog(const char *log_file, const char *opt_log_file,
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifndef WIN32
|
#ifndef WIN32
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We can't do this on Windows because it will keep the "pg_ctl start"
|
* We can't do this on Windows because it will keep the "pg_ctl start"
|
||||||
* output filename open until the server stops, so we do the \n\n above
|
* output filename open until the server stops, so we do the \n\n above on
|
||||||
* on that platform. We use a unique filename for "pg_ctl start" that is
|
* that platform. We use a unique filename for "pg_ctl start" that is
|
||||||
* never reused while the server is running, so it works fine. We could
|
* never reused while the server is running, so it works fine. We could
|
||||||
* log these commands to a third file, but that just adds complexity.
|
* log these commands to a third file, but that just adds complexity.
|
||||||
*/
|
*/
|
||||||
@ -178,7 +180,6 @@ pid_lock_file_exists(const char *datadir)
|
|||||||
void
|
void
|
||||||
verify_directories(void)
|
verify_directories(void)
|
||||||
{
|
{
|
||||||
|
|
||||||
#ifndef WIN32
|
#ifndef WIN32
|
||||||
if (access(".", R_OK | W_OK | X_OK) != 0)
|
if (access(".", R_OK | W_OK | X_OK) != 0)
|
||||||
#else
|
#else
|
||||||
|
@ -127,7 +127,6 @@ linkAndUpdateFile(pageCnvCtx *pageConverter,
|
|||||||
static int
|
static int
|
||||||
copy_file(const char *srcfile, const char *dstfile, bool force)
|
copy_file(const char *srcfile, const char *dstfile, bool force)
|
||||||
{
|
{
|
||||||
|
|
||||||
#define COPY_BUF_SIZE (50 * BLCKSZ)
|
#define COPY_BUF_SIZE (50 * BLCKSZ)
|
||||||
|
|
||||||
int src_fd;
|
int src_fd;
|
||||||
|
@ -60,10 +60,9 @@ gen_db_file_maps(DbInfo *old_db, DbInfo *new_db,
|
|||||||
* table names change during ALTER TABLE ALTER COLUMN SET TYPE. In >=
|
* table names change during ALTER TABLE ALTER COLUMN SET TYPE. In >=
|
||||||
* 9.0, TOAST relation names always use heap table oids, hence we
|
* 9.0, TOAST relation names always use heap table oids, hence we
|
||||||
* cannot check relation names when upgrading from pre-9.0. Clusters
|
* cannot check relation names when upgrading from pre-9.0. Clusters
|
||||||
* upgraded to 9.0 will get matching TOAST names.
|
* upgraded to 9.0 will get matching TOAST names. If index names don't
|
||||||
* If index names don't match primary key constraint names, this will
|
* match primary key constraint names, this will fail because pg_dump
|
||||||
* fail because pg_dump dumps constraint names and pg_upgrade checks
|
* dumps constraint names and pg_upgrade checks index names.
|
||||||
* index names.
|
|
||||||
*/
|
*/
|
||||||
if (strcmp(old_rel->nspname, new_rel->nspname) != 0 ||
|
if (strcmp(old_rel->nspname, new_rel->nspname) != 0 ||
|
||||||
((GET_MAJOR_VERSION(old_cluster.major_version) >= 900 ||
|
((GET_MAJOR_VERSION(old_cluster.major_version) >= 900 ||
|
||||||
@ -79,7 +78,10 @@ gen_db_file_maps(DbInfo *old_db, DbInfo *new_db,
|
|||||||
num_maps++;
|
num_maps++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Do this check after the loop so hopefully we will produce a clearer error above */
|
/*
|
||||||
|
* Do this check after the loop so hopefully we will produce a clearer
|
||||||
|
* error above
|
||||||
|
*/
|
||||||
if (old_db->rel_arr.nrels != new_db->rel_arr.nrels)
|
if (old_db->rel_arr.nrels != new_db->rel_arr.nrels)
|
||||||
pg_log(PG_FATAL, "old and new databases \"%s\" have a different number of relations\n",
|
pg_log(PG_FATAL, "old and new databases \"%s\" have a different number of relations\n",
|
||||||
old_db->db_name);
|
old_db->db_name);
|
||||||
@ -285,8 +287,11 @@ get_rel_infos(ClusterInfo *cluster, DbInfo *dbinfo)
|
|||||||
"LEFT OUTER JOIN pg_catalog.pg_index i "
|
"LEFT OUTER JOIN pg_catalog.pg_index i "
|
||||||
" ON c.oid = i.indexrelid "
|
" ON c.oid = i.indexrelid "
|
||||||
"WHERE relkind IN ('r', 'm', 'i'%s) AND "
|
"WHERE relkind IN ('r', 'm', 'i'%s) AND "
|
||||||
/* pg_dump only dumps valid indexes; testing indisready is
|
|
||||||
* necessary in 9.2, and harmless in earlier/later versions. */
|
/*
|
||||||
|
* pg_dump only dumps valid indexes; testing indisready is necessary in
|
||||||
|
* 9.2, and harmless in earlier/later versions.
|
||||||
|
*/
|
||||||
" i.indisvalid IS DISTINCT FROM false AND "
|
" i.indisvalid IS DISTINCT FROM false AND "
|
||||||
" i.indisready IS DISTINCT FROM false AND "
|
" i.indisready IS DISTINCT FROM false AND "
|
||||||
/* exclude possible orphaned temp tables */
|
/* exclude possible orphaned temp tables */
|
||||||
|
@ -314,8 +314,8 @@ check_required_directory(char **dirpath, char **configpath,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Trim off any trailing path separators because we construct paths
|
* Trim off any trailing path separators because we construct paths by
|
||||||
* by appending to this path.
|
* appending to this path.
|
||||||
*/
|
*/
|
||||||
#ifndef WIN32
|
#ifndef WIN32
|
||||||
if ((*dirpath)[strlen(*dirpath) - 1] == '/')
|
if ((*dirpath)[strlen(*dirpath) - 1] == '/')
|
||||||
@ -398,10 +398,10 @@ void
|
|||||||
get_sock_dir(ClusterInfo *cluster, bool live_check)
|
get_sock_dir(ClusterInfo *cluster, bool live_check)
|
||||||
{
|
{
|
||||||
#ifdef HAVE_UNIX_SOCKETS
|
#ifdef HAVE_UNIX_SOCKETS
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* sockdir and port were added to postmaster.pid in PG 9.1.
|
* sockdir and port were added to postmaster.pid in PG 9.1. Pre-9.1 cannot
|
||||||
* Pre-9.1 cannot process pg_ctl -w for sockets in non-default
|
* process pg_ctl -w for sockets in non-default locations.
|
||||||
* locations.
|
|
||||||
*/
|
*/
|
||||||
if (GET_MAJOR_VERSION(cluster->major_version) >= 901)
|
if (GET_MAJOR_VERSION(cluster->major_version) >= 901)
|
||||||
{
|
{
|
||||||
@ -415,11 +415,13 @@ get_sock_dir(ClusterInfo *cluster, bool live_check)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* If we are doing a live check, we will use the old cluster's Unix
|
* If we are doing a live check, we will use the old cluster's
|
||||||
* domain socket directory so we can connect to the live server.
|
* Unix domain socket directory so we can connect to the live
|
||||||
|
* server.
|
||||||
*/
|
*/
|
||||||
unsigned short orig_port = cluster->port;
|
unsigned short orig_port = cluster->port;
|
||||||
char filename[MAXPGPATH], line[MAXPGPATH];
|
char filename[MAXPGPATH],
|
||||||
|
line[MAXPGPATH];
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
int lineno;
|
int lineno;
|
||||||
|
|
||||||
@ -454,9 +456,12 @@ get_sock_dir(ClusterInfo *cluster, bool live_check)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
/* Can't get sockdir and pg_ctl -w can't use a non-default, use default */
|
|
||||||
cluster->sockdir = NULL;
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Can't get sockdir and pg_ctl -w can't use a non-default, use
|
||||||
|
* default
|
||||||
|
*/
|
||||||
|
cluster->sockdir = NULL;
|
||||||
#else /* !HAVE_UNIX_SOCKETS */
|
#else /* !HAVE_UNIX_SOCKETS */
|
||||||
cluster->sockdir = NULL;
|
cluster->sockdir = NULL;
|
||||||
#endif
|
#endif
|
||||||
|
@ -59,9 +59,9 @@ setupPageConverter(void)
|
|||||||
if (newPageVersion != oldPageVersion)
|
if (newPageVersion != oldPageVersion)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* The clusters use differing page layouts, see if we can find a plugin
|
* The clusters use differing page layouts, see if we can find a
|
||||||
* that knows how to convert from the old page layout to the new page
|
* plugin that knows how to convert from the old page layout to the
|
||||||
* layout.
|
* new page layout.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if ((converter = loadConverterPlugin(newPageVersion, oldPageVersion)) == NULL)
|
if ((converter = loadConverterPlugin(newPageVersion, oldPageVersion)) == NULL)
|
||||||
@ -161,6 +161,4 @@ loadConverterPlugin(uint16 newPageVersion, uint16 oldPageVersion)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -30,13 +30,15 @@ static int parallel_jobs;
|
|||||||
*/
|
*/
|
||||||
HANDLE *thread_handles;
|
HANDLE *thread_handles;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
char log_file[MAXPGPATH];
|
char log_file[MAXPGPATH];
|
||||||
char opt_log_file[MAXPGPATH];
|
char opt_log_file[MAXPGPATH];
|
||||||
char cmd[MAX_STRING];
|
char cmd[MAX_STRING];
|
||||||
} exec_thread_arg;
|
} exec_thread_arg;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
DbInfoArr *old_db_arr;
|
DbInfoArr *old_db_arr;
|
||||||
DbInfoArr *new_db_arr;
|
DbInfoArr *new_db_arr;
|
||||||
char old_pgdata[MAXPGPATH];
|
char old_pgdata[MAXPGPATH];
|
||||||
@ -52,7 +54,6 @@ void **cur_thread_args;
|
|||||||
|
|
||||||
DWORD win32_exec_prog(exec_thread_arg *args);
|
DWORD win32_exec_prog(exec_thread_arg *args);
|
||||||
DWORD win32_transfer_all_new_dbs(transfer_thread_arg *args);
|
DWORD win32_transfer_all_new_dbs(transfer_thread_arg *args);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -67,6 +68,7 @@ parallel_exec_prog(const char *log_file, const char *opt_log_file,
|
|||||||
{
|
{
|
||||||
va_list args;
|
va_list args;
|
||||||
char cmd[MAX_STRING];
|
char cmd[MAX_STRING];
|
||||||
|
|
||||||
#ifndef WIN32
|
#ifndef WIN32
|
||||||
pid_t child;
|
pid_t child;
|
||||||
#else
|
#else
|
||||||
@ -119,8 +121,8 @@ parallel_exec_prog(const char *log_file, const char *opt_log_file,
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* For safety and performance, we keep the args allocated during
|
* For safety and performance, we keep the args allocated during
|
||||||
* the entire life of the process, and we don't free the args
|
* the entire life of the process, and we don't free the args in a
|
||||||
* in a thread different from the one that allocated it.
|
* thread different from the one that allocated it.
|
||||||
*/
|
*/
|
||||||
for (i = 0; i < user_opts.jobs; i++)
|
for (i = 0; i < user_opts.jobs; i++)
|
||||||
exec_thread_args[i] = pg_malloc(sizeof(exec_thread_arg));
|
exec_thread_args[i] = pg_malloc(sizeof(exec_thread_arg));
|
||||||
@ -167,7 +169,8 @@ win32_exec_prog(exec_thread_arg *args)
|
|||||||
* This has the same API as transfer_all_new_dbs, except it does parallel execution
|
* This has the same API as transfer_all_new_dbs, except it does parallel execution
|
||||||
* by transfering multiple tablespaces in parallel
|
* by transfering multiple tablespaces in parallel
|
||||||
*/
|
*/
|
||||||
void parallel_transfer_all_new_dbs(DbInfoArr *old_db_arr, DbInfoArr *new_db_arr,
|
void
|
||||||
|
parallel_transfer_all_new_dbs(DbInfoArr *old_db_arr, DbInfoArr *new_db_arr,
|
||||||
char *old_pgdata, char *new_pgdata,
|
char *old_pgdata, char *new_pgdata,
|
||||||
char *old_tablespace)
|
char *old_tablespace)
|
||||||
{
|
{
|
||||||
@ -224,8 +227,8 @@ void parallel_transfer_all_new_dbs(DbInfoArr *old_db_arr, DbInfoArr *new_db_arr,
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* For safety and performance, we keep the args allocated during
|
* For safety and performance, we keep the args allocated during
|
||||||
* the entire life of the process, and we don't free the args
|
* the entire life of the process, and we don't free the args in a
|
||||||
* in a thread different from the one that allocated it.
|
* thread different from the one that allocated it.
|
||||||
*/
|
*/
|
||||||
for (i = 0; i < user_opts.jobs; i++)
|
for (i = 0; i < user_opts.jobs; i++)
|
||||||
transfer_thread_args[i] = pg_malloc(sizeof(transfer_thread_arg));
|
transfer_thread_args[i] = pg_malloc(sizeof(transfer_thread_arg));
|
||||||
@ -293,7 +296,6 @@ reap_child(bool wait_for_child)
|
|||||||
|
|
||||||
if (WEXITSTATUS(work_status) != 0)
|
if (WEXITSTATUS(work_status) != 0)
|
||||||
pg_log(PG_FATAL, "child worker exited abnormally: %s\n", strerror(errno));
|
pg_log(PG_FATAL, "child worker exited abnormally: %s\n", strerror(errno));
|
||||||
|
|
||||||
#else
|
#else
|
||||||
/* wait for one to finish */
|
/* wait for one to finish */
|
||||||
thread_num = WaitForMultipleObjects(parallel_jobs, thread_handles,
|
thread_num = WaitForMultipleObjects(parallel_jobs, thread_handles,
|
||||||
@ -321,10 +323,10 @@ reap_child(bool wait_for_child)
|
|||||||
thread_handles[thread_num] = thread_handles[parallel_jobs - 1];
|
thread_handles[thread_num] = thread_handles[parallel_jobs - 1];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We must swap the arg struct pointers because the thread we
|
* We must swap the arg struct pointers because the thread we just
|
||||||
* just moved is active, and we must make sure it is not
|
* moved is active, and we must make sure it is not reused by the next
|
||||||
* reused by the next created thread. Instead, the new thread
|
* created thread. Instead, the new thread will use the arg struct of
|
||||||
* will use the arg struct of the thread that just died.
|
* the thread that just died.
|
||||||
*/
|
*/
|
||||||
tmp_args = cur_thread_args[thread_num];
|
tmp_args = cur_thread_args[thread_num];
|
||||||
cur_thread_args[thread_num] = cur_thread_args[parallel_jobs - 1];
|
cur_thread_args[thread_num] = cur_thread_args[parallel_jobs - 1];
|
||||||
|
@ -193,13 +193,12 @@ setup(char *argv0, bool *live_check)
|
|||||||
if (pid_lock_file_exists(old_cluster.pgdata))
|
if (pid_lock_file_exists(old_cluster.pgdata))
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* If we have a postmaster.pid file, try to start the server. If
|
* If we have a postmaster.pid file, try to start the server. If it
|
||||||
* it starts, the pid file was stale, so stop the server. If it
|
* starts, the pid file was stale, so stop the server. If it doesn't
|
||||||
* doesn't start, assume the server is running. If the pid file
|
* start, assume the server is running. If the pid file is left over
|
||||||
* is left over from a server crash, this also allows any committed
|
* from a server crash, this also allows any committed transactions
|
||||||
* transactions stored in the WAL to be replayed so they are not
|
* stored in the WAL to be replayed so they are not lost, because WAL
|
||||||
* lost, because WAL files are not transfered from old to new
|
* files are not transfered from old to new servers.
|
||||||
* servers.
|
|
||||||
*/
|
*/
|
||||||
if (start_postmaster(&old_cluster, false))
|
if (start_postmaster(&old_cluster, false))
|
||||||
stop_postmaster(false);
|
stop_postmaster(false);
|
||||||
@ -313,8 +312,8 @@ create_new_objects(void)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Technically, we only need to install these support functions in new
|
* Technically, we only need to install these support functions in new
|
||||||
* databases that also exist in the old cluster, but for completeness
|
* databases that also exist in the old cluster, but for completeness we
|
||||||
* we process all new databases.
|
* process all new databases.
|
||||||
*/
|
*/
|
||||||
for (dbnum = 0; dbnum < new_cluster.dbarr.ndbs; dbnum++)
|
for (dbnum = 0; dbnum < new_cluster.dbarr.ndbs; dbnum++)
|
||||||
{
|
{
|
||||||
@ -330,7 +329,8 @@ create_new_objects(void)
|
|||||||
|
|
||||||
for (dbnum = 0; dbnum < old_cluster.dbarr.ndbs; dbnum++)
|
for (dbnum = 0; dbnum < old_cluster.dbarr.ndbs; dbnum++)
|
||||||
{
|
{
|
||||||
char sql_file_name[MAXPGPATH], log_file_name[MAXPGPATH];
|
char sql_file_name[MAXPGPATH],
|
||||||
|
log_file_name[MAXPGPATH];
|
||||||
DbInfo *old_db = &old_cluster.dbarr.dbs[dbnum];
|
DbInfo *old_db = &old_cluster.dbarr.dbs[dbnum];
|
||||||
|
|
||||||
pg_log(PG_STATUS, "%s", old_db->db_name);
|
pg_log(PG_STATUS, "%s", old_db->db_name);
|
||||||
@ -418,6 +418,7 @@ copy_clog_xlog_xid(void)
|
|||||||
copy_subdir_files("pg_multixact/offsets");
|
copy_subdir_files("pg_multixact/offsets");
|
||||||
copy_subdir_files("pg_multixact/members");
|
copy_subdir_files("pg_multixact/members");
|
||||||
prep_status("Setting next multixact ID and offset for new cluster");
|
prep_status("Setting next multixact ID and offset for new cluster");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* we preserve all files and contents, so we must preserve both "next"
|
* we preserve all files and contents, so we must preserve both "next"
|
||||||
* counters here and the oldest multi present on system.
|
* counters here and the oldest multi present on system.
|
||||||
@ -434,6 +435,7 @@ copy_clog_xlog_xid(void)
|
|||||||
else if (new_cluster.controldata.cat_ver >= MULTIXACT_FORMATCHANGE_CAT_VER)
|
else if (new_cluster.controldata.cat_ver >= MULTIXACT_FORMATCHANGE_CAT_VER)
|
||||||
{
|
{
|
||||||
prep_status("Setting oldest multixact ID on new cluster");
|
prep_status("Setting oldest multixact ID on new cluster");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We don't preserve files in this case, but it's important that the
|
* We don't preserve files in this case, but it's important that the
|
||||||
* oldest multi is set to the latest value used by the old system, so
|
* oldest multi is set to the latest value used by the old system, so
|
||||||
@ -549,7 +551,6 @@ set_frozenxids(void)
|
|||||||
static void
|
static void
|
||||||
cleanup(void)
|
cleanup(void)
|
||||||
{
|
{
|
||||||
|
|
||||||
fclose(log_opts.internal);
|
fclose(log_opts.internal);
|
||||||
|
|
||||||
/* Remove dump and log files? */
|
/* Remove dump and log files? */
|
||||||
@ -567,7 +568,8 @@ cleanup(void)
|
|||||||
if (old_cluster.dbarr.dbs)
|
if (old_cluster.dbarr.dbs)
|
||||||
for (dbnum = 0; dbnum < old_cluster.dbarr.ndbs; dbnum++)
|
for (dbnum = 0; dbnum < old_cluster.dbarr.ndbs; dbnum++)
|
||||||
{
|
{
|
||||||
char sql_file_name[MAXPGPATH], log_file_name[MAXPGPATH];
|
char sql_file_name[MAXPGPATH],
|
||||||
|
log_file_name[MAXPGPATH];
|
||||||
DbInfo *old_db = &old_cluster.dbarr.dbs[dbnum];
|
DbInfo *old_db = &old_cluster.dbarr.dbs[dbnum];
|
||||||
|
|
||||||
snprintf(sql_file_name, sizeof(sql_file_name), DB_DUMP_FILE_MASK, old_db->db_oid);
|
snprintf(sql_file_name, sizeof(sql_file_name), DB_DUMP_FILE_MASK, old_db->db_oid);
|
||||||
|
@ -477,11 +477,11 @@ void old_8_3_invalidate_bpchar_pattern_ops_indexes(ClusterInfo *cluster,
|
|||||||
char *old_8_3_create_sequence_script(ClusterInfo *cluster);
|
char *old_8_3_create_sequence_script(ClusterInfo *cluster);
|
||||||
|
|
||||||
/* parallel.c */
|
/* parallel.c */
|
||||||
void parallel_exec_prog(const char *log_file, const char *opt_log_file,
|
void
|
||||||
|
parallel_exec_prog(const char *log_file, const char *opt_log_file,
|
||||||
const char *fmt,...)
|
const char *fmt,...)
|
||||||
__attribute__((format(PG_PRINTF_ATTRIBUTE, 3, 4)));
|
__attribute__((format(PG_PRINTF_ATTRIBUTE, 3, 4)));
|
||||||
void parallel_transfer_all_new_dbs(DbInfoArr *old_db_arr, DbInfoArr *new_db_arr,
|
void parallel_transfer_all_new_dbs(DbInfoArr *old_db_arr, DbInfoArr *new_db_arr,
|
||||||
char *old_pgdata, char *new_pgdata,
|
char *old_pgdata, char *new_pgdata,
|
||||||
char *old_tablespace);
|
char *old_tablespace);
|
||||||
bool reap_child(bool wait_for_child);
|
bool reap_child(bool wait_for_child);
|
||||||
|
|
||||||
|
@ -35,11 +35,11 @@ transfer_all_new_tablespaces(DbInfoArr *old_db_arr, DbInfoArr *new_db_arr,
|
|||||||
user_opts.transfer_mode == TRANSFER_MODE_LINK ? "Linking" : "Copying");
|
user_opts.transfer_mode == TRANSFER_MODE_LINK ? "Linking" : "Copying");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Transfering files by tablespace is tricky because a single database
|
* Transfering files by tablespace is tricky because a single database can
|
||||||
* can use multiple tablespaces. For non-parallel mode, we just pass a
|
* use multiple tablespaces. For non-parallel mode, we just pass a NULL
|
||||||
* NULL tablespace path, which matches all tablespaces. In parallel mode,
|
* tablespace path, which matches all tablespaces. In parallel mode, we
|
||||||
* we pass the default tablespace and all user-created tablespaces
|
* pass the default tablespace and all user-created tablespaces and let
|
||||||
* and let those operations happen in parallel.
|
* those operations happen in parallel.
|
||||||
*/
|
*/
|
||||||
if (user_opts.jobs <= 1)
|
if (user_opts.jobs <= 1)
|
||||||
parallel_transfer_all_new_dbs(old_db_arr, new_db_arr, old_pgdata,
|
parallel_transfer_all_new_dbs(old_db_arr, new_db_arr, old_pgdata,
|
||||||
@ -219,11 +219,9 @@ transfer_relfile(pageCnvCtx *pageConverter, FileNameMap *map,
|
|||||||
char extent_suffix[65];
|
char extent_suffix[65];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Now copy/link any related segments as well. Remember, PG breaks
|
* Now copy/link any related segments as well. Remember, PG breaks large
|
||||||
* large files into 1GB segments, the first segment has no extension,
|
* files into 1GB segments, the first segment has no extension, subsequent
|
||||||
* subsequent segments are named relfilenode.1, relfilenode.2,
|
* segments are named relfilenode.1, relfilenode.2, relfilenode.3. copied.
|
||||||
* relfilenode.3.
|
|
||||||
* copied.
|
|
||||||
*/
|
*/
|
||||||
for (segno = 0;; segno++)
|
for (segno = 0;; segno++)
|
||||||
{
|
{
|
||||||
@ -286,4 +284,3 @@ transfer_relfile(pageCnvCtx *pageConverter, FileNameMap *map,
|
|||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,6 +89,7 @@ static bool
|
|||||||
verify_directory(const char *directory)
|
verify_directory(const char *directory)
|
||||||
{
|
{
|
||||||
DIR *dir = opendir(directory);
|
DIR *dir = opendir(directory);
|
||||||
|
|
||||||
if (dir == NULL)
|
if (dir == NULL)
|
||||||
return false;
|
return false;
|
||||||
closedir(dir);
|
closedir(dir);
|
||||||
@ -672,9 +673,9 @@ main(int argc, char **argv)
|
|||||||
(uint32) private.startptr);
|
(uint32) private.startptr);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Display a message that we're skipping data if `from` wasn't a pointer to
|
* Display a message that we're skipping data if `from` wasn't a pointer
|
||||||
* the start of a record and also wasn't a pointer to the beginning of a
|
* to the start of a record and also wasn't a pointer to the beginning of
|
||||||
* segment (e.g. we were used in file mode).
|
* a segment (e.g. we were used in file mode).
|
||||||
*/
|
*/
|
||||||
if (first_record != private.startptr && (private.startptr % XLogSegSize) != 0)
|
if (first_record != private.startptr && (private.startptr % XLogSegSize) != 0)
|
||||||
printf("first record is after %X/%X, at %X/%X, skipping over %u bytes\n",
|
printf("first record is after %X/%X, at %X/%X, skipping over %u bytes\n",
|
||||||
|
@ -33,4 +33,3 @@
|
|||||||
const RmgrDescData RmgrDescTable[RM_MAX_ID + 1] = {
|
const RmgrDescData RmgrDescTable[RM_MAX_ID + 1] = {
|
||||||
#include "access/rmgrlist.h"
|
#include "access/rmgrlist.h"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -162,7 +162,8 @@ char *index_tablespace = NULL;
|
|||||||
|
|
||||||
bool use_log; /* log transaction latencies to a file */
|
bool use_log; /* log transaction latencies to a file */
|
||||||
bool use_quiet; /* quiet logging onto stderr */
|
bool use_quiet; /* quiet logging onto stderr */
|
||||||
int agg_interval; /* log aggregates instead of individual transactions */
|
int agg_interval; /* log aggregates instead of individual
|
||||||
|
* transactions */
|
||||||
bool is_connect; /* establish connection for each transaction */
|
bool is_connect; /* establish connection for each transaction */
|
||||||
bool is_latencies; /* report per-command latencies */
|
bool is_latencies; /* report per-command latencies */
|
||||||
int main_pid; /* main process id used in log filename */
|
int main_pid; /* main process id used in log filename */
|
||||||
@ -265,7 +266,8 @@ typedef struct
|
|||||||
int cnt; /* number of transactions */
|
int cnt; /* number of transactions */
|
||||||
double min_duration; /* min/max durations */
|
double min_duration; /* min/max durations */
|
||||||
double max_duration;
|
double max_duration;
|
||||||
double sum; /* sum(duration), sum(duration^2) - for estimates */
|
double sum; /* sum(duration), sum(duration^2) - for
|
||||||
|
* estimates */
|
||||||
double sum2;
|
double sum2;
|
||||||
|
|
||||||
} AggVals;
|
} AggVals;
|
||||||
@ -874,7 +876,8 @@ clientDone(CState *st, bool ok)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
void agg_vals_init(AggVals * aggs, instr_time start)
|
void
|
||||||
|
agg_vals_init(AggVals *aggs, instr_time start)
|
||||||
{
|
{
|
||||||
/* basic counters */
|
/* basic counters */
|
||||||
aggs->cnt = 0; /* number of transactions */
|
aggs->cnt = 0; /* number of transactions */
|
||||||
@ -964,8 +967,10 @@ top:
|
|||||||
/* should we aggregate the results or not? */
|
/* should we aggregate the results or not? */
|
||||||
if (agg_interval > 0)
|
if (agg_interval > 0)
|
||||||
{
|
{
|
||||||
/* are we still in the same interval? if yes, accumulate the
|
/*
|
||||||
* values (print them otherwise) */
|
* are we still in the same interval? if yes, accumulate
|
||||||
|
* the values (print them otherwise)
|
||||||
|
*/
|
||||||
if (agg->start_time + agg_interval >= INSTR_TIME_GET_DOUBLE(now))
|
if (agg->start_time + agg_interval >= INSTR_TIME_GET_DOUBLE(now))
|
||||||
{
|
{
|
||||||
agg->cnt += 1;
|
agg->cnt += 1;
|
||||||
@ -981,12 +986,18 @@ top:
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Loop until we reach the interval of the current transaction (and
|
/*
|
||||||
* print all the empty intervals in between). */
|
* Loop until we reach the interval of the current
|
||||||
|
* transaction (and print all the empty intervals in
|
||||||
|
* between).
|
||||||
|
*/
|
||||||
while (agg->start_time + agg_interval < INSTR_TIME_GET_DOUBLE(now))
|
while (agg->start_time + agg_interval < INSTR_TIME_GET_DOUBLE(now))
|
||||||
{
|
{
|
||||||
/* This is a non-Windows branch (thanks to the ifdef in usage), so
|
/*
|
||||||
* we don't need to handle this in a special way (see below). */
|
* This is a non-Windows branch (thanks to the
|
||||||
|
* ifdef in usage), so we don't need to handle
|
||||||
|
* this in a special way (see below).
|
||||||
|
*/
|
||||||
fprintf(logfile, "%ld %d %.0f %.0f %.0f %.0f\n",
|
fprintf(logfile, "%ld %d %.0f %.0f %.0f %.0f\n",
|
||||||
agg->start_time, agg->cnt, agg->sum, agg->sum2,
|
agg->start_time, agg->cnt, agg->sum, agg->sum2,
|
||||||
agg->min_duration, agg->max_duration);
|
agg->min_duration, agg->max_duration);
|
||||||
@ -1002,7 +1013,10 @@ top:
|
|||||||
agg->sum2 = 0;
|
agg->sum2 = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* and now update the reset values (include the current) */
|
/*
|
||||||
|
* and now update the reset values (include the
|
||||||
|
* current)
|
||||||
|
*/
|
||||||
agg->cnt = 1;
|
agg->cnt = 1;
|
||||||
agg->min_duration = usec;
|
agg->min_duration = usec;
|
||||||
agg->max_duration = usec;
|
agg->max_duration = usec;
|
||||||
@ -1014,12 +1028,20 @@ top:
|
|||||||
{
|
{
|
||||||
/* no, print raw transactions */
|
/* no, print raw transactions */
|
||||||
#ifndef WIN32
|
#ifndef WIN32
|
||||||
/* This is more than we really ought to know about instr_time */
|
|
||||||
|
/*
|
||||||
|
* This is more than we really ought to know about
|
||||||
|
* instr_time
|
||||||
|
*/
|
||||||
fprintf(logfile, "%d %d %.0f %d %ld %ld\n",
|
fprintf(logfile, "%d %d %.0f %d %ld %ld\n",
|
||||||
st->id, st->cnt, usec, st->use_file,
|
st->id, st->cnt, usec, st->use_file,
|
||||||
(long) now.tv_sec, (long) now.tv_usec);
|
(long) now.tv_sec, (long) now.tv_usec);
|
||||||
#else
|
#else
|
||||||
/* On Windows, instr_time doesn't provide a timestamp anyway */
|
|
||||||
|
/*
|
||||||
|
* On Windows, instr_time doesn't provide a timestamp
|
||||||
|
* anyway
|
||||||
|
*/
|
||||||
fprintf(logfile, "%d %d %.0f %d 0 0\n",
|
fprintf(logfile, "%d %d %.0f %d 0 0\n",
|
||||||
st->id, st->cnt, usec, st->use_file);
|
st->id, st->cnt, usec, st->use_file);
|
||||||
#endif
|
#endif
|
||||||
@ -1234,11 +1256,11 @@ top:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* getrand() needs to be able to subtract max from min and add
|
* getrand() needs to be able to subtract max from min and add one
|
||||||
* one to the result without overflowing. Since we know max > min,
|
* to the result without overflowing. Since we know max > min, we
|
||||||
* we can detect overflow just by checking for a negative result.
|
* can detect overflow just by checking for a negative result. But
|
||||||
* But we must check both that the subtraction doesn't overflow,
|
* we must check both that the subtraction doesn't overflow, and
|
||||||
* and that adding one to the result doesn't overflow either.
|
* that adding one to the result doesn't overflow either.
|
||||||
*/
|
*/
|
||||||
if (max - min < 0 || (max - min) + 1 < 0)
|
if (max - min < 0 || (max - min) + 1 < 0)
|
||||||
{
|
{
|
||||||
@ -1418,7 +1440,6 @@ disconnect_all(CState *state, int length)
|
|||||||
static void
|
static void
|
||||||
init(bool is_no_vacuum)
|
init(bool is_no_vacuum)
|
||||||
{
|
{
|
||||||
|
|
||||||
/* The scale factor at/beyond which 32bit integers are incapable of storing
|
/* The scale factor at/beyond which 32bit integers are incapable of storing
|
||||||
* 64bit values.
|
* 64bit values.
|
||||||
*
|
*
|
||||||
@ -1488,8 +1509,10 @@ init(bool is_no_vacuum)
|
|||||||
int64 k;
|
int64 k;
|
||||||
|
|
||||||
/* used to track elapsed time and estimate of the remaining time */
|
/* used to track elapsed time and estimate of the remaining time */
|
||||||
instr_time start, diff;
|
instr_time start,
|
||||||
double elapsed_sec, remaining_sec;
|
diff;
|
||||||
|
double elapsed_sec,
|
||||||
|
remaining_sec;
|
||||||
int log_interval = 1;
|
int log_interval = 1;
|
||||||
|
|
||||||
if ((con = doConnect()) == NULL)
|
if ((con = doConnect()) == NULL)
|
||||||
@ -1573,8 +1596,10 @@ init(bool is_no_vacuum)
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If we want to stick with the original logging, print a message each
|
/*
|
||||||
* 100k inserted rows. */
|
* If we want to stick with the original logging, print a message each
|
||||||
|
* 100k inserted rows.
|
||||||
|
*/
|
||||||
if ((!use_quiet) && (j % 100000 == 0))
|
if ((!use_quiet) && (j % 100000 == 0))
|
||||||
{
|
{
|
||||||
INSTR_TIME_SET_CURRENT(diff);
|
INSTR_TIME_SET_CURRENT(diff);
|
||||||
@ -1598,7 +1623,8 @@ init(bool is_no_vacuum)
|
|||||||
remaining_sec = (scale * naccounts - j) * elapsed_sec / j;
|
remaining_sec = (scale * naccounts - j) * elapsed_sec / j;
|
||||||
|
|
||||||
/* have we reached the next interval (or end)? */
|
/* have we reached the next interval (or end)? */
|
||||||
if ((j == scale * naccounts) || (elapsed_sec >= log_interval * LOG_STEP_SECONDS)) {
|
if ((j == scale * naccounts) || (elapsed_sec >= log_interval * LOG_STEP_SECONDS))
|
||||||
|
{
|
||||||
|
|
||||||
fprintf(stderr, INT64_FORMAT " of " INT64_FORMAT " tuples (%d%%) done (elapsed %.2f s, remaining %.2f s).\n",
|
fprintf(stderr, INT64_FORMAT " of " INT64_FORMAT " tuples (%d%%) done (elapsed %.2f s, remaining %.2f s).\n",
|
||||||
j, (int64) naccounts * scale,
|
j, (int64) naccounts * scale,
|
||||||
@ -2393,17 +2419,20 @@ main(int argc, char **argv)
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (agg_interval > 0 && (! use_log)) {
|
if (agg_interval > 0 && (!use_log))
|
||||||
|
{
|
||||||
fprintf(stderr, "log aggregation is allowed only when actually logging transactions\n");
|
fprintf(stderr, "log aggregation is allowed only when actually logging transactions\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((duration > 0) && (agg_interval > duration)) {
|
if ((duration > 0) && (agg_interval > duration))
|
||||||
|
{
|
||||||
fprintf(stderr, "number of seconds for aggregation (%d) must not be higher that test duration (%d)\n", agg_interval, duration);
|
fprintf(stderr, "number of seconds for aggregation (%d) must not be higher that test duration (%d)\n", agg_interval, duration);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((duration > 0) && (agg_interval > 0) && (duration % agg_interval != 0)) {
|
if ((duration > 0) && (agg_interval > 0) && (duration % agg_interval != 0))
|
||||||
|
{
|
||||||
fprintf(stderr, "duration (%d) must be a multiple of aggregation interval (%d)\n", duration, agg_interval);
|
fprintf(stderr, "duration (%d) must be a multiple of aggregation interval (%d)\n", duration, agg_interval);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
@ -117,14 +117,11 @@ mp_result mp_int_mul_value(mp_int a, int value, mp_int c);
|
|||||||
mp_result mp_int_mul_pow2(mp_int a, int p2, mp_int c);
|
mp_result mp_int_mul_pow2(mp_int a, int p2, mp_int c);
|
||||||
mp_result mp_int_sqr(mp_int a, mp_int c); /* c = a * a */
|
mp_result mp_int_sqr(mp_int a, mp_int c); /* c = a * a */
|
||||||
|
|
||||||
mp_result
|
mp_result mp_int_div(mp_int a, mp_int b, /* q = a / b */
|
||||||
mp_int_div(mp_int a, mp_int b, /* q = a / b */
|
|
||||||
mp_int q, mp_int r); /* r = a % b */
|
mp_int q, mp_int r); /* r = a % b */
|
||||||
mp_result
|
mp_result mp_int_div_value(mp_int a, int value, /* q = a / value */
|
||||||
mp_int_div_value(mp_int a, int value, /* q = a / value */
|
|
||||||
mp_int q, int *r); /* r = a % value */
|
mp_int q, int *r); /* r = a % value */
|
||||||
mp_result
|
mp_result mp_int_div_pow2(mp_int a, int p2, /* q = a / 2^p2 */
|
||||||
mp_int_div_pow2(mp_int a, int p2, /* q = a / 2^p2 */
|
|
||||||
mp_int q, mp_int r); /* r = q % 2^p2 */
|
mp_int q, mp_int r); /* r = q % 2^p2 */
|
||||||
mp_result mp_int_mod(mp_int a, mp_int m, mp_int c); /* c = a % m */
|
mp_result mp_int_mod(mp_int a, mp_int m, mp_int c); /* c = a % m */
|
||||||
|
|
||||||
@ -143,17 +140,13 @@ int mp_int_divisible_value(mp_int a, int v);
|
|||||||
/* Returns k >= 0 such that z = 2^k, if one exists; otherwise < 0 */
|
/* Returns k >= 0 such that z = 2^k, if one exists; otherwise < 0 */
|
||||||
int mp_int_is_pow2(mp_int z);
|
int mp_int_is_pow2(mp_int z);
|
||||||
|
|
||||||
mp_result
|
mp_result mp_int_exptmod(mp_int a, mp_int b, mp_int m,
|
||||||
mp_int_exptmod(mp_int a, mp_int b, mp_int m,
|
|
||||||
mp_int c); /* c = a^b (mod m) */
|
mp_int c); /* c = a^b (mod m) */
|
||||||
mp_result
|
mp_result mp_int_exptmod_evalue(mp_int a, int value,
|
||||||
mp_int_exptmod_evalue(mp_int a, int value,
|
|
||||||
mp_int m, mp_int c); /* c = a^v (mod m) */
|
mp_int m, mp_int c); /* c = a^v (mod m) */
|
||||||
mp_result
|
mp_result mp_int_exptmod_bvalue(int value, mp_int b,
|
||||||
mp_int_exptmod_bvalue(int value, mp_int b,
|
|
||||||
mp_int m, mp_int c); /* c = v^b (mod m) */
|
mp_int m, mp_int c); /* c = v^b (mod m) */
|
||||||
mp_result
|
mp_result mp_int_exptmod_known(mp_int a, mp_int b,
|
||||||
mp_int_exptmod_known(mp_int a, mp_int b,
|
|
||||||
mp_int m, mp_int mu,
|
mp_int m, mp_int mu,
|
||||||
mp_int c); /* c = a^b (mod m) */
|
mp_int c); /* c = a^b (mod m) */
|
||||||
mp_result mp_int_redux_const(mp_int m, mp_int c);
|
mp_result mp_int_redux_const(mp_int m, mp_int c);
|
||||||
@ -162,8 +155,7 @@ mp_result mp_int_invmod(mp_int a, mp_int m, mp_int c); /* c = 1/a (mod m) */
|
|||||||
|
|
||||||
mp_result mp_int_gcd(mp_int a, mp_int b, mp_int c); /* c = gcd(a, b) */
|
mp_result mp_int_gcd(mp_int a, mp_int b, mp_int c); /* c = gcd(a, b) */
|
||||||
|
|
||||||
mp_result
|
mp_result mp_int_egcd(mp_int a, mp_int b, mp_int c, /* c = gcd(a, b) */
|
||||||
mp_int_egcd(mp_int a, mp_int b, mp_int c, /* c = gcd(a, b) */
|
|
||||||
mp_int x, mp_int y); /* c = ax + by */
|
mp_int x, mp_int y); /* c = ax + by */
|
||||||
|
|
||||||
mp_result mp_int_sqrt(mp_int a, mp_int c); /* c = floor(sqrt(q)) */
|
mp_result mp_int_sqrt(mp_int a, mp_int c); /* c = floor(sqrt(q)) */
|
||||||
|
@ -265,8 +265,7 @@ int pgp_s2k_read(PullFilter *src, PGP_S2K *s2k);
|
|||||||
int pgp_s2k_process(PGP_S2K *s2k, int cipher, const uint8 *key, int klen);
|
int pgp_s2k_process(PGP_S2K *s2k, int cipher, const uint8 *key, int klen);
|
||||||
|
|
||||||
typedef struct PGP_CFB PGP_CFB;
|
typedef struct PGP_CFB PGP_CFB;
|
||||||
int
|
int pgp_cfb_create(PGP_CFB **ctx_p, int algo,
|
||||||
pgp_cfb_create(PGP_CFB **ctx_p, int algo,
|
|
||||||
const uint8 *key, int key_len, int recync, uint8 *iv);
|
const uint8 *key, int key_len, int recync, uint8 *iv);
|
||||||
void pgp_cfb_free(PGP_CFB *ctx);
|
void pgp_cfb_free(PGP_CFB *ctx);
|
||||||
int pgp_cfb_encrypt(PGP_CFB *ctx, const uint8 *data, int len, uint8 *dst);
|
int pgp_cfb_encrypt(PGP_CFB *ctx, const uint8 *data, int len, uint8 *dst);
|
||||||
|
@ -280,8 +280,8 @@ pgrowlocks(PG_FUNCTION_ARGS)
|
|||||||
result = HeapTupleGetDatum(tuple);
|
result = HeapTupleGetDatum(tuple);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* no need to pfree what we allocated; it's on a short-lived memory
|
* no need to pfree what we allocated; it's on a short-lived
|
||||||
* context anyway
|
* memory context anyway
|
||||||
*/
|
*/
|
||||||
|
|
||||||
SRF_RETURN_NEXT(funcctx, result);
|
SRF_RETURN_NEXT(funcctx, result);
|
||||||
|
@ -211,9 +211,9 @@ sepgsql_object_access(ObjectAccessType access,
|
|||||||
/*
|
/*
|
||||||
* A case when we don't want to apply permission
|
* A case when we don't want to apply permission
|
||||||
* check is that relation is internally altered
|
* check is that relation is internally altered
|
||||||
* without user's intention. E.g, no need to
|
* without user's intention. E.g, no need to check
|
||||||
* check on toast table/index to be renamed at
|
* on toast table/index to be renamed at end of
|
||||||
* end of the table rewrites.
|
* the table rewrites.
|
||||||
*/
|
*/
|
||||||
if (is_internal)
|
if (is_internal)
|
||||||
break;
|
break;
|
||||||
@ -241,8 +241,8 @@ sepgsql_object_access(ObjectAccessType access,
|
|||||||
ObjectAccessNamespaceSearch *ns_arg = arg;
|
ObjectAccessNamespaceSearch *ns_arg = arg;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If stacked extension already decided not to allow users
|
* If stacked extension already decided not to allow users to
|
||||||
* to search this schema, we just stick with that decision.
|
* search this schema, we just stick with that decision.
|
||||||
*/
|
*/
|
||||||
if (!ns_arg->result)
|
if (!ns_arg->result)
|
||||||
break;
|
break;
|
||||||
|
@ -351,9 +351,8 @@ sepgsql_fmgr_hook(FmgrHookEventType event,
|
|||||||
*
|
*
|
||||||
* Also, db_procedure:entrypoint permission should be checked
|
* Also, db_procedure:entrypoint permission should be checked
|
||||||
* whether this procedure can perform as an entrypoint of the
|
* whether this procedure can perform as an entrypoint of the
|
||||||
* trusted procedure, or not.
|
* trusted procedure, or not. Note that db_procedure:execute
|
||||||
* Note that db_procedure:execute permission shall be checked
|
* permission shall be checked individually.
|
||||||
* individually.
|
|
||||||
*/
|
*/
|
||||||
if (stack->new_label)
|
if (stack->new_label)
|
||||||
{
|
{
|
||||||
|
@ -81,6 +81,7 @@ sepgsql_schema_post_create(Oid namespaceId)
|
|||||||
tcontext,
|
tcontext,
|
||||||
SEPG_CLASS_DB_SCHEMA,
|
SEPG_CLASS_DB_SCHEMA,
|
||||||
nsp_name);
|
nsp_name);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* check db_schema:{create}
|
* check db_schema:{create}
|
||||||
*/
|
*/
|
||||||
|
@ -237,11 +237,11 @@ worker_spi_main(void *main_arg)
|
|||||||
* start time is always up to date.
|
* start time is always up to date.
|
||||||
*
|
*
|
||||||
* The SPI_connect() call lets us run queries through the SPI manager,
|
* The SPI_connect() call lets us run queries through the SPI manager,
|
||||||
* and the PushActiveSnapshot() call creates an "active" snapshot which
|
* and the PushActiveSnapshot() call creates an "active" snapshot
|
||||||
* is necessary for queries to have MVCC data to work on.
|
* which is necessary for queries to have MVCC data to work on.
|
||||||
*
|
*
|
||||||
* The pgstat_report_activity() call makes our activity visible through
|
* The pgstat_report_activity() call makes our activity visible
|
||||||
* the pgstat views.
|
* through the pgstat views.
|
||||||
*/
|
*/
|
||||||
SetCurrentStatementStartTimestamp();
|
SetCurrentStatementStartTimestamp();
|
||||||
StartTransactionCommand();
|
StartTransactionCommand();
|
||||||
|
@ -173,7 +173,6 @@ void
|
|||||||
ginFindParents(GinBtree btree, GinBtreeStack *stack,
|
ginFindParents(GinBtree btree, GinBtreeStack *stack,
|
||||||
BlockNumber rootBlkno)
|
BlockNumber rootBlkno)
|
||||||
{
|
{
|
||||||
|
|
||||||
Page page;
|
Page page;
|
||||||
Buffer buffer;
|
Buffer buffer;
|
||||||
BlockNumber blkno,
|
BlockNumber blkno,
|
||||||
|
@ -364,8 +364,9 @@ gistScanPage(IndexScanDesc scan, GISTSearchItem *pageItem, double *myDistances,
|
|||||||
item->blkno = ItemPointerGetBlockNumber(&it->t_tid);
|
item->blkno = ItemPointerGetBlockNumber(&it->t_tid);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* LSN of current page is lsn of parent page for child. We only
|
* LSN of current page is lsn of parent page for child. We
|
||||||
* have a shared lock, so we need to get the LSN atomically.
|
* only have a shared lock, so we need to get the LSN
|
||||||
|
* atomically.
|
||||||
*/
|
*/
|
||||||
item->data.parentlsn = BufferGetLSNAtomic(buffer);
|
item->data.parentlsn = BufferGetLSNAtomic(buffer);
|
||||||
}
|
}
|
||||||
|
@ -810,8 +810,8 @@ gistGetFakeLSN(Relation rel)
|
|||||||
if (rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP)
|
if (rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Temporary relations are only accessible in our session, so a
|
* Temporary relations are only accessible in our session, so a simple
|
||||||
* simple backend-local counter will do.
|
* backend-local counter will do.
|
||||||
*/
|
*/
|
||||||
return counter++;
|
return counter++;
|
||||||
}
|
}
|
||||||
|
@ -123,6 +123,7 @@ static const struct
|
|||||||
MultiXactStatus lockstatus;
|
MultiXactStatus lockstatus;
|
||||||
MultiXactStatus updstatus;
|
MultiXactStatus updstatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
tupleLockExtraInfo[MaxLockTupleMode + 1] =
|
tupleLockExtraInfo[MaxLockTupleMode + 1] =
|
||||||
{
|
{
|
||||||
{ /* LockTupleKeyShare */
|
{ /* LockTupleKeyShare */
|
||||||
@ -146,6 +147,7 @@ tupleLockExtraInfo[MaxLockTupleMode + 1] =
|
|||||||
MultiXactStatusUpdate
|
MultiXactStatusUpdate
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Get the LOCKMODE for a given MultiXactStatus */
|
/* Get the LOCKMODE for a given MultiXactStatus */
|
||||||
#define LOCKMODE_from_mxstatus(status) \
|
#define LOCKMODE_from_mxstatus(status) \
|
||||||
(tupleLockExtraInfo[TUPLOCK_from_mxstatus((status))].hwlock)
|
(tupleLockExtraInfo[TUPLOCK_from_mxstatus((status))].hwlock)
|
||||||
@ -365,10 +367,10 @@ heapgetpage(HeapScanDesc scan, BlockNumber page)
|
|||||||
* page. That's how index-only scans work fine in hot standby. A crucial
|
* page. That's how index-only scans work fine in hot standby. A crucial
|
||||||
* difference between index-only scans and heap scans is that the
|
* difference between index-only scans and heap scans is that the
|
||||||
* index-only scan completely relies on the visibility map where as heap
|
* index-only scan completely relies on the visibility map where as heap
|
||||||
* scan looks at the page-level PD_ALL_VISIBLE flag. We are not sure if the
|
* scan looks at the page-level PD_ALL_VISIBLE flag. We are not sure if
|
||||||
* page-level flag can be trusted in the same way, because it might get
|
* the page-level flag can be trusted in the same way, because it might
|
||||||
* propagated somehow without being explicitly WAL-logged, e.g. via a full
|
* get propagated somehow without being explicitly WAL-logged, e.g. via a
|
||||||
* page write. Until we can prove that beyond doubt, let's check each
|
* full page write. Until we can prove that beyond doubt, let's check each
|
||||||
* tuple for visibility the hard way.
|
* tuple for visibility the hard way.
|
||||||
*/
|
*/
|
||||||
all_visible = PageIsAllVisible(dp) && !snapshot->takenDuringRecovery;
|
all_visible = PageIsAllVisible(dp) && !snapshot->takenDuringRecovery;
|
||||||
@ -2730,13 +2732,12 @@ l1:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If this is the first possibly-multixact-able operation in the
|
* If this is the first possibly-multixact-able operation in the current
|
||||||
* current transaction, set my per-backend OldestMemberMXactId setting.
|
* transaction, set my per-backend OldestMemberMXactId setting. We can be
|
||||||
* We can be certain that the transaction will never become a member of
|
* certain that the transaction will never become a member of any older
|
||||||
* any older MultiXactIds than that. (We have to do this even if we
|
* MultiXactIds than that. (We have to do this even if we end up just
|
||||||
* end up just using our own TransactionId below, since some other
|
* using our own TransactionId below, since some other backend could
|
||||||
* backend could incorporate our XID into a MultiXact immediately
|
* incorporate our XID into a MultiXact immediately afterwards.)
|
||||||
* afterwards.)
|
|
||||||
*/
|
*/
|
||||||
MultiXactIdSetOldestMember();
|
MultiXactIdSetOldestMember();
|
||||||
|
|
||||||
@ -3006,13 +3007,13 @@ heap_update(Relation relation, ItemPointer otid, HeapTuple newtup,
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* If we're not updating any "key" column, we can grab a weaker lock type.
|
* If we're not updating any "key" column, we can grab a weaker lock type.
|
||||||
* This allows for more concurrency when we are running simultaneously with
|
* This allows for more concurrency when we are running simultaneously
|
||||||
* foreign key checks.
|
* with foreign key checks.
|
||||||
*
|
*
|
||||||
* Note that if a column gets detoasted while executing the update, but the
|
* Note that if a column gets detoasted while executing the update, but
|
||||||
* value ends up being the same, this test will fail and we will use the
|
* the value ends up being the same, this test will fail and we will use
|
||||||
* stronger lock. This is acceptable; the important case to optimize is
|
* the stronger lock. This is acceptable; the important case to optimize
|
||||||
* updates that don't manipulate key columns, not those that
|
* is updates that don't manipulate key columns, not those that
|
||||||
* serendipitiously arrive at the same key values.
|
* serendipitiously arrive at the same key values.
|
||||||
*/
|
*/
|
||||||
HeapSatisfiesHOTandKeyUpdate(relation, hot_attrs, key_attrs,
|
HeapSatisfiesHOTandKeyUpdate(relation, hot_attrs, key_attrs,
|
||||||
@ -3026,12 +3027,12 @@ heap_update(Relation relation, ItemPointer otid, HeapTuple newtup,
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* If this is the first possibly-multixact-able operation in the
|
* If this is the first possibly-multixact-able operation in the
|
||||||
* current transaction, set my per-backend OldestMemberMXactId setting.
|
* current transaction, set my per-backend OldestMemberMXactId
|
||||||
* We can be certain that the transaction will never become a member of
|
* setting. We can be certain that the transaction will never become a
|
||||||
* any older MultiXactIds than that. (We have to do this even if we
|
* member of any older MultiXactIds than that. (We have to do this
|
||||||
* end up just using our own TransactionId below, since some other
|
* even if we end up just using our own TransactionId below, since
|
||||||
* backend could incorporate our XID into a MultiXact immediately
|
* some other backend could incorporate our XID into a MultiXact
|
||||||
* afterwards.)
|
* immediately afterwards.)
|
||||||
*/
|
*/
|
||||||
MultiXactIdSetOldestMember();
|
MultiXactIdSetOldestMember();
|
||||||
}
|
}
|
||||||
@ -3073,13 +3074,14 @@ l2:
|
|||||||
/*
|
/*
|
||||||
* XXX note that we don't consider the "no wait" case here. This
|
* XXX note that we don't consider the "no wait" case here. This
|
||||||
* isn't a problem currently because no caller uses that case, but it
|
* isn't a problem currently because no caller uses that case, but it
|
||||||
* should be fixed if such a caller is introduced. It wasn't a problem
|
* should be fixed if such a caller is introduced. It wasn't a
|
||||||
* previously because this code would always wait, but now that some
|
* problem previously because this code would always wait, but now
|
||||||
* tuple locks do not conflict with one of the lock modes we use, it is
|
* that some tuple locks do not conflict with one of the lock modes we
|
||||||
* possible that this case is interesting to handle specially.
|
* use, it is possible that this case is interesting to handle
|
||||||
|
* specially.
|
||||||
*
|
*
|
||||||
* This may cause failures with third-party code that calls heap_update
|
* This may cause failures with third-party code that calls
|
||||||
* directly.
|
* heap_update directly.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* must copy state data before unlocking buffer */
|
/* must copy state data before unlocking buffer */
|
||||||
@ -3109,10 +3111,10 @@ l2:
|
|||||||
* gone (or even not sleep at all in some cases); we need to preserve
|
* gone (or even not sleep at all in some cases); we need to preserve
|
||||||
* it as locker, unless it is gone completely.
|
* it as locker, unless it is gone completely.
|
||||||
*
|
*
|
||||||
* If it's not a multi, we need to check for sleeping conditions before
|
* If it's not a multi, we need to check for sleeping conditions
|
||||||
* actually going to sleep. If the update doesn't conflict with the
|
* before actually going to sleep. If the update doesn't conflict
|
||||||
* locks, we just continue without sleeping (but making sure it is
|
* with the locks, we just continue without sleeping (but making sure
|
||||||
* preserved).
|
* it is preserved).
|
||||||
*/
|
*/
|
||||||
if (infomask & HEAP_XMAX_IS_MULTI)
|
if (infomask & HEAP_XMAX_IS_MULTI)
|
||||||
{
|
{
|
||||||
@ -3138,15 +3140,15 @@ l2:
|
|||||||
* Note that the multixact may not be done by now. It could have
|
* Note that the multixact may not be done by now. It could have
|
||||||
* surviving members; our own xact or other subxacts of this
|
* surviving members; our own xact or other subxacts of this
|
||||||
* backend, and also any other concurrent transaction that locked
|
* backend, and also any other concurrent transaction that locked
|
||||||
* the tuple with KeyShare if we only got TupleLockUpdate. If this
|
* the tuple with KeyShare if we only got TupleLockUpdate. If
|
||||||
* is the case, we have to be careful to mark the updated tuple
|
* this is the case, we have to be careful to mark the updated
|
||||||
* with the surviving members in Xmax.
|
* tuple with the surviving members in Xmax.
|
||||||
*
|
*
|
||||||
* Note that there could have been another update in the MultiXact.
|
* Note that there could have been another update in the
|
||||||
* In that case, we need to check whether it committed or aborted.
|
* MultiXact. In that case, we need to check whether it committed
|
||||||
* If it aborted we are safe to update it again; otherwise there is
|
* or aborted. If it aborted we are safe to update it again;
|
||||||
* an update conflict, and we have to return HeapTupleUpdated
|
* otherwise there is an update conflict, and we have to return
|
||||||
* below.
|
* HeapTupleUpdated below.
|
||||||
*
|
*
|
||||||
* In the LockTupleExclusive case, we still need to preserve the
|
* In the LockTupleExclusive case, we still need to preserve the
|
||||||
* surviving members: those would include the tuple locks we had
|
* surviving members: those would include the tuple locks we had
|
||||||
@ -3167,17 +3169,17 @@ l2:
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* If it's just a key-share locker, and we're not changing the
|
* If it's just a key-share locker, and we're not changing the key
|
||||||
* key columns, we don't need to wait for it to end; but we
|
* columns, we don't need to wait for it to end; but we need to
|
||||||
* need to preserve it as locker.
|
* preserve it as locker.
|
||||||
*/
|
*/
|
||||||
if (HEAP_XMAX_IS_KEYSHR_LOCKED(infomask) && key_intact)
|
if (HEAP_XMAX_IS_KEYSHR_LOCKED(infomask) && key_intact)
|
||||||
{
|
{
|
||||||
LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
|
LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* recheck the locker; if someone else changed the tuple while we
|
* recheck the locker; if someone else changed the tuple while
|
||||||
* weren't looking, start over.
|
* we weren't looking, start over.
|
||||||
*/
|
*/
|
||||||
if ((oldtup.t_data->t_infomask & HEAP_XMAX_IS_MULTI) ||
|
if ((oldtup.t_data->t_infomask & HEAP_XMAX_IS_MULTI) ||
|
||||||
!TransactionIdEquals(HeapTupleHeaderGetRawXmax(oldtup.t_data),
|
!TransactionIdEquals(HeapTupleHeaderGetRawXmax(oldtup.t_data),
|
||||||
@ -3194,9 +3196,9 @@ l2:
|
|||||||
LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
|
LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* xwait is done, but if xwait had just locked the tuple then some
|
* xwait is done, but if xwait had just locked the tuple then
|
||||||
* other xact could update this tuple before we get to this point.
|
* some other xact could update this tuple before we get to
|
||||||
* Check for xmax change, and start over if so.
|
* this point. Check for xmax change, and start over if so.
|
||||||
*/
|
*/
|
||||||
if ((oldtup.t_data->t_infomask & HEAP_XMAX_IS_MULTI) ||
|
if ((oldtup.t_data->t_infomask & HEAP_XMAX_IS_MULTI) ||
|
||||||
!TransactionIdEquals(HeapTupleHeaderGetRawXmax(oldtup.t_data),
|
!TransactionIdEquals(HeapTupleHeaderGetRawXmax(oldtup.t_data),
|
||||||
@ -3247,8 +3249,8 @@ l2:
|
|||||||
* visible while we were busy locking the buffer, or during some
|
* visible while we were busy locking the buffer, or during some
|
||||||
* subsequent window during which we had it unlocked, we'll have to unlock
|
* subsequent window during which we had it unlocked, we'll have to unlock
|
||||||
* and re-lock, to avoid holding the buffer lock across an I/O. That's a
|
* and re-lock, to avoid holding the buffer lock across an I/O. That's a
|
||||||
* bit unfortunate, especially since we'll now have to recheck whether
|
* bit unfortunate, especially since we'll now have to recheck whether the
|
||||||
* the tuple has been locked or updated under us, but hopefully it won't
|
* tuple has been locked or updated under us, but hopefully it won't
|
||||||
* happen very often.
|
* happen very often.
|
||||||
*/
|
*/
|
||||||
if (vmbuffer == InvalidBuffer && PageIsAllVisible(page))
|
if (vmbuffer == InvalidBuffer && PageIsAllVisible(page))
|
||||||
@ -3656,9 +3658,9 @@ heap_tuple_attr_equals(TupleDesc tupdesc, int attrnum,
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Extract the corresponding values. XXX this is pretty inefficient if
|
* Extract the corresponding values. XXX this is pretty inefficient if
|
||||||
* there are many indexed columns. Should HeapSatisfiesHOTandKeyUpdate do a
|
* there are many indexed columns. Should HeapSatisfiesHOTandKeyUpdate do
|
||||||
* single heap_deform_tuple call on each tuple, instead? But that doesn't
|
* a single heap_deform_tuple call on each tuple, instead? But that
|
||||||
* work for system columns ...
|
* doesn't work for system columns ...
|
||||||
*/
|
*/
|
||||||
value1 = heap_getattr(tup1, attrnum, tupdesc, &isnull1);
|
value1 = heap_getattr(tup1, attrnum, tupdesc, &isnull1);
|
||||||
value2 = heap_getattr(tup2, attrnum, tupdesc, &isnull2);
|
value2 = heap_getattr(tup2, attrnum, tupdesc, &isnull2);
|
||||||
@ -3944,11 +3946,11 @@ l3:
|
|||||||
LockBuffer(*buffer, BUFFER_LOCK_UNLOCK);
|
LockBuffer(*buffer, BUFFER_LOCK_UNLOCK);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If any subtransaction of the current top transaction already holds a
|
* If any subtransaction of the current top transaction already holds
|
||||||
* lock as strong or stronger than what we're requesting, we
|
* a lock as strong or stronger than what we're requesting, we
|
||||||
* effectively hold the desired lock already. We *must* succeed
|
* effectively hold the desired lock already. We *must* succeed
|
||||||
* without trying to take the tuple lock, else we will deadlock against
|
* without trying to take the tuple lock, else we will deadlock
|
||||||
* anyone wanting to acquire a stronger lock.
|
* against anyone wanting to acquire a stronger lock.
|
||||||
*/
|
*/
|
||||||
if (infomask & HEAP_XMAX_IS_MULTI)
|
if (infomask & HEAP_XMAX_IS_MULTI)
|
||||||
{
|
{
|
||||||
@ -3957,9 +3959,9 @@ l3:
|
|||||||
MultiXactMember *members;
|
MultiXactMember *members;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We don't need to allow old multixacts here; if that had been the
|
* We don't need to allow old multixacts here; if that had been
|
||||||
* case, HeapTupleSatisfiesUpdate would have returned MayBeUpdated
|
* the case, HeapTupleSatisfiesUpdate would have returned
|
||||||
* and we wouldn't be here.
|
* MayBeUpdated and we wouldn't be here.
|
||||||
*/
|
*/
|
||||||
nmembers = GetMultiXactIdMembers(xwait, &members, false);
|
nmembers = GetMultiXactIdMembers(xwait, &members, false);
|
||||||
|
|
||||||
@ -4023,20 +4025,20 @@ l3:
|
|||||||
* continue if the key hasn't been modified.
|
* continue if the key hasn't been modified.
|
||||||
*
|
*
|
||||||
* However, if there are updates, we need to walk the update chain
|
* However, if there are updates, we need to walk the update chain
|
||||||
* to mark future versions of the row as locked, too. That way, if
|
* to mark future versions of the row as locked, too. That way,
|
||||||
* somebody deletes that future version, we're protected against
|
* if somebody deletes that future version, we're protected
|
||||||
* the key going away. This locking of future versions could block
|
* against the key going away. This locking of future versions
|
||||||
* momentarily, if a concurrent transaction is deleting a key; or
|
* could block momentarily, if a concurrent transaction is
|
||||||
* it could return a value to the effect that the transaction
|
* deleting a key; or it could return a value to the effect that
|
||||||
* deleting the key has already committed. So we do this before
|
* the transaction deleting the key has already committed. So we
|
||||||
* re-locking the buffer; otherwise this would be prone to
|
* do this before re-locking the buffer; otherwise this would be
|
||||||
* deadlocks.
|
* prone to deadlocks.
|
||||||
*
|
*
|
||||||
* Note that the TID we're locking was grabbed before we unlocked
|
* Note that the TID we're locking was grabbed before we unlocked
|
||||||
* the buffer. For it to change while we're not looking, the other
|
* the buffer. For it to change while we're not looking, the
|
||||||
* properties we're testing for below after re-locking the buffer
|
* other properties we're testing for below after re-locking the
|
||||||
* would also change, in which case we would restart this loop
|
* buffer would also change, in which case we would restart this
|
||||||
* above.
|
* loop above.
|
||||||
*/
|
*/
|
||||||
if (!(infomask2 & HEAP_KEYS_UPDATED))
|
if (!(infomask2 & HEAP_KEYS_UPDATED))
|
||||||
{
|
{
|
||||||
@ -4045,8 +4047,8 @@ l3:
|
|||||||
updated = !HEAP_XMAX_IS_LOCKED_ONLY(infomask);
|
updated = !HEAP_XMAX_IS_LOCKED_ONLY(infomask);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If there are updates, follow the update chain; bail out
|
* If there are updates, follow the update chain; bail out if
|
||||||
* if that cannot be done.
|
* that cannot be done.
|
||||||
*/
|
*/
|
||||||
if (follow_updates && updated)
|
if (follow_updates && updated)
|
||||||
{
|
{
|
||||||
@ -4069,8 +4071,9 @@ l3:
|
|||||||
/*
|
/*
|
||||||
* Make sure it's still an appropriate lock, else start over.
|
* Make sure it's still an appropriate lock, else start over.
|
||||||
* Also, if it wasn't updated before we released the lock, but
|
* Also, if it wasn't updated before we released the lock, but
|
||||||
* is updated now, we start over too; the reason is that we now
|
* is updated now, we start over too; the reason is that we
|
||||||
* need to follow the update chain to lock the new versions.
|
* now need to follow the update chain to lock the new
|
||||||
|
* versions.
|
||||||
*/
|
*/
|
||||||
if (!HeapTupleHeaderIsOnlyLocked(tuple->t_data) &&
|
if (!HeapTupleHeaderIsOnlyLocked(tuple->t_data) &&
|
||||||
((tuple->t_data->t_infomask2 & HEAP_KEYS_UPDATED) ||
|
((tuple->t_data->t_infomask2 & HEAP_KEYS_UPDATED) ||
|
||||||
@ -4114,8 +4117,8 @@ l3:
|
|||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* If we're requesting NoKeyExclusive, we might also be able to
|
* If we're requesting NoKeyExclusive, we might also be able to
|
||||||
* avoid sleeping; just ensure that there's no other lock type than
|
* avoid sleeping; just ensure that there's no other lock type
|
||||||
* KeyShare. Note that this is a bit more involved than just
|
* than KeyShare. Note that this is a bit more involved than just
|
||||||
* checking hint bits -- we need to expand the multixact to figure
|
* checking hint bits -- we need to expand the multixact to figure
|
||||||
* out lock modes for each one (unless there was only one such
|
* out lock modes for each one (unless there was only one such
|
||||||
* locker).
|
* locker).
|
||||||
@ -4126,8 +4129,8 @@ l3:
|
|||||||
MultiXactMember *members;
|
MultiXactMember *members;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We don't need to allow old multixacts here; if that had been
|
* We don't need to allow old multixacts here; if that had
|
||||||
* the case, HeapTupleSatisfiesUpdate would have returned
|
* been the case, HeapTupleSatisfiesUpdate would have returned
|
||||||
* MayBeUpdated and we wouldn't be here.
|
* MayBeUpdated and we wouldn't be here.
|
||||||
*/
|
*/
|
||||||
nmembers = GetMultiXactIdMembers(xwait, &members, false);
|
nmembers = GetMultiXactIdMembers(xwait, &members, false);
|
||||||
@ -4135,8 +4138,8 @@ l3:
|
|||||||
if (nmembers <= 0)
|
if (nmembers <= 0)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* No need to keep the previous xmax here. This is unlikely
|
* No need to keep the previous xmax here. This is
|
||||||
* to happen.
|
* unlikely to happen.
|
||||||
*/
|
*/
|
||||||
require_sleep = false;
|
require_sleep = false;
|
||||||
}
|
}
|
||||||
@ -4355,8 +4358,8 @@ failed:
|
|||||||
* for cases where it is a plain TransactionId.
|
* for cases where it is a plain TransactionId.
|
||||||
*
|
*
|
||||||
* Note in particular that this covers the case where we already hold
|
* Note in particular that this covers the case where we already hold
|
||||||
* exclusive lock on the tuple and the caller only wants key share or share
|
* exclusive lock on the tuple and the caller only wants key share or
|
||||||
* lock. It would certainly not do to give up the exclusive lock.
|
* share lock. It would certainly not do to give up the exclusive lock.
|
||||||
*/
|
*/
|
||||||
if (!(old_infomask & (HEAP_XMAX_INVALID |
|
if (!(old_infomask & (HEAP_XMAX_INVALID |
|
||||||
HEAP_XMAX_COMMITTED |
|
HEAP_XMAX_COMMITTED |
|
||||||
@ -4379,13 +4382,12 @@ failed:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If this is the first possibly-multixact-able operation in the
|
* If this is the first possibly-multixact-able operation in the current
|
||||||
* current transaction, set my per-backend OldestMemberMXactId setting.
|
* transaction, set my per-backend OldestMemberMXactId setting. We can be
|
||||||
* We can be certain that the transaction will never become a member of
|
* certain that the transaction will never become a member of any older
|
||||||
* any older MultiXactIds than that. (We have to do this even if we
|
* MultiXactIds than that. (We have to do this even if we end up just
|
||||||
* end up just using our own TransactionId below, since some other
|
* using our own TransactionId below, since some other backend could
|
||||||
* backend could incorporate our XID into a MultiXact immediately
|
* incorporate our XID into a MultiXact immediately afterwards.)
|
||||||
* afterwards.)
|
|
||||||
*/
|
*/
|
||||||
MultiXactIdSetOldestMember();
|
MultiXactIdSetOldestMember();
|
||||||
|
|
||||||
@ -4422,8 +4424,8 @@ failed:
|
|||||||
* Make sure there is no forward chain link in t_ctid. Note that in the
|
* Make sure there is no forward chain link in t_ctid. Note that in the
|
||||||
* cases where the tuple has been updated, we must not overwrite t_ctid,
|
* cases where the tuple has been updated, we must not overwrite t_ctid,
|
||||||
* because it was set by the updater. Moreover, if the tuple has been
|
* because it was set by the updater. Moreover, if the tuple has been
|
||||||
* updated, we need to follow the update chain to lock the new versions
|
* updated, we need to follow the update chain to lock the new versions of
|
||||||
* of the tuple as well.
|
* the tuple as well.
|
||||||
*/
|
*/
|
||||||
if (HEAP_XMAX_IS_LOCKED_ONLY(new_infomask))
|
if (HEAP_XMAX_IS_LOCKED_ONLY(new_infomask))
|
||||||
tuple->t_data->t_ctid = *tid;
|
tuple->t_data->t_ctid = *tid;
|
||||||
@ -4565,8 +4567,8 @@ l5:
|
|||||||
MultiXactStatus new_status;
|
MultiXactStatus new_status;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Currently we don't allow XMAX_COMMITTED to be set for multis,
|
* Currently we don't allow XMAX_COMMITTED to be set for multis, so
|
||||||
* so cross-check.
|
* cross-check.
|
||||||
*/
|
*/
|
||||||
Assert(!(old_infomask & HEAP_XMAX_COMMITTED));
|
Assert(!(old_infomask & HEAP_XMAX_COMMITTED));
|
||||||
|
|
||||||
@ -4587,10 +4589,11 @@ l5:
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* If the XMAX is already a MultiXactId, then we need to expand it to
|
* If the XMAX is already a MultiXactId, then we need to expand it to
|
||||||
* include add_to_xmax; but if all the members were lockers and are all
|
* include add_to_xmax; but if all the members were lockers and are
|
||||||
* gone, we can do away with the IS_MULTI bit and just set add_to_xmax
|
* all gone, we can do away with the IS_MULTI bit and just set
|
||||||
* as the only locker/updater. If all lockers are gone and we have an
|
* add_to_xmax as the only locker/updater. If all lockers are gone
|
||||||
* updater that aborted, we can also do without a multi.
|
* and we have an updater that aborted, we can also do without a
|
||||||
|
* multi.
|
||||||
*
|
*
|
||||||
* The cost of doing GetMultiXactIdMembers would be paid by
|
* The cost of doing GetMultiXactIdMembers would be paid by
|
||||||
* MultiXactIdExpand if we weren't to do this, so this check is not
|
* MultiXactIdExpand if we weren't to do this, so this check is not
|
||||||
@ -4633,6 +4636,7 @@ l5:
|
|||||||
status = MultiXactStatusNoKeyUpdate;
|
status = MultiXactStatusNoKeyUpdate;
|
||||||
|
|
||||||
new_status = get_mxact_status_for_lock(mode, is_update);
|
new_status = get_mxact_status_for_lock(mode, is_update);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* since it's not running, it's obviously impossible for the old
|
* since it's not running, it's obviously impossible for the old
|
||||||
* updater to be identical to the current one, so we need not check
|
* updater to be identical to the current one, so we need not check
|
||||||
@ -4737,6 +4741,7 @@ l5:
|
|||||||
status = MultiXactStatusNoKeyUpdate;
|
status = MultiXactStatusNoKeyUpdate;
|
||||||
|
|
||||||
new_status = get_mxact_status_for_lock(mode, is_update);
|
new_status = get_mxact_status_for_lock(mode, is_update);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* since it's not running, it's obviously impossible for the old
|
* since it's not running, it's obviously impossible for the old
|
||||||
* updater to be identical to the current one, so we need not check
|
* updater to be identical to the current one, so we need not check
|
||||||
@ -4802,11 +4807,12 @@ l4:
|
|||||||
xmax = HeapTupleHeaderGetRawXmax(mytup.t_data);
|
xmax = HeapTupleHeaderGetRawXmax(mytup.t_data);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If this tuple is updated and the key has been modified (or deleted),
|
* If this tuple is updated and the key has been modified (or
|
||||||
* what we do depends on the status of the updating transaction: if
|
* deleted), what we do depends on the status of the updating
|
||||||
* it's live, we sleep until it finishes; if it has committed, we have
|
* transaction: if it's live, we sleep until it finishes; if it has
|
||||||
* to fail (i.e. return HeapTupleUpdated); if it aborted, we ignore it.
|
* committed, we have to fail (i.e. return HeapTupleUpdated); if it
|
||||||
* For updates that didn't touch the key, we can just plough ahead.
|
* aborted, we ignore it. For updates that didn't touch the key, we
|
||||||
|
* can just plough ahead.
|
||||||
*/
|
*/
|
||||||
if (!(old_infomask & HEAP_XMAX_INVALID) &&
|
if (!(old_infomask & HEAP_XMAX_INVALID) &&
|
||||||
(mytup.t_data->t_infomask2 & HEAP_KEYS_UPDATED))
|
(mytup.t_data->t_infomask2 & HEAP_KEYS_UPDATED))
|
||||||
@ -4932,12 +4938,12 @@ heap_lock_updated_tuple(Relation rel, HeapTuple tuple, ItemPointer ctid,
|
|||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* If this is the first possibly-multixact-able operation in the
|
* If this is the first possibly-multixact-able operation in the
|
||||||
* current transaction, set my per-backend OldestMemberMXactId setting.
|
* current transaction, set my per-backend OldestMemberMXactId
|
||||||
* We can be certain that the transaction will never become a member of
|
* setting. We can be certain that the transaction will never become a
|
||||||
* any older MultiXactIds than that. (We have to do this even if we
|
* member of any older MultiXactIds than that. (We have to do this
|
||||||
* end up just using our own TransactionId below, since some other
|
* even if we end up just using our own TransactionId below, since
|
||||||
* backend could incorporate our XID into a MultiXact immediately
|
* some other backend could incorporate our XID into a MultiXact
|
||||||
* afterwards.)
|
* immediately afterwards.)
|
||||||
*/
|
*/
|
||||||
MultiXactIdSetOldestMember();
|
MultiXactIdSetOldestMember();
|
||||||
|
|
||||||
@ -5117,9 +5123,9 @@ heap_freeze_tuple(HeapTupleHeader tuple, TransactionId cutoff_xid,
|
|||||||
HeapTupleHeaderSetXmax(tuple, InvalidTransactionId);
|
HeapTupleHeaderSetXmax(tuple, InvalidTransactionId);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The tuple might be marked either XMAX_INVALID or XMAX_COMMITTED
|
* The tuple might be marked either XMAX_INVALID or XMAX_COMMITTED +
|
||||||
* + LOCKED. Normalize to INVALID just to be sure no one gets
|
* LOCKED. Normalize to INVALID just to be sure no one gets confused.
|
||||||
* confused. Also get rid of the HEAP_KEYS_UPDATED bit.
|
* Also get rid of the HEAP_KEYS_UPDATED bit.
|
||||||
*/
|
*/
|
||||||
tuple->t_infomask &= ~HEAP_XMAX_BITS;
|
tuple->t_infomask &= ~HEAP_XMAX_BITS;
|
||||||
tuple->t_infomask |= HEAP_XMAX_INVALID;
|
tuple->t_infomask |= HEAP_XMAX_INVALID;
|
||||||
@ -5257,8 +5263,8 @@ MultiXactIdGetUpdateXid(TransactionId xmax, uint16 t_infomask)
|
|||||||
Assert(t_infomask & HEAP_XMAX_IS_MULTI);
|
Assert(t_infomask & HEAP_XMAX_IS_MULTI);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Since we know the LOCK_ONLY bit is not set, this cannot be a
|
* Since we know the LOCK_ONLY bit is not set, this cannot be a multi from
|
||||||
* multi from pre-pg_upgrade.
|
* pre-pg_upgrade.
|
||||||
*/
|
*/
|
||||||
nmembers = GetMultiXactIdMembers(xmax, &members, false);
|
nmembers = GetMultiXactIdMembers(xmax, &members, false);
|
||||||
|
|
||||||
@ -5284,6 +5290,7 @@ MultiXactIdGetUpdateXid(TransactionId xmax, uint16 t_infomask)
|
|||||||
members[i].status == MultiXactStatusUpdate);
|
members[i].status == MultiXactStatusUpdate);
|
||||||
update_xact = members[i].xid;
|
update_xact = members[i].xid;
|
||||||
#ifndef USE_ASSERT_CHECKING
|
#ifndef USE_ASSERT_CHECKING
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* in an assert-enabled build, walk the whole array to ensure
|
* in an assert-enabled build, walk the whole array to ensure
|
||||||
* there's no other updater.
|
* there's no other updater.
|
||||||
|
@ -532,8 +532,8 @@ _bt_log_reuse_page(Relation rel, BlockNumber blkno, TransactionId latestRemovedX
|
|||||||
START_CRIT_SECTION();
|
START_CRIT_SECTION();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We don't do MarkBufferDirty here because we're about to initialise
|
* We don't do MarkBufferDirty here because we're about to initialise the
|
||||||
* the page, and nobody else can see it yet.
|
* page, and nobody else can see it yet.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* XLOG stuff */
|
/* XLOG stuff */
|
||||||
@ -552,8 +552,8 @@ _bt_log_reuse_page(Relation rel, BlockNumber blkno, TransactionId latestRemovedX
|
|||||||
XLogInsert(RM_BTREE_ID, XLOG_BTREE_REUSE_PAGE, rdata);
|
XLogInsert(RM_BTREE_ID, XLOG_BTREE_REUSE_PAGE, rdata);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We don't do PageSetLSN here because we're about to initialise
|
* We don't do PageSetLSN here because we're about to initialise the
|
||||||
* the page, so no need.
|
* page, so no need.
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -608,8 +608,8 @@ btree_xlog_delete_get_latestRemovedXid(xl_btree_delete *xlrec)
|
|||||||
* In what follows, we have to examine the previous state of the index
|
* In what follows, we have to examine the previous state of the index
|
||||||
* page, as well as the heap page(s) it points to. This is only valid if
|
* page, as well as the heap page(s) it points to. This is only valid if
|
||||||
* WAL replay has reached a consistent database state; which means that
|
* WAL replay has reached a consistent database state; which means that
|
||||||
* the preceding check is not just an optimization, but is *necessary*.
|
* the preceding check is not just an optimization, but is *necessary*. We
|
||||||
* We won't have let in any user sessions before we reach consistency.
|
* won't have let in any user sessions before we reach consistency.
|
||||||
*/
|
*/
|
||||||
if (!reachedConsistency)
|
if (!reachedConsistency)
|
||||||
elog(PANIC, "btree_xlog_delete_get_latestRemovedXid: cannot operate with inconsistent data");
|
elog(PANIC, "btree_xlog_delete_get_latestRemovedXid: cannot operate with inconsistent data");
|
||||||
@ -701,10 +701,10 @@ btree_xlog_delete_get_latestRemovedXid(xl_btree_delete *xlrec)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* XXX If all heap tuples were LP_DEAD then we will be returning
|
* XXX If all heap tuples were LP_DEAD then we will be returning
|
||||||
* InvalidTransactionId here, causing conflict for all HS
|
* InvalidTransactionId here, causing conflict for all HS transactions.
|
||||||
* transactions. That should happen very rarely (reasoning please?). Also
|
* That should happen very rarely (reasoning please?). Also note that
|
||||||
* note that caller can't tell the difference between this case and the
|
* caller can't tell the difference between this case and the fast path
|
||||||
* fast path exit above. May need to change that in future.
|
* exit above. May need to change that in future.
|
||||||
*/
|
*/
|
||||||
return latestRemovedXid;
|
return latestRemovedXid;
|
||||||
}
|
}
|
||||||
|
@ -85,6 +85,7 @@ xlog_desc(StringInfo buf, uint8 xl_info, char *rec)
|
|||||||
else if (info == XLOG_HINT)
|
else if (info == XLOG_HINT)
|
||||||
{
|
{
|
||||||
BkpBlock *bkp = (BkpBlock *) rec;
|
BkpBlock *bkp = (BkpBlock *) rec;
|
||||||
|
|
||||||
appendStringInfo(buf, "page hint: %s block %u",
|
appendStringInfo(buf, "page hint: %s block %u",
|
||||||
relpathperm(bkp->node, bkp->fork),
|
relpathperm(bkp->node, bkp->fork),
|
||||||
bkp->block);
|
bkp->block);
|
||||||
|
@ -177,8 +177,8 @@ typedef struct MultiXactStateData
|
|||||||
MultiXactId lastTruncationPoint;
|
MultiXactId lastTruncationPoint;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* oldest multixact that is still on disk. Anything older than this should
|
* oldest multixact that is still on disk. Anything older than this
|
||||||
* not be consulted.
|
* should not be consulted.
|
||||||
*/
|
*/
|
||||||
MultiXactId oldestMultiXactId;
|
MultiXactId oldestMultiXactId;
|
||||||
Oid oldestMultiXactDB;
|
Oid oldestMultiXactDB;
|
||||||
@ -387,9 +387,9 @@ MultiXactIdExpand(MultiXactId multi, TransactionId xid, MultiXactStatus status)
|
|||||||
multi, xid, mxstatus_to_string(status));
|
multi, xid, mxstatus_to_string(status));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Note: we don't allow for old multis here. The reason is that the
|
* Note: we don't allow for old multis here. The reason is that the only
|
||||||
* only caller of this function does a check that the multixact is
|
* caller of this function does a check that the multixact is no longer
|
||||||
* no longer running.
|
* running.
|
||||||
*/
|
*/
|
||||||
nmembers = GetMultiXactIdMembers(multi, &members, false);
|
nmembers = GetMultiXactIdMembers(multi, &members, false);
|
||||||
|
|
||||||
@ -430,14 +430,14 @@ MultiXactIdExpand(MultiXactId multi, TransactionId xid, MultiXactStatus status)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Determine which of the members of the MultiXactId are still of interest.
|
* Determine which of the members of the MultiXactId are still of
|
||||||
* This is any running transaction, and also any transaction that grabbed
|
* interest. This is any running transaction, and also any transaction
|
||||||
* something stronger than just a lock and was committed. (An update that
|
* that grabbed something stronger than just a lock and was committed.
|
||||||
* aborted is of no interest here.)
|
* (An update that aborted is of no interest here.)
|
||||||
*
|
*
|
||||||
* (Removing dead members is just an optimization, but a useful one.
|
* (Removing dead members is just an optimization, but a useful one. Note
|
||||||
* Note we have the same race condition here as above: j could be 0 at the
|
* we have the same race condition here as above: j could be 0 at the end
|
||||||
* end of the loop.)
|
* of the loop.)
|
||||||
*/
|
*/
|
||||||
newMembers = (MultiXactMember *)
|
newMembers = (MultiXactMember *)
|
||||||
palloc(sizeof(MultiXactMember) * (nmembers + 1));
|
palloc(sizeof(MultiXactMember) * (nmembers + 1));
|
||||||
@ -722,9 +722,9 @@ CreateMultiXactId(int nmembers, MultiXactMember *members)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* XXX Note: there's a lot of padding space in MultiXactMember. We could
|
* XXX Note: there's a lot of padding space in MultiXactMember. We could
|
||||||
* find a more compact representation of this Xlog record -- perhaps all the
|
* find a more compact representation of this Xlog record -- perhaps all
|
||||||
* status flags in one XLogRecData, then all the xids in another one? Not
|
* the status flags in one XLogRecData, then all the xids in another one?
|
||||||
* clear that it's worth the trouble though.
|
* Not clear that it's worth the trouble though.
|
||||||
*/
|
*/
|
||||||
rdata[0].data = (char *) (&xlrec);
|
rdata[0].data = (char *) (&xlrec);
|
||||||
rdata[0].len = SizeOfMultiXactCreate;
|
rdata[0].len = SizeOfMultiXactCreate;
|
||||||
@ -995,10 +995,10 @@ GetNewMultiXactId(int nmembers, MultiXactOffset *offset)
|
|||||||
*
|
*
|
||||||
* We don't care about MultiXactId wraparound here; it will be handled by
|
* We don't care about MultiXactId wraparound here; it will be handled by
|
||||||
* the next iteration. But note that nextMXact may be InvalidMultiXactId
|
* the next iteration. But note that nextMXact may be InvalidMultiXactId
|
||||||
* or the first value on a segment-beginning page after this routine exits,
|
* or the first value on a segment-beginning page after this routine
|
||||||
* so anyone else looking at the variable must be prepared to deal with
|
* exits, so anyone else looking at the variable must be prepared to deal
|
||||||
* either case. Similarly, nextOffset may be zero, but we won't use that
|
* with either case. Similarly, nextOffset may be zero, but we won't use
|
||||||
* as the actual start offset of the next multixact.
|
* that as the actual start offset of the next multixact.
|
||||||
*/
|
*/
|
||||||
(MultiXactState->nextMXact)++;
|
(MultiXactState->nextMXact)++;
|
||||||
|
|
||||||
@ -1066,9 +1066,9 @@ GetMultiXactIdMembers(MultiXactId multi, MultiXactMember **members,
|
|||||||
*
|
*
|
||||||
* An ID older than MultiXactState->oldestMultiXactId cannot possibly be
|
* An ID older than MultiXactState->oldestMultiXactId cannot possibly be
|
||||||
* useful; it should have already been frozen by vacuum. We've truncated
|
* useful; it should have already been frozen by vacuum. We've truncated
|
||||||
* the on-disk structures anyway. Returning the wrong values could lead to
|
* the on-disk structures anyway. Returning the wrong values could lead
|
||||||
* an incorrect visibility result. However, to support pg_upgrade we need
|
* to an incorrect visibility result. However, to support pg_upgrade we
|
||||||
* to allow an empty set to be returned regardless, if the caller is
|
* need to allow an empty set to be returned regardless, if the caller is
|
||||||
* willing to accept it; the caller is expected to check that it's an
|
* willing to accept it; the caller is expected to check that it's an
|
||||||
* allowed condition (such as ensuring that the infomask bits set on the
|
* allowed condition (such as ensuring that the infomask bits set on the
|
||||||
* tuple are consistent with the pg_upgrade scenario). If the caller is
|
* tuple are consistent with the pg_upgrade scenario). If the caller is
|
||||||
@ -1076,8 +1076,8 @@ GetMultiXactIdMembers(MultiXactId multi, MultiXactMember **members,
|
|||||||
* raise an error.
|
* raise an error.
|
||||||
*
|
*
|
||||||
* Conversely, an ID >= nextMXact shouldn't ever be seen here; if it is
|
* Conversely, an ID >= nextMXact shouldn't ever be seen here; if it is
|
||||||
* seen, it implies undetected ID wraparound has occurred. This raises
|
* seen, it implies undetected ID wraparound has occurred. This raises a
|
||||||
* a hard error.
|
* hard error.
|
||||||
*
|
*
|
||||||
* Shared lock is enough here since we aren't modifying any global state.
|
* Shared lock is enough here since we aren't modifying any global state.
|
||||||
* Acquire it just long enough to grab the current counter values. We may
|
* Acquire it just long enough to grab the current counter values. We may
|
||||||
@ -1911,11 +1911,11 @@ SetMultiXactIdLimit(MultiXactId oldest_datminmxid, Oid oldest_datoid)
|
|||||||
multiStopLimit -= FirstMultiXactId;
|
multiStopLimit -= FirstMultiXactId;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We'll start complaining loudly when we get within 10M multis of the stop
|
* We'll start complaining loudly when we get within 10M multis of the
|
||||||
* point. This is kind of arbitrary, but if you let your gas gauge get
|
* stop point. This is kind of arbitrary, but if you let your gas gauge
|
||||||
* down to 1% of full, would you be looking for the next gas station? We
|
* get down to 1% of full, would you be looking for the next gas station?
|
||||||
* need to be fairly liberal about this number because there are lots of
|
* We need to be fairly liberal about this number because there are lots
|
||||||
* scenarios where most transactions are done by automatic clients that
|
* of scenarios where most transactions are done by automatic clients that
|
||||||
* won't pay attention to warnings. (No, we're not gonna make this
|
* won't pay attention to warnings. (No, we're not gonna make this
|
||||||
* configurable. If you know enough to configure it, you know enough to
|
* configurable. If you know enough to configure it, you know enough to
|
||||||
* not get in this kind of trouble in the first place.)
|
* not get in this kind of trouble in the first place.)
|
||||||
@ -1925,8 +1925,8 @@ SetMultiXactIdLimit(MultiXactId oldest_datminmxid, Oid oldest_datoid)
|
|||||||
multiWarnLimit -= FirstMultiXactId;
|
multiWarnLimit -= FirstMultiXactId;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We'll start trying to force autovacuums when oldest_datminmxid gets
|
* We'll start trying to force autovacuums when oldest_datminmxid gets to
|
||||||
* to be more than 200 million transactions old.
|
* be more than 200 million transactions old.
|
||||||
*/
|
*/
|
||||||
multiVacLimit = oldest_datminmxid + 200000000;
|
multiVacLimit = oldest_datminmxid + 200000000;
|
||||||
if (multiVacLimit < FirstMultiXactId)
|
if (multiVacLimit < FirstMultiXactId)
|
||||||
@ -2207,9 +2207,9 @@ TruncateMultiXact(MultiXactId oldestMXact)
|
|||||||
/*
|
/*
|
||||||
* Note we can't just plow ahead with the truncation; it's possible that
|
* Note we can't just plow ahead with the truncation; it's possible that
|
||||||
* there are no segments to truncate, which is a problem because we are
|
* there are no segments to truncate, which is a problem because we are
|
||||||
* going to attempt to read the offsets page to determine where to truncate
|
* going to attempt to read the offsets page to determine where to
|
||||||
* the members SLRU. So we first scan the directory to determine the
|
* truncate the members SLRU. So we first scan the directory to determine
|
||||||
* earliest offsets page number that we can read without error.
|
* the earliest offsets page number that we can read without error.
|
||||||
*/
|
*/
|
||||||
trunc.earliestExistingPage = -1;
|
trunc.earliestExistingPage = -1;
|
||||||
SlruScanDirectory(MultiXactOffsetCtl, SlruScanDirCbFindEarliest, &trunc);
|
SlruScanDirectory(MultiXactOffsetCtl, SlruScanDirCbFindEarliest, &trunc);
|
||||||
@ -2220,9 +2220,9 @@ TruncateMultiXact(MultiXactId oldestMXact)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* First, compute the safe truncation point for MultiXactMember.
|
* First, compute the safe truncation point for MultiXactMember. This is
|
||||||
* This is the starting offset of the multixact we were passed
|
* the starting offset of the multixact we were passed as MultiXactOffset
|
||||||
* as MultiXactOffset cutoff.
|
* cutoff.
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
int pageno;
|
int pageno;
|
||||||
|
@ -179,8 +179,8 @@ readTimeLineHistory(TimeLineID targetTLI)
|
|||||||
errhint("Timeline IDs must be less than child timeline's ID.")));
|
errhint("Timeline IDs must be less than child timeline's ID.")));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create one more entry for the "tip" of the timeline, which has no
|
* Create one more entry for the "tip" of the timeline, which has no entry
|
||||||
* entry in the history file.
|
* in the history file.
|
||||||
*/
|
*/
|
||||||
entry = (TimeLineHistoryEntry *) palloc(sizeof(TimeLineHistoryEntry));
|
entry = (TimeLineHistoryEntry *) palloc(sizeof(TimeLineHistoryEntry));
|
||||||
entry->tli = targetTLI;
|
entry->tli = targetTLI;
|
||||||
@ -553,6 +553,7 @@ tliOfPointInHistory(XLogRecPtr ptr, List *history)
|
|||||||
foreach(cell, history)
|
foreach(cell, history)
|
||||||
{
|
{
|
||||||
TimeLineHistoryEntry *tle = (TimeLineHistoryEntry *) lfirst(cell);
|
TimeLineHistoryEntry *tle = (TimeLineHistoryEntry *) lfirst(cell);
|
||||||
|
|
||||||
if ((XLogRecPtrIsInvalid(tle->begin) || tle->begin <= ptr) &&
|
if ((XLogRecPtrIsInvalid(tle->begin) || tle->begin <= ptr) &&
|
||||||
(XLogRecPtrIsInvalid(tle->end) || ptr < tle->end))
|
(XLogRecPtrIsInvalid(tle->end) || ptr < tle->end))
|
||||||
{
|
{
|
||||||
|
@ -1024,8 +1024,8 @@ RecordTransactionCommit(void)
|
|||||||
*
|
*
|
||||||
* It's safe to change the delayChkpt flag of our own backend without
|
* It's safe to change the delayChkpt flag of our own backend without
|
||||||
* holding the ProcArrayLock, since we're the only one modifying it.
|
* holding the ProcArrayLock, since we're the only one modifying it.
|
||||||
* This makes checkpoint's determination of which xacts are delayChkpt a
|
* This makes checkpoint's determination of which xacts are delayChkpt
|
||||||
* bit fuzzy, but it doesn't matter.
|
* a bit fuzzy, but it doesn't matter.
|
||||||
*/
|
*/
|
||||||
START_CRIT_SECTION();
|
START_CRIT_SECTION();
|
||||||
MyPgXact->delayChkpt = true;
|
MyPgXact->delayChkpt = true;
|
||||||
@ -4683,12 +4683,11 @@ xact_redo_commit_internal(TransactionId xid, XLogRecPtr lsn,
|
|||||||
* from the template database, and then commit the transaction. If we
|
* from the template database, and then commit the transaction. If we
|
||||||
* crash after all the files have been copied but before the commit, you
|
* crash after all the files have been copied but before the commit, you
|
||||||
* have files in the data directory without an entry in pg_database. To
|
* have files in the data directory without an entry in pg_database. To
|
||||||
* minimize the window
|
* minimize the window for that, we use ForceSyncCommit() to rush the
|
||||||
* for that, we use ForceSyncCommit() to rush the commit record to disk as
|
* commit record to disk as quick as possible. We have the same window
|
||||||
* quick as possible. We have the same window during recovery, and forcing
|
* during recovery, and forcing an XLogFlush() (which updates
|
||||||
* an XLogFlush() (which updates minRecoveryPoint during recovery) helps
|
* minRecoveryPoint during recovery) helps to reduce that problem window,
|
||||||
* to reduce that problem window, for any user that requested
|
* for any user that requested ForceSyncCommit().
|
||||||
* ForceSyncCommit().
|
|
||||||
*/
|
*/
|
||||||
if (XactCompletionForceSyncCommit(xinfo))
|
if (XactCompletionForceSyncCommit(xinfo))
|
||||||
XLogFlush(lsn);
|
XLogFlush(lsn);
|
||||||
|
@ -403,7 +403,8 @@ typedef struct XLogCtlData
|
|||||||
uint32 ckptXidEpoch; /* nextXID & epoch of latest checkpoint */
|
uint32 ckptXidEpoch; /* nextXID & epoch of latest checkpoint */
|
||||||
TransactionId ckptXid;
|
TransactionId ckptXid;
|
||||||
XLogRecPtr asyncXactLSN; /* LSN of newest async commit/abort */
|
XLogRecPtr asyncXactLSN; /* LSN of newest async commit/abort */
|
||||||
XLogSegNo lastRemovedSegNo; /* latest removed/recycled XLOG segment */
|
XLogSegNo lastRemovedSegNo; /* latest removed/recycled XLOG
|
||||||
|
* segment */
|
||||||
|
|
||||||
/* Fake LSN counter, for unlogged relations. Protected by ulsn_lck */
|
/* Fake LSN counter, for unlogged relations. Protected by ulsn_lck */
|
||||||
XLogRecPtr unloggedLSN;
|
XLogRecPtr unloggedLSN;
|
||||||
@ -1251,10 +1252,10 @@ XLogCheckBuffer(XLogRecData *rdata, bool holdsExclusiveLock,
|
|||||||
page = BufferGetPage(rdata->buffer);
|
page = BufferGetPage(rdata->buffer);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We assume page LSN is first data on *every* page that can be passed
|
* We assume page LSN is first data on *every* page that can be passed to
|
||||||
* to XLogInsert, whether it has the standard page layout or not. We
|
* XLogInsert, whether it has the standard page layout or not. We don't
|
||||||
* don't need to take the buffer header lock for PageGetLSN if we hold
|
* need to take the buffer header lock for PageGetLSN if we hold an
|
||||||
* an exclusive lock on the page and/or the relation.
|
* exclusive lock on the page and/or the relation.
|
||||||
*/
|
*/
|
||||||
if (holdsExclusiveLock)
|
if (holdsExclusiveLock)
|
||||||
*lsn = PageGetLSN(page);
|
*lsn = PageGetLSN(page);
|
||||||
@ -1979,8 +1980,8 @@ XLogFlush(XLogRecPtr record)
|
|||||||
/*
|
/*
|
||||||
* Sleep before flush! By adding a delay here, we may give further
|
* Sleep before flush! By adding a delay here, we may give further
|
||||||
* backends the opportunity to join the backlog of group commit
|
* backends the opportunity to join the backlog of group commit
|
||||||
* followers; this can significantly improve transaction throughput, at
|
* followers; this can significantly improve transaction throughput,
|
||||||
* the risk of increasing transaction latency.
|
* at the risk of increasing transaction latency.
|
||||||
*
|
*
|
||||||
* We do not sleep if enableFsync is not turned on, nor if there are
|
* We do not sleep if enableFsync is not turned on, nor if there are
|
||||||
* fewer than CommitSiblings other backends with active transactions.
|
* fewer than CommitSiblings other backends with active transactions.
|
||||||
@ -3215,8 +3216,8 @@ RestoreBackupBlockContents(XLogRecPtr lsn, BkpBlock bkpb, char *blk,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The checksum value on this page is currently invalid. We don't
|
* The checksum value on this page is currently invalid. We don't need to
|
||||||
* need to reset it here since it will be set before being written.
|
* reset it here since it will be set before being written.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
PageSetLSN(page, lsn);
|
PageSetLSN(page, lsn);
|
||||||
@ -3272,16 +3273,17 @@ ReadRecord(XLogReaderState *xlogreader, XLogRecPtr RecPtr, int emode,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We only end up here without a message when XLogPageRead() failed
|
* We only end up here without a message when XLogPageRead()
|
||||||
* - in that case we already logged something.
|
* failed - in that case we already logged something. In
|
||||||
* In StandbyMode that only happens if we have been triggered, so
|
* StandbyMode that only happens if we have been triggered, so we
|
||||||
* we shouldn't loop anymore in that case.
|
* shouldn't loop anymore in that case.
|
||||||
*/
|
*/
|
||||||
if (errormsg)
|
if (errormsg)
|
||||||
ereport(emode_for_corrupt_record(emode,
|
ereport(emode_for_corrupt_record(emode,
|
||||||
RecPtr ? RecPtr : EndRecPtr),
|
RecPtr ? RecPtr : EndRecPtr),
|
||||||
(errmsg_internal("%s", errormsg) /* already translated */ ));
|
(errmsg_internal("%s", errormsg) /* already translated */ ));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check page TLI is one of the expected values.
|
* Check page TLI is one of the expected values.
|
||||||
*/
|
*/
|
||||||
@ -3314,10 +3316,10 @@ ReadRecord(XLogReaderState *xlogreader, XLogRecPtr RecPtr, int emode,
|
|||||||
lastSourceFailed = true;
|
lastSourceFailed = true;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If archive recovery was requested, but we were still doing crash
|
* If archive recovery was requested, but we were still doing
|
||||||
* recovery, switch to archive recovery and retry using the offline
|
* crash recovery, switch to archive recovery and retry using the
|
||||||
* archive. We have now replayed all the valid WAL in pg_xlog, so
|
* offline archive. We have now replayed all the valid WAL in
|
||||||
* we are presumably now consistent.
|
* pg_xlog, so we are presumably now consistent.
|
||||||
*
|
*
|
||||||
* We require that there's at least some valid WAL present in
|
* We require that there's at least some valid WAL present in
|
||||||
* pg_xlog, however (!fetch_ckpt). We could recover using the WAL
|
* pg_xlog, however (!fetch_ckpt). We could recover using the WAL
|
||||||
@ -3401,8 +3403,8 @@ rescanLatestTimeLine(void)
|
|||||||
newExpectedTLEs = readTimeLineHistory(newtarget);
|
newExpectedTLEs = readTimeLineHistory(newtarget);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the current timeline is not part of the history of the new
|
* If the current timeline is not part of the history of the new timeline,
|
||||||
* timeline, we cannot proceed to it.
|
* we cannot proceed to it.
|
||||||
*/
|
*/
|
||||||
found = false;
|
found = false;
|
||||||
foreach(cell, newExpectedTLEs)
|
foreach(cell, newExpectedTLEs)
|
||||||
@ -4998,8 +5000,8 @@ StartupXLOG(void)
|
|||||||
&backupFromStandby))
|
&backupFromStandby))
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Archive recovery was requested, and thanks to the backup label file,
|
* Archive recovery was requested, and thanks to the backup label
|
||||||
* we know how far we need to replay to reach consistency. Enter
|
* file, we know how far we need to replay to reach consistency. Enter
|
||||||
* archive recovery directly.
|
* archive recovery directly.
|
||||||
*/
|
*/
|
||||||
InArchiveRecovery = true;
|
InArchiveRecovery = true;
|
||||||
@ -5049,8 +5051,8 @@ StartupXLOG(void)
|
|||||||
/*
|
/*
|
||||||
* It's possible that archive recovery was requested, but we don't
|
* It's possible that archive recovery was requested, but we don't
|
||||||
* know how far we need to replay the WAL before we reach consistency.
|
* know how far we need to replay the WAL before we reach consistency.
|
||||||
* This can happen for example if a base backup is taken from a running
|
* This can happen for example if a base backup is taken from a
|
||||||
* server using an atomic filesystem snapshot, without calling
|
* running server using an atomic filesystem snapshot, without calling
|
||||||
* pg_start/stop_backup. Or if you just kill a running master server
|
* pg_start/stop_backup. Or if you just kill a running master server
|
||||||
* and put it into archive recovery by creating a recovery.conf file.
|
* and put it into archive recovery by creating a recovery.conf file.
|
||||||
*
|
*
|
||||||
@ -5058,8 +5060,8 @@ StartupXLOG(void)
|
|||||||
* replaying all the WAL present in pg_xlog, and only enter archive
|
* replaying all the WAL present in pg_xlog, and only enter archive
|
||||||
* recovery after that.
|
* recovery after that.
|
||||||
*
|
*
|
||||||
* But usually we already know how far we need to replay the WAL (up to
|
* But usually we already know how far we need to replay the WAL (up
|
||||||
* minRecoveryPoint, up to backupEndPoint, or until we see an
|
* to minRecoveryPoint, up to backupEndPoint, or until we see an
|
||||||
* end-of-backup record), and we can enter archive recovery directly.
|
* end-of-backup record), and we can enter archive recovery directly.
|
||||||
*/
|
*/
|
||||||
if (ArchiveRecoveryRequested &&
|
if (ArchiveRecoveryRequested &&
|
||||||
@ -5119,15 +5121,16 @@ StartupXLOG(void)
|
|||||||
* timeline in the history of the requested timeline, we cannot proceed:
|
* timeline in the history of the requested timeline, we cannot proceed:
|
||||||
* the backup is not part of the history of the requested timeline.
|
* the backup is not part of the history of the requested timeline.
|
||||||
*/
|
*/
|
||||||
Assert(expectedTLEs); /* was initialized by reading checkpoint record */
|
Assert(expectedTLEs); /* was initialized by reading checkpoint
|
||||||
|
* record */
|
||||||
if (tliOfPointInHistory(checkPointLoc, expectedTLEs) !=
|
if (tliOfPointInHistory(checkPointLoc, expectedTLEs) !=
|
||||||
checkPoint.ThisTimeLineID)
|
checkPoint.ThisTimeLineID)
|
||||||
{
|
{
|
||||||
XLogRecPtr switchpoint;
|
XLogRecPtr switchpoint;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* tliSwitchPoint will throw an error if the checkpoint's timeline
|
* tliSwitchPoint will throw an error if the checkpoint's timeline is
|
||||||
* is not in expectedTLEs at all.
|
* not in expectedTLEs at all.
|
||||||
*/
|
*/
|
||||||
switchpoint = tliSwitchPoint(ControlFile->checkPointCopy.ThisTimeLineID, expectedTLEs, NULL);
|
switchpoint = tliSwitchPoint(ControlFile->checkPointCopy.ThisTimeLineID, expectedTLEs, NULL);
|
||||||
ereport(FATAL,
|
ereport(FATAL,
|
||||||
@ -5206,16 +5209,16 @@ StartupXLOG(void)
|
|||||||
ThisTimeLineID = checkPoint.ThisTimeLineID;
|
ThisTimeLineID = checkPoint.ThisTimeLineID;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copy any missing timeline history files between 'now' and the
|
* Copy any missing timeline history files between 'now' and the recovery
|
||||||
* recovery target timeline from archive to pg_xlog. While we don't need
|
* target timeline from archive to pg_xlog. While we don't need those
|
||||||
* those files ourselves - the history file of the recovery target
|
* files ourselves - the history file of the recovery target timeline
|
||||||
* timeline covers all the previous timelines in the history too - a
|
* covers all the previous timelines in the history too - a cascading
|
||||||
* cascading standby server might be interested in them. Or, if you
|
* standby server might be interested in them. Or, if you archive the WAL
|
||||||
* archive the WAL from this server to a different archive than the
|
* from this server to a different archive than the master, it'd be good
|
||||||
* master, it'd be good for all the history files to get archived there
|
* for all the history files to get archived there after failover, so that
|
||||||
* after failover, so that you can use one of the old timelines as a
|
* you can use one of the old timelines as a PITR target. Timeline history
|
||||||
* PITR target. Timeline history files are small, so it's better to copy
|
* files are small, so it's better to copy them unnecessarily than not
|
||||||
* them unnecessarily than not copy them and regret later.
|
* copy them and regret later.
|
||||||
*/
|
*/
|
||||||
restoreTimeLineHistoryFiles(ThisTimeLineID, recoveryTargetTLI);
|
restoreTimeLineHistoryFiles(ThisTimeLineID, recoveryTargetTLI);
|
||||||
|
|
||||||
@ -5517,6 +5520,7 @@ StartupXLOG(void)
|
|||||||
do
|
do
|
||||||
{
|
{
|
||||||
bool switchedTLI = false;
|
bool switchedTLI = false;
|
||||||
|
|
||||||
#ifdef WAL_DEBUG
|
#ifdef WAL_DEBUG
|
||||||
if (XLOG_DEBUG ||
|
if (XLOG_DEBUG ||
|
||||||
(rmid == RM_XACT_ID && trace_recovery_messages <= DEBUG2) ||
|
(rmid == RM_XACT_ID && trace_recovery_messages <= DEBUG2) ||
|
||||||
@ -5598,13 +5602,13 @@ StartupXLOG(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Before replaying this record, check if this record
|
* Before replaying this record, check if this record causes
|
||||||
* causes the current timeline to change. The record is
|
* the current timeline to change. The record is already
|
||||||
* already considered to be part of the new timeline,
|
* considered to be part of the new timeline, so we update
|
||||||
* so we update ThisTimeLineID before replaying it.
|
* ThisTimeLineID before replaying it. That's important so
|
||||||
* That's important so that replayEndTLI, which is
|
* that replayEndTLI, which is recorded as the minimum
|
||||||
* recorded as the minimum recovery point's TLI if
|
* recovery point's TLI if recovery stops after this record,
|
||||||
* recovery stops after this record, is set correctly.
|
* is set correctly.
|
||||||
*/
|
*/
|
||||||
if (record->xl_rmid == RM_XLOG_ID)
|
if (record->xl_rmid == RM_XLOG_ID)
|
||||||
{
|
{
|
||||||
@ -5952,8 +5956,9 @@ StartupXLOG(void)
|
|||||||
* allows some extra error checking in xlog_redo.
|
* allows some extra error checking in xlog_redo.
|
||||||
*
|
*
|
||||||
* In fast promotion, only create a lightweight end-of-recovery record
|
* In fast promotion, only create a lightweight end-of-recovery record
|
||||||
* instead of a full checkpoint. A checkpoint is requested later, after
|
* instead of a full checkpoint. A checkpoint is requested later,
|
||||||
* we're fully out of recovery mode and already accepting queries.
|
* after we're fully out of recovery mode and already accepting
|
||||||
|
* queries.
|
||||||
*/
|
*/
|
||||||
if (bgwriterLaunched)
|
if (bgwriterLaunched)
|
||||||
{
|
{
|
||||||
@ -5972,14 +5977,15 @@ StartupXLOG(void)
|
|||||||
fast_promoted = true;
|
fast_promoted = true;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Insert a special WAL record to mark the end of recovery,
|
* Insert a special WAL record to mark the end of
|
||||||
* since we aren't doing a checkpoint. That means that the
|
* recovery, since we aren't doing a checkpoint. That
|
||||||
* checkpointer process may likely be in the middle of a
|
* means that the checkpointer process may likely be in
|
||||||
* time-smoothed restartpoint and could continue to be for
|
* the middle of a time-smoothed restartpoint and could
|
||||||
* minutes after this. That sounds strange, but the effect
|
* continue to be for minutes after this. That sounds
|
||||||
* is roughly the same and it would be stranger to try to
|
* strange, but the effect is roughly the same and it
|
||||||
* come out of the restartpoint and then checkpoint.
|
* would be stranger to try to come out of the
|
||||||
* We request a checkpoint later anyway, just for safety.
|
* restartpoint and then checkpoint. We request a
|
||||||
|
* checkpoint later anyway, just for safety.
|
||||||
*/
|
*/
|
||||||
CreateEndOfRecoveryRecord();
|
CreateEndOfRecoveryRecord();
|
||||||
}
|
}
|
||||||
@ -6092,8 +6098,8 @@ StartupXLOG(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If there were cascading standby servers connected to us, nudge any
|
* If there were cascading standby servers connected to us, nudge any wal
|
||||||
* wal sender processes to notice that we've been promoted.
|
* sender processes to notice that we've been promoted.
|
||||||
*/
|
*/
|
||||||
WalSndWakeup();
|
WalSndWakeup();
|
||||||
|
|
||||||
@ -6151,9 +6157,9 @@ CheckRecoveryConsistency(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Have we passed our safe starting point? Note that minRecoveryPoint
|
* Have we passed our safe starting point? Note that minRecoveryPoint is
|
||||||
* is known to be incorrectly set if ControlFile->backupEndRequired,
|
* known to be incorrectly set if ControlFile->backupEndRequired, until
|
||||||
* until the XLOG_BACKUP_RECORD arrives to advise us of the correct
|
* the XLOG_BACKUP_RECORD arrives to advise us of the correct
|
||||||
* minRecoveryPoint. All we know prior to that is that we're not
|
* minRecoveryPoint. All we know prior to that is that we're not
|
||||||
* consistent yet.
|
* consistent yet.
|
||||||
*/
|
*/
|
||||||
@ -6946,8 +6952,8 @@ CreateCheckPoint(int flags)
|
|||||||
TRACE_POSTGRESQL_CHECKPOINT_START(flags);
|
TRACE_POSTGRESQL_CHECKPOINT_START(flags);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* In some cases there are groups of actions that must all occur on
|
* In some cases there are groups of actions that must all occur on one
|
||||||
* one side or the other of a checkpoint record. Before flushing the
|
* side or the other of a checkpoint record. Before flushing the
|
||||||
* checkpoint record we must explicitly wait for any backend currently
|
* checkpoint record we must explicitly wait for any backend currently
|
||||||
* performing those groups of actions.
|
* performing those groups of actions.
|
||||||
*
|
*
|
||||||
@ -7211,8 +7217,8 @@ CreateEndOfRecoveryRecord(void)
|
|||||||
XLogFlush(recptr);
|
XLogFlush(recptr);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Update the control file so that crash recovery can follow
|
* Update the control file so that crash recovery can follow the timeline
|
||||||
* the timeline changes to this point.
|
* changes to this point.
|
||||||
*/
|
*/
|
||||||
LWLockAcquire(ControlFileLock, LW_EXCLUSIVE);
|
LWLockAcquire(ControlFileLock, LW_EXCLUSIVE);
|
||||||
ControlFile->time = (pg_time_t) xlrec.end_time;
|
ControlFile->time = (pg_time_t) xlrec.end_time;
|
||||||
@ -7458,7 +7464,8 @@ CreateRestartPoint(int flags)
|
|||||||
XLogRecPtr endptr;
|
XLogRecPtr endptr;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get the current end of xlog replayed or received, whichever is later.
|
* Get the current end of xlog replayed or received, whichever is
|
||||||
|
* later.
|
||||||
*/
|
*/
|
||||||
receivePtr = GetWalRcvWriteRecPtr(NULL, NULL);
|
receivePtr = GetWalRcvWriteRecPtr(NULL, NULL);
|
||||||
replayPtr = GetXLogReplayRecPtr(NULL);
|
replayPtr = GetXLogReplayRecPtr(NULL);
|
||||||
@ -7468,8 +7475,8 @@ CreateRestartPoint(int flags)
|
|||||||
_logSegNo--;
|
_logSegNo--;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Update ThisTimeLineID to the timeline we're currently replaying,
|
* Update ThisTimeLineID to the timeline we're currently replaying, so
|
||||||
* so that we install any recycled segments on that timeline.
|
* that we install any recycled segments on that timeline.
|
||||||
*
|
*
|
||||||
* There is no guarantee that the WAL segments will be useful on the
|
* There is no guarantee that the WAL segments will be useful on the
|
||||||
* current timeline; if recovery proceeds to a new timeline right
|
* current timeline; if recovery proceeds to a new timeline right
|
||||||
@ -7480,8 +7487,8 @@ CreateRestartPoint(int flags)
|
|||||||
* It's possible or perhaps even likely that we finish recovery while
|
* It's possible or perhaps even likely that we finish recovery while
|
||||||
* a restartpoint is in progress. That means we may get to this point
|
* a restartpoint is in progress. That means we may get to this point
|
||||||
* some minutes afterwards. Setting ThisTimeLineID at that time would
|
* some minutes afterwards. Setting ThisTimeLineID at that time would
|
||||||
* actually set it backwards, so we don't want that to persist; if
|
* actually set it backwards, so we don't want that to persist; if we
|
||||||
* we do reset it here, make sure to reset it back afterwards. This
|
* do reset it here, make sure to reset it back afterwards. This
|
||||||
* doesn't look very clean or principled, but its the best of about
|
* doesn't look very clean or principled, but its the best of about
|
||||||
* five different ways of handling this edge case.
|
* five different ways of handling this edge case.
|
||||||
*/
|
*/
|
||||||
@ -7693,8 +7700,8 @@ XLogSaveBufferForHint(Buffer buffer)
|
|||||||
GetRedoRecPtr();
|
GetRedoRecPtr();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Setup phony rdata element for use within XLogCheckBuffer only.
|
* Setup phony rdata element for use within XLogCheckBuffer only. We reuse
|
||||||
* We reuse and reset rdata for any actual WAL record insert.
|
* and reset rdata for any actual WAL record insert.
|
||||||
*/
|
*/
|
||||||
rdata[0].buffer = buffer;
|
rdata[0].buffer = buffer;
|
||||||
rdata[0].buffer_std = true;
|
rdata[0].buffer_std = true;
|
||||||
@ -7861,10 +7868,10 @@ checkTimeLineSwitch(XLogRecPtr lsn, TimeLineID newTLI, TimeLineID prevTLI)
|
|||||||
ereport(PANIC,
|
ereport(PANIC,
|
||||||
(errmsg("unexpected prev timeline ID %u (current timeline ID %u) in checkpoint record",
|
(errmsg("unexpected prev timeline ID %u (current timeline ID %u) in checkpoint record",
|
||||||
prevTLI, ThisTimeLineID)));
|
prevTLI, ThisTimeLineID)));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The new timeline better be in the list of timelines we expect
|
* The new timeline better be in the list of timelines we expect to see,
|
||||||
* to see, according to the timeline history. It should also not
|
* according to the timeline history. It should also not decrease.
|
||||||
* decrease.
|
|
||||||
*/
|
*/
|
||||||
if (newTLI < ThisTimeLineID || !tliInHistory(newTLI, expectedTLEs))
|
if (newTLI < ThisTimeLineID || !tliInHistory(newTLI, expectedTLEs))
|
||||||
ereport(PANIC,
|
ereport(PANIC,
|
||||||
@ -7872,14 +7879,13 @@ checkTimeLineSwitch(XLogRecPtr lsn, TimeLineID newTLI, TimeLineID prevTLI)
|
|||||||
newTLI, ThisTimeLineID)));
|
newTLI, ThisTimeLineID)));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we have not yet reached min recovery point, and we're about
|
* If we have not yet reached min recovery point, and we're about to
|
||||||
* to switch to a timeline greater than the timeline of the min
|
* switch to a timeline greater than the timeline of the min recovery
|
||||||
* recovery point: trouble. After switching to the new timeline,
|
* point: trouble. After switching to the new timeline, we could not
|
||||||
* we could not possibly visit the min recovery point on the
|
* possibly visit the min recovery point on the correct timeline anymore.
|
||||||
* correct timeline anymore. This can happen if there is a newer
|
* This can happen if there is a newer timeline in the archive that
|
||||||
* timeline in the archive that branched before the timeline the
|
* branched before the timeline the min recovery point is on, and you
|
||||||
* min recovery point is on, and you attempt to do PITR to the
|
* attempt to do PITR to the new timeline.
|
||||||
* new timeline.
|
|
||||||
*/
|
*/
|
||||||
if (!XLogRecPtrIsInvalid(minRecoveryPoint) &&
|
if (!XLogRecPtrIsInvalid(minRecoveryPoint) &&
|
||||||
lsn < minRecoveryPoint &&
|
lsn < minRecoveryPoint &&
|
||||||
@ -8105,17 +8111,17 @@ xlog_redo(XLogRecPtr lsn, XLogRecord *record)
|
|||||||
BkpBlock bkpb;
|
BkpBlock bkpb;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Hint bit records contain a backup block stored "inline" in the normal
|
* Hint bit records contain a backup block stored "inline" in the
|
||||||
* data since the locking when writing hint records isn't sufficient to
|
* normal data since the locking when writing hint records isn't
|
||||||
* use the normal backup block mechanism, which assumes exclusive lock
|
* sufficient to use the normal backup block mechanism, which assumes
|
||||||
* on the buffer supplied.
|
* exclusive lock on the buffer supplied.
|
||||||
*
|
*
|
||||||
* Since the only change in these backup block are hint bits, there are
|
* Since the only change in these backup block are hint bits, there
|
||||||
* no recovery conflicts generated.
|
* are no recovery conflicts generated.
|
||||||
*
|
*
|
||||||
* This also means there is no corresponding API call for this,
|
* This also means there is no corresponding API call for this, so an
|
||||||
* so an smgr implementation has no need to implement anything.
|
* smgr implementation has no need to implement anything. Which means
|
||||||
* Which means nothing is needed in md.c etc
|
* nothing is needed in md.c etc
|
||||||
*/
|
*/
|
||||||
data = XLogRecGetData(record);
|
data = XLogRecGetData(record);
|
||||||
memcpy(&bkpb, data, sizeof(BkpBlock));
|
memcpy(&bkpb, data, sizeof(BkpBlock));
|
||||||
@ -8379,6 +8385,7 @@ char *
|
|||||||
XLogFileNameP(TimeLineID tli, XLogSegNo segno)
|
XLogFileNameP(TimeLineID tli, XLogSegNo segno)
|
||||||
{
|
{
|
||||||
char *result = palloc(MAXFNAMELEN);
|
char *result = palloc(MAXFNAMELEN);
|
||||||
|
|
||||||
XLogFileName(result, tli, segno);
|
XLogFileName(result, tli, segno);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -9571,11 +9578,12 @@ WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case XLOG_FROM_PG_XLOG:
|
case XLOG_FROM_PG_XLOG:
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check to see if the trigger file exists. Note that we do
|
* Check to see if the trigger file exists. Note that we
|
||||||
* this only after failure, so when you create the trigger
|
* do this only after failure, so when you create the
|
||||||
* file, we still finish replaying as much as we can from
|
* trigger file, we still finish replaying as much as we
|
||||||
* archive and pg_xlog before failover.
|
* can from archive and pg_xlog before failover.
|
||||||
*/
|
*/
|
||||||
if (StandbyMode && CheckForStandbyTrigger())
|
if (StandbyMode && CheckForStandbyTrigger())
|
||||||
{
|
{
|
||||||
@ -9584,15 +9592,15 @@ WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Not in standby mode, and we've now tried the archive and
|
* Not in standby mode, and we've now tried the archive
|
||||||
* pg_xlog.
|
* and pg_xlog.
|
||||||
*/
|
*/
|
||||||
if (!StandbyMode)
|
if (!StandbyMode)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If primary_conninfo is set, launch walreceiver to try to
|
* If primary_conninfo is set, launch walreceiver to try
|
||||||
* stream the missing WAL.
|
* to stream the missing WAL.
|
||||||
*
|
*
|
||||||
* If fetching_ckpt is TRUE, RecPtr points to the initial
|
* If fetching_ckpt is TRUE, RecPtr points to the initial
|
||||||
* checkpoint location. In that case, we use RedoStartLSN
|
* checkpoint location. In that case, we use RedoStartLSN
|
||||||
@ -9624,28 +9632,32 @@ WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess,
|
|||||||
RequestXLogStreaming(tli, ptr, PrimaryConnInfo);
|
RequestXLogStreaming(tli, ptr, PrimaryConnInfo);
|
||||||
receivedUpto = 0;
|
receivedUpto = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Move to XLOG_FROM_STREAM state in either case. We'll get
|
* Move to XLOG_FROM_STREAM state in either case. We'll
|
||||||
* immediate failure if we didn't launch walreceiver, and
|
* get immediate failure if we didn't launch walreceiver,
|
||||||
* move on to the next state.
|
* and move on to the next state.
|
||||||
*/
|
*/
|
||||||
currentSource = XLOG_FROM_STREAM;
|
currentSource = XLOG_FROM_STREAM;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case XLOG_FROM_STREAM:
|
case XLOG_FROM_STREAM:
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Failure while streaming. Most likely, we got here because
|
* Failure while streaming. Most likely, we got here
|
||||||
* streaming replication was terminated, or promotion was
|
* because streaming replication was terminated, or
|
||||||
* triggered. But we also get here if we find an invalid
|
* promotion was triggered. But we also get here if we
|
||||||
* record in the WAL streamed from master, in which case
|
* find an invalid record in the WAL streamed from master,
|
||||||
* something is seriously wrong. There's little chance that
|
* in which case something is seriously wrong. There's
|
||||||
* the problem will just go away, but PANIC is not good for
|
* little chance that the problem will just go away, but
|
||||||
* availability either, especially in hot standby mode. So,
|
* PANIC is not good for availability either, especially
|
||||||
* we treat that the same as disconnection, and retry from
|
* in hot standby mode. So, we treat that the same as
|
||||||
* archive/pg_xlog again. The WAL in the archive should be
|
* disconnection, and retry from archive/pg_xlog again.
|
||||||
* identical to what was streamed, so it's unlikely that it
|
* The WAL in the archive should be identical to what was
|
||||||
* helps, but one can hope...
|
* streamed, so it's unlikely that it helps, but one can
|
||||||
|
* hope...
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Before we leave XLOG_FROM_STREAM state, make sure that
|
* Before we leave XLOG_FROM_STREAM state, make sure that
|
||||||
* walreceiver is not active, so that it won't overwrite
|
* walreceiver is not active, so that it won't overwrite
|
||||||
@ -9668,11 +9680,12 @@ WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* XLOG_FROM_STREAM is the last state in our state machine,
|
* XLOG_FROM_STREAM is the last state in our state
|
||||||
* so we've exhausted all the options for obtaining the
|
* machine, so we've exhausted all the options for
|
||||||
* requested WAL. We're going to loop back and retry from
|
* obtaining the requested WAL. We're going to loop back
|
||||||
* the archive, but if it hasn't been long since last
|
* and retry from the archive, but if it hasn't been long
|
||||||
* attempt, sleep 5 seconds to avoid busy-waiting.
|
* since last attempt, sleep 5 seconds to avoid
|
||||||
|
* busy-waiting.
|
||||||
*/
|
*/
|
||||||
now = (pg_time_t) time(NULL);
|
now = (pg_time_t) time(NULL);
|
||||||
if ((now - last_fail_time) < 5)
|
if ((now - last_fail_time) < 5)
|
||||||
@ -9691,9 +9704,9 @@ WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess,
|
|||||||
else if (currentSource == XLOG_FROM_PG_XLOG)
|
else if (currentSource == XLOG_FROM_PG_XLOG)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* We just successfully read a file in pg_xlog. We prefer files
|
* We just successfully read a file in pg_xlog. We prefer files in
|
||||||
* in the archive over ones in pg_xlog, so try the next file
|
* the archive over ones in pg_xlog, so try the next file again
|
||||||
* again from the archive first.
|
* from the archive first.
|
||||||
*/
|
*/
|
||||||
if (InArchiveRecovery)
|
if (InArchiveRecovery)
|
||||||
currentSource = XLOG_FROM_ARCHIVE;
|
currentSource = XLOG_FROM_ARCHIVE;
|
||||||
@ -9754,13 +9767,14 @@ WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess,
|
|||||||
/*
|
/*
|
||||||
* Walreceiver is active, so see if new data has arrived.
|
* Walreceiver is active, so see if new data has arrived.
|
||||||
*
|
*
|
||||||
* We only advance XLogReceiptTime when we obtain fresh WAL
|
* We only advance XLogReceiptTime when we obtain fresh
|
||||||
* from walreceiver and observe that we had already processed
|
* WAL from walreceiver and observe that we had already
|
||||||
* everything before the most recent "chunk" that it flushed to
|
* processed everything before the most recent "chunk"
|
||||||
* disk. In steady state where we are keeping up with the
|
* that it flushed to disk. In steady state where we are
|
||||||
* incoming data, XLogReceiptTime will be updated on each cycle.
|
* keeping up with the incoming data, XLogReceiptTime will
|
||||||
* When we are behind, XLogReceiptTime will not advance, so the
|
* be updated on each cycle. When we are behind,
|
||||||
* grace time allotted to conflicting queries will decrease.
|
* XLogReceiptTime will not advance, so the grace time
|
||||||
|
* allotted to conflicting queries will decrease.
|
||||||
*/
|
*/
|
||||||
if (RecPtr < receivedUpto)
|
if (RecPtr < receivedUpto)
|
||||||
havedata = true;
|
havedata = true;
|
||||||
@ -9784,12 +9798,13 @@ WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess,
|
|||||||
if (havedata)
|
if (havedata)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Great, streamed far enough. Open the file if it's not
|
* Great, streamed far enough. Open the file if it's
|
||||||
* open already. Also read the timeline history file if
|
* not open already. Also read the timeline history
|
||||||
* we haven't initialized timeline history yet; it should
|
* file if we haven't initialized timeline history
|
||||||
* be streamed over and present in pg_xlog by now. Use
|
* yet; it should be streamed over and present in
|
||||||
* XLOG_FROM_STREAM so that source info is set correctly
|
* pg_xlog by now. Use XLOG_FROM_STREAM so that
|
||||||
* and XLogReceiptTime isn't changed.
|
* source info is set correctly and XLogReceiptTime
|
||||||
|
* isn't changed.
|
||||||
*/
|
*/
|
||||||
if (readFile < 0)
|
if (readFile < 0)
|
||||||
{
|
{
|
||||||
@ -9818,20 +9833,21 @@ WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess,
|
|||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Note that we don't "return false" immediately here.
|
* Note that we don't "return false" immediately here.
|
||||||
* After being triggered, we still want to replay all the
|
* After being triggered, we still want to replay all
|
||||||
* WAL that was already streamed. It's in pg_xlog now, so
|
* the WAL that was already streamed. It's in pg_xlog
|
||||||
* we just treat this as a failure, and the state machine
|
* now, so we just treat this as a failure, and the
|
||||||
* will move on to replay the streamed WAL from pg_xlog,
|
* state machine will move on to replay the streamed
|
||||||
* and then recheck the trigger and exit replay.
|
* WAL from pg_xlog, and then recheck the trigger and
|
||||||
|
* exit replay.
|
||||||
*/
|
*/
|
||||||
lastSourceFailed = true;
|
lastSourceFailed = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Wait for more WAL to arrive. Time out after 5 seconds, like
|
* Wait for more WAL to arrive. Time out after 5 seconds,
|
||||||
* when polling the archive, to react to a trigger file
|
* like when polling the archive, to react to a trigger
|
||||||
* promptly.
|
* file promptly.
|
||||||
*/
|
*/
|
||||||
WaitLatch(&XLogCtl->recoveryWakeupLatch,
|
WaitLatch(&XLogCtl->recoveryWakeupLatch,
|
||||||
WL_LATCH_SET | WL_TIMEOUT,
|
WL_LATCH_SET | WL_TIMEOUT,
|
||||||
@ -9903,11 +9919,10 @@ CheckForStandbyTrigger(void)
|
|||||||
if (IsPromoteTriggered())
|
if (IsPromoteTriggered())
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* In 9.1 and 9.2 the postmaster unlinked the promote file
|
* In 9.1 and 9.2 the postmaster unlinked the promote file inside the
|
||||||
* inside the signal handler. We now leave the file in place
|
* signal handler. We now leave the file in place and let the Startup
|
||||||
* and let the Startup process do the unlink. This allows
|
* process do the unlink. This allows Startup to know whether we're
|
||||||
* Startup to know whether we're doing fast or normal
|
* doing fast or normal promotion. Fast promotion takes precedence.
|
||||||
* promotion. Fast promotion takes precedence.
|
|
||||||
*/
|
*/
|
||||||
if (stat(FAST_PROMOTE_SIGNAL_FILE, &stat_buf) == 0)
|
if (stat(FAST_PROMOTE_SIGNAL_FILE, &stat_buf) == 0)
|
||||||
{
|
{
|
||||||
|
@ -87,9 +87,9 @@ RestoreArchivedFile(char *path, const char *xlogfname,
|
|||||||
* of log segments that weren't yet transferred to the archive.
|
* of log segments that weren't yet transferred to the archive.
|
||||||
*
|
*
|
||||||
* Notice that we don't actually overwrite any files when we copy back
|
* Notice that we don't actually overwrite any files when we copy back
|
||||||
* from archive because the restore_command may inadvertently
|
* from archive because the restore_command may inadvertently restore
|
||||||
* restore inappropriate xlogs, or they may be corrupt, so we may wish to
|
* inappropriate xlogs, or they may be corrupt, so we may wish to fallback
|
||||||
* fallback to the segments remaining in current XLOGDIR later. The
|
* to the segments remaining in current XLOGDIR later. The
|
||||||
* copy-from-archive filename is always the same, ensuring that we don't
|
* copy-from-archive filename is always the same, ensuring that we don't
|
||||||
* run out of disk space on long recoveries.
|
* run out of disk space on long recoveries.
|
||||||
*/
|
*/
|
||||||
@ -434,18 +434,19 @@ KeepFileRestoredFromArchive(char *path, char *xlogfname)
|
|||||||
if (stat(xlogfpath, &statbuf) == 0)
|
if (stat(xlogfpath, &statbuf) == 0)
|
||||||
{
|
{
|
||||||
char oldpath[MAXPGPATH];
|
char oldpath[MAXPGPATH];
|
||||||
|
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
static unsigned int deletedcounter = 1;
|
static unsigned int deletedcounter = 1;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* On Windows, if another process (e.g a walsender process) holds
|
* On Windows, if another process (e.g a walsender process) holds the
|
||||||
* the file open in FILE_SHARE_DELETE mode, unlink will succeed,
|
* file open in FILE_SHARE_DELETE mode, unlink will succeed, but the
|
||||||
* but the file will still show up in directory listing until the
|
* file will still show up in directory listing until the last handle
|
||||||
* last handle is closed, and we cannot rename the new file in its
|
* is closed, and we cannot rename the new file in its place until
|
||||||
* place until that. To avoid that problem, rename the old file to
|
* that. To avoid that problem, rename the old file to a temporary
|
||||||
* a temporary name first. Use a counter to create a unique
|
* name first. Use a counter to create a unique filename, because the
|
||||||
* filename, because the same file might be restored from the
|
* same file might be restored from the archive multiple times, and a
|
||||||
* archive multiple times, and a walsender could still be holding
|
* walsender could still be holding onto an old deleted version of it.
|
||||||
* onto an old deleted version of it.
|
|
||||||
*/
|
*/
|
||||||
snprintf(oldpath, MAXPGPATH, "%s.deleted%u",
|
snprintf(oldpath, MAXPGPATH, "%s.deleted%u",
|
||||||
xlogfpath, deletedcounter++);
|
xlogfpath, deletedcounter++);
|
||||||
@ -474,17 +475,17 @@ KeepFileRestoredFromArchive(char *path, char *xlogfname)
|
|||||||
path, xlogfpath)));
|
path, xlogfpath)));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create .done file forcibly to prevent the restored segment from
|
* Create .done file forcibly to prevent the restored segment from being
|
||||||
* being archived again later.
|
* archived again later.
|
||||||
*/
|
*/
|
||||||
XLogArchiveForceDone(xlogfname);
|
XLogArchiveForceDone(xlogfname);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the existing file was replaced, since walsenders might have it
|
* If the existing file was replaced, since walsenders might have it open,
|
||||||
* open, request them to reload a currently-open segment. This is only
|
* request them to reload a currently-open segment. This is only required
|
||||||
* required for WAL segments, walsenders don't hold other files open, but
|
* for WAL segments, walsenders don't hold other files open, but there's
|
||||||
* there's no harm in doing this too often, and we don't know what kind
|
* no harm in doing this too often, and we don't know what kind of a file
|
||||||
* of a file we're dealing with here.
|
* we're dealing with here.
|
||||||
*/
|
*/
|
||||||
if (reload)
|
if (reload)
|
||||||
WalSndRqstFileReload();
|
WalSndRqstFileReload();
|
||||||
|
@ -221,9 +221,9 @@ XLogReadRecord(XLogReaderState *state, XLogRecPtr RecPtr, char **errormsg)
|
|||||||
targetRecOff = RecPtr % XLOG_BLCKSZ;
|
targetRecOff = RecPtr % XLOG_BLCKSZ;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Read the page containing the record into state->readBuf. Request
|
* Read the page containing the record into state->readBuf. Request enough
|
||||||
* enough byte to cover the whole record header, or at least the part of
|
* byte to cover the whole record header, or at least the part of it that
|
||||||
* it that fits on the same page.
|
* fits on the same page.
|
||||||
*/
|
*/
|
||||||
readOff = ReadPageInternal(state,
|
readOff = ReadPageInternal(state,
|
||||||
targetPagePtr,
|
targetPagePtr,
|
||||||
|
@ -870,6 +870,7 @@ AddNewRelationTuple(Relation pg_class_desc,
|
|||||||
* that will do.
|
* that will do.
|
||||||
*/
|
*/
|
||||||
new_rel_reltup->relfrozenxid = RecentXmin;
|
new_rel_reltup->relfrozenxid = RecentXmin;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Similarly, initialize the minimum Multixact to the first value that
|
* Similarly, initialize the minimum Multixact to the first value that
|
||||||
* could possibly be stored in tuples in the table. Running
|
* could possibly be stored in tuples in the table. Running
|
||||||
@ -1915,10 +1916,10 @@ StoreAttrDefault(Relation rel, AttrNumber attnum,
|
|||||||
/*
|
/*
|
||||||
* Post creation hook for attribute defaults.
|
* Post creation hook for attribute defaults.
|
||||||
*
|
*
|
||||||
* XXX. ALTER TABLE ALTER COLUMN SET/DROP DEFAULT is implemented
|
* XXX. ALTER TABLE ALTER COLUMN SET/DROP DEFAULT is implemented with a
|
||||||
* with a couple of deletion/creation of the attribute's default entry,
|
* couple of deletion/creation of the attribute's default entry, so the
|
||||||
* so the callee should check existence of an older version of this
|
* callee should check existence of an older version of this entry if it
|
||||||
* entry if it needs to distinguish.
|
* needs to distinguish.
|
||||||
*/
|
*/
|
||||||
InvokeObjectPostCreateHookArg(AttrDefaultRelationId,
|
InvokeObjectPostCreateHookArg(AttrDefaultRelationId,
|
||||||
RelationGetRelid(rel), attnum, is_internal);
|
RelationGetRelid(rel), attnum, is_internal);
|
||||||
|
@ -293,6 +293,7 @@ RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode,
|
|||||||
Oid namespaceId;
|
Oid namespaceId;
|
||||||
|
|
||||||
namespaceId = LookupExplicitNamespace(relation->schemaname, missing_ok);
|
namespaceId = LookupExplicitNamespace(relation->schemaname, missing_ok);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* For missing_ok, allow a non-existant schema name to
|
* For missing_ok, allow a non-existant schema name to
|
||||||
* return InvalidOid.
|
* return InvalidOid.
|
||||||
|
@ -94,10 +94,11 @@ typedef struct
|
|||||||
AttrNumber attnum_owner; /* attnum of owner field */
|
AttrNumber attnum_owner; /* attnum of owner field */
|
||||||
AttrNumber attnum_acl; /* attnum of acl field */
|
AttrNumber attnum_acl; /* attnum of acl field */
|
||||||
AclObjectKind acl_kind; /* ACL_KIND_* of this object type */
|
AclObjectKind acl_kind; /* ACL_KIND_* of this object type */
|
||||||
bool is_nsp_name_unique; /* can the nsp/name combination (or name
|
bool is_nsp_name_unique; /* can the nsp/name combination (or
|
||||||
* alone, if there's no namespace) be
|
* name alone, if there's no
|
||||||
* considered an unique identifier for an
|
* namespace) be considered an unique
|
||||||
* object of this class? */
|
* identifier for an object of this
|
||||||
|
* class? */
|
||||||
} ObjectPropertyType;
|
} ObjectPropertyType;
|
||||||
|
|
||||||
static ObjectPropertyType ObjectProperty[] =
|
static ObjectPropertyType ObjectProperty[] =
|
||||||
@ -2359,8 +2360,8 @@ pg_identify_object(PG_FUNCTION_ARGS)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We only return the object name if it can be used (together
|
* We only return the object name if it can be used (together with
|
||||||
* with the schema name, if any) as an unique identifier.
|
* the schema name, if any) as an unique identifier.
|
||||||
*/
|
*/
|
||||||
if (get_object_namensp_unique(address.classId))
|
if (get_object_namensp_unique(address.classId))
|
||||||
{
|
{
|
||||||
|
@ -92,11 +92,11 @@ validOperatorName(const char *name)
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* For SQL standard compatibility, '+' and '-' cannot be the last char of a
|
* For SQL standard compatibility, '+' and '-' cannot be the last char of
|
||||||
* multi-char operator unless the operator contains chars that are not in
|
* a multi-char operator unless the operator contains chars that are not
|
||||||
* SQL operators. The idea is to lex '=-' as two operators, but not to
|
* in SQL operators. The idea is to lex '=-' as two operators, but not to
|
||||||
* forbid operator names like '?-' that could not be sequences of standard SQL
|
* forbid operator names like '?-' that could not be sequences of standard
|
||||||
* operators.
|
* SQL operators.
|
||||||
*/
|
*/
|
||||||
if (len > 1 &&
|
if (len > 1 &&
|
||||||
(name[len - 1] == '+' ||
|
(name[len - 1] == '+' ||
|
||||||
|
@ -505,13 +505,12 @@ smgr_redo(XLogRecPtr lsn, XLogRecord *record)
|
|||||||
smgrcreate(reln, MAIN_FORKNUM, true);
|
smgrcreate(reln, MAIN_FORKNUM, true);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Before we perform the truncation, update minimum recovery point
|
* Before we perform the truncation, update minimum recovery point to
|
||||||
* to cover this WAL record. Once the relation is truncated, there's
|
* cover this WAL record. Once the relation is truncated, there's no
|
||||||
* no going back. The buffer manager enforces the WAL-first rule
|
* going back. The buffer manager enforces the WAL-first rule for
|
||||||
* for normal updates to relation files, so that the minimum recovery
|
* normal updates to relation files, so that the minimum recovery
|
||||||
* point is always updated before the corresponding change in the
|
* point is always updated before the corresponding change in the data
|
||||||
* data file is flushed to disk. We have to do the same manually
|
* file is flushed to disk. We have to do the same manually here.
|
||||||
* here.
|
|
||||||
*
|
*
|
||||||
* Doing this before the truncation means that if the truncation fails
|
* Doing this before the truncation means that if the truncation fails
|
||||||
* for some reason, you cannot start up the system even after restart,
|
* for some reason, you cannot start up the system even after restart,
|
||||||
|
@ -501,9 +501,9 @@ CopySendEndOfRow(CopyState cstate)
|
|||||||
ClosePipeToProgram(cstate);
|
ClosePipeToProgram(cstate);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If ClosePipeToProgram() didn't throw an error,
|
* If ClosePipeToProgram() didn't throw an error, the
|
||||||
* the program terminated normally, but closed the
|
* program terminated normally, but closed the pipe
|
||||||
* pipe first. Restore errno, and throw an error.
|
* first. Restore errno, and throw an error.
|
||||||
*/
|
*/
|
||||||
errno = EPIPE;
|
errno = EPIPE;
|
||||||
}
|
}
|
||||||
@ -1022,9 +1022,9 @@ ProcessCopyOptions(CopyState cstate,
|
|||||||
else if (strcmp(defel->defname, "convert_selectively") == 0)
|
else if (strcmp(defel->defname, "convert_selectively") == 0)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Undocumented, not-accessible-from-SQL option: convert only
|
* Undocumented, not-accessible-from-SQL option: convert only the
|
||||||
* the named columns to binary form, storing the rest as NULLs.
|
* named columns to binary form, storing the rest as NULLs. It's
|
||||||
* It's allowed for the column list to be NIL.
|
* allowed for the column list to be NIL.
|
||||||
*/
|
*/
|
||||||
if (cstate->convert_selectively)
|
if (cstate->convert_selectively)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
@ -1929,8 +1929,8 @@ CopyFromErrorCallback(void *arg)
|
|||||||
* Error is relevant to a particular line.
|
* Error is relevant to a particular line.
|
||||||
*
|
*
|
||||||
* If line_buf still contains the correct line, and it's already
|
* If line_buf still contains the correct line, and it's already
|
||||||
* transcoded, print it. If it's still in a foreign encoding,
|
* transcoded, print it. If it's still in a foreign encoding, it's
|
||||||
* it's quite likely that the error is precisely a failure to do
|
* quite likely that the error is precisely a failure to do
|
||||||
* encoding conversion (ie, bad data). We dare not try to convert
|
* encoding conversion (ie, bad data). We dare not try to convert
|
||||||
* it, and at present there's no way to regurgitate it without
|
* it, and at present there's no way to regurgitate it without
|
||||||
* conversion. So we have to punt and just report the line number.
|
* conversion. So we have to punt and just report the line number.
|
||||||
@ -2096,13 +2096,12 @@ CopyFrom(CopyState cstate)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Optimize if new relfilenode was created in this subxact or
|
* Optimize if new relfilenode was created in this subxact or one of its
|
||||||
* one of its committed children and we won't see those rows later
|
* committed children and we won't see those rows later as part of an
|
||||||
* as part of an earlier scan or command. This ensures that if this
|
* earlier scan or command. This ensures that if this subtransaction
|
||||||
* subtransaction aborts then the frozen rows won't be visible
|
* aborts then the frozen rows won't be visible after xact cleanup. Note
|
||||||
* after xact cleanup. Note that the stronger test of exactly
|
* that the stronger test of exactly which subtransaction created it is
|
||||||
* which subtransaction created it is crucial for correctness
|
* crucial for correctness of this optimisation.
|
||||||
* of this optimisation.
|
|
||||||
*/
|
*/
|
||||||
if (cstate->freeze)
|
if (cstate->freeze)
|
||||||
{
|
{
|
||||||
|
@ -1882,8 +1882,11 @@ static int
|
|||||||
errdetail_busy_db(int notherbackends, int npreparedxacts)
|
errdetail_busy_db(int notherbackends, int npreparedxacts)
|
||||||
{
|
{
|
||||||
if (notherbackends > 0 && npreparedxacts > 0)
|
if (notherbackends > 0 && npreparedxacts > 0)
|
||||||
/* We don't deal with singular versus plural here, since gettext
|
|
||||||
* doesn't support multiple plurals in one string. */
|
/*
|
||||||
|
* We don't deal with singular versus plural here, since gettext
|
||||||
|
* doesn't support multiple plurals in one string.
|
||||||
|
*/
|
||||||
errdetail("There are %d other session(s) and %d prepared transaction(s) using the database.",
|
errdetail("There are %d other session(s) and %d prepared transaction(s) using the database.",
|
||||||
notherbackends, npreparedxacts);
|
notherbackends, npreparedxacts);
|
||||||
else if (notherbackends > 0)
|
else if (notherbackends > 0)
|
||||||
|
@ -302,7 +302,8 @@ insert_event_trigger_tuple(char *trigname, char *eventname, Oid evtOwner,
|
|||||||
HeapTuple tuple;
|
HeapTuple tuple;
|
||||||
Datum values[Natts_pg_trigger];
|
Datum values[Natts_pg_trigger];
|
||||||
bool nulls[Natts_pg_trigger];
|
bool nulls[Natts_pg_trigger];
|
||||||
ObjectAddress myself, referenced;
|
ObjectAddress myself,
|
||||||
|
referenced;
|
||||||
|
|
||||||
/* Open pg_event_trigger. */
|
/* Open pg_event_trigger. */
|
||||||
tgrel = heap_open(EventTriggerRelationId, RowExclusiveLock);
|
tgrel = heap_open(EventTriggerRelationId, RowExclusiveLock);
|
||||||
@ -646,11 +647,11 @@ EventTriggerCommonSetup(Node *parsetree,
|
|||||||
tag = CreateCommandTag(parsetree);
|
tag = CreateCommandTag(parsetree);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Filter list of event triggers by command tag, and copy them into
|
* Filter list of event triggers by command tag, and copy them into our
|
||||||
* our memory context. Once we start running the command trigers, or
|
* memory context. Once we start running the command trigers, or indeed
|
||||||
* indeed once we do anything at all that touches the catalogs, an
|
* once we do anything at all that touches the catalogs, an invalidation
|
||||||
* invalidation might leave cachelist pointing at garbage, so we must
|
* might leave cachelist pointing at garbage, so we must do this before we
|
||||||
* do this before we can do much else.
|
* can do much else.
|
||||||
*/
|
*/
|
||||||
foreach(lc, cachelist)
|
foreach(lc, cachelist)
|
||||||
{
|
{
|
||||||
@ -716,8 +717,8 @@ EventTriggerDDLCommandStart(Node *parsetree)
|
|||||||
list_free(runlist);
|
list_free(runlist);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Make sure anything the event triggers did will be visible to
|
* Make sure anything the event triggers did will be visible to the main
|
||||||
* the main command.
|
* command.
|
||||||
*/
|
*/
|
||||||
CommandCounterIncrement();
|
CommandCounterIncrement();
|
||||||
}
|
}
|
||||||
@ -745,8 +746,8 @@ EventTriggerDDLCommandEnd(Node *parsetree)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Make sure anything the main command did will be visible to the
|
* Make sure anything the main command did will be visible to the event
|
||||||
* event triggers.
|
* triggers.
|
||||||
*/
|
*/
|
||||||
CommandCounterIncrement();
|
CommandCounterIncrement();
|
||||||
|
|
||||||
@ -774,10 +775,11 @@ EventTriggerSQLDrop(Node *parsetree)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Use current state to determine whether this event fires at all. If there
|
* Use current state to determine whether this event fires at all. If
|
||||||
* are no triggers for the sql_drop event, then we don't have anything to do
|
* there are no triggers for the sql_drop event, then we don't have
|
||||||
* here. Note that dropped object collection is disabled if this is the case,
|
* anything to do here. Note that dropped object collection is disabled
|
||||||
* so even if we were to try to run, the list would be empty.
|
* if this is the case, so even if we were to try to run, the list would
|
||||||
|
* be empty.
|
||||||
*/
|
*/
|
||||||
if (!currentEventTriggerState ||
|
if (!currentEventTriggerState ||
|
||||||
slist_is_empty(¤tEventTriggerState->SQLDropList))
|
slist_is_empty(¤tEventTriggerState->SQLDropList))
|
||||||
@ -786,24 +788,25 @@ EventTriggerSQLDrop(Node *parsetree)
|
|||||||
runlist = EventTriggerCommonSetup(parsetree,
|
runlist = EventTriggerCommonSetup(parsetree,
|
||||||
EVT_SQLDrop, "sql_drop",
|
EVT_SQLDrop, "sql_drop",
|
||||||
&trigdata);
|
&trigdata);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Nothing to do if run list is empty. Note this shouldn't happen, because
|
* Nothing to do if run list is empty. Note this shouldn't happen,
|
||||||
* if there are no sql_drop events, then objects-to-drop wouldn't have been
|
* because if there are no sql_drop events, then objects-to-drop wouldn't
|
||||||
* collected in the first place and we would have quitted above.
|
* have been collected in the first place and we would have quitted above.
|
||||||
*/
|
*/
|
||||||
if (runlist == NIL)
|
if (runlist == NIL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Make sure anything the main command did will be visible to the
|
* Make sure anything the main command did will be visible to the event
|
||||||
* event triggers.
|
* triggers.
|
||||||
*/
|
*/
|
||||||
CommandCounterIncrement();
|
CommandCounterIncrement();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Make sure pg_event_trigger_dropped_objects only works when running these
|
* Make sure pg_event_trigger_dropped_objects only works when running
|
||||||
* triggers. Use PG_TRY to ensure in_sql_drop is reset even when one
|
* these triggers. Use PG_TRY to ensure in_sql_drop is reset even when
|
||||||
* trigger fails. (This is perhaps not necessary, as the currentState
|
* one trigger fails. (This is perhaps not necessary, as the currentState
|
||||||
* variable will be removed shortly by our caller, but it seems better to
|
* variable will be removed shortly by our caller, but it seems better to
|
||||||
* play safe.)
|
* play safe.)
|
||||||
*/
|
*/
|
||||||
@ -841,8 +844,8 @@ EventTriggerInvoke(List *fn_oid_list, EventTriggerData *trigdata)
|
|||||||
check_stack_depth();
|
check_stack_depth();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Let's evaluate event triggers in their own memory context, so
|
* Let's evaluate event triggers in their own memory context, so that any
|
||||||
* that any leaks get cleaned up promptly.
|
* leaks get cleaned up promptly.
|
||||||
*/
|
*/
|
||||||
context = AllocSetContextCreate(CurrentMemoryContext,
|
context = AllocSetContextCreate(CurrentMemoryContext,
|
||||||
"event trigger context",
|
"event trigger context",
|
||||||
@ -860,10 +863,10 @@ EventTriggerInvoke(List *fn_oid_list, EventTriggerData *trigdata)
|
|||||||
PgStat_FunctionCallUsage fcusage;
|
PgStat_FunctionCallUsage fcusage;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We want each event trigger to be able to see the results of
|
* We want each event trigger to be able to see the results of the
|
||||||
* the previous event trigger's action. Caller is responsible
|
* previous event trigger's action. Caller is responsible for any
|
||||||
* for any command-counter increment that is needed between the
|
* command-counter increment that is needed between the event trigger
|
||||||
* event trigger and anything else in the transaction.
|
* and anything else in the transaction.
|
||||||
*/
|
*/
|
||||||
if (first)
|
if (first)
|
||||||
first = false;
|
first = false;
|
||||||
@ -987,6 +990,7 @@ EventTriggerSupportsObjectClass(ObjectClass objclass)
|
|||||||
return true;
|
return true;
|
||||||
|
|
||||||
case MAX_OCLASS:
|
case MAX_OCLASS:
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This shouldn't ever happen, but we keep the case to avoid a
|
* This shouldn't ever happen, but we keep the case to avoid a
|
||||||
* compiler warning without a "default" clause in the switch.
|
* compiler warning without a "default" clause in the switch.
|
||||||
@ -1112,8 +1116,9 @@ EventTriggerSQLDropAddObject(ObjectAddress *object)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Obtain schema names from the object's catalog tuple, if one exists;
|
* Obtain schema names from the object's catalog tuple, if one exists;
|
||||||
* this lets us skip objects in temp schemas. We trust that ObjectProperty
|
* this lets us skip objects in temp schemas. We trust that
|
||||||
* contains all object classes that can be schema-qualified.
|
* ObjectProperty contains all object classes that can be
|
||||||
|
* schema-qualified.
|
||||||
*/
|
*/
|
||||||
if (is_objectclass_supported(object->classId))
|
if (is_objectclass_supported(object->classId))
|
||||||
{
|
{
|
||||||
|
@ -415,8 +415,8 @@ ExplainOnePlan(PlannedStmt *plannedstmt, IntoClause *into, ExplainState *es,
|
|||||||
instrument_option |= INSTRUMENT_BUFFERS;
|
instrument_option |= INSTRUMENT_BUFFERS;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We always collect timing for the entire statement, even when
|
* We always collect timing for the entire statement, even when node-level
|
||||||
* node-level timing is off, so we don't look at es->timing here.
|
* timing is off, so we don't look at es->timing here.
|
||||||
*/
|
*/
|
||||||
INSTR_TIME_SET_CURRENT(starttime);
|
INSTR_TIME_SET_CURRENT(starttime);
|
||||||
|
|
||||||
|
@ -698,8 +698,8 @@ nextval_internal(Oid relid)
|
|||||||
/*
|
/*
|
||||||
* We must mark the buffer dirty before doing XLogInsert(); see notes in
|
* We must mark the buffer dirty before doing XLogInsert(); see notes in
|
||||||
* SyncOneBuffer(). However, we don't apply the desired changes just yet.
|
* SyncOneBuffer(). However, we don't apply the desired changes just yet.
|
||||||
* This looks like a violation of the buffer update protocol, but it is
|
* This looks like a violation of the buffer update protocol, but it is in
|
||||||
* in fact safe because we hold exclusive lock on the buffer. Any other
|
* fact safe because we hold exclusive lock on the buffer. Any other
|
||||||
* process, including a checkpoint, that tries to examine the buffer
|
* process, including a checkpoint, that tries to examine the buffer
|
||||||
* contents will block until we release the lock, and then will see the
|
* contents will block until we release the lock, and then will see the
|
||||||
* final state that we install below.
|
* final state that we install below.
|
||||||
@ -1226,8 +1226,8 @@ init_params(List *options, bool isInit,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We must reset log_cnt when isInit or when changing any parameters
|
* We must reset log_cnt when isInit or when changing any parameters that
|
||||||
* that would affect future nextval allocations.
|
* would affect future nextval allocations.
|
||||||
*/
|
*/
|
||||||
if (isInit)
|
if (isInit)
|
||||||
new->log_cnt = 0;
|
new->log_cnt = 0;
|
||||||
|
@ -1675,9 +1675,9 @@ MergeAttributes(List *schema, List *supers, char relpersistence,
|
|||||||
&found_whole_row);
|
&found_whole_row);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* For the moment we have to reject whole-row variables.
|
* For the moment we have to reject whole-row variables. We
|
||||||
* We could convert them, if we knew the new table's rowtype
|
* could convert them, if we knew the new table's rowtype OID,
|
||||||
* OID, but that hasn't been assigned yet.
|
* but that hasn't been assigned yet.
|
||||||
*/
|
*/
|
||||||
if (found_whole_row)
|
if (found_whole_row)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
@ -3294,7 +3294,8 @@ ATExecCmd(List **wqueue, AlteredTableInfo *tab, Relation rel,
|
|||||||
ATExecAddConstraint(wqueue, tab, rel, (Constraint *) cmd->def,
|
ATExecAddConstraint(wqueue, tab, rel, (Constraint *) cmd->def,
|
||||||
true, false, lockmode);
|
true, false, lockmode);
|
||||||
break;
|
break;
|
||||||
case AT_ReAddConstraint: /* Re-add pre-existing check constraint */
|
case AT_ReAddConstraint: /* Re-add pre-existing check
|
||||||
|
* constraint */
|
||||||
ATExecAddConstraint(wqueue, tab, rel, (Constraint *) cmd->def,
|
ATExecAddConstraint(wqueue, tab, rel, (Constraint *) cmd->def,
|
||||||
false, true, lockmode);
|
false, true, lockmode);
|
||||||
break;
|
break;
|
||||||
@ -9564,9 +9565,9 @@ ATExecDropInherit(Relation rel, RangeVar *parent, LOCKMODE lockmode)
|
|||||||
RelationGetRelid(parent_rel));
|
RelationGetRelid(parent_rel));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Post alter hook of this inherits. Since object_access_hook doesn't
|
* Post alter hook of this inherits. Since object_access_hook doesn't take
|
||||||
* take multiple object identifiers, we relay oid of parent relation
|
* multiple object identifiers, we relay oid of parent relation using
|
||||||
* using auxiliary_id argument.
|
* auxiliary_id argument.
|
||||||
*/
|
*/
|
||||||
InvokeObjectPostAlterHookArg(InheritsRelationId,
|
InvokeObjectPostAlterHookArg(InheritsRelationId,
|
||||||
RelationGetRelid(rel), 0,
|
RelationGetRelid(rel), 0,
|
||||||
@ -10247,6 +10248,7 @@ PreCommit_on_commit_actions(void)
|
|||||||
/* Do nothing (there shouldn't be such entries, actually) */
|
/* Do nothing (there shouldn't be such entries, actually) */
|
||||||
break;
|
break;
|
||||||
case ONCOMMIT_DELETE_ROWS:
|
case ONCOMMIT_DELETE_ROWS:
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If this transaction hasn't accessed any temporary
|
* If this transaction hasn't accessed any temporary
|
||||||
* relations, we can skip truncating ON COMMIT DELETE ROWS
|
* relations, we can skip truncating ON COMMIT DELETE ROWS
|
||||||
|
@ -1266,6 +1266,7 @@ renametrig(RenameStmt *stmt)
|
|||||||
if (HeapTupleIsValid(tuple = systable_getnext(tgscan)))
|
if (HeapTupleIsValid(tuple = systable_getnext(tgscan)))
|
||||||
{
|
{
|
||||||
tgoid = HeapTupleGetOid(tuple);
|
tgoid = HeapTupleGetOid(tuple);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Update pg_trigger tuple with new tgname.
|
* Update pg_trigger tuple with new tgname.
|
||||||
*/
|
*/
|
||||||
@ -2619,6 +2620,7 @@ ltrmark:;
|
|||||||
switch (test)
|
switch (test)
|
||||||
{
|
{
|
||||||
case HeapTupleSelfUpdated:
|
case HeapTupleSelfUpdated:
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The target tuple was already updated or deleted by the
|
* The target tuple was already updated or deleted by the
|
||||||
* current command, or by a later command in the current
|
* current command, or by a later command in the current
|
||||||
|
@ -924,8 +924,8 @@ DefineDomain(CreateDomainStmt *stmt)
|
|||||||
/*
|
/*
|
||||||
* Check constraints are handled after domain creation, as
|
* Check constraints are handled after domain creation, as
|
||||||
* they require the Oid of the domain; at this point we can
|
* they require the Oid of the domain; at this point we can
|
||||||
* only check that they're not marked NO INHERIT, because
|
* only check that they're not marked NO INHERIT, because that
|
||||||
* that would be bogus.
|
* would be bogus.
|
||||||
*/
|
*/
|
||||||
if (constr->is_no_inherit)
|
if (constr->is_no_inherit)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
@ -1192,14 +1192,14 @@ AlterEnum(AlterEnumStmt *stmt, bool isTopLevel)
|
|||||||
* Ordinarily we disallow adding values within transaction blocks, because
|
* Ordinarily we disallow adding values within transaction blocks, because
|
||||||
* we can't cope with enum OID values getting into indexes and then having
|
* we can't cope with enum OID values getting into indexes and then having
|
||||||
* their defining pg_enum entries go away. However, it's okay if the enum
|
* their defining pg_enum entries go away. However, it's okay if the enum
|
||||||
* type was created in the current transaction, since then there can be
|
* type was created in the current transaction, since then there can be no
|
||||||
* no such indexes that wouldn't themselves go away on rollback. (We
|
* such indexes that wouldn't themselves go away on rollback. (We support
|
||||||
* support this case because pg_dump --binary-upgrade needs it.) We test
|
* this case because pg_dump --binary-upgrade needs it.) We test this by
|
||||||
* this by seeing if the pg_type row has xmin == current XID and is not
|
* seeing if the pg_type row has xmin == current XID and is not
|
||||||
* HEAP_UPDATED. If it is HEAP_UPDATED, we can't be sure whether the
|
* HEAP_UPDATED. If it is HEAP_UPDATED, we can't be sure whether the type
|
||||||
* type was created or only modified in this xact. So we are disallowing
|
* was created or only modified in this xact. So we are disallowing some
|
||||||
* some cases that could theoretically be safe; but fortunately pg_dump
|
* cases that could theoretically be safe; but fortunately pg_dump only
|
||||||
* only needs the simplest case.
|
* needs the simplest case.
|
||||||
*/
|
*/
|
||||||
if (HeapTupleHeaderGetXmin(tup->t_data) == GetCurrentTransactionId() &&
|
if (HeapTupleHeaderGetXmin(tup->t_data) == GetCurrentTransactionId() &&
|
||||||
!(tup->t_data->t_infomask & HEAP_UPDATED))
|
!(tup->t_data->t_infomask & HEAP_UPDATED))
|
||||||
|
@ -327,10 +327,10 @@ get_rel_oids(Oid relid, const RangeVar *vacrel)
|
|||||||
* Since we don't take a lock here, the relation might be gone, or the
|
* Since we don't take a lock here, the relation might be gone, or the
|
||||||
* RangeVar might no longer refer to the OID we look up here. In the
|
* RangeVar might no longer refer to the OID we look up here. In the
|
||||||
* former case, VACUUM will do nothing; in the latter case, it will
|
* former case, VACUUM will do nothing; in the latter case, it will
|
||||||
* process the OID we looked up here, rather than the new one.
|
* process the OID we looked up here, rather than the new one. Neither
|
||||||
* Neither is ideal, but there's little practical alternative, since
|
* is ideal, but there's little practical alternative, since we're
|
||||||
* we're going to commit this transaction and begin a new one between
|
* going to commit this transaction and begin a new one between now
|
||||||
* now and then.
|
* and then.
|
||||||
*/
|
*/
|
||||||
relid = RangeVarGetRelid(vacrel, NoLock, false);
|
relid = RangeVarGetRelid(vacrel, NoLock, false);
|
||||||
|
|
||||||
@ -723,8 +723,8 @@ vac_update_datfrozenxid(void)
|
|||||||
newFrozenXid = GetOldestXmin(true, true);
|
newFrozenXid = GetOldestXmin(true, true);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Similarly, initialize the MultiXact "min" with the value that would
|
* Similarly, initialize the MultiXact "min" with the value that would be
|
||||||
* be used on pg_class for new tables. See AddNewRelationTuple().
|
* used on pg_class for new tables. See AddNewRelationTuple().
|
||||||
*/
|
*/
|
||||||
newFrozenMulti = GetOldestMultiXactId();
|
newFrozenMulti = GetOldestMultiXactId();
|
||||||
|
|
||||||
@ -900,8 +900,8 @@ vac_truncate_clog(TransactionId frozenXID, MultiXactId frozenMulti)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Update the wrap limit for GetNewTransactionId and creation of new
|
* Update the wrap limit for GetNewTransactionId and creation of new
|
||||||
* MultiXactIds. Note: these functions will also signal the postmaster for
|
* MultiXactIds. Note: these functions will also signal the postmaster
|
||||||
* an(other) autovac cycle if needed. XXX should we avoid possibly
|
* for an(other) autovac cycle if needed. XXX should we avoid possibly
|
||||||
* signalling twice?
|
* signalling twice?
|
||||||
*/
|
*/
|
||||||
SetTransactionIdLimit(frozenXID, oldestxid_datoid);
|
SetTransactionIdLimit(frozenXID, oldestxid_datoid);
|
||||||
|
@ -903,11 +903,11 @@ lazy_scan_heap(Relation onerel, LVRelStats *vacrelstats,
|
|||||||
* so that we get back in sync.
|
* so that we get back in sync.
|
||||||
*
|
*
|
||||||
* NB: If the heap page is all-visible but the VM bit is not set,
|
* NB: If the heap page is all-visible but the VM bit is not set,
|
||||||
* we don't need to dirty the heap page. However, if checksums are
|
* we don't need to dirty the heap page. However, if checksums
|
||||||
* enabled, we do need to make sure that the heap page is dirtied
|
* are enabled, we do need to make sure that the heap page is
|
||||||
* before passing it to visibilitymap_set(), because it may be
|
* dirtied before passing it to visibilitymap_set(), because it
|
||||||
* logged. Given that this situation should only happen in rare
|
* may be logged. Given that this situation should only happen in
|
||||||
* cases after a crash, it is not worth optimizing.
|
* rare cases after a crash, it is not worth optimizing.
|
||||||
*/
|
*/
|
||||||
PageSetAllVisible(page);
|
PageSetAllVisible(page);
|
||||||
MarkBufferDirty(buf);
|
MarkBufferDirty(buf);
|
||||||
@ -1146,8 +1146,8 @@ lazy_vacuum_page(Relation onerel, BlockNumber blkno, Buffer buffer,
|
|||||||
MarkBufferDirty(buffer);
|
MarkBufferDirty(buffer);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Now that we have removed the dead tuples from the page, once again check
|
* Now that we have removed the dead tuples from the page, once again
|
||||||
* if the page has become all-visible.
|
* check if the page has become all-visible.
|
||||||
*/
|
*/
|
||||||
if (!visibilitymap_test(onerel, blkno, vmbuffer) &&
|
if (!visibilitymap_test(onerel, blkno, vmbuffer) &&
|
||||||
heap_page_is_all_visible(buffer, &visibility_cutoff_xid))
|
heap_page_is_all_visible(buffer, &visibility_cutoff_xid))
|
||||||
@ -1669,8 +1669,7 @@ heap_page_is_all_visible(Buffer buf, TransactionId *visibility_cutoff_xid)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* This is a stripped down version of the line pointer scan in
|
* This is a stripped down version of the line pointer scan in
|
||||||
* lazy_scan_heap(). So if you change anything here, also check that
|
* lazy_scan_heap(). So if you change anything here, also check that code.
|
||||||
* code.
|
|
||||||
*/
|
*/
|
||||||
maxoff = PageGetMaxOffsetNumber(page);
|
maxoff = PageGetMaxOffsetNumber(page);
|
||||||
for (offnum = FirstOffsetNumber;
|
for (offnum = FirstOffsetNumber;
|
||||||
@ -1689,8 +1688,8 @@ heap_page_is_all_visible(Buffer buf, TransactionId *visibility_cutoff_xid)
|
|||||||
ItemPointerSet(&(tuple.t_self), BufferGetBlockNumber(buf), offnum);
|
ItemPointerSet(&(tuple.t_self), BufferGetBlockNumber(buf), offnum);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Dead line pointers can have index pointers pointing to them. So they
|
* Dead line pointers can have index pointers pointing to them. So
|
||||||
* can't be treated as visible
|
* they can't be treated as visible
|
||||||
*/
|
*/
|
||||||
if (ItemIdIsDead(itemid))
|
if (ItemIdIsDead(itemid))
|
||||||
{
|
{
|
||||||
@ -1716,8 +1715,8 @@ heap_page_is_all_visible(Buffer buf, TransactionId *visibility_cutoff_xid)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The inserter definitely committed. But is it old
|
* The inserter definitely committed. But is it old enough
|
||||||
* enough that everyone sees it as committed?
|
* that everyone sees it as committed?
|
||||||
*/
|
*/
|
||||||
xmin = HeapTupleHeaderGetXmin(tuple.t_data);
|
xmin = HeapTupleHeaderGetXmin(tuple.t_data);
|
||||||
if (!TransactionIdPrecedes(xmin, OldestXmin))
|
if (!TransactionIdPrecedes(xmin, OldestXmin))
|
||||||
|
@ -959,12 +959,13 @@ CheckValidResultRel(Relation resultRel, CmdType operation)
|
|||||||
RelationGetRelationName(resultRel))));
|
RelationGetRelationName(resultRel))));
|
||||||
break;
|
break;
|
||||||
case RELKIND_VIEW:
|
case RELKIND_VIEW:
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Okay only if there's a suitable INSTEAD OF trigger. Messages
|
* Okay only if there's a suitable INSTEAD OF trigger. Messages
|
||||||
* here should match rewriteHandler.c's rewriteTargetView, except
|
* here should match rewriteHandler.c's rewriteTargetView, except
|
||||||
* that we omit errdetail because we haven't got the information
|
* that we omit errdetail because we haven't got the information
|
||||||
* handy (and given that we really shouldn't get here anyway,
|
* handy (and given that we really shouldn't get here anyway, it's
|
||||||
* it's not worth great exertion to get).
|
* not worth great exertion to get).
|
||||||
*/
|
*/
|
||||||
switch (operation)
|
switch (operation)
|
||||||
{
|
{
|
||||||
@ -1391,7 +1392,8 @@ ExecEndPlan(PlanState *planstate, EState *estate)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* close any relations selected FOR [KEY] UPDATE/SHARE, again keeping locks
|
* close any relations selected FOR [KEY] UPDATE/SHARE, again keeping
|
||||||
|
* locks
|
||||||
*/
|
*/
|
||||||
foreach(l, estate->es_rowMarks)
|
foreach(l, estate->es_rowMarks)
|
||||||
{
|
{
|
||||||
@ -1546,9 +1548,9 @@ ExecRelCheck(ResultRelInfo *resultRelInfo,
|
|||||||
qual = resultRelInfo->ri_ConstraintExprs[i];
|
qual = resultRelInfo->ri_ConstraintExprs[i];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* NOTE: SQL specifies that a NULL result from a constraint
|
* NOTE: SQL specifies that a NULL result from a constraint expression
|
||||||
* expression is not to be treated as a failure. Therefore, tell
|
* is not to be treated as a failure. Therefore, tell ExecQual to
|
||||||
* ExecQual to return TRUE for NULL.
|
* return TRUE for NULL.
|
||||||
*/
|
*/
|
||||||
if (!ExecQual(qual, econtext, true))
|
if (!ExecQual(qual, econtext, true))
|
||||||
return check[i].ccname;
|
return check[i].ccname;
|
||||||
@ -1901,13 +1903,13 @@ EvalPlanQualFetch(EState *estate, Relation relation, int lockmode,
|
|||||||
/*
|
/*
|
||||||
* If tuple was inserted by our own transaction, we have to check
|
* If tuple was inserted by our own transaction, we have to check
|
||||||
* cmin against es_output_cid: cmin >= current CID means our
|
* cmin against es_output_cid: cmin >= current CID means our
|
||||||
* command cannot see the tuple, so we should ignore it.
|
* command cannot see the tuple, so we should ignore it. Otherwise
|
||||||
* Otherwise heap_lock_tuple() will throw an error, and so would
|
* heap_lock_tuple() will throw an error, and so would any later
|
||||||
* any later attempt to update or delete the tuple. (We need not
|
* attempt to update or delete the tuple. (We need not check cmax
|
||||||
* check cmax because HeapTupleSatisfiesDirty will consider a
|
* because HeapTupleSatisfiesDirty will consider a tuple deleted
|
||||||
* tuple deleted by our transaction dead, regardless of cmax.)
|
* by our transaction dead, regardless of cmax.) Wee just checked
|
||||||
* Wee just checked that priorXmax == xmin, so we can test that
|
* that priorXmax == xmin, so we can test that variable instead of
|
||||||
* variable instead of doing HeapTupleHeaderGetXmin again.
|
* doing HeapTupleHeaderGetXmin again.
|
||||||
*/
|
*/
|
||||||
if (TransactionIdIsCurrentTransactionId(priorXmax) &&
|
if (TransactionIdIsCurrentTransactionId(priorXmax) &&
|
||||||
HeapTupleHeaderGetCmin(tuple.t_data) >= estate->es_output_cid)
|
HeapTupleHeaderGetCmin(tuple.t_data) >= estate->es_output_cid)
|
||||||
@ -1929,6 +1931,7 @@ EvalPlanQualFetch(EState *estate, Relation relation, int lockmode,
|
|||||||
switch (test)
|
switch (test)
|
||||||
{
|
{
|
||||||
case HeapTupleSelfUpdated:
|
case HeapTupleSelfUpdated:
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The target tuple was already updated or deleted by the
|
* The target tuple was already updated or deleted by the
|
||||||
* current command, or by a later command in the current
|
* current command, or by a later command in the current
|
||||||
|
@ -139,6 +139,7 @@ lnext:
|
|||||||
switch (test)
|
switch (test)
|
||||||
{
|
{
|
||||||
case HeapTupleSelfUpdated:
|
case HeapTupleSelfUpdated:
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The target tuple was already updated or deleted by the
|
* The target tuple was already updated or deleted by the
|
||||||
* current command, or by a later command in the current
|
* current command, or by a later command in the current
|
||||||
|
@ -397,13 +397,14 @@ ldelete:;
|
|||||||
switch (result)
|
switch (result)
|
||||||
{
|
{
|
||||||
case HeapTupleSelfUpdated:
|
case HeapTupleSelfUpdated:
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The target tuple was already updated or deleted by the
|
* The target tuple was already updated or deleted by the
|
||||||
* current command, or by a later command in the current
|
* current command, or by a later command in the current
|
||||||
* transaction. The former case is possible in a join DELETE
|
* transaction. The former case is possible in a join DELETE
|
||||||
* where multiple tuples join to the same target tuple.
|
* where multiple tuples join to the same target tuple. This
|
||||||
* This is somewhat questionable, but Postgres has always
|
* is somewhat questionable, but Postgres has always allowed
|
||||||
* allowed it: we just ignore additional deletion attempts.
|
* it: we just ignore additional deletion attempts.
|
||||||
*
|
*
|
||||||
* The latter case arises if the tuple is modified by a
|
* The latter case arises if the tuple is modified by a
|
||||||
* command in a BEFORE trigger, or perhaps by a command in a
|
* command in a BEFORE trigger, or perhaps by a command in a
|
||||||
@ -417,9 +418,9 @@ ldelete:;
|
|||||||
* to business rules; so throwing an error is the only safe
|
* to business rules; so throwing an error is the only safe
|
||||||
* course.
|
* course.
|
||||||
*
|
*
|
||||||
* If a trigger actually intends this type of interaction,
|
* If a trigger actually intends this type of interaction, it
|
||||||
* it can re-execute the DELETE and then return NULL to
|
* can re-execute the DELETE and then return NULL to cancel
|
||||||
* cancel the outer delete.
|
* the outer delete.
|
||||||
*/
|
*/
|
||||||
if (hufd.cmax != estate->es_output_cid)
|
if (hufd.cmax != estate->es_output_cid)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
@ -678,14 +679,15 @@ lreplace:;
|
|||||||
switch (result)
|
switch (result)
|
||||||
{
|
{
|
||||||
case HeapTupleSelfUpdated:
|
case HeapTupleSelfUpdated:
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The target tuple was already updated or deleted by the
|
* The target tuple was already updated or deleted by the
|
||||||
* current command, or by a later command in the current
|
* current command, or by a later command in the current
|
||||||
* transaction. The former case is possible in a join UPDATE
|
* transaction. The former case is possible in a join UPDATE
|
||||||
* where multiple tuples join to the same target tuple.
|
* where multiple tuples join to the same target tuple. This
|
||||||
* This is pretty questionable, but Postgres has always
|
* is pretty questionable, but Postgres has always allowed it:
|
||||||
* allowed it: we just execute the first update action and
|
* we just execute the first update action and ignore
|
||||||
* ignore additional update attempts.
|
* additional update attempts.
|
||||||
*
|
*
|
||||||
* The latter case arises if the tuple is modified by a
|
* The latter case arises if the tuple is modified by a
|
||||||
* command in a BEFORE trigger, or perhaps by a command in a
|
* command in a BEFORE trigger, or perhaps by a command in a
|
||||||
@ -697,9 +699,9 @@ lreplace:;
|
|||||||
* previous ones. So throwing an error is the only safe
|
* previous ones. So throwing an error is the only safe
|
||||||
* course.
|
* course.
|
||||||
*
|
*
|
||||||
* If a trigger actually intends this type of interaction,
|
* If a trigger actually intends this type of interaction, it
|
||||||
* it can re-execute the UPDATE (assuming it can figure out
|
* can re-execute the UPDATE (assuming it can figure out how)
|
||||||
* how) and then return NULL to cancel the outer update.
|
* and then return NULL to cancel the outer update.
|
||||||
*/
|
*/
|
||||||
if (hufd.cmax != estate->es_output_cid)
|
if (hufd.cmax != estate->es_output_cid)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
|
@ -47,7 +47,6 @@ int
|
|||||||
cx(PlannerInfo *root, Gene *tour1, Gene *tour2, Gene *offspring,
|
cx(PlannerInfo *root, Gene *tour1, Gene *tour2, Gene *offspring,
|
||||||
int num_gene, City *city_table)
|
int num_gene, City *city_table)
|
||||||
{
|
{
|
||||||
|
|
||||||
int i,
|
int i,
|
||||||
start_pos,
|
start_pos,
|
||||||
curr_pos;
|
curr_pos;
|
||||||
|
@ -46,7 +46,6 @@ void
|
|||||||
px(PlannerInfo *root, Gene *tour1, Gene *tour2, Gene *offspring, int num_gene,
|
px(PlannerInfo *root, Gene *tour1, Gene *tour2, Gene *offspring, int num_gene,
|
||||||
City *city_table)
|
City *city_table)
|
||||||
{
|
{
|
||||||
|
|
||||||
int num_positions;
|
int num_positions;
|
||||||
int i,
|
int i,
|
||||||
pos,
|
pos,
|
||||||
|
@ -2083,9 +2083,9 @@ generate_implied_equalities_for_column(PlannerInfo *root,
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Scan members, looking for a match to the target column. Note
|
* Scan members, looking for a match to the target column. Note that
|
||||||
* that child EC members are considered, but only when they belong to
|
* child EC members are considered, but only when they belong to the
|
||||||
* the target relation. (Unlike regular members, the same expression
|
* target relation. (Unlike regular members, the same expression
|
||||||
* could be a child member of more than one EC. Therefore, it's
|
* could be a child member of more than one EC. Therefore, it's
|
||||||
* potentially order-dependent which EC a child relation's target
|
* potentially order-dependent which EC a child relation's target
|
||||||
* column gets matched to. This is annoying but it only happens in
|
* column gets matched to. This is annoying but it only happens in
|
||||||
|
@ -2630,8 +2630,8 @@ check_partial_indexes(PlannerInfo *root, RelOptInfo *rel)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Construct a list of clauses that we can assume true for the purpose
|
* Construct a list of clauses that we can assume true for the purpose of
|
||||||
* of proving the index(es) usable. Restriction clauses for the rel are
|
* proving the index(es) usable. Restriction clauses for the rel are
|
||||||
* always usable, and so are any join clauses that are "movable to" this
|
* always usable, and so are any join clauses that are "movable to" this
|
||||||
* rel. Also, we can consider any EC-derivable join clauses (which must
|
* rel. Also, we can consider any EC-derivable join clauses (which must
|
||||||
* be "movable to" this rel, by definition).
|
* be "movable to" this rel, by definition).
|
||||||
@ -2653,8 +2653,8 @@ check_partial_indexes(PlannerInfo *root, RelOptInfo *rel)
|
|||||||
/*
|
/*
|
||||||
* Add on any equivalence-derivable join clauses. Computing the correct
|
* Add on any equivalence-derivable join clauses. Computing the correct
|
||||||
* relid sets for generate_join_implied_equalities is slightly tricky
|
* relid sets for generate_join_implied_equalities is slightly tricky
|
||||||
* because the rel could be a child rel rather than a true baserel, and
|
* because the rel could be a child rel rather than a true baserel, and in
|
||||||
* in that case we must remove its parent's relid from all_baserels.
|
* that case we must remove its parent's relid from all_baserels.
|
||||||
*/
|
*/
|
||||||
if (rel->reloptkind == RELOPT_OTHER_MEMBER_REL)
|
if (rel->reloptkind == RELOPT_OTHER_MEMBER_REL)
|
||||||
{
|
{
|
||||||
|
@ -861,11 +861,11 @@ make_outerjoininfo(PlannerInfo *root,
|
|||||||
Assert(jointype != JOIN_RIGHT);
|
Assert(jointype != JOIN_RIGHT);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Presently the executor cannot support FOR [KEY] UPDATE/SHARE marking of rels
|
* Presently the executor cannot support FOR [KEY] UPDATE/SHARE marking of
|
||||||
* appearing on the nullable side of an outer join. (It's somewhat unclear
|
* rels appearing on the nullable side of an outer join. (It's somewhat
|
||||||
* what that would mean, anyway: what should we mark when a result row is
|
* unclear what that would mean, anyway: what should we mark when a result
|
||||||
* generated from no element of the nullable relation?) So, complain if
|
* row is generated from no element of the nullable relation?) So,
|
||||||
* any nullable rel is FOR [KEY] UPDATE/SHARE.
|
* complain if any nullable rel is FOR [KEY] UPDATE/SHARE.
|
||||||
*
|
*
|
||||||
* You might be wondering why this test isn't made far upstream in the
|
* You might be wondering why this test isn't made far upstream in the
|
||||||
* parser. It's because the parser hasn't got enough info --- consider
|
* parser. It's because the parser hasn't got enough info --- consider
|
||||||
|
@ -260,8 +260,8 @@ optimize_minmax_aggregates(PlannerInfo *root, List *tlist,
|
|||||||
* We have to replace Aggrefs with Params in equivalence classes too, else
|
* We have to replace Aggrefs with Params in equivalence classes too, else
|
||||||
* ORDER BY or DISTINCT on an optimized aggregate will fail. We don't
|
* ORDER BY or DISTINCT on an optimized aggregate will fail. We don't
|
||||||
* need to process child eclass members though, since they aren't of
|
* need to process child eclass members though, since they aren't of
|
||||||
* interest anymore --- and replace_aggs_with_params_mutator isn't able
|
* interest anymore --- and replace_aggs_with_params_mutator isn't able to
|
||||||
* to handle Aggrefs containing translated child Vars, anyway.
|
* handle Aggrefs containing translated child Vars, anyway.
|
||||||
*
|
*
|
||||||
* Note: at some point it might become necessary to mutate other data
|
* Note: at some point it might become necessary to mutate other data
|
||||||
* structures too, such as the query's sortClause or distinctClause. Right
|
* structures too, such as the query's sortClause or distinctClause. Right
|
||||||
|
@ -571,9 +571,9 @@ subquery_planner(PlannerGlobal *glob, Query *parse,
|
|||||||
returningLists = NIL;
|
returningLists = NIL;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If there was a FOR [KEY] UPDATE/SHARE clause, the LockRows node will
|
* If there was a FOR [KEY] UPDATE/SHARE clause, the LockRows node
|
||||||
* have dealt with fetching non-locked marked rows, else we need
|
* will have dealt with fetching non-locked marked rows, else we
|
||||||
* to have ModifyTable do that.
|
* need to have ModifyTable do that.
|
||||||
*/
|
*/
|
||||||
if (parse->rowMarks)
|
if (parse->rowMarks)
|
||||||
rowMarks = NIL;
|
rowMarks = NIL;
|
||||||
@ -964,8 +964,8 @@ inheritance_planner(PlannerInfo *root)
|
|||||||
root->simple_rel_array = save_rel_array;
|
root->simple_rel_array = save_rel_array;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If there was a FOR [KEY] UPDATE/SHARE clause, the LockRows node will have
|
* If there was a FOR [KEY] UPDATE/SHARE clause, the LockRows node will
|
||||||
* dealt with fetching non-locked marked rows, else we need to have
|
* have dealt with fetching non-locked marked rows, else we need to have
|
||||||
* ModifyTable do that.
|
* ModifyTable do that.
|
||||||
*/
|
*/
|
||||||
if (parse->rowMarks)
|
if (parse->rowMarks)
|
||||||
@ -1075,8 +1075,8 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
|
|||||||
tlist);
|
tlist);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Can't handle FOR [KEY] UPDATE/SHARE here (parser should have checked
|
* Can't handle FOR [KEY] UPDATE/SHARE here (parser should have
|
||||||
* already, but let's make sure).
|
* checked already, but let's make sure).
|
||||||
*/
|
*/
|
||||||
if (parse->rowMarks)
|
if (parse->rowMarks)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
@ -1741,9 +1741,9 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If there is a FOR [KEY] UPDATE/SHARE clause, add the LockRows node. (Note: we
|
* If there is a FOR [KEY] UPDATE/SHARE clause, add the LockRows node.
|
||||||
* intentionally test parse->rowMarks not root->rowMarks here. If there
|
* (Note: we intentionally test parse->rowMarks not root->rowMarks here.
|
||||||
* are only non-locking rowmarks, they should be handled by the
|
* If there are only non-locking rowmarks, they should be handled by the
|
||||||
* ModifyTable node instead.)
|
* ModifyTable node instead.)
|
||||||
*/
|
*/
|
||||||
if (parse->rowMarks)
|
if (parse->rowMarks)
|
||||||
@ -1927,9 +1927,9 @@ preprocess_rowmarks(PlannerInfo *root)
|
|||||||
if (parse->rowMarks)
|
if (parse->rowMarks)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* We've got trouble if FOR [KEY] UPDATE/SHARE appears inside grouping,
|
* We've got trouble if FOR [KEY] UPDATE/SHARE appears inside
|
||||||
* since grouping renders a reference to individual tuple CTIDs
|
* grouping, since grouping renders a reference to individual tuple
|
||||||
* invalid. This is also checked at parse time, but that's
|
* CTIDs invalid. This is also checked at parse time, but that's
|
||||||
* insufficient because of rule substitution, query pullup, etc.
|
* insufficient because of rule substitution, query pullup, etc.
|
||||||
*/
|
*/
|
||||||
CheckSelectLocking(parse);
|
CheckSelectLocking(parse);
|
||||||
@ -1937,7 +1937,8 @@ preprocess_rowmarks(PlannerInfo *root)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* We only need rowmarks for UPDATE, DELETE, or FOR [KEY] UPDATE/SHARE.
|
* We only need rowmarks for UPDATE, DELETE, or FOR [KEY]
|
||||||
|
* UPDATE/SHARE.
|
||||||
*/
|
*/
|
||||||
if (parse->commandType != CMD_UPDATE &&
|
if (parse->commandType != CMD_UPDATE &&
|
||||||
parse->commandType != CMD_DELETE)
|
parse->commandType != CMD_DELETE)
|
||||||
|
@ -1288,9 +1288,9 @@ is_simple_subquery(Query *subquery, RangeTblEntry *rte,
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Don't pull up if the RTE represents a security-barrier view; we couldn't
|
* Don't pull up if the RTE represents a security-barrier view; we
|
||||||
* prevent information leakage once the RTE's Vars are scattered about in
|
* couldn't prevent information leakage once the RTE's Vars are scattered
|
||||||
* the upper query.
|
* about in the upper query.
|
||||||
*/
|
*/
|
||||||
if (rte->security_barrier)
|
if (rte->security_barrier)
|
||||||
return false;
|
return false;
|
||||||
|
@ -282,6 +282,7 @@ set_cheapest(RelOptInfo *parent_rel)
|
|||||||
/* old path is less-parameterized, keep it */
|
/* old path is less-parameterized, keep it */
|
||||||
break;
|
break;
|
||||||
case BMS_DIFFERENT:
|
case BMS_DIFFERENT:
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This means that neither path has the least possible
|
* This means that neither path has the least possible
|
||||||
* parameterization for the rel. We'll sit on the old
|
* parameterization for the rel. We'll sit on the old
|
||||||
@ -328,8 +329,8 @@ set_cheapest(RelOptInfo *parent_rel)
|
|||||||
parameterized_paths = lcons(cheapest_total_path, parameterized_paths);
|
parameterized_paths = lcons(cheapest_total_path, parameterized_paths);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If there is no unparameterized path, use the best parameterized path
|
* If there is no unparameterized path, use the best parameterized path as
|
||||||
* as cheapest_total_path (but not as cheapest_startup_path).
|
* cheapest_total_path (but not as cheapest_startup_path).
|
||||||
*/
|
*/
|
||||||
if (cheapest_total_path == NULL)
|
if (cheapest_total_path == NULL)
|
||||||
cheapest_total_path = best_param_path;
|
cheapest_total_path = best_param_path;
|
||||||
|
@ -2167,10 +2167,10 @@ transformCreateTableAsStmt(ParseState *pstate, CreateTableAsStmt *stmt)
|
|||||||
errmsg("materialized views may not be defined using bound parameters")));
|
errmsg("materialized views may not be defined using bound parameters")));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* For now, we disallow unlogged materialized views, because it
|
* For now, we disallow unlogged materialized views, because it seems
|
||||||
* seems like a bad idea for them to just go to empty after a crash.
|
* like a bad idea for them to just go to empty after a crash. (If we
|
||||||
* (If we could mark them as unpopulated, that would be better, but
|
* could mark them as unpopulated, that would be better, but that
|
||||||
* that requires catalog changes which crash recovery can't presently
|
* requires catalog changes which crash recovery can't presently
|
||||||
* handle.)
|
* handle.)
|
||||||
*/
|
*/
|
||||||
if (stmt->into->rel->relpersistence == RELPERSISTENCE_UNLOGGED)
|
if (stmt->into->rel->relpersistence == RELPERSISTENCE_UNLOGGED)
|
||||||
@ -2394,8 +2394,8 @@ applyLockingClause(Query *qry, Index rtindex,
|
|||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* If the same RTE is specified for more than one locking strength,
|
* If the same RTE is specified for more than one locking strength,
|
||||||
* treat is as the strongest. (Reasonable, since you can't take both a
|
* treat is as the strongest. (Reasonable, since you can't take both
|
||||||
* shared and exclusive lock at the same time; it'll end up being
|
* a shared and exclusive lock at the same time; it'll end up being
|
||||||
* exclusive anyway.)
|
* exclusive anyway.)
|
||||||
*
|
*
|
||||||
* We also consider that NOWAIT wins if it's specified both ways. This
|
* We also consider that NOWAIT wins if it's specified both ways. This
|
||||||
|
@ -52,6 +52,7 @@ line: while (<GRAM>)
|
|||||||
|
|
||||||
if (!($kcat))
|
if (!($kcat))
|
||||||
{
|
{
|
||||||
|
|
||||||
# Is this the beginning of a keyword list?
|
# Is this the beginning of a keyword list?
|
||||||
foreach $k (keys %keyword_categories)
|
foreach $k (keys %keyword_categories)
|
||||||
{
|
{
|
||||||
@ -81,6 +82,7 @@ line: while (<GRAM>)
|
|||||||
}
|
}
|
||||||
elsif ($arr[$fieldIndexer] eq '/*')
|
elsif ($arr[$fieldIndexer] eq '/*')
|
||||||
{
|
{
|
||||||
|
|
||||||
# start of a multiline comment
|
# start of a multiline comment
|
||||||
$comment = 1;
|
$comment = 1;
|
||||||
next;
|
next;
|
||||||
@ -92,6 +94,7 @@ line: while (<GRAM>)
|
|||||||
|
|
||||||
if ($arr[$fieldIndexer] eq ';')
|
if ($arr[$fieldIndexer] eq ';')
|
||||||
{
|
{
|
||||||
|
|
||||||
# end of keyword list
|
# end of keyword list
|
||||||
$kcat = '';
|
$kcat = '';
|
||||||
next;
|
next;
|
||||||
@ -116,6 +119,7 @@ foreach $kcat (keys %keyword_categories)
|
|||||||
|
|
||||||
foreach $kword (@{ $keywords{$kcat} })
|
foreach $kword (@{ $keywords{$kcat} })
|
||||||
{
|
{
|
||||||
|
|
||||||
# Some keyword have a _P suffix. Remove it for the comparison.
|
# Some keyword have a _P suffix. Remove it for the comparison.
|
||||||
$bare_kword = $kword;
|
$bare_kword = $kword;
|
||||||
$bare_kword =~ s/_P$//;
|
$bare_kword =~ s/_P$//;
|
||||||
@ -206,6 +210,7 @@ kwlist_line: while (<KWLIST>)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
||||||
# Remove it from the hash, so that we can
|
# Remove it from the hash, so that we can
|
||||||
# complain at the end if there's keywords left
|
# complain at the end if there's keywords left
|
||||||
# that were not found in kwlist.h
|
# that were not found in kwlist.h
|
||||||
|
@ -715,8 +715,8 @@ transformFromClauseItem(ParseState *pstate, Node *n,
|
|||||||
/*
|
/*
|
||||||
* Make the left-side RTEs available for LATERAL access within the
|
* Make the left-side RTEs available for LATERAL access within the
|
||||||
* right side, by temporarily adding them to the pstate's namespace
|
* right side, by temporarily adding them to the pstate's namespace
|
||||||
* list. Per SQL:2008, if the join type is not INNER or LEFT then
|
* list. Per SQL:2008, if the join type is not INNER or LEFT then the
|
||||||
* the left-side names must still be exposed, but it's an error to
|
* left-side names must still be exposed, but it's an error to
|
||||||
* reference them. (Stupid design, but that's what it says.) Hence,
|
* reference them. (Stupid design, but that's what it says.) Hence,
|
||||||
* we always push them into the namespace, but mark them as not
|
* we always push them into the namespace, but mark them as not
|
||||||
* lateral_ok if the jointype is wrong.
|
* lateral_ok if the jointype is wrong.
|
||||||
|
@ -1411,9 +1411,9 @@ transformSubLink(ParseState *pstate, SubLink *sublink)
|
|||||||
return result;
|
return result;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check to see if the sublink is in an invalid place within the query.
|
* Check to see if the sublink is in an invalid place within the query. We
|
||||||
* We allow sublinks everywhere in SELECT/INSERT/UPDATE/DELETE, but
|
* allow sublinks everywhere in SELECT/INSERT/UPDATE/DELETE, but generally
|
||||||
* generally not in utility statements.
|
* not in utility statements.
|
||||||
*/
|
*/
|
||||||
err = NULL;
|
err = NULL;
|
||||||
switch (pstate->p_expr_kind)
|
switch (pstate->p_expr_kind)
|
||||||
|
@ -556,6 +556,7 @@ transformColumnDefinition(CreateStmtContext *cxt, ColumnDef *column)
|
|||||||
errmsg("constraints are not supported on foreign tables"),
|
errmsg("constraints are not supported on foreign tables"),
|
||||||
parser_errposition(cxt->pstate,
|
parser_errposition(cxt->pstate,
|
||||||
constraint->location)));
|
constraint->location)));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Fill in the current attribute's name and throw it into the
|
* Fill in the current attribute's name and throw it into the
|
||||||
* list of FK constraints to be processed later.
|
* list of FK constraints to be processed later.
|
||||||
@ -1405,8 +1406,8 @@ transformIndexConstraints(CreateStmtContext *cxt)
|
|||||||
/*
|
/*
|
||||||
* Scan the index list and remove any redundant index specifications. This
|
* Scan the index list and remove any redundant index specifications. This
|
||||||
* can happen if, for instance, the user writes UNIQUE PRIMARY KEY. A
|
* can happen if, for instance, the user writes UNIQUE PRIMARY KEY. A
|
||||||
* strict reading of SQL would suggest raising an error instead, but
|
* strict reading of SQL would suggest raising an error instead, but that
|
||||||
* that strikes me as too anal-retentive. - tgl 2001-02-14
|
* strikes me as too anal-retentive. - tgl 2001-02-14
|
||||||
*
|
*
|
||||||
* XXX in ALTER TABLE case, it'd be nice to look for duplicate
|
* XXX in ALTER TABLE case, it'd be nice to look for duplicate
|
||||||
* pre-existing indexes, too.
|
* pre-existing indexes, too.
|
||||||
|
@ -384,10 +384,10 @@ PGSharedMemoryCreate(Size size, bool makePrivate, int port)
|
|||||||
* settings.
|
* settings.
|
||||||
*
|
*
|
||||||
* However, we disable this logic in the EXEC_BACKEND case, and fall back
|
* However, we disable this logic in the EXEC_BACKEND case, and fall back
|
||||||
* to the old method of allocating the entire segment using System V shared
|
* to the old method of allocating the entire segment using System V
|
||||||
* memory, because there's no way to attach an mmap'd segment to a process
|
* shared memory, because there's no way to attach an mmap'd segment to a
|
||||||
* after exec(). Since EXEC_BACKEND is intended only for developer use,
|
* process after exec(). Since EXEC_BACKEND is intended only for
|
||||||
* this shouldn't be a big problem.
|
* developer use, this shouldn't be a big problem.
|
||||||
*/
|
*/
|
||||||
#ifndef EXEC_BACKEND
|
#ifndef EXEC_BACKEND
|
||||||
{
|
{
|
||||||
@ -406,9 +406,9 @@ PGSharedMemoryCreate(Size size, bool makePrivate, int port)
|
|||||||
/*
|
/*
|
||||||
* We assume that no one will attempt to run PostgreSQL 9.3 or later
|
* We assume that no one will attempt to run PostgreSQL 9.3 or later
|
||||||
* on systems that are ancient enough that anonymous shared memory is
|
* on systems that are ancient enough that anonymous shared memory is
|
||||||
* not supported, such as pre-2.4 versions of Linux. If that turns out
|
* not supported, such as pre-2.4 versions of Linux. If that turns
|
||||||
* to be false, we might need to add a run-time test here and do this
|
* out to be false, we might need to add a run-time test here and do
|
||||||
* only if the running kernel supports it.
|
* this only if the running kernel supports it.
|
||||||
*/
|
*/
|
||||||
AnonymousShmem = mmap(NULL, size, PROT_READ | PROT_WRITE, PG_MMAP_FLAGS,
|
AnonymousShmem = mmap(NULL, size, PROT_READ | PROT_WRITE, PG_MMAP_FLAGS,
|
||||||
-1, 0);
|
-1, 0);
|
||||||
@ -519,9 +519,9 @@ PGSharedMemoryCreate(Size size, bool makePrivate, int port)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* If AnonymousShmem is NULL here, then we're not using anonymous shared
|
* If AnonymousShmem is NULL here, then we're not using anonymous shared
|
||||||
* memory, and should return a pointer to the System V shared memory block.
|
* memory, and should return a pointer to the System V shared memory
|
||||||
* Otherwise, the System V shared memory block is only a shim, and we must
|
* block. Otherwise, the System V shared memory block is only a shim, and
|
||||||
* return a pointer to the real block.
|
* we must return a pointer to the real block.
|
||||||
*/
|
*/
|
||||||
if (AnonymousShmem == NULL)
|
if (AnonymousShmem == NULL)
|
||||||
return hdr;
|
return hdr;
|
||||||
|
@ -949,8 +949,8 @@ rebuild_database_list(Oid newdb)
|
|||||||
PgStat_StatDBEntry *entry;
|
PgStat_StatDBEntry *entry;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* skip databases with no stat entries -- in particular, this gets
|
* skip databases with no stat entries -- in particular, this gets rid
|
||||||
* rid of dropped databases
|
* of dropped databases
|
||||||
*/
|
*/
|
||||||
entry = pgstat_fetch_stat_dbentry(avdb->adl_datid);
|
entry = pgstat_fetch_stat_dbentry(avdb->adl_datid);
|
||||||
if (entry == NULL)
|
if (entry == NULL)
|
||||||
|
@ -930,8 +930,8 @@ CheckpointerShmemInit(void)
|
|||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* First time through, so initialize. Note that we zero the whole
|
* First time through, so initialize. Note that we zero the whole
|
||||||
* requests array; this is so that CompactCheckpointerRequestQueue
|
* requests array; this is so that CompactCheckpointerRequestQueue can
|
||||||
* can assume that any pad bytes in the request structs are zeroes.
|
* assume that any pad bytes in the request structs are zeroes.
|
||||||
*/
|
*/
|
||||||
MemSet(CheckpointerShmem, 0, size);
|
MemSet(CheckpointerShmem, 0, size);
|
||||||
SpinLockInit(&CheckpointerShmem->ckpt_lck);
|
SpinLockInit(&CheckpointerShmem->ckpt_lck);
|
||||||
|
@ -102,9 +102,9 @@ fork_process(void)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Older Linux kernels have oom_adj not oom_score_adj. This works
|
* Older Linux kernels have oom_adj not oom_score_adj. This works
|
||||||
* similarly except with a different scale of adjustment values.
|
* similarly except with a different scale of adjustment values. If
|
||||||
* If it's necessary to build Postgres to work with either API,
|
* it's necessary to build Postgres to work with either API, you can
|
||||||
* you can define both LINUX_OOM_SCORE_ADJ and LINUX_OOM_ADJ.
|
* define both LINUX_OOM_SCORE_ADJ and LINUX_OOM_ADJ.
|
||||||
*/
|
*/
|
||||||
#ifdef LINUX_OOM_ADJ
|
#ifdef LINUX_OOM_ADJ
|
||||||
{
|
{
|
||||||
|
@ -4401,9 +4401,9 @@ pgstat_recv_inquiry(PgStat_MsgInquiry *msg, int len)
|
|||||||
* request's cutoff time, update it; otherwise there's nothing to do.
|
* request's cutoff time, update it; otherwise there's nothing to do.
|
||||||
*
|
*
|
||||||
* Note that if a request is found, we return early and skip the below
|
* Note that if a request is found, we return early and skip the below
|
||||||
* check for clock skew. This is okay, since the only way for a DB request
|
* check for clock skew. This is okay, since the only way for a DB
|
||||||
* to be present in the list is that we have been here since the last write
|
* request to be present in the list is that we have been here since the
|
||||||
* round.
|
* last write round.
|
||||||
*/
|
*/
|
||||||
slist_foreach(iter, &last_statrequests)
|
slist_foreach(iter, &last_statrequests)
|
||||||
{
|
{
|
||||||
|
@ -207,8 +207,10 @@ BackgroundWorker *MyBgworkerEntry = NULL;
|
|||||||
|
|
||||||
/* The socket number we are listening for connections on */
|
/* The socket number we are listening for connections on */
|
||||||
int PostPortNumber;
|
int PostPortNumber;
|
||||||
|
|
||||||
/* The directory names for Unix socket(s) */
|
/* The directory names for Unix socket(s) */
|
||||||
char *Unix_socket_directories;
|
char *Unix_socket_directories;
|
||||||
|
|
||||||
/* The TCP listen address(es) */
|
/* The TCP listen address(es) */
|
||||||
char *ListenAddresses;
|
char *ListenAddresses;
|
||||||
|
|
||||||
@ -1212,8 +1214,8 @@ PostmasterMain(int argc, char *argv[])
|
|||||||
/*
|
/*
|
||||||
* We can start up without the IDENT file, although it means that you
|
* We can start up without the IDENT file, although it means that you
|
||||||
* cannot log in using any of the authentication methods that need a
|
* cannot log in using any of the authentication methods that need a
|
||||||
* user name mapping. load_ident() already logged the details of
|
* user name mapping. load_ident() already logged the details of error
|
||||||
* error to the log.
|
* to the log.
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5214,11 +5216,11 @@ RegisterBackgroundWorker(BackgroundWorker *worker)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Enforce maximum number of workers. Note this is overly restrictive:
|
* Enforce maximum number of workers. Note this is overly restrictive: we
|
||||||
* we could allow more non-shmem-connected workers, because these don't
|
* could allow more non-shmem-connected workers, because these don't count
|
||||||
* count towards the MAX_BACKENDS limit elsewhere. This doesn't really
|
* towards the MAX_BACKENDS limit elsewhere. This doesn't really matter
|
||||||
* matter for practical purposes; several million processes would need to
|
* for practical purposes; several million processes would need to run on
|
||||||
* run on a single server.
|
* a single server.
|
||||||
*/
|
*/
|
||||||
if (++numworkers > maxworkers)
|
if (++numworkers > maxworkers)
|
||||||
{
|
{
|
||||||
|
@ -583,8 +583,8 @@ SysLogger_Start(void)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* The initial logfile is created right in the postmaster, to verify that
|
* The initial logfile is created right in the postmaster, to verify that
|
||||||
* the Log_directory is writable. We save the reference time so that
|
* the Log_directory is writable. We save the reference time so that the
|
||||||
* the syslogger child process can recompute this file name.
|
* syslogger child process can recompute this file name.
|
||||||
*
|
*
|
||||||
* It might look a bit strange to re-do this during a syslogger restart,
|
* It might look a bit strange to re-do this during a syslogger restart,
|
||||||
* but we must do so since the postmaster closed syslogFile after the
|
* but we must do so since the postmaster closed syslogFile after the
|
||||||
|
@ -79,8 +79,8 @@ pg_regprefix(regex_t *re,
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Since a correct NFA should never contain any exit-free loops, it should
|
* Since a correct NFA should never contain any exit-free loops, it should
|
||||||
* not be possible for our traversal to return to a previously visited
|
* not be possible for our traversal to return to a previously visited NFA
|
||||||
* NFA state. Hence we need at most nstates chrs in the output string.
|
* state. Hence we need at most nstates chrs in the output string.
|
||||||
*/
|
*/
|
||||||
*string = (chr *) MALLOC(cnfa->nstates * sizeof(chr));
|
*string = (chr *) MALLOC(cnfa->nstates * sizeof(chr));
|
||||||
if (*string == NULL)
|
if (*string == NULL)
|
||||||
@ -122,8 +122,8 @@ findprefix(struct cnfa * cnfa,
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* The "pre" state must have only BOS/BOL outarcs, else pattern isn't
|
* The "pre" state must have only BOS/BOL outarcs, else pattern isn't
|
||||||
* anchored left. If we have both BOS and BOL, they must go to the
|
* anchored left. If we have both BOS and BOL, they must go to the same
|
||||||
* same next state.
|
* next state.
|
||||||
*/
|
*/
|
||||||
st = cnfa->pre;
|
st = cnfa->pre;
|
||||||
nextst = -1;
|
nextst = -1;
|
||||||
|
@ -249,8 +249,8 @@ perform_base_backup(basebackup_options *opt, DIR *tblspcdir)
|
|||||||
* I'd rather not worry about timelines here, so scan pg_xlog and
|
* I'd rather not worry about timelines here, so scan pg_xlog and
|
||||||
* include all WAL files in the range between 'startptr' and 'endptr',
|
* include all WAL files in the range between 'startptr' and 'endptr',
|
||||||
* regardless of the timeline the file is stamped with. If there are
|
* regardless of the timeline the file is stamped with. If there are
|
||||||
* some spurious WAL files belonging to timelines that don't belong
|
* some spurious WAL files belonging to timelines that don't belong in
|
||||||
* in this server's history, they will be included too. Normally there
|
* this server's history, they will be included too. Normally there
|
||||||
* shouldn't be such files, but if there are, there's little harm in
|
* shouldn't be such files, but if there are, there's little harm in
|
||||||
* including them.
|
* including them.
|
||||||
*/
|
*/
|
||||||
@ -290,9 +290,9 @@ perform_base_backup(basebackup_options *opt, DIR *tblspcdir)
|
|||||||
CheckXLogRemoved(startsegno, ThisTimeLineID);
|
CheckXLogRemoved(startsegno, ThisTimeLineID);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Put the WAL filenames into an array, and sort. We send the files
|
* Put the WAL filenames into an array, and sort. We send the files in
|
||||||
* in order from oldest to newest, to reduce the chance that a file
|
* order from oldest to newest, to reduce the chance that a file is
|
||||||
* is recycled before we get a chance to send it over.
|
* recycled before we get a chance to send it over.
|
||||||
*/
|
*/
|
||||||
nWalFiles = list_length(walFileList);
|
nWalFiles = list_length(walFileList);
|
||||||
walFiles = palloc(nWalFiles * sizeof(char *));
|
walFiles = palloc(nWalFiles * sizeof(char *));
|
||||||
@ -311,6 +311,7 @@ perform_base_backup(basebackup_options *opt, DIR *tblspcdir)
|
|||||||
if (segno != startsegno)
|
if (segno != startsegno)
|
||||||
{
|
{
|
||||||
char startfname[MAXFNAMELEN];
|
char startfname[MAXFNAMELEN];
|
||||||
|
|
||||||
XLogFileName(startfname, ThisTimeLineID, startsegno);
|
XLogFileName(startfname, ThisTimeLineID, startsegno);
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errmsg("could not find WAL file \"%s\"", startfname)));
|
(errmsg("could not find WAL file \"%s\"", startfname)));
|
||||||
@ -324,6 +325,7 @@ perform_base_backup(basebackup_options *opt, DIR *tblspcdir)
|
|||||||
if (!(nextsegno == segno || currsegno == segno))
|
if (!(nextsegno == segno || currsegno == segno))
|
||||||
{
|
{
|
||||||
char nextfname[MAXFNAMELEN];
|
char nextfname[MAXFNAMELEN];
|
||||||
|
|
||||||
XLogFileName(nextfname, ThisTimeLineID, nextsegno);
|
XLogFileName(nextfname, ThisTimeLineID, nextsegno);
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errmsg("could not find WAL file \"%s\"", nextfname)));
|
(errmsg("could not find WAL file \"%s\"", nextfname)));
|
||||||
@ -332,6 +334,7 @@ perform_base_backup(basebackup_options *opt, DIR *tblspcdir)
|
|||||||
if (segno != endsegno)
|
if (segno != endsegno)
|
||||||
{
|
{
|
||||||
char endfname[MAXFNAMELEN];
|
char endfname[MAXFNAMELEN];
|
||||||
|
|
||||||
XLogFileName(endfname, ThisTimeLineID, endsegno);
|
XLogFileName(endfname, ThisTimeLineID, endsegno);
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errmsg("could not find WAL file \"%s\"", endfname)));
|
(errmsg("could not find WAL file \"%s\"", endfname)));
|
||||||
@ -415,6 +418,7 @@ perform_base_backup(basebackup_options *opt, DIR *tblspcdir)
|
|||||||
foreach(lc, historyFileList)
|
foreach(lc, historyFileList)
|
||||||
{
|
{
|
||||||
char *fname = lfirst(lc);
|
char *fname = lfirst(lc);
|
||||||
|
|
||||||
snprintf(pathbuf, MAXPGPATH, XLOGDIR "/%s", fname);
|
snprintf(pathbuf, MAXPGPATH, XLOGDIR "/%s", fname);
|
||||||
|
|
||||||
if (lstat(pathbuf, &statbuf) != 0)
|
if (lstat(pathbuf, &statbuf) != 0)
|
||||||
@ -657,6 +661,7 @@ SendXlogRecPtrResult(XLogRecPtr ptr, TimeLineID tli)
|
|||||||
pq_sendstring(&buf, "tli");
|
pq_sendstring(&buf, "tli");
|
||||||
pq_sendint(&buf, 0, 4); /* table oid */
|
pq_sendint(&buf, 0, 4); /* table oid */
|
||||||
pq_sendint(&buf, 0, 2); /* attnum */
|
pq_sendint(&buf, 0, 2); /* attnum */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* int8 may seem like a surprising data type for this, but in thory int4
|
* int8 may seem like a surprising data type for this, but in thory int4
|
||||||
* would not be wide enough for this, as TimeLineID is unsigned.
|
* would not be wide enough for this, as TimeLineID is unsigned.
|
||||||
@ -747,7 +752,8 @@ sendTablespace(char *path, bool sizeonly)
|
|||||||
TABLESPACE_VERSION_DIRECTORY);
|
TABLESPACE_VERSION_DIRECTORY);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Store a directory entry in the tar file so we get the permissions right.
|
* Store a directory entry in the tar file so we get the permissions
|
||||||
|
* right.
|
||||||
*/
|
*/
|
||||||
if (lstat(pathbuf, &statbuf) != 0)
|
if (lstat(pathbuf, &statbuf) != 0)
|
||||||
{
|
{
|
||||||
|
@ -214,7 +214,8 @@ libpqrcv_endstreaming(TimeLineID *next_tli)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* After COPY is finished, we should receive a result set indicating the
|
* After COPY is finished, we should receive a result set indicating the
|
||||||
* next timeline's ID, or just CommandComplete if the server was shut down.
|
* next timeline's ID, or just CommandComplete if the server was shut
|
||||||
|
* down.
|
||||||
*
|
*
|
||||||
* If we had not yet received CopyDone from the backend, PGRES_COPY_IN
|
* If we had not yet received CopyDone from the backend, PGRES_COPY_IN
|
||||||
* would also be possible. However, at the moment this function is only
|
* would also be possible. However, at the moment this function is only
|
||||||
|
@ -332,12 +332,13 @@ WalReceiverMain(void)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Get any missing history files. We do this always, even when we're
|
* Get any missing history files. We do this always, even when we're
|
||||||
* not interested in that timeline, so that if we're promoted to become
|
* not interested in that timeline, so that if we're promoted to
|
||||||
* the master later on, we don't select the same timeline that was
|
* become the master later on, we don't select the same timeline that
|
||||||
* already used in the current master. This isn't bullet-proof - you'll
|
* was already used in the current master. This isn't bullet-proof -
|
||||||
* need some external software to manage your cluster if you need to
|
* you'll need some external software to manage your cluster if you
|
||||||
* ensure that a unique timeline id is chosen in every case, but let's
|
* need to ensure that a unique timeline id is chosen in every case,
|
||||||
* avoid the confusion of timeline id collisions where we can.
|
* but let's avoid the confusion of timeline id collisions where we
|
||||||
|
* can.
|
||||||
*/
|
*/
|
||||||
WalRcvFetchTimeLineHistoryFiles(startpointTLI, primaryTLI);
|
WalRcvFetchTimeLineHistoryFiles(startpointTLI, primaryTLI);
|
||||||
|
|
||||||
@ -387,7 +388,8 @@ WalReceiverMain(void)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Emergency bailout if postmaster has died. This is to avoid
|
* Emergency bailout if postmaster has died. This is to avoid
|
||||||
* the necessity for manual cleanup of all postmaster children.
|
* the necessity for manual cleanup of all postmaster
|
||||||
|
* children.
|
||||||
*/
|
*/
|
||||||
if (!PostmasterIsAlive())
|
if (!PostmasterIsAlive())
|
||||||
exit(1);
|
exit(1);
|
||||||
@ -422,7 +424,10 @@ WalReceiverMain(void)
|
|||||||
{
|
{
|
||||||
if (len > 0)
|
if (len > 0)
|
||||||
{
|
{
|
||||||
/* Something was received from master, so reset timeout */
|
/*
|
||||||
|
* Something was received from master, so reset
|
||||||
|
* timeout
|
||||||
|
*/
|
||||||
last_recv_timestamp = GetCurrentTimestamp();
|
last_recv_timestamp = GetCurrentTimestamp();
|
||||||
ping_sent = false;
|
ping_sent = false;
|
||||||
XLogWalRcvProcessMsg(buf[0], &buf[1], len - 1);
|
XLogWalRcvProcessMsg(buf[0], &buf[1], len - 1);
|
||||||
@ -457,10 +462,11 @@ WalReceiverMain(void)
|
|||||||
/*
|
/*
|
||||||
* We didn't receive anything new. If we haven't heard
|
* We didn't receive anything new. If we haven't heard
|
||||||
* anything from the server for more than
|
* anything from the server for more than
|
||||||
* wal_receiver_timeout / 2, ping the server. Also, if it's
|
* wal_receiver_timeout / 2, ping the server. Also, if
|
||||||
* been longer than wal_receiver_status_interval since the
|
* it's been longer than wal_receiver_status_interval
|
||||||
* last update we sent, send a status update to the master
|
* since the last update we sent, send a status update to
|
||||||
* anyway, to report any progress in applying WAL.
|
* the master anyway, to report any progress in applying
|
||||||
|
* WAL.
|
||||||
*/
|
*/
|
||||||
bool requestReply = false;
|
bool requestReply = false;
|
||||||
|
|
||||||
@ -482,8 +488,8 @@ WalReceiverMain(void)
|
|||||||
(errmsg("terminating walreceiver due to timeout")));
|
(errmsg("terminating walreceiver due to timeout")));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We didn't receive anything new, for half of receiver
|
* We didn't receive anything new, for half of
|
||||||
* replication timeout. Ping the server.
|
* receiver replication timeout. Ping the server.
|
||||||
*/
|
*/
|
||||||
if (!ping_sent)
|
if (!ping_sent)
|
||||||
{
|
{
|
||||||
@ -511,9 +517,9 @@ WalReceiverMain(void)
|
|||||||
DisableWalRcvImmediateExit();
|
DisableWalRcvImmediateExit();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the server had switched to a new timeline that we didn't know
|
* If the server had switched to a new timeline that we didn't
|
||||||
* about when we began streaming, fetch its timeline history file
|
* know about when we began streaming, fetch its timeline history
|
||||||
* now.
|
* file now.
|
||||||
*/
|
*/
|
||||||
WalRcvFetchTimeLineHistoryFiles(startpointTLI, primaryTLI);
|
WalRcvFetchTimeLineHistoryFiles(startpointTLI, primaryTLI);
|
||||||
}
|
}
|
||||||
@ -614,8 +620,8 @@ WalRcvWaitForStartPosition(XLogRecPtr *startpoint, TimeLineID *startpointTLI)
|
|||||||
if (walrcv->walRcvState == WALRCV_STOPPING)
|
if (walrcv->walRcvState == WALRCV_STOPPING)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* We should've received SIGTERM if the startup process wants
|
* We should've received SIGTERM if the startup process wants us
|
||||||
* us to die, but might as well check it here too.
|
* to die, but might as well check it here too.
|
||||||
*/
|
*/
|
||||||
SpinLockRelease(&walrcv->mutex);
|
SpinLockRelease(&walrcv->mutex);
|
||||||
exit(1);
|
exit(1);
|
||||||
@ -664,8 +670,9 @@ WalRcvFetchTimeLineHistoryFiles(TimeLineID first, TimeLineID last)
|
|||||||
DisableWalRcvImmediateExit();
|
DisableWalRcvImmediateExit();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check that the filename on the master matches what we calculated
|
* Check that the filename on the master matches what we
|
||||||
* ourselves. This is just a sanity check, it should always match.
|
* calculated ourselves. This is just a sanity check, it should
|
||||||
|
* always match.
|
||||||
*/
|
*/
|
||||||
TLHistoryFileName(expectedfname, tli);
|
TLHistoryFileName(expectedfname, tli);
|
||||||
if (strcmp(fname, expectedfname) != 0)
|
if (strcmp(fname, expectedfname) != 0)
|
||||||
@ -890,8 +897,8 @@ XLogWalRcvWrite(char *buf, Size nbytes, XLogRecPtr recptr)
|
|||||||
XLogFileNameP(recvFileTLI, recvSegNo))));
|
XLogFileNameP(recvFileTLI, recvSegNo))));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create .done file forcibly to prevent the streamed segment from
|
* Create .done file forcibly to prevent the streamed segment
|
||||||
* being archived later.
|
* from being archived later.
|
||||||
*/
|
*/
|
||||||
XLogFileName(xlogfname, recvFileTLI, recvSegNo);
|
XLogFileName(xlogfname, recvFileTLI, recvSegNo);
|
||||||
XLogArchiveForceDone(xlogfname);
|
XLogArchiveForceDone(xlogfname);
|
||||||
|
@ -96,6 +96,7 @@ bool am_cascading_walsender = false; /* Am I cascading WAL to
|
|||||||
int max_wal_senders = 0; /* the maximum number of concurrent walsenders */
|
int max_wal_senders = 0; /* the maximum number of concurrent walsenders */
|
||||||
int wal_sender_timeout = 60 * 1000; /* maximum time to send one
|
int wal_sender_timeout = 60 * 1000; /* maximum time to send one
|
||||||
* WAL data message */
|
* WAL data message */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* State for WalSndWakeupRequest
|
* State for WalSndWakeupRequest
|
||||||
*/
|
*/
|
||||||
@ -138,6 +139,7 @@ static StringInfoData tmpbuf;
|
|||||||
* Timestamp of the last receipt of the reply from the standby.
|
* Timestamp of the last receipt of the reply from the standby.
|
||||||
*/
|
*/
|
||||||
static TimestampTz last_reply_timestamp;
|
static TimestampTz last_reply_timestamp;
|
||||||
|
|
||||||
/* Have we sent a heartbeat message asking for reply, since last reply? */
|
/* Have we sent a heartbeat message asking for reply, since last reply? */
|
||||||
static bool ping_sent = false;
|
static bool ping_sent = false;
|
||||||
|
|
||||||
@ -322,8 +324,8 @@ SendTimeLineHistory(TimeLineHistoryCmd *cmd)
|
|||||||
off_t bytesleft;
|
off_t bytesleft;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Reply with a result set with one row, and two columns. The first col
|
* Reply with a result set with one row, and two columns. The first col is
|
||||||
* is the name of the history file, 2nd is the contents.
|
* the name of the history file, 2nd is the contents.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
TLHistoryFileName(histfname, cmd->timeline);
|
TLHistoryFileName(histfname, cmd->timeline);
|
||||||
@ -420,8 +422,8 @@ StartReplication(StartReplicationCmd *cmd)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Select the timeline. If it was given explicitly by the client, use
|
* Select the timeline. If it was given explicitly by the client, use
|
||||||
* that. Otherwise use the timeline of the last replayed record, which
|
* that. Otherwise use the timeline of the last replayed record, which is
|
||||||
* is kept in ThisTimeLineID.
|
* kept in ThisTimeLineID.
|
||||||
*/
|
*/
|
||||||
if (am_cascading_walsender)
|
if (am_cascading_walsender)
|
||||||
{
|
{
|
||||||
@ -448,8 +450,8 @@ StartReplication(StartReplicationCmd *cmd)
|
|||||||
sendTimeLineIsHistoric = true;
|
sendTimeLineIsHistoric = true;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check that the timeline the client requested for exists, and the
|
* Check that the timeline the client requested for exists, and
|
||||||
* requested start location is on that timeline.
|
* the requested start location is on that timeline.
|
||||||
*/
|
*/
|
||||||
timeLineHistory = readTimeLineHistory(ThisTimeLineID);
|
timeLineHistory = readTimeLineHistory(ThisTimeLineID);
|
||||||
switchpoint = tliSwitchPoint(cmd->timeline, timeLineHistory,
|
switchpoint = tliSwitchPoint(cmd->timeline, timeLineHistory,
|
||||||
@ -461,14 +463,14 @@ StartReplication(StartReplicationCmd *cmd)
|
|||||||
* requested startpoint is on that timeline in our history.
|
* requested startpoint is on that timeline in our history.
|
||||||
*
|
*
|
||||||
* This is quite loose on purpose. We only check that we didn't
|
* This is quite loose on purpose. We only check that we didn't
|
||||||
* fork off the requested timeline before the switchpoint. We don't
|
* fork off the requested timeline before the switchpoint. We
|
||||||
* check that we switched *to* it before the requested starting
|
* don't check that we switched *to* it before the requested
|
||||||
* point. This is because the client can legitimately request to
|
* starting point. This is because the client can legitimately
|
||||||
* start replication from the beginning of the WAL segment that
|
* request to start replication from the beginning of the WAL
|
||||||
* contains switchpoint, but on the new timeline, so that it
|
* segment that contains switchpoint, but on the new timeline, so
|
||||||
* doesn't end up with a partial segment. If you ask for a too old
|
* that it doesn't end up with a partial segment. If you ask for a
|
||||||
* starting point, you'll get an error later when we fail to find
|
* too old starting point, you'll get an error later when we fail
|
||||||
* the requested WAL segment in pg_xlog.
|
* to find the requested WAL segment in pg_xlog.
|
||||||
*
|
*
|
||||||
* XXX: we could be more strict here and only allow a startpoint
|
* XXX: we could be more strict here and only allow a startpoint
|
||||||
* that's older than the switchpoint, if it it's still in the same
|
* that's older than the switchpoint, if it it's still in the same
|
||||||
@ -503,12 +505,13 @@ StartReplication(StartReplicationCmd *cmd)
|
|||||||
if (!sendTimeLineIsHistoric || cmd->startpoint < sendTimeLineValidUpto)
|
if (!sendTimeLineIsHistoric || cmd->startpoint < sendTimeLineValidUpto)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* When we first start replication the standby will be behind the primary.
|
* When we first start replication the standby will be behind the
|
||||||
* For some applications, for example, synchronous replication, it is
|
* primary. For some applications, for example, synchronous
|
||||||
* important to have a clear state for this initial catchup mode, so we
|
* replication, it is important to have a clear state for this initial
|
||||||
* can trigger actions when we change streaming state later. We may stay
|
* catchup mode, so we can trigger actions when we change streaming
|
||||||
* in this state for a long time, which is exactly why we want to be able
|
* state later. We may stay in this state for a long time, which is
|
||||||
* to monitor whether or not we are still here.
|
* exactly why we want to be able to monitor whether or not we are
|
||||||
|
* still here.
|
||||||
*/
|
*/
|
||||||
WalSndSetState(WALSNDSTATE_CATCHUP);
|
WalSndSetState(WALSNDSTATE_CATCHUP);
|
||||||
|
|
||||||
@ -582,6 +585,7 @@ StartReplication(StartReplicationCmd *cmd)
|
|||||||
pq_sendstring(&buf, "next_tli");
|
pq_sendstring(&buf, "next_tli");
|
||||||
pq_sendint(&buf, 0, 4); /* table oid */
|
pq_sendint(&buf, 0, 4); /* table oid */
|
||||||
pq_sendint(&buf, 0, 2); /* attnum */
|
pq_sendint(&buf, 0, 2); /* attnum */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* int8 may seem like a surprising data type for this, but in theory
|
* int8 may seem like a surprising data type for this, but in theory
|
||||||
* int4 would not be wide enough for this, as TimeLineID is unsigned.
|
* int4 would not be wide enough for this, as TimeLineID is unsigned.
|
||||||
@ -932,11 +936,11 @@ ProcessStandbyHSFeedbackMessage(void)
|
|||||||
* cleanup conflicts on the standby server.
|
* cleanup conflicts on the standby server.
|
||||||
*
|
*
|
||||||
* There is a small window for a race condition here: although we just
|
* There is a small window for a race condition here: although we just
|
||||||
* checked that feedbackXmin precedes nextXid, the nextXid could have gotten
|
* checked that feedbackXmin precedes nextXid, the nextXid could have
|
||||||
* advanced between our fetching it and applying the xmin below, perhaps
|
* gotten advanced between our fetching it and applying the xmin below,
|
||||||
* far enough to make feedbackXmin wrap around. In that case the xmin we
|
* perhaps far enough to make feedbackXmin wrap around. In that case the
|
||||||
* set here would be "in the future" and have no effect. No point in
|
* xmin we set here would be "in the future" and have no effect. No point
|
||||||
* worrying about this since it's too late to save the desired data
|
* in worrying about this since it's too late to save the desired data
|
||||||
* anyway. Assuming that the standby sends us an increasing sequence of
|
* anyway. Assuming that the standby sends us an increasing sequence of
|
||||||
* xmins, this could only happen during the first reply cycle, else our
|
* xmins, this could only happen during the first reply cycle, else our
|
||||||
* own xmin would prevent nextXid from advancing so far.
|
* own xmin would prevent nextXid from advancing so far.
|
||||||
@ -969,8 +973,8 @@ WalSndLoop(void)
|
|||||||
ping_sent = false;
|
ping_sent = false;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Loop until we reach the end of this timeline or the client requests
|
* Loop until we reach the end of this timeline or the client requests to
|
||||||
* to stop streaming.
|
* stop streaming.
|
||||||
*/
|
*/
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
@ -1082,8 +1086,8 @@ WalSndLoop(void)
|
|||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* If half of wal_sender_timeout has lapsed without receiving
|
* If half of wal_sender_timeout has lapsed without receiving
|
||||||
* any reply from standby, send a keep-alive message to standby
|
* any reply from standby, send a keep-alive message to
|
||||||
* requesting an immediate reply.
|
* standby requesting an immediate reply.
|
||||||
*/
|
*/
|
||||||
timeout = TimestampTzPlusMilliseconds(last_reply_timestamp,
|
timeout = TimestampTzPlusMilliseconds(last_reply_timestamp,
|
||||||
wal_sender_timeout / 2);
|
wal_sender_timeout / 2);
|
||||||
@ -1133,6 +1137,7 @@ WalSndLoop(void)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
send_failure:
|
send_failure:
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get here on send failure. Clean up and exit.
|
* Get here on send failure. Clean up and exit.
|
||||||
*
|
*
|
||||||
@ -1431,16 +1436,16 @@ XLogSend(bool *caughtup)
|
|||||||
/*
|
/*
|
||||||
* Streaming the latest timeline on a standby.
|
* Streaming the latest timeline on a standby.
|
||||||
*
|
*
|
||||||
* Attempt to send all WAL that has already been replayed, so that
|
* Attempt to send all WAL that has already been replayed, so that we
|
||||||
* we know it's valid. If we're receiving WAL through streaming
|
* know it's valid. If we're receiving WAL through streaming
|
||||||
* replication, it's also OK to send any WAL that has been received
|
* replication, it's also OK to send any WAL that has been received
|
||||||
* but not replayed.
|
* but not replayed.
|
||||||
*
|
*
|
||||||
* The timeline we're recovering from can change, or we can be
|
* The timeline we're recovering from can change, or we can be
|
||||||
* promoted. In either case, the current timeline becomes historic.
|
* promoted. In either case, the current timeline becomes historic. We
|
||||||
* We need to detect that so that we don't try to stream past the
|
* need to detect that so that we don't try to stream past the point
|
||||||
* point where we switched to another timeline. We check for promotion
|
* where we switched to another timeline. We check for promotion or
|
||||||
* or timeline switch after calculating FlushPtr, to avoid a race
|
* timeline switch after calculating FlushPtr, to avoid a race
|
||||||
* condition: if the timeline becomes historic just after we checked
|
* condition: if the timeline becomes historic just after we checked
|
||||||
* that it was still current, it's still be OK to stream it up to the
|
* that it was still current, it's still be OK to stream it up to the
|
||||||
* FlushPtr that was calculated before it became historic.
|
* FlushPtr that was calculated before it became historic.
|
||||||
@ -1509,13 +1514,14 @@ XLogSend(bool *caughtup)
|
|||||||
* forked to the next timeline, stop streaming.
|
* forked to the next timeline, stop streaming.
|
||||||
*
|
*
|
||||||
* Note: We might already have sent WAL > sendTimeLineValidUpto. The
|
* Note: We might already have sent WAL > sendTimeLineValidUpto. The
|
||||||
* startup process will normally replay all WAL that has been received from
|
* startup process will normally replay all WAL that has been received
|
||||||
* the master, before promoting, but if the WAL streaming is terminated at
|
* from the master, before promoting, but if the WAL streaming is
|
||||||
* a WAL page boundary, the valid portion of the timeline might end in the
|
* terminated at a WAL page boundary, the valid portion of the timeline
|
||||||
* middle of a WAL record. We might've already sent the first half of that
|
* might end in the middle of a WAL record. We might've already sent the
|
||||||
* partial WAL record to the cascading standby, so that sentPtr >
|
* first half of that partial WAL record to the cascading standby, so that
|
||||||
* sendTimeLineValidUpto. That's OK; the cascading standby can't replay the
|
* sentPtr > sendTimeLineValidUpto. That's OK; the cascading standby can't
|
||||||
* partial WAL record either, so it can still follow our timeline switch.
|
* replay the partial WAL record either, so it can still follow our
|
||||||
|
* timeline switch.
|
||||||
*/
|
*/
|
||||||
if (sendTimeLineIsHistoric && sendTimeLineValidUpto <= sentPtr)
|
if (sendTimeLineIsHistoric && sendTimeLineValidUpto <= sentPtr)
|
||||||
{
|
{
|
||||||
@ -1651,8 +1657,8 @@ GetStandbyFlushRecPtr(void)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* We can safely send what's already been replayed. Also, if walreceiver
|
* We can safely send what's already been replayed. Also, if walreceiver
|
||||||
* is streaming WAL from the same timeline, we can send anything that
|
* is streaming WAL from the same timeline, we can send anything that it
|
||||||
* it has streamed, but hasn't been replayed yet.
|
* has streamed, but hasn't been replayed yet.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
receivePtr = GetWalRcvWriteRecPtr(NULL, &receiveTLI);
|
receivePtr = GetWalRcvWriteRecPtr(NULL, &receiveTLI);
|
||||||
|
@ -541,9 +541,9 @@ DefineQueryRewrite(char *rulename,
|
|||||||
DeleteSystemAttributeTuples(event_relid);
|
DeleteSystemAttributeTuples(event_relid);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Drop the toast table if any. (This won't take care of updating
|
* Drop the toast table if any. (This won't take care of updating the
|
||||||
* the toast fields in the relation's own pg_class entry; we handle
|
* toast fields in the relation's own pg_class entry; we handle that
|
||||||
* that below.)
|
* below.)
|
||||||
*/
|
*/
|
||||||
if (OidIsValid(toastrelid))
|
if (OidIsValid(toastrelid))
|
||||||
{
|
{
|
||||||
|
@ -131,9 +131,9 @@ AcquireRewriteLocks(Query *parsetree, bool forUpdatePushedDown)
|
|||||||
*
|
*
|
||||||
* If the relation is the query's result relation, then we
|
* If the relation is the query's result relation, then we
|
||||||
* need RowExclusiveLock. Otherwise, check to see if the
|
* need RowExclusiveLock. Otherwise, check to see if the
|
||||||
* relation is accessed FOR [KEY] UPDATE/SHARE or not. We can't
|
* relation is accessed FOR [KEY] UPDATE/SHARE or not. We
|
||||||
* just grab AccessShareLock because then the executor would
|
* can't just grab AccessShareLock because then the executor
|
||||||
* be trying to upgrade the lock, leading to possible
|
* would be trying to upgrade the lock, leading to possible
|
||||||
* deadlocks.
|
* deadlocks.
|
||||||
*/
|
*/
|
||||||
if (rt_index == parsetree->resultRelation)
|
if (rt_index == parsetree->resultRelation)
|
||||||
@ -1375,8 +1375,8 @@ ApplyRetrieveRule(Query *parsetree,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If FOR [KEY] UPDATE/SHARE of view, be sure we get right initial lock on the
|
* If FOR [KEY] UPDATE/SHARE of view, be sure we get right initial lock on
|
||||||
* relations it references.
|
* the relations it references.
|
||||||
*/
|
*/
|
||||||
rc = get_parse_rowmark(parsetree, rt_index);
|
rc = get_parse_rowmark(parsetree, rt_index);
|
||||||
forUpdatePushedDown |= (rc != NULL);
|
forUpdatePushedDown |= (rc != NULL);
|
||||||
@ -1423,9 +1423,9 @@ ApplyRetrieveRule(Query *parsetree,
|
|||||||
rte->modifiedCols = NULL;
|
rte->modifiedCols = NULL;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If FOR [KEY] UPDATE/SHARE of view, mark all the contained tables as implicit
|
* If FOR [KEY] UPDATE/SHARE of view, mark all the contained tables as
|
||||||
* FOR [KEY] UPDATE/SHARE, the same as the parser would have done if the view's
|
* implicit FOR [KEY] UPDATE/SHARE, the same as the parser would have done
|
||||||
* subquery had been written out explicitly.
|
* if the view's subquery had been written out explicitly.
|
||||||
*
|
*
|
||||||
* Note: we don't consider forUpdatePushedDown here; such marks will be
|
* Note: we don't consider forUpdatePushedDown here; such marks will be
|
||||||
* made by recursing from the upper level in markQueryForLocking.
|
* made by recursing from the upper level in markQueryForLocking.
|
||||||
@ -2089,9 +2089,9 @@ relation_is_updatable(Oid reloid, int req_events)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* If the relation doesn't exist, say "false" rather than throwing an
|
* If the relation doesn't exist, say "false" rather than throwing an
|
||||||
* error. This is helpful since scanning an information_schema view
|
* error. This is helpful since scanning an information_schema view under
|
||||||
* under MVCC rules can result in referencing rels that were just
|
* MVCC rules can result in referencing rels that were just deleted
|
||||||
* deleted according to a SnapshotNow probe.
|
* according to a SnapshotNow probe.
|
||||||
*/
|
*/
|
||||||
if (rel == NULL)
|
if (rel == NULL)
|
||||||
return false;
|
return false;
|
||||||
@ -2680,10 +2680,10 @@ RewriteQuery(Query *parsetree, List *rewrite_events)
|
|||||||
parsetree = rewriteTargetView(parsetree, rt_entry_relation);
|
parsetree = rewriteTargetView(parsetree, rt_entry_relation);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* At this point product_queries contains any DO ALSO rule actions.
|
* At this point product_queries contains any DO ALSO rule
|
||||||
* Add the rewritten query before or after those. This must match
|
* actions. Add the rewritten query before or after those. This
|
||||||
* the handling the original query would have gotten below, if
|
* must match the handling the original query would have gotten
|
||||||
* we allowed it to be included again.
|
* below, if we allowed it to be included again.
|
||||||
*/
|
*/
|
||||||
if (parsetree->commandType == CMD_INSERT)
|
if (parsetree->commandType == CMD_INSERT)
|
||||||
product_queries = lcons(parsetree, product_queries);
|
product_queries = lcons(parsetree, product_queries);
|
||||||
|
@ -1406,6 +1406,7 @@ ReplaceVarsFromTargetList_callback(Var *var,
|
|||||||
return (Node *) var;
|
return (Node *) var;
|
||||||
|
|
||||||
case REPLACEVARS_SUBSTITUTE_NULL:
|
case REPLACEVARS_SUBSTITUTE_NULL:
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If Var is of domain type, we should add a CoerceToDomain
|
* If Var is of domain type, we should add a CoerceToDomain
|
||||||
* node, in case there is a NOT NULL domain constraint.
|
* node, in case there is a NOT NULL domain constraint.
|
||||||
|
@ -1220,7 +1220,8 @@ BufferSync(int flags)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Unless this is a shutdown checkpoint, we write only permanent, dirty
|
* Unless this is a shutdown checkpoint, we write only permanent, dirty
|
||||||
* buffers. But at shutdown or end of recovery, we write all dirty buffers.
|
* buffers. But at shutdown or end of recovery, we write all dirty
|
||||||
|
* buffers.
|
||||||
*/
|
*/
|
||||||
if (!((flags & CHECKPOINT_IS_SHUTDOWN) || (flags & CHECKPOINT_END_OF_RECOVERY)))
|
if (!((flags & CHECKPOINT_IS_SHUTDOWN) || (flags & CHECKPOINT_END_OF_RECOVERY)))
|
||||||
mask |= BM_PERMANENT;
|
mask |= BM_PERMANENT;
|
||||||
@ -1964,14 +1965,14 @@ FlushBuffer(volatile BufferDesc *buf, SMgrRelation reln)
|
|||||||
* However, this rule does not apply to unlogged relations, which will be
|
* However, this rule does not apply to unlogged relations, which will be
|
||||||
* lost after a crash anyway. Most unlogged relation pages do not bear
|
* lost after a crash anyway. Most unlogged relation pages do not bear
|
||||||
* LSNs since we never emit WAL records for them, and therefore flushing
|
* LSNs since we never emit WAL records for them, and therefore flushing
|
||||||
* up through the buffer LSN would be useless, but harmless. However, GiST
|
* up through the buffer LSN would be useless, but harmless. However,
|
||||||
* indexes use LSNs internally to track page-splits, and therefore unlogged
|
* GiST indexes use LSNs internally to track page-splits, and therefore
|
||||||
* GiST pages bear "fake" LSNs generated by GetFakeLSNForUnloggedRel. It
|
* unlogged GiST pages bear "fake" LSNs generated by
|
||||||
* is unlikely but possible that the fake LSN counter could advance past
|
* GetFakeLSNForUnloggedRel. It is unlikely but possible that the fake
|
||||||
* the WAL insertion point; and if it did happen, attempting to flush WAL
|
* LSN counter could advance past the WAL insertion point; and if it did
|
||||||
* through that location would fail, with disastrous system-wide
|
* happen, attempting to flush WAL through that location would fail, with
|
||||||
* consequences. To make sure that can't happen, skip the flush if the
|
* disastrous system-wide consequences. To make sure that can't happen,
|
||||||
* buffer isn't permanent.
|
* skip the flush if the buffer isn't permanent.
|
||||||
*/
|
*/
|
||||||
if (buf->flags & BM_PERMANENT)
|
if (buf->flags & BM_PERMANENT)
|
||||||
XLogFlush(recptr);
|
XLogFlush(recptr);
|
||||||
@ -2204,8 +2205,8 @@ DropRelFileNodesAllBuffers(RelFileNodeBackend *rnodes, int nnodes)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If there are no non-local relations, then we're done. Release the memory
|
* If there are no non-local relations, then we're done. Release the
|
||||||
* and return.
|
* memory and return.
|
||||||
*/
|
*/
|
||||||
if (n == 0)
|
if (n == 0)
|
||||||
{
|
{
|
||||||
@ -2215,8 +2216,8 @@ DropRelFileNodesAllBuffers(RelFileNodeBackend *rnodes, int nnodes)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* For low number of relations to drop just use a simple walk through, to
|
* For low number of relations to drop just use a simple walk through, to
|
||||||
* save the bsearch overhead. The threshold to use is rather a guess than a
|
* save the bsearch overhead. The threshold to use is rather a guess than
|
||||||
* exactly determined value, as it depends on many factors (CPU and RAM
|
* a exactly determined value, as it depends on many factors (CPU and RAM
|
||||||
* speeds, amount of shared buffers etc.).
|
* speeds, amount of shared buffers etc.).
|
||||||
*/
|
*/
|
||||||
use_bsearch = n > DROP_RELS_BSEARCH_THRESHOLD;
|
use_bsearch = n > DROP_RELS_BSEARCH_THRESHOLD;
|
||||||
@ -2605,13 +2606,13 @@ MarkBufferDirtyHint(Buffer buffer)
|
|||||||
/*
|
/*
|
||||||
* This routine might get called many times on the same page, if we are
|
* This routine might get called many times on the same page, if we are
|
||||||
* making the first scan after commit of an xact that added/deleted many
|
* making the first scan after commit of an xact that added/deleted many
|
||||||
* tuples. So, be as quick as we can if the buffer is already dirty. We do
|
* tuples. So, be as quick as we can if the buffer is already dirty. We
|
||||||
* this by not acquiring spinlock if it looks like the status bits are
|
* do this by not acquiring spinlock if it looks like the status bits are
|
||||||
* already set. Since we make this test unlocked, there's a chance we
|
* already set. Since we make this test unlocked, there's a chance we
|
||||||
* might fail to notice that the flags have just been cleared, and failed
|
* might fail to notice that the flags have just been cleared, and failed
|
||||||
* to reset them, due to memory-ordering issues. But since this function
|
* to reset them, due to memory-ordering issues. But since this function
|
||||||
* is only intended to be used in cases where failing to write out the data
|
* is only intended to be used in cases where failing to write out the
|
||||||
* would be harmless anyway, it doesn't really matter.
|
* data would be harmless anyway, it doesn't really matter.
|
||||||
*/
|
*/
|
||||||
if ((bufHdr->flags & (BM_DIRTY | BM_JUST_DIRTIED)) !=
|
if ((bufHdr->flags & (BM_DIRTY | BM_JUST_DIRTIED)) !=
|
||||||
(BM_DIRTY | BM_JUST_DIRTIED))
|
(BM_DIRTY | BM_JUST_DIRTIED))
|
||||||
@ -2622,21 +2623,20 @@ MarkBufferDirtyHint(Buffer buffer)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* If checksums are enabled, and the buffer is permanent, then a full
|
* If checksums are enabled, and the buffer is permanent, then a full
|
||||||
* page image may be required even for some hint bit updates to protect
|
* page image may be required even for some hint bit updates to
|
||||||
* against torn pages. This full page image is only necessary if the
|
* protect against torn pages. This full page image is only necessary
|
||||||
* hint bit update is the first change to the page since the last
|
* if the hint bit update is the first change to the page since the
|
||||||
* checkpoint.
|
* last checkpoint.
|
||||||
*
|
*
|
||||||
* We don't check full_page_writes here because that logic is
|
* We don't check full_page_writes here because that logic is included
|
||||||
* included when we call XLogInsert() since the value changes
|
* when we call XLogInsert() since the value changes dynamically.
|
||||||
* dynamically.
|
|
||||||
*/
|
*/
|
||||||
if (DataChecksumsEnabled() && (bufHdr->flags & BM_PERMANENT))
|
if (DataChecksumsEnabled() && (bufHdr->flags & BM_PERMANENT))
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* If we're in recovery we cannot dirty a page because of a hint.
|
* If we're in recovery we cannot dirty a page because of a hint.
|
||||||
* We can set the hint, just not dirty the page as a result so
|
* We can set the hint, just not dirty the page as a result so the
|
||||||
* the hint is lost when we evict the page or shutdown.
|
* hint is lost when we evict the page or shutdown.
|
||||||
*
|
*
|
||||||
* See src/backend/storage/page/README for longer discussion.
|
* See src/backend/storage/page/README for longer discussion.
|
||||||
*/
|
*/
|
||||||
@ -2646,21 +2646,21 @@ MarkBufferDirtyHint(Buffer buffer)
|
|||||||
/*
|
/*
|
||||||
* If the block is already dirty because we either made a change
|
* If the block is already dirty because we either made a change
|
||||||
* or set a hint already, then we don't need to write a full page
|
* or set a hint already, then we don't need to write a full page
|
||||||
* image. Note that aggressive cleaning of blocks
|
* image. Note that aggressive cleaning of blocks dirtied by hint
|
||||||
* dirtied by hint bit setting would increase the call rate.
|
* bit setting would increase the call rate. Bulk setting of hint
|
||||||
* Bulk setting of hint bits would reduce the call rate...
|
* bits would reduce the call rate...
|
||||||
*
|
*
|
||||||
* We must issue the WAL record before we mark the buffer dirty.
|
* We must issue the WAL record before we mark the buffer dirty.
|
||||||
* Otherwise we might write the page before we write the WAL.
|
* Otherwise we might write the page before we write the WAL. That
|
||||||
* That causes a race condition, since a checkpoint might occur
|
* causes a race condition, since a checkpoint might occur between
|
||||||
* between writing the WAL record and marking the buffer dirty.
|
* writing the WAL record and marking the buffer dirty. We solve
|
||||||
* We solve that with a kluge, but one that is already in use
|
* that with a kluge, but one that is already in use during
|
||||||
* during transaction commit to prevent race conditions.
|
* transaction commit to prevent race conditions. Basically, we
|
||||||
* Basically, we simply prevent the checkpoint WAL record from
|
* simply prevent the checkpoint WAL record from being written
|
||||||
* being written until we have marked the buffer dirty. We don't
|
* until we have marked the buffer dirty. We don't start the
|
||||||
* start the checkpoint flush until we have marked dirty, so our
|
* checkpoint flush until we have marked dirty, so our checkpoint
|
||||||
* checkpoint must flush the change to disk successfully or the
|
* must flush the change to disk successfully or the checkpoint
|
||||||
* checkpoint never gets written, so crash recovery will fix.
|
* never gets written, so crash recovery will fix.
|
||||||
*
|
*
|
||||||
* It's possible we may enter here without an xid, so it is
|
* It's possible we may enter here without an xid, so it is
|
||||||
* essential that CreateCheckpoint waits for virtual transactions
|
* essential that CreateCheckpoint waits for virtual transactions
|
||||||
@ -2677,13 +2677,13 @@ MarkBufferDirtyHint(Buffer buffer)
|
|||||||
dirtied = true; /* Means "will be dirtied by this action" */
|
dirtied = true; /* Means "will be dirtied by this action" */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set the page LSN if we wrote a backup block. We aren't
|
* Set the page LSN if we wrote a backup block. We aren't supposed
|
||||||
* supposed to set this when only holding a share lock but
|
* to set this when only holding a share lock but as long as we
|
||||||
* as long as we serialise it somehow we're OK. We choose to
|
* serialise it somehow we're OK. We choose to set LSN while
|
||||||
* set LSN while holding the buffer header lock, which causes
|
* holding the buffer header lock, which causes any reader of an
|
||||||
* any reader of an LSN who holds only a share lock to also
|
* LSN who holds only a share lock to also obtain a buffer header
|
||||||
* obtain a buffer header lock before using PageGetLSN(),
|
* lock before using PageGetLSN(), which is enforced in
|
||||||
* which is enforced in BufferGetLSNAtomic().
|
* BufferGetLSNAtomic().
|
||||||
*
|
*
|
||||||
* If checksums are enabled, you might think we should reset the
|
* If checksums are enabled, you might think we should reset the
|
||||||
* checksum here. That will happen when the page is written
|
* checksum here. That will happen when the page is written
|
||||||
|
@ -1429,11 +1429,11 @@ GetSnapshotData(Snapshot snapshot)
|
|||||||
* depending upon when the snapshot was taken, or change normal
|
* depending upon when the snapshot was taken, or change normal
|
||||||
* snapshot processing so it matches.
|
* snapshot processing so it matches.
|
||||||
*
|
*
|
||||||
* Note: It is possible for recovery to end before we finish taking the
|
* Note: It is possible for recovery to end before we finish taking
|
||||||
* snapshot, and for newly assigned transaction ids to be added to the
|
* the snapshot, and for newly assigned transaction ids to be added to
|
||||||
* ProcArray. xmax cannot change while we hold ProcArrayLock, so those
|
* the ProcArray. xmax cannot change while we hold ProcArrayLock, so
|
||||||
* newly added transaction ids would be filtered away, so we need not
|
* those newly added transaction ids would be filtered away, so we
|
||||||
* be concerned about them.
|
* need not be concerned about them.
|
||||||
*/
|
*/
|
||||||
subcount = KnownAssignedXidsGetAndSetXmin(snapshot->subxip, &xmin,
|
subcount = KnownAssignedXidsGetAndSetXmin(snapshot->subxip, &xmin,
|
||||||
xmax);
|
xmax);
|
||||||
@ -1688,8 +1688,8 @@ GetRunningTransactionData(void)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Top-level XID of a transaction is always less than any of
|
* Top-level XID of a transaction is always less than any of
|
||||||
* its subxids, so we don't need to check if any of the subxids
|
* its subxids, so we don't need to check if any of the
|
||||||
* are smaller than oldestRunningXid
|
* subxids are smaller than oldestRunningXid
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -443,10 +443,10 @@ ResolveRecoveryConflictWithBufferPin(void)
|
|||||||
ProcWaitForSignal();
|
ProcWaitForSignal();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Clear any timeout requests established above. We assume here that
|
* Clear any timeout requests established above. We assume here that the
|
||||||
* the Startup process doesn't have any other timeouts than what this
|
* Startup process doesn't have any other timeouts than what this function
|
||||||
* function uses. If that stops being true, we could cancel the
|
* uses. If that stops being true, we could cancel the timeouts
|
||||||
* timeouts individually, but that'd be slower.
|
* individually, but that'd be slower.
|
||||||
*/
|
*/
|
||||||
disable_all_timeouts(false);
|
disable_all_timeouts(false);
|
||||||
}
|
}
|
||||||
|
@ -2333,8 +2333,8 @@ LockReassignOwner(LOCALLOCK *locallock, ResourceOwner parent)
|
|||||||
int ip = -1;
|
int ip = -1;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Scan to see if there are any locks belonging to current owner or
|
* Scan to see if there are any locks belonging to current owner or its
|
||||||
* its parent
|
* parent
|
||||||
*/
|
*/
|
||||||
lockOwners = locallock->lockOwners;
|
lockOwners = locallock->lockOwners;
|
||||||
for (i = locallock->numLockOwners - 1; i >= 0; i--)
|
for (i = locallock->numLockOwners - 1; i >= 0; i--)
|
||||||
@ -2690,9 +2690,9 @@ GetLockConflicts(const LOCKTAG *locktag, LOCKMODE lockmode)
|
|||||||
LWLockAcquire(proc->backendLock, LW_SHARED);
|
LWLockAcquire(proc->backendLock, LW_SHARED);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the target backend isn't referencing the same database as the
|
* If the target backend isn't referencing the same database as
|
||||||
* lock, then we needn't examine the individual relation IDs at
|
* the lock, then we needn't examine the individual relation IDs
|
||||||
* all; none of them can be relevant.
|
* at all; none of them can be relevant.
|
||||||
*
|
*
|
||||||
* See FastPathTransferLocks() for discussion of why we do this
|
* See FastPathTransferLocks() for discussion of why we do this
|
||||||
* test after acquiring the lock.
|
* test after acquiring the lock.
|
||||||
@ -3165,8 +3165,8 @@ PostPrepare_Locks(TransactionId xid)
|
|||||||
* our procLink chain and put it into the new proc's chain, too.
|
* our procLink chain and put it into the new proc's chain, too.
|
||||||
*
|
*
|
||||||
* Note: the updated proclock hash key will still belong to the
|
* Note: the updated proclock hash key will still belong to the
|
||||||
* same hash partition, cf proclock_hash(). So the partition
|
* same hash partition, cf proclock_hash(). So the partition lock
|
||||||
* lock we already hold is sufficient for this.
|
* we already hold is sufficient for this.
|
||||||
*/
|
*/
|
||||||
SHMQueueDelete(&proclock->procLink);
|
SHMQueueDelete(&proclock->procLink);
|
||||||
|
|
||||||
@ -3177,9 +3177,9 @@ PostPrepare_Locks(TransactionId xid)
|
|||||||
proclocktag.myProc = newproc;
|
proclocktag.myProc = newproc;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Update the proclock. We should not find any existing entry
|
* Update the proclock. We should not find any existing entry for
|
||||||
* for the same hash key, since there can be only one entry for
|
* the same hash key, since there can be only one entry for any
|
||||||
* any given lock with my own proc.
|
* given lock with my own proc.
|
||||||
*/
|
*/
|
||||||
if (!hash_update_hash_key(LockMethodProcLockHash,
|
if (!hash_update_hash_key(LockMethodProcLockHash,
|
||||||
(void *) proclock,
|
(void *) proclock,
|
||||||
|
@ -1575,8 +1575,8 @@ GetSerializableTransactionSnapshot(Snapshot snapshot)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Can't use serializable mode while recovery is still active, as it is,
|
* Can't use serializable mode while recovery is still active, as it is,
|
||||||
* for example, on a hot standby. We could get here despite the check
|
* for example, on a hot standby. We could get here despite the check in
|
||||||
* in check_XactIsoLevel() if default_transaction_isolation is set to
|
* check_XactIsoLevel() if default_transaction_isolation is set to
|
||||||
* serializable, so phrase the hint accordingly.
|
* serializable, so phrase the hint accordingly.
|
||||||
*/
|
*/
|
||||||
if (RecoveryInProgress())
|
if (RecoveryInProgress())
|
||||||
|
@ -186,8 +186,8 @@ InitProcGlobal(void)
|
|||||||
* five separate consumers: (1) normal backends, (2) autovacuum workers
|
* five separate consumers: (1) normal backends, (2) autovacuum workers
|
||||||
* and the autovacuum launcher, (3) background workers, (4) auxiliary
|
* and the autovacuum launcher, (3) background workers, (4) auxiliary
|
||||||
* processes, and (5) prepared transactions. Each PGPROC structure is
|
* processes, and (5) prepared transactions. Each PGPROC structure is
|
||||||
* dedicated to exactly one of these purposes, and they do not move between
|
* dedicated to exactly one of these purposes, and they do not move
|
||||||
* groups.
|
* between groups.
|
||||||
*/
|
*/
|
||||||
procs = (PGPROC *) ShmemAlloc(TotalProcs * sizeof(PGPROC));
|
procs = (PGPROC *) ShmemAlloc(TotalProcs * sizeof(PGPROC));
|
||||||
ProcGlobal->allProcs = procs;
|
ProcGlobal->allProcs = procs;
|
||||||
|
@ -101,10 +101,10 @@ PageIsVerified(Page page, BlockNumber blkno)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The following checks don't prove the header is correct,
|
* The following checks don't prove the header is correct, only that
|
||||||
* only that it looks sane enough to allow into the buffer pool.
|
* it looks sane enough to allow into the buffer pool. Later usage of
|
||||||
* Later usage of the block can still reveal problems,
|
* the block can still reveal problems, which is why we offer the
|
||||||
* which is why we offer the checksum option.
|
* checksum option.
|
||||||
*/
|
*/
|
||||||
if ((p->pd_flags & ~PD_VALID_FLAG_BITS) == 0 &&
|
if ((p->pd_flags & ~PD_VALID_FLAG_BITS) == 0 &&
|
||||||
p->pd_lower <= p->pd_upper &&
|
p->pd_lower <= p->pd_upper &&
|
||||||
@ -905,10 +905,10 @@ PageSetChecksumCopy(Page page, BlockNumber blkno)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* We make a copy iff we need to calculate a checksum because other
|
* We make a copy iff we need to calculate a checksum because other
|
||||||
* backends may set hint bits on this page while we write, which
|
* backends may set hint bits on this page while we write, which would
|
||||||
* would mean the checksum differs from the page contents. It doesn't
|
* mean the checksum differs from the page contents. It doesn't matter if
|
||||||
* matter if we include or exclude hints during the copy, as long
|
* we include or exclude hints during the copy, as long as we write a
|
||||||
* as we write a valid page and associated checksum.
|
* valid page and associated checksum.
|
||||||
*/
|
*/
|
||||||
memcpy((char *) pageCopy, (char *) page, BLCKSZ);
|
memcpy((char *) pageCopy, (char *) page, BLCKSZ);
|
||||||
PageSetChecksumInplace(pageCopy, blkno);
|
PageSetChecksumInplace(pageCopy, blkno);
|
||||||
@ -931,6 +931,7 @@ PageSetChecksumInplace(Page page, BlockNumber blkno)
|
|||||||
if (DataChecksumsEnabled())
|
if (DataChecksumsEnabled())
|
||||||
{
|
{
|
||||||
PageHeader p = (PageHeader) page;
|
PageHeader p = (PageHeader) page;
|
||||||
|
|
||||||
p->pd_checksum = PageCalcChecksum16(page, blkno);
|
p->pd_checksum = PageCalcChecksum16(page, blkno);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -958,9 +959,8 @@ PageCalcChecksum16(Page page, BlockNumber blkno)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Save pd_checksum and set it to zero, so that the checksum calculation
|
* Save pd_checksum and set it to zero, so that the checksum calculation
|
||||||
* isn't affected by the checksum stored on the page. We do this to
|
* isn't affected by the checksum stored on the page. We do this to allow
|
||||||
* allow optimization of the checksum calculation on the whole block
|
* optimization of the checksum calculation on the whole block in one go.
|
||||||
* in one go.
|
|
||||||
*/
|
*/
|
||||||
save_checksum = phdr->pd_checksum;
|
save_checksum = phdr->pd_checksum;
|
||||||
phdr->pd_checksum = 0;
|
phdr->pd_checksum = 0;
|
||||||
|
@ -134,7 +134,8 @@ checksum_block(char *data, uint32 size)
|
|||||||
uint32 sums[N_SUMS];
|
uint32 sums[N_SUMS];
|
||||||
uint32 (*dataArr)[N_SUMS] = (uint32 (*)[N_SUMS]) data;
|
uint32 (*dataArr)[N_SUMS] = (uint32 (*)[N_SUMS]) data;
|
||||||
uint32 result = 0;
|
uint32 result = 0;
|
||||||
int i, j;
|
int i,
|
||||||
|
j;
|
||||||
|
|
||||||
/* ensure that the size is compatible with the algorithm */
|
/* ensure that the size is compatible with the algorithm */
|
||||||
Assert((size % (sizeof(uint32) * N_SUMS)) == 0);
|
Assert((size % (sizeof(uint32) * N_SUMS)) == 0);
|
||||||
|
@ -443,8 +443,8 @@ smgrdounlinkall(SMgrRelation *rels, int nrels, bool isRedo)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* create an array which contains all relations to be dropped, and
|
* create an array which contains all relations to be dropped, and close
|
||||||
* close each relation's forks at the smgr level while at it
|
* each relation's forks at the smgr level while at it
|
||||||
*/
|
*/
|
||||||
rnodes = palloc(sizeof(RelFileNodeBackend) * nrels);
|
rnodes = palloc(sizeof(RelFileNodeBackend) * nrels);
|
||||||
for (i = 0; i < nrels; i++)
|
for (i = 0; i < nrels; i++)
|
||||||
@ -466,8 +466,8 @@ smgrdounlinkall(SMgrRelation *rels, int nrels, bool isRedo)
|
|||||||
DropRelFileNodesAllBuffers(rnodes, nrels);
|
DropRelFileNodesAllBuffers(rnodes, nrels);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* It'd be nice to tell the stats collector to forget them immediately, too.
|
* It'd be nice to tell the stats collector to forget them immediately,
|
||||||
* But we can't because we don't know the OIDs.
|
* too. But we can't because we don't know the OIDs.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -475,8 +475,8 @@ smgrdounlinkall(SMgrRelation *rels, int nrels, bool isRedo)
|
|||||||
* dangling smgr references they may have for these rels. We should do
|
* dangling smgr references they may have for these rels. We should do
|
||||||
* this before starting the actual unlinking, in case we fail partway
|
* this before starting the actual unlinking, in case we fail partway
|
||||||
* through that step. Note that the sinval messages will eventually come
|
* through that step. Note that the sinval messages will eventually come
|
||||||
* back to this backend, too, and thereby provide a backstop that we closed
|
* back to this backend, too, and thereby provide a backstop that we
|
||||||
* our own smgr rel.
|
* closed our own smgr rel.
|
||||||
*/
|
*/
|
||||||
for (i = 0; i < nrels; i++)
|
for (i = 0; i < nrels; i++)
|
||||||
CacheInvalidateSmgr(rnodes[i]);
|
CacheInvalidateSmgr(rnodes[i]);
|
||||||
@ -492,6 +492,7 @@ smgrdounlinkall(SMgrRelation *rels, int nrels, bool isRedo)
|
|||||||
for (i = 0; i < nrels; i++)
|
for (i = 0; i < nrels; i++)
|
||||||
{
|
{
|
||||||
int which = rels[i]->smgr_which;
|
int which = rels[i]->smgr_which;
|
||||||
|
|
||||||
for (forknum = 0; forknum <= MAX_FORKNUM; forknum++)
|
for (forknum = 0; forknum <= MAX_FORKNUM; forknum++)
|
||||||
(*(smgrsw[which].smgr_unlink)) (rnodes[i], forknum, isRedo);
|
(*(smgrsw[which].smgr_unlink)) (rnodes[i], forknum, isRedo);
|
||||||
}
|
}
|
||||||
|
@ -388,8 +388,8 @@ compute_array_stats(VacAttrStats *stats, AnalyzeAttrFetchFunc fetchfunc,
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* If element type is pass-by-reference, we must copy it into
|
* If element type is pass-by-reference, we must copy it into
|
||||||
* palloc'd space, so that we can release the array below.
|
* palloc'd space, so that we can release the array below. (We
|
||||||
* (We do this so that the space needed for element values is
|
* do this so that the space needed for element values is
|
||||||
* limited by the size of the hashtable; if we kept all the
|
* limited by the size of the hashtable; if we kept all the
|
||||||
* array values around, it could be much more.)
|
* array values around, it could be much more.)
|
||||||
*/
|
*/
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user