* Copyright (c) 2020 Huawei Technologies Co.,Ltd.
*
* openGauss is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
* ---------------------------------------------------------------------------------------
*
* roach_adpter.cpp
*
* IDENTIFICATION
* src/gausskernel/storage/bulkload/roach_adpter.cpp
*
* ---------------------------------------------------------------------------------------
*/
#include "postgres.h"
#include "knl/knl_variable.h"
#include "bulkload/roach_adpter.h"
#include "parser/parse_func.h"
#include "utils/lsyscache.h"
#include "optimizer/streamplan.h"
template bool getNextRoach<true>(CopyState cstate);
template bool getNextRoach<false>(CopyState cstate);
template void initRoachState<true>(CopyState cstate, const char *filename, List *totalTask);
template void initRoachState<false>(CopyState cstate, const char *filename, List *totalTask);
RoachRoutine *initRoachRoutine()
{
Datum datum;
RoachRoutine *routine = NULL;
Oid func_oid;
func_oid = LookupFuncName(list_make1(makeString("roach_handler")), 0, NULL, false);
if (get_func_rettype(func_oid) != FDW_HANDLEROID)
ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("function roach_handler must return type \"fdw_handler\"")));
datum = OidFunctionCall0(func_oid);
routine = (RoachRoutine *)DatumGetPointer(datum);
return routine;
}
template <bool import>
bool getNextRoach(CopyState cstate)
{
List *taskList = cstate->taskList;
ListCell *prevTaskPtr = cstate->curTaskPtr;
ListCell *curTaskPtr = (prevTaskPtr == NULL ? list_head(taskList) : lnext(prevTaskPtr));
Assert(cstate->roach_routine);
Assert(IsA(cstate->roach_routine, RoachRoutine));
RoachRoutine *roachroutine = (RoachRoutine *)cstate->roach_routine;
if (curTaskPtr == NULL || cstate->roach_context != NULL) {
return false;
}
DistFdwFileSegment *segment = (DistFdwFileSegment *)lfirst(curTaskPtr);
Assert(segment);
const char *mode = import ? "r" : "w";
void *roach_context = roachroutine->Open(segment->filename, (char *)mode);
if (roach_context == NULL)
ereport(ERROR, (errcode_for_file_access(), errmsg("could not open roach %s", cstate->filename)));
cstate->roach_context = roach_context;
return true;
}
int copyGetRoachData(CopyState cstate, char* databuf, int minread, int maxread)
{
Assert(cstate->roach_routine);
Assert(IsA(cstate->roach_routine, RoachRoutine));
RoachRoutine *roachroutine = (RoachRoutine *)cstate->roach_routine;
int bytesread = (int)(roachroutine->Read(databuf, 1, maxread, cstate->roach_context));
if (roachroutine->Error(cstate->roach_context))
ereport(ERROR, (errcode(ERRCODE_FILE_READ_FAILED), errmsg("could not read from roach")));
return bytesread;
}
template <bool import>
void initRoachState(CopyState cstate, const char *filename, List *totalTask)
{
cstate->copy_dest = COPY_ROACH;
if (IS_PGXC_DATANODE) {
cstate->roach_routine = (Node *)initRoachRoutine();
if (!cstate->roach_routine)
ereport(ERROR,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), errmsg("Failed to init roach routine.")));
#ifdef USE_ASSERT_CHECKING
List *urllist = DeserializeLocations(filename);
if (list_length(urllist) > 1) {
ereport(ERROR,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), errmsg("can not specify multiple locations")));
}
#endif
char roachPath[PATH_MAX + 1];
const char *pos = strstr(filename, ROACH_PREFIX);
pos += ROACH_PREFIX_LEN;
errno_t ret = snprintf_s(roachPath, sizeof(roachPath), PATH_MAX, "%s/%s", pos,
g_instance.attr.attr_common.PGXCNodeName);
securec_check_ss(ret, "", "");
roachPath[PATH_MAX] = '\0';
List *taskList = NIL;
DistFdwFileSegment *segment = makeNode(DistFdwFileSegment);
segment->filename = pstrdup(roachPath);
taskList = lappend(taskList, segment);
if (list_length(taskList) == 0) {
taskList = addNullTask(taskList);
}
cstate->taskList = taskList;
cstate->curTaskPtr = NULL;
cstate->curReadOffset = 0;
(void)getNextRoach<import>(cstate);
}
}
void endRoachBulkLoad(CopyState cstate)
{
if (IS_PGXC_DATANODE) {
Assert(cstate->roach_routine);
Assert(IsA(cstate->roach_routine, RoachRoutine));
RoachRoutine *roachroutine = (RoachRoutine *)cstate->roach_routine;
if (cstate->roach_context && roachroutine->Close(cstate->roach_context))
ereport(ERROR, (errcode_for_file_access(), errmsg("could not close roach %s", cstate->filename)));
}
}
void exportRoach(CopyState cstate)
{
Assert(cstate->copy_dest == COPY_ROACH);
Assert(cstate->fileformat != FORMAT_BINARY);
errno_t rc = 0;
if (cstate->eol_type == EOL_NL)
CopySendChar(cstate, '\n');
else
CopySendString(cstate, "\r\n");
StringInfo in = cstate->fe_msgbuf;
const char *pdata = in->data;
int dsize = in->len;
if (cstate->raw_buf_len == RAW_BUF_SIZE) {
exportRoachFlushOut(cstate, true);
}
do {
int avail = (RAW_BUF_SIZE - cstate->raw_buf_len);
Assert(avail > 0);
if (dsize <= avail) {
rc = (errno_t)memcpy_s(cstate->raw_buf + cstate->raw_buf_len, avail, pdata, dsize);
securec_check(rc, "\0", "\0");
cstate->raw_buf_len += dsize;
break;
}
rc = (errno_t)memcpy_s(cstate->raw_buf + cstate->raw_buf_len, avail, pdata, avail);
securec_check(rc, "\0", "\0");
Assert((cstate->raw_buf_len + avail) == RAW_BUF_SIZE);
cstate->raw_buf_len = RAW_BUF_SIZE;
exportRoachFlushOut(cstate, false);
pdata += avail;
dsize -= avail;
Assert(dsize > 0);
} while (true);
resetStringInfo(in);
}
void exportRoachFlushOut(CopyState cstate, bool isWholeLineAtEnd)
{
Assert(cstate->roach_routine);
Assert(IsA(cstate->roach_routine, RoachRoutine));
RoachRoutine *roachroutine = (RoachRoutine *)cstate->roach_routine;
Assert(((cstate->roach_context == NULL) && IS_STREAM_PLAN) ||
(!(cstate->roach_context == NULL) && !IS_STREAM_PLAN));
if ((cstate->roach_context != NULL) &&
((roachroutine->Write(cstate->raw_buf, cstate->raw_buf_len, 1, cstate->roach_context, isWholeLineAtEnd) != 1) ||
roachroutine->Error(cstate->roach_context)))
ereport(ERROR, (errcode_for_file_access(), errmsg("could not write to roach")));
cstate->raw_buf_len = 0;
}