blob: 625b20c888f1669eae55e39c34f6ba697cee22c1 [file] [log] [blame]
/*-------------------------------------------------------------------------
*
* persistentendxactrec.c
* Make and read persistent information in commit, abort, and prepared records.
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "miscadmin.h"
#include "access/persistentendxactrec.h"
#include "storage/smgr.h"
#include "utils/guc.h"
#include "cdb/cdbpersistentstore.h"
#include "cdb/cdbpersistentfilesysobj.h"
char *PersistentXactObjKind_Name(
PersistentEndXactObjKind objKind)
{
switch (objKind)
{
case PersistentEndXactObjKind_FileSysAction: return "File-System Action";
case PersistentEndXactObjKind_AppendOnlyMirrorResyncEofs: return "Append-Only Mirror Resync EOFs";
default:
return "Unknown";
}
}
char *EndXactRecKind_Name(
EndXactRecKind endXactRecKind)
{
switch (endXactRecKind)
{
case EndXactRecKind_Commit: return "Commit";
case EndXactRecKind_Abort: return "Abort";
case EndXactRecKind_Prepare: return "Prepare";
default:
return "Unknown";
}
}
bool EndXactRecKind_NeedsAction(
EndXactRecKind endXactRecKind,
PersistentEndXactFileSysAction action)
{
switch (action)
{
case PersistentEndXactFileSysAction_Create:
return true; // Go to 'Created' state on commit, or 'Aborting Create' state and perform DROP on abort.
case PersistentEndXactFileSysAction_Drop:
return (endXactRecKind != EndXactRecKind_Abort);
// Peform DROP on commit.
case PersistentEndXactFileSysAction_AbortingCreateNeeded:
return true; // Clean-up required on commit or abort.
default:
elog(ERROR, "Unexpected persistent end transaction file-system action: %d",
action);
return false; // Not reached.
}
}
char *PersistentEndXactFileSysAction_Name(
PersistentEndXactFileSysAction action)
{
switch (action)
{
case PersistentEndXactFileSysAction_Create: return "CREATE";
case PersistentEndXactFileSysAction_Drop: return "DROP";
case PersistentEndXactFileSysAction_AbortingCreateNeeded: return "Aborting Create Needed";
default:
return "Unknown";
}
}
/*
* Structure containing an object.
*/
typedef struct PersistentEndXactRecObjHdr
{
int32 len;
int16 objKind;
union
{
uint8 data[0];
uint64 align;
} p;
} PersistentEndXactRecObjHdr;
void PersistentEndXactRec_Print(
char *procName,
PersistentEndXactRecObjects *objects)
{
int i;
elog(Persistent_DebugPrintLevel(),
"%s: file-system action count %d, Append-Only mirror resync EOFs count %d",
procName,
objects->typed.fileSysActionInfosCount,
objects->typed.appendOnlyMirrorResyncEofsCount);
for (i = 0; i < objects->typed.fileSysActionInfosCount; i++)
{
PersistentEndXactFileSysActionInfo *fileSysActionInfos =
&objects->typed.fileSysActionInfos[i];
elog(Persistent_DebugPrintLevel(),
"%s: [%d] action '%s' %s, relation storage manager '%s', persistent serial num " INT64_FORMAT ", TID %s",
procName,
i,
PersistentEndXactFileSysAction_Name(fileSysActionInfos->action),
PersistentFileSysObjName_TypeAndObjectName(&fileSysActionInfos->fsObjName),
PersistentFileSysRelStorageMgr_Name(fileSysActionInfos->relStorageMgr),
fileSysActionInfos->persistentSerialNum,
ItemPointerToString(&fileSysActionInfos->persistentTid));
}
for (i = 0; i < objects->typed.appendOnlyMirrorResyncEofsCount; i++)
{
PersistentEndXactAppendOnlyMirrorResyncEofs *eofs =
&objects->typed.appendOnlyMirrorResyncEofs[i];
elog(Persistent_DebugPrintLevel(),
"%s: [%d] Append-Only Mirror Resync EOFs %u/%u/%u, segment file #%d -- persistent serial num " INT64_FORMAT ", TID %s, mirror loss EOF " INT64_FORMAT ", mirror new EOF " INT64_FORMAT,
procName,
i,
eofs->relFileNode.spcNode,
eofs->relFileNode.dbNode,
eofs->relFileNode.relNode,
eofs->segmentFileNum,
eofs->persistentSerialNum,
ItemPointerToString(&eofs->persistentTid),
eofs->mirrorLossEof,
eofs->mirrorNewEof);
}
}
static int PersistentEndXactRec_CountForObject(
PersistentEndXactObjKind objKind,
int32 len)
{
int count = 0;
switch (objKind)
{
case PersistentEndXactObjKind_FileSysAction:
count = len / sizeof(PersistentEndXactFileSysActionInfo);
break;
case PersistentEndXactObjKind_AppendOnlyMirrorResyncEofs:
count = len / sizeof(PersistentEndXactAppendOnlyMirrorResyncEofs);
break;
default:
elog(ERROR, "Unexpected persistent transaction object kind: %d",
objKind);
}
return count;
}
static void PersistentEndXactRec_SetObjectInfo(
PersistentEndXactRecObjects *objects,
PersistentEndXactObjKind objKind,
void *data,
int count,
int32 len)
{
PeristentEndXaxtUntyped *untyped = &objects->untyped[objKind-1];
untyped->data = data;
untyped->count = count;
untyped->len = len;
}
static void PersistentEndXactRec_GetObjectInfo(
PersistentEndXactRecObjects *objects,
PersistentEndXactObjKind objKind,
uint8 **data,
int *count,
int32 *len)
{
PeristentEndXaxtUntyped *untyped = &objects->untyped[objKind-1];
*data = untyped->data;
*count = untyped->count;
*len = untyped->len;
}
void PersistentEndXactRec_Init(
PersistentEndXactRecObjects *objects)
{
MemSet(objects, 0, sizeof(PersistentEndXactRecObjects));
}
static void
PersistentEndXactRec_VerifyFileSysActionInfos(
EndXactRecKind endXactRecKind,
PersistentEndXactFileSysActionInfo *fileSysActionInfos,
int count)
{
int i;
ItemPointerData maxTid;
if (InRecovery || Persistent_BeforePersistenceWork())
return;
for (i = 0; i < count; i++)
{
PersistentTidIsKnownResult persistentTidIsKnownResult;
if (!PersistentEndXactFileSysAction_IsValid(fileSysActionInfos[i].action))
elog(ERROR, "Persistent file-system action is invalid (%d) (index %d, transaction kind '%s')",
fileSysActionInfos[i].action,
i,
EndXactRecKind_Name(endXactRecKind));
if (!PersistentFsObjType_IsValid(fileSysActionInfos[i].fsObjName.type))
elog(ERROR, "Persistent file-system object type is invalid (%d) (index %d, transaction kind '%s')",
fileSysActionInfos[i].fsObjName.type,
i,
EndXactRecKind_Name(endXactRecKind));
if (PersistentStore_IsZeroTid(&fileSysActionInfos[i].persistentTid))
elog(ERROR, "TID for persistent '%s' tuple is invalid (0,0) (index %d, transaction kind '%s')",
PersistentFileSysObjName_TypeAndObjectName(&fileSysActionInfos[i].fsObjName),
i,
EndXactRecKind_Name(endXactRecKind));
persistentTidIsKnownResult = PersistentFileSysObj_TidIsKnown(
fileSysActionInfos[i].fsObjName.type,
&fileSysActionInfos[i].persistentTid,
&maxTid);
switch (persistentTidIsKnownResult)
{
case PersistentTidIsKnownResult_BeforePersistenceWork:
elog(ERROR, "Shouldn't being trying to verify persistent TID before persistence work");
break;
case PersistentTidIsKnownResult_ScanNotPerformedYet:
// UNDONE: For now, just debug log this.
if (Debug_persistent_print)
elog(Persistent_DebugPrintLevel(),
"Can't verify persistent TID if we haven't done the persistent scan yet");
break;
case PersistentTidIsKnownResult_MaxTidIsZero:
// UNDONE: For now, just debug log this.
if (Debug_persistent_print)
elog(Persistent_DebugPrintLevel(),
"TID for persistent '%s' tuple TID %s and the last known TID zero (0,0) (index %d, transaction kind '%s')",
PersistentFileSysObjName_TypeAndObjectName(&fileSysActionInfos[i].fsObjName),
ItemPointerToString(&fileSysActionInfos[i].persistentTid),
i,
EndXactRecKind_Name(endXactRecKind));
break;
case PersistentTidIsKnownResult_NotKnown:
// UNDONE: For now, just debug log this.
if (Debug_persistent_print)
elog(Persistent_DebugPrintLevel(),
"TID for persistent '%s' tuple TID %s is beyond the last known TID %s (index %d, transaction kind '%s')",
PersistentFileSysObjName_TypeAndObjectName(&fileSysActionInfos[i].fsObjName),
ItemPointerToString(&fileSysActionInfos[i].persistentTid),
ItemPointerToString2(&maxTid),
i,
EndXactRecKind_Name(endXactRecKind));
break;
case PersistentTidIsKnownResult_Known:
/* OK */
break;
default:
elog(ERROR, "Unexpected persistent file-system TID is known result: %d",
persistentTidIsKnownResult);
}
if (fileSysActionInfos[i].persistentSerialNum == 0)
elog(ERROR, "Persistent '%s' serial number is invalid (0) (index %d, transaction kind '%s')",
PersistentFileSysObjName_TypeAndObjectName(&fileSysActionInfos[i].fsObjName),
i,
EndXactRecKind_Name(endXactRecKind));
if (fileSysActionInfos[i].fsObjName.type == PersistentFsObjType_RelationFile &&
!PersistentFileSysRelStorageMgr_IsValid(fileSysActionInfos[i].relStorageMgr))
elog(ERROR, "Persistent '%s' relation storage manager has invalid value (%d) (index %d, transaction kind '%s')",
PersistentFileSysObjName_TypeAndObjectName(&fileSysActionInfos[i].fsObjName),
fileSysActionInfos[i].relStorageMgr,
i,
EndXactRecKind_Name(endXactRecKind));
}
}
void PersistentEndXactRec_AddFileSysActionInfos(
PersistentEndXactRecObjects *objects,
EndXactRecKind endXactRecKind,
PersistentEndXactFileSysActionInfo *fileSysActionInfos,
int count)
{
objects->typed.fileSysActionInfos = fileSysActionInfos;
objects->typed.fileSysActionInfosCount = count;
objects->typed.fileSysActionInfosLen = count * sizeof(PersistentEndXactFileSysActionInfo);
PersistentEndXactRec_VerifyFileSysActionInfos(
endXactRecKind,
fileSysActionInfos,
count);
}
int32 PersistentEndXactRec_FetchObjectsFromSmgr(
PersistentEndXactRecObjects *objects,
EndXactRecKind endXactRecKind,
int16 *objectCount)
{
int32 serializeLen;
int objKind;
void *data;
int32 count;
int32 len;
MemSet(objects, 0, sizeof(PersistentEndXactRecObjects));
*objectCount = 0;
serializeLen = 0;
for (objKind = 1; objKind < MaxPersistentEndXactObjKind; objKind++)
{
data = NULL;
count = 0;
len = 0;
switch (objKind)
{
case PersistentEndXactObjKind_FileSysAction:
count = smgrGetPendingFileSysWork(
endXactRecKind,
(PersistentEndXactFileSysActionInfo**)&data);
len = count * sizeof(PersistentEndXactFileSysActionInfo);
PersistentEndXactRec_VerifyFileSysActionInfos(
endXactRecKind,
(PersistentEndXactFileSysActionInfo*)data,
count);
break;
case PersistentEndXactObjKind_AppendOnlyMirrorResyncEofs:
break;
default:
elog(ERROR, "Unexpected persistent transaction object kind: %d",
objKind);
}
if (len > 0)
{
(*objectCount)++;
serializeLen += offsetof(PersistentEndXactRecObjHdr, p.data) + len;
PersistentEndXactRec_SetObjectInfo(
objects, objKind, data, count, len);
}
}
return serializeLen;
}
bool PersistentEndXactRec_WillHaveObjectsFromSmgr(
EndXactRecKind endXactRecKind)
{
int objKind;
for (objKind = 1; objKind < MaxPersistentEndXactObjKind; objKind++)
{
switch (objKind)
{
case PersistentEndXactObjKind_FileSysAction:
if (smgrIsPendingFileSysWork(endXactRecKind))
{
return true;
}
break;
case PersistentEndXactObjKind_AppendOnlyMirrorResyncEofs:
/*if (smgrIsAppendOnlyMirrorResyncEofs(endXactRecKind))
{
return true;
}*/
break;
default:
elog(ERROR, "Unexpected persistent transaction object kind: %d",
objKind);
}
}
return false;
}
int16 PersistentEndXactRec_ObjectCount(
PersistentEndXactRecObjects *objects,
EndXactRecKind endXactRecKind)
{
int16 objectCount;
int objKind;
uint8 *data;
int count;
int32 len;
objectCount = 0;
for (objKind = 1; objKind < MaxPersistentEndXactObjKind; objKind++)
{
PersistentEndXactRec_GetObjectInfo(
objects, objKind, &data, &count, &len);
if (len > 0)
{
objectCount++;
}
}
return objectCount;
}
int32 PersistentEndXactRec_SerializeLen(
PersistentEndXactRecObjects *objects,
EndXactRecKind endXactRecKind)
{
int32 fillLen;
int objKind;
uint8 *data;
int count;
int32 len;
fillLen = 0;
for (objKind = 1; objKind < MaxPersistentEndXactObjKind; objKind++)
{
PersistentEndXactRec_GetObjectInfo(
objects, objKind, &data, &count, &len);
if (len > 0)
{
fillLen += offsetof(PersistentEndXactRecObjHdr, p.data) + len;
}
}
return fillLen;
}
static void PersistentEndXactRec_AddSection(
uint8 *buffer,
int32 bufferLen,
int32 *currentLen,
PersistentEndXactObjKind objKind,
uint8 *data,
int32 len)
{
uint8 *next;
PersistentEndXactRecObjHdr *header;
const int headerLen = offsetof(PersistentEndXactRecObjHdr, p.data);
Assert(len > 0);
Assert(*currentLen + headerLen + len <= bufferLen);
next = &buffer[*currentLen];
header = (PersistentEndXactRecObjHdr*)next;
MemSet(header, 0, headerLen);
header->len = len;
header->objKind = objKind;
memcpy(header->p.data, data, len);
(*currentLen) += headerLen + len;
}
void PersistentEndXactRec_Serialize(
PersistentEndXactRecObjects *objects,
EndXactRecKind endXactRecKind,
int16 *numOfObjects,
uint8 *buffer,
int32 bufferLen)
{
int objKind;
int32 currentLen;
uint8 *data;
int count;
int32 len;
*numOfObjects = 0;
currentLen = 0;
for (objKind = 1; objKind < MaxPersistentEndXactObjKind; objKind++)
{
PersistentEndXactRec_GetObjectInfo(
objects, objKind, &data, &count, &len);
if (len > 0)
{
PersistentEndXactRec_AddSection(
buffer,
bufferLen,
&currentLen,
objKind,
data,
len);
(*numOfObjects)++;
}
}
if (currentLen != bufferLen)
{
elog(ERROR, "Persistent end transaction serialize length mismatch (actual %d, supplied %d)",
currentLen, bufferLen);
}
}
int32 PersistentEndXactRec_DeserializeLen(
uint8 *buffer,
int16 numOfObjects)
{
int deserializeLen;
int n;
PersistentEndXactRecObjHdr *header;
int32 len;
deserializeLen = 0;
header = (PersistentEndXactRecObjHdr*)buffer;
for (n = 0; n < numOfObjects; n++)
{
len = header->len;
deserializeLen += offsetof(PersistentEndXactRecObjHdr, p.data) + len;
header = (PersistentEndXactRecObjHdr*)&buffer[deserializeLen];
}
return deserializeLen;
}
void PersistentEndXactRec_Deserialize(
uint8 *buffer,
int16 numOfObjects,
PersistentEndXactRecObjects *objects,
uint8 **nextData)
{
int32 currentLen;
int n;
int objKind;
PersistentEndXactRecObjHdr *header;
int32 len;
uint8 *data;
int count;
MemSet(objects, 0, sizeof(PersistentEndXactRecObjects));
currentLen = 0;
header = (PersistentEndXactRecObjHdr*)buffer;
for (n = 0; n < numOfObjects; n++)
{
len = header->len;
objKind = header->objKind;
data = header->p.data;
count = PersistentEndXactRec_CountForObject(objKind, len);
PersistentEndXactRec_SetObjectInfo(
objects, objKind, data, count, len);
currentLen += offsetof(PersistentEndXactRecObjHdr, p.data) + len;
header = (PersistentEndXactRecObjHdr*)&buffer[currentLen];
}
*nextData = (uint8*)header;
}