Skip to content

Commit 4d63e26

Browse files
committed
Further hacking on performance of COPY OUT. It seems that fwrite()'s
per-call overhead is quite significant, at least on Linux: whatever it's doing is more than just shoving the bytes into a buffer. Buffering the data so we can call fwrite() just once per row seems to be a win.
1 parent 223ae69 commit 4d63e26

File tree

1 file changed

+40
-45
lines changed

1 file changed

+40
-45
lines changed

src/backend/commands/copy.c

Lines changed: 40 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/commands/copy.c,v 1.265 2006/05/25 18:42:17 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/commands/copy.c,v 1.266 2006/05/26 22:50:02 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -95,7 +95,8 @@ typedef struct CopyStateData
9595
/* low-level state data */
9696
CopyDest copy_dest; /* type of copy source/destination */
9797
FILE *copy_file; /* used if copy_dest == COPY_FILE */
98-
StringInfo fe_msgbuf; /* used if copy_dest == COPY_NEW_FE */
98+
StringInfo fe_msgbuf; /* used for all dests during COPY TO, only
99+
* for dest == COPY_NEW_FE in COPY FROM */
99100
bool fe_copy; /* true for all FE copy dests */
100101
bool fe_eof; /* true if detected end of copy data */
101102
EolType eol_type; /* EOL type of input */
@@ -287,7 +288,6 @@ SendCopyBegin(CopyState cstate)
287288
pq_sendint(&buf, format, 2); /* per-column formats */
288289
pq_endmessage(&buf);
289290
cstate->copy_dest = COPY_NEW_FE;
290-
cstate->fe_msgbuf = makeStringInfo();
291291
}
292292
else if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 2)
293293
{
@@ -364,23 +364,16 @@ SendCopyEnd(CopyState cstate)
364364
{
365365
if (cstate->copy_dest == COPY_NEW_FE)
366366
{
367-
if (cstate->binary)
368-
{
369-
/* Need to flush out file trailer word */
370-
CopySendEndOfRow(cstate);
371-
}
372-
else
373-
{
374-
/* Shouldn't have any unsent data */
375-
Assert(cstate->fe_msgbuf->len == 0);
376-
}
367+
/* Shouldn't have any unsent data */
368+
Assert(cstate->fe_msgbuf->len == 0);
377369
/* Send Copy Done message */
378370
pq_putemptymessage('c');
379371
}
380372
else
381373
{
382-
/* The FE/BE protocol uses \n as newline for all platforms */
383-
CopySendData(cstate, "\\.\n", 3);
374+
CopySendData(cstate, "\\.", 2);
375+
/* Need to flush out the trailer (this also appends a newline) */
376+
CopySendEndOfRow(cstate);
384377
pq_endcopyout(false);
385378
}
386379
}
@@ -390,53 +383,34 @@ SendCopyEnd(CopyState cstate)
390383
* CopySendString does the same for null-terminated strings
391384
* CopySendChar does the same for single characters
392385
* CopySendEndOfRow does the appropriate thing at end of each data row
386+
* (data is not actually flushed except by CopySendEndOfRow)
393387
*
394388
* NB: no data conversion is applied by these functions
395389
*----------
396390
*/
397391
static void
398392
CopySendData(CopyState cstate, void *databuf, int datasize)
399393
{
400-
switch (cstate->copy_dest)
401-
{
402-
case COPY_FILE:
403-
fwrite(databuf, datasize, 1, cstate->copy_file);
404-
if (ferror(cstate->copy_file))
405-
ereport(ERROR,
406-
(errcode_for_file_access(),
407-
errmsg("could not write to COPY file: %m")));
408-
break;
409-
case COPY_OLD_FE:
410-
if (pq_putbytes((char *) databuf, datasize))
411-
{
412-
/* no hope of recovering connection sync, so FATAL */
413-
ereport(FATAL,
414-
(errcode(ERRCODE_CONNECTION_FAILURE),
415-
errmsg("connection lost during COPY to stdout")));
416-
}
417-
break;
418-
case COPY_NEW_FE:
419-
appendBinaryStringInfo(cstate->fe_msgbuf,
420-
(char *) databuf, datasize);
421-
break;
422-
}
394+
appendBinaryStringInfo(cstate->fe_msgbuf, (char *) databuf, datasize);
423395
}
424396

425397
static void
426398
CopySendString(CopyState cstate, const char *str)
427399
{
428-
CopySendData(cstate, (void *) str, strlen(str));
400+
appendBinaryStringInfo(cstate->fe_msgbuf, str, strlen(str));
429401
}
430402

431403
static void
432404
CopySendChar(CopyState cstate, char c)
433405
{
434-
CopySendData(cstate, &c, 1);
406+
appendStringInfoCharMacro(cstate->fe_msgbuf, c);
435407
}
436408

437409
static void
438410
CopySendEndOfRow(CopyState cstate)
439411
{
412+
StringInfo fe_msgbuf = cstate->fe_msgbuf;
413+
440414
switch (cstate->copy_dest)
441415
{
442416
case COPY_FILE:
@@ -449,24 +423,40 @@ CopySendEndOfRow(CopyState cstate)
449423
CopySendString(cstate, "\r\n");
450424
#endif
451425
}
426+
427+
(void) fwrite(fe_msgbuf->data, fe_msgbuf->len,
428+
1, cstate->copy_file);
429+
if (ferror(cstate->copy_file))
430+
ereport(ERROR,
431+
(errcode_for_file_access(),
432+
errmsg("could not write to COPY file: %m")));
452433
break;
453434
case COPY_OLD_FE:
454435
/* The FE/BE protocol uses \n as newline for all platforms */
455436
if (!cstate->binary)
456437
CopySendChar(cstate, '\n');
438+
439+
if (pq_putbytes(fe_msgbuf->data, fe_msgbuf->len))
440+
{
441+
/* no hope of recovering connection sync, so FATAL */
442+
ereport(FATAL,
443+
(errcode(ERRCODE_CONNECTION_FAILURE),
444+
errmsg("connection lost during COPY to stdout")));
445+
}
457446
break;
458447
case COPY_NEW_FE:
459448
/* The FE/BE protocol uses \n as newline for all platforms */
460449
if (!cstate->binary)
461450
CopySendChar(cstate, '\n');
451+
462452
/* Dump the accumulated row as one CopyData message */
463-
(void) pq_putmessage('d', cstate->fe_msgbuf->data,
464-
cstate->fe_msgbuf->len);
465-
/* Reset fe_msgbuf to empty */
466-
cstate->fe_msgbuf->len = 0;
467-
cstate->fe_msgbuf->data[0] = '\0';
453+
(void) pq_putmessage('d', fe_msgbuf->data, fe_msgbuf->len);
468454
break;
469455
}
456+
457+
/* Reset fe_msgbuf to empty */
458+
fe_msgbuf->len = 0;
459+
fe_msgbuf->data[0] = '\0';
470460
}
471461

472462
/*
@@ -1237,6 +1227,9 @@ CopyTo(CopyState cstate)
12371227
attr_count = list_length(cstate->attnumlist);
12381228
null_print_client = cstate->null_print; /* default */
12391229

1230+
/* We use fe_msgbuf as a per-row buffer regardless of copy_dest */
1231+
cstate->fe_msgbuf = makeStringInfo();
1232+
12401233
/* Get info about the columns we need to process. */
12411234
out_functions = (FmgrInfo *) palloc(num_phys_attrs * sizeof(FmgrInfo));
12421235
force_quote = (bool *) palloc(num_phys_attrs * sizeof(bool));
@@ -1423,6 +1416,8 @@ CopyTo(CopyState cstate)
14231416
{
14241417
/* Generate trailer for a binary copy */
14251418
CopySendInt16(cstate, -1);
1419+
/* Need to flush out the trailer */
1420+
CopySendEndOfRow(cstate);
14261421
}
14271422

14281423
MemoryContextDelete(mycontext);

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy