diff --git a/doc/src/sgml/ref/pgbench.sgml b/doc/src/sgml/ref/pgbench.sgml index e3a0abb4c7..a6370f00dd 100644 *** a/doc/src/sgml/ref/pgbench.sgml --- b/doc/src/sgml/ref/pgbench.sgml *************** *** 193,204 **** pgbench options d ! g (Generate data) Generate data and load it into the standard tables, replacing any data already present. --- 193,226 ---- ! g or G (Generate data, client-side or server-side) Generate data and load it into the standard tables, replacing any data already present. + + With g (client-side data generation), + data is generated in pgbench client and then + sent to the server. This uses the client/server bandwidth + extensively through a COPY. + Using g causes logging to print one message + each 100,000 rows when generating data into + pgbench_accounts table. + + + With G (server-side data generation), + only limited queries are sent from pgbench + client and then data is actually generated in the server. + No significant bandwidth is required for this variant, but + the server will do more work. + Using G causes logging to print no progress + message when generating data into + pgbench_accounts table. + + + + *************** *** 262,270 **** pgbench options d Switch logging to quiet mode, producing only one progress message per 5 ! seconds. The default logging prints one message each 100000 rows, which often outputs many lines per second (especially on good hardware). --- 284,296 ---- Switch logging to quiet mode, producing only one progress message per 5 ! seconds. The default logging prints one message each 100,000 rows, which often outputs many lines per second (especially on good hardware). + + This setting has no effect if G is specified + in . + diff --git a/src/bin/pgbench/pgbenchindex 03bcd22996..14dbc4510c 100644 *** a/src/bin/pgbench/pgbench.c --- b/src/bin/pgbench/pgbench.c *************** *** 132,137 **** static int pthread_join(pthread_t th, void **thread_return); --- 132,138 ---- * some configurable parameters */ #define DEFAULT_INIT_STEPS "dtgvp" /* default -I setting */ + #define ALL_INIT_STEPS "dtgGvpf" /* all possible steps */ #define LOG_STEP_SECONDS 5 /* seconds between log messages */ #define DEFAULT_NXACTS 10 /* default nxacts */ *************** *** 627,633 **** usage(void) " %s [OPTION]... [DBNAME]\n" "\nInitialization options:\n" " -i, --initialize invokes initialization mode\n" ! " -I, --init-steps=[dtgvpf]+ (default \"dtgvp\")\n" " run selected initialization steps\n" " -F, --fillfactor=NUM set fill factor\n" " -n, --no-vacuum do not run VACUUM during initialization\n" --- 628,634 ---- " %s [OPTION]... [DBNAME]\n" "\nInitialization options:\n" " -i, --initialize invokes initialization mode\n" ! " -I, --init-steps=[" ALL_INIT_STEPS "]+ (default \"" DEFAULT_INIT_STEPS "\")\n" " run selected initialization steps\n" " -F, --fillfactor=NUM set fill factor\n" " -n, --no-vacuum do not run VACUUM during initialization\n" *************** *** 3803,3812 **** append_fillfactor(char *opts, int len) } /* ! * Fill the standard tables with some data */ static void ! initGenerateData(PGconn *con) { char sql[256]; PGresult *res; --- 3804,3826 ---- } /* ! * Truncate away any old data, in one command in case there are foreign keys */ static void ! initTruncateTables(PGconn *con) ! { ! executeStatement(con, "truncate table " ! "pgbench_accounts, " ! "pgbench_branches, " ! "pgbench_history, " ! "pgbench_tellers"); ! } ! ! /* ! * Fill the standard tables with some data generated and sent from the client ! */ ! static void ! initGenerateDataClientSide(PGconn *con) { char sql[256]; PGresult *res; *************** *** 3820,3826 **** initGenerateData(PGconn *con) remaining_sec; int log_interval = 1; ! fprintf(stderr, "generating data...\n"); /* * we do all of this in one transaction to enable the backend's --- 3834,3840 ---- remaining_sec; int log_interval = 1; ! fprintf(stderr, "generating data (client-side)...\n"); /* * we do all of this in one transaction to enable the backend's *************** *** 3828,3842 **** initGenerateData(PGconn *con) */ executeStatement(con, "begin"); ! /* ! * truncate away any old data, in one command in case there are foreign ! * keys ! */ ! executeStatement(con, "truncate table " ! "pgbench_accounts, " ! "pgbench_branches, " ! "pgbench_history, " ! "pgbench_tellers"); /* * fill branches, tellers, accounts in that order in case foreign keys --- 3842,3849 ---- */ executeStatement(con, "begin"); ! /* truncate away any old data */ ! initTruncateTables(con); /* * fill branches, tellers, accounts in that order in case foreign keys *************** *** 3940,3945 **** initGenerateData(PGconn *con) --- 3947,3997 ---- executeStatement(con, "commit"); } + /* + * Fill the standard tables with some data generated on the server + * + * As already the case with the client-side data generation, the filler + * column defaults to NULL in pgbench_branches and pgbench_tellers, + * and is a blank-padded string in pgbench_accounts. + */ + static void + initGenerateDataServerSide(PGconn *con) + { + char sql[256]; + + fprintf(stderr, "generating data (server-side)...\n"); + + /* + * we do all of this in one transaction to enable the backend's + * data-loading optimizations + */ + executeStatement(con, "begin"); + + /* truncate away any old data */ + initTruncateTables(con); + + snprintf(sql, sizeof(sql), + "insert into pgbench_branches(bid,bbalance) " + "select bid, 0 " + "from generate_series(1, %d) as bid", nbranches * scale); + executeStatement(con, sql); + + snprintf(sql, sizeof(sql), + "insert into pgbench_tellers(tid,bid,tbalance) " + "select tid, (tid - 1) / %d + 1, 0 " + "from generate_series(1, %d) as tid", ntellers, ntellers * scale); + executeStatement(con, sql); + + snprintf(sql, sizeof(sql), + "insert into pgbench_accounts(aid,bid,abalance,filler) " + "select aid, (aid - 1) / %d + 1, 0, '' " + "from generate_series(1, "INT64_FORMAT") as aid", + naccounts, (int64) naccounts * scale); + executeStatement(con, sql); + + executeStatement(con, "commit"); + } + /* * Invoke vacuum on the standard tables */ *************** *** 4020,4040 **** initCreateFKeys(PGconn *con) static void checkInitSteps(const char *initialize_steps) { - const char *step; - if (initialize_steps[0] == '\0') { fprintf(stderr, "no initialization steps specified\n"); exit(1); } ! for (step = initialize_steps; *step != '\0'; step++) { ! if (strchr("dtgvpf ", *step) == NULL) { ! fprintf(stderr, "unrecognized initialization step \"%c\"\n", *step); ! fprintf(stderr, "allowed steps are: \"d\", \"t\", \"g\", \"v\", \"p\", \"f\"\n"); exit(1); } } --- 4072,4092 ---- static void checkInitSteps(const char *initialize_steps) { if (initialize_steps[0] == '\0') { fprintf(stderr, "no initialization steps specified\n"); exit(1); } ! for (const char *step = initialize_steps; *step != '\0'; step++) { ! if (strchr(ALL_INIT_STEPS " ", *step) == NULL) { ! fprintf(stderr, ! "unrecognized initialization step \"%c\"\n", *step); ! fprintf(stderr, ! "Allowed step characters are: \"" ALL_INIT_STEPS "\".\n"); exit(1); } } *************** *** 4075,4082 **** runInitSteps(const char *initialize_steps) initCreateTables(con); break; case 'g': ! op = "generate"; ! initGenerateData(con); break; case 'v': op = "vacuum"; --- 4127,4138 ---- initCreateTables(con); break; case 'g': ! op = "client-side generate"; ! initGenerateDataClientSide(con); ! break; ! case 'G': ! op = "server-side generate"; ! initGenerateDataServerSide(con); break; case 'v': op = "vacuum"; diff --git a/src/bin/pgbench/t/0index c441626d7c..1845869016 100644 *** a/src/bin/pgbench/t/001_pgbench_with_server.pl --- b/src/bin/pgbench/t/001_pgbench_with_server.pl *************** *** 130,136 **** pgbench( # Test interaction of --init-steps with legacy step-selection options pgbench( ! '--initialize --init-steps=dtpvgvv --no-vacuum --foreign-keys --unlogged-tables --partitions=3', 0, [qr{^$}], [ --- 130,136 ---- # Test interaction of --init-steps with legacy step-selection options pgbench( ! '--initialize --init-steps=dtpvGvv --no-vacuum --foreign-keys --unlogged-tables --partitions=3', 0, [qr{^$}], [ *************** *** 138,144 **** pgbench( qr{creating tables}, qr{creating 3 partitions}, qr{creating primary keys}, ! qr{.* of .* tuples \(.*\) done}, qr{creating foreign keys}, qr{(?!vacuuming)}, # no vacuum qr{done in \d+\.\d\d s } --- 138,144 ---- qr{creating tables}, qr{creating 3 partitions}, qr{creating primary keys}, ! qr{generating data \(server-side\)}, qr{creating foreign keys}, qr{(?!vacuuming)}, # no vacuum qr{done in \d+\.\d\d s } diff --git a/src/bin/pgbench/t/002_pgbench_no_serveindex 1e9542af3f..8b6d442812 100644 *** a/src/bin/pgbench/t/002_pgbench_no_server.pl --- b/src/bin/pgbench/t/002_pgbench_no_server.pl *************** *** 147,153 **** my @options = ( [ 'invalid init step', '-i -I dta', ! [ qr{unrecognized initialization step}, qr{allowed steps are} ] ], [ 'bad random seed', --- 147,153 ---- [ 'invalid init step', '-i -I dta', ! [ qr{unrecognized initialization step}, qr{Allowed step characters are} ] ], [ 'bad random seed',