blob: 14a2cbc9993aa9d263791f1ce3fd9fcc4e52b35f [file] [log] [blame]
/*
* 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.
*/
/*-------------------------------------------------------------------------
*
* cdbpersistentrelation.c
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "access/xlogmm.h"
#include "cdb/cdbpersistentrelation.h"
#include "cdb/cdbpersistentfilesysobj.h"
#include "commands/tablespace.h"
typedef struct PersistentRelationSharedData
{
PersistentFileSysObjSharedData fileSysObjSharedData;
} PersistentRelationSharedData;
#define PersistentRelationData_StaticInit {PersistentFileSysObjData_StaticInit}
typedef struct PersistentRelationData
{
PersistentFileSysObjData fileSysObjData;
} PersistentRelationData;
typedef struct RelationDirEntryKey
{
Oid tablespaceOid;
Oid databaseOid;
Oid relfilenodeOid;
} RelationDirEntryKey;
typedef struct RelationDirEntryData
{
RelationDirEntryKey key;
PersistentFileSysState state;
int64 persistentSerialNum;
ItemPointerData persistentTid;
} RelationDirEntryData;
typedef RelationDirEntryData *RelationDirEntry;
/*
* Global Variables
*/
PersistentRelationSharedData *persistentRelationSharedData = NULL;
static HTAB *persistentRelationSharedHashTable = NULL;
PersistentRelationData persistentRelationData = PersistentRelationData_StaticInit;
/*
* Variables for checking table space.
*/
static Oid persistentRelationCheckTablespace;
static int32 persistentRelationCheckTablespaceUseCount;
static RelFileNode persistentRelationCheckTablespaceRelationNode;
static bool PersistentRelation_CheckTablespaceScanTupleCallback(
ItemPointer persistentTid,
int64 persistentSerialNum,
Datum *values)
{
RelFileNode relFileNode;
PersistentFileSysState state;
int32 reserved;
TransactionId parentXid;
int64 serialNum;
ItemPointerData previousFreeTid;
bool sharedStorage;
GpPersistentRelationNode_GetValues(
values,
&relFileNode.spcNode,
&relFileNode.dbNode,
&relFileNode.relNode,
&state,
&reserved,
&parentXid,
&serialNum,
&previousFreeTid,
&sharedStorage);
if (state == PersistentFileSysState_Created &&
relFileNode.spcNode == persistentRelationCheckTablespace)
{
persistentRelationCheckTablespaceUseCount++;
if (persistentRelationCheckTablespaceUseCount == 1)
{
memcpy(&persistentRelationCheckTablespaceRelationNode, &relFileNode, sizeof(RelFileNode));
}
}
return true; // Continue;
}
void PersistentRelation_CheckTablespace(
Oid tablespace,
int32 *useCount,
RelFileNode *exampleRelationNode)
{
persistentRelationCheckTablespace = tablespace;
persistentRelationCheckTablespaceUseCount = 0;
MemSet(&persistentRelationCheckTablespaceRelationNode, 0, sizeof(RelFileNode));
PersistentFileSysObj_Scan(
PersistentFsObjType_RelationDir,
PersistentRelation_CheckTablespaceScanTupleCallback);
*useCount = persistentRelationCheckTablespaceUseCount;
memcpy(exampleRelationNode, &persistentRelationCheckTablespaceRelationNode, sizeof(RelFileNode));
}
static void PersistentRelation_VerifyInitScan(void)
{
if (persistentRelationSharedData == NULL)
{
elog(PANIC, "Persistent relation information shared-memory not setup");
}
PersistentFileSysObj_VerifyInitScan();
}
/*
* Return the hash entry for a relation.
*/
static RelationDirEntry
PersistentRelation_FindEntryUnderLock(
RelFileNode *relFileNode)
{
bool found;
RelationDirEntry relationDirEntry;
RelationDirEntryKey key;
elog(DEBUG1, "PersistentRelation_FindEntryUnderLock: Relation (%u/%u/%u)",
relFileNode->spcNode,
relFileNode->dbNode,
relFileNode->relNode);
if (persistentRelationSharedHashTable == NULL)
{
elog(PANIC, "Persistent relation information shared-memory not setup");
}
key.tablespaceOid = relFileNode->spcNode;
key.databaseOid = relFileNode->dbNode;
key.relfilenodeOid = relFileNode->relNode;
relationDirEntry = (RelationDirEntry)
hash_search(persistentRelationSharedHashTable,
(void *)&key,
HASH_FIND,
&found);
if (!found)
{
return NULL;
}
return relationDirEntry;
}
static RelationDirEntry
PersistentRelation_CreateEntryUnderLock(
RelFileNode *relFileNode)
{
bool found;
RelationDirEntry relationDirEntry;
RelationDirEntryKey key;
elog(DEBUG1, "PersistentRelation_CreateEntryUnderLock: relation (%u/%u/%u)",
relFileNode->spcNode,
relFileNode->dbNode,
relFileNode->relNode);
if (persistentRelationSharedHashTable == NULL)
{
elog(PANIC, "Persistent relation information shared-memory not setup");
}
key.tablespaceOid = relFileNode->spcNode;
key.databaseOid = relFileNode->dbNode;
key.relfilenodeOid = relFileNode->relNode;
relationDirEntry = (RelationDirEntry)
hash_search(persistentRelationSharedHashTable,
(void *)&key,
HASH_ENTER,
&found);
if (relationDirEntry == NULL)
{
return NULL;
}
relationDirEntry->state = PersistentFileSysState_Free;
relationDirEntry->persistentSerialNum = 0;
MemSet(&relationDirEntry->persistentTid, 0, sizeof(ItemPointerData));
return relationDirEntry;
}
static void
PersistentRelation_RemoveEntryUnderLock(
RelationDirEntry relationDirEntry)
{
RelationDirEntry removeRelationDirEntry;
if (persistentRelationSharedHashTable == NULL)
{
elog(PANIC, "Persistent relation information shared-memory not setup");
}
removeRelationDirEntry = (RelationDirEntry)
hash_search(persistentRelationSharedHashTable,
(void *) &relationDirEntry->key,
HASH_REMOVE,
NULL);
if (removeRelationDirEntry == NULL)
{
elog(ERROR, "Trying to delete entry that does not exist");
}
}
PersistentFileSysState
PersistentRelation_GetState(
RelFileNode *relFileNode)
{
READ_PERSISTENT_STATE_ORDERED_LOCK_DECLARE;
RelationDirEntry relationDirEntry;
PersistentFileSysState state;
PersistentRelation_VerifyInitScan();
READ_PERSISTENT_STATE_ORDERED_LOCK;
relationDirEntry = PersistentRelation_FindEntryUnderLock(relFileNode);
if (relationDirEntry == NULL)
{
elog(ERROR, "Did not find persistent relation entry %u/%u/%u",
relFileNode->spcNode,
relFileNode->dbNode,
relFileNode->relNode);
}
state = relationDirEntry->state;
READ_PERSISTENT_STATE_ORDERED_UNLOCK;
return state;
}
static bool
PersistentRelation_ScanTupleCallback(
ItemPointer persistentTid,
int64 persistentSerialNum,
Datum *values)
{
RelFileNode relFileNode;
PersistentFileSysState state;
int32 reserved;
TransactionId parentXid;
int64 serialNum;
ItemPointerData previousFreeTid;
RelationDirEntry relationDirEntry;
bool sharedStorage;
GpPersistentRelationNode_GetValues(
values,
&relFileNode.spcNode,
&relFileNode.dbNode,
&relFileNode.relNode,
&state,
&reserved,
&parentXid,
&serialNum,
&previousFreeTid,
&sharedStorage);
if (state == PersistentFileSysState_Free)
{
if (Debug_persistent_print)
{
elog(Persistent_DebugPrintLevel(),
"PersistentRelation_ScanTupleCallback: TID %s, serial number " INT64_FORMAT " is free",
ItemPointerToString2(persistentTid),
persistentSerialNum);
}
return true;
}
relationDirEntry = PersistentRelation_CreateEntryUnderLock(&relFileNode);
if (relationDirEntry == NULL)
{
elog(ERROR, "Out of shared-memory for persistent relations");
}
relationDirEntry->state = state;
relationDirEntry->persistentSerialNum = serialNum;
relationDirEntry->persistentTid = *persistentTid;
if (Debug_persistent_print)
{
elog(Persistent_DebugPrintLevel(),
"PersistentRelation_ScanTupleCallback: tablespace %u, database %u, relation %u, state %s, TID %s, serial number " INT64_FORMAT,
relFileNode.spcNode,
relFileNode.dbNode,
relFileNode.relNode,
PersistentFileSysObjState_Name(state),
ItemPointerToString2(persistentTid),
persistentSerialNum);
}
return true;
}
void PersistentRelation_Reset(void)
{
HASH_SEQ_STATUS stat;
RelationDirEntry relationDirEntry;
hash_seq_init(&stat, persistentRelationSharedHashTable);
while (true)
{
RelationDirEntry removeRelationDirEntry;
PersistentFileSysObjName fsObjName;
RelFileNode relFileNode;
relationDirEntry = hash_seq_search(&stat);
if (relationDirEntry == NULL)
{
break;
}
relFileNode.spcNode = relationDirEntry->key.tablespaceOid;
relFileNode.dbNode = relationDirEntry->key.databaseOid;
relFileNode.relNode = relationDirEntry->key.relfilenodeOid;
PersistentFileSysObjName_SetRelationDir(
&fsObjName,
&relFileNode,
is_tablespace_shared);
if (Debug_persistent_print)
{
elog(Persistent_DebugPrintLevel(),
"Persistent relation directory: Resetting '%s' serial number " INT64_FORMAT " at TID %s",
PersistentFileSysObjName_ObjectName(&fsObjName),
relationDirEntry->persistentSerialNum,
ItemPointerToString(&relationDirEntry->persistentTid));
}
removeRelationDirEntry = (RelationDirEntry)
hash_search(persistentRelationSharedHashTable,
(void *) &relationDirEntry->key,
HASH_REMOVE,
NULL);
if (removeRelationDirEntry == NULL)
{
elog(ERROR, "Trying to delete entry that does not exist");
}
}
}
void
PersistentRelation_LookupTidAndSerialNum(
RelFileNode *relFileNode,
ItemPointer persistentTid,
int64 *persistentSerialNum)
{
READ_PERSISTENT_STATE_ORDERED_LOCK_DECLARE;
RelationDirEntry relationDirEntry;
PersistentRelation_VerifyInitScan();
READ_PERSISTENT_STATE_ORDERED_LOCK;
relationDirEntry = PersistentRelation_FindEntryUnderLock(relFileNode);
if (relationDirEntry == NULL)
{
elog(ERROR, "Did not find persistent relation entry %u/%u/%u",
relFileNode->spcNode,
relFileNode->dbNode,
relFileNode->relNode);
}
*persistentTid = relationDirEntry->persistentTid;
*persistentSerialNum = relationDirEntry->persistentSerialNum;
READ_PERSISTENT_STATE_ORDERED_UNLOCK;
}
// -----------------------------------------------------------------------------
// Shmem
// -----------------------------------------------------------------------------
static Size PersistentRelation_SharedDataSize(void)
{
return MAXALIGN(sizeof(PersistentRelationSharedData));
}
/*
* Return the required shared-memory size for this module.
*/
Size PersistentRelation_ShmemSize(void)
{
Size size;
/* The hash table of persistent relations */
size = hash_estimate_size((Size)gp_max_relations,
sizeof(RelationDirEntryData));
/* The shared-memory structure. */
size = add_size(size, PersistentRelation_SharedDataSize());
elog(LOG, "PersistentRelation_ShmemSize: %zu = "
"gp_max_relations: %d "
"* sizeof(RelationDirEntryData): %zu "
"+ PersistentRelation_SharedDataSize(): %zu",
size,
gp_max_relations,
sizeof(RelationDirEntryData),
PersistentRelation_SharedDataSize());
return size;
}
/*
* PersistentRelation_HashTableInit
*
* Create or find shared-memory hash table.
*/
static bool
PersistentRelation_HashTableInit(void)
{
HASHCTL info;
int hash_flags;
/* Set key and entry sizes. */
MemSet(&info, 0, sizeof(info));
info.keysize = sizeof(RelationDirEntryKey);
info.entrysize = sizeof(RelationDirEntryData);
info.hash = tag_hash;
hash_flags = (HASH_ELEM | HASH_FUNCTION);
persistentRelationSharedHashTable =
ShmemInitHash("Persistent Relation Hash",
gp_max_relations,
gp_max_relations,
&info,
hash_flags);
if (persistentRelationSharedHashTable == NULL)
{
return false;
}
return true;
}
/*
* Initialize the shared-memory for this module.
*/
void PersistentRelation_ShmemInit(void)
{
bool found;
bool ok;
/* Create the shared-memory structure. */
persistentRelationSharedData =
(PersistentRelationSharedData *)
ShmemInitStruct("Mirrored Relation Data",
PersistentRelation_SharedDataSize(),
&found);
if (!found)
{
PersistentFileSysObj_InitShared(
&persistentRelationSharedData->fileSysObjSharedData);
}
/* Create or find our shared-memory hash table. */
ok = PersistentRelation_HashTableInit();
if (!ok)
{
ereport(FATAL,
(errcode(ERRCODE_OUT_OF_MEMORY),
errmsg("Not enough shared memory for persistent relation hash table")));
}
PersistentFileSysObj_Init(
&persistentRelationData.fileSysObjData,
&persistentRelationSharedData->fileSysObjSharedData,
PersistentFsObjType_RelationDir,
PersistentRelation_ScanTupleCallback);
Assert(persistentRelationSharedData != NULL);
Assert(persistentRelationSharedHashTable != NULL);
}
void PersistentRelation_MarkCreatePending(
RelFileNode *relFileNode,
ItemPointer persistentTid,
int64 *persistentSerialNum,
bool flushToXLog)
{
WRITE_PERSISTENT_STATE_ORDERED_LOCK_DECLARE;
PersistentFileSysObjName fsObjName;
RelationDirEntry relationDirEntry;
ItemPointerData previousFreeTid;
Datum values[Natts_gp_persistent_relation_node];
if (RelFileNode_IsEmpty(relFileNode))
{
elog(ERROR, "Invalid RelFileNode (0,0,0)");
}
MemSet(&previousFreeTid, 0, sizeof(ItemPointerData));
if (Persistent_BeforePersistenceWork())
{
if (Debug_persistent_print)
{
elog(Persistent_DebugPrintLevel(),
"Skipping persistent relation '%s' because we are before persistence work",
relpath(*relFileNode));
}
*persistentSerialNum = 0;
/*
* The initdb process will load the persistent table once we out
* of bootstrap mode.
*/
return;
}
PersistentRelation_VerifyInitScan();
PersistentFileSysObjName_SetRelationDir(
&fsObjName,
relFileNode,
is_tablespace_shared);
WRITE_PERSISTENT_STATE_ORDERED_LOCK;
relationDirEntry = PersistentRelation_CreateEntryUnderLock(relFileNode);
if (relationDirEntry == NULL)
{
/* If out of shared memory, no need to promote to PANIC. */
WRITE_PERSISTENT_STATE_ORDERED_UNLOCK;
ereport(ERROR,
(errcode(ERRCODE_OUT_OF_MEMORY),
errmsg("Out of shared-memory for persistent relations"),
errhint("You may need to increase the gp_max_relations value"),
errOmitLocation(true)));
}
relationDirEntry->state = PersistentFileSysState_CreatePending;
GpPersistentRelationNode_SetDatumValues(
values,
relFileNode->spcNode,
relFileNode->dbNode,
relFileNode->relNode,
PersistentFileSysState_CreatePending,
/* reserved */ 0,
/* parentXid */ GetTopTransactionId(),
/* persistentSerialNum */ 0, // This will be set by PersistentFileSysObj_AddTuple.
&previousFreeTid,
is_tablespace_shared(relFileNode->spcNode));
PersistentFileSysObj_AddTuple(
PersistentFsObjType_RelationDir,
values,
flushToXLog,
&relationDirEntry->persistentTid,
&relationDirEntry->persistentSerialNum);
*persistentTid = relationDirEntry->persistentTid;
*persistentSerialNum = relationDirEntry->persistentSerialNum;
/*
* This XLOG must be generated under the persistent write-lock.
*/
#ifdef MASTER_MIRROR_SYNC
mmxlog_log_create_relation(
relFileNode->spcNode,
relFileNode->dbNode,
relFileNode->relNode,
persistentTid, *persistentSerialNum);
#endif
/*
* MPP-18228
* To make adding 'Create Pending' entry to persistent table and
* adding to the PendingDelete list atomic
*/
PendingDelete_AddCreatePendingEntryWrapper(
&fsObjName,
persistentTid,
*persistentSerialNum);
WRITE_PERSISTENT_STATE_ORDERED_UNLOCK;
}
void PersistentRelation_AddCreated(
RelFileNode *relFileNode,
ItemPointer persistentTid,
int64 *persistentSerialNum,
bool flushToXLog)
{
WRITE_PERSISTENT_STATE_ORDERED_LOCK_DECLARE;
PersistentFileSysObjName fsObjName;
RelationDirEntry relationDirEntry;
ItemPointerData previousFreeTid;
Datum values[Natts_gp_persistent_relation_node];
if (RelFileNode_IsEmpty(relFileNode))
{
elog(ERROR, "Invalid RelFileNode (0,0,0)");
}
MemSet(&previousFreeTid, 0, sizeof(ItemPointerData));
if (!Persistent_BeforePersistenceWork())
{
elog(ERROR, "We can only add to persistent meta-data when special states");
}
/* Verify PersistentFileSysObj_BuildInitScan has been called */
PersistentRelation_VerifyInitScan();
PersistentFileSysObjName_SetRelationDir(
&fsObjName,
relFileNode,
is_tablespace_shared);
WRITE_PERSISTENT_STATE_ORDERED_LOCK;
relationDirEntry = PersistentRelation_CreateEntryUnderLock(relFileNode);
if (relationDirEntry == NULL)
{
/* If out of shared memory, no need to promote to PANIC. */
WRITE_PERSISTENT_STATE_ORDERED_UNLOCK;
ereport(ERROR,
(errcode(ERRCODE_OUT_OF_MEMORY),
errmsg("Out of shared-memory for persistent relations"),
errhint("You may need to increase the gp_max_relations value"),
errOmitLocation(true)));
}
relationDirEntry->state = PersistentFileSysState_Created;
GpPersistentRelationNode_SetDatumValues(
values,
relFileNode->spcNode,
relFileNode->dbNode,
relFileNode->relNode,
PersistentFileSysState_Created,
/* reserved */ 0,
/* parentXid */ InvalidTransactionId,
/* persistentSerialNum */ 0,
&previousFreeTid,
is_tablespace_shared(relFileNode->spcNode));
PersistentFileSysObj_AddTuple(
PersistentFsObjType_RelationDir,
values,
flushToXLog,
&relationDirEntry->persistentTid,
&relationDirEntry->persistentSerialNum);
*persistentTid = relationDirEntry->persistentTid;
*persistentSerialNum = relationDirEntry->persistentSerialNum;
WRITE_PERSISTENT_STATE_ORDERED_UNLOCK;
if (Debug_persistent_print)
{
elog(Persistent_DebugPrintLevel(),
"Persistent relation: Add '%s', in state 'Created', serial number " INT64_FORMAT " at TID %s",
PersistentFileSysObjName_ObjectName(&fsObjName),
*persistentSerialNum,
ItemPointerToString(persistentTid));
}
}
void PersistentRelation_Created(
PersistentFileSysObjName *fsObjName,
ItemPointer persistentTid,
int64 persistentSerialNum,
bool retryPossible)
{
WRITE_PERSISTENT_STATE_ORDERED_LOCK_DECLARE;
RelFileNode *relFileNode = &fsObjName->variant.rel.relFileNode;
RelationDirEntry relationDirEntry;
PersistentFileSysObjStateChangeResult stateChangeResult;
if (RelFileNode_IsEmpty(relFileNode))
{
elog(ERROR, "Invalid RelFileNode (0,0,0)");
}
if (Persistent_BeforePersistenceWork())
{
if (Debug_persistent_print)
{
elog(Persistent_DebugPrintLevel(),
"Skipping persistent relation '%s' because we are before persistence work",
relpath(*relFileNode));
}
/*
* The initdb process will load the persistent table once we out of bootstrap mode.
*/
return;
}
PersistentRelation_VerifyInitScan();
/*
* Do this check after skipping out if in bootstrap mode.
*/
if (PersistentStore_IsZeroTid(persistentTid))
{
elog(ERROR, "TID for persistent '%s' tuple for 'Created is invalid (0,0)",
PersistentFileSysObjName_TypeAndObjectName(fsObjName));
}
if (persistentSerialNum == 0)
{
elog(ERROR, "Persistent '%s' serial number for 'Created' is invalid (0)",
PersistentFileSysObjName_TypeAndObjectName(fsObjName));
}
WRITE_PERSISTENT_STATE_ORDERED_LOCK;
relationDirEntry = PersistentRelation_FindEntryUnderLock(relFileNode);
if (relationDirEntry == NULL)
{
elog(ERROR, "Did not find persistent relation entry %u/%u/%u",
relFileNode->spcNode,
relFileNode->dbNode,
relFileNode->relNode);
}
if (relationDirEntry->state != PersistentFileSysState_CreatePending)
{
elog(ERROR, "Persistent relation entry %u/%u/%u expected to be in 'Create Pending' state (actual state '%s')",
relFileNode->spcNode,
relFileNode->dbNode,
relFileNode->relNode,
PersistentFileSysObjState_Name(relationDirEntry->state));
}
stateChangeResult = PersistentFileSysObj_StateChange(
fsObjName,
persistentTid,
persistentSerialNum,
PersistentFileSysState_Created,
retryPossible,
/* flushToXLog */ false,
/* oldState */ NULL,
/* verifiedActionCallback */ NULL);
relationDirEntry->state = PersistentFileSysState_Created;
WRITE_PERSISTENT_STATE_ORDERED_UNLOCK;
if (Debug_persistent_print)
{
elog(Persistent_DebugPrintLevel(),
"Persistent relation: '%s' changed state from 'Create Pending' to 'Created', serial number " INT64_FORMAT "at TID %s (State-Change result '%s')",
PersistentFileSysObjName_ObjectName(fsObjName),
persistentSerialNum,
ItemPointerToString(persistentTid),
PersistentFileSysObjStateChangeResult_Name(stateChangeResult));
}
return ;
}
PersistentFileSysObjStateChangeResult PersistentRelation_MarkDropPending(
PersistentFileSysObjName *fsObjName,
ItemPointer persistentTid,
int64 persistentSerialNum,
bool retryPossible)
{
WRITE_PERSISTENT_STATE_ORDERED_LOCK_DECLARE;
RelFileNode *relFileNode = &fsObjName->variant.rel.relFileNode;
RelationDirEntry relationDirEntry;
PersistentFileSysState oldState;
PersistentFileSysObjStateChangeResult stateChangeResult;
if (RelFileNode_IsEmpty(relFileNode))
{
elog(ERROR, "Invalid RelFileNode (0,0,0)");
}
if (Persistent_BeforePersistenceWork())
{
if (Debug_persistent_print)
{
elog(Persistent_DebugPrintLevel(),
"Skipping persistent relation '%s' because we are before persistence work",
relpath(*relFileNode));
/*
* The initdb process will load the persistent table once we out of bootstrap mode.
*/
return PersistentFileSysObjStateChangeResult_None;
}
}
PersistentRelation_VerifyInitScan();
/*
* Do this check after skipping out if in bootstrap mode.
*/
if (PersistentStore_IsZeroTid(persistentTid))
{
elog(ERROR, "TID for persisent '%s' tuple for mark DROP pending is invalid (0,0)",
PersistentFileSysObjName_TypeAndObjectName(fsObjName));
}
if (persistentSerialNum == 0)
{
elog(ERROR, "Persistent '%s' serial number for mark DROP pending is valid (0)",
PersistentFileSysObjName_TypeAndObjectName(fsObjName));
}
WRITE_PERSISTENT_STATE_ORDERED_LOCK;
relationDirEntry = PersistentRelation_FindEntryUnderLock(relFileNode);
if (relationDirEntry == NULL)
{
elog(ERROR, "Did not find persistent relation entry %u/%u/%u",
relFileNode->spcNode,
relFileNode->dbNode,
relFileNode->relNode);
}
if ((relationDirEntry->state != PersistentFileSysState_CreatePending) &&
(relationDirEntry->state != PersistentFileSysState_Created))
{
elog(ERROR, "Persistent relation entry %u/%u/%u expected to be in 'Create Pending' or 'Created' state (actual state '%s')",
relFileNode->spcNode,
relFileNode->dbNode,
relFileNode->relNode,
PersistentFileSysObjState_Name(relationDirEntry->state));
}
stateChangeResult = PersistentFileSysObj_StateChange(
fsObjName,
persistentTid,
persistentSerialNum,
PersistentFileSysState_DropPending,
retryPossible,
/* flushToXLog */ false,
&oldState,
/* verfifiedActionCallback */ NULL);
relationDirEntry->state = PersistentFileSysState_DropPending;
WRITE_PERSISTENT_STATE_ORDERED_UNLOCK;
if (Debug_persistent_print)
{
elog(Persistent_DebugPrintLevel(),
"Persistent relation: '%s' changed state from '%s' to 'Drop Pending', serial number " INT64_FORMAT " TID %s (State-Change result '%s')",
PersistentFileSysObjName_ObjectName(fsObjName),
PersistentFileSysObjState_Name(oldState),
persistentSerialNum,
ItemPointerToString(persistentTid),
PersistentFileSysObjStateChangeResult_Name(stateChangeResult));
}
return stateChangeResult;
}
PersistentFileSysObjStateChangeResult PersistentRelation_MarkAbortingCreate(
PersistentFileSysObjName *fsObjName,
ItemPointer persistentTid,
int64 persistentSerialNum,
bool retryPossible)
{
WRITE_PERSISTENT_STATE_ORDERED_LOCK_DECLARE;
RelFileNode *relFileNode = &fsObjName->variant.rel.relFileNode;
RelationDirEntry relationDirEntry;
PersistentFileSysObjStateChangeResult stateChangeResult;
if (RelFileNode_IsEmpty(relFileNode))
{
elog(ERROR, "Invalid RelFileNode (0,0,0)");
}
if (Persistent_BeforePersistenceWork())
{
if (Debug_persistent_print)
{
elog(Persistent_DebugPrintLevel(),
"Skipping persistent relation '%s' because we are before persistence work",
relpath(*relFileNode));
/*
* The initdb process will load the persistent table once we out of bootstrap mode.
*/
return PersistentFileSysObjStateChangeResult_None;
}
}
PersistentRelation_VerifyInitScan();
/*
* Do this check after skipping out if in bootstrap mode.
*/
if (PersistentStore_IsZeroTid(persistentTid))
{
elog(ERROR, "TID for persistent '%s' tuple for mark DROP pending is invalid (0,0)",
PersistentFileSysObjName_TypeAndObjectName(fsObjName));
}
if (persistentSerialNum == 0)
{
elog(ERROR, "Persistent '%s' serial number for mark DROP pending is invalid (0)",
PersistentFileSysObjName_TypeAndObjectName(fsObjName));
}
WRITE_PERSISTENT_STATE_ORDERED_LOCK;
relationDirEntry = PersistentRelation_FindEntryUnderLock(relFileNode);
if (relationDirEntry == NULL)
{
elog(ERROR, "Did not find persistent relation entry %u/%u/%u",
relFileNode->spcNode,
relFileNode->dbNode,
relFileNode->relNode);
}
if (relationDirEntry->state != PersistentFileSysState_CreatePending)
{
elog(ERROR, "Persistent relation entry %u/%u/%u expected to be in 'Create Pending' (actual state '%s')",
relFileNode->spcNode,
relFileNode->dbNode,
relFileNode->relNode,
PersistentFileSysObjState_Name(relationDirEntry->state));
}
stateChangeResult = PersistentFileSysObj_StateChange(
fsObjName,
persistentTid,
persistentSerialNum,
PersistentFileSysState_AbortingCreate,
retryPossible,
/* flushToXLog */ false,
/* oldState */ NULL,
/* verifiedActionCallback */ NULL);
relationDirEntry->state = PersistentFileSysState_AbortingCreate;
WRITE_PERSISTENT_STATE_ORDERED_UNLOCK;
if (Debug_persistent_print)
{
elog(Persistent_DebugPrintLevel(),
"Persistent relation: '%s' changed state from 'Create Pending' to 'Aborting Create', serial number " INT64_FORMAT " at TID %s (State-Change result '%s')",
PersistentFileSysObjName_ObjectName(fsObjName),
persistentSerialNum,
ItemPointerToString(persistentTid),
PersistentFileSysObjStateChangeResult_Name(stateChangeResult));
}
return stateChangeResult;
}
static void
PersistentRelation_DroppedVerifiedActionCallback(
PersistentFileSysObjName *fsObjName,
ItemPointer persistentTid,
int64 persistentSerialNum,
PersistentFileSysObjVerifyExpectedResult verifyExpectedResult)
{
RelFileNode *relFileNode = &fsObjName->variant.rel.relFileNode;
switch(verifyExpectedResult)
{
case PersistentFileSysObjVerifyExpectedResult_DeleteUnnecessary:
case PersistentFileSysObjVerifyExpectedResult_StateChangeAlreadyDone:
case PersistentFileSysObjVerifyExpectedResult_ErrorSuppressed:
break;
case PersistentFileSysObjVerifyExpectedResult_StateChangeNeeded:
/*
* This XLOG must be generated under the persistent write-lock.
*/
#ifdef MASTER_MIRROR_SYNC
mmxlog_log_remove_relation(relFileNode->spcNode, relFileNode->dbNode, relFileNode->relNode,
persistentTid, persistentSerialNum);
#endif
break;
default:
elog(ERROR, "Unexpected persistent object verify expected result: %d",
verifyExpectedResult);
}
}
void PersistentRelation_Dropped(
PersistentFileSysObjName *fsObjName,
ItemPointer persistentTid,
int64 persistentSerialNum)
{
WRITE_PERSISTENT_STATE_ORDERED_LOCK_DECLARE;
RelFileNode *relFileNode = &fsObjName->variant.rel.relFileNode;
RelationDirEntry relationDirEntry;
PersistentFileSysState oldState;
PersistentFileSysObjStateChangeResult stateChangeResult;
if (RelFileNode_IsEmpty(relFileNode))
{
elog(ERROR, "Invalid RelFileNode (0,0,0)");
}
if (Persistent_BeforePersistenceWork())
{
if (Debug_persistent_print)
{
elog(Persistent_DebugPrintLevel(),
"Skipping persistent relation '%s' because we are before persistence work",
relpath(*relFileNode));
}
/*
* The initdb process will load the persistent table once we out of bootstrap mode.
*/
}
PersistentRelation_VerifyInitScan();
/*
* Do this check after skipping out if in bootstrap mode.
*/
if (PersistentStore_IsZeroTid(persistentTid))
{
elog(ERROR, "TID for persistent '%s' tuple for mark DROP pending is invalid (0,0)",
PersistentFileSysObjName_TypeAndObjectName(fsObjName));
}
if (persistentSerialNum == 0)
{
elog(ERROR, "Persistent '%s' serial number for mark DROP pending is invalid (0)",
PersistentFileSysObjName_TypeAndObjectName(fsObjName));
}
WRITE_PERSISTENT_STATE_ORDERED_LOCK;
relationDirEntry = PersistentRelation_FindEntryUnderLock(relFileNode);
if (relationDirEntry == NULL)
{
elog(ERROR, "Did not find persistent relation entry %u/%u/%u",
relFileNode->spcNode,
relFileNode->dbNode,
relFileNode->relNode);
}
if ((relationDirEntry->state != PersistentFileSysState_DropPending) &&
(relationDirEntry->state != PersistentFileSysState_AbortingCreate))
{
elog(ERROR, "Persistent relation entry %u/%u/%u expected to be in 'Drop Pending' or 'Aborting Create' (actual state '%s')",
relFileNode->spcNode,
relFileNode->dbNode,
relFileNode->relNode,
PersistentFileSysObjState_Name(relationDirEntry->state));
}
stateChangeResult = PersistentFileSysObj_StateChange(
fsObjName,
persistentTid,
persistentSerialNum,
PersistentFileSysState_Free,
/* retryPossible */ false,
/* flushToXLog */ false,
&oldState,
PersistentRelation_DroppedVerifiedActionCallback);
relationDirEntry->state = PersistentFileSysState_Free;
PersistentRelation_RemoveEntryUnderLock(relationDirEntry);
WRITE_PERSISTENT_STATE_ORDERED_UNLOCK;
if (Debug_persistent_print)
{
elog(Persistent_DebugPrintLevel(),
"Persistent relation: '%s' changed state from '%s' to (Free), serial number " INT64_FORMAT " at TID %s (State-Change result '%s')",
PersistentFileSysObjName_ObjectName(fsObjName),
PersistentFileSysObjState_Name(oldState),
persistentSerialNum,
ItemPointerToString(persistentTid),
PersistentFileSysObjStateChangeResult_Name(stateChangeResult));
}
}