On Wed, Sep 6, 2017 at 12:11 AM, Fabien COELHO <[email protected]> wrote:
>
>> Sorry, I don't follow that. You meant I should add a newline before
>> pg_realloc()? That is,
>>
>> + initialize_cmds =
>> + (char *) pg_realloc(initialize_cmds,
>> + sizeof(char) * n_cmds +
>> 1);
>
>
> Yes. Or maybe my terminal was doing tricks, because I had the impression
> that both argument where on the same line with many tabs in between, but
> maybe I just misinterpreted the diff file. My apology if it is the case.
>
I understood. It looks ugly in the patch but can be applied properly
by git apply command. Attached latest patch incorporated the comments
I got so far.
Regards,
--
Masahiko Sawada
NIPPON TELEGRAPH AND TELEPHONE CORPORATION
NTT Open Source Software Center
diff --git a/doc/src/sgml/ref/pgbench.sgml b/doc/src/sgml/ref/pgbench.sgml
index f5db8d1..48e3581 100644
--- a/doc/src/sgml/ref/pgbench.sgml
+++ b/doc/src/sgml/ref/pgbench.sgml
@@ -159,6 +159,75 @@ pgbench <optional> <replaceable>options</> </optional> <replaceable>dbname</>
</varlistentry>
<varlistentry>
+ <term><option>-I {<replaceable>custom_init_command</replaceable> [...]}</option></term>
+ <term><option>--custom-initialize={<replaceable>custom_init_command</replaceable> [...]}</option></term>
+ <listitem>
+ <para>
+ Specify custom initialization steps.
+ <replaceable>custom_init_command</replaceable> specifies custom
+ initialization steps for the initialization. The default is
+ <literal>ctgvp</literal>. Each command is invoked in the
+ specified order. The supported commands are:
+
+ <variablelist>
+ <varlistentry>
+ <term><literal>c</literal> (cleanup)</term>
+ <listitem>
+ <para>
+ Destroying existing pgbench tables: <structname>pgbench_accounts</>,
+ <structname>pgbench_branches</>, <structname>pgbench_history</>
+ and <structname>pgbench_tellers</>.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>t</literal> (table creation)</term>
+ <listitem>
+ <para>
+ Create four tables <structname>pgbench_accounts</>,
+ <structname>pgbench_branches</>, <structname>pgbench_history</>
+ and <structname>pgbench_tellers</>.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>g</literal> (generate data)</term>
+ <listitem>
+ <para>
+ Generate data and load it to standard tables.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>v</literal> (vacuum)</term>
+ <listitem>
+ <para>
+ Invoke vacuum on standard tables.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>p</literal> (primary key)</term>
+ <listitem>
+ <para>
+ Create primary keys on standard tables.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>f</literal> (foreign key)</term>
+ <listitem>
+ <para>
+ Create foreign keys constraints between the standard tables.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><option>-F</option> <replaceable>fillfactor</></term>
<term><option>--fillfactor=</option><replaceable>fillfactor</></term>
<listitem>
diff --git a/src/bin/pgbench/pgbench.c b/src/bin/pgbench/pgbench.c
index e37496c..f6b0452 100644
--- a/src/bin/pgbench/pgbench.c
+++ b/src/bin/pgbench/pgbench.c
@@ -95,6 +95,8 @@ static int pthread_join(pthread_t th, void **thread_return);
#define MIN_GAUSSIAN_PARAM 2.0 /* minimum parameter for gauss */
+#define DEFAULT_INIT_COMMANDS "ctgvp"
+
int nxacts = 0; /* number of transactions per client */
int duration = 0; /* duration in seconds */
int64 end_time = 0; /* when to stop in micro seconds, under -T */
@@ -112,9 +114,9 @@ int scale = 1;
int fillfactor = 100;
/*
- * create foreign key constraints on the tables?
+ * no vacuum at all before testing?
*/
-int foreign_keys = 0;
+bool is_no_vacuum = false;
/*
* use unlogged tables?
@@ -458,6 +460,12 @@ static void pgbench_error(const char *fmt,...) pg_attribute_printf(1, 2);
static void addScript(ParsedScript script);
static void *threadRun(void *arg);
static void setalarm(int seconds);
+static void initCleanupTables(PGconn *con);
+static void initCreateTables(PGconn *con);
+static void initLoadData(PGconn *con);
+static void initVacuum(PGconn *con);
+static void initCreatePKeys(PGconn *con);
+static void initCreateFKeys(PGconn *con);
/* callback functions for our flex lexer */
@@ -484,6 +492,8 @@ usage(void)
" create indexes in the specified tablespace\n"
" --tablespace=TABLESPACE create tables in the specified tablespace\n"
" --unlogged-tables create tables as unlogged tables\n"
+ " -I, --custom-initialize=[ctgvpf]+\n"
+ " initialize with custom initialization commands\n"
"\nOptions to select what to run:\n"
" -b, --builtin=NAME[@W] add builtin script NAME weighted at W (default: 1)\n"
" (use \"-b list\" to list available scripts)\n"
@@ -2605,9 +2615,55 @@ disconnect_all(CState *state, int length)
}
}
-/* create tables and setup data */
+/* Check custom initialization commands */
+static void
+checkCustomCommands(char *commands)
+{
+ char *cmd;
+
+ if (commands[0] == '\0')
+ {
+ fprintf(stderr, "initialize command is empty\n");
+ exit(1);
+ }
+
+ for (cmd = commands; *cmd != '\0'; cmd++)
+ {
+ if (strchr("ctgvpf ", *cmd) == NULL)
+ {
+ fprintf(stderr, "invalid custom initialization script command \"%c\"\n", *cmd);
+ fprintf(stderr, "possible commands are: \"c\", \"t\", \"g\", \"v\", \"p\", \"f\"\n");
+ exit(1);
+ }
+ }
+}
+
+/* Remove old tables, if it exists */
+static void
+initCleanupTables(PGconn *con)
+{
+ int i;
+
+ /* tables in reverse foreign key dependencies order */
+ static const char *Tables[] = {
+ "pgbench_history", "pgbench_tellers", "pgbench_accounts", "pgbench_branches"
+ };
+
+ fprintf(stderr, "cleaning up...\n");
+
+ for (i = 0; i < lengthof(Tables); i++)
+ {
+ char buffer[256];
+
+ /* Remove old table, if it exists. */
+ snprintf(buffer, sizeof(buffer), "drop table if exists %s", Tables[i]);
+ executeStatement(con, buffer);
+ }
+}
+
+/* Create tables */
static void
-init(bool is_no_vacuum)
+initCreateTables(PGconn *con)
{
/*
* The scale factor at/beyond which 32-bit integers are insufficient for
@@ -2662,34 +2718,10 @@ init(bool is_no_vacuum)
1
}
};
- static const char *const DDLINDEXes[] = {
- "alter table pgbench_branches add primary key (bid)",
- "alter table pgbench_tellers add primary key (tid)",
- "alter table pgbench_accounts add primary key (aid)"
- };
- static const char *const DDLKEYs[] = {
- "alter table pgbench_tellers add foreign key (bid) references pgbench_branches",
- "alter table pgbench_accounts add foreign key (bid) references pgbench_branches",
- "alter table pgbench_history add foreign key (bid) references pgbench_branches",
- "alter table pgbench_history add foreign key (tid) references pgbench_tellers",
- "alter table pgbench_history add foreign key (aid) references pgbench_accounts"
- };
- PGconn *con;
- PGresult *res;
- char sql[256];
- int i;
- int64 k;
+ int i;
- /* used to track elapsed time and estimate of the remaining time */
- instr_time start,
- diff;
- double elapsed_sec,
- remaining_sec;
- int log_interval = 1;
-
- if ((con = doConnect()) == NULL)
- exit(1);
+ fprintf(stderr, "creating tables...\n");
for (i = 0; i < lengthof(DDLs); i++)
{
@@ -2698,10 +2730,6 @@ init(bool is_no_vacuum)
const struct ddlinfo *ddl = &DDLs[i];
const char *cols;
- /* Remove old table, if it exists. */
- snprintf(buffer, sizeof(buffer), "drop table if exists %s", ddl->table);
- executeStatement(con, buffer);
-
/* Construct new create table statement. */
opts[0] = '\0';
if (ddl->declare_fillfactor)
@@ -2726,9 +2754,31 @@ init(bool is_no_vacuum)
executeStatement(con, buffer);
}
+}
+/* Fill the standard table with some data */
+static void
+initLoadData(PGconn *con)
+{
+ char sql[256];
+ PGresult *res;
+ int i;
+ int64 k;
+
+ /* used to track elapsed time and estimate of the remaining time */
+ instr_time start,
+ diff;
+ double elapsed_sec,
+ remaining_sec;
+ int log_interval = 1;
+
+ /*
+ * fill the pgbench_accounts table with some data
+ */
executeStatement(con, "begin");
+ executeStatement(con, "truncate pgbench_history, pgbench_branches, pgbench_tellers, pgbench_accounts");
+
for (i = 0; i < nbranches * scale; i++)
{
/* "filler" column defaults to NULL */
@@ -2747,16 +2797,6 @@ init(bool is_no_vacuum)
executeStatement(con, sql);
}
- executeStatement(con, "commit");
-
- /*
- * fill the pgbench_accounts table with some data
- */
- fprintf(stderr, "creating tables...\n");
-
- executeStatement(con, "begin");
- executeStatement(con, "truncate pgbench_accounts");
-
res = PQexec(con, "copy pgbench_accounts from stdin");
if (PQresultStatus(res) != PGRES_COPY_IN)
{
@@ -2831,20 +2871,33 @@ init(bool is_no_vacuum)
exit(1);
}
executeStatement(con, "commit");
+}
- /* vacuum */
- if (!is_no_vacuum)
- {
- fprintf(stderr, "vacuum...\n");
- executeStatement(con, "vacuum analyze pgbench_branches");
- executeStatement(con, "vacuum analyze pgbench_tellers");
- executeStatement(con, "vacuum analyze pgbench_accounts");
- executeStatement(con, "vacuum analyze pgbench_history");
- }
+/* Invoke vacuum on all tables */
+static void
+initVacuum(PGconn *con)
+{
+ fprintf(stderr, "vacuum...\n");
+ executeStatement(con, "vacuum analyze pgbench_branches");
+ executeStatement(con, "vacuum analyze pgbench_tellers");
+ executeStatement(con, "vacuum analyze pgbench_accounts");
+ executeStatement(con, "vacuum analyze pgbench_history");
+}
+
+/*
+ * Create primary keys on three tables; pgbench_accounts,
+ * pgbench_branches and pgbench_tellers.
+ */
+static void
+initCreatePKeys(PGconn *con)
+{
+ static const char *const DDLINDEXes[] = {
+ "alter table pgbench_branches add primary key (bid)",
+ "alter table pgbench_tellers add primary key (tid)",
+ "alter table pgbench_accounts add primary key (aid)"
+ };
+ int i;
- /*
- * create indexes
- */
fprintf(stderr, "set primary keys...\n");
for (i = 0; i < lengthof(DDLINDEXes); i++)
{
@@ -2865,16 +2918,71 @@ init(bool is_no_vacuum)
executeStatement(con, buffer);
}
+}
- /*
- * create foreign keys
- */
- if (foreign_keys)
+/*
+ * Create foreign key constraints between the standard tables
+ */
+static void
+initCreateFKeys(PGconn *con)
+{
+ static const char *const DDLKEYs[] = {
+ "alter table pgbench_tellers add constraint pgbench_tellers_bid_fkey foreign key (bid) references pgbench_branches",
+ "alter table pgbench_accounts add constraint pgbench_accounts_bid_fkey foreign key (bid) references pgbench_branches",
+ "alter table pgbench_history add constraint pgbench_history_bid_fkey foreign key (bid) references pgbench_branches",
+ "alter table pgbench_history add constraint pgbench_history_tid_fkey foreign key (tid) references pgbench_tellers",
+ "alter table pgbench_history add constraint pgbench_history_aid_fkey foreign key (aid) references pgbench_accounts"
+ };
+
+ int i;
+
+ fprintf(stderr, "set foreign keys...\n");
+ for (i = 0; i < lengthof(DDLKEYs); i++)
{
- fprintf(stderr, "set foreign keys...\n");
- for (i = 0; i < lengthof(DDLKEYs); i++)
+ executeStatement(con, DDLKEYs[i]);
+ }
+}
+
+/* invoke each initialization commands */
+static void
+init(char *initialize_cmds)
+{
+ char *cmd = initialize_cmds;
+ PGconn *con;
+
+ if ((con = doConnect()) == NULL)
+ exit(1);
+
+ for (cmd = initialize_cmds; *cmd != '\0'; cmd++)
+ {
+ switch (*cmd)
{
- executeStatement(con, DDLKEYs[i]);
+ case 'c':
+ initCleanupTables(con);
+ break;
+ case 't':
+ initCreateTables(con);
+ break;
+ case 'g':
+ initLoadData(con);
+ break;
+ case 'v':
+ initVacuum(con);
+ break;
+ case 'p':
+ initCreatePKeys(con);
+ break;
+ case 'f':
+ initCreateFKeys(con);
+ break;
+ case ' ':
+ break; /* skip */
+ default:
+ {
+ fprintf(stderr, "invalid custom initialization script command \"%c\"\n", *cmd);
+ PQfinish(con);
+ exit(1);
+ }
}
}
@@ -3648,6 +3756,7 @@ main(int argc, char **argv)
{"fillfactor", required_argument, NULL, 'F'},
{"host", required_argument, NULL, 'h'},
{"initialize", no_argument, NULL, 'i'},
+ {"custom-initialize", required_argument, NULL, 'I'},
{"jobs", required_argument, NULL, 'j'},
{"log", no_argument, NULL, 'l'},
{"latency-limit", required_argument, NULL, 'L'},
@@ -3666,7 +3775,6 @@ main(int argc, char **argv)
{"username", required_argument, NULL, 'U'},
{"vacuum-all", no_argument, NULL, 'v'},
/* long-named only options */
- {"foreign-keys", no_argument, &foreign_keys, 1},
{"index-tablespace", required_argument, NULL, 3},
{"tablespace", required_argument, NULL, 2},
{"unlogged-tables", no_argument, &unlogged_tables, 1},
@@ -3674,12 +3782,13 @@ main(int argc, char **argv)
{"aggregate-interval", required_argument, NULL, 5},
{"progress-timestamp", no_argument, NULL, 6},
{"log-prefix", required_argument, NULL, 7},
+ {"foreign-keys", no_argument, NULL, 8},
{NULL, 0, NULL, 0}
};
int c;
int is_init_mode = 0; /* initialize mode? */
- int is_no_vacuum = 0; /* no vacuum at all before testing? */
+ char *initialize_cmds;
int do_vacuum_accounts = 0; /* do vacuum accounts before testing? */
int optindex;
bool scale_given = false;
@@ -3740,7 +3849,9 @@ main(int argc, char **argv)
state = (CState *) pg_malloc(sizeof(CState));
memset(state, 0, sizeof(CState));
- while ((c = getopt_long(argc, argv, "ih:nvp:dqb:SNc:j:Crs:t:T:U:lf:D:F:M:P:R:L:", long_options, &optindex)) != -1)
+ initialize_cmds = pg_strdup(DEFAULT_INIT_COMMANDS);
+
+ while ((c = getopt_long(argc, argv, "iI:h:nvp:dqb:SNc:j:Crs:t:T:U:lf:D:F:M:P:R:L:", long_options, &optindex)) != -1)
{
char *script;
@@ -3749,12 +3860,30 @@ main(int argc, char **argv)
case 'i':
is_init_mode++;
break;
+ case 'I':
+ pg_free(initialize_cmds);
+ initialize_cmds = pg_strdup(optarg);
+
+ /* Check input custom initialization command string */
+ checkCustomCommands(initialize_cmds);
+
+ initialization_option_set = true;
+ break;
case 'h':
pghost = pg_strdup(optarg);
break;
case 'n':
- is_no_vacuum++;
- break;
+ {
+ char *p;
+
+ is_no_vacuum = true;
+
+ /* Get rid of vacuum commands from initialization commands */
+ while ((p = strchr(initialize_cmds, 'v')) != NULL)
+ *p = ' ';
+
+ break;
+ }
case 'v':
do_vacuum_accounts++;
break;
@@ -3977,7 +4106,7 @@ main(int argc, char **argv)
break;
case 0:
/* This covers long options which take no argument. */
- if (foreign_keys || unlogged_tables)
+ if (unlogged_tables)
initialization_option_set = true;
break;
case 2: /* tablespace */
@@ -4015,6 +4144,24 @@ main(int argc, char **argv)
benchmarking_option_set = true;
logfile_prefix = pg_strdup(optarg);
break;
+ case 8:
+ {
+ /*
+ * If a building foreign key command is not specified in
+ * initialization commands, the command is added to the end.
+ */
+ if (strchr(initialize_cmds, 'f') == NULL)
+ {
+ int n_cmds = strlen(initialize_cmds) + 1;
+
+ initialize_cmds = (char *) pg_realloc(initialize_cmds,
+ sizeof(char) * n_cmds + 1);
+ initialize_cmds[n_cmds - 1] = 'f';
+ initialize_cmds[n_cmds] = '\0';
+ }
+ initialization_option_set = true;
+ }
+ break;
default:
fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
exit(1);
@@ -4094,7 +4241,7 @@ main(int argc, char **argv)
exit(1);
}
- init(is_no_vacuum);
+ init(initialize_cmds);
exit(0);
}
else
--
Sent via pgsql-hackers mailing list ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers