forked from huawei/openGauss-server
Compare commits
4 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
c6cf59f29f | |
|
|
a5410b7f86 | |
|
|
c711c7dc5f | |
|
|
3bea35e8c1 |
|
|
@ -72,7 +72,7 @@ select_package_command
|
|||
export PLAT_FORM_STR=$(sh "${ROOT_DIR}/src/get_PlatForm_str.sh")
|
||||
if [ "${PLAT_FORM_STR}"x == "Failed"x -o "${PLAT_FORM_STR}"x == ""x ]
|
||||
then
|
||||
echo "We only support openEuler(aarch64), EulerOS(aarch64), CentOS, Kylin(aarch64), Asianux platform."
|
||||
echo "We only support openEuler(aarch64), EulerOS(aarch64), CentOS, Kylin(aarch64) platform."
|
||||
exit 1;
|
||||
fi
|
||||
|
||||
|
|
@ -96,21 +96,16 @@ elif [[ "$PLAT_FORM_STR" =~ "kylin" ]]; then
|
|||
if [ "$PLATFORM_ARCH"X == "aarch64"X ];then
|
||||
GAUSSDB_EXTRA_FLAGS=" -D__USE_NUMA"
|
||||
fi
|
||||
elif [[ "$PLAT_FORM_STR" =~ "asianux" ]]; then
|
||||
dist_version="Asianux"
|
||||
if [ "$PLATFORM_ARCH"X == "aarch64"X ];then
|
||||
GAUSSDB_EXTRA_FLAGS=" -D__USE_NUMA"
|
||||
fi
|
||||
else
|
||||
echo "We only support openEuler(aarch64), EulerOS(aarch64), CentOS, Kylin(aarch64), Asianux platform."
|
||||
echo "We only support openEuler(aarch64), EulerOS(aarch64), CentOS, Kylin(aarch64) platform."
|
||||
echo "Kernel is $kernel"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
##add platform architecture information
|
||||
if [ "$PLATFORM_ARCH"X == "aarch64"X ] ; then
|
||||
if [ "$dist_version" != "openEuler" ] && [ "$dist_version" != "EulerOS" ] && [ "$dist_version" != "Kylin" ] && [ "$dist_version" != "Asianux" ]; then
|
||||
echo "We only support NUMA on openEuler(aarch64), EulerOS(aarch64), Kylin(aarch64), Asianux platform."
|
||||
if [ "$dist_version" != "openEuler" ] && [ "$dist_version" != "EulerOS" ] && [ "$dist_version" != "Kylin" ] ; then
|
||||
echo "We only support NUMA on openEuler(aarch64), EulerOS(aarch64), Kylin(aarch64) platform."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
|
|
|||
|
|
@ -26,7 +26,6 @@ Complete list of usable sgml source files in this directory.
|
|||
<!ENTITY alterOperator SYSTEM "alter_operator.sgml">
|
||||
<!ENTITY alterOperatorClass SYSTEM "alter_opclass.sgml">
|
||||
<!ENTITY alterOperatorFamily SYSTEM "alter_opfamily.sgml">
|
||||
<!ENTITY alterProcedure SYSTEM "alter_procedure.sgml">
|
||||
<!ENTITY alterRole SYSTEM "alter_role.sgml">
|
||||
<!ENTITY alterSchema SYSTEM "alter_schema.sgml">
|
||||
<!ENTITY alterServer SYSTEM "alter_server.sgml">
|
||||
|
|
|
|||
|
|
@ -1,37 +0,0 @@
|
|||
<refentry id="sql-alterprocedure">
|
||||
<indexterm zone="sql-alterprocedure">
|
||||
<primary>ALTER PROCEDURE</primary>
|
||||
</indexterm>
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle>ALTER PROCEDURE</refentrytitle>
|
||||
<manvolnum>7</manvolnum>
|
||||
<refmiscinfo>SQL - Language Statements</refmiscinfo>
|
||||
</refmeta>
|
||||
|
||||
<refnamediv>
|
||||
<refname>ALTER PROCEDURE</refname>
|
||||
<refpurpose>change the definition of a procedure</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<refsynopsisdiv>
|
||||
<synopsis>
|
||||
ALTER PROCEDURE <replaceable>name</replaceable> [ ( [ [ <replaceable class="parameter">argmode</replaceable> ] [ <replaceable class="parameter">argname</replaceable> ] <replaceable class="parameter">argtype</replaceable> [, ...] ] ) ]
|
||||
<replaceable class="parameter">action</replaceable> [ ... ] [ RESTRICT ]
|
||||
ALTER PROCEDURE <replaceable>name</replaceable> [ ( [ [ <replaceable class="parameter">argmode</replaceable> ] [ <replaceable class="parameter">argname</replaceable> ] <replaceable class="parameter">argtype</replaceable> [, ...] ] ) ]
|
||||
RENAME TO <replaceable>new_name</replaceable>
|
||||
ALTER PROCEDURE <replaceable>name</replaceable> [ ( [ [ <replaceable class="parameter">argmode</replaceable> ] [ <replaceable class="parameter">argname</replaceable> ] <replaceable class="parameter">argtype</replaceable> [, ...] ] ) ]
|
||||
OWNER TO { <replaceable>new_owner</replaceable> | CURRENT_ROLE | CURRENT_USER | SESSION_USER }
|
||||
ALTER PROCEDURE <replaceable>name</replaceable> [ ( [ [ <replaceable class="parameter">argmode</replaceable> ] [ <replaceable class="parameter">argname</replaceable> ] <replaceable class="parameter">argtype</replaceable> [, ...] ] ) ]
|
||||
SET SCHEMA <replaceable>new_schema</replaceable>
|
||||
|
||||
<phrase>where <replaceable class="parameter">action</replaceable> is one of:</phrase>
|
||||
|
||||
[ EXTERNAL ] SECURITY INVOKER | [ EXTERNAL ] SECURITY DEFINER
|
||||
SET <replaceable class="parameter">configuration_parameter</replaceable> { TO | = } { <replaceable class="parameter">value</replaceable> | DEFAULT }
|
||||
SET <replaceable class="parameter">configuration_parameter</replaceable> FROM CURRENT
|
||||
RESET <replaceable class="parameter">configuration_parameter</replaceable>
|
||||
RESET ALL
|
||||
</synopsis>
|
||||
</refsynopsisdiv>
|
||||
</refentry>
|
||||
|
|
@ -11,7 +11,7 @@
|
|||
<refsynopsisdiv>
|
||||
<synopsis>
|
||||
DROP TABLE [ IF EXISTS ]
|
||||
{[schema.]table_name} [, ...] [ CASCADE | RESTRICT ] [ PURGE ];
|
||||
{[schema.]table_name} [, ...] [ CASCADE | RESTRICT ] [ PURGE ]};
|
||||
</synopsis>
|
||||
</refsynopsisdiv>
|
||||
</refentry>
|
||||
|
|
@ -27,14 +27,7 @@
|
|||
#include "securec_check.h"
|
||||
#include "cipher.h"
|
||||
#include "crypt.h"
|
||||
/*
|
||||
function name: crypt_malloc_zero
|
||||
description: Distribute internal memory
|
||||
arguments: An integer that designates the size of internal memory distributed
|
||||
return value: A pointer of type void*
|
||||
Note:If the size of internal memory distributed is zero, it's unreasonable. The size should be greater than zero.
|
||||
At the same time, if malloc fails, program would exit.
|
||||
*/
|
||||
|
||||
void* crypt_malloc_zero(size_t size)
|
||||
{
|
||||
void* ret = NULL;
|
||||
|
|
|
|||
|
|
@ -34,14 +34,6 @@
|
|||
static int check_key_num(const char* password);
|
||||
static void create_child_dir(const char* pathdir);
|
||||
|
||||
|
||||
/*
|
||||
function name: check_path
|
||||
description: Check if the string delivered has the character that should not be included
|
||||
arguments: A pointer to string that its type is const char
|
||||
return value: void
|
||||
Note:none
|
||||
*/
|
||||
void check_path(const char *path_name)
|
||||
{
|
||||
const char* danger_character_list[] = {"|",
|
||||
|
|
@ -77,14 +69,6 @@ void check_path(const char *path_name)
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
function name: check_key_num
|
||||
description: Check if the password is a null string, if so, then the password is invalid.
|
||||
At the same time, the function check if the length of password exceeds MAX_CRYPT_LEN, if so, print the error.
|
||||
arguments: A pointer to string that its type is const char
|
||||
return value: An integer that its type is static int
|
||||
Note:The length of password should not be zero, and never exceeds MAX_CRYPT_LEN
|
||||
*/
|
||||
static int check_key_num(const char* password)
|
||||
{
|
||||
int key_len = 0;
|
||||
|
|
|
|||
|
|
@ -5923,7 +5923,7 @@ int main(int argc, char** argv)
|
|||
&option_index)) != -1)
|
||||
#endif
|
||||
#else
|
||||
while ((c = getopt_long(argc, argv, "b:cD:e:fi:G:l:m:M:N:o:O:p:P:r:R:v:x:sS:t:u:U:wWZ:C:dqL:T:Q:", long_options,
|
||||
while ((c = getopt_long(argc, argv, "b:cD:e:fi:G:l:m:M:N:o:O:p:P:r:R:v:x:sS:t:u:U:wWZ:dqL:T:Q:", long_options,
|
||||
&option_index)) != -1)
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -233,7 +233,6 @@ char* all_data_nodename_list = NULL;
|
|||
const uint32 USTORE_UPGRADE_VERSION = 92368;
|
||||
const uint32 PACKAGE_ENHANCEMENT = 92444;
|
||||
const uint32 SUBSCRIPTION_VERSION = 92580;
|
||||
const uint32 SUBSCRIPTION_BINARY_VERSION_NUM = 92606;
|
||||
|
||||
#ifdef DUMPSYSLOG
|
||||
char* syslogpath = NULL;
|
||||
|
|
@ -4445,9 +4444,7 @@ void getSubscriptions(Archive *fout)
|
|||
int i_subslotname;
|
||||
int i_subsynccommit;
|
||||
int i_subpublications;
|
||||
int i_subbinary;
|
||||
int i;
|
||||
int ntups;
|
||||
int i, ntups;
|
||||
|
||||
if (no_subscriptions || GetVersionNum(fout) < SUBSCRIPTION_VERSION) {
|
||||
return;
|
||||
|
|
@ -4472,20 +4469,14 @@ void getSubscriptions(Archive *fout)
|
|||
resetPQExpBuffer(query);
|
||||
|
||||
/* Get the subscriptions in current database. */
|
||||
appendPQExpBuffer(query, "SELECT s.tableoid, s.oid, s.subname,"
|
||||
"(%s s.subowner) AS rolname, s.subconninfo, s.subslotname, "
|
||||
"s.subsynccommit, s.subpublications, \n", username_subquery);
|
||||
|
||||
if (GetVersionNum(fout) >= SUBSCRIPTION_BINARY_VERSION_NUM) {
|
||||
appendPQExpBuffer(query, " s.subbinary\n");
|
||||
} else {
|
||||
appendPQExpBuffer(query, " false AS subbinary\n");
|
||||
}
|
||||
|
||||
appendPQExpBuffer(query, "FROM pg_catalog.pg_subscription s "
|
||||
appendPQExpBuffer(query,
|
||||
"SELECT s.tableoid, s.oid, s.subname,"
|
||||
"(%s s.subowner) AS rolname, "
|
||||
" s.subconninfo, s.subslotname, s.subsynccommit, s.subpublications "
|
||||
"FROM pg_catalog.pg_subscription s "
|
||||
"WHERE s.subdbid = (SELECT oid FROM pg_catalog.pg_database"
|
||||
" WHERE datname = current_database())");
|
||||
|
||||
" WHERE datname = current_database())",
|
||||
username_subquery);
|
||||
res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
|
||||
|
||||
ntups = PQntuples(res);
|
||||
|
|
@ -4503,7 +4494,6 @@ void getSubscriptions(Archive *fout)
|
|||
i_subslotname = PQfnumber(res, "subslotname");
|
||||
i_subsynccommit = PQfnumber(res, "subsynccommit");
|
||||
i_subpublications = PQfnumber(res, "subpublications");
|
||||
i_subbinary = PQfnumber(res, "subbinary");
|
||||
|
||||
subinfo = (SubscriptionInfo *)pg_malloc(ntups * sizeof(SubscriptionInfo));
|
||||
|
||||
|
|
@ -4522,7 +4512,6 @@ void getSubscriptions(Archive *fout)
|
|||
}
|
||||
subinfo[i].subsynccommit = gs_strdup(PQgetvalue(res, i, i_subsynccommit));
|
||||
subinfo[i].subpublications = gs_strdup(PQgetvalue(res, i, i_subpublications));
|
||||
subinfo[i].subbinary = gs_strdup(PQgetvalue(res, i, i_subbinary));
|
||||
|
||||
if (strlen(subinfo[i].rolname) == 0) {
|
||||
write_msg(NULL, "WARNING: owner of subscription \"%s\" appears to be invalid\n", subinfo[i].dobj.name);
|
||||
|
|
@ -4589,10 +4578,6 @@ static void dumpSubscription(Archive *fout, const SubscriptionInfo *subinfo)
|
|||
appendPQExpBufferStr(query, "NONE");
|
||||
}
|
||||
|
||||
if (strcmp(subinfo->subbinary, "t") == 0) {
|
||||
appendPQExpBuffer(query, ", binary = true");
|
||||
}
|
||||
|
||||
if (strcmp(subinfo->subsynccommit, "off") != 0) {
|
||||
appendPQExpBuffer(query, ", synchronous_commit = %s", fmtId(subinfo->subsynccommit));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -498,7 +498,6 @@ typedef struct _SubscriptionInfo {
|
|||
char *subslotname;
|
||||
char *subsynccommit;
|
||||
char *subpublications;
|
||||
char *subbinary;
|
||||
} SubscriptionInfo;
|
||||
|
||||
/* global decls */
|
||||
|
|
|
|||
|
|
@ -31,9 +31,6 @@
|
|||
it will be backuped up in external dirs */
|
||||
parray *pgdata_nobackup_dir = NULL;
|
||||
|
||||
/* list of logical replication slots */
|
||||
parray *logical_replslot = NULL;
|
||||
|
||||
static int standby_message_timeout_local = 10 ; /* 10 sec = default */
|
||||
static XLogRecPtr stop_backup_lsn = InvalidXLogRecPtr;
|
||||
static XLogRecPtr stop_stream_lsn = InvalidXLogRecPtr;
|
||||
|
|
@ -92,11 +89,10 @@ static void backup_cleanup(bool fatal, void *userdata);
|
|||
|
||||
static void *backup_files(void *arg);
|
||||
|
||||
static void do_backup_instance(PGconn *backup_conn, PGNodeInfo *nodeInfo, bool no_sync, bool backup_logs,
|
||||
bool backup_replslots);
|
||||
static void do_backup_instance(PGconn *backup_conn, PGNodeInfo *nodeInfo, bool no_sync, bool backup_logs);
|
||||
|
||||
static void pg_start_backup(const char *label, bool smooth, pgBackup *backup,
|
||||
PGNodeInfo *nodeInfo, PGconn *conn, bool backup_replslots);
|
||||
PGNodeInfo *nodeInfo, PGconn *conn);
|
||||
static void pg_stop_backup(pgBackup *backup, PGconn *pg_startbackup_conn, PGNodeInfo *nodeInfo);
|
||||
static int checkpoint_timeout(PGconn *backup_conn);
|
||||
|
||||
|
|
@ -562,7 +558,7 @@ static void sync_files(parray *database_map, const char *database_path, parray *
|
|||
* Move files from 'pgdata' to a subdirectory in 'backup_path'.
|
||||
*/
|
||||
static void
|
||||
do_backup_instance(PGconn *backup_conn, PGNodeInfo *nodeInfo, bool no_sync, bool backup_logs, bool backup_replslots)
|
||||
do_backup_instance(PGconn *backup_conn, PGNodeInfo *nodeInfo, bool no_sync, bool backup_logs)
|
||||
{
|
||||
int i;
|
||||
char database_path[MAXPGPATH];
|
||||
|
|
@ -595,7 +591,7 @@ do_backup_instance(PGconn *backup_conn, PGNodeInfo *nodeInfo, bool no_sync, bool
|
|||
securec_check_c(rc, "\0", "\0");
|
||||
|
||||
/* Call pg_start_backup function in openGauss connect */
|
||||
pg_start_backup(label, smooth_checkpoint, ¤t, nodeInfo, backup_conn, backup_replslots);
|
||||
pg_start_backup(label, smooth_checkpoint, ¤t, nodeInfo, backup_conn);
|
||||
|
||||
/* Obtain current timeline */
|
||||
#if PG_VERSION_NUM >= 90600
|
||||
|
|
@ -628,10 +624,10 @@ do_backup_instance(PGconn *backup_conn, PGNodeInfo *nodeInfo, bool no_sync, bool
|
|||
/* list files with the logical path. omit $PGDATA */
|
||||
if (fio_is_remote(FIO_DB_HOST))
|
||||
fio_list_dir(backup_files_list, instance_config.pgdata,
|
||||
true, true, false, backup_logs, true, 0, backup_replslots);
|
||||
true, true, false, backup_logs, true, 0);
|
||||
else
|
||||
dir_list_file(backup_files_list, instance_config.pgdata,
|
||||
true, true, false, backup_logs, true, 0, FIO_LOCAL_HOST, backup_replslots);
|
||||
true, true, false, backup_logs, true, 0, FIO_LOCAL_HOST);
|
||||
|
||||
/*
|
||||
* Get database_map (name to oid) for use in partial restore feature.
|
||||
|
|
@ -753,11 +749,6 @@ do_backup_instance(PGconn *backup_conn, PGNodeInfo *nodeInfo, bool no_sync, bool
|
|||
}
|
||||
pgdata_nobackup_dir = NULL;
|
||||
|
||||
if (logical_replslot) {
|
||||
free_dir_list(logical_replslot);
|
||||
}
|
||||
logical_replslot = NULL;
|
||||
|
||||
/* Cleanup */
|
||||
if (backup_list)
|
||||
{
|
||||
|
|
@ -858,7 +849,7 @@ static void do_after_backup()
|
|||
*/
|
||||
int
|
||||
do_backup(time_t start_time, pgSetBackupParams *set_backup_params,
|
||||
bool no_validate, bool no_sync, bool backup_logs, bool backup_replslots)
|
||||
bool no_validate, bool no_sync, bool backup_logs)
|
||||
{
|
||||
PGconn *backup_conn = NULL;
|
||||
PGNodeInfo nodeInfo;
|
||||
|
|
@ -934,7 +925,7 @@ do_backup(time_t start_time, pgSetBackupParams *set_backup_params,
|
|||
add_note(¤t, set_backup_params->note);
|
||||
|
||||
/* backup data */
|
||||
do_backup_instance(backup_conn, &nodeInfo, no_sync, backup_logs, backup_replslots);
|
||||
do_backup_instance(backup_conn, &nodeInfo, no_sync, backup_logs);
|
||||
pgut_atexit_pop(backup_cleanup, NULL);
|
||||
|
||||
/* compute size of wal files of this backup stored in the archive */
|
||||
|
|
@ -1043,15 +1034,13 @@ confirm_block_size(PGconn *conn, const char *name, int blcksz)
|
|||
*/
|
||||
static void
|
||||
pg_start_backup(const char *label, bool smooth, pgBackup *backup,
|
||||
PGNodeInfo *nodeInfo, PGconn *conn, bool backup_replslots)
|
||||
PGNodeInfo *nodeInfo, PGconn *conn)
|
||||
{
|
||||
PGresult *res;
|
||||
const char *params[2];
|
||||
uint32 lsn_hi;
|
||||
uint32 lsn_lo;
|
||||
int ret;
|
||||
int i;
|
||||
XLogRecPtr startLsn;
|
||||
|
||||
params[0] = label;
|
||||
|
||||
|
|
@ -1079,33 +1068,7 @@ pg_start_backup(const char *label, bool smooth, pgBackup *backup,
|
|||
XLogDataFromLSN(ret, PQgetvalue(res, 0, 0), &lsn_hi, &lsn_lo);
|
||||
securec_check_for_sscanf_s(ret, 2, "\0", "\0");
|
||||
/* Calculate LSN */
|
||||
startLsn = ((uint64) lsn_hi )<< 32 | lsn_lo;
|
||||
|
||||
if (backup_replslots) {
|
||||
logical_replslot = parray_new();
|
||||
/* query for logical replication slots of subscriptions */
|
||||
res = pgut_execute(conn,
|
||||
"SELECT slot_name, restart_lsn FROM pg_catalog.pg_get_replication_slots()"
|
||||
"WHERE slot_type = 'logical' AND plugin = 'pgoutput'", 0, NULL);
|
||||
if (PQntuples(res) == 0) {
|
||||
elog(LOG, "logical replication slots for subscriptions not found");
|
||||
} else {
|
||||
XLogRecPtr repslotLsn;
|
||||
|
||||
for (i = 0; i < PQntuples(res); i++) {
|
||||
XLogDataFromLSN(ret, PQgetvalue(res, i, 1), &lsn_hi, &lsn_lo);
|
||||
securec_check_for_sscanf_s(ret, 2, "\0", "\0");
|
||||
repslotLsn = ((uint64) lsn_hi )<< 32 | lsn_lo;
|
||||
startLsn = Min(startLsn, repslotLsn);
|
||||
|
||||
char* slotname = pg_strdup(PQgetvalue(res, i, 0));
|
||||
parray_append(logical_replslot, slotname);
|
||||
}
|
||||
elog(WARNING, "logical replication slots for subscriptions will be backed up. "
|
||||
"If don't use them after restoring, please drop them to avoid affecting xlog recycling.");
|
||||
}
|
||||
}
|
||||
backup->start_lsn = startLsn;
|
||||
backup->start_lsn = ((uint64) lsn_hi )<< 32 | lsn_lo;
|
||||
|
||||
PQclear(res);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,6 +42,13 @@ const char *pgdata_exclude_dir[] =
|
|||
(const char *)"pg_stat_tmp",
|
||||
(const char *)"pgsql_tmp",
|
||||
|
||||
/*
|
||||
* It is generally not useful to backup the contents of this directory even
|
||||
* if the intention is to restore to another master. See backup.sgml for a
|
||||
* more detailed description.
|
||||
*/
|
||||
(const char *)"pg_replslot",
|
||||
|
||||
/* Contents removed on startup, see dsm_cleanup_for_mmap(). */
|
||||
(const char *)"pg_dynshmem",
|
||||
|
||||
|
|
@ -61,7 +68,7 @@ const char *pgdata_exclude_dir[] =
|
|||
(const char *)"pg_subtrans",
|
||||
|
||||
/* end of list */
|
||||
NULL, /* pg_log and pg_replslot will be set later */
|
||||
NULL, /* pg_log will be set later */
|
||||
NULL
|
||||
};
|
||||
|
||||
|
|
@ -121,20 +128,17 @@ may be removed int the future */
|
|||
|
||||
static int pgCompareString(const void *str1, const void *str2);
|
||||
|
||||
static char dir_check_file(pgFile *file, bool backup_logs, bool backup_replslots);
|
||||
static char dir_check_file(pgFile *file, bool backup_logs);
|
||||
static char check_in_tablespace(pgFile *file, bool in_tablespace);
|
||||
static char check_db_dir(pgFile *file);
|
||||
static char check_digit_file(pgFile *file);
|
||||
static char check_nobackup_dir(pgFile *file);
|
||||
static void dir_list_file_internal(parray *files, pgFile *parent, const char *parent_dir,
|
||||
bool exclude, bool follow_symlink, bool backup_logs,
|
||||
bool skip_hidden, int external_dir_num, fio_location location,
|
||||
bool backup_replslots);
|
||||
bool skip_hidden, int external_dir_num, fio_location location);
|
||||
static void opt_path_map(ConfigOption *opt, const char *arg,
|
||||
TablespaceList *list, const char *type);
|
||||
|
||||
char check_logical_replslot_dir(const char *rel_path);
|
||||
|
||||
/* Tablespace mapping */
|
||||
static TablespaceList tablespace_dirs = {NULL, NULL};
|
||||
/* Extra directories mapping */
|
||||
|
|
@ -534,7 +538,7 @@ db_map_entry_free(void *entry)
|
|||
void
|
||||
dir_list_file(parray *files, const char *root, bool exclude, bool follow_symlink,
|
||||
bool add_root, bool backup_logs, bool skip_hidden, int external_dir_num,
|
||||
fio_location location, bool backup_replslots)
|
||||
fio_location location)
|
||||
{
|
||||
pgFile *file;
|
||||
|
||||
|
|
@ -561,7 +565,7 @@ dir_list_file(parray *files, const char *root, bool exclude, bool follow_symlink
|
|||
parray_append(files, file);
|
||||
|
||||
dir_list_file_internal(files, file, root, exclude, follow_symlink,
|
||||
backup_logs, skip_hidden, external_dir_num, location, backup_replslots);
|
||||
backup_logs, skip_hidden, external_dir_num, location);
|
||||
|
||||
if (!add_root)
|
||||
pgFileFree(file);
|
||||
|
|
@ -585,7 +589,7 @@ dir_list_file(parray *files, const char *root, bool exclude, bool follow_symlink
|
|||
* - datafiles
|
||||
*/
|
||||
static char
|
||||
dir_check_file(pgFile *file, bool backup_logs, bool backup_replslots)
|
||||
dir_check_file(pgFile *file, bool backup_logs)
|
||||
{
|
||||
int i;
|
||||
int sscanf_res;
|
||||
|
|
@ -648,29 +652,6 @@ dir_check_file(pgFile *file, bool backup_logs, bool backup_replslots)
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Backup pg_replslot if it is specified.
|
||||
* It is generally not useful to backup the contents of this directory even
|
||||
* if the intention is to restore to another master. See backup.sgml for a
|
||||
* more detailed description.
|
||||
*/
|
||||
if (!backup_replslots) {
|
||||
if (strcmp(file->rel_path, PG_REPLSLOT_DIR) == 0) {
|
||||
/* Skip */
|
||||
elog(VERBOSE, "Excluding directory content: %s", file->rel_path);
|
||||
return CHECK_EXCLUDE_FALSE;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* Check file that under pg_replslot and judge whether it
|
||||
* belonged to logical replication slots for subscriptions.
|
||||
*/
|
||||
if (strcmp(file->rel_path, PG_REPLSLOT_DIR) != 0 &&
|
||||
path_is_prefix_of_path(PG_REPLSLOT_DIR, file->rel_path)) {
|
||||
return check_logical_replslot_dir(file->rel_path);
|
||||
}
|
||||
}
|
||||
|
||||
ret = check_nobackup_dir(file);
|
||||
if (ret != -1) { /* -1 means need backup */
|
||||
return ret;
|
||||
|
|
@ -768,35 +749,6 @@ static char check_nobackup_dir(pgFile *file)
|
|||
return ret;
|
||||
}
|
||||
|
||||
char check_logical_replslot_dir(const char *rel_path)
|
||||
{
|
||||
char ret = CHECK_FALSE;
|
||||
int i = 0;
|
||||
char *tmp = pg_strdup(rel_path);
|
||||
char *p;
|
||||
#define DIRECTORY_DELIMITER "/"
|
||||
|
||||
if (logical_replslot) {
|
||||
/* extract slot name from rel_path, such as sub1 from pg_replslot/sub1/snap */
|
||||
p = strtok(tmp, DIRECTORY_DELIMITER);
|
||||
if (p != NULL) {
|
||||
p = strtok(NULL, DIRECTORY_DELIMITER);
|
||||
}
|
||||
|
||||
for (i = 0; p != NULL && i < (int)parray_num(logical_replslot); i++) {
|
||||
char *slotName = (char *)parray_get(logical_replslot, i);
|
||||
if (strcmp(p, slotName) == 0) {
|
||||
pfree(tmp);
|
||||
return CHECK_TRUE;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ret = CHECK_TRUE;
|
||||
}
|
||||
pfree(tmp);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static char check_db_dir(pgFile *file)
|
||||
{
|
||||
char ret = -1;
|
||||
|
|
@ -937,8 +889,7 @@ bool SkipSomeDirFile(pgFile *file, struct dirent *dent, bool skipHidden)
|
|||
static void
|
||||
dir_list_file_internal(parray *files, pgFile *parent, const char *parent_dir,
|
||||
bool exclude, bool follow_symlink, bool backup_logs,
|
||||
bool skip_hidden, int external_dir_num, fio_location location,
|
||||
bool backup_replslots)
|
||||
bool skip_hidden, int external_dir_num, fio_location location)
|
||||
{
|
||||
DIR *dir;
|
||||
struct dirent *dent;
|
||||
|
|
@ -986,7 +937,7 @@ dir_list_file_internal(parray *files, pgFile *parent, const char *parent_dir,
|
|||
|
||||
if (exclude)
|
||||
{
|
||||
check_res = dir_check_file(file, backup_logs, backup_replslots);
|
||||
check_res = dir_check_file(file, backup_logs);
|
||||
if (check_res == CHECK_FALSE)
|
||||
{
|
||||
/* Skip */
|
||||
|
|
@ -1012,7 +963,7 @@ dir_list_file_internal(parray *files, pgFile *parent, const char *parent_dir,
|
|||
*/
|
||||
if (S_ISDIR(file->mode))
|
||||
dir_list_file_internal(files, file, child, exclude, follow_symlink,
|
||||
backup_logs, skip_hidden, external_dir_num, location, backup_replslots);
|
||||
backup_logs, skip_hidden, external_dir_num, location);
|
||||
}
|
||||
|
||||
if (errno && errno != ENOENT)
|
||||
|
|
|
|||
|
|
@ -51,7 +51,6 @@ typedef struct
|
|||
bool exclusive_backup;
|
||||
bool skip_hidden;
|
||||
int external_dir_num;
|
||||
bool backup_replslots;
|
||||
} fio_list_dir_request;
|
||||
|
||||
typedef struct
|
||||
|
|
@ -1795,7 +1794,7 @@ cleanup:
|
|||
/* Compile the array of files located on remote machine in directory root */
|
||||
void fio_list_dir(parray *files, const char *root, bool exclude,
|
||||
bool follow_symlink, bool add_root, bool backup_logs,
|
||||
bool skip_hidden, int external_dir_num, bool backup_replslots)
|
||||
bool skip_hidden, int external_dir_num)
|
||||
{
|
||||
fio_header hdr;
|
||||
fio_list_dir_request req;
|
||||
|
|
@ -1812,7 +1811,6 @@ void fio_list_dir(parray *files, const char *root, bool exclude,
|
|||
req.exclusive_backup = exclusive_backup;
|
||||
req.skip_hidden = skip_hidden;
|
||||
req.external_dir_num = external_dir_num;
|
||||
req.backup_replslots = backup_replslots;
|
||||
|
||||
hdr.cop = FIO_LIST_DIR;
|
||||
hdr.size = sizeof(req);
|
||||
|
|
@ -1872,14 +1870,7 @@ void fio_list_dir(parray *files, const char *root, bool exclude,
|
|||
securec_check_ss_c(nRet, "\0", "\0");
|
||||
}
|
||||
|
||||
/*
|
||||
* Check file that under pg_replslot and judge whether it
|
||||
* belonged to logical replication slots for subscriptions.
|
||||
*/
|
||||
if (backup_replslots && strcmp(buf, PG_REPLSLOT_DIR) != 0 &&
|
||||
path_is_prefix_of_path(PG_REPLSLOT_DIR, buf) && check_logical_replslot_dir(file->rel_path) != 1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
parray_append(files, file);
|
||||
}
|
||||
|
|
@ -1923,7 +1914,7 @@ static void fio_list_dir_impl(int out, char* buf)
|
|||
|
||||
dir_list_file(file_files, req->path, req->exclude, req->follow_symlink,
|
||||
req->add_root, req->backup_logs, req->skip_hidden,
|
||||
req->external_dir_num, FIO_LOCAL_HOST, req->backup_replslots);
|
||||
req->external_dir_num, FIO_LOCAL_HOST);
|
||||
|
||||
/* send information about files to the main process */
|
||||
for (i = 0; i < (int)parray_num(file_files); i++)
|
||||
|
|
|
|||
|
|
@ -163,7 +163,5 @@ extern z_off_t fio_gzseek(gzFile f, z_off_t offset, int whence);
|
|||
extern const char* fio_gzerror(gzFile file, int *errnum);
|
||||
#endif
|
||||
|
||||
extern char check_logical_replslot_dir(const char *rel_path);
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -154,7 +154,6 @@ void help_pg_probackup(void)
|
|||
printf(_(" [--remote-port=port] [--ssh-options=ssh_options]\n"));
|
||||
printf(_(" [--remote-libpath=libpath]\n"));
|
||||
printf(_(" [--ttl=interval] [--expire-time=time]\n"));
|
||||
printf(_(" [--backup-pg-replslot]\n"));
|
||||
printf(_(" [--help]\n"));
|
||||
|
||||
printf(_("\n %s restore -B backup-path --instance=instance_name\n"), PROGRAM_NAME);
|
||||
|
|
@ -421,7 +420,6 @@ static void help_backup(void)
|
|||
printf(_(" [--remote-port=port] [--ssh-options=ssh_options]\n"));
|
||||
printf(_(" [--remote-libpath=libpath]\n"));
|
||||
printf(_(" [--ttl=interval] [--expire-time=time]\n\n"));
|
||||
printf(_(" [--backup-pg-replslot]\n"));
|
||||
|
||||
printf(_(" -B, --backup-path=backup-path location of the backup storage area\n"));
|
||||
printf(_(" --instance=instance_name name of the instance\n"));
|
||||
|
|
@ -443,7 +441,6 @@ static void help_backup(void)
|
|||
printf(_(" --note=text add note to backup\n"));
|
||||
printf(_(" (example: --note='backup before app update to v13.1')\n"));
|
||||
printf(_(" --archive-timeout=timeout wait timeout for WAL segment archiving (default: 5min)\n"));
|
||||
printf(_(" --backup-pg-replslot] backup of '%s' directory\n"), PG_REPLSLOT_DIR);
|
||||
|
||||
printf(_("\n Logging options:\n"));
|
||||
printf(_(" --log-level-console=log-level-console\n"));
|
||||
|
|
|
|||
|
|
@ -77,7 +77,6 @@ int rw_timeout = 0;
|
|||
|
||||
/* backup options */
|
||||
bool backup_logs = false;
|
||||
bool backup_replslots = false;
|
||||
bool smooth_checkpoint;
|
||||
char *remote_agent;
|
||||
static char *backup_note = NULL;
|
||||
|
|
@ -187,7 +186,6 @@ static ConfigOption cmd_options[] =
|
|||
{ 'b', 145, "wal", &delete_wal, SOURCE_CMD_STRICT },
|
||||
{ 'b', 146, "expired", &delete_expired, SOURCE_CMD_STRICT },
|
||||
{ 's', 172, "status", &delete_status, SOURCE_CMD_STRICT },
|
||||
{ 'b', 186, "backup-pg-replslot", &backup_replslots, SOURCE_CMD_STRICT},
|
||||
|
||||
{ 'b', 147, "force", &force, SOURCE_CMD_STRICT },
|
||||
{ 'b', 148, "compress", &compress_shortcut, SOURCE_CMD_STRICT },
|
||||
|
|
@ -552,7 +550,7 @@ static int do_actual_operate()
|
|||
elog(ERROR, "required parameter not specified: BACKUP_MODE "
|
||||
"(-b, --backup-mode)");
|
||||
|
||||
return do_backup(start_time, set_backup_params, no_validate, no_sync, backup_logs, backup_replslots);
|
||||
return do_backup(start_time, set_backup_params, no_validate, no_sync, backup_logs);
|
||||
}
|
||||
case RESTORE_CMD:
|
||||
return do_restore_or_validate(current.backup_id,
|
||||
|
|
|
|||
|
|
@ -69,7 +69,6 @@ extern const char *PROGRAM_FULL_PATH;
|
|||
#define HEADER_MAP "page_header_map"
|
||||
#define HEADER_MAP_TMP "page_header_map_tmp"
|
||||
#define PG_RELATIVE_TBLSPC_DIR "pg_location"
|
||||
#define PG_REPLSLOT_DIR "pg_replslot"
|
||||
|
||||
/* Timeout defaults */
|
||||
#define ARCHIVE_TIMEOUT_DEFAULT 300
|
||||
|
|
|
|||
|
|
@ -54,9 +54,6 @@ extern bool smooth_checkpoint;
|
|||
it will be backuped up in external dirs */
|
||||
extern parray *pgdata_nobackup_dir;
|
||||
|
||||
/* list of logical replication slots */
|
||||
extern parray *logical_replslot;
|
||||
|
||||
/* remote probackup options */
|
||||
extern char* remote_agent;
|
||||
|
||||
|
|
@ -92,7 +89,7 @@ extern const char *pgdata_exclude_dir[];
|
|||
|
||||
/* in backup.c */
|
||||
extern int do_backup(time_t start_time, pgSetBackupParams *set_backup_params,
|
||||
bool no_validate, bool no_sync, bool backup_logs, bool backup_replslots);
|
||||
bool no_validate, bool no_sync, bool backup_logs);
|
||||
extern BackupMode parse_backup_mode(const char *value);
|
||||
extern const char *deparse_backup_mode(BackupMode mode);
|
||||
extern void process_block_change(ForkNumber forknum, const RelFileNode rnode,
|
||||
|
|
@ -242,8 +239,7 @@ extern const char* deparse_compress_alg(int alg);
|
|||
/* in dir.c */
|
||||
extern void dir_list_file(parray *files, const char *root, bool exclude,
|
||||
bool follow_symlink, bool add_root, bool backup_logs,
|
||||
bool skip_hidden, int external_dir_num, fio_location location,
|
||||
bool backup_replslots = false);
|
||||
bool skip_hidden, int external_dir_num, fio_location location);
|
||||
|
||||
extern void create_data_directories(parray *dest_files,
|
||||
const char *data_dir,
|
||||
|
|
@ -436,8 +432,7 @@ extern int fio_send_file(const char *from_fullpath, const char *to_fullpath, FIL
|
|||
pgFile *file, char **errormsg);
|
||||
|
||||
extern void fio_list_dir(parray *files, const char *root, bool exclude, bool follow_symlink,
|
||||
bool add_root, bool backup_logs, bool skip_hidden, int external_dir_num,
|
||||
bool backup_replslots = false);
|
||||
bool add_root, bool backup_logs, bool skip_hidden, int external_dir_num);
|
||||
|
||||
extern bool pgut_rmtree(const char *path, bool rmtopdir, bool strict);
|
||||
|
||||
|
|
|
|||
|
|
@ -6230,7 +6230,7 @@ Datum GetPartBoundaryByTuple(Relation rel, HeapTuple tuple)
|
|||
return Timestamp2Boundarys(rel, Align2UpBoundary(value, partMap->intervalValue, boundaryTs));
|
||||
}
|
||||
|
||||
Oid AddNewIntervalPartition(Relation rel, void* insertTuple, bool isDDL)
|
||||
Oid AddNewIntervalPartition(Relation rel, void* insertTuple)
|
||||
{
|
||||
Relation pgPartRel = NULL;
|
||||
Oid newPartOid = InvalidOid;
|
||||
|
|
@ -6327,13 +6327,7 @@ Oid AddNewIntervalPartition(Relation rel, void* insertTuple, bool isDDL)
|
|||
*/
|
||||
CommandCounterIncrement();
|
||||
|
||||
/*
|
||||
* If add interval partition in the DDL, do not need to change the csn
|
||||
* because the scn has been changed in the DDL.
|
||||
*/
|
||||
if (!isDDL) {
|
||||
UpdatePgObjectChangecsn(RelationGetRelid(rel), rel->rd_rel->relkind);
|
||||
}
|
||||
UpdatePgObjectChangecsn(RelationGetRelid(rel), rel->rd_rel->relkind);
|
||||
|
||||
return newPartOid;
|
||||
}
|
||||
|
|
@ -7119,7 +7113,7 @@ int lookupHBucketid(oidvector *buckets, int low, int2 bktId)
|
|||
* Description :
|
||||
* Notes :
|
||||
*/
|
||||
Oid heapTupleGetPartitionId(Relation rel, void *tuple, bool isDDL)
|
||||
Oid heapTupleGetPartitionId(Relation rel, void *tuple)
|
||||
{
|
||||
Oid partitionid = InvalidOid;
|
||||
|
||||
|
|
@ -7146,7 +7140,7 @@ Oid heapTupleGetPartitionId(Relation rel, void *tuple, bool isDDL)
|
|||
(errcode(ERRCODE_NO_DATA_FOUND), errmsg("inserted partition key does not map to any table partition")));
|
||||
} break;
|
||||
case PART_AREA_INTERVAL: {
|
||||
return AddNewIntervalPartition(rel, tuple, isDDL);
|
||||
return AddNewIntervalPartition(rel, tuple);
|
||||
} break;
|
||||
case PART_AREA_LIST: {
|
||||
ereport(ERROR,
|
||||
|
|
|
|||
|
|
@ -47,7 +47,8 @@ static void InternalAggIsSupported(const char *aggName)
|
|||
"json_agg",
|
||||
"json_object_agg",
|
||||
"st_summarystatsagg",
|
||||
"st_union"
|
||||
"st_union",
|
||||
"wm_concat"
|
||||
};
|
||||
|
||||
uint len = lengthof(supportList);
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ static_assert(sizeof(false) == sizeof(char), "illegal bool size");
|
|||
static struct HTAB* nameHash = NULL;
|
||||
static struct HTAB* oidHash = NULL;
|
||||
|
||||
/* for dolphin */
|
||||
/* for b_sql_plugin */
|
||||
struct HTAB* b_nameHash = NULL;
|
||||
struct HTAB* b_oidHash = NULL;
|
||||
|
||||
|
|
@ -118,7 +118,7 @@ static const FuncGroup* NameHashTableAccess(HASHACTION action, const char* name,
|
|||
|
||||
Assert(name != NULL);
|
||||
|
||||
if (DB_IS_CMPT(B_FORMAT) && b_nameHash != NULL && u_sess->attr.attr_sql.dolphin) {
|
||||
if (DB_IS_CMPT(B_FORMAT) && b_nameHash != NULL && u_sess->attr.attr_sql.b_sql_plugin) {
|
||||
result = (HashEntryNameToFuncGroup *)hash_search(b_nameHash, &temp_name, action, &found);
|
||||
} else {
|
||||
result = (HashEntryNameToFuncGroup *)hash_search(nameHash, &temp_name, action, &found);
|
||||
|
|
@ -144,7 +144,7 @@ static const Builtin_func* OidHashTableAccess(HASHACTION action, Oid oid, const
|
|||
bool found = false;
|
||||
Assert(oid > 0);
|
||||
|
||||
if (DB_IS_CMPT(B_FORMAT) && b_oidHash != NULL && u_sess->attr.attr_sql.dolphin) {
|
||||
if (DB_IS_CMPT(B_FORMAT) && b_oidHash != NULL && u_sess->attr.attr_sql.b_sql_plugin) {
|
||||
result = (HashEntryOidToBuiltinFunc *)hash_search(b_oidHash, &oid, action, &found);
|
||||
} else {
|
||||
result = (HashEntryOidToBuiltinFunc *)hash_search(oidHash, &oid, action, &found);
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
#include "utils/builtins.h"
|
||||
#include "utils/fmgroids.h"
|
||||
#include "utils/syscache.h"
|
||||
#include "replication/worker_internal.h"
|
||||
|
||||
static List *textarray_to_stringlist(ArrayType *textarray);
|
||||
|
||||
|
|
@ -90,13 +91,6 @@ Subscription *GetSubscription(Oid subid, bool missing_ok)
|
|||
}
|
||||
sub->publications = textarray_to_stringlist(DatumGetArrayTypeP(datum));
|
||||
|
||||
datum = SysCacheGetAttr(SUBSCRIPTIONOID, tup, Anum_pg_subscription_subbinary, &isnull);
|
||||
if (unlikely(isnull)) {
|
||||
sub->binary = false;
|
||||
} else {
|
||||
sub->binary = DatumGetBool(datum);
|
||||
}
|
||||
|
||||
ReleaseSysCache(tup);
|
||||
|
||||
return sub;
|
||||
|
|
@ -189,7 +183,7 @@ char *get_subscription_name(Oid subid, bool missing_ok)
|
|||
}
|
||||
|
||||
/* Clear the list content, only deal with DefElem and string content */
|
||||
void ClearListContent(List *list)
|
||||
static void ClearListContent(List *list)
|
||||
{
|
||||
ListCell *cell = NULL;
|
||||
foreach(cell, list) {
|
||||
|
|
@ -209,6 +203,25 @@ void ClearListContent(List *list)
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Decrypt conninfo for subscription.
|
||||
* IMPORTANT: caller should clear and free the memory after using it immediately
|
||||
*/
|
||||
char *DecryptConninfo(char *encryptConninfo)
|
||||
{
|
||||
const char* sensitiveOptionsArray[] = {"password"};
|
||||
const int sensitiveArrayLength = lengthof(sensitiveOptionsArray);
|
||||
List *defList = ConninfoToDefList(encryptConninfo);
|
||||
DecryptOptions(defList, sensitiveOptionsArray, sensitiveArrayLength, SUBSCRIPTION_MODE);
|
||||
char *decryptConninfo = DefListToString(defList);
|
||||
|
||||
/* defList has plain content, clear it before free */
|
||||
ClearListContent(defList);
|
||||
list_free_ext(defList);
|
||||
/* IMPORTANT: caller should clear and free the memory after using it immediately */
|
||||
return decryptConninfo;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert text array to list of strings.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -70,7 +70,6 @@
|
|||
|
||||
THR_LOCAL bool skip_read_extern_fields = false;
|
||||
|
||||
#define IS_DATANODE_BUT_NOT_SINGLENODE (IS_PGXC_DATANODE && !IS_SINGLE_NODE)
|
||||
/*
|
||||
* Macros to simplify reading of different kinds of fields. Use these
|
||||
* wherever possible to reduce the chance for silly typos. Note that these
|
||||
|
|
@ -402,27 +401,24 @@ THR_LOCAL bool skip_read_extern_fields = false;
|
|||
token = pg_strtok(&length); /* skip :fldname */ \
|
||||
local_node->fldname = _readBitmapset()
|
||||
|
||||
#define READ_TYPEINFO_FIELD(fldname) \
|
||||
do { \
|
||||
if (local_node->fldname >= FirstBootstrapObjectId) { \
|
||||
IF_EXIST(exprtypename) \
|
||||
{ \
|
||||
char* exprtypename = NULL; \
|
||||
char* exprtypenamespace = NULL; \
|
||||
token = pg_strtok(&length); \
|
||||
token = pg_strtok(&length); \
|
||||
exprtypename = nullable_string(token, length); \
|
||||
token = pg_strtok(&length); \
|
||||
token = pg_strtok(&length); \
|
||||
exprtypenamespace = nullable_string(token, length); \
|
||||
/* No need to reset field on CN or singlenode, keep pg_strtok() for forward compatibility */ \
|
||||
if (IS_DATANODE_BUT_NOT_SINGLENODE) { \
|
||||
local_node->fldname = get_typeoid(get_namespace_oid(exprtypenamespace, false), exprtypename); \
|
||||
} \
|
||||
pfree_ext(exprtypename); \
|
||||
pfree_ext(exprtypenamespace); \
|
||||
} \
|
||||
} \
|
||||
#define READ_TYPEINFO_FIELD(fldname) \
|
||||
do { \
|
||||
if (local_node->fldname >= FirstBootstrapObjectId) { \
|
||||
IF_EXIST(exprtypename) \
|
||||
{ \
|
||||
char* exprtypename = NULL; \
|
||||
char* exprtypenamespace = NULL; \
|
||||
token = pg_strtok(&length); \
|
||||
token = pg_strtok(&length); \
|
||||
exprtypename = nullable_string(token, length); \
|
||||
token = pg_strtok(&length); \
|
||||
token = pg_strtok(&length); \
|
||||
exprtypenamespace = nullable_string(token, length); \
|
||||
local_node->fldname = get_typeoid(get_namespace_oid(exprtypenamespace, false), exprtypename); \
|
||||
pfree_ext(exprtypename); \
|
||||
pfree_ext(exprtypenamespace); \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define READ_TYPEINFO(typePtr) \
|
||||
|
|
@ -497,30 +493,9 @@ THR_LOCAL bool skip_read_extern_fields = false;
|
|||
token = pg_strtok(&length); \
|
||||
token = pg_strtok(&length); \
|
||||
funcnamespace = nullable_string(token, length); \
|
||||
bool notfound = false; \
|
||||
if (IS_DATANODE_BUT_NOT_SINGLENODE && !skip_read_extern_fields) { \
|
||||
Oid funcoid = InvalidOid; \
|
||||
do { \
|
||||
Oid nspid = get_namespace_oid(funcnamespace, true); \
|
||||
if (!OidIsValid(nspid)) { \
|
||||
notfound = true; \
|
||||
break; \
|
||||
} \
|
||||
funcoid = get_func_oid(funcname, nspid, (Expr*)local_node); \
|
||||
} while (0); \
|
||||
if (notfound || !OidIsValid(funcoid)) { \
|
||||
ereport(ERROR, \
|
||||
(errmodule(MOD_OPT), errcode(ERRCODE_UNDEFINED_OBJECT), \
|
||||
errmsg("Cannot identify function %s.%s while deserializing field.", \
|
||||
funcname, funcnamespace), \
|
||||
errdetail("Function with oid %u or its namespace may be renamed", \
|
||||
local_node->fldname), \
|
||||
errhint("Please rebuild column defalt expression, views etc. that are" \
|
||||
" related to this renamed object."), \
|
||||
errcause("Object renamed after recorded as nodetree."), \
|
||||
erraction("Rebuild relevant object."))); \
|
||||
} \
|
||||
local_node->fldname = funcoid; \
|
||||
if (IS_PGXC_DATANODE && !skip_read_extern_fields) { \
|
||||
local_node->fldname = \
|
||||
get_func_oid(funcname, get_namespace_oid(funcnamespace, false), (Expr*)local_node); \
|
||||
} \
|
||||
pfree_ext(funcname); \
|
||||
pfree_ext(funcnamespace); \
|
||||
|
|
@ -550,7 +525,7 @@ THR_LOCAL bool skip_read_extern_fields = false;
|
|||
token = pg_strtok(&length); \
|
||||
token = pg_strtok(&length); \
|
||||
oprrightname = nullable_string(token, length); \
|
||||
if (IS_DATANODE_BUT_NOT_SINGLENODE) { \
|
||||
if (IS_PGXC_DATANODE) { \
|
||||
namespaceId = get_namespace_oid(opnamespace, false); \
|
||||
oprleft = get_typeoid(namespaceId, oprleftname); \
|
||||
oprright = oprleft; \
|
||||
|
|
@ -593,7 +568,7 @@ THR_LOCAL bool skip_read_extern_fields = false;
|
|||
token = pg_strtok(&length); \
|
||||
token = pg_strtok(&length); \
|
||||
oprrightname = nullable_string(token, length); \
|
||||
if (IS_DATANODE_BUT_NOT_SINGLENODE) { \
|
||||
if (IS_PGXC_DATANODE) { \
|
||||
namespaceId = get_namespace_oid(opnamespace, false); \
|
||||
oprleft = get_typeoid(namespaceId, oprleftname); \
|
||||
oprright = oprleft; \
|
||||
|
|
@ -2151,21 +2126,14 @@ static FuncExpr* _readFuncExpr(void)
|
|||
ereport(ERROR, (errcode(ERRCODE_UNEXPECTED_NULL_VALUE), errmsg("NULL seqNamespace for nextval()")));
|
||||
}
|
||||
|
||||
if (IS_DATANODE_BUT_NOT_SINGLENODE && !skip_read_extern_fields) {
|
||||
if (!IS_PGXC_COORDINATOR && !skip_read_extern_fields) {
|
||||
Oid seqid = get_valid_relname_relid(seqNamespace, seqName);
|
||||
|
||||
Oid seqid = get_valid_relname_relid(seqNamespace, seqName, true);
|
||||
Const* firstArg = (Const*)linitial(local_node->args);
|
||||
if (OidIsValid(seqid)) {
|
||||
Const* firstArg = (Const*)linitial(local_node->args);
|
||||
if (firstArg != NULL) {
|
||||
firstArg->constvalue = ObjectIdGetDatum(seqid);
|
||||
}
|
||||
} else {
|
||||
ereport(ERROR, (errmodule(MOD_OPT), errcode(ERRCODE_UNDEFINED_OBJECT),
|
||||
errmsg("Cannot identify sequence %s.%s while deserializing field.", seqNamespace, seqName),
|
||||
errdetail("Sequence with oid %u or its namespace may be renamed",
|
||||
DatumGetObjectId(firstArg->constvalue)),
|
||||
errhint("Please rebuild column defalt expression, views etc. that are related to this sequence"),
|
||||
errcause("Object renamed after recorded as nodetree."), erraction("Rebuild relevant object.")));
|
||||
}
|
||||
}
|
||||
pfree_ext(seqName);
|
||||
|
|
|
|||
|
|
@ -1454,14 +1454,7 @@ FuncCandidateList sort_candidate_func_list(FuncCandidateList oldCandidates)
|
|||
}
|
||||
candidates[smallestIndex] = NULL;
|
||||
}
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
if (candidates[i] != NULL) {
|
||||
lastCandidate->next = candidates[i];
|
||||
lastCandidate = lastCandidate->next;
|
||||
}
|
||||
}
|
||||
lastCandidate->next = NULL;
|
||||
|
||||
pfree(candidates);
|
||||
return sortedCandidates;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ void GlobalBaseDefCache::RemoveElemFromBucket(GlobalBaseEntry *base)
|
|||
if (is_relation) {
|
||||
GlobalRelationEntry *entry = (GlobalRelationEntry *)base;
|
||||
uint64 rel_size = GetRelEstimateSize(entry);
|
||||
pg_atomic_fetch_sub_u64(&m_base_space, AllocSetContextUsedSpace(((AllocSet)entry->rel_mem_manager)));
|
||||
pg_atomic_fetch_sub_u64(&m_base_space, rel_size);
|
||||
m_db_entry->MemoryEstimateSub(rel_size);
|
||||
} else {
|
||||
GlobalPartitionEntry *entry = (GlobalPartitionEntry *)base;
|
||||
|
|
@ -77,7 +77,7 @@ void GlobalBaseDefCache::AddHeadToBucket(Index hash_index, GlobalBaseEntry *base
|
|||
if (is_relation) {
|
||||
GlobalRelationEntry *entry = (GlobalRelationEntry *)base;
|
||||
uint64 rel_size = GetRelEstimateSize(entry);
|
||||
pg_atomic_fetch_add_u64(&m_base_space, AllocSetContextUsedSpace(((AllocSet)entry->rel_mem_manager)));
|
||||
pg_atomic_fetch_add_u64(&m_base_space, rel_size);
|
||||
m_db_entry->MemoryEstimateAdd(rel_size);
|
||||
} else {
|
||||
GlobalPartitionEntry *entry = (GlobalPartitionEntry *)base;
|
||||
|
|
@ -400,4 +400,4 @@ GlobalBaseDefCache::GlobalBaseDefCache(Oid db_oid, bool is_shared, GlobalSysDBCa
|
|||
m_base_space = 0;
|
||||
m_obj_locks = NULL;
|
||||
m_db_entry = entry;
|
||||
}
|
||||
}
|
||||
|
|
@ -659,27 +659,7 @@ void GlobalSysDBCache::InitSysCacheRelIds()
|
|||
*/
|
||||
void GlobalSysDBCache::RefreshHotStandby()
|
||||
{
|
||||
if (!EnableGlobalSysCache()) {
|
||||
return;
|
||||
}
|
||||
hot_standby = (t_thrd.postmaster_cxt.HaShmData->current_mode != STANDBY_MODE || XLogStandbyInfoActive());
|
||||
if (hot_standby || !m_is_inited) {
|
||||
return;
|
||||
}
|
||||
/* clean all */
|
||||
for (int hash_index = 0; hash_index < m_nbuckets; hash_index ++) {
|
||||
PthreadRWlockRdlock(LOCAL_SYSDB_RESOWNER, &m_db_locks[hash_index]);
|
||||
for (Dlelem * elt = DLGetTail(m_bucket_list.GetBucket(hash_index)); elt != NULL;) {
|
||||
GlobalSysDBCacheEntry *entry = (GlobalSysDBCacheEntry *)DLE_VAL(elt);
|
||||
elt = DLGetPred(elt);
|
||||
entry->ResetDBCache<true>();
|
||||
}
|
||||
PthreadRWlockUnlock(LOCAL_SYSDB_RESOWNER, &m_db_locks[hash_index]);
|
||||
}
|
||||
if (m_global_shared_db_entry != NULL) {
|
||||
m_global_shared_db_entry->ResetDBCache<true>();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void GlobalSysDBCache::Init(MemoryContext parent)
|
||||
|
|
@ -1292,18 +1272,9 @@ int ResizeHashBucket(int origin_nbucket, DynamicHashBucketStrategy strategy)
|
|||
return cc_nbuckets;
|
||||
}
|
||||
|
||||
void NotifyGscRecoveryStarted()
|
||||
{
|
||||
if (!EnableGlobalSysCache()) {
|
||||
return;
|
||||
}
|
||||
g_instance.global_sysdbcache.recovery_finished = false;
|
||||
|
||||
}
|
||||
|
||||
void NotifyGscRecoveryFinished()
|
||||
{
|
||||
if (EnableGlobalSysCache()) {
|
||||
g_instance.global_sysdbcache.recovery_finished = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -183,7 +183,7 @@ void GlobalSysTabCache::InvalidTuples(int cache_id, uint32 hash_value, bool rese
|
|||
|
||||
/* maybe upgrade from version before v5r2c00, the cacheid is out of order
|
||||
* whatever, we cache nothing except relmap, so just ignore the catcache invalmsg */
|
||||
if (unlikely(!g_instance.global_sysdbcache.recovery_finished && m_global_systupcaches[cache_id] == NULL)) {
|
||||
if (unlikely(!g_instance.global_sysdbcache.recovery_finished) && m_global_systupcaches[cache_id] == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ Partition LocalPartDefCache::SearchPartitionFromGlobalCopy(Oid part_oid)
|
|||
if (!g_instance.global_sysdbcache.hot_standby) {
|
||||
return NULL;
|
||||
}
|
||||
if (unlikely(!IsPrimaryRecoveryFinished())) {
|
||||
if (unlikely(!g_instance.global_sysdbcache.recovery_finished)) {
|
||||
return NULL;
|
||||
}
|
||||
uint32 hash_value = oid_hash((void *)&(part_oid), sizeof(Oid));
|
||||
|
|
@ -165,7 +165,7 @@ static bool IsPartOidStoreInGlobal(Oid part_oid)
|
|||
if (!g_instance.global_sysdbcache.hot_standby) {
|
||||
return false;
|
||||
}
|
||||
if (unlikely(!IsPrimaryRecoveryFinished())) {
|
||||
if (unlikely(!g_instance.global_sysdbcache.recovery_finished)) {
|
||||
return false;
|
||||
}
|
||||
if (g_instance.global_sysdbcache.StopInsertGSC()) {
|
||||
|
|
@ -456,4 +456,4 @@ Partition LocalPartDefCache::PartitionIdGetPartition(Oid part_oid, StorageType s
|
|||
}
|
||||
|
||||
return pd;
|
||||
}
|
||||
}
|
||||
|
|
@ -433,7 +433,7 @@ LocalCatCTup *LocalSysTupCache::SearchTupleFromGlobal(Datum *arguments, uint32 h
|
|||
bool bypass_gsc = HistoricSnapshotActive() ||
|
||||
m_global_systupcache->enable_rls ||
|
||||
!g_instance.global_sysdbcache.hot_standby ||
|
||||
unlikely(!IsPrimaryRecoveryFinished());
|
||||
unlikely(!g_instance.global_sysdbcache.recovery_finished);
|
||||
if (invalid_entries.ExistTuple(hash_value) || bypass_gsc) {
|
||||
global_ct = m_global_systupcache->SearchTupleFromFile(hash_value, arguments, true);
|
||||
} else {
|
||||
|
|
@ -585,7 +585,7 @@ LocalCatCList *LocalSysTupCache::SearchListFromGlobal(int nkeys, Datum *argument
|
|||
bool bypass_gsc = HistoricSnapshotActive() ||
|
||||
m_global_systupcache->enable_rls ||
|
||||
!g_instance.global_sysdbcache.hot_standby ||
|
||||
unlikely(!IsPrimaryRecoveryFinished());
|
||||
unlikely(!g_instance.global_sysdbcache.recovery_finished);
|
||||
GlobalCatCList *global_cl;
|
||||
if (invalid_entries.ExistList() || bypass_gsc) {
|
||||
global_cl = m_global_systupcache->SearchListFromFile(hash_value, nkeys, arguments, true);
|
||||
|
|
@ -703,7 +703,7 @@ LocalCatCTup *LocalSysTupCache::SearchTupleFromGlobalForProcAllArgs(
|
|||
bool bypass_gsc = HistoricSnapshotActive() ||
|
||||
m_global_systupcache->enable_rls ||
|
||||
!g_instance.global_sysdbcache.hot_standby ||
|
||||
unlikely(!IsPrimaryRecoveryFinished());
|
||||
unlikely(!g_instance.global_sysdbcache.recovery_finished);
|
||||
if (invalid_entries.ExistTuple(hash_value) || bypass_gsc) {
|
||||
global_ct = m_global_systupcache->SearchTupleFromFileWithArgModes(hash_value, arguments, argModes, true);
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ Relation LocalTabDefCache::SearchRelationFromGlobalCopy(Oid rel_oid)
|
|||
if (!g_instance.global_sysdbcache.hot_standby) {
|
||||
return NULL;
|
||||
}
|
||||
if (unlikely(!IsPrimaryRecoveryFinished())) {
|
||||
if (unlikely(!g_instance.global_sysdbcache.recovery_finished)) {
|
||||
return NULL;
|
||||
}
|
||||
uint32 hash_value = oid_hash((void *)&(rel_oid), sizeof(Oid));
|
||||
|
|
@ -190,7 +190,7 @@ static bool IsRelOidStoreInGlobal(Oid rel_oid)
|
|||
if (!g_instance.global_sysdbcache.hot_standby) {
|
||||
return false;
|
||||
}
|
||||
if (unlikely(!IsPrimaryRecoveryFinished())) {
|
||||
if (unlikely(!g_instance.global_sysdbcache.recovery_finished)) {
|
||||
return false;
|
||||
}
|
||||
if (g_instance.global_sysdbcache.StopInsertGSC()) {
|
||||
|
|
@ -1137,4 +1137,4 @@ void LocalTabDefCache::ResetInitFlag()
|
|||
m_is_inited_phase3 = false;
|
||||
|
||||
m_db_id = InvalidOid;
|
||||
}
|
||||
}
|
||||
|
|
@ -1723,7 +1723,7 @@ char* get_relname_relid_extend(
|
|||
extern bool StreamTopConsumerAmI();
|
||||
|
||||
/* same as get_relname_relid except we check for cache invalidation here */
|
||||
Oid get_valid_relname_relid(const char* relnamespace, const char* relname, bool nsp_missing_ok)
|
||||
Oid get_valid_relname_relid(const char* relnamespace, const char* relname)
|
||||
{
|
||||
Oid nspid = InvalidOid;
|
||||
Oid oldnspid = InvalidOid;
|
||||
|
|
@ -1747,10 +1747,7 @@ Oid get_valid_relname_relid(const char* relnamespace, const char* relname, bool
|
|||
if (EnableLocalSysCache()) {
|
||||
thrd_inval_count = t_thrd.lsc_cxt.lsc->inval_cxt.SIMCounter;
|
||||
}
|
||||
nspid = get_namespace_oid(relnamespace, nsp_missing_ok);
|
||||
if (!OidIsValid(nspid)) {
|
||||
return InvalidOid;
|
||||
}
|
||||
nspid = get_namespace_oid(relnamespace, false);
|
||||
relid = get_relname_relid(relname, nspid);
|
||||
/*
|
||||
* In bootstrap processing mode, we don't bother with locking
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ bool open_join_children = true;
|
|||
bool will_shutdown = false;
|
||||
|
||||
/* hard-wired binary version number */
|
||||
const uint32 GRAND_VERSION_NUM = 92606;
|
||||
const uint32 GRAND_VERSION_NUM = 92605;
|
||||
|
||||
const uint32 PREDPUSH_SAME_LEVEL_VERSION_NUM = 92522;
|
||||
const uint32 UPSERT_WHERE_VERSION_NUM = 92514;
|
||||
|
|
@ -101,7 +101,6 @@ const uint32 PRIVS_DIRECTORY_VERSION_NUM = 92460;
|
|||
const uint32 COMMENT_RECORD_PARAM_VERSION_NUM = 92484;
|
||||
const uint32 SCAN_BATCH_MODE_VERSION_NUM = 92568;
|
||||
const uint32 PUBLICATION_VERSION_NUM = 92580;
|
||||
const uint32 SUBSCRIPTION_BINARY_VERSION_NUM = 92606;
|
||||
|
||||
/* Version number of the guc parameter backend_version added in V500R001C20 */
|
||||
const uint32 V5R1C20_BACKEND_VERSION_NUM = 92305;
|
||||
|
|
|
|||
|
|
@ -2712,8 +2712,8 @@ void PostgresInitializer::InitExtensionVariable()
|
|||
}
|
||||
|
||||
/* check whether the extension has been created */
|
||||
const char* dolphin = "dolphin";
|
||||
u_sess->attr.attr_sql.dolphin = CheckIfExtensionExists(dolphin);
|
||||
const char* b_sql_plugin = "b_sql_plugin";
|
||||
u_sess->attr.attr_sql.b_sql_plugin = CheckIfExtensionExists(b_sql_plugin);
|
||||
}
|
||||
|
||||
void PostgresInitializer::FinishInit()
|
||||
|
|
|
|||
|
|
@ -10340,16 +10340,7 @@ check_sql_expr(const char *stmt, int location, int leaderlen)
|
|||
|
||||
oldCxt = MemoryContextSwitchTo(u_sess->plsql_cxt.curr_compile_context->compile_tmp_cxt);
|
||||
u_sess->plsql_cxt.plpgsql_yylloc = plpgsql_yylloc;
|
||||
RawParserHook parser_hook= raw_parser;
|
||||
#ifndef ENABLE_MULTIPLE_NODES
|
||||
if (u_sess->attr.attr_sql.dolphin) {
|
||||
int id = GetCustomParserId();
|
||||
if (id >= 0 && g_instance.raw_parser_hook[id] != NULL) {
|
||||
parser_hook = (RawParserHook)g_instance.raw_parser_hook[id];
|
||||
}
|
||||
}
|
||||
#endif
|
||||
(void)parser_hook(stmt, NULL);
|
||||
(void) raw_parser(stmt);
|
||||
MemoryContextSwitchTo(oldCxt);
|
||||
|
||||
/* Restore former ereport callback */
|
||||
|
|
|
|||
|
|
@ -44,22 +44,11 @@ static int g_iPosBlackList = 0;
|
|||
/* array store for black list */
|
||||
static BBOX_BLACKLIST_STRU g_stBlackList[BBOX_BLACK_LIST_COUNT_MAX];
|
||||
|
||||
/*
|
||||
function name: BBOX_DetermineMsb
|
||||
description: The function should judge the mode that PC uses to store data is Big-endian/Little-endian.
|
||||
arguments: void
|
||||
return value: An integer that indicates the mode is Big-endian/Little-endian,
|
||||
if it is ELFDATA2LSB, the mode is Little-endian,
|
||||
if it is ELFDATA2MSB, the mode is Big-endian.
|
||||
note:The way that this function judge the mode that PC uses to store data is through a union variable unProbe,
|
||||
at first we give its first member variable sShortInt a value BBOX_MSB_LSB_INT of type short, then its second
|
||||
member variable cSplit[sizeof(short)] equaling to cSplit[2] would have the equal value of the first. Finally we
|
||||
just need to compare BBOX_LITTER_BITS and BBOX_HIGH_BITS, namely the low byte and high byte of
|
||||
BBOX_MSB_LSB_INT, with unProbe.cSplit[0] and unProbe.cSplit[1], if they are correspondingly equal, the mode is
|
||||
Little-endian, else is the Big-endian.
|
||||
date: 2022/8/2
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
/*
|
||||
* Determines whether the byte order of the local machine is large or small
|
||||
* return : ELFDATA2LSB - large
|
||||
* : ELFDATA2MSB - small
|
||||
*/
|
||||
int BBOX_DetermineMsb(void)
|
||||
{
|
||||
union INT_PROBE {
|
||||
|
|
|
|||
|
|
@ -51,19 +51,8 @@ struct PIPE_IDS {
|
|||
static struct PIPE_IDS astPipeIds[BBOX_MAX_PIDS];
|
||||
|
||||
/*
|
||||
function name: bbox_strncmp
|
||||
description: To compare two substrings, the pointers pszSrc and pszTarget store their host strings'addresses.
|
||||
arguments: Two pointers of type const char*, pointing to two strings needed to be compared.
|
||||
An integer indicates the number of characters at the former of two strings that
|
||||
will be compared.
|
||||
return value: Type s32, an interger.
|
||||
If it's zero, then the former substrings of string pszSrc and pszTarget are same,
|
||||
else it indicates the difference between the first two characters that these two
|
||||
strings can't match.
|
||||
note:The two pointers shouldn't be null. The last argument shouldn't less than zero.
|
||||
date: 2022/8/2
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
* compare string pszSrc and pszTarget
|
||||
*/
|
||||
s32 bbox_strncmp(const char* pszSrc, const char* pszTarget, s32 count)
|
||||
{
|
||||
signed char cRes = 0;
|
||||
|
|
@ -79,20 +68,8 @@ s32 bbox_strncmp(const char* pszSrc, const char* pszTarget, s32 count)
|
|||
}
|
||||
|
||||
/*
|
||||
function name: bbox_strcmp
|
||||
description: compare two strings, the pointer pszSrc and pszTarget store their addresses.
|
||||
arguments: Two pointers of type const char*, pointing to two strings needed to be compared.
|
||||
An integer indicates the number of characters at the former of two strings that
|
||||
will be compared.
|
||||
return value: Type s32, an interger.
|
||||
If it's zero, then the former substrings of string pszSrc and pszTarget are same,
|
||||
else if it's 1, then it indicates between first two characters that these two
|
||||
strings can't match, the character of first string that pszSrc points is greater,
|
||||
else if it's -1, the character of second string that pszTarget points is greater.
|
||||
note:The two pointers shouldn't be null. The last argument shouldn't less than zero.
|
||||
date: 2022/8/2
|
||||
contact tel:same
|
||||
*/
|
||||
* compare string pszSrc and pszTarget
|
||||
*/
|
||||
s32 bbox_strcmp(const char* pszSrc, const char* pszTarget)
|
||||
{
|
||||
unsigned char c1, c2;
|
||||
|
|
@ -113,15 +90,8 @@ s32 bbox_strcmp(const char* pszSrc, const char* pszTarget)
|
|||
}
|
||||
|
||||
/*
|
||||
function name: bbox_strlen
|
||||
description: Calculate the length of string.
|
||||
arguments: An pointer that indicates the address of a string.
|
||||
return value: Type s32, an integer indicating the length of string.
|
||||
note: the length of string=(address of the last character not '\0'-address of the first character)/sizeof(char), and sizeof(char)
|
||||
equals to 1, so the length of string=(address of the last character not '\0'-address of the first character).
|
||||
date: 2022/8/2
|
||||
contact tel:same
|
||||
*/
|
||||
* get the length of string pszString
|
||||
*/
|
||||
s32 bbox_strlen(const char* pszString)
|
||||
{
|
||||
const char* pszTemp = NULL;
|
||||
|
|
@ -135,16 +105,8 @@ s32 bbox_strlen(const char* pszString)
|
|||
}
|
||||
|
||||
/*
|
||||
function name: bbox_strnlen
|
||||
description: Calculate the length of string, but having some restrictive conditions.
|
||||
arguments: An pointer that indicates the address of a string.
|
||||
And an integer that indicates the maxlenth.
|
||||
return value: Type s32, an integer indicating the length of string.
|
||||
note: If the length of string exceed the argument count, then return the length of string,
|
||||
else return the argument count.
|
||||
date: 2022/8/2
|
||||
contact tel:same
|
||||
*/
|
||||
* get the length of string pszString
|
||||
*/
|
||||
s32 bbox_strnlen(const char* pszString, s32 count)
|
||||
{
|
||||
const char* pszTemp = NULL;
|
||||
|
|
@ -157,16 +119,8 @@ s32 bbox_strnlen(const char* pszString, s32 count)
|
|||
}
|
||||
|
||||
/*
|
||||
function name: bbox_atoi
|
||||
description: Convert a string that includes continuous digital characters to an integer,
|
||||
if the first character of the string is '-', then we will return a negative result.
|
||||
arguments: An pointer that indicates the address of a string.
|
||||
return value: Type s32, an integer indicating the result of string converted.
|
||||
note: I think the function isn't perfect, though it's not a core function. For example, what about
|
||||
the condition that the first character of the string is '+'?
|
||||
date: 2022/8/2
|
||||
contact tel:same
|
||||
*/
|
||||
* convert a string to interger
|
||||
*/
|
||||
s32 bbox_atoi(const char* pszString)
|
||||
{
|
||||
s32 n = 0;
|
||||
|
|
@ -186,18 +140,10 @@ s32 bbox_atoi(const char* pszString)
|
|||
|
||||
return iNeg ? -n : n;
|
||||
}
|
||||
|
||||
/*
|
||||
function name: bbox_memcmp
|
||||
description: Compare former count bytes in ASCII of data stored in two areas that pointers cs and ct direct.
|
||||
arguments: Two pointers to areas of memory, and an integer indicating the max counts compared.
|
||||
return value: Type s32, an integer.
|
||||
If the value returned is 0, then the data stored in two areas destined are same,
|
||||
else if is 1, then between two first data in ASCII of byte different, cs's is greater,
|
||||
else if is -1, then ct's is greater.
|
||||
note: The two pointers should not be null, it's dangerous.
|
||||
date: 2022/8/2
|
||||
contact tel: same
|
||||
*/
|
||||
* compare memory
|
||||
*/
|
||||
s32 bbox_memcmp(const void* cs, const void* ct, s32 count)
|
||||
{
|
||||
const unsigned char *su1 = NULL;
|
||||
|
|
@ -213,18 +159,8 @@ s32 bbox_memcmp(const void* cs, const void* ct, s32 count)
|
|||
}
|
||||
|
||||
/*
|
||||
function name: bbox_strstr
|
||||
description: Judge if the string s2 directs is substring of string s1 directs.
|
||||
arguments: Two pointers of type const char*, pointing to two strings.
|
||||
return value: Type char*, a pointer. Actually it's a address, if s2 directs a
|
||||
null string, then return the address of the first character of s1,
|
||||
if the string s2 directs isn't substring of string s1 directs, return
|
||||
null, if the string s2 directs is substring of string s1 directs, then return
|
||||
the address of first character matched.
|
||||
note: The two pointers should not be null, it's dangerous.
|
||||
date: 2022/8/2
|
||||
contact tel: same
|
||||
*/
|
||||
* search string l2 in l1
|
||||
*/
|
||||
char* bbox_strstr(const char* s1, const char* s2)
|
||||
{
|
||||
int l1, l2;
|
||||
|
|
@ -246,17 +182,8 @@ char* bbox_strstr(const char* s1, const char* s2)
|
|||
}
|
||||
|
||||
/*
|
||||
function name: bbox_mkdir
|
||||
description: We distinguish parent directory and child directory through character '/',
|
||||
normally through a for loop, we can make sure all directories above the directory
|
||||
we want to creat exist, finally we will creat the flag directory after its parent.
|
||||
arguments: A pointers of type const char*, pointing to one strings, which indicates the filename and its full path.
|
||||
return value: An integer of type s32, if it's RET_ERR, then we fail to make a directory, else if it's RET_OK then we succeed.
|
||||
note: Take care the last non-null character of the string needed to be '/', and once if flag directory's
|
||||
ancestors aren't exist, the function return RET_ERR.
|
||||
date: 2022/8/2
|
||||
contact tel: same
|
||||
*/
|
||||
* make a directory
|
||||
*/
|
||||
s32 bbox_mkdir(const char* pszDir)
|
||||
{
|
||||
char szDirName[BBOX_TMP_LEN_32 * 16];
|
||||
|
|
@ -301,16 +228,8 @@ s32 bbox_mkdir(const char* pszDir)
|
|||
}
|
||||
|
||||
/*
|
||||
function name: bbox_GetFreePid
|
||||
description: Through a for loop, we search a free pipe in a structure array, to an array element if its
|
||||
member variable isUsed's value is 0, we return the array element's another member variable
|
||||
stPid's address.
|
||||
arguments: void
|
||||
return value: An pointer of type struct PIPE_ID* or NULL.
|
||||
note: none
|
||||
date: 2022/8/2
|
||||
contact tel: same
|
||||
*/
|
||||
* search free pipe id
|
||||
*/
|
||||
struct PIPE_ID* bbox_GetFreePid(void)
|
||||
{
|
||||
u32 i;
|
||||
|
|
@ -326,14 +245,8 @@ struct PIPE_ID* bbox_GetFreePid(void)
|
|||
}
|
||||
|
||||
/*
|
||||
function name: bbox_PutPid
|
||||
description: Release the occupied pipe.
|
||||
arguments: A pointer of type struct PIPE_ID*.
|
||||
return value: void
|
||||
note: If the argument pointer is null, then there is no need to free the storage, the function ends.
|
||||
date: 2022/8/2
|
||||
contact tel: same
|
||||
*/
|
||||
* Release the occupied pipeid
|
||||
*/
|
||||
void bbox_PutPid(struct PIPE_ID* pstPid)
|
||||
{
|
||||
struct PIPE_IDS* pstPids = NULL;
|
||||
|
|
@ -348,16 +261,8 @@ void bbox_PutPid(struct PIPE_ID* pstPid)
|
|||
}
|
||||
|
||||
/*
|
||||
function name: bbox_FindPid
|
||||
description: In all occupied pipes, the function search the flag pipe through compare all structure
|
||||
array elements's member variable stPid's member variable iFd with the function
|
||||
argument iFd, if they are equal, then return the addres of this array elements.
|
||||
arguments: An integer that indicates a file's file handle.
|
||||
return value: A pointer of type struct PIPE_ID* or NULL.
|
||||
note: none
|
||||
date: 2022/8/2
|
||||
contact tel: same
|
||||
*/
|
||||
* find available pipe id by file handle
|
||||
*/
|
||||
struct PIPE_ID* bbox_FindPid(int iFd)
|
||||
{
|
||||
u32 i;
|
||||
|
|
@ -376,17 +281,8 @@ struct PIPE_ID* bbox_FindPid(int iFd)
|
|||
}
|
||||
|
||||
/*
|
||||
function name: sys_popen
|
||||
description: The function gets a free pipe by function bbox_GetFreePid, if normally, then creat a pipe
|
||||
through sys_pipe, andcreat a child process through function sys_fork, execute a shell command
|
||||
to run a process.
|
||||
arguments: One pointer to a string that represents command line, another pointer of type const char*
|
||||
indicates that the file file handle directs is used in the this mode.
|
||||
return value: A pointer of type struct PIPE_ID* or NULL.
|
||||
note: The string that indicates pszMode should only be "r" or "w",
|
||||
date: 2022/8/2
|
||||
contact tel: same
|
||||
*/
|
||||
* run popen
|
||||
*/
|
||||
s32 sys_popen(char* pszCmd, const char* pszMode)
|
||||
{
|
||||
struct PIPE_ID* volatile stCurPid = NULL;
|
||||
|
|
@ -491,15 +387,8 @@ s32 sys_popen(char* pszCmd, const char* pszMode)
|
|||
}
|
||||
|
||||
/*
|
||||
function name: sys_pclose
|
||||
description: The function has an contrary action to function sys_popen, it close the pipe
|
||||
that sys_popen open.
|
||||
arguments: iFd, an integer that indicates a file handle.
|
||||
return value: An integer that indicates the final status of the process working before.
|
||||
note: none
|
||||
date: 2022/8/2
|
||||
contact tel: same
|
||||
*/
|
||||
* close file handle
|
||||
*/
|
||||
int sys_pclose(s32 iFd)
|
||||
{
|
||||
struct PIPE_ID* pstCur = NULL;
|
||||
|
|
@ -522,17 +411,8 @@ int sys_pclose(s32 iFd)
|
|||
}
|
||||
|
||||
/*
|
||||
function name: bbox_listdir
|
||||
description: The function list all files below this path in directory.
|
||||
arguments: The first argument is a pointer to a string representing a file path, all files below
|
||||
this path will be listed in directory. The second argument is a pointer to a callback
|
||||
function. The last is a pointer of type void*, it indicates a command line.
|
||||
return value: An integer that indicates the result of function, if normal, it's RET_OK, else
|
||||
it's RET_ERR.
|
||||
note: The path that the first argument represents should be absolute path, take care.
|
||||
date: 2022/8/2
|
||||
contact tel: same
|
||||
*/
|
||||
* list file in directory
|
||||
*/
|
||||
s32 bbox_listdir(const char* pstPath, BBOX_LIST_DIR_CALLBACK callback, void* pArgs)
|
||||
{
|
||||
struct linux_dirent* pstEntry = NULL;
|
||||
|
|
|
|||
|
|
@ -57,37 +57,23 @@ void bbox_initlog(int iLogScreen)
|
|||
}
|
||||
|
||||
/*
|
||||
function name: bbox_itoc
|
||||
description: Convert an integer to a character.
|
||||
arguments: An integer needed to be converted.
|
||||
return value: An character that corresponds to the function's integer argument.
|
||||
note: The integer argument can be converted in radices more than decimalism.
|
||||
date: 2022/8/2
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
* convert int to string
|
||||
*/
|
||||
inline char bbox_itoc(u8 sNum)
|
||||
{
|
||||
return (char)((sNum < 10) ? (sNum + 48) : (sNum + 87));
|
||||
}
|
||||
|
||||
/*
|
||||
function name: bbox_put_dox
|
||||
description: Conversion of number systems.
|
||||
arguments: The first argument pCallback is a pointer to a callback function, we
|
||||
use it to reverse the final result. The second argument is a pointer of
|
||||
type void* used as a argument of function pCallback. The third argument
|
||||
piCount is a pointer of type int, an offset pointer, also be used as a argument
|
||||
of pCallback. The fourth argument is an integer of 32 bits, it indicates the buffer
|
||||
size pCallback uses.The fifth argument uNum is a decimal integer that will
|
||||
be converted to an integer in another radix. The sixth argument is used as
|
||||
base to conversion of number systems. The last argument indicates the integer
|
||||
after converted is a negative integer or not.
|
||||
return value: An integer, indicating if the function pCallback work successfully.
|
||||
note: The argument uNum should be a positive integer, after conversion of number systems
|
||||
the sign will be appended to string's tail.
|
||||
date: 2022/8/2
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
* convert int to string
|
||||
* in : pCallback - call back function
|
||||
* ptr - private data to call this function
|
||||
* piCount - offset pointer
|
||||
* iSize - buffer size
|
||||
* uNum - the variable to convert
|
||||
* sSys - type of variable
|
||||
* isNeg - is negative
|
||||
* return : need call back
|
||||
*/
|
||||
s32 bbox_put_dox(BBOX_vnprintCallBack pCallback, void* ptr, s32* piCount, u32 iSize, u64 uNum, s32 sSys, s32 isNeg)
|
||||
{
|
||||
s64 i = 0;
|
||||
|
|
@ -122,21 +108,15 @@ s32 bbox_put_dox(BBOX_vnprintCallBack pCallback, void* ptr, s32* piCount, u32 iS
|
|||
|
||||
return iRet;
|
||||
}
|
||||
|
||||
/*
|
||||
function name: bbox_vsnprintf
|
||||
description: The function is used to print string in corresponding array.
|
||||
arguments: The first argument is a pointer to a callback function, the next is a
|
||||
pointer to private data to call this function, also to buffer.
|
||||
The third is used to destine buffer size. The forth is used to destine
|
||||
the print format of deferent string, the last is a pointer to variable parameter list.
|
||||
return value: An integer, if iSize is big enough, then the return value is the length of
|
||||
string been written in destined memory successfully, not include '\0',
|
||||
if function makes errors, the return value is a negative integer.
|
||||
note: none
|
||||
date: 2022/8/3
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
* simple signal-safe function vsnprintf
|
||||
* in : pCallback - call back function
|
||||
* ptr - private data to call this function
|
||||
* iSize - buffer size
|
||||
* pFmt - format type
|
||||
* ap - parameter list pointer¸ñʽ
|
||||
* return : length of string
|
||||
*/
|
||||
s32 bbox_vsnprintf(BBOX_vnprintCallBack pCallback, void* ptr, s32 iSize, const char* pFmt, va_list ap)
|
||||
{
|
||||
|
||||
|
|
@ -255,20 +235,13 @@ s32 bbox_vsnprintf(BBOX_vnprintCallBack pCallback, void* ptr, s32 iSize, const c
|
|||
}
|
||||
|
||||
/*
|
||||
function name: bbox_SnprintCallback
|
||||
description: The function is used to print string in corresponding array, usually
|
||||
used as the first argument of function bbox_vsnprintf.
|
||||
arguments: The first argument is a character waited to be written into buffer that
|
||||
pPtr directs, the second argument directs a buffer area, the third is a
|
||||
pointer to an integera used to record the count to call this callback function,
|
||||
at the same time, it represents the count of characters written into buffer, it's
|
||||
a pointer so that we can conveniently modify data storedin it. The last
|
||||
argument destines the size of buffer, it represents the limit of length.
|
||||
return value: An integer, if written successfully, it's RET_OK, else it's RET_ERR.
|
||||
note: none
|
||||
date: 2022/8/3
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
* call back function of snprintf_s
|
||||
* in : c - string to calculate
|
||||
* pPtr - pointer to buffer
|
||||
* piCount - count of character
|
||||
* iSize - limit of length
|
||||
* return : length of string
|
||||
*/
|
||||
s32 bbox_SnprintCallback(char c, void* pPtr, s32* piCount, s32 iSize)
|
||||
{
|
||||
char** pszBuff = (char**)pPtr;
|
||||
|
|
|
|||
|
|
@ -64,14 +64,8 @@ u8 g_szAltStackMem[BBOX_ALT_STACKSIZE]; /* independent thread stack memory */
|
|||
BBOX_ATOMIC_STRU g_isBusy = BBOX_ATOMIC_INIT(0); /* whether deal with core file. */
|
||||
|
||||
/*
|
||||
function name: BBOX_ReserveZeroStack
|
||||
description: The function creat a empty stack, and its size depend on argument count.
|
||||
arguments: An integer of type s32, namely int, it destines the storage of stack.
|
||||
return value: void
|
||||
note: The stack this function creats is actually a character array.
|
||||
date: 2022/8/3
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
* reserved count bytes on current stack, and set 0
|
||||
*/
|
||||
void BBOX_ReserveZeroStack(s32 count)
|
||||
{
|
||||
char buff[count];
|
||||
|
|
@ -101,14 +95,8 @@ s32 BBOX_CloneRun(u32 uFlags, s32 (*pFn)(void*), void* pArg, ...)
|
|||
}
|
||||
|
||||
/*
|
||||
function name: BBOX_GetTaskNumber
|
||||
description: When get a path to specific process, this function will return count of threads below it.
|
||||
arguments: A pointer of type char*, including a path to specific process.
|
||||
return value: An integer that indicates the count of threads below specific process.
|
||||
note: none
|
||||
date: 2022/8/3
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
* get count of thread
|
||||
*/
|
||||
s32 BBOX_GetTaskNumber(char* szTaskPath)
|
||||
{
|
||||
struct kernel_stat stProcSB = {0};
|
||||
|
|
@ -142,17 +130,8 @@ s32 BBOX_GetTaskNumber(char* szTaskPath)
|
|||
}
|
||||
|
||||
/*
|
||||
function name: BBOX_GetTaskId
|
||||
description: When get a path to specific process, this function will return count of threads below it.
|
||||
arguments: The first argument is a structure pointer named pstTaskInfo,its type is struct TASK_ATTACH_INFO*,
|
||||
we use it as a structure array to store requisite thread infomation, the next argument destines
|
||||
the max size of the array that the first argument destines. The last argument is a pointer of type
|
||||
char*, including a path to specific process.
|
||||
return value: An integer that indicates the count of threads stored in structure array.
|
||||
note: none
|
||||
date: 2022/8/3
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
* get thread pid
|
||||
*/
|
||||
s32 BBOX_GetTaskId(struct TASK_ATTACH_INFO* pstTaskInfo, s32 iSize, char* szTaskPath)
|
||||
{
|
||||
s32 iProc = -1;
|
||||
|
|
@ -235,19 +214,13 @@ errout:
|
|||
}
|
||||
|
||||
/*
|
||||
function name: BBOX_PtraceAttachPid
|
||||
description: The function is used to check the process whose id stored in structure array pstTaskInfo work normally.
|
||||
arguments: The first argument is a structure pointer named pstTaskInfo,its type is struct TASK_ATTACH_INFO*,
|
||||
it is used as a structure array that has stored requisite thread infomation, the next argument destines
|
||||
the size of the array that the first argument destines, namely how many elements the array has.
|
||||
The last argument is an integer to decide if need to check if the trace to destined process
|
||||
work normally, if normal, corresponding element of array pstTaskInfo's member variable cIsAttached
|
||||
will change from 0 to 1.
|
||||
return value: An integer, if function work normally, the value is RET_OK, else is RET_ERR.
|
||||
note: none
|
||||
date: 2022/8/3
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
* a ptrace debug thread
|
||||
* in : TASK_ATTACH_INFO - thread information
|
||||
* iPidCount - count of thread information
|
||||
* iDoPtraceCheck - check if ptrace success
|
||||
* return : 0 - success
|
||||
* err code - failed
|
||||
*/
|
||||
s32 BBOX_PtraceAttachPid(struct TASK_ATTACH_INFO* pstTaskInfo, s32 iPidCount, s32 iDoPtraceCheck)
|
||||
{
|
||||
u32 i;
|
||||
|
|
@ -299,18 +272,13 @@ s32 BBOX_PtraceAttachPid(struct TASK_ATTACH_INFO* pstTaskInfo, s32 iPidCount, s3
|
|||
}
|
||||
|
||||
/*
|
||||
function name: BBOX_DetachAllThread
|
||||
description: The function is used to cancel checking the process whose id stored in structure array pstTaskInfo
|
||||
work normally, "work normally" means in array pstTaskInfo corresponding element's member
|
||||
variable cIsAttached's value is 1.
|
||||
arguments: The first argument is a structure pointer named pstTaskInfo,its type is struct TASK_ATTACH_INFO*,
|
||||
it is used as a structure array that has stored requisite thread infomation, the next argument destines
|
||||
the size of the array that the first argument destines, namely how many elements the array has.
|
||||
return value: void
|
||||
note: none
|
||||
date: 2022/8/3
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
* cancel ptrace debug thread
|
||||
* in : TASK_ATTACH_INFO - thread information
|
||||
* iPidCount - count of thread information
|
||||
* iDoPtraceCheck - check if ptrace success
|
||||
* return : 0 - success
|
||||
* err code - failed
|
||||
*/
|
||||
void BBOX_DetachAllThread(struct TASK_ATTACH_INFO* pstTaskInfo, s32 iPidCount)
|
||||
{
|
||||
u32 i;
|
||||
|
|
@ -355,18 +323,12 @@ void BBOX_CheckResumeThread(void* pArgs)
|
|||
}
|
||||
|
||||
/*
|
||||
function name: BBOX_PtraceAndRun
|
||||
description: When get a path to specific process, this function will trace the threads below it, and get the
|
||||
information for example how many threads work normally then store it in pstArgs.
|
||||
arguments: The first argument is a structure pointer named pstArgs, its type is struct BBOX_ListParams*,
|
||||
what matters is its member variable callback function pointer, the next argument destines
|
||||
the max count of the thread. The last argument is a pointer of type char*, including a path
|
||||
to specific process.
|
||||
return value: An integer, if function work normally, the value is RET_OK, else is RET_ERR.
|
||||
note: none
|
||||
date: 2022/8/3
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
* ptrace thread and run function.
|
||||
* in : pstArgs - information of callback function
|
||||
* iMaxThreadCount - max count of thread
|
||||
* pszProcSelfTask - /proc/[pid]/task of current tracked thread.
|
||||
* return 0 if success else err code.
|
||||
*/
|
||||
s32 BBOX_PtraceAndRun(struct BBOX_ListParams* pstArgs, s32 iMaxThreadCount, char* pszProcSelfTask)
|
||||
{
|
||||
struct TASK_ATTACH_INFO stTaskInfo[iMaxThreadCount];
|
||||
|
|
@ -445,15 +407,8 @@ errout:
|
|||
}
|
||||
|
||||
/*
|
||||
function name: BBOX_PrintFailedLog
|
||||
description: Write log infomation into specific file, if errors arise, print the infomation about errors.
|
||||
arguments: The only argument is a pointer of type const char* to a filename string, if this file doesn't
|
||||
exist, we will creat a new file named it.
|
||||
return value: An integer, if function work normally, the value is RET_OK, else is RET_ERR.
|
||||
note: none
|
||||
date: 2022/8/3
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
* print log information if export failed.
|
||||
*/
|
||||
void BBOX_PrintFailedLog(const char* pFileName)
|
||||
{
|
||||
ssize_t iRet = 0;
|
||||
|
|
@ -482,15 +437,8 @@ void BBOX_PrintFailedLog(const char* pFileName)
|
|||
}
|
||||
|
||||
/*
|
||||
function name: BBOX_ListThread
|
||||
description: Export thread information.
|
||||
arguments: The only argument is a structure pointer named pstArgs, its type is struct BBOX_ListParams*,
|
||||
what matters is its member variable callback function pointer and thread infomation.
|
||||
return value: void
|
||||
note: none
|
||||
date: 2022/8/3
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
* export thread information.
|
||||
*/
|
||||
void BBOX_ListThread(struct BBOX_ListParams* pstArgs)
|
||||
{
|
||||
pid_t ppid = 0;
|
||||
|
|
@ -597,18 +545,12 @@ errout:
|
|||
}
|
||||
|
||||
/*
|
||||
function name: BBOX_GetClonePidResult
|
||||
description: The function get the status of child process at first, then according to it assign pstArgs's
|
||||
member variables iError and iResult appropriate values.
|
||||
arguments: The first argument is a integer named iClonePid, it represents the pid of child process.
|
||||
The second argument is a structure pointer named pstArgs, its type is struct BBOX_ListParams*,
|
||||
what matters is its member variable callback function pointer and thread infomation.
|
||||
The third argument is a integer indicating error code.
|
||||
return value: An integer, if function work normally, the value is RET_OK, else is RET_ERR.
|
||||
note: none
|
||||
date: 2022/8/3
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
* get return value of child process
|
||||
* in : iClonePid - PID of child process
|
||||
* pstArgs - parameter
|
||||
* iCloneErrno - err code
|
||||
* return 0 if success else failed.
|
||||
*/
|
||||
s32 BBOX_GetClonePidResult(pid_t iClonePid, struct BBOX_ListParams* pstArgs, s32 iCloneErrno)
|
||||
{
|
||||
s32 iStatus = 0;
|
||||
|
|
|
|||
|
|
@ -57,22 +57,6 @@ BlacklistItem g_blacklist_items[] = {
|
|||
{DATA_WRITER_QUEUE, "DATA_WRITER_QUEUE", false}
|
||||
};
|
||||
|
||||
/*
|
||||
function name: coredump_handler
|
||||
description: When a program is abnormal, but the exception appears in the core of process and wasn't caught,
|
||||
The function will generate a file to store the information about memory of process, status of register
|
||||
and running stack.
|
||||
arguments: The first argument is an integer indicating signal code that usually used in program of processing
|
||||
signal as variable.
|
||||
The second argument is a structure pointer of type siginfo_t*, the memory that this pointer
|
||||
directs stores comprehensive information about signal, for example, which process sends
|
||||
and which user sends.
|
||||
The third argument is a pointer of type void*, other kinds of pointers can directly used here.
|
||||
return value: void
|
||||
note: none
|
||||
date: 2022/8/4
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
static void coredump_handler(int sig, siginfo_t *si, void *uc)
|
||||
{
|
||||
static volatile int64 first_tid = INVALID_TID;
|
||||
|
|
@ -100,19 +84,8 @@ static void coredump_handler(int sig, siginfo_t *si, void *uc)
|
|||
}
|
||||
|
||||
/*
|
||||
function name: bbox_handler
|
||||
description: Handle signal conditions for bbox.
|
||||
arguments: The first argument is an integer indicating signal code that usually used in program of processing
|
||||
signal as variable.
|
||||
The second argument is a structure pointer of type siginfo_t*, the memory that this pointer
|
||||
directs stores comprehensive information about signal, for example, which process sends
|
||||
and which user sends.
|
||||
The third argument is a pointer of type void*, other kinds of pointers can directly used here.
|
||||
return value: void
|
||||
note: none
|
||||
date: 2022/8/4
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
* bbox_handler - handle signal conditions for bbox
|
||||
*/
|
||||
static void bbox_handler(int sig, siginfo_t *si, void *uc)
|
||||
{
|
||||
static volatile int64 first_tid = INVALID_TID;
|
||||
|
|
@ -152,16 +125,8 @@ static void bbox_handler(int sig, siginfo_t *si, void *uc)
|
|||
}
|
||||
|
||||
/*
|
||||
function name: get_bbox_coredump_pattern_path
|
||||
description: Get the core dump file's path from the file "/proc/sys/kernel/core_pattern".
|
||||
arguments: The first argument is a pointer to string, we use it to store core dump file's path acquired
|
||||
from the file "/proc/sys/kernel/core_pattern", the next argument is the number of characters
|
||||
reading from the file "/proc/sys/kernel/core_pattern", all len-1 characters or less if appear '\n'.
|
||||
return value: void
|
||||
note: none
|
||||
date: 2022/8/4
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
* get_bbox_coredump_pattern_path - get the core dump path from the file "/proc/sys/kernel/core_pattern"
|
||||
*/
|
||||
static void get_bbox_coredump_pattern_path(char* path, Size len)
|
||||
{
|
||||
FILE* fp = NULL;
|
||||
|
|
@ -191,17 +156,7 @@ static void get_bbox_coredump_pattern_path(char* path, Size len)
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
function name: build_bbox_corepath
|
||||
description: Get the core dump file's path.
|
||||
arguments: The first argument is a pointer to string, we use it to store core dump file's path,
|
||||
the next argument is the size of the path's name, the last argument is a pointer
|
||||
to string that indicates maybe store a path to configure the core dump file.
|
||||
return value: void
|
||||
note: none
|
||||
date: 2022/8/4
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
/* compute directory into which bbox dump core files are saved. */
|
||||
static void build_bbox_corepath(char *bbox_core_path, Size path_size, char *config_path)
|
||||
{
|
||||
struct stat stat_buf;
|
||||
|
|
@ -277,15 +232,6 @@ void assign_bbox_corepath(const char* newval, void* extra)
|
|||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
function name: show_bbox_dump_path
|
||||
description: Get the dump file's path.
|
||||
arguments: void
|
||||
return value: A pointer of type const char*, directing the path to dump or NULL.
|
||||
note: none
|
||||
date: 2022/8/4
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
const char* show_bbox_dump_path(void)
|
||||
{
|
||||
const char* path = g_bbox_dump_path;
|
||||
|
|
@ -293,15 +239,6 @@ const char* show_bbox_dump_path(void)
|
|||
return (path != NULL) ? path : "";
|
||||
}
|
||||
|
||||
/*
|
||||
function name: split_string_into_blacklist
|
||||
description: Get all strings been divided into character ',' in source string.
|
||||
arguments: A pointer of type const char*, directing the source string.
|
||||
return value: A pointer of type static List*.
|
||||
note: none
|
||||
date: 2022/8/4
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
static List* split_string_into_blacklist(const char* source)
|
||||
{
|
||||
List *result = NIL;
|
||||
|
|
@ -327,6 +264,7 @@ static List* split_string_into_blacklist(const char* source)
|
|||
return result;
|
||||
}
|
||||
|
||||
|
||||
bool check_bbox_blacklist(char** newval, void** extra, GucSource source)
|
||||
{
|
||||
if (t_thrd.proc_cxt.MyProcPid != PostmasterPid)
|
||||
|
|
@ -464,15 +402,10 @@ void bbox_blacklist_remove(BlacklistIndex item, void* addr)
|
|||
}
|
||||
|
||||
/*
|
||||
function name: CheckFilenameValid
|
||||
description: Check if the filename is in line with norms, or if dangerous characters appear
|
||||
the filename is invalid.
|
||||
arguments: A pointer to string indicating filename.
|
||||
return value: An integer, if function works normally, the value is RET_OK, else it's RET_ERR.
|
||||
note: none
|
||||
date: 2022/8/4
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
* @Description: check the value from environment variablethe to prevent command injection.
|
||||
* @in input_env_value : the input value need be checked.
|
||||
*
|
||||
*/
|
||||
int CheckFilenameValid(const char* inputEnvValue)
|
||||
{
|
||||
const int maxLen = 1024;
|
||||
|
|
|
|||
|
|
@ -45,15 +45,6 @@
|
|||
|
||||
static bool CommCheckFilterMatch(const char *filter, int len, const char *ip, int port);
|
||||
|
||||
/*
|
||||
function name: SetCPUAffinity
|
||||
description: The function set the affinity of CPU or CPUs destined by argument cpu_id.
|
||||
arguments: An integer representing the id of one CPU or more.
|
||||
return value: void
|
||||
note: none
|
||||
date: 2022/8/5
|
||||
contact: 18720816902
|
||||
*/
|
||||
void SetCPUAffinity(int cpu_id)
|
||||
{
|
||||
cpu_set_t mask;
|
||||
|
|
@ -279,15 +270,6 @@ IPAddrType CommLibNetGetIPType(unsigned int ip)
|
|||
#define CMD_STR_MAX 512
|
||||
#define CMD_OUTPUT_BUFFER_SIZE 1024
|
||||
|
||||
/*
|
||||
function name: CommCheckLtranProcess
|
||||
description: The function check if the process currently working has loaded transactions.
|
||||
arguments: void
|
||||
return value: 0 or 1, if 1, then at least one loaded transcation exists, if 0, no one.
|
||||
note: none
|
||||
date: 2022/8/5
|
||||
contact: 18720816902
|
||||
*/
|
||||
int CommCheckLtranProcess()
|
||||
{
|
||||
AutoContextSwitch commContext(g_instance.comm_cxt.comm_global_mem_cxt);
|
||||
|
|
@ -405,21 +387,6 @@ static T GetCommProxySubParameter(const char* str_attr, const char* key)
|
|||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
function name: ParseCommProxyNumaBind
|
||||
description: Get the ids of CPU to bind process with specific CPU.
|
||||
arguments: The first argument is a pointer of type const char* to a string that indicating
|
||||
the id of CPUs below NUMA, not necessarily all CPUs.
|
||||
The second argument is an integer telling us we will get CPUs' id from which position
|
||||
of array str_attr.
|
||||
The third argument tells us the number of NUMA system framework.
|
||||
The fourth argument is a pointer to an integer array used to store CPUs' id gotten
|
||||
from string str_attr, we can use these ids to bind specific CPU.
|
||||
return value: void
|
||||
note: none
|
||||
date: 2022/8/5
|
||||
contact: 18720816902
|
||||
*/
|
||||
static void ParseCommProxyNumaBind(
|
||||
const char* str_attr, const int pos, const int numa_num, int* numa_bind)
|
||||
{
|
||||
|
|
@ -520,22 +487,6 @@ bool ParseCommProxyAttr(CommProxyConfig* config)
|
|||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
function name: CommCheckFilterMatch
|
||||
description: This function compare the ip and port allowed with ip and port gotten from
|
||||
Filter, if they are correspondingly same, it will return true value.
|
||||
arguments: The first argument is a pointer of type const char* to a string that indicating
|
||||
the id and port of the request been sent to Filter, the id and port have been
|
||||
separated by character ':'.
|
||||
The second argument is an integer telling us we the length of the string first
|
||||
argument directs.
|
||||
The third argument tells us the ip allowed.
|
||||
The fourth argument tells us the port allowed.
|
||||
return value: static bool
|
||||
note: none
|
||||
date: 2022/8/4
|
||||
contact: 18720816902
|
||||
*/
|
||||
static bool CommCheckFilterMatch(const char *filter, int len, const char *ip, int port)
|
||||
{
|
||||
char *str_ip = NULL;
|
||||
|
|
|
|||
|
|
@ -175,24 +175,6 @@ void UpdateTxRxStats(int msg_level)
|
|||
last_rx_nbytes = current_rx_nbytes;
|
||||
}
|
||||
|
||||
/*
|
||||
function name: parse_monitor_sock_queue
|
||||
description: Compare the string recv_buffer with "sockqueue fd:fd", the "fd"
|
||||
after character ':' is an integer indicating file descriptor. If recv_buffer
|
||||
accords with the format, the function will takes next action to see if
|
||||
fd is 0, which represents stdin, so the function ends with returned value 0.
|
||||
If fd isn't 0, compare the third argument type with ParseMonitorTypeSet,
|
||||
if equal, then get a structure variable including socket descriptor
|
||||
destined by the fd gotten from the first argument, if it's NULL, we can
|
||||
write "fd:[%d], type:[normal fd], no sock queue" into send_buffer.
|
||||
arguments: The first argument is a pointer to a string indicating request infomation.
|
||||
The second argument is a pointer to a string to store sent infomation.
|
||||
The third argument tells the kind of socket request.
|
||||
return value: 0 or 1.
|
||||
note: none
|
||||
date: 2022/8/5
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
int parse_monitor_sock_queue(char* recv_buffer, char* send_buffer, ParseMonitorType type)
|
||||
{
|
||||
int length;
|
||||
|
|
@ -223,25 +205,6 @@ int parse_monitor_sock_queue(char* recv_buffer, char* send_buffer, ParseMonitorT
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
function name: parse_monitor_fd
|
||||
description: Compare the string recv_buffer with "query fd:fd", the "fd"
|
||||
after character ':' is an integer indicating file descriptor. If recv_buffer
|
||||
accords with the format, the function will takes next action to see if
|
||||
fd is 0, which represents stdin, so the function ends with returned value 0.
|
||||
If fd isn't 0, compare the third argument type with ParseMonitorTypeSet,
|
||||
if equal, then get a structure variable including socket descriptor
|
||||
destined by the fd gotten from the first argument, if it's NULL, we can
|
||||
write "fd:[%d], type:[normal fd]"(%d--fd) into send_buffer, else write
|
||||
"fd:[%d], type:[%d]"(%d--fd,%d--sock_desc->m_fd_type).
|
||||
arguments: The first argument is a pointer to a string indicating request infomation.
|
||||
The second argument is a pointer to a string to store sent infomation.
|
||||
The third argument tells the kind of socket request.
|
||||
return value: 0 or 1.
|
||||
note: none
|
||||
date: 2022/8/5
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
int parse_monitor_fd(char* recv_buffer, char* send_buffer, ParseMonitorType type)
|
||||
{
|
||||
int length;
|
||||
|
|
|
|||
|
|
@ -53,24 +53,6 @@ static void comm_wait_broadcast_end(SocketRequest** req_arr, int num);
|
|||
* export function definition
|
||||
************************************************************************************
|
||||
*/
|
||||
|
||||
/*
|
||||
function name: comm_proxy_socket
|
||||
description: This function creates a socket file descriptor whose protocol family is
|
||||
domain, protocol type is type, and protocol number is protocol. If the
|
||||
function call is successful, it will return a file descriptor that identifies
|
||||
the socket. If it fails, it will return - 1.
|
||||
arguments: The first argument specifies the protocol family, it's used as domain to
|
||||
set up network communication.
|
||||
The second argument is used to set the type of socket communication.
|
||||
The third argument is used to specify a specific type of a protocol, which
|
||||
is a type in the second argument types' type.
|
||||
return value: If the function call is successful, it will return a file descriptor that
|
||||
identifies the socket. If it fails, it will return - 1.
|
||||
note: none
|
||||
date: 2022/8/8
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
int comm_proxy_socket(int domain, int type, int protocol)
|
||||
{
|
||||
SocketRequest req;
|
||||
|
|
@ -172,16 +154,6 @@ ssize_t comm_proxy_addr_recv(int sockfd, void *buf, size_t len, int flags)
|
|||
return comm_proxy_recv(sockfd, buf, len, flags);
|
||||
}
|
||||
|
||||
/*
|
||||
function name: comm_proxy_close
|
||||
description: The function is used to release the resources allocated
|
||||
to the socket by the system.
|
||||
arguments: The argument is the socket file descriptor to be closed.
|
||||
return value: If the call is successful, return 0; otherwise, return - 1 and set errno.
|
||||
note: none
|
||||
date: 2022/8/8
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
int comm_proxy_close(int fd)
|
||||
{
|
||||
SocketRequest req;
|
||||
|
|
@ -233,18 +205,6 @@ int comm_proxy_close(int fd)
|
|||
return result.s_ret;
|
||||
}
|
||||
|
||||
/*
|
||||
function name: comm_proxy_shutdown
|
||||
description: The function is used to release the resources allocated
|
||||
to the socket by the system.
|
||||
arguments: The first argument is a descriptor used to identify a socket.
|
||||
The second argument is used to describe which operations
|
||||
are prohibited, which determines the behavior of the function.
|
||||
return value: If the call is successful, return 0; otherwise, return - 1 and set errno.
|
||||
note: none
|
||||
date: 2022/8/8
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
int comm_proxy_shutdown(int fd, int how)
|
||||
{
|
||||
SocketRequest req;
|
||||
|
|
@ -299,21 +259,6 @@ int comm_proxy_shutdown(int fd, int how)
|
|||
return result.s_ret;
|
||||
}
|
||||
|
||||
/*
|
||||
function name: comm_proxy_accept
|
||||
description: This function extracts the first connection from the waiting connection queue of S, creates
|
||||
a new socket interface similar to s and returns a handle.
|
||||
arguments: The first argument is a socket descriptor, which listens for connection after comm_proxy_listen().
|
||||
The second argument is a optional pointer pointing to a buffer where the address of the
|
||||
connection entity known to the communication layer is received. The actual format of the
|
||||
addr argument is determined by the address family generated when the socket is created.
|
||||
The third argument is a optional pointer, used together with addr, pointing to the integer
|
||||
number with the length of addr address.
|
||||
return value: The return value is a new socket descriptor, which represents a new connection with the client.
|
||||
note: none
|
||||
date: 2022/8/8
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
int comm_proxy_accept(int sockfd, struct sockaddr* addr, socklen_t* addrlen)
|
||||
{
|
||||
SocketRequest req;
|
||||
|
|
@ -398,17 +343,6 @@ int comm_proxy_accept4(int sockfd, struct sockaddr* addr, socklen_t* addrlen, in
|
|||
return comm_proxy_accept(sockfd, addr, addrlen);
|
||||
}
|
||||
|
||||
/*
|
||||
function name: comm_proxy_connect
|
||||
description: This function is used to establish a connection with a specified socket.
|
||||
arguments: The first argument is used to identify an unconnected socket.
|
||||
The second argument is a pointer to the sockaddr structure to socket will be connected.
|
||||
The third argument is byte length of sockaddr structure.
|
||||
return value: The return value is 0 if succeed, - 1 is returned for failure and error reason is stored in errno.
|
||||
note: none
|
||||
date: 2022/8/8
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
int comm_proxy_connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
|
||||
{
|
||||
SocketRequest req;
|
||||
|
|
@ -460,17 +394,6 @@ int comm_proxy_connect(int sockfd, const struct sockaddr *addr, socklen_t addrle
|
|||
return result.s_ret;
|
||||
}
|
||||
|
||||
/*
|
||||
function name: comm_proxy_bind
|
||||
description: This function binds a local address with a set of interfaces.
|
||||
arguments: The first argument indicates the socket descriptor that has been established.
|
||||
The second argument is a pointer to the sockaddr structure to socket.
|
||||
The third argument is byte length of sockaddr structure.
|
||||
return value: The return value is 0 if succeed, - 1 is returned for failure and error reason is stored in errno.
|
||||
note: none
|
||||
date: 2022/8/8
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
int comm_proxy_bind(int sockfd, const struct sockaddr* ServerAddr, socklen_t addrlen)
|
||||
{
|
||||
SocketRequest req;
|
||||
|
|
@ -498,16 +421,6 @@ int comm_proxy_bind(int sockfd, const struct sockaddr* ServerAddr, socklen_t add
|
|||
return result.s_ret;
|
||||
}
|
||||
|
||||
/*
|
||||
function name: comm_proxy_listen
|
||||
description: This function creates a socket interface and listens for the requested connection.
|
||||
arguments: The first argument is a descriptor used to identify a bundled but unconnected socket.
|
||||
The second argument indicates the maximum length of waiting for connection queue
|
||||
return value: The return value is 0 if succeed, - 1 is returned for failure and error reason is stored in errno.
|
||||
note: none
|
||||
date: 2022/8/8
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
int comm_proxy_listen(int sockfd, int backlog)
|
||||
{
|
||||
SocketRequest req;
|
||||
|
|
@ -534,19 +447,6 @@ int comm_proxy_listen(int sockfd, int backlog)
|
|||
return result.s_ret;
|
||||
}
|
||||
|
||||
/*
|
||||
function name: comm_proxy_setsockopt
|
||||
description: The function is used to set option values for sockets of any type and any state.
|
||||
arguments: The first argument is a descriptor that identifies a socket interface.
|
||||
The second argument indicates the level defined by the option.
|
||||
The third argument specifies the option to be set.
|
||||
The fourth argument is a pointer to the buffer where the new value of the option to be set is stored.
|
||||
The fifth argument indicates optval buffer length.
|
||||
return value: The return value is 0 if succeed, - 1 is returned for failure and error reason is stored in errno.
|
||||
note: none
|
||||
date: 2022/8/8
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
int comm_proxy_setsockopt(int sockfd, int level, int optname, const void* optval, socklen_t optlen)
|
||||
{
|
||||
SocketRequest req;
|
||||
|
|
@ -576,19 +476,6 @@ int comm_proxy_setsockopt(int sockfd, int level, int optname, const void* optval
|
|||
return result.s_ret;
|
||||
}
|
||||
|
||||
/*
|
||||
function name: comm_proxy_getsockopt
|
||||
description: The function is used to obtain the current value of the option of any type and any state socket, and store the result in optval.
|
||||
arguments: The first argument is a descriptor that identifies a socket interface.
|
||||
The second argument indicates the level defined by the option.
|
||||
The third argument specifies the socket options to be obtained.
|
||||
The fourth argument is a pointer to the buffer where the obtained option value is stored.
|
||||
The fifth argument is a pointer to the length value of optval buffer.
|
||||
return value: The return value is 0 if succeed, - 1 is returned for failure and error reason is stored in errno.
|
||||
note: none
|
||||
date: 2022/8/8
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
int comm_proxy_getsockopt(int sockfd, int level, int optname, void* optval, socklen_t* optlen)
|
||||
{
|
||||
SocketRequest req;
|
||||
|
|
@ -617,18 +504,6 @@ int comm_proxy_getsockopt(int sockfd, int level, int optname, void* optval, sock
|
|||
return result.s_ret;
|
||||
}
|
||||
|
||||
/*
|
||||
function name: comm_proxy_getsockname
|
||||
description: The function is used to get the name of a socket. It is used for a bundled or
|
||||
connected socket, and the local address will be returned.
|
||||
arguments: The first argument is a descriptor that identifies a socket interface.
|
||||
The second argument indicates the address of the receiving socket.
|
||||
The third argument specifies the length of the name buffer.
|
||||
return value: The return value is 0 if succeed, - 1 is returned for failure and error reason is stored in errno.
|
||||
note: none
|
||||
date: 2022/8/8
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
int comm_proxy_getsockname(int sockfd, struct sockaddr* addr, socklen_t* addrlen)
|
||||
{
|
||||
SocketRequest req;
|
||||
|
|
@ -655,17 +530,6 @@ int comm_proxy_getsockname(int sockfd, struct sockaddr* addr, socklen_t* addrlen
|
|||
return result.s_ret;
|
||||
}
|
||||
|
||||
/*
|
||||
function name: comm_proxy_getpeername
|
||||
description: The function is used to obtain the foreign protocol address associated with a socket.
|
||||
arguments: The first argument is a descriptor that identifies a socket interface.
|
||||
The second argument indicates the name structure of the receiver address.
|
||||
The third argument specifies the length of the name structure.
|
||||
return value: The return value is 0 if succeed, - 1 is returned for failure and error reason is stored in errno.
|
||||
note: none
|
||||
date: 2022/8/8
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
int comm_proxy_getpeername(int sockfd, struct sockaddr* addr, socklen_t* addrlen)
|
||||
{
|
||||
SocketRequest req;
|
||||
|
|
@ -692,19 +556,6 @@ int comm_proxy_getpeername(int sockfd, struct sockaddr* addr, socklen_t* addrlen
|
|||
return result.s_ret;
|
||||
}
|
||||
|
||||
/*
|
||||
function name: comm_proxy_fcntl
|
||||
description: The function can change the nature of the opened file, it provides control over descriptors.
|
||||
The argument sockfd is a descriptor operated by the argument cmd. For the value of cmd,
|
||||
fcntl can accept the third argument arg, which is a variable argument.
|
||||
arguments: The first argument is a descriptor that identifies a socket interface.
|
||||
The second argument represents the instruction to be operated.
|
||||
The third argument is a variable argument
|
||||
return value: The return value is 0 if succeed, - 1 is returned for failure and error reason is stored in errno.
|
||||
note: none
|
||||
date: 2022/8/8
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
int comm_proxy_fcntl(int sockfd, int cmd, ...)
|
||||
{
|
||||
SocketRequest req;
|
||||
|
|
@ -771,17 +622,6 @@ int comm_proxy_fcntl(int sockfd, int cmd, ...)
|
|||
return result.s_ret;
|
||||
}
|
||||
|
||||
/*
|
||||
function name: comm_proxy_poll
|
||||
description: The function is used to hang the current file pointer to the waiting queue.
|
||||
arguments: The first argument is an array of struct pollfd structure type, used to store the socket descriptor whose state needs to be detected.
|
||||
The second argument is used to mark the total number of structural elements in the array fdarray;
|
||||
The third argument is the blocking time of the comm_proxy_poll function call.
|
||||
return value: The return value is 0 if succeed, - 1 is returned for failure and error reason is stored in errno.
|
||||
note: none
|
||||
date: 2022/8/8
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
int comm_proxy_poll(struct pollfd* fdarray, unsigned long nfds, int timeout)
|
||||
{
|
||||
CommWaitPollParam param;
|
||||
|
|
@ -818,15 +658,6 @@ int comm_proxy_poll(struct pollfd* fdarray, unsigned long nfds, int timeout)
|
|||
return param.s_ret;
|
||||
}
|
||||
|
||||
/*
|
||||
function name: comm_proxy_epoll_create
|
||||
description: The function is used to create a handle to epoll.
|
||||
arguments: The only argument size is used to tell the kernel how many listeners there are.
|
||||
return value: Returns a file descriptor that points to the newly created epoll instance
|
||||
note: none
|
||||
date: 2022/8/8
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
int comm_proxy_epoll_create(int size)
|
||||
{
|
||||
/*
|
||||
|
|
@ -856,21 +687,6 @@ int comm_proxy_epoll_create1(int flag)
|
|||
return comm_proxy_epoll_create(1);
|
||||
}
|
||||
|
||||
/*
|
||||
function name: comm_proxy_epoll_ctl
|
||||
description: This system call performs control operations on the epoll instance referenced
|
||||
by the file descriptor epfd. It requires the operation op to execute the target
|
||||
file descriptor fd. It's used as epoll's event registration function, it adds,
|
||||
modifies, or deletes events of interest to the epoll object.
|
||||
arguments: The first argument is a specific file descriptor for epoll generated by epoll_ create.
|
||||
The second argument indicates the actions to be taken, such as registering events.
|
||||
The third argument is associated file descriptor.
|
||||
The fourth argument is a pointer of type struct epoll_event, used to tell the kernel what events and actions to listen for.
|
||||
return value: The return value is 0 if succeed, - 1 is returned for failure and error reason is stored in errno.
|
||||
note: none
|
||||
date: 2022/8/8
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
int comm_proxy_epoll_ctl(int epfd, int op, int fd, struct epoll_event* event)
|
||||
{
|
||||
SocketRequest req;
|
||||
|
|
@ -1110,23 +926,6 @@ int comm_proxy_epoll_ctl(int epfd, int op, int fd, struct epoll_event* event)
|
|||
return result.s_ret;
|
||||
}
|
||||
|
||||
/*
|
||||
function name: comm_proxy_epoll_wait
|
||||
description: Wait for IO events on the specified epoll file descriptor.
|
||||
arguments: The first argument is a specific file descriptor for epoll generated by epoll_ create.
|
||||
The second argument is a pointer to type epoll_ event structure, but it is now used
|
||||
as a container to get the collection of events from the kernel.
|
||||
The third argument is used to tell how large the container is (number of event
|
||||
array members), that is, the number of events that can be processed each time.
|
||||
The fourth argument is the timeout value for waiting for IO events.
|
||||
return value: When successful, comm_proxy_epoll_wait() returns the number of file descriptors
|
||||
ready for the requested IO. Returns zero if no file descriptor is ready within the
|
||||
requested timeout milliseconds. When an error occurs, comm_proxy_epoll_wait()
|
||||
returns - 1 and sets errno correctly.
|
||||
note: none
|
||||
date: 2022/8/8
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
int comm_proxy_epoll_wait(int epfd, struct epoll_event* events, int maxevents, int timeout)
|
||||
{
|
||||
CommWaitEpollWaitParam param;
|
||||
|
|
|
|||
|
|
@ -81,27 +81,6 @@ void mc_tcp_set_keepalive(int fd)
|
|||
mc_tcp_setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, (char*)&count, sizeof(count));
|
||||
}
|
||||
|
||||
/*
|
||||
function name: mc_tcp_get_peer_name
|
||||
description: This function is used to obtain the host IP and port number of the host bound to the specific socket.
|
||||
arguments: The first argument is a descriptor to a specified socket.
|
||||
The second argument is used to store the host IP address bound to the socket determined by the first parameter, in dotted decimal.
|
||||
The third parameter is used to store the port number bound to a specific socket, in the order of host bytes.
|
||||
return value: Return 0 if the function runs successfully.
|
||||
When the call to the getpeername() function fails:
|
||||
1、Return EBADF if the socket argument is not a valid file descriptor.
|
||||
2、Return EINVAL if the socket has been shut down.
|
||||
3、Return ENOTCONN if the socket is not connected or otherwise has not had the peer pre-specified.
|
||||
4、Return ENOTSOCK if the socket argument does not refer to a socket.
|
||||
5、Return EOPNOTSUPP if the operation is not supported for the socket protocol.
|
||||
6、Return ENOBUFS if insufficient resources were available in the system to complete the call.
|
||||
Return -2 when the host IP address belongs to IPv4 type, it fails to convert it to dotted decimal.
|
||||
Return -3 when the host IP address belongs to IPv6 type, it fails to convert it to dotted decimal.
|
||||
Return -4 when the error type is not any of the above.
|
||||
note: Allocate a certain amount of memory space for the host and port pointers respectively in advance.
|
||||
date: 2022/8/9
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
int mc_tcp_get_peer_name(int fd, char* host, int* port)
|
||||
{
|
||||
struct sockaddr peeraddr = {0};
|
||||
|
|
@ -142,17 +121,6 @@ int mc_tcp_set_cloexec(int fd)
|
|||
return set_socketopt(fd, 1, FD_CLOEXEC);
|
||||
}
|
||||
|
||||
/*
|
||||
function name: mc_tcp_accept
|
||||
description: This function will block the process by default until a client connection is established and returns a new available socket.
|
||||
arguments: The first argument is a socket descriptor to a specific socket.
|
||||
The second argument is a result parameter, which is used to accept a return value that specifies the address of the client.
|
||||
The third argument is also a result argument, which is used to accept the size of the sockaddr structure. It indicates the number of bytes occupied by the sockaddr structure.
|
||||
return value: Return a value less than 0 if an error occurred when call the function accept4(), else return the new fd of socket.
|
||||
note: none
|
||||
date: 2022/8/9
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
int mc_tcp_accept(int fd, struct sockaddr* sa, socklen_t* salenptr)
|
||||
{
|
||||
int new_fd;
|
||||
|
|
@ -179,17 +147,6 @@ again:
|
|||
return (new_fd);
|
||||
}
|
||||
|
||||
/*
|
||||
function name: mc_tcp_bind
|
||||
description: This function binds the specified socket to a specific IP address and port.
|
||||
arguments: The first argument indicates the socket descriptor that has been established.
|
||||
The second argument is a pointer to the sockaddr structure to socket.
|
||||
The third argument is byte length of sockaddr structure.
|
||||
return value: Return errno, the return value is 0 if succeed, else one of other error types is returned for failure.
|
||||
note: none
|
||||
date: 2022/8/9
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
int mc_tcp_bind(int fd, const struct sockaddr* sa, socklen_t salen)
|
||||
{
|
||||
int error = -1;
|
||||
|
|
@ -234,20 +191,6 @@ static void mc_tcp_do_listen(int fd, int backlog)
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
function name: mc_tcp_read_block
|
||||
description: This function receives data from the other end of TCP in a blocking manner, the receiving
|
||||
process will not end until the data of size byte length is successfully received or a real error occurs in the receiving process
|
||||
arguments: The first argument indicates the specific socket that has been established.
|
||||
The second argument is a pointer to memory area, we use it to store received data.
|
||||
The third argument is byte length of the memory area pointed to by the data pointer.
|
||||
The fourth argument specifies additional operations in addition to the read operation.
|
||||
return value: If there is no error, it returns the byte length of the successfully read data. If an error
|
||||
occurs, return - 1.
|
||||
note: When the data is read successfully, the byte length of the data is greater than 0.
|
||||
date: 2022/8/10
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
int mc_tcp_read_block(int fd, void* data, int size, int flags)
|
||||
{
|
||||
#ifdef LIBCOMM_FAULT_INJECTION_ENABLE
|
||||
|
|
@ -318,20 +261,6 @@ int mc_tcp_read_block(int fd, void* data, int size, int flags)
|
|||
return (size_t)nbytes;
|
||||
}
|
||||
|
||||
/*
|
||||
function name: mc_tcp_read_nonblock
|
||||
description: This function receives data from the other end of TCP in a non blocking manner,
|
||||
the data receiving process is only performed once.
|
||||
arguments: The first argument indicates the specific socket that has been established.
|
||||
The second argument is a pointer to memory area, we use it to store received data.
|
||||
The third argument is byte length of the memory area pointed to by the data pointer.
|
||||
The fourth argument specifies additional operations in addition to the read operation.
|
||||
return value: If the error type is one of the errors represented by EAGAIN, EWOULDBLOCK and EINTR, it returns 0;
|
||||
other error types return - 1; if there is no error, it returns the byte length of the successfully read data.
|
||||
note: When the data is read successfully, the byte length of the data is greater than 0.
|
||||
date: 2022/8/10
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
int mc_tcp_read_nonblock(int fd, void* data, int size, int flags)
|
||||
{
|
||||
#ifdef LIBCOMM_FAULT_INJECTION_ENABLE
|
||||
|
|
@ -377,17 +306,6 @@ int mc_tcp_read_nonblock(int fd, void* data, int size, int flags)
|
|||
return (size_t)nbytes;
|
||||
}
|
||||
|
||||
/*
|
||||
function name: mc_tcp_check_socket
|
||||
description: This function binds the specified socket to a specific IP address and port.
|
||||
arguments: The only argument indicates the specific socket that has been established.
|
||||
return value: Return -1 if when the recv function wait for the protocol to receive data,
|
||||
the other end of TCP closes the connection or a real error occurred while
|
||||
reading data. In other cases, 0 is returned.
|
||||
note: none
|
||||
date: 2022/8/10
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
int mc_tcp_check_socket(int sock)
|
||||
{
|
||||
char temp_buf[IOV_DATA_SIZE] = {0};
|
||||
|
|
@ -450,19 +368,6 @@ int mc_tcp_check_socket(int sock)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
function name: mc_tcp_write_block
|
||||
description: This function writes data to the specified socket in blocking mode, the sending process
|
||||
will not end until all the data are successfully sent or a real error occurs during the sending process
|
||||
arguments: The first argument indicates the specific socket that has been established.
|
||||
The second argument is a pointer to memory area, we use it to store data to be sent.
|
||||
The third argument is byte length of data to be sent.
|
||||
return value: If there is no error, it returns the byte length of the successfully sent data. If an error
|
||||
occurs, return - 1.
|
||||
note: none
|
||||
date: 2022/8/10
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
int mc_tcp_write_block(int fd, const void* data, int size)
|
||||
{
|
||||
#ifdef LIBCOMM_FAULT_INJECTION_ENABLE
|
||||
|
|
@ -521,21 +426,6 @@ int mc_tcp_write_block(int fd, const void* data, int size)
|
|||
return (size_t)nSend;
|
||||
}
|
||||
|
||||
/*
|
||||
function name: mc_tcp_write_noblock
|
||||
description: This function writes data to the specified socket in non blocking mode,
|
||||
the data transmission process is only performed once.
|
||||
arguments: The first argument indicates the specific socket that has been established.
|
||||
The second argument is a pointer to memory area, we use it to store data to be sent.
|
||||
The third argument is byte length of data to be sent.
|
||||
return value: If the sending fails but the failure reason is one of the error types represented by EAGAIN、
|
||||
EWOULDBLOCK、EINTR 和ENOBUFS, then 0 is returned; if the error type is other, then - 1
|
||||
is returned; If the transmission is successful, the byte length of the successfully transmitted
|
||||
data is returned
|
||||
note: none
|
||||
date: 2022/8/10
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
int mc_tcp_write_noblock(int fd, const void* data, int size)
|
||||
{
|
||||
#ifdef LIBCOMM_FAULT_INJECTION_ENABLE
|
||||
|
|
@ -629,17 +519,6 @@ int mc_tcp_addr_init(const char* host, int port, struct sockaddr_storage* ss, in
|
|||
return (error == 1) ? 0 : error;
|
||||
}
|
||||
|
||||
/*
|
||||
function name: mc_tcp_connect_nonblock
|
||||
description: This function is used to create a socket and establish a connection with the port of the specified host
|
||||
in non blocking mode.
|
||||
arguments: The first parameter specifies a specific host, and the second parameter specifies a specific port of the host.
|
||||
return value: If the connection is successfully established, the file descriptor of the socket connected to the port of the
|
||||
specified host is returned; otherwise, - 1 is returned.
|
||||
note: none
|
||||
date: 2022/8/10
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
int mc_tcp_connect_nonblock(const char* host, int port)
|
||||
{
|
||||
int sockfd, n;
|
||||
|
|
@ -687,18 +566,6 @@ int mc_tcp_connect_nonblock(const char* host, int port)
|
|||
return sockfd;
|
||||
}
|
||||
|
||||
/*
|
||||
function name: mc_tcp_connect
|
||||
description: This function first obtains the ports of other hosts with the same domain name stored through
|
||||
the ports of specific hosts, and creates a socket to establish a connection with an appropriate
|
||||
one of these ports.
|
||||
arguments: The first parameter specifies a specific host, and the second parameter specifies a specific port of the host.
|
||||
return value: The key is to successfully establish a connection with a port in the linked list. If the connection is successful, the
|
||||
socket file descriptor connected to it will be returned. Otherwise, it will return - 1.
|
||||
note: We finally get the infomation of the ports of other hosts through a linked list.
|
||||
date: 2022/8/10
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
int mc_tcp_connect(const char* host, int port)
|
||||
{
|
||||
#ifdef LIBCOMM_FAULT_INJECTION_ENABLE
|
||||
|
|
@ -789,18 +656,6 @@ retry:
|
|||
return (sockfd);
|
||||
}
|
||||
|
||||
/*
|
||||
function name: mc_tcp_listen
|
||||
description: This function first obtains the ports of other hosts with the same domain name stored through
|
||||
the ports of specific hosts, and creates a socket to bind with an appropriate one of these ports.
|
||||
arguments: The first parameter specifies a specific host, and the second parameter specifies a specific port of the host.
|
||||
The third is used to store size of protocol address.
|
||||
return value: The key lies in the successful binding with a port in the linked list. If the binding is successful, the socket file
|
||||
descriptor connected to it will be returned. Otherwise, it will return - 1.
|
||||
note: We finally get the infomation of the ports of other hosts through a linked list.
|
||||
date: 2022/8/10
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
int mc_tcp_listen(const char* host, int port, socklen_t* addrlenp)
|
||||
{
|
||||
#ifdef LIBCOMM_FAULT_INJECTION_ENABLE
|
||||
|
|
|
|||
|
|
@ -232,21 +232,6 @@ static int gs_tcp_write_noblock(int node_idx, int sock, const char* msg, int msg
|
|||
|
||||
return send_bytes;
|
||||
}
|
||||
|
||||
/*
|
||||
function name: libcomm_tcp_send
|
||||
description: This function is used to send the message including message head and message body, to
|
||||
a specific socket.
|
||||
arguments: send_ info is a pointer of LibcommRecvInfo* type, pointing to the memory storing the data
|
||||
waiting to be sent.
|
||||
return value: Data will be sent twice in total. Before sending data, if it is found that the socket to receive
|
||||
data is not matched with the specified socket, then - 1 will be returned; If the sending of
|
||||
message head or message body fails, return - 1; If the function runs successfully, the byte
|
||||
length of the message body sent successfully is returned.
|
||||
note: none
|
||||
date: 2022/8/11
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
static int libcomm_tcp_send(LibcommSendInfo* send_info)
|
||||
{
|
||||
int sock = send_info->socket;
|
||||
|
|
@ -337,19 +322,6 @@ static int libcomm_tcp_send(LibcommSendInfo* send_info)
|
|||
return send_bytes;
|
||||
}
|
||||
|
||||
/*
|
||||
function name: libcomm_tcp_recv_noidx
|
||||
description: This function is used to store the message transmitted from the sender, specifically to obtain
|
||||
the message from a specific socket.
|
||||
arguments: recv_ info is a pointer of LibcommRecvInfo* type, pointing to the memory to store the data
|
||||
received.
|
||||
return value: If it fails to allocate memory for iov_ Item, return RECV_MEM_ERROR;
|
||||
If it fails to obtain data, no matter it is a message header or a message body, from the specified socket in blocking mode, return RECV_NET_ERROR;
|
||||
If the function runs successfully, the byte length of the read message body is returned.
|
||||
note: none
|
||||
date: 2022/8/11
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
static int libcomm_tcp_recv_noidx(LibcommRecvInfo* recv_info)
|
||||
{
|
||||
int sock = recv_info->socket;
|
||||
|
|
@ -399,23 +371,6 @@ static int libcomm_tcp_recv_noidx(LibcommRecvInfo* recv_info)
|
|||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
function name: libcomm_tcp_recv
|
||||
description: This function is used to store the message transmitted from the sender, specifically to obtain
|
||||
the message from a specific socket.
|
||||
arguments: recv_ info is a pointer of LibcommRecvInfo* type, pointing to the memory to store the data
|
||||
received.
|
||||
return value: If the receiver has not been determined, call libcomm_tcp_recv_noidx() and take the return value
|
||||
of (libcomm_tcp_recv_noidx (recv_info)); Return RECV_NET_ERROR if there is an error in the
|
||||
process of reading the message heade or message body; If there is no data readable in the
|
||||
receiving buffer of the specified socket at this time or the number of bytes of the data that
|
||||
has been read is not enough, it returns RECV_NEED_RETRY; If iov_item is NULL, it returns
|
||||
RECV_MEM_ERROR if it fails to allocate space for it; If the function runs successfully, then
|
||||
the byte length of the read message head and message body is returned.
|
||||
note: none
|
||||
date: 2022/8/11
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
int libcomm_tcp_recv(LibcommRecvInfo* recv_info)
|
||||
{
|
||||
MsgHead* msg_head = NULL;
|
||||
|
|
|
|||
|
|
@ -137,16 +137,6 @@ static int LibCommClientSSLDHVerifyCb(const SSL* s, const SSL_CTX* ctx,
|
|||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
function name: ssl_cipher_list2string
|
||||
description: This function converts the two-dimensional character array storing the key into a one-dimensional character array.
|
||||
arguments: The first argument represents the two-dimensional character array to be converted.
|
||||
The second argument indicates the number of one-dimensional arrays contained in this two-dimensional array.
|
||||
return value: Returns a pointer to the one-dimensional character array that has been successfully converted. If the conversion fails, NULL is returned.
|
||||
note: none
|
||||
date: 2022/8/12
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
static char* ssl_cipher_list2string(const char* ciphers[], const int num) {
|
||||
int i;
|
||||
int catlen = 0;
|
||||
|
|
@ -237,20 +227,7 @@ char* LibCommErrMessage(void) {
|
|||
return errBuf;
|
||||
}
|
||||
|
||||
/*
|
||||
function name: LibCommClientSSLPasswd
|
||||
description: As a client, this function is used to detect whether there is a file with a valid key in the specified
|
||||
directory and whether there is permission to operate it. If so, the password will be decrypted by
|
||||
using the file.
|
||||
arguments: The first parameter is a pointer of type (SSL *).
|
||||
The second parameter is used to obtain the absolute path of the certificate file.
|
||||
The third parameter represents the user name.
|
||||
The fourth parameter is a pointer of type (libcommconn *), whose member variable contains the ciphertext to be decrypted.
|
||||
return value: If the path is empty or does not have operation permission to the directory where the certificate file is located, a non-1 value is returned; otherwise, 0 is returned.
|
||||
note: none
|
||||
date: 2022/8/12
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
|
||||
int LibCommClientSSLPasswd(SSL* pstContext, const char * path, const char * userName, LibCommConn * conn) {
|
||||
char* CertFilesDir = NULL;
|
||||
char CertFilesPath[MAXPATH] = {0};
|
||||
|
|
@ -274,8 +251,8 @@ int LibCommClientSSLPasswd(SSL* pstContext, const char * path, const char * user
|
|||
|
||||
/*check whether the cipher and rand files begins with userName exist.
|
||||
if exist, decrypt it.
|
||||
if not,decrypt the default cipher and rand files begins with client.
|
||||
Because,for every client user may own certification and private key*/
|
||||
if not,decrypt the default cipher and rand files begins with client%.
|
||||
Because,for every client user mayown certification and private key*/
|
||||
if (NULL == userName) {
|
||||
retval = LibCommClientCheckPermissionCipherFile(CertFilesDir, conn, NULL);
|
||||
if (retval != 1)
|
||||
|
|
|
|||
|
|
@ -33,16 +33,6 @@ inline int mc_lqueue_item_size(struct mc_lqueue_item* q_item)
|
|||
return q_item->element.data->iov_len;
|
||||
}
|
||||
|
||||
/*
|
||||
function name: mc_lqueue_add
|
||||
description: Add an element to a specific queue.
|
||||
arguments: The first parameter is a pointer of type (mc_lqueue *), whose member variable list points to the target queue.
|
||||
The second parameter points to the element to be added to the queue.
|
||||
return value: Returns 1 if the element is successfully added to the queue, otherwise returns - 1.
|
||||
note: none
|
||||
date: 2022/8/13
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
int mc_lqueue_add(struct mc_lqueue* q, struct mc_lqueue_item* q_item)
|
||||
{
|
||||
if (q == NULL || q_item == NULL) {
|
||||
|
|
@ -70,17 +60,6 @@ int mc_lqueue_add(struct mc_lqueue* q, struct mc_lqueue_item* q_item)
|
|||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
function name: mc_lqueue_remove
|
||||
description: Remove the head element in a specific queue.
|
||||
arguments: The first parameter is a pointer of type (mc_lqueue *), whose member variable list points to the target queue.
|
||||
The second parameter points to the queue head element used to store the removal from the queue.
|
||||
return value: Return NULL if an error occurs during the removal of the queue head element, otherwise a pointer to
|
||||
the successfully removed queue head element is returned.
|
||||
note: none
|
||||
date: 2022/8/13
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
struct mc_lqueue_item* mc_lqueue_remove(struct mc_lqueue* q, struct mc_lqueue_item* q_item)
|
||||
{
|
||||
if (q == NULL) {
|
||||
|
|
@ -110,18 +89,6 @@ struct mc_lqueue_item* mc_lqueue_remove(struct mc_lqueue* q, struct mc_lqueue_it
|
|||
return q_item;
|
||||
}
|
||||
|
||||
/*
|
||||
function name: mc_lqueue_init
|
||||
description: This function is used to open an area in the memory area. One part of the area is used to store a queue with
|
||||
a certain specification, and the other part is used to store the information of the queue, such as the specification
|
||||
and the number of elements. Finally, a pointer to the area is returned.
|
||||
arguments: This parameter specifies that the maximum number of elements that the queue can hold is size, but this does
|
||||
not mean that the size of the queue is so large at the beginning.
|
||||
return value: If the function runs successfully, it returns a pointer to the opened memory area; otherwise, it returns NULL.
|
||||
note: none
|
||||
date: 2022/8/13
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
struct mc_lqueue* mc_lqueue_init(unsigned long size)
|
||||
{
|
||||
if (size == 0) {
|
||||
|
|
|
|||
|
|
@ -222,7 +222,6 @@ NON_EXEC_STATIC void PercentileMain()
|
|||
g_instance.stat_cxt.force_process = false;
|
||||
sleep(SLEEP_INTERVAL);
|
||||
}
|
||||
elog(LOG, "instrumention percentile ended");
|
||||
gs_thread_exit(0);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -26,11 +26,9 @@ import logging
|
|||
try:
|
||||
from .dao.gsql_execute import GSqlExecute
|
||||
from .dao.execute_factory import ExecuteFactory
|
||||
from .mcts import MCTS
|
||||
except ImportError:
|
||||
from dao.gsql_execute import GSqlExecute
|
||||
from dao.execute_factory import ExecuteFactory
|
||||
from mcts import MCTS
|
||||
|
||||
ENABLE_MULTI_NODE = False
|
||||
SAMPLE_NUM = 5
|
||||
|
|
@ -194,12 +192,9 @@ class IndexAdvisor:
|
|||
self.workload_used_index))
|
||||
if DRIVER:
|
||||
self.db.close_conn()
|
||||
if MAX_INDEX_STORAGE:
|
||||
opt_config = MCTS(self.workload_info[0], atomic_config_total, candidate_indexes,
|
||||
MAX_INDEX_STORAGE, MAX_INDEX_NUM)
|
||||
else:
|
||||
opt_config = greedy_determine_opt_config(self.workload_info[0], atomic_config_total,
|
||||
candidate_indexes, self.index_cost_total[0])
|
||||
|
||||
opt_config = greedy_determine_opt_config(self.workload_info[0], atomic_config_total,
|
||||
candidate_indexes, self.index_cost_total[0])
|
||||
self.retain_lower_cost_index(candidate_indexes)
|
||||
if len(opt_config) == 0:
|
||||
print("No optimal indexes generated!")
|
||||
|
|
@ -948,7 +943,7 @@ def check_parameter(args):
|
|||
raise argparse.ArgumentTypeError("%s is an invalid positive int value" %
|
||||
args.max_index_num)
|
||||
if args.max_index_storage is not None and args.max_index_storage <= 0:
|
||||
raise argparse.ArgumentTypeError("%s is an invalid positive float value" %
|
||||
raise argparse.ArgumentTypeError("%s is an invalid positive int value" %
|
||||
args.max_index_storage)
|
||||
JSON_TYPE = args.json
|
||||
MAX_INDEX_NUM = args.max_index_num
|
||||
|
|
@ -976,7 +971,7 @@ def main(argv):
|
|||
arg_parser.add_argument(
|
||||
"--max_index_num", help="Maximum number of suggested indexes", type=int)
|
||||
arg_parser.add_argument("--max_index_storage",
|
||||
help="Maximum storage of suggested indexes/MB", type=float)
|
||||
help="Maximum storage of suggested indexes/MB", type=int)
|
||||
arg_parser.add_argument("--multi_iter_mode", action='store_true',
|
||||
help="Whether to use multi-iteration algorithm", default=False)
|
||||
arg_parser.add_argument("--multi_node", action='store_true',
|
||||
|
|
|
|||
|
|
@ -1,397 +0,0 @@
|
|||
import sys
|
||||
import math
|
||||
import random
|
||||
import copy
|
||||
|
||||
STORAGE_THRESHOLD = 0
|
||||
AVAILABLE_CHOICES = None
|
||||
ATOMIC_CHOICES = None
|
||||
WORKLOAD_INFO = None
|
||||
MAX_INDEX_NUM = 0
|
||||
|
||||
|
||||
def is_same_index(index, compared_index):
|
||||
return index.table == compared_index.table and \
|
||||
index.columns == compared_index.columns and \
|
||||
index.index_type == compared_index.index_type
|
||||
|
||||
|
||||
def atomic_config_is_valid(atomic_config, config):
|
||||
# if candidate indexes contains all atomic index of current config1, then record it
|
||||
for atomic_index in atomic_config:
|
||||
is_exist = False
|
||||
for index in config:
|
||||
if is_same_index(index, atomic_index):
|
||||
index.storage = atomic_index.storage
|
||||
is_exist = True
|
||||
break
|
||||
if not is_exist:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def find_subsets_num(choice):
|
||||
atomic_subsets_num = []
|
||||
for pos, atomic in enumerate(ATOMIC_CHOICES):
|
||||
if not atomic or len(atomic) > len(choice):
|
||||
continue
|
||||
# find valid atomic index
|
||||
if atomic_config_is_valid(atomic, choice):
|
||||
atomic_subsets_num.append(pos)
|
||||
# find the same atomic index as the candidate index
|
||||
if len(atomic) == 1 and (is_same_index(choice[-1], atomic[0])):
|
||||
choice[-1].atomic_pos = pos
|
||||
return atomic_subsets_num
|
||||
|
||||
|
||||
def find_best_benefit(choice):
|
||||
atomic_subsets_num = find_subsets_num(choice)
|
||||
total_benefit = 0
|
||||
for ind, obj in enumerate(WORKLOAD_INFO):
|
||||
# calculate the best benefit for the current sql
|
||||
max_benefit = 0
|
||||
for pos in atomic_subsets_num:
|
||||
if (obj.cost_list[0] - obj.cost_list[pos]) > max_benefit:
|
||||
max_benefit = obj.cost_list[0] - obj.cost_list[pos]
|
||||
total_benefit += max_benefit
|
||||
return total_benefit
|
||||
|
||||
|
||||
def get_diff(available_choices, choices):
|
||||
except_choices = copy.copy(available_choices)
|
||||
for i in available_choices:
|
||||
for j in choices:
|
||||
if is_same_index(i, j):
|
||||
except_choices.remove(i)
|
||||
return except_choices
|
||||
|
||||
|
||||
class State(object):
|
||||
"""
|
||||
The game state of the Monte Carlo tree search,
|
||||
the state data recorded under a certain Node node,
|
||||
including the current game score, the current number of game rounds,
|
||||
and the execution record from the beginning to the current.
|
||||
|
||||
It is necessary to realize whether the current state has reached the end of the game state,
|
||||
and support the operation of randomly fetching from the Action collection.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self.current_storage = 0.0
|
||||
self.current_benefit = 0.0
|
||||
# record the sum of choices up to the current state
|
||||
self.accumulation_choices = []
|
||||
# record available choices of current state
|
||||
self.available_choices = []
|
||||
self.displayable_choices = []
|
||||
|
||||
def get_available_choices(self):
|
||||
return self.available_choices
|
||||
|
||||
def set_available_choices(self, choices):
|
||||
self.available_choices = choices
|
||||
|
||||
def get_current_storage(self):
|
||||
return self.current_storage
|
||||
|
||||
def set_current_storage(self, value):
|
||||
self.current_storage = value
|
||||
|
||||
def get_current_benefit(self):
|
||||
return self.current_benefit
|
||||
|
||||
def set_current_benefit(self, value):
|
||||
self.current_benefit = value
|
||||
|
||||
def get_accumulation_choices(self):
|
||||
return self.accumulation_choices
|
||||
|
||||
def set_accumulation_choices(self, choices):
|
||||
self.accumulation_choices = choices
|
||||
|
||||
def is_terminal(self):
|
||||
# the current node is a leaf node
|
||||
return len(self.accumulation_choices) == MAX_INDEX_NUM
|
||||
|
||||
def compute_benefit(self):
|
||||
return self.current_benefit
|
||||
|
||||
def get_next_state_with_random_choice(self):
|
||||
# ensure that the choices taken are not repeated
|
||||
if not self.available_choices:
|
||||
return None
|
||||
random_choice = random.choice([choice for choice in self.available_choices])
|
||||
self.available_choices.remove(random_choice)
|
||||
choice = copy.copy(self.accumulation_choices)
|
||||
choice.append(random_choice)
|
||||
benefit = find_best_benefit(choice)
|
||||
# if current choice not satisfy restrictions, then continue get next choice
|
||||
if benefit <= self.current_benefit or \
|
||||
self.current_storage + random_choice.storage > STORAGE_THRESHOLD:
|
||||
return self.get_next_state_with_random_choice()
|
||||
|
||||
next_state = State()
|
||||
# initialize the properties of the new state
|
||||
next_state.set_accumulation_choices(choice)
|
||||
next_state.set_current_benefit(benefit)
|
||||
next_state.set_current_storage(self.current_storage + random_choice.storage)
|
||||
next_state.set_available_choices(get_diff(AVAILABLE_CHOICES, choice))
|
||||
return next_state
|
||||
|
||||
def __repr__(self):
|
||||
self.displayable_choices = ['{}: {}'.format(choice.table, choice.columns)
|
||||
for choice in self.accumulation_choices]
|
||||
return "reward: {}, storage :{}, choices: {}".format(
|
||||
self.current_benefit, self.current_storage, self.displayable_choices)
|
||||
|
||||
|
||||
class Node(object):
|
||||
"""
|
||||
The Node of the Monte Carlo tree search tree contains the parent node and
|
||||
current point information,
|
||||
which is used to calculate the traversal times and quality value of the UCB,
|
||||
and the State of the Node selected by the game.
|
||||
"""
|
||||
def __init__(self):
|
||||
self.visit_number = 0
|
||||
self.quality = 0.0
|
||||
|
||||
self.parent = None
|
||||
self.children = []
|
||||
self.state = None
|
||||
|
||||
def get_parent(self):
|
||||
return self.parent
|
||||
|
||||
def set_parent(self, parent):
|
||||
self.parent = parent
|
||||
|
||||
def get_children(self):
|
||||
return self.children
|
||||
|
||||
def expand_child(self, node):
|
||||
node.set_parent(self)
|
||||
self.children.append(node)
|
||||
|
||||
def set_state(self, state):
|
||||
self.state = state
|
||||
|
||||
def get_state(self):
|
||||
return self.state
|
||||
|
||||
def get_visit_number(self):
|
||||
return self.visit_number
|
||||
|
||||
def set_visit_number(self, number):
|
||||
self.visit_number = number
|
||||
|
||||
def update_visit_number(self):
|
||||
self.visit_number += 1
|
||||
|
||||
def get_quality_value(self):
|
||||
return self.quality
|
||||
|
||||
def set_quality_value(self, value):
|
||||
self.quality = value
|
||||
|
||||
def update_quality_value(self, reward):
|
||||
self.quality += reward
|
||||
|
||||
def is_all_expand(self):
|
||||
return len(self.children) == \
|
||||
len(AVAILABLE_CHOICES) - len(self.get_state().get_accumulation_choices())
|
||||
|
||||
def __repr__(self):
|
||||
return "Node: {}, Q/N: {}/{}, State: {}".format(
|
||||
hash(self), self.quality, self.visit_number, self.state)
|
||||
|
||||
|
||||
def tree_policy(node):
|
||||
"""
|
||||
In the Selection and Expansion stages of Monte Carlo tree search,
|
||||
the node that needs to be searched (such as the root node) is passed in,
|
||||
and the best node that needs to be expanded is returned
|
||||
according to the exploration/exploitation algorithm.
|
||||
Note that if the node is a leaf node, it will be returned directly.
|
||||
|
||||
The basic strategy is to first find the child nodes that have not been selected at present,
|
||||
and select them randomly if there are more than one. If both are selected,
|
||||
find the one with the largest UCB value that has weighed exploration/exploitation,
|
||||
and randomly select if the UCB values are equal.
|
||||
"""
|
||||
|
||||
# check if the current node is leaf node
|
||||
while node and not node.get_state().is_terminal():
|
||||
|
||||
if node.is_all_expand():
|
||||
node = best_child(node, True)
|
||||
else:
|
||||
# return the new sub node
|
||||
sub_node = expand(node)
|
||||
# when there is no node that satisfies the condition in the remaining nodes,
|
||||
# this state is empty
|
||||
if sub_node.get_state():
|
||||
return sub_node
|
||||
|
||||
# return the leaf node
|
||||
return node
|
||||
|
||||
|
||||
def default_policy(node):
|
||||
"""
|
||||
In the Simulation stage of Monte Carlo tree search, input a node that needs to be expanded,
|
||||
create a new node after random operation, and return the reward of the new node.
|
||||
Note that the input node should not be a child node,
|
||||
and there are unexecuted Actions that can be expendable.
|
||||
|
||||
The basic strategy is to choose the Action at random.
|
||||
"""
|
||||
|
||||
# get the state of the game
|
||||
current_state = copy.deepcopy(node.get_state())
|
||||
|
||||
# run until the game over
|
||||
while not current_state.is_terminal():
|
||||
# pick one random action to play and get next state
|
||||
next_state = current_state.get_next_state_with_random_choice()
|
||||
if not next_state:
|
||||
break
|
||||
current_state = next_state
|
||||
|
||||
final_state_reward = current_state.compute_benefit()
|
||||
return final_state_reward
|
||||
|
||||
|
||||
def expand(node):
|
||||
"""
|
||||
Enter a node, expand a new node on the node, use the random method to execute the Action,
|
||||
and return the new node. Note that it is necessary to ensure that the newly
|
||||
added nodes are different from other node Action
|
||||
"""
|
||||
|
||||
new_state = node.get_state().get_next_state_with_random_choice()
|
||||
sub_node = Node()
|
||||
sub_node.set_state(new_state)
|
||||
node.expand_child(sub_node)
|
||||
|
||||
return sub_node
|
||||
|
||||
|
||||
def best_child(node, is_exploration):
|
||||
"""
|
||||
Using the UCB algorithm,
|
||||
select the child node with the highest score after weighing the exploration and exploitation.
|
||||
Note that if it is the prediction stage,
|
||||
the current Q-value score with the highest score is directly selected.
|
||||
"""
|
||||
|
||||
best_score = -sys.maxsize
|
||||
best_sub_node = None
|
||||
|
||||
# travel all sub nodes to find the best one
|
||||
for sub_node in node.get_children():
|
||||
# The children nodes of the node contains the children node whose state is empty,
|
||||
# this kind of node comes from the node that does not meet the conditions.
|
||||
if not sub_node.get_state():
|
||||
continue
|
||||
# ignore exploration for inference
|
||||
if is_exploration:
|
||||
C = 1 / math.sqrt(2.0)
|
||||
else:
|
||||
C = 0.0
|
||||
|
||||
# UCB = quality / times + C * sqrt(2 * ln(total_times) / times)
|
||||
left = sub_node.get_quality_value() / sub_node.get_visit_number()
|
||||
right = 2.0 * math.log(node.get_visit_number()) / sub_node.get_visit_number()
|
||||
score = left + C * math.sqrt(right)
|
||||
# get the maximum score, while filtering nodes that do not meet the space constraints and
|
||||
# nodes that have no revenue
|
||||
if score > best_score \
|
||||
and sub_node.get_state().get_current_storage() <= STORAGE_THRESHOLD \
|
||||
and sub_node.get_state().get_current_benefit() > 0:
|
||||
best_sub_node = sub_node
|
||||
best_score = score
|
||||
|
||||
return best_sub_node
|
||||
|
||||
|
||||
def backpropagate(node, reward):
|
||||
"""
|
||||
In the Backpropagation stage of Monte Carlo tree search,
|
||||
input the node that needs to be expended and the reward of the newly executed Action,
|
||||
feed it back to the expend node and all upstream nodes,
|
||||
and update the corresponding data.
|
||||
"""
|
||||
|
||||
# update util the root node
|
||||
while node is not None:
|
||||
# update the visit number
|
||||
node.update_visit_number()
|
||||
|
||||
# update the quality value
|
||||
node.update_quality_value(reward)
|
||||
|
||||
# change the node to the parent node
|
||||
node = node.parent
|
||||
|
||||
|
||||
def monte_carlo_tree_search(node):
|
||||
"""
|
||||
Implement the Monte Carlo tree search algorithm, pass in a root node,
|
||||
expand new nodes and update data according to the
|
||||
tree structure that has been explored before in a limited time,
|
||||
and then return as long as the child node with the highest exploitation.
|
||||
|
||||
When making predictions,
|
||||
you only need to select the node with the largest exploitation according to the Q value,
|
||||
and find the next optimal node.
|
||||
"""
|
||||
|
||||
computation_budget = len(AVAILABLE_CHOICES) * 3
|
||||
|
||||
# run as much as possible under the computation budget
|
||||
for i in range(computation_budget):
|
||||
# 1. find the best node to expand
|
||||
expand_node = tree_policy(node)
|
||||
if not expand_node:
|
||||
# when it is None, it means that all nodes are added but no nodes meet the space limit
|
||||
break
|
||||
# 2. random get next action and get reward
|
||||
reward = default_policy(expand_node)
|
||||
|
||||
# 3. update all passing nodes with reward
|
||||
backpropagate(expand_node, reward)
|
||||
|
||||
# get the best next node
|
||||
best_next_node = best_child(node, False)
|
||||
|
||||
return best_next_node
|
||||
|
||||
|
||||
def MCTS(workload_info, atomic_choices, available_choices, storage_threshold, max_index_num):
|
||||
global ATOMIC_CHOICES, STORAGE_THRESHOLD, WORKLOAD_INFO, AVAILABLE_CHOICES, MAX_INDEX_NUM
|
||||
WORKLOAD_INFO = workload_info
|
||||
AVAILABLE_CHOICES = available_choices
|
||||
ATOMIC_CHOICES = atomic_choices
|
||||
STORAGE_THRESHOLD = storage_threshold
|
||||
MAX_INDEX_NUM = max_index_num if max_index_num else len(available_choices)
|
||||
|
||||
# create the initialized state and initialized node
|
||||
init_state = State()
|
||||
choices = copy.copy(available_choices)
|
||||
init_state.set_available_choices(choices)
|
||||
init_node = Node()
|
||||
init_node.set_state(init_state)
|
||||
current_node = init_node
|
||||
|
||||
opt_config = []
|
||||
# set the rounds to play
|
||||
for i in range(len(AVAILABLE_CHOICES)):
|
||||
if current_node:
|
||||
current_node = monte_carlo_tree_search(current_node)
|
||||
if current_node:
|
||||
opt_config = current_node.state.accumulation_choices
|
||||
else:
|
||||
break
|
||||
return opt_config
|
||||
|
|
@ -27,7 +27,6 @@ from collections.abc import Iterable
|
|||
from collections import defaultdict
|
||||
|
||||
import index_advisor_workload as iaw
|
||||
import mcts
|
||||
|
||||
|
||||
def hash_any(obj):
|
||||
|
|
@ -228,32 +227,6 @@ select * from student_range_part1 where credit=1;
|
|||
|
||||
class IndexAdvisorTester(unittest.TestCase):
|
||||
|
||||
def test_mcts(self):
|
||||
storage_threshold = 12
|
||||
index1 = iaw.IndexItem('public.a', 'col1', index_type='global')
|
||||
index2 = iaw.IndexItem('public.b', 'col1', index_type='global')
|
||||
index3 = iaw.IndexItem('public.c', 'col1', index_type='global')
|
||||
index4 = iaw.IndexItem('public.d', 'col1', index_type='global')
|
||||
|
||||
atomic_index1 = iaw.IndexItem('public.a', 'col1', index_type='global')
|
||||
atomic_index2 = iaw.IndexItem('public.b', 'col1', index_type='global')
|
||||
atomic_index3 = iaw.IndexItem('public.c', 'col1', index_type='global')
|
||||
atomic_index4 = iaw.IndexItem('public.d', 'col1', index_type='global')
|
||||
|
||||
atomic_index1.storage = 10
|
||||
atomic_index2.storage = 4
|
||||
atomic_index3.storage = 7
|
||||
available_choices = [index1, index2, index3, index4]
|
||||
atomic_choices = [[], [atomic_index2], [atomic_index1], [atomic_index3],
|
||||
[atomic_index2, atomic_index3], [atomic_index4]]
|
||||
query = iaw.QueryItem('select * from gia_01', 1)
|
||||
query.cost_list = [10, 7, 5, 9, 4, 11]
|
||||
workload_info = [query]
|
||||
|
||||
results = mcts.MCTS(workload_info, atomic_choices, available_choices, storage_threshold, 2)
|
||||
self.assertLessEqual([index1.atomic_pos, index2.atomic_pos, index3.atomic_pos], [2, 1, 3])
|
||||
self.assertSetEqual({results[0].table, results[1].table}, {'public.b', 'public.c'})
|
||||
|
||||
def test_get_indexable_columns(self):
|
||||
tables = 'table1 table2 table2 table3 table3 table3'.split()
|
||||
columns = 'col1,col2 col2 col3 col1,col2 col2,col3 col2,col5'.split()
|
||||
|
|
|
|||
|
|
@ -1175,7 +1175,7 @@ void CreateExtension(CreateExtensionStmt* stmt)
|
|||
FEATURE_NOT_PUBLIC_ERROR("EXTENSION is not yet supported.");
|
||||
}
|
||||
|
||||
if (pg_strcasecmp(stmt->extname, "dolphin") == 0 && !DB_IS_CMPT(B_FORMAT)) {
|
||||
if (pg_strcasecmp(stmt->extname, "b_sql_plugin") == 0 && !DB_IS_CMPT(B_FORMAT)) {
|
||||
ereport(ERROR,
|
||||
(errmsg("please create extension \"%s\" with B type DBCOMPATIBILITY", stmt->extname)));
|
||||
}
|
||||
|
|
@ -1418,8 +1418,8 @@ void CreateExtension(CreateExtensionStmt* stmt)
|
|||
|
||||
u_sess->exec_cxt.extension_is_valid = true;
|
||||
|
||||
if (pg_strcasecmp(stmt->extname, "dolphin") == 0) {
|
||||
u_sess->attr.attr_sql.dolphin = true;
|
||||
if (pg_strcasecmp(stmt->extname, "b_sql_plugin") == 0) {
|
||||
u_sess->attr.attr_sql.b_sql_plugin = true;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@
|
|||
#include "utils/array.h"
|
||||
#include "utils/acl.h"
|
||||
|
||||
static bool ConnectPublisher(char* conninfo, char* slotname);
|
||||
static void ConnectPublisher(char *conninfo, char* slotname);
|
||||
static void CreateSlotInPublisher(char *slotname);
|
||||
static void ValidateReplicationSlot(char *slotname, List *publications);
|
||||
|
||||
|
|
@ -56,7 +56,7 @@ static void ValidateReplicationSlot(char *slotname, List *publications);
|
|||
* accommodate that.
|
||||
*/
|
||||
static void parse_subscription_options(const List *options, char **conninfo, List **publications, bool *enabled_given,
|
||||
bool *enabled, bool *slot_name_given, char **slot_name, char **synchronous_commit, bool *binary_given, bool *binary)
|
||||
bool *enabled, bool *slot_name_given, char **slot_name, char **synchronous_commit)
|
||||
{
|
||||
ListCell *lc;
|
||||
|
||||
|
|
@ -76,10 +76,6 @@ static void parse_subscription_options(const List *options, char **conninfo, Lis
|
|||
if (synchronous_commit) {
|
||||
*synchronous_commit = NULL;
|
||||
}
|
||||
if (binary) {
|
||||
*binary_given = false;
|
||||
*binary = false;
|
||||
}
|
||||
|
||||
/* Parse options */
|
||||
foreach (lc, options) {
|
||||
|
|
@ -128,15 +124,6 @@ static void parse_subscription_options(const List *options, char **conninfo, Lis
|
|||
/* Test if the given value is valid for synchronous_commit GUC. */
|
||||
(void)set_config_option("synchronous_commit", *synchronous_commit, PGC_BACKEND, PGC_S_TEST, GUC_ACTION_SET,
|
||||
false, 0, false);
|
||||
} else if (strcmp(defel->defname, "binary") == 0 && binary) {
|
||||
if (*binary_given) {
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("conflicting or redundant options")));
|
||||
}
|
||||
|
||||
*binary_given = true;
|
||||
*binary = defGetBoolean(defel);
|
||||
} else {
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR), errmsg("unrecognized subscription parameter: %s", defel->defname)));
|
||||
|
|
@ -210,82 +197,26 @@ static Datum publicationListToArray(List *publist)
|
|||
}
|
||||
|
||||
/*
|
||||
* Parse the original connection string which is encrypted, poll all hosts and ports,
|
||||
* and try to connect to the publisher.
|
||||
* When checkRemoteMode is true, the remotemode must be normal or primary.
|
||||
* Return true to indicate successful connection.
|
||||
* connect publisher and create slot.
|
||||
* the input conninfo should be encrypt, we will decrypt password inside
|
||||
*/
|
||||
bool AttemptConnectPublisher(const char *conninfoOriginal, char* slotname, bool checkRemoteMode)
|
||||
{
|
||||
size_t conninfoLen = strlen(conninfoOriginal) + 1;
|
||||
|
||||
char* conninfo = NULL;
|
||||
StringInfoData conninfoWithoutHostport;
|
||||
initStringInfo(&conninfoWithoutHostport);
|
||||
HostPort* hostPortList[MAX_REPLNODE_NUM] = {NULL};
|
||||
ParseConninfo(conninfoOriginal, &conninfoWithoutHostport, hostPortList);
|
||||
if (hostPortList[0] == NULL) {
|
||||
ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg(
|
||||
"invalid connection string syntax, missing host and port")));
|
||||
}
|
||||
bool connectSuccess = false;
|
||||
conninfo = (char*)palloc(conninfoLen * sizeof(char));
|
||||
for (int i = 0; i < MAX_REPLNODE_NUM; ++i) {
|
||||
if (hostPortList[i] == NULL) {
|
||||
break;
|
||||
}
|
||||
int ret = snprintf_s(conninfo, conninfoLen, conninfoLen - 1,
|
||||
"%s host=%s port=%s", conninfoWithoutHostport.data,
|
||||
hostPortList[i]->host, hostPortList[i]->port);
|
||||
securec_check_ss(ret, "\0", "\0");
|
||||
|
||||
connectSuccess = ConnectPublisher(conninfo, slotname);
|
||||
if (!connectSuccess) {
|
||||
/* try next host */
|
||||
continue;
|
||||
}
|
||||
if (!checkRemoteMode) {
|
||||
break;
|
||||
}
|
||||
ServerMode publisherServerMde = IdentifyRemoteMode();
|
||||
if (publisherServerMde == NORMAL_MODE || publisherServerMde == PRIMARY_MODE) {
|
||||
break;
|
||||
}
|
||||
/* it's a standby, try next host */
|
||||
(WalReceiverFuncTable[GET_FUNC_IDX]).walrcv_disconnect();
|
||||
connectSuccess = false;
|
||||
}
|
||||
pfree_ext(conninfo);
|
||||
|
||||
/* clean up */
|
||||
FreeStringInfo(&conninfoWithoutHostport);
|
||||
for (int i = 0; i < MAX_REPLNODE_NUM; ++i) {
|
||||
if (hostPortList[i] == NULL) {
|
||||
break;
|
||||
}
|
||||
pfree_ext(hostPortList[i]->host);
|
||||
pfree_ext(hostPortList[i]->port);
|
||||
pfree_ext(hostPortList[i]);
|
||||
}
|
||||
return connectSuccess;
|
||||
}
|
||||
|
||||
/*
|
||||
* connect to publisher with conninfo
|
||||
*/
|
||||
static bool ConnectPublisher(char* conninfo, char* slotname)
|
||||
static void ConnectPublisher(char *conninfo, char *slotname)
|
||||
{
|
||||
/* Try to connect to the publisher. */
|
||||
volatile WalRcvData *walrcv = t_thrd.walreceiverfuncs_cxt.WalRcv;
|
||||
SpinLockAcquire(&walrcv->mutex);
|
||||
walrcv->conn_target = REPCONNTARGET_PUBLICATION;
|
||||
SpinLockRelease(&walrcv->mutex);
|
||||
char* decryptConninfo = EncryptOrDecryptConninfo(conninfo, 'D');
|
||||
|
||||
char *decryptConninfo = DecryptConninfo(conninfo);
|
||||
bool connectSuccess = (WalReceiverFuncTable[GET_FUNC_IDX]).walrcv_connect(decryptConninfo, NULL, slotname, -1);
|
||||
int rc = memset_s(decryptConninfo, strlen(decryptConninfo), 0, strlen(decryptConninfo));
|
||||
securec_check(rc, "", "");
|
||||
pfree_ext(decryptConninfo);
|
||||
return connectSuccess;
|
||||
|
||||
if (!connectSuccess) {
|
||||
ereport(ERROR, (errcode(ERRCODE_CONNECTION_FAILURE), errmsg("could not connect to the publisher")));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -362,10 +293,9 @@ ObjectAddress CreateSubscription(CreateSubscriptionStmt *stmt, bool isTopLevel)
|
|||
bool enabled_given = false;
|
||||
bool enabled = true;
|
||||
char *synchronous_commit;
|
||||
char *conninfo;
|
||||
char *slotname;
|
||||
bool slotname_given;
|
||||
bool binary;
|
||||
bool binary_given;
|
||||
char originname[NAMEDATALEN];
|
||||
List *publications;
|
||||
int rc;
|
||||
|
|
@ -375,7 +305,7 @@ ObjectAddress CreateSubscription(CreateSubscriptionStmt *stmt, bool isTopLevel)
|
|||
* Connection and publication should not be specified here.
|
||||
*/
|
||||
parse_subscription_options(stmt->options, NULL, NULL, &enabled_given, &enabled, &slotname_given, &slotname,
|
||||
&synchronous_commit, &binary_given, &binary);
|
||||
&synchronous_commit);
|
||||
|
||||
/*
|
||||
* Since creating a replication slot is not transactional, rolling back
|
||||
|
|
@ -403,10 +333,11 @@ ObjectAddress CreateSubscription(CreateSubscriptionStmt *stmt, bool isTopLevel)
|
|||
synchronous_commit = "off";
|
||||
}
|
||||
|
||||
conninfo = stmt->conninfo;
|
||||
publications = stmt->publication;
|
||||
|
||||
/* Check the connection info string. */
|
||||
libpqrcv_check_conninfo(stmt->conninfo);
|
||||
libpqrcv_check_conninfo(conninfo);
|
||||
|
||||
/* Everything ok, form a new tuple. */
|
||||
rc = memset_s(values, sizeof(values), 0, sizeof(values));
|
||||
|
|
@ -418,12 +349,18 @@ ObjectAddress CreateSubscription(CreateSubscriptionStmt *stmt, bool isTopLevel)
|
|||
values[Anum_pg_subscription_subname - 1] = DirectFunctionCall1(namein, CStringGetDatum(stmt->subname));
|
||||
values[Anum_pg_subscription_subowner - 1] = ObjectIdGetDatum(owner);
|
||||
values[Anum_pg_subscription_subenabled - 1] = BoolGetDatum(enabled);
|
||||
values[Anum_pg_subscription_subbinary - 1] = BoolGetDatum(binary);
|
||||
|
||||
/* encrypt conninfo */
|
||||
char *encryptConninfo = EncryptOrDecryptConninfo(stmt->conninfo, 'E');
|
||||
List *conninfoList = ConninfoToDefList(stmt->conninfo);
|
||||
/* Sensitive options for subscription, will be encrypted when saved to catalog. */
|
||||
const char* sensitiveOptionsArray[] = {"password"};
|
||||
const int sensitiveArrayLength = lengthof(sensitiveOptionsArray);
|
||||
EncryptGenericOptions(conninfoList, sensitiveOptionsArray, sensitiveArrayLength, SUBSCRIPTION_MODE);
|
||||
char *encryptConninfo = DefListToString(conninfoList);
|
||||
|
||||
values[Anum_pg_subscription_subconninfo - 1] = CStringGetTextDatum(encryptConninfo);
|
||||
|
||||
pfree_ext(conninfoList);
|
||||
if (enabled) {
|
||||
if (!slotname_given) {
|
||||
slotname = stmt->subname;
|
||||
|
|
@ -459,14 +396,11 @@ ObjectAddress CreateSubscription(CreateSubscriptionStmt *stmt, bool isTopLevel)
|
|||
*/
|
||||
if (enabled) {
|
||||
Assert(slotname);
|
||||
|
||||
if (!AttemptConnectPublisher(encryptConninfo, slotname, true)) {
|
||||
ereport(ERROR, (errcode(ERRCODE_CONNECTION_FAILURE), errmsg("Failed to connect to publisher.")));
|
||||
}
|
||||
|
||||
ConnectPublisher(encryptConninfo, slotname);
|
||||
CreateSlotInPublisher(slotname);
|
||||
(WalReceiverFuncTable[GET_FUNC_IDX]).walrcv_disconnect();
|
||||
}
|
||||
|
||||
pfree_ext(encryptConninfo);
|
||||
heap_close(rel, RowExclusiveLock);
|
||||
rc = memset_s(stmt->conninfo, strlen(stmt->conninfo), 0, strlen(stmt->conninfo));
|
||||
|
|
@ -505,8 +439,6 @@ ObjectAddress AlterSubscription(AlterSubscriptionStmt *stmt)
|
|||
Oid subid;
|
||||
bool enabled_given = false;
|
||||
bool enabled;
|
||||
bool binary_given;
|
||||
bool binary;
|
||||
char *synchronous_commit;
|
||||
char *conninfo;
|
||||
char *slot_name;
|
||||
|
|
@ -541,7 +473,7 @@ ObjectAddress AlterSubscription(AlterSubscriptionStmt *stmt)
|
|||
|
||||
/* Parse options. */
|
||||
parse_subscription_options(stmt->options, &conninfo, &publications, &enabled_given, &enabled, &slotname_given,
|
||||
&slot_name, &synchronous_commit, &binary_given, &binary);
|
||||
&slot_name, &synchronous_commit);
|
||||
|
||||
/* Form a new tuple. */
|
||||
rc = memset_s(nulls, sizeof(nulls), false, sizeof(nulls));
|
||||
|
|
@ -558,15 +490,23 @@ ObjectAddress AlterSubscription(AlterSubscriptionStmt *stmt)
|
|||
if (conninfo) {
|
||||
/* Check the connection info string. */
|
||||
libpqrcv_check_conninfo(conninfo);
|
||||
encryptConninfo = EncryptOrDecryptConninfo(conninfo, 'E');
|
||||
rc = memset_s(conninfo, strlen(conninfo), 0, strlen(conninfo));
|
||||
securec_check(rc, "\0", "\0");
|
||||
values[Anum_pg_subscription_subconninfo - 1] = CStringGetTextDatum(encryptConninfo);
|
||||
replaces[Anum_pg_subscription_subconninfo - 1] = true;
|
||||
|
||||
/* encrypt conninfo */
|
||||
List *conninfoList = ConninfoToDefList(conninfo);
|
||||
/* Sensitive options for subscription, will be encrypted when saved to catalog. */
|
||||
const char* sensitiveOptionsArray[] = {"password"};
|
||||
const int sensitiveArrayLength = lengthof(sensitiveOptionsArray);
|
||||
EncryptGenericOptions(conninfoList, sensitiveOptionsArray, sensitiveArrayLength, SUBSCRIPTION_MODE);
|
||||
encryptConninfo = DefListToString(conninfoList);
|
||||
needFreeConninfo = true;
|
||||
|
||||
/* need to check whether new conninfo can be used to connect to new publisher */
|
||||
values[Anum_pg_subscription_subconninfo - 1] = CStringGetTextDatum(encryptConninfo);
|
||||
replaces[Anum_pg_subscription_subconninfo - 1] = true;
|
||||
|
||||
pfree_ext(conninfoList);
|
||||
|
||||
if (sub->enabled || (enabled_given && enabled)) {
|
||||
/* we need to check whether new conninfo can be used to connect to new publisher */
|
||||
checkConn = true;
|
||||
}
|
||||
}
|
||||
|
|
@ -608,10 +548,6 @@ ObjectAddress AlterSubscription(AlterSubscriptionStmt *stmt)
|
|||
values[Anum_pg_subscription_subsynccommit - 1] = CStringGetTextDatum(synchronous_commit);
|
||||
replaces[Anum_pg_subscription_subsynccommit - 1] = true;
|
||||
}
|
||||
if (binary_given) {
|
||||
values[Anum_pg_subscription_subbinary - 1] = BoolGetDatum(binary);
|
||||
replaces[Anum_pg_subscription_subbinary - 1] = true;
|
||||
}
|
||||
if (publications != NIL) {
|
||||
values[Anum_pg_subscription_subpublications - 1] = publicationListToArray(publications);
|
||||
replaces[Anum_pg_subscription_subpublications - 1] = true;
|
||||
|
|
@ -634,18 +570,16 @@ ObjectAddress AlterSubscription(AlterSubscriptionStmt *stmt)
|
|||
if (sub->enabled && !enabled) {
|
||||
ereport(ERROR, (errmsg("If you want to deactivate this subscription, use DROP SUBSCRIPTION.")));
|
||||
}
|
||||
/* enabling subscription, but slot hasn't been created,
|
||||
* then mark createSlot to true.
|
||||
*/
|
||||
if (!sub->enabled && enabled && (!sub->slotname || !*(sub->slotname))) {
|
||||
/* enable subscription */
|
||||
if (!sub->enabled && enabled) {
|
||||
/* if slot hasn't been created, then create it */
|
||||
if (!sub->slotname || !*(sub->slotname)) {
|
||||
createSlot = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (checkConn || createSlot || validateSlot) {
|
||||
if (!AttemptConnectPublisher(encryptConninfo, finalSlotName, true)) {
|
||||
ereport(ERROR, (errcode(ERRCODE_CONNECTION_FAILURE), errmsg(
|
||||
checkConn ? "The new conninfo cannot connect to new publisher." : "Failed to connect to publisher.")));
|
||||
}
|
||||
ConnectPublisher(encryptConninfo, finalSlotName);
|
||||
|
||||
if (createSlot) {
|
||||
CreateSlotInPublisher(finalSlotName);
|
||||
|
|
@ -663,6 +597,12 @@ ObjectAddress AlterSubscription(AlterSubscriptionStmt *stmt)
|
|||
if (needFreeConninfo) {
|
||||
pfree_ext(encryptConninfo);
|
||||
}
|
||||
|
||||
if (conninfo) {
|
||||
rc = memset_s(conninfo, strlen(conninfo), 0, strlen(conninfo));
|
||||
securec_check(rc, "", "");
|
||||
}
|
||||
|
||||
return myself;
|
||||
}
|
||||
|
||||
|
|
@ -813,11 +753,7 @@ void DropSubscription(DropSubscriptionStmt *stmt, bool isTopLevel)
|
|||
initStringInfo(&cmd);
|
||||
appendStringInfo(&cmd, "DROP_REPLICATION_SLOT %s", quote_identifier(slotname));
|
||||
|
||||
if (!AttemptConnectPublisher(conninfo, slotname, true)) {
|
||||
ereport(ERROR, (errcode(ERRCODE_CONNECTION_FAILURE), errmsg(
|
||||
"could not connect to publisher.")));
|
||||
}
|
||||
|
||||
ConnectPublisher(conninfo, slotname);
|
||||
PG_TRY();
|
||||
{
|
||||
int sqlstate = 0;
|
||||
|
|
@ -843,7 +779,6 @@ void DropSubscription(DropSubscriptionStmt *stmt, bool isTopLevel)
|
|||
|
||||
(WalReceiverFuncTable[GET_FUNC_IDX]).walrcv_disconnect();
|
||||
|
||||
pfree_ext(conninfo);
|
||||
pfree(cmd.data);
|
||||
heap_close(rel, NoLock);
|
||||
}
|
||||
|
|
@ -973,149 +908,3 @@ void RenameSubscription(List *oldname, const char *newname)
|
|||
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse the host or port string into a string array,
|
||||
* where host and port are separated by ",".
|
||||
* input: conn --- host or port string separated by ","
|
||||
* output: connArray --- host or port string array
|
||||
* return: the length of connArray
|
||||
* for example:
|
||||
* (1):
|
||||
* conn = 1.1.1.1,2.2.2.2,...,9.9.9.9
|
||||
* connArray = {
|
||||
* 1,.1.1.1,
|
||||
* 2.2.2.2,
|
||||
* ...,
|
||||
* 9.9.9.9
|
||||
* }
|
||||
* return 9
|
||||
* (2):
|
||||
* conn = 1,2,...,9
|
||||
* connArray = {1,2,...,9}
|
||||
* return 9
|
||||
*/
|
||||
static int HostsPortsToArray(const char* conn, char** connArray)
|
||||
{
|
||||
if (conn == NULL) {
|
||||
return 0;
|
||||
}
|
||||
char* cp = NULL;
|
||||
char* cur = NULL;
|
||||
char *buf = pstrdup(conn);
|
||||
|
||||
cp = buf;
|
||||
int i = 0;
|
||||
while (*cp) {
|
||||
cur = cp;
|
||||
while (*cp && *cp != ',') {
|
||||
++cp;
|
||||
}
|
||||
if (*cp == ',') {
|
||||
*cp = '\0';
|
||||
++cp;
|
||||
}
|
||||
if (i >= MAX_REPLNODE_NUM) {
|
||||
ereport(ERROR, (errmsg("Currently, a maximum of %d servers are "
|
||||
"supported.", MAX_REPLNODE_NUM)));
|
||||
}
|
||||
connArray[i++] = pstrdup(cur);
|
||||
|
||||
if (*cp == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
pfree(buf);
|
||||
return i;
|
||||
}
|
||||
|
||||
/*
|
||||
* parse host and port
|
||||
*/
|
||||
static void ParseHostPort(char* hoststr, char* portstr, HostPort** hostPortList)
|
||||
{
|
||||
char* hosts[MAX_REPLNODE_NUM] = {NULL};
|
||||
char* ports[MAX_REPLNODE_NUM] = {NULL};
|
||||
int hostNum = HostsPortsToArray(hoststr, hosts);
|
||||
int portNum = HostsPortsToArray(portstr, ports);
|
||||
if (hostNum != portNum) {
|
||||
ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("The number of host and port are inconsistent.")));
|
||||
}
|
||||
|
||||
for (int i = 0; i < hostNum; ++i) {
|
||||
hostPortList[i] = (HostPort*)palloc(sizeof(HostPort));
|
||||
hostPortList[i]->host = hosts[i];
|
||||
hostPortList[i]->port = ports[i];
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse conninfo
|
||||
* conninfo format:
|
||||
* 'dbname=abc user=username password=xxxx host=ip1,ip2,...,ip9 port=p1,p2,...,p9'
|
||||
* after parsing:
|
||||
* conninfoWithoutHostPort:
|
||||
* 'dbname=abc user=username password=xxxx'
|
||||
* hostPortList:
|
||||
* {
|
||||
* {host=ip1, port=p1},
|
||||
* {host=ip2, port=p2},
|
||||
* ...
|
||||
* {host=ip9, port=p9}
|
||||
* }
|
||||
*/
|
||||
void ParseConninfo(const char* conninfo, StringInfoData* conninfoWithoutHostPort, HostPort** hostPortList)
|
||||
{
|
||||
List* conninfoList = ConninfoToDefList(conninfo);
|
||||
ListCell* l = NULL;
|
||||
|
||||
char* hostStr = NULL;
|
||||
char* portStr = NULL;
|
||||
foreach (l, conninfoList) {
|
||||
DefElem* defel = (DefElem*)lfirst(l);
|
||||
if (pg_strcasecmp(defel->defname, "host") == 0) {
|
||||
hostStr = defGetString(defel);
|
||||
} else if (pg_strcasecmp(defel->defname, "port") == 0) {
|
||||
portStr = defGetString(defel);
|
||||
} else {
|
||||
appendStringInfo(conninfoWithoutHostPort, "%s=%s ", defel->defname, defGetString(defel));
|
||||
}
|
||||
}
|
||||
if (hostPortList != NULL) {
|
||||
ParseHostPort(hostStr, portStr, hostPortList);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* encrypt conninfo when action = 'E'
|
||||
* decrypt conninfo when action = 'D'
|
||||
* conninfoNew: encrypted or decrypted conninfo
|
||||
*/
|
||||
char* EncryptOrDecryptConninfo(const char* conninfo, const char action)
|
||||
{
|
||||
/* parse conninfo to list */
|
||||
List *conninfoList = ConninfoToDefList(conninfo);
|
||||
/* Sensitive options for subscription */
|
||||
const char* sensitiveOptionsArray[] = {"password"};
|
||||
const int sensitiveArrayLength = lengthof(sensitiveOptionsArray);
|
||||
switch (action) {
|
||||
/* Encrypt */
|
||||
case 'E':
|
||||
EncryptGenericOptions(conninfoList, sensitiveOptionsArray, sensitiveArrayLength, SUBSCRIPTION_MODE);
|
||||
break;
|
||||
|
||||
/* Decrypt */
|
||||
case 'D':
|
||||
DecryptOptions(conninfoList, sensitiveOptionsArray, sensitiveArrayLength, SUBSCRIPTION_MODE);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
char* conninfoNew = DefListToString(conninfoList);
|
||||
ClearListContent(conninfoList);
|
||||
list_free_ext(conninfoList);
|
||||
|
||||
return conninfoNew;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23175,7 +23175,7 @@ static void checkValidationForExchangeTable(Relation partTableRel, Relation ordT
|
|||
int2 bucketId = InvalidBktId;
|
||||
|
||||
// get right partition oid for the tuple
|
||||
targetPartOid = heapTupleGetPartitionId(partTableRel, (HeapTuple)tuple, true);
|
||||
targetPartOid = heapTupleGetPartitionId(partTableRel, (HeapTuple) tuple);
|
||||
|
||||
searchFakeReationForPartitionOid(
|
||||
partRelHTAB, CurrentMemoryContext, partTableRel, targetPartOid, partRel, part, RowExclusiveLock);
|
||||
|
|
@ -24797,8 +24797,7 @@ static Oid AddTemporaryPartitionForAlterPartitions(const AlterTableCmd* cmd, Rel
|
|||
destPartOid = AddTemporaryHashPartitionForAlterPartitions(cmd, partTableRel, partSeq, renameTargetPart);
|
||||
break;
|
||||
}
|
||||
case PART_TYPE_RANGE:
|
||||
case PART_TYPE_INTERVAL: {
|
||||
case PART_TYPE_RANGE: {
|
||||
destPartOid = AddTemporaryRangePartitionForAlterPartitions(cmd, partTableRel, partSeq, renameTargetPart);
|
||||
break;
|
||||
}
|
||||
|
|
@ -25099,11 +25098,11 @@ static void readTuplesAndInsertInternal(Relation tempTableRel, Relation partTabl
|
|||
|
||||
/* tableam_tops_copy_tuple is not ready so we add UStore hack path */
|
||||
copyTuple = tableam_tops_copy_tuple(tuple);
|
||||
targetPartOid = heapTupleGetPartitionId(partTableRel, (void *)tuple, true);
|
||||
targetPartOid = heapTupleGetPartitionId(partTableRel, (void *)tuple);
|
||||
searchFakeReationForPartitionOid(
|
||||
partRelHTAB, CurrentMemoryContext, partTableRel, targetPartOid, partRel, part, RowExclusiveLock);
|
||||
if (RelationIsSubPartitioned(partTableRel)) {
|
||||
targetPartOid = heapTupleGetPartitionId(partRel, (void *)tuple, true);
|
||||
targetPartOid = heapTupleGetPartitionId(partRel, (void *)tuple);
|
||||
searchFakeReationForPartitionOid(partRelHTAB, CurrentMemoryContext, partRel, targetPartOid, subPartRel,
|
||||
subPart, RowExclusiveLock);
|
||||
partRel = subPartRel;
|
||||
|
|
|
|||
|
|
@ -1181,17 +1181,6 @@ static Node* pull_up_simple_subquery(PlannerInfo* root, Node* jtnode, RangeTblEn
|
|||
return jtnode;
|
||||
}
|
||||
|
||||
/*
|
||||
* We must flatten any join alias Vars in the subquery's targetlist,
|
||||
* because pulling up the subquery's subqueries might have changed their
|
||||
* expansions into arbitrary expressions, which could affect
|
||||
* pullup_replace_vars' decisions about whether PlaceHolderVar wrappers
|
||||
* are needed for tlist entries. (Likely it'd be better to do
|
||||
* flatten_join_alias_vars on the whole query tree at some earlier stage,
|
||||
* maybe even in the rewriter; but for now let's just fix this case here.)
|
||||
*/
|
||||
subquery->targetList = (List *) flatten_join_alias_vars(subroot, (Node *) subquery->targetList);
|
||||
|
||||
/*
|
||||
* Adjust level-0 varnos in subquery so that we can append its rangetable
|
||||
* to upper query's. We have to fix the subquery's append_rel_list as
|
||||
|
|
|
|||
|
|
@ -1263,7 +1263,7 @@ static void ckpt_pagewriter_main_thread_loop(void)
|
|||
HandlePageWriterMainInterrupts();
|
||||
|
||||
candidate_num = get_curr_candidate_nums(false) + get_curr_candidate_nums(true);
|
||||
if (candidate_num == 0 && !t_thrd.pagewriter_cxt.shutdown_requested) {
|
||||
if (candidate_num == 0) {
|
||||
/* wakeup sub thread scan the buffer pool, init the candidate list */
|
||||
wakeup_sub_thread();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -825,10 +825,10 @@ void client_read_ended(void)
|
|||
#define INIT_PLUGIN_OBJECT "init_plugin_object"
|
||||
void InitBSqlPluginHookIfNeeded()
|
||||
{
|
||||
const char* dolphin = "dolphin";
|
||||
const char* b_sql_plugin = "b_sql_plugin";
|
||||
CFunInfo tmpCF;
|
||||
|
||||
tmpCF = load_external_function(dolphin, INIT_PLUGIN_OBJECT, false, false);
|
||||
tmpCF = load_external_function(b_sql_plugin, INIT_PLUGIN_OBJECT, false, false);
|
||||
if (tmpCF.user_fn != NULL) {
|
||||
((void* (*)(void))(tmpCF.user_fn))();
|
||||
}
|
||||
|
|
@ -862,11 +862,9 @@ List* pg_parse_query(const char* query_string, List** query_string_locationlist)
|
|||
|
||||
List* (*parser_hook)(const char*, List**) = raw_parser;
|
||||
#ifndef ENABLE_MULTIPLE_NODES
|
||||
if (u_sess->attr.attr_sql.dolphin) {
|
||||
int id = GetCustomParserId();
|
||||
if (id >= 0 && g_instance.raw_parser_hook[id] != NULL) {
|
||||
parser_hook = (List* (*)(const char*, List**))g_instance.raw_parser_hook[id];
|
||||
}
|
||||
int id = GetCustomParserId();
|
||||
if (id >= 0 && g_instance.raw_parser_hook[id] != NULL) {
|
||||
parser_hook = (List* (*)(const char*, List**))g_instance.raw_parser_hook[id];
|
||||
}
|
||||
#endif
|
||||
raw_parsetree_list = parser_hook(query_string, query_string_locationlist);
|
||||
|
|
@ -6114,9 +6112,6 @@ void ProcessInterrupts(void)
|
|||
|
||||
/* The logical replication launcher can be stopped at any time. */
|
||||
proc_exit(0);
|
||||
} else if (IsLogicalWorker()) {
|
||||
ereport(FATAL, (errcode(ERRCODE_ADMIN_SHUTDOWN),
|
||||
errmsg("terminating logical replication worker due to administrator command")));
|
||||
#endif
|
||||
} else if (IsTxnSnapCapturerProcess()) {
|
||||
ereport(FATAL,
|
||||
|
|
@ -7574,7 +7569,7 @@ int PostgresMain(int argc, char* argv[], const char* dbname, const char* usernam
|
|||
init_set_params_htab();
|
||||
|
||||
#ifndef ENABLE_MULTIPLE_NODES
|
||||
if (u_sess->proc_cxt.MyDatabaseId != InvalidOid && DB_IS_CMPT(B_FORMAT) && u_sess->attr.attr_sql.dolphin) {
|
||||
if (u_sess->proc_cxt.MyDatabaseId != InvalidOid && DB_IS_CMPT(B_FORMAT) && u_sess->attr.attr_sql.b_sql_plugin) {
|
||||
InitBSqlPluginHookIfNeeded();
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -848,7 +848,7 @@ static bool InitSession(knl_session_context* session)
|
|||
t_thrd.proc_cxt.PostInit->InitSession();
|
||||
|
||||
#ifndef ENABLE_MULTIPLE_NODES
|
||||
if (u_sess->proc_cxt.MyDatabaseId != InvalidOid && DB_IS_CMPT(B_FORMAT) && u_sess->attr.attr_sql.dolphin) {
|
||||
if (u_sess->proc_cxt.MyDatabaseId != InvalidOid && DB_IS_CMPT(B_FORMAT) && u_sess->attr.attr_sql.b_sql_plugin) {
|
||||
InitBSqlPluginHookIfNeeded();
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -720,6 +720,7 @@ static Datum ExecEvalWholeRowVar(
|
|||
{
|
||||
Var* variable = (Var*)wrvstate->xprstate.expr;
|
||||
TupleTableSlot* slot = NULL;
|
||||
TupleDesc slot_tupdesc;
|
||||
bool needslow = false;
|
||||
|
||||
if (isDone != NULL)
|
||||
|
|
@ -801,13 +802,21 @@ static Datum ExecEvalWholeRowVar(
|
|||
if (wrvstate->wrv_junkFilter != NULL)
|
||||
slot = ExecFilterJunk(wrvstate->wrv_junkFilter, slot);
|
||||
|
||||
slot_tupdesc = slot->tts_tupleDescriptor;
|
||||
|
||||
/*
|
||||
* If it's a RECORD Var, we'll use the slot's type ID info. It's likely
|
||||
* that the slot's type is also RECORD; if so, make sure it's been
|
||||
* "blessed", so that the Datum can be interpreted later.
|
||||
*
|
||||
* If the Var identifies a named composite type, we must check that the
|
||||
* actual tuple type is compatible with it.
|
||||
*/
|
||||
if (variable->vartype != RECORDOID) {
|
||||
if (variable->vartype == RECORDOID) {
|
||||
if (slot_tupdesc->tdtypeid == RECORDOID && slot_tupdesc->tdtypmod < 0)
|
||||
assign_record_type_typmod(slot_tupdesc);
|
||||
} else {
|
||||
TupleDesc var_tupdesc;
|
||||
TupleDesc slot_tupdesc;
|
||||
int i;
|
||||
|
||||
/*
|
||||
|
|
@ -824,8 +833,6 @@ static Datum ExecEvalWholeRowVar(
|
|||
*/
|
||||
var_tupdesc = lookup_rowtype_tupdesc(variable->vartype, -1);
|
||||
|
||||
slot_tupdesc = slot->tts_tupleDescriptor;
|
||||
|
||||
if (var_tupdesc->natts != slot_tupdesc->natts)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_DATATYPE_MISMATCH),
|
||||
|
|
@ -879,7 +886,6 @@ static Datum ExecEvalWholeRowFast(
|
|||
{
|
||||
Var* variable = (Var*)wrvstate->xprstate.expr;
|
||||
TupleTableSlot* slot = NULL;
|
||||
TupleDesc slot_tupdesc;
|
||||
HeapTuple tuple;
|
||||
TupleDesc tupleDesc;
|
||||
HeapTupleHeader dtuple;
|
||||
|
|
@ -909,17 +915,6 @@ static Datum ExecEvalWholeRowFast(
|
|||
if (wrvstate->wrv_junkFilter != NULL)
|
||||
slot = ExecFilterJunk(wrvstate->wrv_junkFilter, slot);
|
||||
|
||||
/*
|
||||
* If it's a RECORD Var, we'll use the slot's type ID info. It's likely
|
||||
* that the slot's type is also RECORD; if so, make sure it's been
|
||||
* "blessed", so that the Datum can be interpreted later.
|
||||
*/
|
||||
slot_tupdesc = slot->tts_tupleDescriptor;
|
||||
if (variable->vartype == RECORDOID) {
|
||||
if (slot_tupdesc->tdtypeid == RECORDOID && slot_tupdesc->tdtypmod < 0)
|
||||
assign_record_type_typmod(slot_tupdesc);
|
||||
}
|
||||
|
||||
tuple = ExecFetchSlotTuple(slot);
|
||||
tupleDesc = slot->tts_tupleDescriptor;
|
||||
|
||||
|
|
|
|||
|
|
@ -322,6 +322,7 @@ static bool RelationFindReplTupleByIndex(EState *estate, Relation rel, Relation
|
|||
}
|
||||
if (found) {
|
||||
/* Found tuple, try to lock it in the lockmode. */
|
||||
outslot->tts_tuple = ExecMaterializeSlot(outslot);
|
||||
xwait = TransactionIdIsValid(snap.xmin) ? snap.xmin : snap.xmax;
|
||||
/*
|
||||
* If the tuple is locked, wait for locking transaction to finish
|
||||
|
|
@ -345,16 +346,12 @@ static bool RelationFindReplTupleByIndex(EState *estate, Relation rel, Relation
|
|||
ItemPointer tid = tableam_tops_get_t_self(targetRel, outslot->tts_tuple);
|
||||
|
||||
if (RelationIsUstoreFormat(targetRel)) {
|
||||
/* materialize the slot, so we can visit it after the scan is end */
|
||||
outslot->tts_tuple = UHeapMaterialize(outslot);
|
||||
ItemPointerCopy(tid, &UHeaplocktup.ctid);
|
||||
rc = memset_s(&tbuf, sizeof(tbuf), 0, sizeof(tbuf));
|
||||
securec_check(rc, "\0", "\0");
|
||||
UHeaplocktup.disk_tuple = &tbuf.hdr;
|
||||
locktup = &UHeaplocktup;
|
||||
} else {
|
||||
/* materialize the slot, so we can visit it after the scan is end */
|
||||
outslot->tts_tuple = ExecMaterializeSlot(outslot);
|
||||
ItemPointerCopy(tid, &heaplocktup.t_self);
|
||||
locktup = &heaplocktup;
|
||||
}
|
||||
|
|
@ -404,10 +401,6 @@ static bool tuple_equals_slot(TupleDesc desc, const Tuple tup, TupleTableSlot *s
|
|||
/* Check equality of the attributes. */
|
||||
for (attrnum = 0; attrnum < desc->natts; attrnum++) {
|
||||
TypeCacheEntry *typentry;
|
||||
/* skip generate column */
|
||||
if (GetGeneratedCol(desc, attrnum)) {
|
||||
continue;
|
||||
}
|
||||
/*
|
||||
* If one value is NULL and other is not, then they are certainly not
|
||||
* equal
|
||||
|
|
@ -485,6 +478,7 @@ static bool RelationFindReplTupleSeq(Relation rel, LockTupleMode lockmode, Tuple
|
|||
|
||||
found = true;
|
||||
ExecStoreTuple(scantuple, outslot, InvalidBuffer, false);
|
||||
outslot->tts_tuple = ExecMaterializeSlot(outslot);
|
||||
|
||||
xwait = TransactionIdIsValid(snap.xmin) ? snap.xmin : snap.xmax;
|
||||
/*
|
||||
|
|
@ -517,16 +511,12 @@ static bool RelationFindReplTupleSeq(Relation rel, LockTupleMode lockmode, Tuple
|
|||
ItemPointer tid = tableam_tops_get_t_self(rel, outslot->tts_tuple);
|
||||
|
||||
if (RelationIsUstoreFormat(targetRel)) {
|
||||
/* materialize the slot, so we can visit it after the scan is end */
|
||||
outslot->tts_tuple = UHeapMaterialize(outslot);
|
||||
ItemPointerCopy(tid, &UHeaplocktup.ctid);
|
||||
rc = memset_s(&tbuf, sizeof(tbuf), 0, sizeof(tbuf));
|
||||
securec_check(rc, "\0", "\0");
|
||||
UHeaplocktup.disk_tuple = &tbuf.hdr;
|
||||
locktup = &UHeaplocktup;
|
||||
} else {
|
||||
/* materialize the slot, so we can visit it after the scan is end */
|
||||
outslot->tts_tuple = ExecMaterializeSlot(outslot);
|
||||
ItemPointerCopy(tid, &heaplocktup.t_self);
|
||||
locktup = &heaplocktup;
|
||||
}
|
||||
|
|
@ -663,6 +653,7 @@ void ExecSimpleRelationUpdate(EState *estate, EPQState *epqstate, TupleTableSlot
|
|||
/* Compute stored generated columns */
|
||||
if (rel->rd_att->constr && rel->rd_att->constr->has_generated_stored) {
|
||||
ExecComputeStoredGenerated(resultRelInfo, estate, slot, tuple, CMD_UPDATE);
|
||||
tuple = slot->tts_tuple;
|
||||
}
|
||||
|
||||
/* Check the constraints of the tuple */
|
||||
|
|
@ -681,11 +672,10 @@ void ExecSimpleRelationUpdate(EState *estate, EPQState *epqstate, TupleTableSlot
|
|||
rowMovement = true;
|
||||
}
|
||||
|
||||
tuple = slot->tts_tuple;
|
||||
CommandId cid = GetCurrentCommandId(true);
|
||||
/* OK, update the tuple and index entries for it */
|
||||
if (!rowMovement) {
|
||||
res = tableam_tuple_update(targetRelation, parentRelation, searchSlotTid, tuple, cid,
|
||||
res = tableam_tuple_update(targetRelation, parentRelation, searchSlotTid, slot->tts_tuple, cid,
|
||||
InvalidSnapshot, estate->es_snapshot, true, &oldslot, &tmfd, &updateIndexes, &modifiedIdxAttrs,
|
||||
false, allowInplaceUpdate);
|
||||
CheckTupleModifyRes(res);
|
||||
|
|
|
|||
|
|
@ -72,9 +72,7 @@
|
|||
extern char* nodeTagToString(NodeTag type);
|
||||
|
||||
typedef VectorBatch* (*VectorEngineFunc)(PlanState* node);
|
||||
/*
|
||||
This is a test.
|
||||
*/
|
||||
|
||||
VectorBatch* UnSupportVectorRunner(PlanState* node)
|
||||
{
|
||||
ereport(ERROR,
|
||||
|
|
|
|||
|
|
@ -8965,8 +8965,6 @@ void StartupXLOG(void)
|
|||
g_instance.comm_cxt.predo_cxt.redoPf.redo_done_time = 0;
|
||||
pg_atomic_write_u32(&(g_instance.comm_cxt.localinfo_cxt.is_finish_redo), 0);
|
||||
|
||||
NotifyGscRecoveryStarted();
|
||||
|
||||
/*
|
||||
* Initialize WAL insert status array and the flush index - lastWalStatusEntryFlushed.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1818,47 +1818,3 @@ void UHeapSlotStoreUHeapTuple(UHeapTuple utuple, TupleTableSlot *slot, bool shou
|
|||
/* Mark extracted state invalid */
|
||||
slot->tts_nvalid = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Make the contents of the uheap table's slot contents solely depend on the slot(make them a local copy),
|
||||
* and not on underlying external resources like another memory context, buffers etc.
|
||||
*
|
||||
* @pram slot: slot to be materialized.
|
||||
*/
|
||||
Tuple UHeapMaterialize(TupleTableSlot *slot)
|
||||
{
|
||||
Assert(!slot->tts_isempty);
|
||||
Assert(slot->tts_tupslotTableAm == TAM_USTORE);
|
||||
Assert(slot->tts_tupleDescriptor != NULL);
|
||||
/*
|
||||
* If we have a regular physical tuple, and it's locally palloc'd, we have
|
||||
* nothing to do.
|
||||
*/
|
||||
if (slot->tts_tuple && slot->tts_shouldFree) {
|
||||
return slot->tts_tuple;
|
||||
}
|
||||
|
||||
/*
|
||||
* Otherwise, copy or build a physical tuple, and store it into the slot.
|
||||
*
|
||||
* We may be called in a context that is shorter-lived than the tuple
|
||||
* slot, but we have to ensure that the materialized tuple will survive
|
||||
* anyway.
|
||||
*/
|
||||
MemoryContext old_context = MemoryContextSwitchTo(slot->tts_mcxt);
|
||||
if (slot->tts_tuple != NULL) {
|
||||
slot->tts_tuple = UHeapCopyTuple((UHeapTuple)slot->tts_tuple);
|
||||
} else {
|
||||
slot->tts_tuple = UHeapFormTuple(slot->tts_tupleDescriptor, slot->tts_values, slot->tts_isnull);
|
||||
}
|
||||
slot->tts_shouldFree = true;
|
||||
MemoryContextSwitchTo(old_context);
|
||||
|
||||
/*
|
||||
* Have to deform from scratch, otherwise tts_values[] entries could point
|
||||
* into the non-materialized tuple (which might be gone when accessed).
|
||||
*/
|
||||
slot->tts_nvalid = 0;
|
||||
return slot->tts_tuple;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -238,19 +238,15 @@ public:
|
|||
return m_purpose;
|
||||
}
|
||||
|
||||
GcEpochType GcStartInnerTxn()
|
||||
void GcStartTxnMTtests()
|
||||
{
|
||||
m_gcEpoch = GetGlobalEpoch();
|
||||
|
||||
return m_gcEpoch;
|
||||
if (m_gcEpoch != GetGlobalEpoch())
|
||||
m_gcEpoch = GetGlobalEpoch();
|
||||
}
|
||||
|
||||
void GcEndInnerTxn(bool clean_gc)
|
||||
void GcEndTxnMTtests()
|
||||
{
|
||||
if (clean_gc) {
|
||||
RunQuicese();
|
||||
}
|
||||
m_gcEpoch = 0;
|
||||
RunQuicese();
|
||||
}
|
||||
|
||||
void GcStartTxn()
|
||||
|
|
@ -276,7 +272,6 @@ public:
|
|||
RunQuicese();
|
||||
m_managerLock.unlock();
|
||||
}
|
||||
m_gcEpoch = 0;
|
||||
m_isTxnStarted = false;
|
||||
}
|
||||
|
||||
|
|
@ -318,6 +313,7 @@ public:
|
|||
{
|
||||
if (m_performGcEpoch != g_gcActiveEpoch)
|
||||
HardQuiesce(m_rcuFreeCount);
|
||||
m_gcEpoch = 0;
|
||||
}
|
||||
|
||||
/** @brief Clean all object at the end of the session */
|
||||
|
|
|
|||
|
|
@ -258,15 +258,6 @@ bool Index::IndexInsert(Sentinel*& outputSentinel, const Key* key, uint32_t pid,
|
|||
outputSentinel = IndexInsertImpl(key, sentinel, inserted, pid);
|
||||
// sync between rollback/delete and insert
|
||||
if (inserted == false) {
|
||||
if (unlikely(outputSentinel == nullptr)) {
|
||||
MOT_REPORT_ERROR(
|
||||
MOT_ERROR_OOM, "Index Insert", "Failed to insert sentinel to index %s", m_name.c_str());
|
||||
rc = RC_MEMORY_ALLOCATION_ERROR;
|
||||
m_sentinelPool->Release<Sentinel>(sentinel);
|
||||
sentinel = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Spin if the counter is 0 - aborting in parallel or sentinel is marks for commit
|
||||
if (outputSentinel->RefCountUpdate(INC, pid) == RC_OK)
|
||||
retryInsert = false;
|
||||
|
|
@ -309,16 +300,8 @@ Sentinel* Index::IndexInsert(const Key* key, Row* row, uint32_t pid)
|
|||
// no need to report to full error stack
|
||||
SetLastError(MOT_ERROR_UNIQUE_VIOLATION, MOT_SEVERITY_NORMAL);
|
||||
m_sentinelPool->Release<Sentinel>(sentinel);
|
||||
sentinel = nullptr;
|
||||
return nullptr;
|
||||
} else {
|
||||
if (inserted == false) {
|
||||
MOT_REPORT_ERROR(MOT_ERROR_OOM, "Index Insert", "Failed to insert sentinel to index %s", m_name.c_str());
|
||||
m_sentinelPool->Release<Sentinel>(sentinel);
|
||||
sentinel = nullptr;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (GetIndexOrder() == IndexOrder::INDEX_ORDER_PRIMARY) {
|
||||
sentinel->SetPrimaryIndex();
|
||||
sentinel->SetNextPtr(row);
|
||||
|
|
@ -360,6 +343,9 @@ Sentinel* Index::IndexReadHeader(const Key* key, uint32_t pid) const
|
|||
Sentinel* Index::IndexRemove(const Key* key, uint32_t pid)
|
||||
{
|
||||
Sentinel* sentinel = IndexRemoveImpl(key, pid);
|
||||
|
||||
MOT_ASSERT(sentinel != nullptr);
|
||||
MOT_ASSERT(sentinel->GetCounter() == 0);
|
||||
return sentinel;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -56,22 +56,12 @@ void* basic_table<P>::insert(MOT::Key const* const& key, void* const& entry, boo
|
|||
5. Update the the key slice, keylen, key suffix and key's value in the
|
||||
leaf
|
||||
6. Add the key's location in permutation's back (key is not visible for
|
||||
readers yet) as key's location is not part of the permutation yet, the key
|
||||
readers yet) As key's location is not part of the permutation yet, the key
|
||||
is not reachable (aka not present). In addition, the leaf is still locked.
|
||||
Unlocking the node and enter the key into the permutation will be done
|
||||
later in finish_insert (done in lp.finish function). */
|
||||
later in finish_insert (called from lp.finish). */
|
||||
|
||||
bool found = false;
|
||||
if (!lp.find_insert(*mtSessionThreadInfo, found)) {
|
||||
// Failed to insert key due to memory allocation failure.
|
||||
MOT_ASSERT(!mtSessionThreadInfo->non_disruptive_error());
|
||||
MOT_ASSERT(found == false);
|
||||
lp.finish(0, *mtSessionThreadInfo);
|
||||
result = false;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MOT_ASSERT(mtSessionThreadInfo->non_disruptive_error());
|
||||
bool found = lp.find_insert(*mtSessionThreadInfo);
|
||||
|
||||
// If the key is new (not previously existing) then we record the entry under
|
||||
// that key
|
||||
|
|
|
|||
|
|
@ -33,15 +33,15 @@ namespace Masstree {
|
|||
template <typename P>
|
||||
struct gc_layer_rcu_callback_ng : public P::threadinfo_type::mrcu_callback {
|
||||
typedef typename P::threadinfo_type threadinfo;
|
||||
node_base<P>** root_ref_;
|
||||
node_base<P>* root_;
|
||||
int len_;
|
||||
size_t size_;
|
||||
MOT::MasstreePrimaryIndex* index_;
|
||||
char s_[0];
|
||||
gc_layer_rcu_callback_ng(node_base<P>** root_ref, Str prefix, size_t size)
|
||||
: root_ref_(root_ref), len_(prefix.length()), size_(size), index_(mtSessionThreadInfo->get_working_index())
|
||||
gc_layer_rcu_callback_ng(node_base<P>* root, Str prefix, size_t size)
|
||||
: root_(root), len_(prefix.length()), size_(size), index_(mtSessionThreadInfo->get_working_index())
|
||||
{
|
||||
errno_t erc = memcpy_s(s_, len_, prefix.data(), len_);
|
||||
errno_t erc = memcpy_s(s_, size_, prefix.data(), len_);
|
||||
securec_check(erc, "\0", "\0");
|
||||
}
|
||||
size_t operator()(bool drop_index);
|
||||
|
|
@ -51,7 +51,7 @@ struct gc_layer_rcu_callback_ng : public P::threadinfo_type::mrcu_callback {
|
|||
return size_;
|
||||
}
|
||||
|
||||
static void make(node_base<P>** root_ref, Str prefix, threadinfo& ti);
|
||||
static void make(node_base<P>* root, Str prefix, threadinfo& ti);
|
||||
};
|
||||
|
||||
template <typename P>
|
||||
|
|
@ -60,8 +60,8 @@ size_t gc_layer_rcu_callback_ng<P>::operator()(bool drop_index)
|
|||
// If drop_index == true, all index's pools are going to be cleaned, so we can skip gc_layer call (which might add
|
||||
// more elements into GC)
|
||||
if (drop_index == false) {
|
||||
// GC layer remove might delete elements from tree and might create new gc layer removal requests and add them to GC.
|
||||
// Index must be provided to allow access to the memory pools.
|
||||
// GC layer remove might delete elements from tree and add them to the limbolist. Index must be provided to
|
||||
// allow access to the memory pools.
|
||||
mtSessionThreadInfo->set_working_index(index_);
|
||||
(*this)(*mtSessionThreadInfo);
|
||||
mtSessionThreadInfo->set_working_index(NULL);
|
||||
|
|
@ -73,33 +73,30 @@ size_t gc_layer_rcu_callback_ng<P>::operator()(bool drop_index)
|
|||
template <typename P>
|
||||
void gc_layer_rcu_callback_ng<P>::operator()(threadinfo& ti)
|
||||
{
|
||||
masstree_invariant(root_ref_);
|
||||
|
||||
tcursor<P> node_cursor(root_ref_, s_, len_);
|
||||
bool do_remove = node_cursor.gc_layer(ti);
|
||||
if (!do_remove || !node_cursor.finish_remove(ti)) {
|
||||
node_cursor.n_->unlock();
|
||||
// root_ node while creating gc_layer_rcu_callback_ng might not be the current root. Find updated tree's root.
|
||||
while (!root_->is_root()) {
|
||||
root_ = root_->maybe_parent();
|
||||
}
|
||||
ti.add_nodes_to_gc();
|
||||
}
|
||||
|
||||
template <typename P>
|
||||
void gc_layer_rcu_callback_ng<P>::make(node_base<P>** root_ref, Str prefix, threadinfo& ti)
|
||||
{
|
||||
size_t sz = prefix.len + sizeof(gc_layer_rcu_callback_ng<P>);
|
||||
// As we are using slab allocator for allocation, sz is will be updated by ti.allocate with the real allocation
|
||||
// size. We need this size for GC deallocation size report
|
||||
void* data = ti.allocate(sz, memtag_masstree_gc, &sz /* IN/OUT PARAM */);
|
||||
if (!data) {
|
||||
// If allocation fails, gc layer removal command will not be added to GC and this layer wont be removed.
|
||||
// We might deal with this issue in the future by replacing the current mechanism with one of the following options:
|
||||
// 1. Use thread local GC layer removal object (per threadinfo) and keep list of key suffixes to clean (also in threadinfo)
|
||||
// 2. Move this feature to VACUUM process: Create special iterator that adds GC Layer callbacks when it finds empty layers
|
||||
ti.set_last_error(MT_MERR_GC_LAYER_REMOVAL_MAKE);
|
||||
// If root was already deleted, do nothing.
|
||||
if (root_->deleted()) {
|
||||
return;
|
||||
}
|
||||
|
||||
gc_layer_rcu_callback_ng<P>* cb = new (data) gc_layer_rcu_callback_ng<P>(root_ref, prefix, sz);
|
||||
tcursor<P> node_cursor(root_, s_, len_);
|
||||
if (!node_cursor.gc_layer(ti) || !node_cursor.finish_remove(ti)) {
|
||||
node_cursor.n_->unlock();
|
||||
}
|
||||
}
|
||||
|
||||
template <typename P>
|
||||
void gc_layer_rcu_callback_ng<P>::make(node_base<P>* root, Str prefix, threadinfo& ti)
|
||||
{
|
||||
size_t sz = prefix.len + sizeof(gc_layer_rcu_callback_ng<P>);
|
||||
// As we are using slab allocator to allocate the memory, sz is will updated in ti.allocate with the real allocated
|
||||
// size
|
||||
void* data = ti.allocate(sz, memtag_masstree_gc, &sz /*OUT PARAM*/);
|
||||
gc_layer_rcu_callback_ng<P>* cb = new (data) gc_layer_rcu_callback_ng<P>(root, prefix, sz);
|
||||
ti.rcu_register(cb, sz);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -69,17 +69,14 @@ Sentinel* MasstreePrimaryIndex::IndexInsertImpl(const Key* key, Sentinel* sentin
|
|||
mtSessionThreadInfo->set_gc_session(
|
||||
MOTEngine::GetInstance()->GetCurrentGcSession()); // set current GC session in thread-pooled envelope
|
||||
|
||||
mtSessionThreadInfo->set_last_error(MT_MERR_OK);
|
||||
|
||||
existingItem = m_index.insert(key, sentinel, inserted, pid);
|
||||
|
||||
mtSessionThreadInfo->set_gc_session(NULL);
|
||||
mtSessionThreadInfo->set_working_index(NULL);
|
||||
|
||||
if (!inserted && existingItem) { // key mapping already exists in unique index
|
||||
if (!inserted) { // key mapping already exists in unique index
|
||||
result = reinterpret_cast<Sentinel*>(existingItem);
|
||||
} // otherwise return null pointer (if !inserted && !existingItem, Key does not exist and insertation failed due to
|
||||
// memory issue)
|
||||
} // otherwise return null pointer
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
@ -111,8 +108,6 @@ Sentinel* MasstreePrimaryIndex::IndexRemoveImpl(const Key* key, uint32_t pid)
|
|||
mtSessionThreadInfo->set_gc_session(
|
||||
MOTEngine::GetInstance()->GetCurrentGcSession()); // set current GC session in thread-pooled envelope
|
||||
|
||||
mtSessionThreadInfo->set_last_error(MT_MERR_OK);
|
||||
|
||||
output = m_index.remove(key->GetKeyBuf(), key->GetKeyLength(), result, pid);
|
||||
|
||||
mtSessionThreadInfo->set_gc_session(NULL);
|
||||
|
|
|
|||
|
|
@ -37,7 +37,6 @@
|
|||
#include "masstree/mot_masstree_struct.hpp"
|
||||
#include "masstree/mot_masstree_iterator.hpp"
|
||||
#include <cmath>
|
||||
#include "mot_engine.h"
|
||||
|
||||
namespace MOT {
|
||||
/**
|
||||
|
|
@ -303,38 +302,11 @@ public:
|
|||
/**
|
||||
* @brief Print Masstree pools memory consumption details to log.
|
||||
*/
|
||||
virtual void PrintPoolsStats(LogLevel level = LogLevel::LL_DEBUG)
|
||||
virtual void PrintPoolsStats()
|
||||
{
|
||||
m_leafsPool->Print("Leafs pool", level);
|
||||
m_internodesPool->Print("Internode pool", level);
|
||||
m_ksuffixSlab->Print("Ksuffix slab", level);
|
||||
}
|
||||
|
||||
virtual void GetLeafsPoolStats(uint64_t& objSize, uint64_t& numUsedObj, uint64_t& totalSize, uint64_t& netto)
|
||||
{
|
||||
PoolStatsSt stats = {};
|
||||
m_leafsPool->GetStats(stats);
|
||||
|
||||
objSize = stats.m_objSize;
|
||||
numUsedObj = stats.m_totalObjCount - stats.m_freeObjCount;
|
||||
totalSize = stats.m_poolCount * stats.m_poolGrossSize;
|
||||
netto = numUsedObj * objSize;
|
||||
}
|
||||
|
||||
virtual void GetInternodesPoolStats(uint64_t& objSize, uint64_t& numUsedObj, uint64_t& totalSize, uint64_t& netto)
|
||||
{
|
||||
PoolStatsSt stats = {};
|
||||
m_internodesPool->GetStats(stats);
|
||||
|
||||
objSize = stats.m_objSize;
|
||||
numUsedObj = stats.m_totalObjCount - stats.m_freeObjCount;
|
||||
totalSize = stats.m_poolCount * stats.m_poolGrossSize;
|
||||
netto = numUsedObj * objSize;
|
||||
}
|
||||
|
||||
virtual PoolStatsSt* GetKsuffixSlabStats()
|
||||
{
|
||||
return m_ksuffixSlab->GetStats();
|
||||
m_leafsPool->Print("Leafs pool: ");
|
||||
m_internodesPool->Print("Internode pool: ");
|
||||
m_ksuffixSlab->Print("Ksuffix slab: ");
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -344,8 +316,6 @@ public:
|
|||
{
|
||||
m_initialized = false;
|
||||
DestroyPools();
|
||||
// remove masstree's root pointer (not valid anymore)
|
||||
*(m_index.root_ref()) = nullptr;
|
||||
|
||||
return IndexInitImpl(NULL);
|
||||
}
|
||||
|
|
@ -362,7 +332,7 @@ public:
|
|||
* @param tag Hint to determine which pool to use.
|
||||
* @return Pointer to allocated memory.
|
||||
*/
|
||||
virtual void* AllocateMem(int& size, enum memtag tag)
|
||||
void* AllocateMem(int& size, enum memtag tag)
|
||||
{
|
||||
switch (tag) {
|
||||
case memtag_masstree_leaf:
|
||||
|
|
@ -390,7 +360,7 @@ public:
|
|||
* @param Pointer to allocated memory.
|
||||
* @return True if deallocation succeeded.
|
||||
*/
|
||||
virtual bool DeallocateMem(void* ptr, int size, enum memtag tag)
|
||||
bool DeallocateMem(void* ptr, int size, enum memtag tag)
|
||||
{
|
||||
switch (tag) {
|
||||
case memtag_masstree_leaf:
|
||||
|
|
@ -461,16 +431,10 @@ public:
|
|||
{
|
||||
// If dropIndex == true, all index's pools are going to be cleaned, so we skip the release here
|
||||
mtSessionThreadInfo->set_gc_session(GetCurrentGcSession());
|
||||
GcEpochType local_epoch =
|
||||
GetSessionManager()->GetCurrentSessionContext()->GetTxnManager()->GetGcSession()->GcStartInnerTxn();
|
||||
|
||||
size_t allocationSize = (*static_cast<mrcu_callback*>(gcRemoveLayerFuncObjPtr))(dropIndex);
|
||||
|
||||
if (dropIndex == false) {
|
||||
((SlabAllocator*)slab)->Release(gcRemoveLayerFuncObjPtr, allocationSize);
|
||||
}
|
||||
|
||||
GetSessionManager()->GetCurrentSessionContext()->GetTxnManager()->GetGcSession()->GcEndInnerTxn(false);
|
||||
mtSessionThreadInfo->set_gc_session(NULL);
|
||||
return allocationSize;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -582,7 +582,6 @@ Row* Table::RemoveKeyFromIndex(Row* row, Sentinel* sentinel, uint64_t tid, GcMan
|
|||
#endif
|
||||
currSentinel = ix->IndexRemove(&key, tid);
|
||||
MOT_ASSERT(currSentinel == sentinel);
|
||||
MOT_ASSERT(currSentinel->GetCounter() == 0);
|
||||
if (likely(gc != nullptr)) {
|
||||
if (ix->GetIndexOrder() == IndexOrder::INDEX_ORDER_PRIMARY) {
|
||||
OutputRow = currSentinel->GetData();
|
||||
|
|
|
|||
|
|
@ -413,8 +413,6 @@ RC TxnManager::RollbackInsert(Access* ac)
|
|||
#endif
|
||||
outputSen = index_->IndexRemove(&m_key, GetThdId());
|
||||
MOT_ASSERT(outputSen != nullptr);
|
||||
MOT_ASSERT(outputSen->GetCounter() == 0);
|
||||
|
||||
GcSessionRecordRcu(index_->GetIndexId(), outputSen, nullptr, Index::SentinelDtor, SENTINEL_SIZE(index_));
|
||||
// If we are the owner of the key and insert on top of a deleted row,
|
||||
// lets check if we can reclaim the deleted row
|
||||
|
|
@ -822,8 +820,6 @@ void TxnInsertAction::CleanupOptimisticInsert(
|
|||
MOT_ASSERT(pIndexInsertResult->GetCounter() == 0);
|
||||
Sentinel* outputSen = index_->IndexRemove(currentItem->m_key, m_manager->GetThdId());
|
||||
MOT_ASSERT(outputSen != nullptr);
|
||||
MOT_ASSERT(outputSen->GetCounter() == 0);
|
||||
|
||||
m_manager->GcSessionRecordRcu(
|
||||
index_->GetIndexId(), outputSen, nullptr, Index::SentinelDtor, SENTINEL_SIZE(index_));
|
||||
m_manager->m_accessMgr->IncreaseTableStat(table);
|
||||
|
|
|
|||
|
|
@ -255,14 +255,8 @@ void StartRemoteStreaming(const LibpqrcvConnectParam *options)
|
|||
stringlist_to_identifierstr(t_thrd.libwalreceiver_cxt.streamConn, options->publicationNames);
|
||||
appendStringInfo(&cmd, ", publication_names %s",
|
||||
PQescapeLiteral(t_thrd.libwalreceiver_cxt.streamConn, pubnames_str, strlen(pubnames_str)));
|
||||
pfree(pubnames_str);
|
||||
|
||||
if (options->binary && PQserverVersion(t_thrd.libwalreceiver_cxt.streamConn) >= 90204) {
|
||||
appendStringInfoString(&cmd, ", binary 'true'");
|
||||
ereport(DEBUG5, (errmsg("append binary true")));
|
||||
}
|
||||
|
||||
appendStringInfoChar(&cmd, ')');
|
||||
pfree(pubnames_str);
|
||||
}
|
||||
|
||||
PGresult *res = libpqrcv_PQexec(cmd.data);
|
||||
|
|
@ -426,7 +420,7 @@ void IdentifyRemoteSystem(bool checkRemote)
|
|||
}
|
||||
|
||||
/* identify remote mode, should do this after connect success. */
|
||||
ServerMode IdentifyRemoteMode()
|
||||
static ServerMode IdentifyRemoteMode()
|
||||
{
|
||||
Assert(t_thrd.libwalreceiver_cxt.streamConn != NULL);
|
||||
volatile WalRcvData *walrcv = t_thrd.walreceiverfuncs_cxt.WalRcv;
|
||||
|
|
@ -449,9 +443,7 @@ ServerMode IdentifyRemoteMode()
|
|||
num_fields)));
|
||||
}
|
||||
remoteMode = (ServerMode)pg_strtoint32(PQgetvalue(res, 0, 0));
|
||||
if (walrcv->conn_target != REPCONNTARGET_PUBLICATION &&
|
||||
!t_thrd.walreceiver_cxt.AmWalReceiverForFailover &&
|
||||
(!IS_PRIMARY_NORMAL(remoteMode)) &&
|
||||
if (!t_thrd.walreceiver_cxt.AmWalReceiverForFailover && (!IS_PRIMARY_NORMAL(remoteMode)) &&
|
||||
/* remoteMode of cascade standby is a standby */
|
||||
!t_thrd.xlog_cxt.is_cascade_standby && !IS_SHARED_STORAGE_MODE) {
|
||||
PQclear(res);
|
||||
|
|
|
|||
|
|
@ -223,7 +223,6 @@ void LogicalDecodingProcessRecord(LogicalDecodingContext *ctx, XLogReaderState *
|
|||
return;
|
||||
}
|
||||
|
||||
ResourceOwner tmpOwner = t_thrd.utils_cxt.CurrentResourceOwner;
|
||||
/* cast so we get a warning when new rmgrs are added */
|
||||
switch ((RmgrIds)XLogRecGetRmid(record)) {
|
||||
/*
|
||||
|
|
@ -258,7 +257,6 @@ void LogicalDecodingProcessRecord(LogicalDecodingContext *ctx, XLogReaderState *
|
|||
default:
|
||||
break;
|
||||
}
|
||||
t_thrd.utils_cxt.CurrentResourceOwner = tmpOwner;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
#include "catalog/pg_type.h"
|
||||
#include "libpq/pqformat.h"
|
||||
#include "replication/logicalproto.h"
|
||||
#include "utils/builtins.h"
|
||||
#include "utils/lsyscache.h"
|
||||
#include "utils/syscache.h"
|
||||
|
||||
|
|
@ -27,7 +28,7 @@
|
|||
static const int LOGICALREP_IS_REPLICA_IDENTITY = 1;
|
||||
|
||||
static void logicalrep_write_attrs(StringInfo out, Relation rel);
|
||||
static void logicalrep_write_tuple(StringInfo out, Relation rel, HeapTuple tuple, bool binary);
|
||||
static void logicalrep_write_tuple(StringInfo out, Relation rel, HeapTuple tuple);
|
||||
|
||||
static void logicalrep_read_attrs(StringInfo in, LogicalRepRelation *rel);
|
||||
static void logicalrep_read_tuple(StringInfo in, LogicalRepTupleData *tuple);
|
||||
|
|
@ -114,7 +115,7 @@ void logicalrep_write_origin(StringInfo out, const char *origin, XLogRecPtr orig
|
|||
/*
|
||||
* Write INSERT to the output stream.
|
||||
*/
|
||||
void logicalrep_write_insert(StringInfo out, Relation rel, HeapTuple newtuple, bool binary)
|
||||
void logicalrep_write_insert(StringInfo out, Relation rel, HeapTuple newtuple)
|
||||
{
|
||||
pq_sendbyte(out, 'I'); /* action INSERT */
|
||||
|
||||
|
|
@ -122,7 +123,7 @@ void logicalrep_write_insert(StringInfo out, Relation rel, HeapTuple newtuple, b
|
|||
pq_sendint32(out, RelationGetRelid(rel));
|
||||
|
||||
pq_sendbyte(out, 'N'); /* new tuple follows */
|
||||
logicalrep_write_tuple(out, rel, newtuple, binary);
|
||||
logicalrep_write_tuple(out, rel, newtuple);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -150,7 +151,7 @@ LogicalRepRelId logicalrep_read_insert(StringInfo in, LogicalRepTupleData *newtu
|
|||
/*
|
||||
* Write UPDATE to the output stream.
|
||||
*/
|
||||
void logicalrep_write_update(StringInfo out, Relation rel, HeapTuple oldtuple, HeapTuple newtuple, bool binary)
|
||||
void logicalrep_write_update(StringInfo out, Relation rel, HeapTuple oldtuple, HeapTuple newtuple)
|
||||
{
|
||||
pq_sendbyte(out, 'U'); /* action UPDATE */
|
||||
|
||||
|
|
@ -165,11 +166,11 @@ void logicalrep_write_update(StringInfo out, Relation rel, HeapTuple oldtuple, H
|
|||
pq_sendbyte(out, 'O'); /* old tuple follows */
|
||||
else
|
||||
pq_sendbyte(out, 'K'); /* old key follows */
|
||||
logicalrep_write_tuple(out, rel, oldtuple, binary);
|
||||
logicalrep_write_tuple(out, rel, oldtuple);
|
||||
}
|
||||
|
||||
pq_sendbyte(out, 'N'); /* new tuple follows */
|
||||
logicalrep_write_tuple(out, rel, newtuple, binary);
|
||||
logicalrep_write_tuple(out, rel, newtuple);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -212,7 +213,7 @@ LogicalRepRelId logicalrep_read_update(StringInfo in, bool *has_oldtuple, Logica
|
|||
/*
|
||||
* Write DELETE to the output stream.
|
||||
*/
|
||||
void logicalrep_write_delete(StringInfo out, Relation rel, HeapTuple oldtuple, bool binary)
|
||||
void logicalrep_write_delete(StringInfo out, Relation rel, HeapTuple oldtuple)
|
||||
{
|
||||
char relreplident = RelationGetRelReplident(rel);
|
||||
Assert(relreplident == REPLICA_IDENTITY_DEFAULT ||
|
||||
|
|
@ -228,7 +229,7 @@ void logicalrep_write_delete(StringInfo out, Relation rel, HeapTuple oldtuple, b
|
|||
else
|
||||
pq_sendbyte(out, 'K'); /* old key follows */
|
||||
|
||||
logicalrep_write_tuple(out, rel, oldtuple, binary);
|
||||
logicalrep_write_tuple(out, rel, oldtuple);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -343,7 +344,7 @@ void logicalrep_read_typ(StringInfo in, LogicalRepTyp *ltyp)
|
|||
/*
|
||||
* Write a tuple to the outputstream, in the most efficient format possible.
|
||||
*/
|
||||
static void logicalrep_write_tuple(StringInfo out, Relation rel, HeapTuple tuple, bool binary)
|
||||
static void logicalrep_write_tuple(StringInfo out, Relation rel, HeapTuple tuple)
|
||||
{
|
||||
TupleDesc desc;
|
||||
Datum values[MaxTupleAttributeNumber];
|
||||
|
|
@ -370,6 +371,7 @@ static void logicalrep_write_tuple(StringInfo out, Relation rel, HeapTuple tuple
|
|||
HeapTuple typtup;
|
||||
Form_pg_type typclass;
|
||||
Form_pg_attribute att = desc->attrs[i];
|
||||
char *outputstr;
|
||||
|
||||
/* skip dropped columns */
|
||||
if (att->attisdropped || GetGeneratedCol(desc, i)) {
|
||||
|
|
@ -377,7 +379,7 @@ static void logicalrep_write_tuple(StringInfo out, Relation rel, HeapTuple tuple
|
|||
}
|
||||
|
||||
if (isnull[i]) {
|
||||
pq_sendbyte(out, LOGICALREP_COLUMN_NULL); /* null column */
|
||||
pq_sendbyte(out, 'n'); /* null column */
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -386,91 +388,61 @@ static void logicalrep_write_tuple(StringInfo out, Relation rel, HeapTuple tuple
|
|||
elog(ERROR, "cache lookup failed for type %u", att->atttypid);
|
||||
typclass = (Form_pg_type)GETSTRUCT(typtup);
|
||||
|
||||
/*
|
||||
* Send in binary if requested and type has suitable send function.
|
||||
*/
|
||||
if (binary && OidIsValid(typclass->typsend)) {
|
||||
bytea* outputbytes = NULL;
|
||||
pq_sendbyte(out, LOGICALREP_COLUMN_BINARY);
|
||||
if (!typclass->typbyval && typclass->typlen == -1) {
|
||||
/* definitely detoasted Datum */
|
||||
Datum val = PointerGetDatum(PG_DETOAST_DATUM(values[i]));
|
||||
outputbytes = OidSendFunctionCall(typclass->typsend, val);
|
||||
} else {
|
||||
outputbytes = OidSendFunctionCall(typclass->typsend, values[i]);
|
||||
}
|
||||
int len = VARSIZE(outputbytes) - VARHDRSZ;
|
||||
pq_sendint(out, len, 4); /* length */
|
||||
pq_sendbytes(out, VARDATA(outputbytes), len); /* data */
|
||||
if (outputbytes != NULL) {
|
||||
pfree(outputbytes);
|
||||
}
|
||||
pq_sendbyte(out, 't'); /* 'text' data follows */
|
||||
if (!typclass->typbyval && typclass->typlen == -1) {
|
||||
/* definitely detoasted Datum */
|
||||
Datum val = PointerGetDatum(PG_DETOAST_DATUM(values[i]));
|
||||
outputstr = OidOutputFunctionCall(typclass->typoutput, val);
|
||||
} else {
|
||||
char* outputstr = NULL;
|
||||
pq_sendbyte(out, LOGICALREP_COLUMN_TEXT);
|
||||
if (!typclass->typbyval && typclass->typlen == -1) {
|
||||
/* definitely detoasted Datum */
|
||||
Datum val = PointerGetDatum(PG_DETOAST_DATUM(values[i]));
|
||||
outputstr = OidOutputFunctionCall(typclass->typoutput, val);
|
||||
} else {
|
||||
outputstr = OidOutputFunctionCall(typclass->typoutput, values[i]);
|
||||
}
|
||||
pq_sendcountedtext(out, outputstr, strlen(outputstr), false);
|
||||
if (outputstr != NULL) {
|
||||
pfree(outputstr);
|
||||
}
|
||||
outputstr = OidOutputFunctionCall(typclass->typoutput, values[i]);
|
||||
}
|
||||
pq_sendcountedtext(out, outputstr, strlen(outputstr), false);
|
||||
pfree(outputstr);
|
||||
ReleaseSysCache(typtup);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Read tuple in logical replication format from stream.
|
||||
* Read tuple in remote format from stream.
|
||||
*
|
||||
* The returned tuple points into the input stringinfo.
|
||||
*/
|
||||
static void logicalrep_read_tuple(StringInfo in, LogicalRepTupleData *tuple)
|
||||
{
|
||||
/* Get number of attributes. */
|
||||
uint16 natts = pq_getmsgint(in, sizeof(uint16));
|
||||
uint16 i;
|
||||
uint16 natts;
|
||||
int rc;
|
||||
|
||||
/* Allocate space for per-column values; zero out unused StringInfoDatas */
|
||||
tuple->colvalues = (StringInfoData *) palloc0(natts * sizeof(StringInfoData));
|
||||
tuple->colstatus = (char *) palloc(natts * sizeof(char));
|
||||
/* Get number of attributes. */
|
||||
natts = pq_getmsgint(in, sizeof(uint16));
|
||||
|
||||
rc = memset_s(tuple->changed, sizeof(tuple->changed), 0, sizeof(tuple->changed));
|
||||
securec_check(rc, "", "");
|
||||
tuple->ncols = natts;
|
||||
|
||||
/* Read the data */
|
||||
for (uint16 i = 0; i < natts; i++) {
|
||||
char kind = pq_getmsgbyte(in);
|
||||
tuple->colstatus[i] = kind;
|
||||
uint32 len;
|
||||
StringInfo value = &tuple->colvalues[i];
|
||||
for (i = 0; i < natts; i++) {
|
||||
char kind;
|
||||
|
||||
kind = pq_getmsgbyte(in);
|
||||
|
||||
switch (kind) {
|
||||
case LOGICALREP_COLUMN_NULL: /* null */
|
||||
/* nothing more to do */
|
||||
case 'n': /* null */
|
||||
tuple->values[i] = NULL;
|
||||
tuple->changed[i] = true;
|
||||
break;
|
||||
case LOGICALREP_COLUMN_TEXT:
|
||||
len = pq_getmsgint(in, sizeof(uint32)); /* read length */
|
||||
case 't': { /* text formatted value */
|
||||
uint32 len;
|
||||
tuple->changed[i] = true;
|
||||
|
||||
len = pq_getmsgint(in, sizeof(uint32)); /* read length */
|
||||
|
||||
/* and data */
|
||||
value->data = (char *) palloc((len + 1) * sizeof(char));
|
||||
pq_copymsgbytes(in, value->data, len);
|
||||
value->data[len] = '\0';
|
||||
/* make StringInfo fully valid */
|
||||
value->len = len;
|
||||
value->cursor = 0;
|
||||
value->maxlen = len;
|
||||
break;
|
||||
case LOGICALREP_COLUMN_BINARY:
|
||||
len = pq_getmsgint(in, sizeof(uint32)); /* read length */
|
||||
|
||||
/* and data */
|
||||
value->data = (char *)palloc0((len + 1) * sizeof(char));
|
||||
pq_copymsgbytes(in, value->data, len);
|
||||
/* make StringInfo fully valid */
|
||||
value->len = len;
|
||||
value->cursor = 0;
|
||||
value->maxlen = len;
|
||||
tuple->values[i] = (char *)palloc(len + 1);
|
||||
pq_copymsgbytes(in, tuple->values[i], len);
|
||||
tuple->values[i][len] = '\0';
|
||||
break;
|
||||
}
|
||||
default:
|
||||
elog(ERROR, "unrecognized data representation type '%c'", kind);
|
||||
break;
|
||||
|
|
@ -479,7 +451,7 @@ static void logicalrep_read_tuple(StringInfo in, LogicalRepTupleData *tuple)
|
|||
}
|
||||
|
||||
/*
|
||||
* Write relation attributes metadata to the stream.
|
||||
* Write relation attributes to the stream.
|
||||
*/
|
||||
static void logicalrep_write_attrs(StringInfo out, Relation rel)
|
||||
{
|
||||
|
|
@ -532,7 +504,7 @@ static void logicalrep_write_attrs(StringInfo out, Relation rel)
|
|||
}
|
||||
|
||||
/*
|
||||
* Read relation attribute metadata from the stream.
|
||||
* Read relation attribute names from the stream.
|
||||
*/
|
||||
static void logicalrep_read_attrs(StringInfo in, LogicalRepRelation *rel)
|
||||
{
|
||||
|
|
@ -601,25 +573,3 @@ static const char *logicalrep_read_namespace(StringInfo in)
|
|||
|
||||
return nspname;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write conninfo to the output stream.
|
||||
*/
|
||||
void logicalrep_write_conninfo(StringInfo out, char* conninfo)
|
||||
{
|
||||
pq_sendbyte(out, 'S'); /* action */
|
||||
|
||||
pq_writestring(out, conninfo); /* conninfo follows */
|
||||
}
|
||||
|
||||
/*
|
||||
* Read conninfo from stream.
|
||||
*/
|
||||
void logicalrep_read_conninfo(StringInfo in, char** conninfo)
|
||||
{
|
||||
const char* conninfoTemp = pq_getmsgstring(in);
|
||||
size_t conninfoLen = strlen(conninfoTemp) + 1;
|
||||
*conninfo = (char*)palloc(conninfoLen);
|
||||
int rc = strcpy_s(*conninfo, conninfoLen, conninfoTemp);
|
||||
securec_check(rc, "", "");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,7 +41,6 @@
|
|||
#include "catalog/pg_partition_fn.h"
|
||||
|
||||
#include "commands/trigger.h"
|
||||
#include "commands/subscriptioncmds.h"
|
||||
|
||||
#include "executor/executor.h"
|
||||
#include "executor/node/nodeModifyTable.h"
|
||||
|
|
@ -112,8 +111,6 @@ static void store_flush_position(XLogRecPtr remote_lsn);
|
|||
static void reread_subscription(void);
|
||||
static void ApplyWorkerProcessMsg(char type, StringInfo s, XLogRecPtr *lastRcv);
|
||||
static void apply_dispatch(StringInfo s);
|
||||
static void apply_handle_conninfo(StringInfo s);
|
||||
static void UpdateConninfo(char* standbysInfo);
|
||||
|
||||
/* SIGHUP: set flag to re-read config file at next convenient time */
|
||||
static void LogicalrepWorkerSighub(SIGNAL_ARGS)
|
||||
|
|
@ -121,6 +118,18 @@ static void LogicalrepWorkerSighub(SIGNAL_ARGS)
|
|||
t_thrd.applyworker_cxt.got_SIGHUP = true;
|
||||
}
|
||||
|
||||
/* SIGTERM: time to die */
|
||||
static void LogicalrepWorkerSigterm(SIGNAL_ARGS)
|
||||
{
|
||||
int saveErrno = errno;
|
||||
|
||||
t_thrd.applyworker_cxt.got_SIGTERM = true;
|
||||
if (t_thrd.proc)
|
||||
SetLatch(&t_thrd.proc->procLatch);
|
||||
|
||||
errno = saveErrno;
|
||||
}
|
||||
|
||||
/*
|
||||
* Make sure that we started local transaction.
|
||||
*
|
||||
|
|
@ -256,11 +265,11 @@ static void slot_store_error_callback(void *arg)
|
|||
}
|
||||
|
||||
/*
|
||||
* Store tuple data into slot.
|
||||
*
|
||||
* Incoming data can be either text or binary format.
|
||||
* Store data in C string form into slot.
|
||||
* This is similar to BuildTupleFromCStrings but TupleTableSlot fits our
|
||||
* use better.
|
||||
*/
|
||||
static void slot_store_data(TupleTableSlot *slot, LogicalRepRelMapEntry *rel, LogicalRepTupleData *tupleData)
|
||||
static void slot_store_cstrings(TupleTableSlot *slot, LogicalRepRelMapEntry *rel, char **values)
|
||||
{
|
||||
int natts = slot->tts_tupleDescriptor->natts;
|
||||
int i;
|
||||
|
|
@ -277,52 +286,19 @@ static void slot_store_data(TupleTableSlot *slot, LogicalRepRelMapEntry *rel, Lo
|
|||
errcallback.previous = t_thrd.log_cxt.error_context_stack;
|
||||
t_thrd.log_cxt.error_context_stack = &errcallback;
|
||||
|
||||
/* Call the "in" function for each non-dropped, non-null attribute */
|
||||
/* Call the "in" function for each non-dropped attribute */
|
||||
for (i = 0; i < natts; i++) {
|
||||
Form_pg_attribute att = slot->tts_tupleDescriptor->attrs[i];
|
||||
int remoteattnum = rel->attrmap[i];
|
||||
Oid typinput;
|
||||
Oid typioparam;
|
||||
|
||||
if (!att->attisdropped && remoteattnum >= 0) {
|
||||
StringInfo colvalue = &tupleData->colvalues[remoteattnum];
|
||||
if (!att->attisdropped && remoteattnum >= 0 && values[remoteattnum] != NULL) {
|
||||
errarg.remote_attnum = remoteattnum;
|
||||
|
||||
if (tupleData->colstatus[remoteattnum] == LOGICALREP_COLUMN_TEXT) {
|
||||
Oid typinput;
|
||||
Oid typioparam;
|
||||
|
||||
getTypeInputInfo(att->atttypid, &typinput, &typioparam);
|
||||
slot->tts_values[i] = OidInputFunctionCall(typinput, colvalue->data, typioparam, att->atttypmod);
|
||||
slot->tts_isnull[i] = false;
|
||||
} else if (tupleData->colstatus[remoteattnum] == LOGICALREP_COLUMN_BINARY) {
|
||||
Oid typreceive;
|
||||
Oid typioparam;
|
||||
|
||||
/*
|
||||
* In some code paths we may be asked to re-parse the same
|
||||
* tuple data. Reset the StringInfo's cursor so that works.
|
||||
*/
|
||||
colvalue->cursor = 0;
|
||||
|
||||
getTypeBinaryInputInfo(att->atttypid, &typreceive, &typioparam);
|
||||
slot->tts_values[i] = OidReceiveFunctionCall(typreceive, colvalue, typioparam, att->atttypmod);
|
||||
|
||||
/* Trouble if it didn't eat the whole buffer */
|
||||
if (colvalue->cursor != colvalue->len) {
|
||||
ereport(ERROR, (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
|
||||
errmsg("incorrect binary data format in logical replication column %d",
|
||||
remoteattnum + 1)));
|
||||
}
|
||||
slot->tts_isnull[i] = false;
|
||||
} else {
|
||||
/*
|
||||
* NULL value from remote. (We don't expect to see
|
||||
* LOGICALREP_COLUMN_UNCHANGED here, but if we do, treat it as
|
||||
* NULL.)
|
||||
*/
|
||||
slot->tts_values[i] = (Datum) 0;
|
||||
slot->tts_isnull[i] = true;
|
||||
}
|
||||
/* Reset attnum for error callback */
|
||||
getTypeInputInfo(att->atttypid, &typinput, &typioparam);
|
||||
slot->tts_values[i] = OidInputFunctionCall(typinput, values[remoteattnum], typioparam, att->atttypmod);
|
||||
slot->tts_isnull[i] = false;
|
||||
errarg.remote_attnum = -1;
|
||||
} else {
|
||||
/*
|
||||
|
|
@ -342,19 +318,18 @@ static void slot_store_data(TupleTableSlot *slot, LogicalRepRelMapEntry *rel, Lo
|
|||
}
|
||||
|
||||
/*
|
||||
* Replace updated columns with data from the LogicalRepTupleData struct.
|
||||
* Replace selected columns with user data provided as C strings.
|
||||
* This is somewhat similar to heap_modify_tuple but also calls the type
|
||||
* input functions on the user data.
|
||||
*
|
||||
* "slot" is filled with a copy of the tuple in "srcslot", replacing
|
||||
* columns provided in "tupleData" and leaving others as-is.
|
||||
*
|
||||
* "slot" is filled with a copy of the tuple in "srcslot", with
|
||||
* columns selected by the "replaces" array replaced with data values
|
||||
* from "values".
|
||||
* Caution: unreplaced pass-by-ref columns in "slot" will point into the
|
||||
* storage for "srcslot". This is OK for current usage, but someday we may
|
||||
* need to materialize "slot" at the end to make it independent of "srcslot".
|
||||
*/
|
||||
static void slot_modify_data(TupleTableSlot *slot, TupleTableSlot *srcslot, LogicalRepRelMapEntry *rel,
|
||||
LogicalRepTupleData *tupleData)
|
||||
static void slot_modify_cstrings(TupleTableSlot *slot, TupleTableSlot *srcslot, LogicalRepRelMapEntry *rel,
|
||||
char **values, const bool *replaces)
|
||||
{
|
||||
int natts = slot->tts_tupleDescriptor->natts;
|
||||
int i;
|
||||
|
|
@ -389,47 +364,23 @@ static void slot_modify_data(TupleTableSlot *slot, TupleTableSlot *srcslot, Logi
|
|||
Form_pg_attribute att = slot->tts_tupleDescriptor->attrs[i];
|
||||
int remoteattnum = rel->attrmap[i];
|
||||
|
||||
if (remoteattnum < 0) {
|
||||
if (remoteattnum < 0 || !replaces[remoteattnum]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (tupleData->colstatus[remoteattnum] != LOGICALREP_COLUMN_UNCHANGED) {
|
||||
StringInfo colvalue = &tupleData->colvalues[remoteattnum];
|
||||
if (values[remoteattnum] != NULL) {
|
||||
Oid typinput;
|
||||
Oid typioparam;
|
||||
|
||||
errarg.remote_attnum = remoteattnum;
|
||||
|
||||
if (tupleData->colstatus[remoteattnum] == LOGICALREP_COLUMN_TEXT) {
|
||||
Oid typinput;
|
||||
Oid typioparam;
|
||||
|
||||
getTypeInputInfo(att->atttypid, &typinput, &typioparam);
|
||||
slot->tts_values[i] = OidInputFunctionCall(typinput, colvalue->data, typioparam, att->atttypmod);
|
||||
slot->tts_isnull[i] = false;
|
||||
} else if (tupleData->colstatus[remoteattnum] == LOGICALREP_COLUMN_BINARY) {
|
||||
Oid typreceive;
|
||||
Oid typioparam;
|
||||
|
||||
/*
|
||||
* In some code paths we may be asked to re-parse the same
|
||||
* tuple data. Reset the StringInfo's cursor so that works.
|
||||
*/
|
||||
colvalue->cursor = 0;
|
||||
|
||||
getTypeBinaryInputInfo(att->atttypid, &typreceive, &typioparam);
|
||||
slot->tts_values[i] = OidReceiveFunctionCall(typreceive, colvalue, typioparam, att->atttypmod);
|
||||
|
||||
/* Trouble if it didn't eat the whole buffer */
|
||||
if (colvalue->cursor != colvalue->len) {
|
||||
ereport(ERROR, (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
|
||||
errmsg("incorrect binary data format in logical replication column %d", remoteattnum + 1)));
|
||||
}
|
||||
slot->tts_isnull[i] = false;
|
||||
} else {
|
||||
/* must be LOGICALREP_COLUMN_NULL */
|
||||
slot->tts_values[i] = (Datum) 0;
|
||||
slot->tts_isnull[i] = true;
|
||||
}
|
||||
|
||||
getTypeInputInfo(att->atttypid, &typinput, &typioparam);
|
||||
slot->tts_values[i] = OidInputFunctionCall(typinput, values[remoteattnum], typioparam, att->atttypmod);
|
||||
slot->tts_isnull[i] = false;
|
||||
errarg.remote_attnum = -1;
|
||||
} else {
|
||||
slot->tts_values[i] = (Datum)0;
|
||||
slot->tts_isnull[i] = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -565,7 +516,7 @@ static void apply_handle_insert(StringInfo s)
|
|||
PushActiveSnapshot(GetTransactionSnapshot());
|
||||
/* Process and store remote tuple in the slot */
|
||||
oldctx = MemoryContextSwitchTo(GetPerTupleMemoryContext(estate));
|
||||
slot_store_data(remoteslot, rel, &newtup);
|
||||
slot_store_cstrings(remoteslot, rel, newtup.values);
|
||||
slot_fill_defaults(rel, estate, remoteslot);
|
||||
MemoryContextSwitchTo(oldctx);
|
||||
|
||||
|
|
@ -695,7 +646,7 @@ static void apply_handle_update(StringInfo s)
|
|||
int remoteattnum = rel->attrmap[i];
|
||||
if (!att->attisdropped && remoteattnum >= 0) {
|
||||
Assert(remoteattnum < newtup.ncols);
|
||||
if (newtup.colstatus[i] != LOGICALREP_COLUMN_UNCHANGED) {
|
||||
if (newtup.changed[i]) {
|
||||
target_rte->updatedCols = bms_add_member(target_rte->updatedCols,
|
||||
i + 1 - FirstLowInvalidHeapAttributeNumber);
|
||||
}
|
||||
|
|
@ -709,7 +660,7 @@ static void apply_handle_update(StringInfo s)
|
|||
|
||||
/* Build the search tuple. */
|
||||
oldctx = MemoryContextSwitchTo(GetPerTupleMemoryContext(estate));
|
||||
slot_store_data(remoteslot, rel, has_oldtup ? &oldtup : &newtup);
|
||||
slot_store_cstrings(remoteslot, rel, has_oldtup ? oldtup.values : newtup.values);
|
||||
MemoryContextSwitchTo(oldctx);
|
||||
|
||||
/*
|
||||
|
|
@ -732,7 +683,7 @@ static void apply_handle_update(StringInfo s)
|
|||
if (found) {
|
||||
/* Process and store remote tuple in the slot */
|
||||
oldctx = MemoryContextSwitchTo(GetPerTupleMemoryContext(estate));
|
||||
slot_modify_data(remoteslot, localslot, rel, &newtup);
|
||||
slot_modify_cstrings(remoteslot, localslot, rel, newtup.values, newtup.changed);
|
||||
MemoryContextSwitchTo(oldctx);
|
||||
|
||||
EvalPlanQualSetSlot(&epqstate, remoteslot);
|
||||
|
|
@ -797,7 +748,7 @@ static void apply_handle_delete(StringInfo s)
|
|||
|
||||
/* Find the tuple using the replica identity index. */
|
||||
oldctx = MemoryContextSwitchTo(GetPerTupleMemoryContext(estate));
|
||||
slot_store_data(remoteslot, rel, &oldtup);
|
||||
slot_store_cstrings(remoteslot, rel, oldtup.values);
|
||||
MemoryContextSwitchTo(oldctx);
|
||||
|
||||
/*
|
||||
|
|
@ -873,9 +824,6 @@ static void apply_dispatch(StringInfo s)
|
|||
case 'O':
|
||||
apply_handle_origin(s);
|
||||
break;
|
||||
case 'S':
|
||||
apply_handle_conninfo(s);
|
||||
break;
|
||||
default:
|
||||
ereport(ERROR, (errcode(ERRCODE_PROTOCOL_VIOLATION),
|
||||
errmsg("invalid logical replication message type \"%c\"", action)));
|
||||
|
|
@ -1056,15 +1004,13 @@ static void ApplyLoop(void)
|
|||
/* mark as idle, before starting to loop */
|
||||
pgstat_report_activity(STATE_IDLE, NULL);
|
||||
|
||||
for (;;) {
|
||||
while (!t_thrd.applyworker_cxt.got_SIGTERM) {
|
||||
MemoryContextSwitchTo(t_thrd.applyworker_cxt.messageContext);
|
||||
|
||||
int len;
|
||||
char *buf = NULL;
|
||||
unsigned char type;
|
||||
|
||||
CHECK_FOR_INTERRUPTS();
|
||||
|
||||
/* Wait a while for data to arrive */
|
||||
if ((WalReceiverFuncTable[GET_FUNC_IDX]).walrcv_receive(NAPTIME_PER_CYCLE, &type, &buf, &len)) {
|
||||
StringInfoData s;
|
||||
|
|
@ -1278,17 +1224,6 @@ static void reread_subscription(void)
|
|||
proc_exit(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Exit if any parameter that affects the remote connection was changed.
|
||||
* The launcher will start a new worker.
|
||||
*/
|
||||
if (strcmp(newsub->name, t_thrd.applyworker_cxt.mySubscription->name) != 0 ||
|
||||
newsub->binary != t_thrd.applyworker_cxt.mySubscription->binary) {
|
||||
ereport(LOG, (errmsg("logical replication apply worker for subscription \"%s\" "
|
||||
"will restart because of a parameter change", t_thrd.applyworker_cxt.mySubscription->name)));
|
||||
proc_exit(0);
|
||||
}
|
||||
|
||||
/* !slotname should never happen when enabled is true. */
|
||||
Assert(newsub->slotname);
|
||||
|
||||
|
|
@ -1361,7 +1296,7 @@ void ApplyWorkerMain()
|
|||
*/
|
||||
gspqsignal(SIGHUP, LogicalrepWorkerSighub);
|
||||
gspqsignal(SIGINT, StatementCancelHandler);
|
||||
gspqsignal(SIGTERM, die);
|
||||
gspqsignal(SIGTERM, LogicalrepWorkerSigterm);
|
||||
|
||||
gspqsignal(SIGQUIT, quickdie);
|
||||
gspqsignal(SIGALRM, handle_sig_alarm);
|
||||
|
|
@ -1487,9 +1422,14 @@ void ApplyWorkerMain()
|
|||
|
||||
CommitTransactionCommand();
|
||||
|
||||
if (!AttemptConnectPublisher(t_thrd.applyworker_cxt.mySubscription->conninfo,
|
||||
t_thrd.applyworker_cxt.mySubscription->name, true)) {
|
||||
ereport(ERROR, (errcode(ERRCODE_CONNECTION_FAILURE), errmsg("Failed to connect to publisher.")));
|
||||
char *decryptConnInfo = DecryptConninfo(t_thrd.applyworker_cxt.mySubscription->conninfo);
|
||||
bool connectSuccess = (WalReceiverFuncTable[GET_FUNC_IDX]).walrcv_connect(decryptConnInfo, NULL,
|
||||
t_thrd.applyworker_cxt.mySubscription->name, -1);
|
||||
rc = memset_s(decryptConnInfo, strlen(decryptConnInfo), 0, strlen(decryptConnInfo));
|
||||
securec_check(rc, "", "");
|
||||
pfree_ext(decryptConnInfo);
|
||||
if (!connectSuccess) {
|
||||
ereport(ERROR, (errcode(ERRCODE_CONNECTION_FAILURE), errmsg("could not connect to the publisher")));
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -1507,7 +1447,6 @@ void ApplyWorkerMain()
|
|||
options.slotname = t_thrd.applyworker_cxt.mySubscription->slotname;
|
||||
options.protoVersion = LOGICALREP_PROTO_VERSION_NUM;
|
||||
options.publicationNames = t_thrd.applyworker_cxt.mySubscription->publications;
|
||||
options.binary = t_thrd.applyworker_cxt.mySubscription->binary;
|
||||
|
||||
/* Start streaming from the slot. */
|
||||
(WalReceiverFuncTable[GET_FUNC_IDX]).walrcv_startstreaming(&options);
|
||||
|
|
@ -1656,72 +1595,3 @@ char* DefListToString(const List *defList)
|
|||
return buf.data;
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle conninfo update message.
|
||||
*/
|
||||
static void apply_handle_conninfo(StringInfo s)
|
||||
{
|
||||
char* standbysInfo = NULL;
|
||||
logicalrep_read_conninfo(s, &standbysInfo);
|
||||
UpdateConninfo(standbysInfo);
|
||||
pfree_ext(standbysInfo);
|
||||
}
|
||||
|
||||
static void UpdateConninfo(char* standbysInfo)
|
||||
{
|
||||
Relation rel;
|
||||
bool nulls[Natts_pg_subscription];
|
||||
bool replaces[Natts_pg_subscription];
|
||||
Datum values[Natts_pg_subscription];
|
||||
HeapTuple tup;
|
||||
Subscription* sub = t_thrd.applyworker_cxt.mySubscription;
|
||||
Oid subid = sub->oid;
|
||||
|
||||
StartTransactionCommand();
|
||||
rel = heap_open(SubscriptionRelationId, RowExclusiveLock);
|
||||
/* Fetch the existing tuple. */
|
||||
tup = SearchSysCacheCopy2(SUBSCRIPTIONNAME, u_sess->proc_cxt.MyDatabaseId,
|
||||
CStringGetDatum(t_thrd.applyworker_cxt.mySubscription->name));
|
||||
if (!HeapTupleIsValid(tup)) {
|
||||
ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("subscription \"%s\" does not exist",
|
||||
t_thrd.applyworker_cxt.mySubscription->name)));
|
||||
}
|
||||
subid = HeapTupleGetOid(tup);
|
||||
|
||||
/* Form a new tuple. */
|
||||
int rc = memset_s(nulls, sizeof(nulls), false, sizeof(nulls));
|
||||
securec_check(rc, "", "");
|
||||
rc = memset_s(values, sizeof(values), 0, sizeof(values));
|
||||
securec_check(rc, "", "");
|
||||
rc = memset_s(replaces, sizeof(replaces), false, sizeof(replaces));
|
||||
securec_check(rc, "", "");
|
||||
|
||||
/* get conninfoWithoutHostport */
|
||||
StringInfoData conninfoWithoutHostport;
|
||||
initStringInfo(&conninfoWithoutHostport);
|
||||
ParseConninfo(sub->conninfo, &conninfoWithoutHostport, (HostPort**)NULL);
|
||||
|
||||
/* join conninfoWithoutHostport together with standbysinfo */
|
||||
appendStringInfo(&conninfoWithoutHostport, " %s", standbysInfo);
|
||||
/* Replace connection information */
|
||||
values[Anum_pg_subscription_subconninfo - 1] = CStringGetTextDatum(conninfoWithoutHostport.data);
|
||||
replaces[Anum_pg_subscription_subconninfo - 1] = true;
|
||||
tup = heap_modify_tuple(tup, RelationGetDescr(rel), values, nulls, replaces);
|
||||
|
||||
/* Update the catalog. */
|
||||
simple_heap_update(rel, &tup->t_self, tup);
|
||||
CatalogUpdateIndexes(rel, tup);
|
||||
|
||||
heap_close(rel, RowExclusiveLock);
|
||||
CommitTransactionCommand();
|
||||
|
||||
ereport(LOG, (errmsg("Update conninfo successfully, new conninfo %s.", standbysInfo)));
|
||||
}
|
||||
|
||||
/*
|
||||
* Is current process a logical replication worker?
|
||||
*/
|
||||
bool IsLogicalWorker(void)
|
||||
{
|
||||
return t_thrd.applyworker_cxt.curWorker != NULL;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,8 +15,6 @@
|
|||
|
||||
#include "catalog/pg_publication.h"
|
||||
|
||||
#include "commands/defrem.h"
|
||||
|
||||
#include "replication/logical.h"
|
||||
#include "replication/logicalproto.h"
|
||||
#include "replication/origin.h"
|
||||
|
|
@ -46,8 +44,6 @@ static bool pgoutput_origin_filter(LogicalDecodingContext *ctx, RepOriginId orig
|
|||
|
||||
static List *LoadPublications(List *pubnames);
|
||||
static void publication_invalidation_cb(Datum arg, int cacheid, uint32 hashvalue);
|
||||
static bool ReplconninfoChanged();
|
||||
static void GetConninfo(StringInfoData* standbysInfo);
|
||||
|
||||
/* Entry in the map used to remember which relation schemas we sent. */
|
||||
typedef struct RelationSyncEntry {
|
||||
|
|
@ -83,9 +79,6 @@ static void parse_output_parameters(List *options, PGOutputData *data)
|
|||
ListCell *lc;
|
||||
bool protocol_version_given = false;
|
||||
bool publication_names_given = false;
|
||||
bool binary_option_given = false;
|
||||
|
||||
data->binary = false;
|
||||
|
||||
foreach (lc, options) {
|
||||
DefElem *defel = (DefElem *)lfirst(lc);
|
||||
|
|
@ -115,12 +108,6 @@ static void parse_output_parameters(List *options, PGOutputData *data)
|
|||
|
||||
if (!SplitIdentifierString(strVal(defel->arg), ',', &(data->publication_names)))
|
||||
ereport(ERROR, (errcode(ERRCODE_INVALID_NAME), errmsg("invalid publication_names syntax")));
|
||||
} else if (strcmp(defel->defname, "binary") == 0) {
|
||||
if (binary_option_given)
|
||||
ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("conflicting or redundant options")));
|
||||
binary_option_given = true;
|
||||
|
||||
data->binary = defGetBoolean(defel);
|
||||
} else
|
||||
elog(ERROR, "unrecognized pgoutput option: %s", defel->defname);
|
||||
}
|
||||
|
|
@ -219,22 +206,6 @@ static void pgoutput_commit_txn(LogicalDecodingContext *ctx, ReorderBufferTXN *t
|
|||
OutputPluginPrepareWrite(ctx, true);
|
||||
logicalrep_write_commit(ctx->out, txn, commit_lsn);
|
||||
OutputPluginWrite(ctx, true);
|
||||
|
||||
/*
|
||||
* Send the newest connecttion information to the subscriber,
|
||||
* when the connection information about the standby changes.
|
||||
*/
|
||||
if (ReplconninfoChanged()) {
|
||||
StringInfoData standbysInfo;
|
||||
initStringInfo(&standbysInfo);
|
||||
|
||||
GetConninfo(&standbysInfo);
|
||||
OutputPluginPrepareWrite(ctx, true);
|
||||
logicalrep_write_conninfo(ctx->out, standbysInfo.data);
|
||||
OutputPluginWrite(ctx, true);
|
||||
|
||||
FreeStringInfo(&standbysInfo);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -329,19 +300,19 @@ static void pgoutput_change(LogicalDecodingContext *ctx, ReorderBufferTXN *txn,
|
|||
switch (change->action) {
|
||||
case REORDER_BUFFER_CHANGE_INSERT:
|
||||
OutputPluginPrepareWrite(ctx, true);
|
||||
logicalrep_write_insert(ctx->out, relation, &change->data.tp.newtuple->tuple, data->binary);
|
||||
logicalrep_write_insert(ctx->out, relation, &change->data.tp.newtuple->tuple);
|
||||
OutputPluginWrite(ctx, true);
|
||||
break;
|
||||
case REORDER_BUFFER_CHANGE_UINSERT:
|
||||
OutputPluginPrepareWrite(ctx, true);
|
||||
logicalrep_write_insert(ctx->out, relation, (HeapTuple)(&change->data.utp.newtuple->tuple), data->binary);
|
||||
logicalrep_write_insert(ctx->out, relation, (HeapTuple)(&change->data.utp.newtuple->tuple));
|
||||
OutputPluginWrite(ctx, true);
|
||||
break;
|
||||
case REORDER_BUFFER_CHANGE_UPDATE: {
|
||||
HeapTuple oldtuple = change->data.tp.oldtuple ? &change->data.tp.oldtuple->tuple : NULL;
|
||||
|
||||
OutputPluginPrepareWrite(ctx, true);
|
||||
logicalrep_write_update(ctx->out, relation, oldtuple, &change->data.tp.newtuple->tuple, data->binary);
|
||||
logicalrep_write_update(ctx->out, relation, oldtuple, &change->data.tp.newtuple->tuple);
|
||||
OutputPluginWrite(ctx, true);
|
||||
break;
|
||||
}
|
||||
|
|
@ -349,14 +320,14 @@ static void pgoutput_change(LogicalDecodingContext *ctx, ReorderBufferTXN *txn,
|
|||
HeapTuple oldtuple = change->data.utp.oldtuple ? ((HeapTuple)(&change->data.utp.oldtuple->tuple)) : NULL;
|
||||
|
||||
OutputPluginPrepareWrite(ctx, true);
|
||||
logicalrep_write_update(ctx->out, relation, oldtuple, (HeapTuple)(&change->data.utp.newtuple->tuple), data->binary);
|
||||
logicalrep_write_update(ctx->out, relation, oldtuple, (HeapTuple)(&change->data.utp.newtuple->tuple));
|
||||
OutputPluginWrite(ctx, true);
|
||||
break;
|
||||
}
|
||||
case REORDER_BUFFER_CHANGE_DELETE:
|
||||
if (change->data.tp.oldtuple) {
|
||||
OutputPluginPrepareWrite(ctx, true);
|
||||
logicalrep_write_delete(ctx->out, relation, &change->data.tp.oldtuple->tuple, data->binary);
|
||||
logicalrep_write_delete(ctx->out, relation, &change->data.tp.oldtuple->tuple);
|
||||
OutputPluginWrite(ctx, true);
|
||||
} else
|
||||
elog(DEBUG1, "didn't send DELETE change because of missing oldtuple");
|
||||
|
|
@ -364,7 +335,7 @@ static void pgoutput_change(LogicalDecodingContext *ctx, ReorderBufferTXN *txn,
|
|||
case REORDER_BUFFER_CHANGE_UDELETE:
|
||||
if (change->data.utp.oldtuple) {
|
||||
OutputPluginPrepareWrite(ctx, true);
|
||||
logicalrep_write_delete(ctx->out, relation, (HeapTuple)(&change->data.utp.oldtuple->tuple), data->binary);
|
||||
logicalrep_write_delete(ctx->out, relation, (HeapTuple)(&change->data.utp.oldtuple->tuple));
|
||||
OutputPluginWrite(ctx, true);
|
||||
} else
|
||||
elog(DEBUG1, "didn't send DELETE change because of missing oldtuple");
|
||||
|
|
@ -634,43 +605,3 @@ static void rel_sync_cache_publication_cb(Datum arg, int cacheid, uint32 hashval
|
|||
entry->pubactions.pubdelete = false;
|
||||
}
|
||||
}
|
||||
|
||||
static void GetConninfo(StringInfoData* standbysInfo)
|
||||
{
|
||||
bool primaryJoined = false;
|
||||
StringInfoData hosts;
|
||||
StringInfoData ports;
|
||||
initStringInfo(&hosts);
|
||||
initStringInfo(&ports);
|
||||
for (int i = 1; i < MAX_REPLNODE_NUM + 1; ++i) {
|
||||
t_thrd.postmaster_cxt.ReplConnChangeType[i] = 0;
|
||||
if (t_thrd.postmaster_cxt.ReplConnArray[i] == NULL) {
|
||||
continue;
|
||||
}
|
||||
if (!primaryJoined) {
|
||||
appendStringInfo(&hosts, "%s,%s",
|
||||
t_thrd.postmaster_cxt.ReplConnArray[i]->localhost,
|
||||
t_thrd.postmaster_cxt.ReplConnArray[i]->remotehost);
|
||||
appendStringInfo(&ports, "%d,%d",
|
||||
t_thrd.postmaster_cxt.ReplConnArray[i]->localport,
|
||||
t_thrd.postmaster_cxt.ReplConnArray[i]->remoteport);
|
||||
primaryJoined = true;
|
||||
} else {
|
||||
appendStringInfo(&hosts, ",%s",
|
||||
t_thrd.postmaster_cxt.ReplConnArray[i]->remotehost);
|
||||
appendStringInfo(&ports, ",%d",
|
||||
t_thrd.postmaster_cxt.ReplConnArray[i]->remoteport);
|
||||
}
|
||||
}
|
||||
appendStringInfo(standbysInfo, "host=%s port=%s", hosts.data, ports.data);
|
||||
}
|
||||
|
||||
static inline bool ReplconninfoChanged()
|
||||
{
|
||||
for (int i = 1; i < MAX_REPLNODE_NUM; ++i) {
|
||||
if (t_thrd.postmaster_cxt.ReplConnChangeType[i]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1934,18 +1934,14 @@ ArchiveConfig* formArchiveConfigFromStr(char *content, bool encrypted)
|
|||
ArchiveConnConfig* conn_config = NULL;
|
||||
char* media_type = NULL;
|
||||
errno_t rc = EOK;
|
||||
char *content_copy = NULL;
|
||||
/* SplitIdentifierString will change origin string */
|
||||
char *content_copy = pstrdup(content);
|
||||
char *tmp = NULL;
|
||||
List* elemlist = NIL;
|
||||
int param_num = 0;
|
||||
size_t elem_index = 0;
|
||||
archive_config = (ArchiveConfig *)palloc0(sizeof(ArchiveConfig));
|
||||
char decryptSecretAccessKeyStr[DEST_CIPHER_LENGTH] = {'\0'};
|
||||
if (content == NULL || strlen(content) == 0) {
|
||||
goto FAILURE;
|
||||
}
|
||||
/* SplitIdentifierString will change origin string */
|
||||
content_copy = pstrdup(content);
|
||||
/* Parse string into list of identifiers */
|
||||
if (!SplitIdentifierString(content_copy, ';', &elemlist, false, false)) {
|
||||
goto FAILURE;
|
||||
|
|
|
|||
|
|
@ -401,7 +401,6 @@ int WalSenderMain(void)
|
|||
t_thrd.walsender_cxt.server_run_mode = t_thrd.postmaster_cxt.HaShmData->current_mode;
|
||||
|
||||
SetHaWalSenderChannel();
|
||||
Assert(t_thrd.utils_cxt.CurrentResourceOwner != NULL);
|
||||
/* Handle handshake messages before streaming */
|
||||
WalSndHandshake();
|
||||
|
||||
|
|
@ -497,7 +496,6 @@ static void WalSndHandshake(void)
|
|||
|
||||
while (!repCxt.replicationStarted) {
|
||||
int firstchar;
|
||||
Assert(t_thrd.utils_cxt.CurrentResourceOwner != NULL);
|
||||
|
||||
WalSndSetState(WALSNDSTATE_STARTUP);
|
||||
set_ps_display("idle", false);
|
||||
|
|
@ -2035,8 +2033,6 @@ bool isLogicalSlotExist(char* slotName)
|
|||
}
|
||||
|
||||
static void IdentifyCommand(Node* cmd_node, ReplicationCxt* repCxt, const char *cmd_string){
|
||||
ResourceOwner tmpOwner = t_thrd.utils_cxt.CurrentResourceOwner;
|
||||
Assert(tmpOwner != NULL);
|
||||
switch (cmd_node->type) {
|
||||
case T_IdentifySystemCmd:
|
||||
IdentifySystem();
|
||||
|
|
@ -2144,7 +2140,7 @@ static void IdentifyCommand(Node* cmd_node, ReplicationCxt* repCxt, const char *
|
|||
ereport(FATAL,
|
||||
(errcode(ERRCODE_PROTOCOL_VIOLATION), errmsg("invalid standby query string: %s", cmd_string)));
|
||||
}
|
||||
t_thrd.utils_cxt.CurrentResourceOwner = tmpOwner;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -3600,12 +3596,8 @@ static int WalSndLoop(WalSndSendDataCallback send_data)
|
|||
t_thrd.walsender_cxt.last_logical_xlog_advanced_timestamp = GetCurrentTimestamp();
|
||||
t_thrd.walsender_cxt.waiting_for_ping_response = false;
|
||||
|
||||
ResourceOwner tmpOwner = t_thrd.utils_cxt.CurrentResourceOwner;
|
||||
Assert(!IsTransactionOrTransactionBlock() &&
|
||||
strcmp(ResourceOwnerGetName(tmpOwner), "walsender top-level resource owner") == 0);
|
||||
/* Loop forever, unless we get an error */
|
||||
for (;;) {
|
||||
t_thrd.utils_cxt.CurrentResourceOwner = tmpOwner;
|
||||
TimestampTz now;
|
||||
|
||||
/* Clear any already-pending wakeups */
|
||||
|
|
@ -4014,7 +4006,6 @@ static int WalSndLoop(WalSndSendDataCallback send_data)
|
|||
}
|
||||
}
|
||||
|
||||
t_thrd.utils_cxt.CurrentResourceOwner = tmpOwner;
|
||||
WalSndShutdown();
|
||||
return 1; /* keep the compiler quiet */
|
||||
}
|
||||
|
|
|
|||
|
|
@ -145,29 +145,6 @@ then
|
|||
plat_form_str=ubuntu18.04_"$cpu_bit"
|
||||
fi
|
||||
|
||||
##################################################################################
|
||||
# the modification here will also lead to the synchronous modification of the 3rd-party compilation library path
|
||||
# PR link : https://gitee.com/opengauss/openGauss-third_party/pulls/130
|
||||
# redflag platform
|
||||
# the result form like this: asianux_x86_64
|
||||
##################################################################################
|
||||
if [ "$kernel"x = "redflag"x ]
|
||||
then
|
||||
plat_form_str=asianux7.6_"$cpu_bit"
|
||||
fi
|
||||
|
||||
|
||||
##################################################################################
|
||||
# the modification here will also lead to the synchronous modification of the 3rd-party compilation library path
|
||||
# PR link : https://gitee.com/opengauss/openGauss-third_party/pulls/130
|
||||
# asianux platform
|
||||
# the result form like this: asianux_aarch64
|
||||
##################################################################################
|
||||
if [ "$kernel"x = "asianux"x ]
|
||||
then
|
||||
plat_form_str=asianux7.5_"$cpu_bit"
|
||||
fi
|
||||
|
||||
##################################################################################
|
||||
#
|
||||
# other platform
|
||||
|
|
|
|||
|
|
@ -314,5 +314,4 @@ template<bool hasnull>
|
|||
void UHeapFillDiskTuple(TupleDesc tupleDesc, Datum *values, const bool *isnull, UHeapDiskTupleData *diskTuple,
|
||||
uint32 dataSize, bool enableReverseBitmap, bool enableReserve);
|
||||
void CheckTupleValidity(Relation rel, UHeapTuple utuple);
|
||||
Tuple UHeapMaterialize(TupleTableSlot *slot);
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -165,7 +165,7 @@ extern void addNewPartitionTuple(Relation pg_part_desc, Partition new_part_desc,
|
|||
Datum interval, Datum maxValues, Datum transitionPoint, Datum reloptions);
|
||||
|
||||
extern void heap_truncate_one_part(Relation rel , Oid partOid);
|
||||
extern Oid heapTupleGetPartitionId(Relation rel, void *tuple, bool isDDL = false);
|
||||
extern Oid heapTupleGetPartitionId(Relation rel, void *tuple);
|
||||
extern Oid heapTupleGetSubPartitionId(Relation rel, void *tuple);
|
||||
extern void heap_truncate(List *relids);
|
||||
extern void heap_truncate_one_rel(Relation rel);
|
||||
|
|
@ -240,7 +240,7 @@ extern char* make_column_map(TupleDesc tuple_desc);
|
|||
*/
|
||||
extern bool* CheckPartkeyHasTimestampwithzone(Relation partTableRel, bool isForSubPartition = false);
|
||||
|
||||
extern Oid AddNewIntervalPartition(Relation rel, void* insertTuple, bool isDDL = false);
|
||||
extern Oid AddNewIntervalPartition(Relation rel, void* insertTuple);
|
||||
|
||||
extern int GetIndexKeyAttsByTuple(Relation relation, HeapTuple indexTuple);
|
||||
|
||||
|
|
|
|||
|
|
@ -50,15 +50,13 @@ CATALOG(pg_subscription,6126) BKI_SHARED_RELATION BKI_ROWTYPE_OID(6128) BKI_SCHE
|
|||
NameData subslotname; /* Slot name on publisher */
|
||||
text subsynccommit; /* Synchronous commit setting for worker */
|
||||
text subpublications[1]; /* List of publications subscribed to */
|
||||
bool subbinary; /* True if the subscription wants the
|
||||
* publisher to send data in binary */
|
||||
#endif
|
||||
}
|
||||
FormData_pg_subscription;
|
||||
|
||||
typedef FormData_pg_subscription *Form_pg_subscription;
|
||||
|
||||
#define Natts_pg_subscription 9
|
||||
#define Natts_pg_subscription 8
|
||||
#define Anum_pg_subscription_subdbid 1
|
||||
#define Anum_pg_subscription_subname 2
|
||||
#define Anum_pg_subscription_subowner 3
|
||||
|
|
@ -67,7 +65,6 @@ typedef FormData_pg_subscription *Form_pg_subscription;
|
|||
#define Anum_pg_subscription_subslotname 6
|
||||
#define Anum_pg_subscription_subsynccommit 7
|
||||
#define Anum_pg_subscription_subpublications 8
|
||||
#define Anum_pg_subscription_subbinary 9
|
||||
|
||||
|
||||
typedef struct Subscription {
|
||||
|
|
@ -80,7 +77,6 @@ typedef struct Subscription {
|
|||
char *slotname; /* Name of the replication slot */
|
||||
char *synccommit; /* Synchronous commit setting for worker */
|
||||
List *publications; /* List of publication names to subscribe to */
|
||||
bool binary; /* Indicates if the subscription wants data in binary format */
|
||||
} Subscription;
|
||||
|
||||
|
||||
|
|
@ -90,7 +86,6 @@ extern Oid get_subscription_oid(const char *subname, bool missing_ok);
|
|||
extern char *get_subscription_name(Oid subid, bool missing_ok);
|
||||
|
||||
extern int CountDBSubscriptions(Oid dbid);
|
||||
extern void ClearListContent(List *list);
|
||||
|
||||
extern char *DecryptConninfo(char *encryptConninfo);
|
||||
|
||||
#endif /* PG_SUBSCRIPTION_H */
|
||||
|
|
|
|||
|
|
@ -17,11 +17,6 @@
|
|||
|
||||
#include "nodes/parsenodes.h"
|
||||
|
||||
typedef struct HostPort {
|
||||
char* host;
|
||||
char* port;
|
||||
} HostPort;
|
||||
|
||||
extern ObjectAddress CreateSubscription(CreateSubscriptionStmt *stmt, bool isTopLevel);
|
||||
extern ObjectAddress AlterSubscription(AlterSubscriptionStmt *stmt);
|
||||
extern void DropSubscription(DropSubscriptionStmt *stmt, bool isTopLevel);
|
||||
|
|
@ -29,12 +24,6 @@ extern void DropSubscription(DropSubscriptionStmt *stmt, bool isTopLevel);
|
|||
extern ObjectAddress AlterSubscriptionOwner(const char *name, Oid newOwnerId);
|
||||
extern void AlterSubscriptionOwner_oid(Oid subid, Oid newOwnerId);
|
||||
extern void RenameSubscription(List* oldname, const char* newname);
|
||||
extern void AddStandbysInfo(char* standbysInfo);
|
||||
extern void DropStandbysInfo(char* standbysInfo);
|
||||
|
||||
extern void ParseConninfo(const char* conninfo, StringInfoData* conninfoWithoutHostPort, HostPort** hostPortList);
|
||||
extern char* EncryptOrDecryptConninfo(const char* conninfo, const char action);
|
||||
extern bool AttemptConnectPublisher(const char *conninfoOriginal, char* slotname, bool checkRemoteMode);
|
||||
|
||||
#endif /* SUBSCRIPTIONCMDS_H */
|
||||
|
||||
|
|
|
|||
|
|
@ -238,7 +238,7 @@ typedef struct knl_session_attr_sql {
|
|||
#ifndef ENABLE_MULTIPLE_NODES
|
||||
bool enable_custom_parser;
|
||||
#endif
|
||||
bool dolphin;
|
||||
bool b_sql_plugin;
|
||||
} knl_session_attr_sql;
|
||||
|
||||
#endif /* SRC_INCLUDE_KNL_KNL_SESSION_ATTR_SQL */
|
||||
|
|
|
|||
|
|
@ -90,7 +90,6 @@ extern const uint32 SUPPORT_DATA_REPAIR;
|
|||
extern const uint32 SCAN_BATCH_MODE_VERSION_NUM;
|
||||
extern const uint32 RELMAP_4K_VERSION_NUM;
|
||||
extern const uint32 PUBLICATION_VERSION_NUM;
|
||||
extern const uint32 SUBSCRIPTION_BINARY_VERSION_NUM;
|
||||
extern const uint32 ANALYZER_HOOK_VERSION_NUM;
|
||||
extern const uint32 SUPPORT_HASH_XLOG_VERSION_NUM;
|
||||
extern const uint32 PITR_INIT_VERSION_NUM;
|
||||
|
|
|
|||
|
|
@ -35,7 +35,6 @@ typedef struct LibpqrcvConnectParam {
|
|||
bool logical;
|
||||
uint32 protoVersion; /* Logical protocol version */
|
||||
List *publicationNames; /* String list of publications */
|
||||
bool binary; /* Ask publisher to use binary */
|
||||
}LibpqrcvConnectParam;
|
||||
|
||||
extern int32 pg_atoi(char* s, int size, int c);
|
||||
|
|
@ -54,6 +53,5 @@ extern bool libpqrcv_command(const char *cmd, char **err, int *sqlstate);
|
|||
extern void IdentifyRemoteSystem(bool checkRemote);
|
||||
extern void CreateRemoteReplicationSlot(XLogRecPtr startpoint, const char* slotname, bool isLogical);
|
||||
extern void StartRemoteStreaming(const LibpqrcvConnectParam *options);
|
||||
extern ServerMode IdentifyRemoteMode();
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -31,7 +31,6 @@
|
|||
#include "access/extreme_rto/spsc_blocking_queue.h"
|
||||
#include "access/parallel_recovery/redo_item.h"
|
||||
|
||||
#include "nodes/parsenodes_common.h"
|
||||
#include "nodes/replnodes.h"
|
||||
#include "access/ustore/knl_utuple.h"
|
||||
#include "replication/logical_queue.h"
|
||||
|
|
|
|||
|
|
@ -35,21 +35,12 @@
|
|||
* Keep in mind that the columns correspond to the *remote* table.
|
||||
*/
|
||||
typedef struct LogicalRepTupleData {
|
||||
/* Array of StringInfos, one per column; some may be unused */
|
||||
StringInfoData *colvalues;
|
||||
/* Array of markers for null/unchanged/text/binary, one per column */
|
||||
char *colstatus;
|
||||
char *values[MaxTupleAttributeNumber]; /* value in out function format or NULL if values is NULL */
|
||||
bool changed[MaxTupleAttributeNumber]; /* marker for changed/unchanged values */
|
||||
/* Length of above arrays */
|
||||
int ncols;
|
||||
} LogicalRepTupleData;
|
||||
|
||||
/* Possible values for LogicalRepTupleData.colstatus[colnum] */
|
||||
/* These values are also used in the on-the-wire protocol */
|
||||
#define LOGICALREP_COLUMN_NULL 'n'
|
||||
#define LOGICALREP_COLUMN_UNCHANGED 'u'
|
||||
#define LOGICALREP_COLUMN_TEXT 't'
|
||||
#define LOGICALREP_COLUMN_BINARY 'b' /* added in PG14 */
|
||||
|
||||
typedef uint32 LogicalRepRelId;
|
||||
|
||||
/* Relation information */
|
||||
|
|
@ -90,18 +81,16 @@ extern void logicalrep_read_begin(StringInfo in, LogicalRepBeginData *begin_data
|
|||
extern void logicalrep_write_commit(StringInfo out, ReorderBufferTXN *txn, XLogRecPtr commit_lsn);
|
||||
extern void logicalrep_read_commit(StringInfo in, LogicalRepCommitData *commit_data);
|
||||
extern void logicalrep_write_origin(StringInfo out, const char *origin, XLogRecPtr origin_lsn);
|
||||
extern void logicalrep_write_insert(StringInfo out, Relation rel, HeapTuple newtuple, bool binary);
|
||||
extern void logicalrep_write_insert(StringInfo out, Relation rel, HeapTuple newtuple);
|
||||
extern LogicalRepRelId logicalrep_read_insert(StringInfo in, LogicalRepTupleData *newtup);
|
||||
extern void logicalrep_write_update(StringInfo out, Relation rel, HeapTuple oldtuple, HeapTuple newtuple, bool binary);
|
||||
extern void logicalrep_write_update(StringInfo out, Relation rel, HeapTuple oldtuple, HeapTuple newtuple);
|
||||
extern LogicalRepRelId logicalrep_read_update(StringInfo in, bool *has_oldtuple, LogicalRepTupleData *oldtup,
|
||||
LogicalRepTupleData *newtup);
|
||||
extern void logicalrep_write_delete(StringInfo out, Relation rel, HeapTuple oldtuple, bool binary);
|
||||
extern void logicalrep_write_delete(StringInfo out, Relation rel, HeapTuple oldtuple);
|
||||
extern LogicalRepRelId logicalrep_read_delete(StringInfo in, LogicalRepTupleData *oldtup);
|
||||
extern void logicalrep_write_rel(StringInfo out, Relation rel);
|
||||
extern LogicalRepRelation *logicalrep_read_rel(StringInfo in);
|
||||
extern void logicalrep_write_typ(StringInfo out, Oid typoid);
|
||||
extern void logicalrep_read_typ(StringInfo out, LogicalRepTyp *ltyp);
|
||||
extern void logicalrep_write_conninfo(StringInfo out, char* conninfo);
|
||||
extern void logicalrep_read_conninfo(StringInfo in, char** conninfo);
|
||||
|
||||
#endif /* LOGICALREP_PROTO_H */
|
||||
|
|
|
|||
|
|
@ -13,6 +13,5 @@
|
|||
#define LOGICALWORKER_H
|
||||
|
||||
extern void ApplyWorkerMain();
|
||||
extern bool IsLogicalWorker(void);
|
||||
|
||||
#endif /* LOGICALWORKER_H */
|
||||
|
|
|
|||
|
|
@ -24,7 +24,6 @@ typedef struct PGOutputData {
|
|||
|
||||
List *publication_names;
|
||||
List *publications;
|
||||
bool binary;
|
||||
} PGOutputData;
|
||||
|
||||
#endif /* PGOUTPUT_H */
|
||||
|
|
|
|||
|
|
@ -229,15 +229,10 @@ private:
|
|||
bool m_syscache_relids[FirstNormalObjectId];
|
||||
|
||||
};
|
||||
void NotifyGscRecoveryStarted();
|
||||
void NotifyGscRecoveryFinished();
|
||||
extern Datum gs_gsc_dbstat_info(PG_FUNCTION_ARGS);
|
||||
extern Datum gs_gsc_clean(PG_FUNCTION_ARGS);
|
||||
extern Datum gs_gsc_catalog_detail(PG_FUNCTION_ARGS);
|
||||
extern Datum gs_gsc_table_detail(PG_FUNCTION_ARGS);
|
||||
extern int ResizeHashBucket(int origin_nbucket, DynamicHashBucketStrategy strategy);
|
||||
|
||||
/* only primary node check recovery, recovery from upgrade may have misorder cacheids */
|
||||
#define IsPrimaryRecoveryFinished() \
|
||||
(g_instance.global_sysdbcache.recovery_finished || t_thrd.postmaster_cxt.HaShmData->current_mode == STANDBY_MODE)
|
||||
#endif
|
||||
#endif
|
||||
|
|
@ -213,7 +213,7 @@ extern bool check_rel_is_partitioned(Oid relid);
|
|||
extern Oid partid_get_parentid(Oid partid);
|
||||
extern bool is_not_strict_agg(Oid funcOid);
|
||||
extern bool is_pgxc_class_table(Oid tableoid);
|
||||
extern Oid get_valid_relname_relid(const char* relnamespace, const char* relname, bool nsp_missing_ok = false);
|
||||
extern Oid get_valid_relname_relid(const char* relnamespace, const char* relname);
|
||||
extern bool get_func_iswindow(Oid funcid);
|
||||
extern char get_func_prokind(Oid funcid);
|
||||
extern char get_typecategory(Oid typid);
|
||||
|
|
|
|||
|
|
@ -1385,8 +1385,6 @@ typedef struct PlDebugEntry {
|
|||
PLpgSQL_function* func;
|
||||
} PlDebugEntry;
|
||||
|
||||
typedef List* (*RawParserHook)(const char*, List**);
|
||||
|
||||
const int MAXINT8LEN = 25;
|
||||
const int DEFAULT_DEBUG_BUF_SIZE = 1024;
|
||||
const long NANOSECOND_PER_SECOND = 1000000000L; /* 1s */
|
||||
|
|
|
|||
|
|
@ -1,37 +0,0 @@
|
|||
--
|
||||
-- check for over-optimization of whole-row Var referencing an Append plan
|
||||
--
|
||||
create table int4_test(f1 int4);
|
||||
select (select q from (select 1,2,3 where f1>0 union all select 4,5,6 where f1<=0) q) from int4_test;
|
||||
q
|
||||
---
|
||||
(0 rows)
|
||||
|
||||
select (select q from (select 1,2,3 where f1>0 union all select 4,5,6.0 where f1<=0) q) from int4_test;
|
||||
q
|
||||
---
|
||||
(0 rows)
|
||||
|
||||
insert into int4_test(f1) values(' 0 ');
|
||||
insert into int4_test(f1) values('123456 ');
|
||||
select * from int4_test;
|
||||
f1
|
||||
--------
|
||||
0
|
||||
123456
|
||||
(2 rows)
|
||||
|
||||
select (select q from (select 1,2,3 where f1>0 union all select 4,5,6 where f1<=0) q) from int4_test;
|
||||
q
|
||||
---------
|
||||
(4,5,6)
|
||||
(1,2,3)
|
||||
(2 rows)
|
||||
|
||||
select (select q from (select 1,2,3 where f1>0 union all select 4,5,6.0 where f1<=0) q) from int4_test;
|
||||
q
|
||||
-----------
|
||||
(4,5,6.0)
|
||||
(1,2,3)
|
||||
(2 rows)
|
||||
|
||||
|
|
@ -1,116 +0,0 @@
|
|||
create schema deserialize_func1;
|
||||
set current_schema = deserialize_func1;
|
||||
create sequence test_seq;
|
||||
create or replace function test_func() return int
|
||||
as
|
||||
begin
|
||||
return 1;
|
||||
end;
|
||||
/
|
||||
create table t1(key int, id int default nextval('test_seq'));
|
||||
create table t2(key int, id int default test_func());
|
||||
select * from pg_get_tabledef('deserialize_func1.t1');
|
||||
pg_get_tabledef
|
||||
------------------------------------------------------
|
||||
SET search_path = deserialize_func1; +
|
||||
CREATE TABLE t1 ( +
|
||||
key integer, +
|
||||
id integer DEFAULT nextval('test_seq'::regclass)+
|
||||
) +
|
||||
WITH (orientation=row, compression=no);
|
||||
(1 row)
|
||||
|
||||
select * from pg_get_tabledef('deserialize_func1.t2');
|
||||
pg_get_tabledef
|
||||
-----------------------------------------
|
||||
SET search_path = deserialize_func1; +
|
||||
CREATE TABLE t2 ( +
|
||||
key integer, +
|
||||
id integer DEFAULT test_func() +
|
||||
) +
|
||||
WITH (orientation=row, compression=no);
|
||||
(1 row)
|
||||
|
||||
alter schema deserialize_func1 rename to deserialize_func2;
|
||||
select * from pg_get_tabledef('deserialize_func2.t1');
|
||||
pg_get_tabledef
|
||||
------------------------------------------------------------------------
|
||||
SET search_path = deserialize_func2; +
|
||||
CREATE TABLE t1 ( +
|
||||
key integer, +
|
||||
id integer DEFAULT nextval('deserialize_func2.test_seq'::regclass)+
|
||||
) +
|
||||
WITH (orientation=row, compression=no);
|
||||
(1 row)
|
||||
|
||||
select * from pg_get_tabledef('deserialize_func2.t2');
|
||||
pg_get_tabledef
|
||||
------------------------------------------------------
|
||||
SET search_path = deserialize_func2; +
|
||||
CREATE TABLE t2 ( +
|
||||
key integer, +
|
||||
id integer DEFAULT deserialize_func2.test_func()+
|
||||
) +
|
||||
WITH (orientation=row, compression=no);
|
||||
(1 row)
|
||||
|
||||
alter table deserialize_func2.t1 alter column id drop default;
|
||||
alter table deserialize_func2.t1 alter column id set default nextval('deserialize_func2.test_seq');
|
||||
select * from pg_get_tabledef('deserialize_func2.t1');
|
||||
pg_get_tabledef
|
||||
------------------------------------------------------------------------
|
||||
SET search_path = deserialize_func2; +
|
||||
CREATE TABLE t1 ( +
|
||||
key integer, +
|
||||
id integer DEFAULT nextval('deserialize_func2.test_seq'::regclass)+
|
||||
) +
|
||||
WITH (orientation=row, compression=no);
|
||||
(1 row)
|
||||
|
||||
alter table deserialize_func2.t2 alter column id drop default;
|
||||
alter table deserialize_func2.t2 alter column id set default deserialize_func2.test_func();
|
||||
select * from pg_get_tabledef('deserialize_func2.t2');
|
||||
pg_get_tabledef
|
||||
------------------------------------------------------
|
||||
SET search_path = deserialize_func2; +
|
||||
CREATE TABLE t2 ( +
|
||||
key integer, +
|
||||
id integer DEFAULT deserialize_func2.test_func()+
|
||||
) +
|
||||
WITH (orientation=row, compression=no);
|
||||
(1 row)
|
||||
|
||||
set current_schema = deserialize_func2;
|
||||
create type type1 as (a int);
|
||||
create view v1 as select '(1)'::type1;
|
||||
alter type type1 rename to type2;
|
||||
select pg_get_viewdef('v1');
|
||||
pg_get_viewdef
|
||||
-------------------------------
|
||||
SELECT '(1)'::type2 AS type1;
|
||||
(1 row)
|
||||
|
||||
drop view v1 cascade;
|
||||
create table atest12 as select x as a, 10001-x as b from generate_series(1, 10000) x;
|
||||
create function func1(integer, integer) returns boolean as $$begin return $1 < $2; end $$ language plpgsql immutable;
|
||||
create operator <<< (procedure=func1, leftarg=integer, rightarg=integer, restrict=scalarltsel);
|
||||
create view atest12v as select * from atest12 where b <<< 5;
|
||||
select pg_get_viewdef('atest12v');
|
||||
pg_get_viewdef
|
||||
-------------------------------------------------
|
||||
SELECT * FROM atest12 WHERE (atest12.b <<< 5);
|
||||
(1 row)
|
||||
|
||||
drop schema if exists deserialize_func1 cascade;
|
||||
NOTICE: schema "deserialize_func1" does not exist, skipping
|
||||
drop schema if exists deserialize_func2 cascade;
|
||||
NOTICE: drop cascades to 9 other objects
|
||||
DETAIL: drop cascades to sequence test_seq
|
||||
drop cascades to function test_func()
|
||||
drop cascades to table t1
|
||||
drop cascades to table t2
|
||||
drop cascades to type type2
|
||||
drop cascades to table atest12
|
||||
drop cascades to function func1(integer,integer)
|
||||
drop cascades to operator <<<(integer,integer)
|
||||
drop cascades to view atest12v
|
||||
|
|
@ -215,107 +215,3 @@ select * from interval_normal_exchange where logdate > '2020-06-01' order by log
|
|||
(0 rows)
|
||||
|
||||
drop table interval_normal_exchange;
|
||||
drop table table_001;
|
||||
ERROR: table "table_001" does not exist
|
||||
create table table_001(
|
||||
COL_1 smallint,
|
||||
COL_2 char(5),
|
||||
COL_3 int,
|
||||
COL_4 date,
|
||||
COL_5 boolean,
|
||||
COL_6 nchar(5),
|
||||
COL_7 float
|
||||
);
|
||||
drop table partition_table_001;
|
||||
ERROR: table "partition_table_001" does not exist
|
||||
create table partition_table_001(
|
||||
COL_1 smallint,
|
||||
COL_2 char(5),
|
||||
COL_3 int,
|
||||
COL_4 date,
|
||||
COL_5 boolean,
|
||||
COL_6 nchar(5),
|
||||
COL_7 float
|
||||
)
|
||||
PARTITION BY RANGE (COL_4)
|
||||
INTERVAL ('1 month')
|
||||
(
|
||||
PARTITION partition_table_001_p1 VALUES LESS THAN ('2020-03-01'),
|
||||
PARTITION partition_table_001_p2 VALUES LESS THAN ('2020-04-01'),
|
||||
PARTITION partition_table_001_p3 VALUES LESS THAN ('2020-05-01')
|
||||
);
|
||||
insert into partition_table_001 values (1,'aaa',1,'2020-02-23',true,'aaa',1.1);
|
||||
insert into partition_table_001 values (2,'bbb',2,'2020-03-23',false,'bbb',2.2);
|
||||
insert into partition_table_001 values (3,'ccc',3,'2020-04-23',true,'ccc',3.3);
|
||||
insert into partition_table_001 values (4,'ddd',4,'2020-05-23',false,'ddd',4.4);
|
||||
insert into partition_table_001 values (5,'eee',5,'2020-06-23',true,'eee',5.5);
|
||||
insert into partition_table_001 values (6,'fff',6,'2020-07-23',false,'fff',6.6);
|
||||
ALTER TABLE partition_table_001 EXCHANGE PARTITION (sys_p1) WITH TABLE table_001;
|
||||
select * from table_001 order by 1;
|
||||
col_1 | col_2 | col_3 | col_4 | col_5 | col_6 | col_7
|
||||
-------+-------+-------+--------------------------+-------+-------+-------
|
||||
4 | ddd | 4 | Sat May 23 00:00:00 2020 | f | ddd | 4.4
|
||||
(1 row)
|
||||
|
||||
select * from partition_table_001 order by 1;
|
||||
col_1 | col_2 | col_3 | col_4 | col_5 | col_6 | col_7
|
||||
-------+-------+-------+--------------------------+-------+-------+-------
|
||||
1 | aaa | 1 | Sun Feb 23 00:00:00 2020 | t | aaa | 1.1
|
||||
2 | bbb | 2 | Mon Mar 23 00:00:00 2020 | f | bbb | 2.2
|
||||
3 | ccc | 3 | Thu Apr 23 00:00:00 2020 | t | ccc | 3.3
|
||||
5 | eee | 5 | Tue Jun 23 00:00:00 2020 | t | eee | 5.5
|
||||
6 | fff | 6 | Thu Jul 23 00:00:00 2020 | f | fff | 6.6
|
||||
(5 rows)
|
||||
|
||||
select relname, parttype, partstrategy, boundaries from pg_partition
|
||||
where parentid = (select oid from pg_class where relname = 'partition_table_001')
|
||||
order by relname;
|
||||
relname | parttype | partstrategy | boundaries
|
||||
------------------------+----------+--------------+------------------------------
|
||||
partition_table_001 | r | i |
|
||||
partition_table_001_p1 | p | r | {2020-03-01}
|
||||
partition_table_001_p2 | p | r | {2020-04-01}
|
||||
partition_table_001_p3 | p | r | {2020-05-01}
|
||||
sys_p1 | p | i | {"Mon Jun 01 00:00:00 2020"}
|
||||
sys_p2 | p | i | {"Wed Jul 01 00:00:00 2020"}
|
||||
sys_p3 | p | i | {"Sat Aug 01 00:00:00 2020"}
|
||||
(7 rows)
|
||||
|
||||
ALTER TABLE partition_table_001 EXCHANGE PARTITION (sys_p1) WITH TABLE table_001;
|
||||
select * from table_001 order by 1;
|
||||
col_1 | col_2 | col_3 | col_4 | col_5 | col_6 | col_7
|
||||
-------+-------+-------+-------+-------+-------+-------
|
||||
(0 rows)
|
||||
|
||||
select * from partition_table_001 order by 1;
|
||||
col_1 | col_2 | col_3 | col_4 | col_5 | col_6 | col_7
|
||||
-------+-------+-------+--------------------------+-------+-------+-------
|
||||
1 | aaa | 1 | Sun Feb 23 00:00:00 2020 | t | aaa | 1.1
|
||||
2 | bbb | 2 | Mon Mar 23 00:00:00 2020 | f | bbb | 2.2
|
||||
3 | ccc | 3 | Thu Apr 23 00:00:00 2020 | t | ccc | 3.3
|
||||
4 | ddd | 4 | Sat May 23 00:00:00 2020 | f | ddd | 4.4
|
||||
5 | eee | 5 | Tue Jun 23 00:00:00 2020 | t | eee | 5.5
|
||||
6 | fff | 6 | Thu Jul 23 00:00:00 2020 | f | fff | 6.6
|
||||
(6 rows)
|
||||
|
||||
insert into table_001 values (7,'eee',7,'2020-08-23',true,'eee',7.7);
|
||||
ALTER TABLE partition_table_001 EXCHANGE PARTITION (sys_p1) WITH TABLE table_001 with validation verbose;
|
||||
select * from table_001 order by 1;
|
||||
col_1 | col_2 | col_3 | col_4 | col_5 | col_6 | col_7
|
||||
-------+-------+-------+--------------------------+-------+-------+-------
|
||||
4 | ddd | 4 | Sat May 23 00:00:00 2020 | f | ddd | 4.4
|
||||
(1 row)
|
||||
|
||||
select * from partition_table_001 order by 1;
|
||||
col_1 | col_2 | col_3 | col_4 | col_5 | col_6 | col_7
|
||||
-------+-------+-------+--------------------------+-------+-------+-------
|
||||
1 | aaa | 1 | Sun Feb 23 00:00:00 2020 | t | aaa | 1.1
|
||||
2 | bbb | 2 | Mon Mar 23 00:00:00 2020 | f | bbb | 2.2
|
||||
3 | ccc | 3 | Thu Apr 23 00:00:00 2020 | t | ccc | 3.3
|
||||
5 | eee | 5 | Tue Jun 23 00:00:00 2020 | t | eee | 5.5
|
||||
6 | fff | 6 | Thu Jul 23 00:00:00 2020 | f | fff | 6.6
|
||||
7 | eee | 7 | Sun Aug 23 00:00:00 2020 | t | eee | 7.7
|
||||
(6 rows)
|
||||
|
||||
drop table table_001;
|
||||
drop table partition_table_001;
|
||||
|
|
|
|||
|
|
@ -1,55 +0,0 @@
|
|||
CREATE TABLE t11 (
|
||||
sec_code character(6) NOT NULL,
|
||||
issue_type character(3) NOT NULL
|
||||
);
|
||||
CREATE TABLE t22 (
|
||||
company_code character(6) NOT NULL,
|
||||
list_profit_flag character(1) NOT NULL
|
||||
);
|
||||
CREATE TABLE t33 (
|
||||
company_code character(6) NOT NULL,
|
||||
issue_flag character(6) NOT NULL
|
||||
);
|
||||
insert into t11 values(1,'S04');
|
||||
insert into t22 values(1,'Y');
|
||||
insert into t33 values(1,'1');
|
||||
insert into t33 values(2,'2');
|
||||
select
|
||||
T5.issue_type
|
||||
,T6.is_type
|
||||
from
|
||||
(
|
||||
select T1.sec_code
|
||||
,issue_type
|
||||
--,case when list_profit_flag='Y' then '是' else '否' end as list_profit_flag
|
||||
from
|
||||
(
|
||||
select sec_code
|
||||
,case when issue_type in ('S04','S05','S06','S09') then '增发'
|
||||
when issue_type in ('S01','S02') then '首发'
|
||||
else '其他' end as issue_type
|
||||
from t11
|
||||
)T1
|
||||
left join
|
||||
(
|
||||
select list_profit_flag
|
||||
,company_code
|
||||
from t22
|
||||
)T2
|
||||
on T1.sec_code=T2.company_code
|
||||
)T5
|
||||
full join
|
||||
(
|
||||
SELECT CASE
|
||||
WHEN issue_flag = ANY (ARRAY['1'::bpchar, '3'::bpchar, '11'::bpchar]) THEN '首发'::text
|
||||
ELSE '增发'::text
|
||||
END AS is_type from t33
|
||||
)T6
|
||||
on T5.issue_type=T6.is_type
|
||||
;
|
||||
issue_type | is_type
|
||||
------------+---------
|
||||
增发 | 增发
|
||||
| 首发
|
||||
(2 rows)
|
||||
|
||||
|
|
@ -1062,73 +1062,6 @@ select /*+ indexscan(tg_hash i_tg_hash_local_a) */ * from tg_hash where a < 9;
|
|||
(81 rows)
|
||||
|
||||
drop table tg_hash;
|
||||
drop table if exists test_ugi_045;
|
||||
NOTICE: table "test_ugi_045" does not exist, skipping
|
||||
create table test_ugi_045
|
||||
(
|
||||
c_id integer not null,
|
||||
c_date DATE,
|
||||
c_info varchar(20) not null
|
||||
)
|
||||
partition by range(c_date)
|
||||
interval('2 day')
|
||||
(
|
||||
partition p1 values less than ('2021-06-01 00:00:00'),
|
||||
partition p2 values less than ('2021-06-03 00:00:00'),
|
||||
partition p3 values less than ('2021-06-05 00:00:00'),
|
||||
partition p4 values less than ('2021-06-07 00:00:00'),
|
||||
partition p5 values less than ('2021-06-09 00:00:00')
|
||||
);
|
||||
insert into test_ugi_045(c_id, c_date, c_info) values(1, '2021-05-30 00:00:00', '1-1');
|
||||
insert into test_ugi_045(c_id, c_date, c_info) values(2, '2021-05-31 00:00:00', '1-1');
|
||||
insert into test_ugi_045(c_id, c_date, c_info) values(3, '2021-06-01 00:00:00', '1-1');
|
||||
insert into test_ugi_045(c_id, c_date, c_info) values(4, '2021-06-02 00:00:00', '1-2');
|
||||
insert into test_ugi_045(c_id, c_date, c_info) values(5, '2021-06-03 00:00:00', '1-2');
|
||||
insert into test_ugi_045(c_id, c_date, c_info) values(6, '2021-06-04 00:00:00', '1-3');
|
||||
insert into test_ugi_045(c_id, c_date, c_info) values(7, '2021-06-05 00:00:00', '1-3');
|
||||
insert into test_ugi_045(c_id, c_date, c_info) values(8, '2021-06-06 00:00:00', '1-4');
|
||||
insert into test_ugi_045(c_id, c_date, c_info) values(9, '2021-06-07 00:00:00', '1-4');
|
||||
insert into test_ugi_045(c_id, c_date, c_info) values(10, '2021-06-08 00:00:00', '1-5');
|
||||
create index global_index_id_045 on test_ugi_045(c_date) global;
|
||||
create index global_index_info_045 on test_ugi_045(c_info) global;
|
||||
select *from test_ugi_045;
|
||||
c_id | c_date | c_info
|
||||
------+---------------------+--------
|
||||
1 | 2021-05-30 00:00:00 | 1-1
|
||||
2 | 2021-05-31 00:00:00 | 1-1
|
||||
3 | 2021-06-01 00:00:00 | 1-1
|
||||
4 | 2021-06-02 00:00:00 | 1-2
|
||||
5 | 2021-06-03 00:00:00 | 1-2
|
||||
6 | 2021-06-04 00:00:00 | 1-3
|
||||
7 | 2021-06-05 00:00:00 | 1-3
|
||||
8 | 2021-06-06 00:00:00 | 1-4
|
||||
9 | 2021-06-07 00:00:00 | 1-4
|
||||
10 | 2021-06-08 00:00:00 | 1-5
|
||||
(10 rows)
|
||||
|
||||
alter table test_ugi_045 truncate partition p3 update global index;
|
||||
set enable_seqscan = off;
|
||||
set enable_bitmapscan = off;
|
||||
select *from test_ugi_045;
|
||||
c_id | c_date | c_info
|
||||
------+---------------------+--------
|
||||
1 | 2021-05-30 00:00:00 | 1-1
|
||||
2 | 2021-05-31 00:00:00 | 1-1
|
||||
3 | 2021-06-01 00:00:00 | 1-1
|
||||
4 | 2021-06-02 00:00:00 | 1-2
|
||||
7 | 2021-06-05 00:00:00 | 1-3
|
||||
8 | 2021-06-06 00:00:00 | 1-4
|
||||
9 | 2021-06-07 00:00:00 | 1-4
|
||||
10 | 2021-06-08 00:00:00 | 1-5
|
||||
(8 rows)
|
||||
|
||||
select *from test_ugi_045 where c_info = '1-2';
|
||||
c_id | c_date | c_info
|
||||
------+---------------------+--------
|
||||
4 | 2021-06-02 00:00:00 | 1-2
|
||||
(1 row)
|
||||
|
||||
drop table if exists test_ugi_045;
|
||||
-- 清理过程
|
||||
drop view check_truncate_results;
|
||||
drop materialized view pg_partition_before_truncate;
|
||||
|
|
|
|||
|
|
@ -24,7 +24,6 @@ CREATE SUBSCRIPTION testsub CONNECTION 'foo';
|
|||
CREATE SUBSCRIPTION testsub PUBLICATION foo;
|
||||
-- fail - could not connect to the publisher
|
||||
create subscription testsub2 connection 'host=abc' publication pub;
|
||||
create subscription testsub2 connection 'host=abc port=12345' publication pub;
|
||||
set client_min_messages to error;
|
||||
-- fail - syntax error, invalid connection string syntax: missing "="
|
||||
CREATE SUBSCRIPTION testsub CONNECTION 'testconn' PUBLICATION testpub;
|
||||
|
|
@ -33,15 +32,12 @@ CREATE SUBSCRIPTION testsub CONNECTION 'dbname=doesnotexist' PUBLICATION testpub
|
|||
CREATE SUBSCRIPTION testsub CONNECTION 'dbname=doesnotexist' PUBLICATION testpub WITH (ENABLED=false, slot_name='testsub', synchronous_commit=off);
|
||||
-- create SUBSCRIPTION with conninfo in two single quote, used to check mask string bug
|
||||
CREATE SUBSCRIPTION testsub_maskconninfo CONNECTION 'host=''1.2.3.4'' port=''12345'' user=''username'' dbname=''postgres'' password=''password_1234''' PUBLICATION testpub WITH (ENABLED=false, slot_name='testsub', synchronous_commit=off);
|
||||
-- fail - The number of host and port are inconsistent
|
||||
create subscription sub1 connection 'dbname=postgres user=pubusr password=Huawei@123 host=192.168.0.38,192.168.0.38,192.168.0.38 port=14001,14501' publication pub1;
|
||||
-- fail - a maximum of 9 servers are supported
|
||||
create subscription sub1 connection 'dbname=postgres user=pubusr password=Huawei@123 host=192.168.0.38,192.168.0.38,192.168.0.38,192.168.0.38,192.168.0.38,192.168.0.38,192.168.0.38,192.168.0.38,192.168.0.38,192.168.0.38 port=14001,14501' publication pub1;
|
||||
|
||||
-- alter connection
|
||||
ALTER SUBSCRIPTION testsub CONNECTION 'host=''1.2.3.4'' port=''12345'' user=''username'' dbname=''postgres'' password=''password_1234''';
|
||||
ALTER SUBSCRIPTION testsub CONNECTION 'dbname=does_not_exist';
|
||||
reset client_min_messages;
|
||||
select subname, pg_get_userbyid(subowner) as Owner, subenabled, subconninfo, subpublications, subbinary from pg_subscription where subname='testsub';
|
||||
select subname, pg_get_userbyid(subowner) as Owner, subenabled, subconninfo, subpublications from pg_subscription where subname='testsub';
|
||||
--- alter subscription
|
||||
------ set publication
|
||||
ALTER SUBSCRIPTION testsub SET PUBLICATION testpub2, testpub3;
|
||||
|
|
@ -61,9 +57,6 @@ select subname, subenabled, subsynccommit from pg_subscription where subname='t
|
|||
ALTER SUBSCRIPTION testsub SET (slot_name='testsub');
|
||||
-- alter owner
|
||||
ALTER SUBSCRIPTION testsub owner to regress_subscription_user2;
|
||||
-- alter subbinary to true
|
||||
ALTER SUBSCRIPTION testsub SET (binary=true);
|
||||
select subname, subbinary from pg_subscription where subname='testsub';
|
||||
--rename
|
||||
ALTER SUBSCRIPTION testsub rename to testsub_rename;
|
||||
--- inside a transaction block
|
||||
|
|
|
|||
|
|
@ -60,10 +60,8 @@ LINE 1: CREATE SUBSCRIPTION testsub PUBLICATION foo;
|
|||
^
|
||||
-- fail - could not connect to the publisher
|
||||
create subscription testsub2 connection 'host=abc' publication pub;
|
||||
ERROR: The number of host and port are inconsistent.
|
||||
create subscription testsub2 connection 'host=abc port=12345' publication pub;
|
||||
WARNING: apply worker could not connect to the remote server
|
||||
ERROR: Failed to connect to publisher.
|
||||
ERROR: could not connect to the publisher
|
||||
set client_min_messages to error;
|
||||
-- fail - syntax error, invalid connection string syntax: missing "="
|
||||
CREATE SUBSCRIPTION testsub CONNECTION 'testconn' PUBLICATION testpub;
|
||||
|
|
@ -74,20 +72,14 @@ ERROR: unrecognized subscription parameter: create_slot
|
|||
CREATE SUBSCRIPTION testsub CONNECTION 'dbname=doesnotexist' PUBLICATION testpub WITH (ENABLED=false, slot_name='testsub', synchronous_commit=off);
|
||||
-- create SUBSCRIPTION with conninfo in two single quote, used to check mask string bug
|
||||
CREATE SUBSCRIPTION testsub_maskconninfo CONNECTION 'host=''1.2.3.4'' port=''12345'' user=''username'' dbname=''postgres'' password=''password_1234''' PUBLICATION testpub WITH (ENABLED=false, slot_name='testsub', synchronous_commit=off);
|
||||
-- fail - The number of host and port are inconsistent
|
||||
create subscription sub1 connection 'dbname=postgres user=pubusr password=Huawei@123 host=192.168.0.38,192.168.0.38,192.168.0.38 port=14001,14501' publication pub1;
|
||||
ERROR: The number of host and port are inconsistent.
|
||||
-- fail - a maximum of 9 servers are supported
|
||||
create subscription sub1 connection 'dbname=postgres user=pubusr password=Huawei@123 host=192.168.0.38,192.168.0.38,192.168.0.38,192.168.0.38,192.168.0.38,192.168.0.38,192.168.0.38,192.168.0.38,192.168.0.38,192.168.0.38 port=14001,14501' publication pub1;
|
||||
ERROR: Currently, a maximum of 9 servers are supported.
|
||||
-- alter connection
|
||||
ALTER SUBSCRIPTION testsub CONNECTION 'host=''1.2.3.4'' port=''12345'' user=''username'' dbname=''postgres'' password=''password_1234''';
|
||||
ALTER SUBSCRIPTION testsub CONNECTION 'dbname=does_not_exist';
|
||||
reset client_min_messages;
|
||||
select subname, pg_get_userbyid(subowner) as Owner, subenabled, subconninfo, subpublications, subbinary from pg_subscription where subname='testsub';
|
||||
subname | owner | subenabled | subconninfo | subpublications | subbinary
|
||||
---------+---------------------------+------------+------------------------+-----------------+-----------
|
||||
testsub | regress_subscription_user | f | dbname=does_not_exist | {testpub} | f
|
||||
select subname, pg_get_userbyid(subowner) as Owner, subenabled, subconninfo, subpublications from pg_subscription where subname='testsub';
|
||||
subname | owner | subenabled | subconninfo | subpublications
|
||||
---------+---------------------------+------------+------------------------+-----------------
|
||||
testsub | regress_subscription_user | f | dbname=does_not_exist | {testpub}
|
||||
(1 row)
|
||||
|
||||
--- alter subscription
|
||||
|
|
@ -130,14 +122,6 @@ ALTER SUBSCRIPTION testsub SET (slot_name='testsub');
|
|||
ERROR: Currently enabled=false, cannot change slot_name to a non-null value.
|
||||
-- alter owner
|
||||
ALTER SUBSCRIPTION testsub owner to regress_subscription_user2;
|
||||
-- alter subbinary to true
|
||||
ALTER SUBSCRIPTION testsub SET (binary=true);
|
||||
select subname, subbinary from pg_subscription where subname='testsub';
|
||||
subname | subbinary
|
||||
---------+-----------
|
||||
testsub | t
|
||||
(1 row)
|
||||
|
||||
--rename
|
||||
ALTER SUBSCRIPTION testsub rename to testsub_rename;
|
||||
--- inside a transaction block
|
||||
|
|
@ -150,7 +134,8 @@ COMMIT;
|
|||
-- -- active SUBSCRIPTION
|
||||
BEGIN;
|
||||
ALTER SUBSCRIPTION testsub_rename ENABLE;
|
||||
ERROR: invalid connection string syntax, missing host and port
|
||||
WARNING: apply worker could not connect to the remote server
|
||||
ERROR: could not connect to the publisher
|
||||
select subname, subenabled from pg_subscription where subname='testsub_rename';
|
||||
ERROR: current transaction is aborted, commands ignored until end of transaction block, firstChar[Q]
|
||||
ALTER SUBSCRIPTION testsub_rename SET (ENABLED=false);
|
||||
|
|
@ -296,11 +281,10 @@ SELECT object_name,detail_info FROM pg_query_audit('2022-01-13 9:30:00', '2031-1
|
|||
testsub_maskconninfo | ALTER SUBSCRIPTION testsub_maskconninfo SET (conninfo='*************************************************************************************************************************;
|
||||
testsub | ALTER SUBSCRIPTION testsub SET (synchronous_commit=on);
|
||||
testsub | ALTER SUBSCRIPTION testsub owner to regress_subscription_user2;
|
||||
testsub | ALTER SUBSCRIPTION testsub SET (binary=true);
|
||||
testsub | ALTER SUBSCRIPTION testsub rename to testsub_rename;
|
||||
testsub_rename | DROP SUBSCRIPTION IF EXISTS testsub_rename;
|
||||
testsub_maskconninfo | DROP SUBSCRIPTION IF EXISTS testsub_maskconninfo;
|
||||
(15 rows)
|
||||
(14 rows)
|
||||
|
||||
--clear audit log
|
||||
SELECT pg_delete_audit('1012-11-10', '3012-11-11');
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ test: pldeveloper_gs_source
|
|||
test: index_advisor
|
||||
test: pl_debugger_server pl_debugger_client
|
||||
test: update_for_wait_s1 update_for_wait_s2
|
||||
test: plan_hint plan_hint_set plan_hint_no_expand plan_hint_iud null_test_opt deserialize_func
|
||||
test: plan_hint plan_hint_set plan_hint_no_expand plan_hint_iud null_test_opt
|
||||
test: large_sequence int16 gs_dump_sequence
|
||||
test: gs_dump_tableof
|
||||
test: analyze_commands
|
||||
|
|
@ -916,5 +916,3 @@ test: fdw_audit
|
|||
test: gs_global_config_audit
|
||||
test: detail
|
||||
test: gs_dump_encrypt
|
||||
test: composite_datum_record
|
||||
test: join_test_alias
|
||||
|
|
|
|||
|
|
@ -5238,7 +5238,7 @@ static void check_global_variables()
|
|||
}
|
||||
}
|
||||
|
||||
#define BASE_PGXC_LIKE_MACRO_NUM 1402
|
||||
#define BASE_PGXC_LIKE_MACRO_NUM 1401
|
||||
static void check_pgxc_like_macros()
|
||||
{
|
||||
#ifdef BUILD_BY_CMAKE
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue