blob: 139eba870d9b6a663813a2ce078442ab9464983d [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.
*/
/*-------------------------------------------------------------------------
*
* cdbpersistentstore.h
*
*-------------------------------------------------------------------------
*/
#ifndef CDBPERSISTENTSTORE_H
#define CDBPERSISTENTSTORE_H
#include "utils/palloc.h"
#include "storage/fd.h"
#include "access/persistentfilesysobjname.h"
#include "catalog/gp_global_sequence.h"
#include "storage/itemptr.h"
#include "access/genam.h"
#include "access/heapam.h"
#include "utils/rel.h"
#include "cdb/cdbdirectopen.h"
#include "utils/guc.h"
/*
* Can be used to suppress errcontext when doing low-level tracing where we
* don't want "dynamic" errcontext like that used by the executor which executes a
* lot of code to determine the errcontext string to recurse and cause stack overflow.
*/
#define SUPPRESS_ERRCONTEXT_DECLARE \
ErrorContextCallback *suppressErrContext = NULL;
#define SUPPRESS_ERRCONTEXT_PUSH() \
{ \
suppressErrContext = error_context_stack; \
error_context_stack = NULL; \
}
#define SUPPRESS_ERRCONTEXT_POP() \
{ \
error_context_stack = suppressErrContext; \
}
#define PersistentStoreSharedDataEyecatcher "PersistentStoreSharedData"
// Length includes 1 extra for NUL.
#define PersistentStoreSharedDataEyecatcher_Len 26
#define PersistentStoreSharedDataMaxCachedSerialNum 100
typedef struct PersistentStoreSharedData
{
char eyecatcher[PersistentStoreSharedDataEyecatcher_Len];
bool needToScanIntoSharedMemory;
int64 maxInUseSerialNum;
int64 maxCachedSerialNum;
int64 inUseCount;
int64 maxFreeOrderNum;
ItemPointerData freeTid;
ItemPointerData maxTid;
} PersistentStoreSharedData;
inline static bool PersistentStoreSharedData_EyecatcherIsValid(
PersistentStoreSharedData *storeSharedData)
{
return (strcmp(storeSharedData->eyecatcher, PersistentStoreSharedDataEyecatcher) == 0);
}
typedef Relation (*PersistentStoreOpenRel) (void);
typedef void (*PersistentStoreCloseRel) (Relation relation);
typedef bool (*PersistentStoreScanTupleCallback) (
ItemPointer persistentTid,
int64 persistentSerialNum,
Datum *values);
typedef void (*PersistentStorePrintTupleCallback) (
int elevel,
char *prefix,
ItemPointer persistentTid,
Datum *values);
#define PersistentStoreData_StaticInit {NULL,0,NULL,NULL,NULL,NULL,0,0,0,0}
typedef struct PersistentStoreData
{
char *tableName;
GpGlobalSequence gpGlobalSequence;
PersistentStoreOpenRel openRel;
PersistentStoreCloseRel closeRel;
PersistentStoreScanTupleCallback scanTupleCallback;
PersistentStorePrintTupleCallback printTupleCallback;
int64 myHighestSerialNum;
int numAttributes;
int attNumPersistentSerialNum;
int attNumPreviousFreeTid;
} PersistentStoreData;
typedef struct PersistentStoreScan
{
PersistentStoreData *storeData;
PersistentStoreSharedData *storeSharedData;
Relation persistentRel;
HeapScanDesc scan;
HeapTuple tuple;
} PersistentStoreScan;
inline static bool PersistentStore_IsZeroTid(
ItemPointer testTid)
{
static ItemPointerData zeroTid = {{0,0},0};
return (ItemPointerCompare(testTid, &zeroTid) == 0);
}
#ifdef USE_ASSERT_CHECKING
typedef struct CheckpointStartLockLocalVars
{
bool checkpointStartLockIsHeldByMe;
bool checkpointStartVariablesSet;
} CheckpointStartLockLocalVars;
#define CHECKPOINT_START_LOCK_DECLARE \
CheckpointStartLockLocalVars checkpointStartLockLocalVars = {false, false};
#else
typedef struct CheckpointStartLockLocalVars
{
bool checkpointStartLockIsHeldByMe;
} CheckpointStartLockLocalVars;
#define CHECKPOINT_START_LOCK_DECLARE \
CheckpointStartLockLocalVars checkpointStartLockLocalVars = {false};
#endif
#ifdef USE_ASSERT_CHECKING
#define CHECKPOINT_START_LOCK \
{ \
checkpointStartLockLocalVars.checkpointStartLockIsHeldByMe = LWLockHeldByMe(CheckpointStartLock); \
checkpointStartLockLocalVars.checkpointStartVariablesSet = true; \
\
if (!checkpointStartLockLocalVars.checkpointStartLockIsHeldByMe) \
{ \
LWLockAcquire(CheckpointStartLock , LW_SHARED); \
} \
else \
{ \
HOLD_INTERRUPTS(); \
} \
\
Assert(InterruptHoldoffCount > 0); \
}
#else
#define CHECKPOINT_START_LOCK \
{ \
checkpointStartLockLocalVars.checkpointStartLockIsHeldByMe = LWLockHeldByMe(CheckpointStartLock); \
\
if (!checkpointStartLockLocalVars.checkpointStartLockIsHeldByMe) \
{ \
LWLockAcquire(CheckpointStartLock , LW_SHARED); \
} \
else \
{ \
HOLD_INTERRUPTS(); \
} \
}
#endif
#ifdef USE_ASSERT_CHECKING
#define CHECKPOINT_START_UNLOCK \
{ \
Assert(checkpointStartLockLocalVars.checkpointStartVariablesSet); \
Assert(InterruptHoldoffCount > 0); \
\
if (!checkpointStartLockLocalVars.checkpointStartLockIsHeldByMe) \
{ \
LWLockRelease(CheckpointStartLock); \
} \
else \
{ \
RESUME_INTERRUPTS(); \
} \
}
#else
#define CHECKPOINT_START_UNLOCK \
{ \
if (!checkpointStartLockLocalVars.checkpointStartLockIsHeldByMe) \
{ \
LWLockRelease(CheckpointStartLock); \
} \
else \
{ \
RESUME_INTERRUPTS(); \
} \
}
#endif
/*
* Helper DEFINEs for the Persistent state-change modules to READ or WRITE.
* We must maintain proper lock acquisition and ordering to prevent any
* possible deadlocks.
*
* The WRITE_PERSISTENT_STATE_ORDERED_LOCK gets these locks:
* MirroredLock SHARED
* CheckpointStartLock SHARED
* PersistentObjLock EXCLUSIVE
*
* The READ_PERSISTENT_STATE_ORDERED_LOCK gets this lock:
* PersistentObjLock SHARED
*
* By taking a SHARED MirroredLock, the process is blocking the filerep resync logic
* from taking an EXCLUSIVE MirroredLock, there by preventing both a mirror write and
* persistent table I/O at the same time. The filerep logic will always wait for an
* EXCLUSIVE lock.
*
* By taking a SHARED CheckpointStartLock, the process is blocking a checkpoint from
* occurring while performing persistent table I/O. The checkpoint logic will always
* wait for an EXCLUSIVE lock.
*
* By taking an exclusive PersistentObjLock, the process is preventing simultaneous
* I/O on the persistent tables. Only one process can obtain an EXCLUSIVE
* PersistentObjLock.
*
* NOTE: Below these locks are the Buffer Pool content locks.
*/
/*
* WRITE
*/
typedef struct WritePersistentStateLockLocalVars
{
bool persistentObjLockIsHeldByMe;
} WritePersistentStateLockLocalVars;
#define WRITE_PERSISTENT_STATE_ORDERED_LOCK_DECLARE \
CHECKPOINT_START_LOCK_DECLARE; \
WritePersistentStateLockLocalVars writePersistentStateLockLocalVars;
#define WRITE_PERSISTENT_STATE_ORDERED_LOCK \
{ \
CHECKPOINT_START_LOCK; \
writePersistentStateLockLocalVars.persistentObjLockIsHeldByMe = LWLockHeldByMe(PersistentObjLock); \
if (!writePersistentStateLockLocalVars.persistentObjLockIsHeldByMe) \
{ \
LWLockAcquire(PersistentObjLock , LW_EXCLUSIVE); \
} \
START_CRIT_SECTION(); \
}
#define WRITE_PERSISTENT_STATE_ORDERED_UNLOCK \
{ \
CHECKPOINT_START_UNLOCK; \
if (!writePersistentStateLockLocalVars.persistentObjLockIsHeldByMe) \
{ \
LWLockRelease(PersistentObjLock); \
} \
END_CRIT_SECTION(); \
}
/*
* READ
*/
typedef struct ReadPersistentStateLockLocalVars
{
bool persistentObjLockIsHeldByMe;
} ReadPersistentStateLockLocalVars;
#define READ_PERSISTENT_STATE_ORDERED_LOCK_DECLARE \
ReadPersistentStateLockLocalVars readPersistentStateLockLocalVars;
#define READ_PERSISTENT_STATE_ORDERED_LOCK \
{ \
readPersistentStateLockLocalVars.persistentObjLockIsHeldByMe = LWLockHeldByMe(PersistentObjLock); \
if (!readPersistentStateLockLocalVars.persistentObjLockIsHeldByMe) \
{ \
LWLockAcquire(PersistentObjLock , LW_SHARED); \
} \
}
#define READ_PERSISTENT_STATE_ORDERED_UNLOCK \
{ \
if (!readPersistentStateLockLocalVars.persistentObjLockIsHeldByMe) \
{ \
LWLockRelease(PersistentObjLock); \
} \
}
inline static bool Persistent_BeforePersistenceWork(void)
{
if (IsBootstrapProcessingMode())
return true;
if (gp_before_persistence_work)
return true;
return false;
}
inline static int PersistentStore_DebugPrintLevel(void)
{
if (Debug_persistent_bootstrap_print && IsBootstrapProcessingMode())
return WARNING;
else
return Debug_persistent_store_print_level;
}
extern void PersistentStore_InitShared(
PersistentStoreSharedData *storeSharedData);
extern void PersistentStore_Init(
PersistentStoreData *storeData,
char *tableName,
GpGlobalSequence gpGlobalSequence,
PersistentStoreOpenRel openRel,
PersistentStoreCloseRel closeRel,
PersistentStoreScanTupleCallback scanTupleCallback,
PersistentStorePrintTupleCallback printTupleCallback,
int numAttributes,
int attNumPersistentSerialNum,
int attNumPreviousFreeTid);
extern void PersistentStore_ResetFreeList(
PersistentStoreData *storeData,
PersistentStoreSharedData *storeSharedData);
extern void PersistentStore_InitScanUnderLock(
PersistentStoreData *storeData,
PersistentStoreSharedData *storeSharedData);
extern void PersistentStore_Scan(
PersistentStoreData *storeData,
PersistentStoreSharedData *storeSharedData,
PersistentStoreScanTupleCallback scanTupleCallback);
extern void PersistentStore_BeginScan(
PersistentStoreData *storeData,
PersistentStoreSharedData *storeSharedData,
PersistentStoreScan *storeScan);
extern bool PersistentStore_GetNext(
PersistentStoreScan *storeScan,
Datum *values,
ItemPointer persistentTid,
int64 *persistentSerialNum);
extern HeapTuple PersistentStore_GetScanTupleCopy(
PersistentStoreScan *storeScan);
extern void PersistentStore_EndScan(
PersistentStoreScan *storeScan);
extern void PersistentStore_FlushXLog(void);
extern int64 PersistentStore_MyHighestSerialNum(
PersistentStoreData *storeData);
extern int64 PersistentStore_CurrentMaxSerialNum(
PersistentStoreSharedData *storeSharedData);
typedef enum PersistentTidIsKnownResult
{
PersistentTidIsKnownResult_None = 0,
PersistentTidIsKnownResult_BeforePersistenceWork,
PersistentTidIsKnownResult_ScanNotPerformedYet,
PersistentTidIsKnownResult_MaxTidIsZero,
PersistentTidIsKnownResult_Known,
PersistentTidIsKnownResult_NotKnown,
MaxPersistentTidIsKnownResult /* must always be last */
} PersistentTidIsKnownResult;
extern PersistentTidIsKnownResult PersistentStore_TidIsKnown(
PersistentStoreSharedData *storeSharedData,
ItemPointer persistentTid,
ItemPointer maxTid);
extern void PersistentStore_UpdateTuple(
PersistentStoreData *storeData,
PersistentStoreSharedData *storeSharedData,
ItemPointer persistentTid,
/* TID of the stored tuple. */
Datum *values,
bool flushToXLog);
/* When true, the XLOG record for this change will be flushed to disk. */
extern void PersistentStore_ReplaceTuple(
PersistentStoreData *storeData,
PersistentStoreSharedData *storeSharedData,
ItemPointer persistentTid,
/* TID of the stored tuple. */
HeapTuple tuple,
Datum *newValues,
bool *replaces,
bool flushToXLog);
/* When true, the XLOG record for this change will be flushed to disk. */
extern void PersistentStore_ReadTuple(
PersistentStoreData *storeData,
PersistentStoreSharedData *storeSharedData,
ItemPointer readTid,
Datum *values,
HeapTuple *tupleCopy);
extern void PersistentStore_AddTuple(
PersistentStoreData *storeData,
PersistentStoreSharedData *storeSharedData,
Datum *values,
bool flushToXLog,
/* When true, the XLOG record for this change will be flushed to disk. */
ItemPointer persistentTid,
/* TID of the stored tuple. */
int64 *persistentSerialNum);
extern void PersistentStore_FreeTuple(
PersistentStoreData *storeData,
PersistentStoreSharedData *storeSharedData,
ItemPointer persistentTid,
/* TID of the stored tuple. */
Datum *freeValues,
bool flushToXLog);
/* When true, the XLOG record for this change will be flushed to disk. */
#endif /* CDBPERSISTENTSTORE_H */