void DtxContextInfo_Deserialize(const char *serializedDtxContextInfo, int serializedDtxContextInfolen, DtxContextInfo *dtxContextInfo) { int i; DistributedSnapshot *ds = &dtxContextInfo->distributedSnapshot; DtxContextInfo_Reset(dtxContextInfo); if (serializedDtxContextInfolen > 0) { int xipsize; const char *p = serializedDtxContextInfo; int32 maxCount; elog((Debug_print_full_dtm ? LOG : DEBUG5), "DtxContextInfo_Deserialize serializedDtxContextInfolen = %d.", serializedDtxContextInfolen); memcpy(&dtxContextInfo->distributedXid, p, sizeof(DistributedTransactionId)); p += sizeof(DistributedTransactionId); if (dtxContextInfo->distributedXid != InvalidDistributedTransactionId) { memcpy(&dtxContextInfo->distributedTimeStamp, p, sizeof(DistributedTransactionTimeStamp)); p += sizeof(DistributedTransactionTimeStamp); memcpy(dtxContextInfo->distributedId, p, TMGIDSIZE); if (strlen(dtxContextInfo->distributedId) >= TMGIDSIZE) elog(PANIC, "Distribute transaction identifier too long (%d)", (int)strlen(dtxContextInfo->distributedId)); p += TMGIDSIZE; memcpy(&dtxContextInfo->curcid, p, sizeof(CommandId)); p += sizeof(CommandId); } else { elog((Debug_print_full_dtm ? LOG : DEBUG5), "DtxContextInfo_Deserialize distributedXid was InvalidDistributedTransactionId"); } memcpy(&dtxContextInfo->segmateSync, p, sizeof(uint32)); p += sizeof(uint32); memcpy(&dtxContextInfo->nestingLevel, p, sizeof(uint32)); p += sizeof(uint32); memcpy(&dtxContextInfo->haveDistributedSnapshot, p, sizeof(bool)); p += sizeof(bool); memcpy(&dtxContextInfo->cursorContext, p, sizeof(bool)); p += sizeof(bool); elog((Debug_print_full_dtm ? LOG : DEBUG3), "DtxContextInfo_Deserialize distributedTimeStamp %u, distributedXid = %u, curcid %d nestingLevel %d segmateSync %u as %s", dtxContextInfo->distributedTimeStamp, dtxContextInfo->distributedXid, dtxContextInfo->curcid, dtxContextInfo->nestingLevel, dtxContextInfo->segmateSync, (Gp_is_writer ? "WRITER" : "READER")); if (dtxContextInfo->haveDistributedSnapshot) { memcpy(&ds->header.distribTransactionTimeStamp, p, sizeof(DistributedTransactionTimeStamp)); p += sizeof(DistributedTransactionTimeStamp); memcpy(&ds->header.xminAllDistributedSnapshots, p, sizeof(DistributedTransactionId)); p += sizeof(DistributedTransactionId); memcpy(&ds->header.distribSnapshotId, p, sizeof(DistributedSnapshotId)); p += sizeof(DistributedSnapshotId); memcpy(&ds->header.xmin, p, sizeof(DistributedTransactionId)); p += sizeof(DistributedTransactionId); memcpy(&ds->header.xmax, p, sizeof(DistributedTransactionId)); p += sizeof(DistributedTransactionId); memcpy(&ds->header.count, p, sizeof(int32)); p += sizeof(int32); /* * Copy this one to a local variable first. */ memcpy(&maxCount, p, sizeof(int32)); p += sizeof(int32); if (maxCount < 0 || ds->header.count > maxCount) { elog(ERROR, "Invalid distributed snapshot received (maxCount %d, count %d)", maxCount, ds->header.count); } /* * If we have allocated space for the in-progress distributed * transactions, check against that space. Otherwise, * use the received maxCount as guide in allocating space. */ if (ds->inProgressXidArray != NULL) { if (ds->header.maxCount == 0) { elog(ERROR, "Bad allocation of in-progress array"); } if (ds->header.count > ds->header.maxCount) { elog(ERROR, "Too many distributed transactions for snapshot (maxCount %d, count %d)", ds->header.maxCount, ds->header.count); } } else { Assert(ds->inProgressXidArray == NULL); if (maxCount > 0) { if (maxCount < ds->header.maxCount) { maxCount = ds->header.maxCount; } else { ds->header.maxCount = maxCount; } ds->inProgressXidArray = (DistributedTransactionId *)malloc(maxCount * sizeof(DistributedTransactionId)); if (ds->inProgressXidArray == NULL) { ereport(ERROR, (errcode(ERRCODE_OUT_OF_MEMORY), errmsg("out of memory"))); } } } if (ds->header.count > 0) { Assert(ds->inProgressXidArray != NULL); xipsize = sizeof(DistributedTransactionId) * ds->header.count; memcpy(ds->inProgressXidArray, p, xipsize); p += xipsize; } } else { elog((Debug_print_full_dtm ? LOG : DEBUG5), "DtxContextInfo_Deserialize no distributed snapshot"); } memcpy(&dtxContextInfo->distributedTxnOptions, p, sizeof(int)); p += sizeof(int); if (DEBUG5 >= log_min_messages || Debug_print_full_dtm) { elog((Debug_print_full_dtm ? LOG : DEBUG5), "DtxContextInfo_Deserialize distributedTimeStamp %u, distributedXid = %u, " "distributedId = %s", dtxContextInfo->distributedTimeStamp, dtxContextInfo->distributedXid, dtxContextInfo->distributedId); if (dtxContextInfo->haveDistributedSnapshot) { elog((Debug_print_full_dtm ? LOG : DEBUG5), "distributedSnapshotHeader (xminAllDistributedSnapshots %u, xmin = %u, xmax = %u, count = %d, maxCount = %d)", ds->header.xminAllDistributedSnapshots, ds->header.xmin, ds->header.xmax, ds->header.count, ds->header.maxCount); for (i = 0; i < ds->header.count; i++) { elog((Debug_print_full_dtm ? LOG : DEBUG5), ".... inProgressXidArray[%d] = %u", i, ds->inProgressXidArray[i]); } elog((Debug_print_snapshot_dtm ? LOG : DEBUG5), "[Distributed Snapshot #%u] *Deserialize* currcid = %d (gxid = %u, '%s')", ds->header.distribSnapshotId, dtxContextInfo->curcid, getDistributedTransactionId(), DtxContextToString(DistributedTransactionContext)); } elog((Debug_print_full_dtm ? LOG : DEBUG5), "DtxContextInfo_Deserialize txnOptions = 0x%x", dtxContextInfo->distributedTxnOptions); } } else { Assert(dtxContextInfo->distributedXid == InvalidDistributedTransactionId); Assert(dtxContextInfo->distributedTxnOptions == 0); } }
char * qdSerializeDtxContextInfo(int *size, bool wantSnapshot, bool inCursor, int txnOptions, char *debugCaller) { char *serializedDtxContextInfo; Snapshot snapshot; int serializedLen; DtxContextInfo *pDtxContextInfo = NULL; /* * If we already have a LatestSnapshot set then no reason to try * and get a new one. just use that one. But... there is one important * reason why this HAS to be here. ROLLBACK stmts get dispatched to QEs * in the abort transaction code. This code tears down enough stuff such * that you can't call GetTransactionSnapshot() within that code. So we * need to use the LatestSnapshot since we can't re-gen a new one. * * It is also very possible that for a single user statement which may * only generate a single snapshot that we will dispatch multiple statements * to our qExecs. Something like: * * QD QEs * | | * User SQL Statement --->| BEGIN | * |-------------->| * | STMT | * |-------------->| * | PREPARE | * |-------------->| * | COMMIT | * |-------------->| * | | * * This may seem like a problem because all four of those will dispatch * the same snapshot with the same curcid. But... this is OK because * BEGIN, PREPARE, and COMMIT don't need Snapshots on the QEs. * * NOTE: This will be a problem if we ever need to dispatch more than one * statement to the qExecs and more than one needs a snapshot! */ *size = 0; snapshot = NULL; if (wantSnapshot) { if (LatestSnapshot == NULL && SerializableSnapshot == NULL && !IsAbortInProgress()) { /* * unfortunately, the dtm issues a select for prepared xacts at the * beginning and this is before a snapshot has been set up. so we need * one for that but not for when we dont have a valid XID. * * but we CANT do this if an ABORT is in progress... instead we'll send * a NONE since the qExecs dont need the information to do a ROLLBACK. */ elog((Debug_print_full_dtm ? LOG : DEBUG5), "qdSerializeDtxContextInfo calling GetTransactionSnapshot to make snapshot"); GetTransactionSnapshot(); } if (LatestSnapshot != NULL) { elog((Debug_print_full_dtm ? LOG : DEBUG5), "qdSerializeDtxContextInfo using LatestSnapshot"); snapshot = LatestSnapshot; elog((Debug_print_snapshot_dtm ? LOG : DEBUG5), "[Distributed Snapshot #%u] *QD Use Latest* currcid = %d (gxid = %u, '%s')", LatestSnapshot->distribSnapshotWithLocalMapping.header. distribSnapshotId, LatestSnapshot->curcid, getDistributedTransactionId(), DtxContextToString(DistributedTransactionContext)); } else if (SerializableSnapshot != NULL) { elog((Debug_print_full_dtm ? LOG : DEBUG5), "qdSerializeDtxContextInfo using SerializableSnapshot"); snapshot = SerializableSnapshot; elog((Debug_print_snapshot_dtm ? LOG : DEBUG5), "[Distributed Snapshot #%u] *QD Use Serializable* currcid = %d (gxid = %u, '%s')", SerializableSnapshot->distribSnapshotWithLocalMapping.header. distribSnapshotId, SerializableSnapshot->curcid, getDistributedTransactionId(), DtxContextToString(DistributedTransactionContext)); } } switch (DistributedTransactionContext) { case DTX_CONTEXT_QD_DISTRIBUTED_CAPABLE: case DTX_CONTEXT_LOCAL_ONLY: if (snapshot != NULL) { DtxContextInfo_CreateOnMaster(&TempQDDtxContextInfo, &snapshot-> distribSnapshotWithLocalMapping, snapshot->curcid, txnOptions); } else { DtxContextInfo_CreateOnMaster(&TempQDDtxContextInfo, NULL, 0, txnOptions); } TempQDDtxContextInfo.cursorContext = inCursor; if (DistributedTransactionContext == DTX_CONTEXT_QD_DISTRIBUTED_CAPABLE && snapshot != NULL) { updateSharedLocalSnapshot(&TempQDDtxContextInfo, snapshot, "qdSerializeDtxContextInfo"); } pDtxContextInfo = &TempQDDtxContextInfo; break; case DTX_CONTEXT_QD_RETRY_PHASE_2: case DTX_CONTEXT_QE_ENTRY_DB_SINGLETON: case DTX_CONTEXT_QE_AUTO_COMMIT_IMPLICIT: case DTX_CONTEXT_QE_TWO_PHASE_EXPLICIT_WRITER: case DTX_CONTEXT_QE_TWO_PHASE_IMPLICIT_WRITER: case DTX_CONTEXT_QE_READER: case DTX_CONTEXT_QE_PREPARED: case DTX_CONTEXT_QE_FINISH_PREPARED: elog(FATAL, "Unexpected distribute transaction context: '%s'", DtxContextToString(DistributedTransactionContext)); default: elog(FATAL, "Unrecognized DTX transaction context: %d", (int) DistributedTransactionContext); } serializedLen = DtxContextInfo_SerializeSize(pDtxContextInfo); Assert(serializedLen > 0); *size = serializedLen; serializedDtxContextInfo = palloc(*size); DtxContextInfo_Serialize(serializedDtxContextInfo, pDtxContextInfo); elog((Debug_print_full_dtm ? LOG : DEBUG5), "qdSerializeDtxContextInfo (called by %s) returning a snapshot of %d bytes (ptr is %s)", debugCaller, *size, (serializedDtxContextInfo != NULL ? "Non-NULL" : "NULL")); return serializedDtxContextInfo; }
void DtxContextInfo_Serialize(char *buffer, DtxContextInfo *dtxContextInfo) { char *p = buffer; int i; int used; DistributedSnapshot *ds = &dtxContextInfo->distributedSnapshot; memcpy(p, &dtxContextInfo->distributedXid, sizeof(DistributedTransactionId)); p += sizeof(DistributedTransactionId); if (dtxContextInfo->distributedXid != InvalidDistributedTransactionId) { memcpy(p, &dtxContextInfo->distributedTimeStamp, sizeof(DistributedTransactionTimeStamp)); p += sizeof(DistributedTransactionTimeStamp); if (strlen(dtxContextInfo->distributedId) >= TMGIDSIZE) elog(PANIC, "Distribute transaction identifier too long (%d)", (int)strlen(dtxContextInfo->distributedId)); memcpy(p, dtxContextInfo->distributedId, TMGIDSIZE); p += TMGIDSIZE; memcpy(p, &dtxContextInfo->curcid, sizeof(CommandId)); p += sizeof(CommandId); } else { elog((Debug_print_full_dtm ? LOG : DEBUG5), "DtxContextInfo_Serialize only copied InvalidDistributedTransactionId"); } elog((Debug_print_full_dtm ? LOG : DEBUG3), "DtxContextInfo_Serialize distributedTimeStamp %u, distributedXid = %u, curcid %d nestingLevel %d segmateSync %u", dtxContextInfo->distributedTimeStamp, dtxContextInfo->distributedXid, dtxContextInfo->curcid, dtxContextInfo->nestingLevel, dtxContextInfo->segmateSync); memcpy(p, &dtxContextInfo->segmateSync, sizeof(uint32)); p += sizeof(uint32); memcpy(p, &dtxContextInfo->nestingLevel, sizeof(uint32)); p += sizeof(uint32); memcpy(p, &dtxContextInfo->haveDistributedSnapshot, sizeof(bool)); p += sizeof(bool); memcpy(p, &dtxContextInfo->cursorContext, sizeof(bool)); p += sizeof(bool); if (dtxContextInfo->haveDistributedSnapshot) { memcpy(p, &ds->header.distribTransactionTimeStamp, sizeof(DistributedTransactionTimeStamp)); p += sizeof(DistributedTransactionTimeStamp); memcpy(p, &ds->header.xminAllDistributedSnapshots, sizeof(DistributedTransactionId)); p += sizeof(DistributedTransactionId); memcpy(p, &ds->header.distribSnapshotId, sizeof(DistributedSnapshotId)); p += sizeof(DistributedSnapshotId); memcpy(p, &ds->header.xmin, sizeof(DistributedTransactionId)); p += sizeof(DistributedTransactionId); memcpy(p, &ds->header.xmax, sizeof(DistributedTransactionId)); p += sizeof(DistributedTransactionId); memcpy(p, &ds->header.count, sizeof(int32)); p += sizeof(int32); memcpy(p, &ds->header.maxCount, sizeof(int32)); p += sizeof(int32); memcpy(p, ds->inProgressXidArray, sizeof(DistributedTransactionId)*ds->header.count); p += sizeof(DistributedTransactionId)*ds->header.count; } memcpy(p, &dtxContextInfo->distributedTxnOptions, sizeof(int)); p += sizeof(int); used = (p - buffer); if (DEBUG5 >= log_min_messages || Debug_print_full_dtm || Debug_print_snapshot_dtm) { elog((Debug_print_full_dtm ? LOG : DEBUG5), "DtxContextInfo_Serialize distributedTimeStamp %u, distributedXid = %u, " "curcid %d", dtxContextInfo->distributedTimeStamp, dtxContextInfo->distributedXid, dtxContextInfo->curcid); if (dtxContextInfo->haveDistributedSnapshot) { elog((Debug_print_full_dtm ? LOG : DEBUG5), "distributedSnapshotHeader (xminAllDistributedSnapshots %u, xmin = %u, xmax = %u, count = %d, maxCount = %d)", ds->header.xminAllDistributedSnapshots, ds->header.xmin, ds->header.xmax, ds->header.count, ds->header.maxCount); for (i = 0; i < ds->header.count; i++) { elog((Debug_print_full_dtm ? LOG : DEBUG5), ".... inProgressXidArray[%d] = %u", i, ds->inProgressXidArray[i]); } elog((Debug_print_snapshot_dtm ? LOG : DEBUG5), "[Distributed Snapshot #%u] *Serialize* currcid = %d (gxid = %u, '%s')", ds->header.distribSnapshotId, dtxContextInfo->curcid, getDistributedTransactionId(), DtxContextToString(DistributedTransactionContext)); } elog((Debug_print_full_dtm ? LOG : DEBUG5),"DtxContextInfo_Serialize txnOptions = 0x%x", dtxContextInfo->distributedTxnOptions); elog((Debug_print_full_dtm ? LOG : DEBUG5),"DtxContextInfo_Serialize copied %d bytes", used); } }