| /* |
| * 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 */ |
| |