blob: 2d009cf4de1566f396415d277de960a76ab1b534 [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.
*/
/*-------------------------------------------------------------------------
*
* cdbpersistentfilespace.c
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "miscadmin.h"
#include "pgstat.h"
#include "utils/palloc.h"
#include "storage/fd.h"
#include "storage/relfilenode.h"
#include "access/genam.h"
#include "access/heapam.h"
#include "access/persistentfilesysobjname.h"
#include "access/transam.h"
#include "access/xlogmm.h"
#include "catalog/catalog.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_authid.h"
#include "catalog/pg_filespace.h"
#include "catalog/pg_filespace_entry.h"
#include "catalog/pg_database.h"
#include "catalog/gp_persistent.h"
#include "catalog/gp_segment_config.h"
#include "cdb/cdbmirroredfilesysobj.h"
#include "postmaster/postmaster.h"
#include "postmaster/primary_mirror_mode.h"
#include "storage/ipc.h"
#include "storage/itemptr.h"
#include "storage/shmem.h"
#include "storage/smgr.h"
#include "utils/guc.h"
#include "utils/hsearch.h"
#include "utils/builtins.h"
#include "utils/fmgroids.h"
#include "utils/faultinjector.h"
#include "cdb/cdbvars.h"
#include "cdb/cdbsharedoidsearch.h"
#include "cdb/cdbdirectopen.h"
#include "cdb/cdbpersistentstore.h"
#include "cdb/cdbpersistentfilesysobj.h"
#include "cdb/cdbpersistentfilespace.h"
#include "commands/filespace.h"
typedef struct PersistentFilespaceSharedData
{
PersistentFileSysObjSharedData fileSysObjSharedData;
} PersistentFilespaceSharedData;
#define PersistentFilespaceData_StaticInit {PersistentFileSysObjData_StaticInit}
typedef struct PersistentFilespaceData
{
PersistentFileSysObjData fileSysObjData;
} PersistentFilespaceData;
typedef struct FilespaceDirEntryKey
{
Oid filespaceOid;
} FilespaceDirEntryKey;
typedef struct FilespaceDirEntryData
{
FilespaceDirEntryKey key;
char locationBlankPadded1[FilespaceLocationBlankPaddedWithNullTermLen];
PersistentFileSysState state;
int64 persistentSerialNum;
ItemPointerData persistentTid;
} FilespaceDirEntryData;
typedef FilespaceDirEntryData *FilespaceDirEntry;
/*
* Global Variables
*/
PersistentFilespaceSharedData *persistentFilespaceSharedData = NULL;
static HTAB *persistentFilespaceSharedHashTable = NULL;
PersistentFilespaceData persistentFilespaceData = PersistentFilespaceData_StaticInit;
static void PersistentFilespace_VerifyInitScan(void)
{
if (persistentFilespaceSharedData == NULL)
elog(PANIC, "Persistent filespace information shared-memory not setup");
PersistentFileSysObj_VerifyInitScan();
}
/*
* Return the hash entry for a filespace.
*/
static FilespaceDirEntry
PersistentFilespace_FindDirUnderLock(
Oid filespaceOid)
{
bool found;
FilespaceDirEntry filespaceDirEntry;
FilespaceDirEntryKey key;
elog(DEBUG1, "PersistentFilespace_FindDirUnderLock: filespace %d", filespaceOid);
if (persistentFilespaceSharedHashTable == NULL)
elog(PANIC, "Persistent filespace information shared-memory not setup");
key.filespaceOid = filespaceOid;
filespaceDirEntry =
(FilespaceDirEntry)
hash_search(persistentFilespaceSharedHashTable,
(void *) &key,
HASH_FIND,
&found);
if (!found)
return NULL;
return filespaceDirEntry;
}
static FilespaceDirEntry
PersistentFilespace_CreateDirUnderLock(
Oid filespaceOid)
{
bool found;
FilespaceDirEntry filespaceDirEntry;
FilespaceDirEntryKey key;
elog(DEBUG1, "PersistentFilespace_CreateDirUnderLock: filespace %d", filespaceOid);
if (persistentFilespaceSharedHashTable == NULL)
elog(PANIC, "Persistent filespace information shared-memory not setup");
key.filespaceOid = filespaceOid;
filespaceDirEntry =
(FilespaceDirEntry)
hash_search(persistentFilespaceSharedHashTable,
(void *) &key,
HASH_ENTER_NULL,
&found);
if (filespaceDirEntry == NULL)
return NULL;
filespaceDirEntry->state = 0;
filespaceDirEntry->persistentSerialNum = 0;
MemSet(&filespaceDirEntry->persistentTid, 0, sizeof(ItemPointerData));
memset(filespaceDirEntry->locationBlankPadded1, ' ', FilespaceLocationBlankPaddedWithNullTermLen);
filespaceDirEntry->locationBlankPadded1[FilespaceLocationBlankPaddedWithNullTermLen-1]='\0';
return filespaceDirEntry;
}
static void
PersistentFilespace_RemoveDirUnderLock(
FilespaceDirEntry filespaceDirEntry)
{
FilespaceDirEntry removeFilespaceDirEntry;
if (persistentFilespaceSharedHashTable == NULL)
elog(PANIC, "Persistent filespace information shared-memory not setup");
removeFilespaceDirEntry =
(FilespaceDirEntry)
hash_search(persistentFilespaceSharedHashTable,
(void *) &filespaceDirEntry->key,
HASH_REMOVE,
NULL);
if (removeFilespaceDirEntry == NULL)
elog(ERROR, "Trying to delete entry that does not exist");
}
// -----------------------------------------------------------------------------
// Scan
// -----------------------------------------------------------------------------
static bool PersistentFilespace_ScanTupleCallback(
ItemPointer persistentTid,
int64 persistentSerialNum,
Datum *values)
{
Oid filespaceOid;
int16 dbId1;
char locationBlankPadded1[FilespaceLocationBlankPaddedWithNullTermLen];
PersistentFileSysState state;
int32 reserved;
TransactionId parentXid;
int64 serialNum;
ItemPointerData previousFreeTid;
FilespaceDirEntry filespaceDirEntry;
bool sharedStorage;
GpPersistentFilespaceNode_GetValues(
values,
&filespaceOid,
&dbId1,
locationBlankPadded1,
&state,
&reserved,
&parentXid,
&serialNum,
&previousFreeTid,
&sharedStorage);
if (state == PersistentFileSysState_Free)
{
if (Debug_persistent_print)
elog(Persistent_DebugPrintLevel(),
"PersistentFilespace_ScanTupleCallback: TID %s, serial number " INT64_FORMAT " is free",
ItemPointerToString2(persistentTid),
persistentSerialNum);
return true; // Continue.
}
filespaceDirEntry =
PersistentFilespace_CreateDirUnderLock(
filespaceOid);
if (filespaceDirEntry == NULL)
elog(ERROR, "Out of shared-memory for persistent filespaces");
memcpy(filespaceDirEntry->locationBlankPadded1, locationBlankPadded1, FilespaceLocationBlankPaddedWithNullTermLen);
filespaceDirEntry->state = state;
filespaceDirEntry->persistentSerialNum = serialNum;
filespaceDirEntry->persistentTid = *persistentTid;
if (Debug_persistent_print)
elog(Persistent_DebugPrintLevel(),
"PersistentFilespace_ScanTupleCallback: filespace %u, dbId1 %d, state '%s', TID %s, serial number " INT64_FORMAT,
filespaceOid,
dbId1,
PersistentFileSysObjState_Name(state),
ItemPointerToString2(persistentTid),
persistentSerialNum);
return true; // Continue.
}
//------------------------------------------------------------------------------
void PersistentFilespace_Reset(void)
{
HASH_SEQ_STATUS stat;
FilespaceDirEntry filespaceDirEntry;
hash_seq_init(&stat, persistentFilespaceSharedHashTable);
while (true)
{
FilespaceDirEntry removeFilespaceDirEntry;
PersistentFileSysObjName fsObjName;
filespaceDirEntry = hash_seq_search(&stat);
if (filespaceDirEntry == NULL)
break;
PersistentFileSysObjName_SetFilespaceDir(
&fsObjName,
filespaceDirEntry->key.filespaceOid,
is_filespace_shared);
if (Debug_persistent_print)
elog(Persistent_DebugPrintLevel(),
"Persistent filespace directory: Resetting '%s' serial number " INT64_FORMAT " at TID %s",
PersistentFileSysObjName_ObjectName(&fsObjName),
filespaceDirEntry->persistentSerialNum,
ItemPointerToString(&filespaceDirEntry->persistentTid));
removeFilespaceDirEntry =
(FilespaceDirEntry)
hash_search(persistentFilespaceSharedHashTable,
(void *) &filespaceDirEntry->key,
HASH_REMOVE,
NULL);
if (removeFilespaceDirEntry == NULL)
elog(ERROR, "Trying to delete entry that does not exist");
}
}
extern void PersistentFilespace_LookupTidAndSerialNum(
Oid filespaceOid,
ItemPointer persistentTid,
int64 *persistentSerialNum)
{
READ_PERSISTENT_STATE_ORDERED_LOCK_DECLARE;
FilespaceDirEntry filespaceDirEntry;
PersistentFilespace_VerifyInitScan();
READ_PERSISTENT_STATE_ORDERED_LOCK;
filespaceDirEntry =
PersistentFilespace_FindDirUnderLock(
filespaceOid);
if (filespaceDirEntry == NULL)
elog(ERROR, "Did not find persistent filespace entry %u",
filespaceOid);
*persistentTid = filespaceDirEntry->persistentTid;
*persistentSerialNum = filespaceDirEntry->persistentSerialNum;
READ_PERSISTENT_STATE_ORDERED_UNLOCK;
}
// -----------------------------------------------------------------------------
// Helpers
// -----------------------------------------------------------------------------
static void PersistentFilespace_AddTuple(
FilespaceDirEntry filespaceDirEntry,
int64 createMirrorDataLossTrackingSessionNum,
int32 reserved,
TransactionId parentXid,
bool flushToXLog)
/* When true, the XLOG record for this change will be flushed to disk. */
{
Oid filespaceOid = filespaceDirEntry->key.filespaceOid;
ItemPointerData previousFreeTid;
Datum values[Natts_gp_persistent_filespace_node];
MemSet(&previousFreeTid, 0, sizeof(ItemPointerData));
GpPersistentFilespaceNode_SetDatumValues(
values,
filespaceOid,
filespaceDirEntry->locationBlankPadded1,
filespaceDirEntry->state,
reserved,
parentXid,
/* persistentSerialNum */ 0, // This will be set by PersistentFileSysObj_AddTuple.
&previousFreeTid,
is_filespace_shared(filespaceDirEntry->key.filespaceOid));
PersistentFileSysObj_AddTuple(
PersistentFsObjType_FilespaceDir,
values,
flushToXLog,
&filespaceDirEntry->persistentTid,
&filespaceDirEntry->persistentSerialNum);
}
static void PersistentFilespace_BlankPadCopyLocation(
char locationBlankPadded[FilespaceLocationBlankPaddedWithNullTermLen],
char *location)
{
int len;
int blankPadLen;
if (location != NULL)
{
len = strlen(location);
if (len > FilespaceLocationBlankPaddedWithNullTermLen - 1)
elog(ERROR, "Location '%s' is too long (found %d characaters -- expected no more than %d characters)",
location,
len,
FilespaceLocationBlankPaddedWithNullTermLen - 1);
}
else
len = 0;
if (len > 0)
memcpy(locationBlankPadded, location, len);
blankPadLen = FilespaceLocationBlankPaddedWithNullTermLen - 1 - len;
if (blankPadLen > 0)
MemSet(&locationBlankPadded[len], ' ', blankPadLen);
locationBlankPadded[FilespaceLocationBlankPaddedWithNullTermLen - 1] = '\0';
}
void PersistentFilespace_ConvertBlankPaddedLocation(
char **filespaceLocation,
char *locationBlankPadded,
bool isPrimary)
{
char *firstBlankChar;
int len;
firstBlankChar = strchr(locationBlankPadded, ' ');
if (firstBlankChar != NULL)
{
len = firstBlankChar - locationBlankPadded;
if (len == 0)
{
if (isPrimary)
elog(ERROR, "Expecting non-empty primary location");
*filespaceLocation = NULL;
return;
}
*filespaceLocation = (char*)palloc(len + 1);
memcpy(*filespaceLocation, locationBlankPadded, len);
(*filespaceLocation)[len] = '\0';
}
else
{
/*
* Whole location is non-blank characters...
*/
len = strlen(locationBlankPadded) + 1;
if (len != FilespaceLocationBlankPaddedWithNullTermLen)
elog(ERROR, "Incorrect format for blank-padded filespace location");
*filespaceLocation = pstrdup(locationBlankPadded);
}
}
bool PersistentFilespace_TryGetFilespacePathUnderLock(
Oid filespaceOid,
char **filespaceLocation)
{
FilespaceDirEntry filespaceDirEntry;
char *primaryBlankPadded = NULL;
*filespaceLocation = NULL;
#ifdef MASTER_MIRROR_SYNC
/*
* Can't rely on persistent tables or memory structures on the standby so
* get it from the cache maintained by the master mirror sync code
*/
if (GPStandby())
{
return mmxlog_filespace_get_path(
filespaceOid,
filespaceLocation);
}
#endif
/*
* Important to make this call AFTER we check if we are the Standby Master.
*/
PersistentFilespace_VerifyInitScan();
filespaceDirEntry =
PersistentFilespace_FindDirUnderLock(
filespaceOid);
if (filespaceDirEntry == NULL)
return false;
/*
* The persistent_filespace_node_table contains the paths for both the
* primary and mirror nodes, and the table is the same on both sides of the
* mirror. When it was first created the primary put its location first,
* but we don't know if we were the primary when it was created or not. To
* determine which path corresponds to this node we compare our dbid to the
* one stored in the table.
*/
primaryBlankPadded = filespaceDirEntry->locationBlankPadded1;
/* These should both have been populated by one of the cases above */
Assert(primaryBlankPadded);
PersistentFilespace_ConvertBlankPaddedLocation(
filespaceLocation,
primaryBlankPadded,
/* isPrimary */ true);
return true;
}
void PersistentFilespace_GetLocation(
Oid filespaceOid,
char **filespaceLocation)
{
READ_PERSISTENT_STATE_ORDERED_LOCK_DECLARE;
/*
* Do not call PersistentFilespace_VerifyInitScan here to allow
* PersistentFilespace_TryGetFilespacePathUnderLock to handle the Standby Master
* special case.
*/
READ_PERSISTENT_STATE_ORDERED_LOCK;
if (!PersistentFilespace_TryGetFilespacePathUnderLock(
filespaceOid,
filespaceLocation))
{
elog(ERROR, "Did not find persistent filespace entry %u", filespaceOid);
}
READ_PERSISTENT_STATE_ORDERED_UNLOCK;
}
// -----------------------------------------------------------------------------
// State Change
// -----------------------------------------------------------------------------
/*
* Indicate we intend to create a filespace file as part of the current transaction.
*
* An XLOG IntentToCreate record is generated that will guard the subsequent file-system
* create in case the transaction aborts.
*
* After 1 or more calls to this routine to mark intention about filespace files that are going
* to be created, call ~_DoPendingCreates to do the actual file-system creates. (See its
* note on XLOG flushing).
*/
void PersistentFilespace_MarkCreatePending(
Oid filespaceOid,
char *filespaceLocation,
ItemPointer persistentTid,
int64 *persistentSerialNum,
bool flushToXLog)
{
WRITE_PERSISTENT_STATE_ORDERED_LOCK_DECLARE;
PersistentFileSysObjName fsObjName;
FilespaceDirEntry filespaceDirEntry;
if (Persistent_BeforePersistenceWork())
{
if (Debug_persistent_print)
elog(Persistent_DebugPrintLevel(),
"Skipping persistent filespace %u because we are before persistence work",
filespaceOid);
return; // The initdb process will load the persistent table once we out of bootstrap mode.
}
PersistentFilespace_VerifyInitScan();
PersistentFileSysObjName_SetFilespaceDir(&fsObjName,filespaceOid,is_filespace_shared);
WRITE_PERSISTENT_STATE_ORDERED_LOCK;
filespaceDirEntry =
PersistentFilespace_CreateDirUnderLock(filespaceOid);
if (filespaceDirEntry == 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 filespaces"),
errhint("You may need to increase the gp_max_filespaces value"),
errOmitLocation(true)));
}
PersistentFilespace_BlankPadCopyLocation(
filespaceDirEntry->locationBlankPadded1,
filespaceLocation);
filespaceDirEntry->state = PersistentFileSysState_CreatePending;
PersistentFilespace_AddTuple(
filespaceDirEntry,
/* createMirrorDataLossTrackingSessionNum */ 0,
/* reserved */ 0,
/* parentXid */ GetTopTransactionId(),
flushToXLog);
*persistentTid = filespaceDirEntry->persistentTid;
*persistentSerialNum = filespaceDirEntry->persistentSerialNum;
/*
* This XLOG must be generated under the persistent write-lock.
*/
#ifdef MASTER_MIRROR_SYNC
mmxlog_log_create_filespace(filespaceOid,persistentTid, *persistentSerialNum);
#endif
#ifdef FAULT_INJECTOR
FaultInjector_InjectFaultIfSet(
FaultBeforePendingDeleteFilespaceEntry,
DDLNotSpecified,
"", // databaseName
""); // tableName
#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;
if (Debug_persistent_print)
elog(Persistent_DebugPrintLevel(),
"Persistent filespace directory: Add '%s' in state 'Created', serial number " INT64_FORMAT " at TID %s",
PersistentFileSysObjName_ObjectName(&fsObjName),
*persistentSerialNum,
ItemPointerToString(persistentTid));
}
// -----------------------------------------------------------------------------
// Rebuild filespace persistent table 'gp_persistent_filespace_node'
// -----------------------------------------------------------------------------
void PersistentFilespace_AddCreated(
Oid filespaceOid,
/* The filespace OID to be added. */
bool flushToXLog)
/* When true, the XLOG record for this change will be flushed to disk. */
{
WRITE_PERSISTENT_STATE_ORDERED_LOCK_DECLARE;
PersistentFileSysObjName fsObjName;
ItemPointerData persistentTid;
int64 persistentSerialNum;
FilespaceDirEntry filespaceDirEntry;
/*if (Persistent_BeforePersistenceWork())
{
if (Debug_persistent_print)
elog(Persistent_DebugPrintLevel(),
"Skipping persistent filespace %u because we are before persistence work",
filespaceOid);
return; // The initdb process will load the persistent table once we out of bootstrap mode.
}*/
PersistentFilespace_VerifyInitScan();
PersistentFileSysObjName_SetFilespaceDir(&fsObjName,filespaceOid,is_filespace_shared);
WRITE_PERSISTENT_STATE_ORDERED_LOCK;
filespaceDirEntry = PersistentFilespace_CreateDirUnderLock(filespaceOid);
if (filespaceDirEntry == 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 filespaces"),
errhint("You may need to increase the gp_max_filespaces value"),
errOmitLocation(true)));
}
// if it is a new generated one, we need to set info from pg_filespace_entry
if(filespaceDirEntry->persistentSerialNum==0 || strlen(filespaceDirEntry->locationBlankPadded1)==0)
{
Relation pg_fs_entry_rel;
HeapScanDesc scandesc;
HeapTuple tuple;
ScanKeyData entry[1];
bool isNull;
Datum locDatum;
char *loc;
/* Lookup the information for the current pg_filespace_entry */
pg_fs_entry_rel = heap_open(FileSpaceEntryRelationId, AccessShareLock);
ScanKeyInit(&entry[0],
Anum_pg_filespace_entry_fsefsoid,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(filespaceOid));
scandesc = heap_beginscan(pg_fs_entry_rel, SnapshotNow, 1, entry);
tuple = heap_getnext(scandesc, ForwardScanDirection);
/* We assume that there can be at most one matching tuple */
if (!HeapTupleIsValid(tuple))
{
elog(ERROR, "filespace %u could not be found in pg_filespace_entry", filespaceOid);
}
locDatum = heap_getattr(tuple,
Anum_pg_filespace_entry_fselocation,
pg_fs_entry_rel->rd_att,
&isNull);
loc = TextDatumGetCString(locDatum);
//convert location with blank padded
memset(filespaceDirEntry->locationBlankPadded1, ' ', FilespaceLocationBlankPaddedWithNullTermLen);
filespaceDirEntry->locationBlankPadded1[FilespaceLocationBlankPaddedWithNullTermLen-1]='\0';
memcpy(filespaceDirEntry->locationBlankPadded1, loc, strlen(loc));
if(isNull)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("internal error: filespace '%u' has no name defined",
filespaceOid)));
heap_endscan(scandesc);
heap_close(pg_fs_entry_rel, AccessShareLock);
}
filespaceDirEntry->state = PersistentFileSysState_Created;
PersistentFilespace_AddTuple(
filespaceDirEntry,
/* createMirrorDataLossTrackingSessionNum */ 0,
/* reserved */ 0,
/* parentXid */ InvalidTransactionId,
flushToXLog);
persistentTid = filespaceDirEntry->persistentTid;
persistentSerialNum = filespaceDirEntry->persistentSerialNum;
WRITE_PERSISTENT_STATE_ORDERED_UNLOCK;
if (Debug_persistent_print)
elog(Persistent_DebugPrintLevel(),
"Persistent filespace directory: Add '%s' in state 'Created', serial number " INT64_FORMAT " at TID '%s' ",
PersistentFileSysObjName_ObjectName(&fsObjName),
persistentSerialNum,
ItemPointerToString(&persistentTid));
}
// -----------------------------------------------------------------------------
// Transaction End
// -----------------------------------------------------------------------------
/*
* Indicate the transaction commited and the filespace is officially created.
*/
void PersistentFilespace_Created(
PersistentFileSysObjName *fsObjName,
/* The filespace OID for the create. */
ItemPointer persistentTid,
/* TID of the gp_persistent_rel_files tuple for the rel file */
int64 persistentSerialNum,
/* Serial number for the filespace. Distinquishes the uses of the tuple. */
bool retryPossible)
{
WRITE_PERSISTENT_STATE_ORDERED_LOCK_DECLARE;
Oid filespaceOid = fsObjName->variant.filespaceOid;
FilespaceDirEntry filespaceDirEntry;
PersistentFileSysObjStateChangeResult stateChangeResult;
if (Persistent_BeforePersistenceWork())
{
if (Debug_persistent_print)
elog(Persistent_DebugPrintLevel(),
"Skipping persistent filespace %u because we are before "
"persistence work",
filespaceOid);
/*
* The initdb process will load the persistent table once we out of
* bootstrap mode.
*/
return;
}
PersistentFilespace_VerifyInitScan();
WRITE_PERSISTENT_STATE_ORDERED_LOCK;
filespaceDirEntry =
PersistentFilespace_FindDirUnderLock(
filespaceOid);
if (filespaceDirEntry == NULL)
elog(ERROR, "did not find persistent filespace entry %u",
filespaceOid);
if (filespaceDirEntry->state != PersistentFileSysState_CreatePending)
elog(ERROR, "persistent filespace entry %u expected to be in "
"'Create Pending' state (actual state '%s')",
filespaceOid,
PersistentFileSysObjState_Name(filespaceDirEntry->state));
stateChangeResult =
PersistentFileSysObj_StateChange(
fsObjName,
persistentTid,
persistentSerialNum,
PersistentFileSysState_Created,
retryPossible,
/* flushToXlog */ false,
/* oldState */ NULL,
/* verifiedActionCallback */ NULL);
filespaceDirEntry->state = PersistentFileSysState_Created;
WRITE_PERSISTENT_STATE_ORDERED_UNLOCK;
if (Debug_persistent_print)
elog(Persistent_DebugPrintLevel(),
"Persistent filespace directory: '%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));
}
/*
* Indicate we intend to drop a filespace file as part of the current transaction.
*
* This filespace file to drop will be listed inside a commit, distributed commit, a distributed
* prepared, and distributed commit prepared XOG records.
*
* For any of the commit type records, once that XLOG record is flushed then the actual
* file-system delete will occur. The flush guarantees the action will be retried after system
* crash.
*/
PersistentFileSysObjStateChangeResult PersistentFilespace_MarkDropPending(
PersistentFileSysObjName *fsObjName,
/* The filespace OID for the drop. */
ItemPointer persistentTid,
/* TID of the gp_persistent_rel_files tuple for the rel file */
int64 persistentSerialNum,
/* Serial number for the filespace. Distinquishes the uses of the tuple. */
bool retryPossible)
{
WRITE_PERSISTENT_STATE_ORDERED_LOCK_DECLARE;
Oid filespaceOid = fsObjName->variant.filespaceOid;
FilespaceDirEntry filespaceDirEntry;
PersistentFileSysObjStateChangeResult stateChangeResult;
if (Persistent_BeforePersistenceWork())
{
if (Debug_persistent_print)
elog(Persistent_DebugPrintLevel(),
"Skipping persistent filespace %u because we are before persistence work",
filespaceOid);
return false; // The initdb process will load the persistent table once we out of bootstrap mode.
}
PersistentFilespace_VerifyInitScan();
WRITE_PERSISTENT_STATE_ORDERED_LOCK;
filespaceDirEntry =
PersistentFilespace_FindDirUnderLock(
filespaceOid);
if (filespaceDirEntry == NULL)
elog(ERROR, "Did not find persistent filespace entry %u",
filespaceOid);
if (filespaceDirEntry->state != PersistentFileSysState_CreatePending &&
filespaceDirEntry->state != PersistentFileSysState_Created)
elog(ERROR, "Persistent filespace entry %u expected to be in 'Create Pending' or 'Created' state (actual state '%s')",
filespaceOid,
PersistentFileSysObjState_Name(filespaceDirEntry->state));
stateChangeResult =
PersistentFileSysObj_StateChange(
fsObjName,
persistentTid,
persistentSerialNum,
PersistentFileSysState_DropPending,
retryPossible,
/* flushToXlog */ false,
/* oldState */ NULL,
/* verifiedActionCallback */ NULL);
filespaceDirEntry->state = PersistentFileSysState_DropPending;
WRITE_PERSISTENT_STATE_ORDERED_UNLOCK;
if (Debug_persistent_print)
elog(Persistent_DebugPrintLevel(),
"Persistent filespace directory: '%s' changed state from 'Create Pending' to 'Drop Pending', serial number " INT64_FORMAT " at TID %s (State-Change result '%s')",
PersistentFileSysObjName_ObjectName(fsObjName),
persistentSerialNum,
ItemPointerToString(persistentTid),
PersistentFileSysObjStateChangeResult_Name(stateChangeResult));
return stateChangeResult;
}
/*
* Indicate we are aborting the create of a filespace file.
*
* This state will make sure the filespace gets dropped after a system crash.
*/
PersistentFileSysObjStateChangeResult PersistentFilespace_MarkAbortingCreate(
PersistentFileSysObjName *fsObjName,
/* The filespace OID for the aborting create. */
ItemPointer persistentTid,
/* TID of the gp_persistent_rel_files tuple for the rel file */
int64 persistentSerialNum,
/* Serial number for the filespace. Distinquishes the uses of the tuple. */
bool retryPossible)
{
WRITE_PERSISTENT_STATE_ORDERED_LOCK_DECLARE;
Oid filespaceOid = fsObjName->variant.filespaceOid;
FilespaceDirEntry filespaceDirEntry;
PersistentFileSysObjStateChangeResult stateChangeResult;
if (Persistent_BeforePersistenceWork())
{
if (Debug_persistent_print)
elog(Persistent_DebugPrintLevel(),
"Skipping persistent filespace %u because we are before persistence work",
filespaceOid);
return false; // The initdb process will load the persistent table once we out of bootstrap mode.
}
PersistentFilespace_VerifyInitScan();
WRITE_PERSISTENT_STATE_ORDERED_LOCK;
filespaceDirEntry =
PersistentFilespace_FindDirUnderLock(
filespaceOid);
if (filespaceDirEntry == NULL)
elog(ERROR, "Did not find persistent filespace entry %u", filespaceOid);
if (filespaceDirEntry->state != PersistentFileSysState_CreatePending)
elog(ERROR, "Persistent filespace entry %u expected to be in 'Create Pending' (actual state '%s')",
filespaceOid,
PersistentFileSysObjState_Name(filespaceDirEntry->state));
stateChangeResult =
PersistentFileSysObj_StateChange(
fsObjName,
persistentTid,
persistentSerialNum,
PersistentFileSysState_AbortingCreate,
retryPossible,
/* flushToXlog */ false,
/* oldState */ NULL,
/* verifiedActionCallback */ NULL);
filespaceDirEntry->state = PersistentFileSysState_AbortingCreate;
WRITE_PERSISTENT_STATE_ORDERED_UNLOCK;
if (Debug_persistent_print)
elog(Persistent_DebugPrintLevel(),
"Persistent filespace directory: '%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
PersistentFilespace_DroppedVerifiedActionCallback(
PersistentFileSysObjName *fsObjName,
ItemPointer persistentTid,
/* TID of the gp_persistent_rel_files tuple for the relation. */
int64 persistentSerialNum,
/* Serial number for the relation. Distinquishes the uses of the tuple. */
PersistentFileSysObjVerifyExpectedResult verifyExpectedResult)
{
Oid filespaceOid = PersistentFileSysObjName_GetFilespaceDir(fsObjName);
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_filespace(filespaceOid,persistentTid, persistentSerialNum);
#endif
break;
default:
elog(ERROR, "Unexpected persistent object verify expected result: %d",
verifyExpectedResult);
}
}
/*
* Indicate we physically removed the filespace file.
*/
void PersistentFilespace_Dropped(
PersistentFileSysObjName *fsObjName,
/* The filespace OID for the dropped filespace. */
ItemPointer persistentTid,
/* TID of the gp_persistent_rel_files tuple for the rel file */
int64 persistentSerialNum)
/* Serial number for the filespace. Distinquishes the uses of the tuple. */
{
WRITE_PERSISTENT_STATE_ORDERED_LOCK_DECLARE;
Oid filespaceOid = fsObjName->variant.filespaceOid;
FilespaceDirEntry filespaceDirEntry;
PersistentFileSysState oldState;
PersistentFileSysObjStateChangeResult stateChangeResult;
if (Persistent_BeforePersistenceWork())
{
if (Debug_persistent_print)
elog(Persistent_DebugPrintLevel(),
"Skipping persistent filespace %u because we are before persistence work",
filespaceOid);
return; // The initdb process will load the persistent table once we out of bootstrap mode.
}
PersistentFilespace_VerifyInitScan();
WRITE_PERSISTENT_STATE_ORDERED_LOCK;
filespaceDirEntry =
PersistentFilespace_FindDirUnderLock(
filespaceOid);
if (filespaceDirEntry == NULL)
elog(ERROR, "Did not find persistent filespace entry %u",
filespaceOid);
if (filespaceDirEntry->state != PersistentFileSysState_DropPending &&
filespaceDirEntry->state != PersistentFileSysState_AbortingCreate)
elog(ERROR, "Persistent filespace entry %u expected to be in 'Drop Pending' or 'Aborting Create' (actual state '%s')",
filespaceOid,
PersistentFileSysObjState_Name(filespaceDirEntry->state));
stateChangeResult =
PersistentFileSysObj_StateChange(
fsObjName,
persistentTid,
persistentSerialNum,
PersistentFileSysState_Free,
/* retryPossible */ false,
/* flushToXlog */ false,
&oldState,
PersistentFilespace_DroppedVerifiedActionCallback);
filespaceDirEntry->state = PersistentFileSysState_Free;
PersistentFilespace_RemoveDirUnderLock(filespaceDirEntry);
WRITE_PERSISTENT_STATE_ORDERED_UNLOCK;
if (Debug_persistent_print)
elog(Persistent_DebugPrintLevel(),
"Persistent filespace directory: '%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));
}
// -----------------------------------------------------------------------------
// Shmem
// -----------------------------------------------------------------------------
static Size PersistentFilespace_SharedDataSize(void)
{
return MAXALIGN(sizeof(PersistentFilespaceSharedData));
}
/*
* Return the required shared-memory size for this module.
*/
Size PersistentFilespace_ShmemSize(void)
{
Size size;
/* The hash table of persistent filespaces */
size = hash_estimate_size((Size)gp_max_filespaces,
sizeof(FilespaceDirEntryData));
/* The shared-memory structure. */
size = add_size(size, PersistentFilespace_SharedDataSize());
elog(LOG, "PersistentFilespace_ShmemSize: %zu = "
"gp_max_filespaces: %d "
"* sizeof(FilespaceDirEntryData): %zu "
"+ PersistentFilespace_SharedDataSize(): %zu",
size,
gp_max_filespaces,
sizeof(FilespaceDirEntryData),
PersistentFilespace_SharedDataSize());
return size;
}
/*
* PersistentFilespace_HashTableInit
*
* Create or find shared-memory hash table.
*/
static bool
PersistentFilespace_HashTableInit(void)
{
HASHCTL info;
int hash_flags;
/* Set key and entry sizes. */
MemSet(&info, 0, sizeof(info));
info.keysize = sizeof(FilespaceDirEntryKey);
info.entrysize = sizeof(FilespaceDirEntryData);
info.hash = tag_hash;
hash_flags = (HASH_ELEM | HASH_FUNCTION);
persistentFilespaceSharedHashTable =
ShmemInitHash("Persistent Filespace Hash",
gp_max_filespaces,
gp_max_filespaces,
&info,
hash_flags);
if (persistentFilespaceSharedHashTable == NULL)
return false;
return true;
}
/*
* Initialize the shared-memory for this module.
*/
void PersistentFilespace_ShmemInit(void)
{
bool found;
bool ok;
/* Create the shared-memory structure. */
persistentFilespaceSharedData =
(PersistentFilespaceSharedData *)
ShmemInitStruct("Persistent Filespace Data",
PersistentFilespace_SharedDataSize(),
&found);
if (!found)
{
PersistentFileSysObj_InitShared(
&persistentFilespaceSharedData->fileSysObjSharedData);
}
/* Create or find our shared-memory hash table. */
ok = PersistentFilespace_HashTableInit();
if (!ok)
ereport(FATAL,
(errcode(ERRCODE_OUT_OF_MEMORY),
errmsg("Not enough shared memory for persistent filespace hash table")));
PersistentFileSysObj_Init(
&persistentFilespaceData.fileSysObjData,
&persistentFilespaceSharedData->fileSysObjSharedData,
PersistentFsObjType_FilespaceDir,
PersistentFilespace_ScanTupleCallback);
Assert(persistentFilespaceSharedData != NULL);
Assert(persistentFilespaceSharedHashTable != NULL);
}
/*
* Note that this can go away when we do away with master mirror sync by WAL.
*/
#ifdef MASTER_MIRROR_SYNC /* annotation to show that this is just for mmsync */
void
get_filespace_data(fspc_agg_state **fas, char *caller)
{
HASH_SEQ_STATUS stat;
FilespaceDirEntry fde;
int maxCount;
Assert(*fas == NULL);
mmxlog_add_filespace_init(fas, &maxCount);
hash_seq_init(&stat, persistentFilespaceSharedHashTable);
while ((fde = hash_seq_search(&stat)) != NULL)
{
mmxlog_add_filespace(
fas, &maxCount,
fde->key.filespaceOid,
fde->locationBlankPadded1,
caller);
}
}
#endif