0006-Parallel-Copy-For-Binary-Format-Files.patch
application/x-patch
Filename: 0006-Parallel-Copy-For-Binary-Format-Files.patch
Type: application/x-patch
Part: 5
Message:
Re: Parallel copy
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: format-patch
Series: patch 0006
Subject: Parallel Copy For Binary Format Files
| File | + | − |
|---|---|---|
| src/backend/commands/copy.c | 597 | 66 |
From 14cf6fcfaa9b49c8e8ab9e503e549d40f1eebafc Mon Sep 17 00:00:00 2001
From: Bharath Rupireddy <bharath.rupireddy@enterprisedb.com>, Vignesh C <vignesh21@gmail.com>
Date: Tue, 23 Jun 2020 07:25:14 +0530
Subject: [PATCH 6/6] Parallel Copy For Binary Format Files
Leader reads data from the file into the DSM data blocks each of 64K size.
It also identifies each tuple data block id, start offset, end offset,
tuple size and updates this information in the ring data structure.
Workers parallely read the tuple information from the ring data structure,
the actual tuple data from the data blocks and parallely insert the tuples
into the table.
---
src/backend/commands/copy.c | 663 +++++++++++++++++++++++++++++++++++++++-----
1 file changed, 597 insertions(+), 66 deletions(-)
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index e8a89a4..e22292c 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -243,6 +243,16 @@ typedef struct ParallelCopyData
}ParallelCopyData;
/*
+ * Tuple boundary information used for parallel copy
+ * for binary format files.
+ */
+typedef struct ParallelCopyTupleInfo
+{
+ uint32 offset;
+ uint32 block_id;
+}ParallelCopyTupleInfo;
+
+/*
* This struct contains all the state variables used throughout a COPY
* operation. For simplicity, we use the same struct for all variants of COPY,
* even though some fields are used in only some cases.
@@ -372,6 +382,16 @@ typedef struct CopyStateData
int nworkers;
bool is_parallel;
ParallelCopyData *pcdata;
+
+ /*
+ * Parallel copy for binary formatted files
+ */
+ ParallelCopyDataBlock *curr_data_block;
+ ParallelCopyDataBlock *prev_data_block;
+ uint32 curr_data_offset;
+ uint32 curr_block_pos;
+ ParallelCopyTupleInfo curr_tuple_start_info;
+ ParallelCopyTupleInfo curr_tuple_end_info;
} CopyStateData;
/*
@@ -397,6 +417,7 @@ typedef struct ParallelCopyCommonKeyData
/* Working state for COPY FROM */
AttrNumber num_defaults;
Oid relid;
+ bool binary;
}ParallelCopyCommonKeyData;
/*
@@ -751,6 +772,14 @@ static void PopulateCatalogInformation(CopyState cstate);
static pg_attribute_always_inline uint32 GetLinePosition(CopyState cstate);
static pg_attribute_always_inline copy_data_source_cb LookupParallelCopyFnPtr(const char *funcname);
static pg_attribute_always_inline char* LookupParallelCopyFnStr(copy_data_source_cb fn_addr);
+static uint32 WaitGetFreeCopyBlock(ParallelCopyShmInfo *pcshared_info);
+static pg_attribute_always_inline bool CopyReadBinaryTupleLeader(CopyState cstate);
+static pg_attribute_always_inline void CopyReadBinaryAttributeLeader(CopyState cstate,
+ FmgrInfo *flinfo, Oid typioparam, int32 typmod,
+ uint32 *new_block_pos);
+static pg_attribute_always_inline bool CopyReadBinaryTupleWorker(CopyState cstate, Datum *values, bool *nulls);
+static pg_attribute_always_inline Datum CopyReadBinaryAttributeWorker(CopyState cstate, int column_no,
+ FmgrInfo *flinfo, Oid typioparam, int32 typmod, bool *isnull);
/*
* CopyCommonInfoForWorker - Copy shared_cstate using cstate information.
@@ -769,6 +798,7 @@ CopyCommonInfoForWorker(CopyState cstate, ParallelCopyCommonKeyData *shared_csta
shared_cstate->convert_selectively = cstate->convert_selectively;
shared_cstate->num_defaults = cstate->num_defaults;
shared_cstate->relid = cstate->pcdata->relid;
+ shared_cstate->binary = cstate->binary;
}
/*
@@ -997,8 +1027,8 @@ FindInsertMethod(CopyState cstate)
static pg_attribute_always_inline bool
IsParallelCopyAllowed(CopyState cstate)
{
- /* Parallel copy not allowed for frontend (2.0 protocol) & binary option. */
- if ((cstate->copy_dest == COPY_OLD_FE) || cstate->binary)
+ /* Parallel copy not allowed for frontend (2.0 protocol). */
+ if (cstate->copy_dest == COPY_OLD_FE)
return false;
/* Check if copy is into foreign table or temporary table. */
@@ -1299,6 +1329,7 @@ ParallelWorkerInitialization(ParallelCopyCommonKeyData *shared_cstate,
cstate->convert_selectively = shared_cstate->convert_selectively;
cstate->num_defaults = shared_cstate->num_defaults;
pcdata->relid = shared_cstate->relid;
+ cstate->binary = shared_cstate->binary;
PopulateGlobalsForCopyFrom(cstate, tup_desc, attnamelist);
@@ -1314,7 +1345,7 @@ ParallelWorkerInitialization(ParallelCopyCommonKeyData *shared_cstate,
initStringInfo(&cstate->attribute_buf);
initStringInfo(&cstate->line_buf);
- for (count = 0; count < WORKER_CHUNK_COUNT;count++)
+ for (count = 0; count < WORKER_CHUNK_COUNT; count++)
initStringInfo(&pcdata->worker_line_buf[count].line_buf);
cstate->line_buf_converted = false;
@@ -1331,6 +1362,15 @@ ParallelWorkerInitialization(ParallelCopyCommonKeyData *shared_cstate,
cstate->max_fields = attr_count;
cstate->raw_fields = (char **)palloc(attr_count * sizeof(char *));
}
+
+ cstate->curr_data_block = NULL;
+ cstate->prev_data_block = NULL;
+ cstate->curr_data_offset = 0;
+ cstate->curr_block_pos = 0;
+ cstate->curr_tuple_start_info.block_id = -1;
+ cstate->curr_tuple_start_info.offset = -1;
+ cstate->curr_tuple_end_info.block_id = -1;
+ cstate->curr_tuple_end_info.offset = -1;
}
/*
@@ -1679,32 +1719,59 @@ ParallelCopyLeader(CopyState cstate)
/* Execute the before statement triggers from the leader */
ExecBeforeStmtTrigger(cstate);
- /* On input just throw the header line away. */
- if (cstate->cur_lineno == 0 && cstate->header_line)
+ if (!cstate->binary)
{
- cstate->cur_lineno++;
- if (CopyReadLine(cstate))
+ /* On input just throw the header line away. */
+ if (cstate->cur_lineno == 0 && cstate->header_line)
{
- pcshared_info->is_read_in_progress = false;
- return; /* done */
+ cstate->cur_lineno++;
+ if (CopyReadLine(cstate))
+ {
+ pcshared_info->is_read_in_progress = false;
+ return; /* done */
+ }
}
- }
- for (;;)
+ for (;;)
+ {
+ bool done;
+ cstate->cur_lineno++;
+
+ /* Actually read the line into memory here. */
+ done = CopyReadLine(cstate);
+
+ /*
+ * EOF at start of line means we're done. If we see EOF after some
+ * characters, we act as though it was newline followed by EOF, ie,
+ * process the line and then exit loop on next iteration.
+ */
+ if (done && cstate->line_buf.len == 0)
+ break;
+ }
+ }
+ else
{
- bool done;
- cstate->cur_lineno++;
+ cstate->curr_data_block = NULL;
+ cstate->prev_data_block = NULL;
+ cstate->curr_data_offset = 0;
+ cstate->curr_block_pos = 0;
+ cstate->curr_tuple_start_info.block_id = -1;
+ cstate->curr_tuple_start_info.offset = -1;
+ cstate->curr_tuple_end_info.block_id = -1;
+ cstate->curr_tuple_end_info.offset = -1;
+ pcshared_info->populated = 0;
+ cstate->cur_lineno = 0;
- /* Actually read the line into memory here. */
- done = CopyReadLine(cstate);
+ for (;;)
+ {
+ bool eof = false;
+ cstate->cur_lineno++;
- /*
- * EOF at start of line means we're done. If we see EOF after some
- * characters, we act as though it was newline followed by EOF, ie,
- * process the line and then exit loop on next iteration.
- */
- if (done && cstate->line_buf.len == 0)
- break;
+ eof = CopyReadBinaryTupleLeader(cstate);
+
+ if (eof)
+ break;
+ }
}
pcshared_info->is_read_in_progress = false;
@@ -1712,6 +1779,456 @@ ParallelCopyLeader(CopyState cstate)
}
/*
+ * CopyReadBinaryTupleLeader - leader reads data from binary formatted file
+ * to data blocks and identies tuple boundaries/offsets so that workers
+ * can work on the data blocks data.
+ */
+static pg_attribute_always_inline bool
+CopyReadBinaryTupleLeader(CopyState cstate)
+{
+ int readbytes = 0;
+ ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+ uint32 block_pos;
+ int16 fld_count;
+ AttrNumber attr_count = list_length(cstate->attnumlist);
+ ListCell *cur;
+ FmgrInfo *in_functions = cstate->in_functions;
+ Oid *typioparams = cstate->typioparams;
+ TupleDesc tupDesc = RelationGetDescr(cstate->rel);
+ uint32 new_block_pos;
+ uint32 line_size;
+
+ if (cstate->curr_data_block == NULL)
+ {
+ block_pos = WaitGetFreeCopyBlock(pcshared_info);
+
+ cstate->curr_block_pos = block_pos;
+
+ cstate->curr_data_block = &pcshared_info->data_blocks[block_pos];
+
+ cstate->curr_data_offset = 0;
+
+ readbytes = CopyGetData(cstate, &cstate->curr_data_block->data, 1, DATA_BLOCK_SIZE);
+
+ elog(DEBUG1, "LEADER - bytes read from file %d", readbytes);
+
+ if (cstate->reached_eof)
+ return true;
+ }
+
+ if (cstate->curr_data_offset + sizeof(fld_count) >= (DATA_BLOCK_SIZE - 1))
+ {
+ ParallelCopyDataBlock *data_block = NULL;
+ uint8 movebytes = 0;
+
+ block_pos = WaitGetFreeCopyBlock(pcshared_info);
+
+ movebytes = DATA_BLOCK_SIZE - cstate->curr_data_offset;
+
+ cstate->curr_data_block->skip_bytes = movebytes;
+
+ data_block = &pcshared_info->data_blocks[block_pos];
+
+ if (movebytes > 0)
+ memmove(&data_block->data[0], &cstate->curr_data_block->data[cstate->curr_data_offset],
+ movebytes);
+
+ elog(DEBUG1, "LEADER - field count is spread across data blocks - moved %d bytes from current block %u to %u block",
+ movebytes, cstate->curr_block_pos, block_pos);
+
+ readbytes = CopyGetData(cstate, &data_block->data[movebytes], 1, (DATA_BLOCK_SIZE - movebytes));
+
+ elog(DEBUG1, "LEADER - bytes read from file after field count is moved to next data block %d", readbytes);
+
+ if (cstate->reached_eof)
+ ereport(ERROR,
+ (errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
+ errmsg("unexpected EOF in COPY data")));
+
+ cstate->curr_data_block = data_block;
+ cstate->curr_data_offset = 0;
+ cstate->curr_block_pos = block_pos;
+ }
+
+ memcpy(&fld_count, &cstate->curr_data_block->data[cstate->curr_data_offset], sizeof(fld_count));
+
+ fld_count = (int16) pg_ntoh16(fld_count);
+
+ if (fld_count == -1)
+ {
+ /*
+ * Received EOF marker. In a V3-protocol copy, wait for the
+ * protocol-level EOF, and complain if it doesn't come
+ * immediately. This ensures that we correctly handle CopyFail,
+ * if client chooses to send that now.
+ *
+ * Note that we MUST NOT try to read more data in an old-protocol
+ * copy, since there is no protocol-level EOF marker then. We
+ * could go either way for copy from file, but choose to throw
+ * error if there's data after the EOF marker, for consistency
+ * with the new-protocol case.
+ */
+ char dummy;
+
+ if (cstate->copy_dest != COPY_OLD_FE &&
+ CopyGetData(cstate, &dummy, 1, 1) > 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
+ errmsg("received copy data after EOF marker")));
+ return true;
+ }
+
+ if (fld_count != attr_count)
+ ereport(ERROR,
+ (errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
+ errmsg("row field count is %d, expected %d",
+ (int) fld_count, attr_count)));
+
+ cstate->curr_tuple_start_info.block_id = cstate->curr_block_pos;
+ cstate->curr_tuple_start_info.offset = cstate->curr_data_offset;
+ cstate->curr_data_offset = cstate->curr_data_offset + sizeof(fld_count);
+ new_block_pos = cstate->curr_block_pos;
+
+ foreach(cur, cstate->attnumlist)
+ {
+ int attnum = lfirst_int(cur);
+ int m = attnum - 1;
+ Form_pg_attribute att = TupleDescAttr(tupDesc, m);
+
+ CopyReadBinaryAttributeLeader(cstate,
+ &in_functions[m],
+ typioparams[m],
+ att->atttypmod,
+ &new_block_pos);
+ }
+
+ cstate->curr_tuple_end_info.block_id = new_block_pos;
+ cstate->curr_tuple_end_info.offset = cstate->curr_data_offset-1;;
+
+ if (cstate->curr_tuple_start_info.block_id == cstate->curr_tuple_end_info.block_id)
+ {
+ elog(DEBUG1,"LEADER - tuple lies in a single data block");
+
+ line_size = cstate->curr_tuple_end_info.offset - cstate->curr_tuple_start_info.offset + 1;
+ pg_atomic_add_fetch_u32(&pcshared_info->data_blocks[cstate->curr_tuple_start_info.block_id].unprocessed_line_parts, 1);
+ }
+ else
+ {
+ uint32 following_block_id = pcshared_info->data_blocks[cstate->curr_tuple_start_info.block_id].following_block;
+
+ elog(DEBUG1,"LEADER - tuple is spread across data blocks");
+
+ line_size = DATA_BLOCK_SIZE - cstate->curr_tuple_start_info.offset -
+ pcshared_info->data_blocks[cstate->curr_tuple_start_info.block_id].skip_bytes;
+
+ pg_atomic_add_fetch_u32(&pcshared_info->data_blocks[cstate->curr_tuple_start_info.block_id].unprocessed_line_parts, 1);
+
+ while (following_block_id != cstate->curr_tuple_end_info.block_id)
+ {
+ line_size = line_size + DATA_BLOCK_SIZE - pcshared_info->data_blocks[following_block_id].skip_bytes;
+
+ pg_atomic_add_fetch_u32(&pcshared_info->data_blocks[following_block_id].unprocessed_line_parts, 1);
+
+ following_block_id = pcshared_info->data_blocks[following_block_id].following_block;
+
+ if (following_block_id == -1)
+ break;
+ }
+
+ if (following_block_id != -1)
+ pg_atomic_add_fetch_u32(&pcshared_info->data_blocks[following_block_id].unprocessed_line_parts, 1);
+
+ line_size = line_size + cstate->curr_tuple_end_info.offset + 1;
+ }
+
+ if (line_size > 0)
+ {
+ int line_pos = UpdateBlockInLineInfo(cstate,
+ cstate->curr_tuple_start_info.block_id,
+ cstate->curr_tuple_start_info.offset,
+ line_size,
+ LINE_LEADER_POPULATED);
+
+ pcshared_info->populated++;
+
+ elog(DEBUG1, "LEADER - adding - block:%u, offset:%u, line size:%u line position:%d",
+ cstate->curr_tuple_start_info.block_id,
+ cstate->curr_tuple_start_info.offset,
+ line_size, line_pos);
+ }
+
+ cstate->curr_tuple_start_info.block_id = -1;
+ cstate->curr_tuple_start_info.offset = -1;
+ cstate->curr_tuple_end_info.block_id = -1;
+ cstate->curr_tuple_end_info.offset = -1;
+
+ return false;
+}
+
+/*
+ * CopyReadBinaryAttributeLeader - leader identifies boundaries/offsets
+ * for each attribute/column, it moves on to next data block if the
+ * attribute/column is spread across data blocks.
+ */
+static pg_attribute_always_inline void
+CopyReadBinaryAttributeLeader(CopyState cstate, FmgrInfo *flinfo,
+ Oid typioparam, int32 typmod, uint32 *new_block_pos)
+{
+ int32 fld_size;
+ int readbytes;
+ ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+ uint32 block_pos;
+
+ if ((cstate->curr_data_offset + sizeof(fld_size)) >= (DATA_BLOCK_SIZE - 1))
+ {
+ ParallelCopyDataBlock *data_block = NULL;
+ uint8 movebytes = DATA_BLOCK_SIZE - cstate->curr_data_offset;
+
+ block_pos = WaitGetFreeCopyBlock(pcshared_info);
+
+ cstate->curr_data_block->skip_bytes = movebytes;
+
+ data_block = &pcshared_info->data_blocks[block_pos];
+
+ if (movebytes > 0)
+ memmove(&data_block->data[0], &cstate->curr_data_block->data[cstate->curr_data_offset], movebytes);
+
+ elog(DEBUG1, "LEADER - field size is spread across data blocks - moved %d bytes from current block %u to %u block",
+ movebytes, cstate->curr_block_pos, block_pos);
+
+ readbytes = CopyGetData(cstate, &data_block->data[movebytes], 1, DATA_BLOCK_SIZE-movebytes);
+
+ elog(DEBUG1, "LEADER - bytes read from file after field size is moved to next data block %d", readbytes);
+
+ if (cstate->reached_eof)
+ ereport(ERROR,
+ (errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
+ errmsg("unexpected EOF in COPY data")));
+
+ cstate->prev_data_block = cstate->curr_data_block;
+ cstate->prev_data_block->following_block = block_pos;
+ cstate->curr_data_block = data_block;
+ cstate->curr_block_pos = block_pos;
+
+ if (cstate->prev_data_block->curr_blk_completed == false)
+ cstate->prev_data_block->curr_blk_completed = true;
+
+ cstate->curr_data_offset = 0;
+ *new_block_pos = block_pos;
+ }
+
+ memcpy(&fld_size, &cstate->curr_data_block->data[cstate->curr_data_offset], sizeof(fld_size));
+
+ cstate->curr_data_offset = cstate->curr_data_offset + sizeof(fld_size);
+
+ fld_size = (int32) pg_ntoh32(fld_size);
+
+ if (fld_size == 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
+ errmsg("unexpected EOF in COPY data")));
+
+ if (fld_size < -1)
+ ereport(ERROR,
+ (errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
+ errmsg("invalid field size")));
+
+ if ((DATA_BLOCK_SIZE-cstate->curr_data_offset) >= fld_size)
+ {
+ cstate->curr_data_offset = cstate->curr_data_offset + fld_size;
+ }
+ else
+ {
+ ParallelCopyDataBlock *data_block = NULL;
+
+ block_pos = WaitGetFreeCopyBlock(pcshared_info);
+
+ data_block = &pcshared_info->data_blocks[block_pos];
+
+ readbytes = CopyGetData(cstate, &data_block->data[0], 1, DATA_BLOCK_SIZE);
+
+ elog(DEBUG1, "LEADER - bytes read from file after detecting that tuple is spread across data blocks %d", readbytes);
+
+ if (cstate->reached_eof)
+ ereport(ERROR,
+ (errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
+ errmsg("unexpected EOF in COPY data")));
+
+
+ cstate->prev_data_block = cstate->curr_data_block;
+ cstate->prev_data_block->following_block = block_pos;
+
+ if (cstate->prev_data_block->curr_blk_completed == false)
+ cstate->prev_data_block->curr_blk_completed = true;
+
+ cstate->curr_data_block = data_block;
+ cstate->curr_data_offset = fld_size - (DATA_BLOCK_SIZE - cstate->curr_data_offset);
+ cstate->curr_block_pos = block_pos;
+ *new_block_pos = block_pos;
+ }
+}
+
+/*
+ * CopyReadBinaryTupleWorker - each worker reads data from data blocks after
+ * getting leader-identified tuple offsets from ring data structure.
+ */
+static pg_attribute_always_inline bool
+CopyReadBinaryTupleWorker(CopyState cstate, Datum *values, bool *nulls)
+{
+ uint32 line_pos;
+ ParallelCopyLineBoundary *line_info;
+ ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+ int16 fld_count;
+ AttrNumber attr_count = list_length(cstate->attnumlist);
+ ListCell *cur;
+ FmgrInfo *in_functions = cstate->in_functions;
+ Oid *typioparams = cstate->typioparams;
+ TupleDesc tupDesc = RelationGetDescr(cstate->rel);
+ int i;
+
+ line_pos = GetLinePosition(cstate);
+
+ if (line_pos == -1)
+ return true;
+
+ line_info = &pcshared_info->line_boundaries.ring[line_pos];
+ cstate->curr_data_block = &pcshared_info->data_blocks[line_info->first_block];
+ cstate->curr_data_offset = line_info->start_offset;
+
+ if (cstate->curr_data_offset + sizeof(fld_count) >= (DATA_BLOCK_SIZE - 1))
+ {
+ /*the case where field count spread across datablocks should never occur.
+ as the leader would have moved it to next block*/
+ elog(DEBUG1, "WORKER - field count spread across datablocks should never occur");
+ }
+
+ memcpy(&fld_count, &cstate->curr_data_block->data[cstate->curr_data_offset], sizeof(fld_count));
+ fld_count = (int16) pg_ntoh16(fld_count);
+
+ if (fld_count == -1)
+ {
+ return true;
+ }
+
+ if (fld_count != attr_count)
+ ereport(ERROR,
+ (errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
+ errmsg("row field count is %d, expected %d",
+ (int) fld_count, attr_count)));
+
+ cstate->curr_data_offset = cstate->curr_data_offset + sizeof(fld_count);
+ i = 0;
+
+ foreach(cur, cstate->attnumlist)
+ {
+ int attnum = lfirst_int(cur);
+ int m = attnum - 1;
+ Form_pg_attribute att = TupleDescAttr(tupDesc, m);
+ cstate->cur_attname = NameStr(att->attname);
+
+ i++;
+ values[m] = CopyReadBinaryAttributeWorker(cstate,
+ i,
+ &in_functions[m],
+ typioparams[m],
+ att->atttypmod,
+ &nulls[m]);
+ cstate->cur_attname = NULL;
+ }
+
+ pg_atomic_sub_fetch_u32(&cstate->curr_data_block->unprocessed_line_parts, 1);
+ line_info->start_offset = -1;
+ pg_atomic_write_u32(&line_info->line_state, LINE_WORKER_PROCESSED);
+ pg_atomic_write_u32(&line_info->line_size, -1);
+ pg_atomic_add_fetch_u64(&pcshared_info->total_worker_processed, 1);
+
+ return false;
+}
+
+/*
+ * CopyReadBinaryAttributeWorker - leader identifies boundaries/offsets
+ * for each attribute/column, it moves on to next data block if the
+ * attribute/column is spread across data blocks.
+ */
+static pg_attribute_always_inline Datum
+CopyReadBinaryAttributeWorker(CopyState cstate, int column_no,
+ FmgrInfo *flinfo, Oid typioparam, int32 typmod, bool *isnull)
+{
+ int32 fld_size;
+ Datum result;
+ ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+
+ if ((cstate->curr_data_offset + sizeof(fld_size)) >= (DATA_BLOCK_SIZE - 1))
+ {
+ ParallelCopyDataBlock *prev_data_block = cstate->curr_data_block;
+
+ elog(DEBUG1, "WORKER - field size is spread across data blocks");
+
+ cstate->curr_data_block = &pcshared_info->data_blocks[cstate->curr_data_block->following_block];
+ pg_atomic_sub_fetch_u32(&prev_data_block->unprocessed_line_parts, 1);
+ cstate->curr_data_offset = 0;
+ }
+
+ memcpy(&fld_size, &cstate->curr_data_block->data[cstate->curr_data_offset], sizeof(fld_size));
+ fld_size = (int32) pg_ntoh32(fld_size);
+
+ if (fld_size == 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
+ errmsg("unexpected EOF in COPY data")));
+
+ if (fld_size < -1)
+ ereport(ERROR,
+ (errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
+ errmsg("invalid field size")));
+
+ cstate->curr_data_offset = cstate->curr_data_offset + sizeof(fld_size);
+
+ /* reset attribute_buf to empty, and load raw data in it */
+ resetStringInfo(&cstate->attribute_buf);
+
+ enlargeStringInfo(&cstate->attribute_buf, fld_size);
+
+ if ((DATA_BLOCK_SIZE-cstate->curr_data_offset) >= fld_size)
+ {
+ elog(DEBUG1, "WORKER - tuple lies in single data block");
+
+ memcpy(&cstate->attribute_buf.data[0],&cstate->curr_data_block->data[cstate->curr_data_offset], fld_size);
+ cstate->curr_data_offset = cstate->curr_data_offset + fld_size;
+ }
+ else
+ {
+ ParallelCopyDataBlock *prev_data_block = cstate->curr_data_block;
+
+ elog(DEBUG1, "WORKER - tuple is spread across data blocks");
+
+ memcpy(&cstate->attribute_buf.data[0], &cstate->curr_data_block->data[cstate->curr_data_offset],
+ (DATA_BLOCK_SIZE - cstate->curr_data_offset));
+ cstate->curr_data_block = &pcshared_info->data_blocks[cstate->curr_data_block->following_block];
+ pg_atomic_sub_fetch_u32(&prev_data_block->unprocessed_line_parts, 1);
+ memcpy(&cstate->attribute_buf.data[DATA_BLOCK_SIZE - cstate->curr_data_offset],
+ &cstate->curr_data_block->data[0], (fld_size - (DATA_BLOCK_SIZE - cstate->curr_data_offset)));
+ cstate->curr_data_offset = fld_size - (DATA_BLOCK_SIZE - cstate->curr_data_offset);
+ }
+
+ cstate->attribute_buf.len = fld_size;
+ cstate->attribute_buf.data[fld_size] = '\0';
+
+ /* Call the column type's binary input converter */
+ result = ReceiveFunctionCall(flinfo, &cstate->attribute_buf,
+ typioparam, typmod);
+
+ /* Trouble if it didn't eat the whole buffer */
+ if (cstate->attribute_buf.cursor != cstate->attribute_buf.len)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
+ errmsg("incorrect binary data format")));
+
+ *isnull = false;
+ return result;
+}
+
+/*
* GetLinePosition - return the line position that worker should process.
*/
static uint32
@@ -5449,60 +5966,74 @@ NextCopyFrom(CopyState cstate, ExprContext *econtext,
else
{
/* binary */
- int16 fld_count;
- ListCell *cur;
+ if (!IsParallelCopy())
+ {
+ int16 fld_count;
+ ListCell *cur;
- cstate->cur_lineno++;
+ cstate->cur_lineno++;
- if (!CopyGetInt16(cstate, &fld_count))
- {
- /* EOF detected (end of file, or protocol-level EOF) */
- return false;
- }
+ if (!CopyGetInt16(cstate, &fld_count))
+ {
+ /* EOF detected (end of file, or protocol-level EOF) */
+ return false;
+ }
- if (fld_count == -1)
- {
- /*
- * Received EOF marker. In a V3-protocol copy, wait for the
- * protocol-level EOF, and complain if it doesn't come
- * immediately. This ensures that we correctly handle CopyFail,
- * if client chooses to send that now.
- *
- * Note that we MUST NOT try to read more data in an old-protocol
- * copy, since there is no protocol-level EOF marker then. We
- * could go either way for copy from file, but choose to throw
- * error if there's data after the EOF marker, for consistency
- * with the new-protocol case.
- */
- char dummy;
+ if (fld_count == -1)
+ {
+ /*
+ * Received EOF marker. In a V3-protocol copy, wait for the
+ * protocol-level EOF, and complain if it doesn't come
+ * immediately. This ensures that we correctly handle CopyFail,
+ * if client chooses to send that now.
+ *
+ * Note that we MUST NOT try to read more data in an old-protocol
+ * copy, since there is no protocol-level EOF marker then. We
+ * could go either way for copy from file, but choose to throw
+ * error if there's data after the EOF marker, for consistency
+ * with the new-protocol case.
+ */
+ char dummy;
+
+ if (cstate->copy_dest != COPY_OLD_FE &&
+ CopyGetData(cstate, &dummy, 1, 1) > 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
+ errmsg("received copy data after EOF marker")));
+ return false;
+ }
- if (cstate->copy_dest != COPY_OLD_FE &&
- CopyGetData(cstate, &dummy, 1, 1) > 0)
+ if (fld_count != attr_count)
ereport(ERROR,
(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
- errmsg("received copy data after EOF marker")));
- return false;
+ errmsg("row field count is %d, expected %d",
+ (int) fld_count, attr_count)));
+
+ foreach(cur, cstate->attnumlist)
+ {
+ int attnum = lfirst_int(cur);
+ int m = attnum - 1;
+ Form_pg_attribute att = TupleDescAttr(tupDesc, m);
+
+ cstate->cur_attname = NameStr(att->attname);
+ values[m] = CopyReadBinaryAttribute(cstate,
+ &in_functions[m],
+ typioparams[m],
+ att->atttypmod,
+ &nulls[m]);
+ cstate->cur_attname = NULL;
+ }
}
+ else
+ {
+ bool eof = false;
- if (fld_count != attr_count)
- ereport(ERROR,
- (errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
- errmsg("row field count is %d, expected %d",
- (int) fld_count, attr_count)));
+ cstate->cur_lineno++;
- foreach(cur, cstate->attnumlist)
- {
- int attnum = lfirst_int(cur);
- int m = attnum - 1;
- Form_pg_attribute att = TupleDescAttr(tupDesc, m);
+ eof = CopyReadBinaryTupleWorker(cstate, values, nulls);
- cstate->cur_attname = NameStr(att->attname);
- values[m] = CopyReadBinaryAttribute(cstate,
- &in_functions[m],
- typioparams[m],
- att->atttypmod,
- &nulls[m]);
- cstate->cur_attname = NULL;
+ if (eof)
+ return false;
}
}
--
1.8.3.1