blob: a78ca215c3ef683de9850e199fac866e7ab812cc [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.
*/
/*-------------------------------------------------------------------------
*
* cdbpersistentdatabase.c
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "miscadmin.h"
#include "pgstat.h"
#include "utils/palloc.h"
#include "storage/fd.h"
#include "storage/relfilenode.h"
#include "catalog/catalog.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_authid.h"
#include "catalog/pg_tablespace.h"
#include "catalog/pg_database.h"
#include "catalog/gp_persistent.h"
#include "cdb/cdbsharedoidsearch.h"
#include "access/persistentfilesysobjname.h"
#include "cdb/cdbdirectopen.h"
#include "cdb/cdbpersistentstore.h"
#include "cdb/cdbpersistentfilesysobj.h"
#include "cdb/cdbpersistenttablespace.h"
#include "cdb/cdbpersistentdatabase.h"
#include "cdb/cdbpersistentrelfile.h"
#include "cdb/cdbvars.h"
#include "storage/itemptr.h"
#include "utils/hsearch.h"
#include "storage/shmem.h"
#include "access/genam.h"
#include "access/heapam.h"
#include "access/transam.h"
#include "utils/guc.h"
#include "storage/smgr.h"
#include "storage/ipc.h"
#include "utils/builtins.h"
#include "utils/faultinjector.h"
#include "commands/tablespace.h"
#include "commands/dbcommands.h"
/*
* This module is for generic relation file create and drop.
*
* For create, it makes the file-system create of an empty file fully transactional so
* the relation file will be deleted even on system crash. The relation file could be a heap,
* index, or append-only (row- or column-store).
*/
/* This value is the gp_max_tablespaces * gp_max_databases. */
int MaxPersistentDatabaseDirectories = 0;
static Oid persistentDatabaseCheckTablespace;
static int32 persistentDatabaseCheckTablespaceUseCount;
typedef struct PersistentDatabaseSharedData
{
PersistentFileSysObjSharedData fileSysObjSharedData;
SharedOidSearchTable databaseDirSearchTable;
/* Variable length -- MUST BE LAST */
} PersistentDatabaseSharedData;
#define PersistentDatabaseData_StaticInit {PersistentFileSysObjData_StaticInit}
typedef struct PersistentDatabaseData
{
PersistentFileSysObjData fileSysObjData;
} PersistentDatabaseData;
/*
* Global Variables
*/
PersistentDatabaseSharedData *persistentDatabaseSharedData = NULL;
PersistentDatabaseData persistentDatabaseData = PersistentDatabaseData_StaticInit;
static void PersistentDatabase_VerifyInitScan(void)
{
if (persistentDatabaseSharedData == NULL)
elog(PANIC, "Persistent database information shared-memory not setup");
PersistentFileSysObj_VerifyInitScan();
}
// -----------------------------------------------------------------------------
// Scan
// -----------------------------------------------------------------------------
static bool PersistentDatabase_ScanTupleCallback(
ItemPointer persistentTid,
int64 persistentSerialNum,
Datum *values)
{
DbDirNode dbDirNode;
PersistentFileSysState state;
int32 reserved;
TransactionId parentXid;
int64 serialNum;
ItemPointerData previousFreeTid;
SharedOidSearchAddResult addResult;
DatabaseDirEntry databaseDirEntry;
bool sharedStorage;
GpPersistentDatabaseNode_GetValues(
values,
&dbDirNode.tablespace,
&dbDirNode.database,
&state,
&reserved,
&parentXid,
&serialNum,
&previousFreeTid,
&sharedStorage);
if (state == PersistentFileSysState_Free)
{
if (Debug_persistent_print)
elog(Persistent_DebugPrintLevel(),
"PersistentDatabase_ScanTupleCallback: TID %s, serial number " INT64_FORMAT " is free",
ItemPointerToString2(persistentTid),
persistentSerialNum);
return true; // Continue.
}
addResult =
SharedOidSearch_Add(
&persistentDatabaseSharedData->databaseDirSearchTable,
dbDirNode.database,
dbDirNode.tablespace,
(SharedOidSearchObjHeader**)&databaseDirEntry);
if (addResult == SharedOidSearchAddResult_NoMemory)
elog(ERROR, "Out of shared-memory for persistent relations");
else if (addResult == SharedOidSearchAddResult_Exists)
elog(PANIC, "Persistent database entry '%s' already exists in state '%s'",
GetDatabasePath(dbDirNode.database, dbDirNode.tablespace),
PersistentFileSysObjState_Name(databaseDirEntry->state));
else
Assert(addResult == SharedOidSearchAddResult_Ok);
databaseDirEntry->state = state;
databaseDirEntry->persistentSerialNum = serialNum;
databaseDirEntry->persistentTid = *persistentTid;
databaseDirEntry->iteratorRefCount = 0;
if (Debug_persistent_print)
elog(Persistent_DebugPrintLevel(),
"PersistentDatabase_ScanTupleCallback: database %u, tablespace %u, state %s, TID %s, serial number " INT64_FORMAT,
dbDirNode.database,
dbDirNode.tablespace,
PersistentFileSysObjState_Name(state),
ItemPointerToString2(persistentTid),
persistentSerialNum);
return true; // Continue.
}
static bool PersistentDatabase_CheckTablespaceScanTupleCallback(
ItemPointer persistentTid,
int64 persistentSerialNum,
Datum *values)
{
DbDirNode dbDirNode;
PersistentFileSysState state;
int32 reserved;
TransactionId parentXid;
int64 serialNum;
ItemPointerData previousFreeTid;
bool sharedStorage;
GpPersistentDatabaseNode_GetValues(
values,
&dbDirNode.tablespace,
&dbDirNode.database,
&state,
&reserved,
&parentXid,
&serialNum,
&previousFreeTid,
&sharedStorage);
if (state == PersistentFileSysState_Created &&
dbDirNode.tablespace == persistentDatabaseCheckTablespace)
{
/*
* Database can access different tablespaces, which will be recorded in
* this relation. Skip the tablespaces which are not recored in
* pg_database relation.
*/
if (MyDatabaseTableSpace == persistentDatabaseCheckTablespace ||
get_database_dts(MyDatabaseId) == persistentDatabaseCheckTablespace)
persistentDatabaseCheckTablespaceUseCount++;
}
return true;
}
// -----------------------------------------------------------------------------
// Iterate
// -----------------------------------------------------------------------------
static bool iterateOnShmemExitArmed = false;
static DatabaseDirEntry dirIterateDatabaseDirEntry = NULL;
static void PersistentDatabase_DirIterateMoveAway(
DatabaseDirEntry prevDatabaseDirEntry)
{
if (prevDatabaseDirEntry == NULL)
return;
Assert(prevDatabaseDirEntry->iteratorRefCount > 0);
prevDatabaseDirEntry->iteratorRefCount--;
if (prevDatabaseDirEntry->iteratorRefCount == 0 &&
prevDatabaseDirEntry->state == PersistentFileSysState_Free)
{
/*
* Our job is to actually free the entry.
*/
SharedOidSearch_Delete(
&persistentDatabaseSharedData->databaseDirSearchTable,
&prevDatabaseDirEntry->header);
}
}
static void PersistentDatabase_ReleaseDirIterator(void)
{
if (dirIterateDatabaseDirEntry != NULL)
{
SharedOidSearch_ReleaseIterator(
&persistentDatabaseSharedData->databaseDirSearchTable,
(SharedOidSearchObjHeader**)&dirIterateDatabaseDirEntry);
Assert(dirIterateDatabaseDirEntry == NULL);
}
PersistentDatabase_DirIterateMoveAway(dirIterateDatabaseDirEntry);
}
static void AtProcExit_PersistentDatabase(int code, Datum arg)
{
PersistentDatabase_ReleaseDirIterator();
}
void PersistentDatabase_DirIterateInit(void)
{
READ_PERSISTENT_STATE_ORDERED_LOCK_DECLARE;
Assert(persistentDatabaseSharedData != NULL);
PersistentDatabase_VerifyInitScan();
PersistentDatabase_ReleaseDirIterator();
READ_PERSISTENT_STATE_ORDERED_LOCK;
if (!iterateOnShmemExitArmed)
{
on_shmem_exit(AtProcExit_PersistentDatabase, 0);
iterateOnShmemExitArmed = true;
}
dirIterateDatabaseDirEntry = NULL;
READ_PERSISTENT_STATE_ORDERED_UNLOCK;
}
bool PersistentDatabase_DirIterateNext(
DbDirNode *dbDirNode,
PersistentFileSysState *state,
ItemPointer persistentTid,
int64 *persistentSerialNum)
{
READ_PERSISTENT_STATE_ORDERED_LOCK_DECLARE;
DatabaseDirEntry prevDatabaseDirEntry;
Assert(persistentDatabaseSharedData != NULL);
PersistentDatabase_VerifyInitScan();
MemSet(dbDirNode, 0, sizeof(DbDirNode));
READ_PERSISTENT_STATE_ORDERED_LOCK;
while (true)
{
prevDatabaseDirEntry = dirIterateDatabaseDirEntry;
SharedOidSearch_Iterate(
&persistentDatabaseSharedData->databaseDirSearchTable,
(SharedOidSearchObjHeader**)&dirIterateDatabaseDirEntry);
PersistentDatabase_DirIterateMoveAway(prevDatabaseDirEntry);
if (dirIterateDatabaseDirEntry == NULL)
{
READ_PERSISTENT_STATE_ORDERED_UNLOCK;
return false;
}
*state = dirIterateDatabaseDirEntry->state;
if (*state == PersistentFileSysState_Free)
{
// UNDONE: Or, PinCount > 1
Assert(dirIterateDatabaseDirEntry->iteratorRefCount > 0);
continue;
}
dbDirNode->database = dirIterateDatabaseDirEntry->header.oid1;
dbDirNode->tablespace = dirIterateDatabaseDirEntry->header.oid2;
*persistentTid = dirIterateDatabaseDirEntry->persistentTid;
*persistentSerialNum = dirIterateDatabaseDirEntry->persistentSerialNum;
dirIterateDatabaseDirEntry->iteratorRefCount++;
break;
}
READ_PERSISTENT_STATE_ORDERED_UNLOCK;
return true;
}
void PersistentDatabase_DirIterateClose(void)
{
READ_PERSISTENT_STATE_ORDERED_LOCK_DECLARE;
Assert(persistentDatabaseSharedData != NULL);
READ_PERSISTENT_STATE_ORDERED_LOCK;
PersistentDatabase_VerifyInitScan();
PersistentDatabase_ReleaseDirIterator();
READ_PERSISTENT_STATE_ORDERED_UNLOCK;
}
bool PersistentDatabase_DbDirExistsUnderLock(
DbDirNode *dbDirNode)
{
DatabaseDirEntry databaseDirEntry;
PersistentDatabase_VerifyInitScan();
databaseDirEntry =
(DatabaseDirEntry)
SharedOidSearch_Find(
&persistentDatabaseSharedData->databaseDirSearchTable,
dbDirNode->database,
dbDirNode->tablespace);
return (databaseDirEntry != NULL);
}
extern void PersistentDatabase_Reset(void)
{
DatabaseDirEntry databaseDirEntry;
databaseDirEntry = NULL;
SharedOidSearch_Iterate(
&persistentDatabaseSharedData->databaseDirSearchTable,
(SharedOidSearchObjHeader**)&databaseDirEntry);
while (true)
{
PersistentFileSysObjName fsObjName;
DatabaseDirEntry nextDatabaseDirEntry;
if (databaseDirEntry == NULL)
{
break;
}
PersistentFileSysObjName_SetDatabaseDir(
&fsObjName,
/* tablespaceOid */ databaseDirEntry->header.oid2,
/* databaseOid */ databaseDirEntry->header.oid1,
NULL);
if (Debug_persistent_print)
elog(Persistent_DebugPrintLevel(),
"Persistent database directory: Resetting '%s' serial number " INT64_FORMAT " at TID %s",
PersistentFileSysObjName_ObjectName(&fsObjName),
databaseDirEntry->persistentSerialNum,
ItemPointerToString(&databaseDirEntry->persistentTid));
nextDatabaseDirEntry = databaseDirEntry;
SharedOidSearch_Iterate(
&persistentDatabaseSharedData->databaseDirSearchTable,
(SharedOidSearchObjHeader**)&nextDatabaseDirEntry);
SharedOidSearch_Delete(
&persistentDatabaseSharedData->databaseDirSearchTable,
&databaseDirEntry->header);
databaseDirEntry = nextDatabaseDirEntry;
}
}
// -----------------------------------------------------------------------------
// Helpers
// -----------------------------------------------------------------------------
static void PersistentDatabase_LookupExistingDbDir(
DbDirNode *dbDirNode,
DatabaseDirEntry *databaseDirEntry)
{
PersistentDatabase_VerifyInitScan();
*databaseDirEntry =
(DatabaseDirEntry)
SharedOidSearch_Find(
&persistentDatabaseSharedData->databaseDirSearchTable,
dbDirNode->database,
dbDirNode->tablespace);
if (*databaseDirEntry == NULL)
elog(ERROR, "Persistent database entry '%s' expected to exist",
GetDatabasePath(dbDirNode->database, dbDirNode->tablespace));
}
/*
* We pass in changable columns like mirrorExistenceState, parentXid, etc instead
* of keep them in our DatabaseDirEntry to avoid stale data.
*/
static void PersistentDatabase_AddTuple(
DatabaseDirEntry databaseDirEntry,
int32 reserved,
TransactionId parentXid,
bool flushToXLog)
/* When true, the XLOG record for this change will be flushed to disk. */
{
Oid tablespaceOid = databaseDirEntry->header.oid2;
Oid databaseOid = databaseDirEntry->header.oid1;
ItemPointerData previousFreeTid;
Datum values[Natts_gp_persistent_database_node];
MemSet(&previousFreeTid, 0, sizeof(ItemPointerData));
GpPersistentDatabaseNode_SetDatumValues(
values,
tablespaceOid,
databaseOid,
databaseDirEntry->state,
reserved,
parentXid,
/* persistentSerialNum */ 0, // This will be set by PersistentFileSysObj_AddTuple.
&previousFreeTid,
is_tablespace_shared(tablespaceOid));
PersistentFileSysObj_AddTuple(
PersistentFsObjType_DatabaseDir,
values,
flushToXLog,
&databaseDirEntry->persistentTid,
&databaseDirEntry->persistentSerialNum);
}
// -----------------------------------------------------------------------------
// State Change
// -----------------------------------------------------------------------------
/*
* Indicate we intend to create a relation 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 relation files that are going
* to be created, call ~_DoPendingCreates to do the actual file-system creates. (See its
* note on XLOG flushing).
*/
void PersistentDatabase_MarkCreatePending(
DbDirNode *dbDirNode,
ItemPointer persistentTid,
int64 *persistentSerialNum,
bool flushToXLog)
{
WRITE_PERSISTENT_STATE_ORDERED_LOCK_DECLARE;
DatabaseDirEntry databaseDirEntry;
SharedOidSearchAddResult addResult;
PersistentFileSysObjName fsObjName;
if (Persistent_BeforePersistenceWork())
{
if (Debug_persistent_print)
elog(Persistent_DebugPrintLevel(),
"Skipping persistent database '%s' because we are before persistence work",
GetDatabasePath(
dbDirNode->database,
dbDirNode->tablespace));
/*
* The initdb process will load the persistent table once we
* out of bootstrap mode.
*/
return;
}
PersistentDatabase_VerifyInitScan();
PersistentFileSysObjName_SetDatabaseDir(
&fsObjName,
dbDirNode->tablespace,
dbDirNode->database,
is_tablespace_shared);
WRITE_PERSISTENT_STATE_ORDERED_LOCK;
databaseDirEntry =
(DatabaseDirEntry)
SharedOidSearch_Find(
&persistentDatabaseSharedData->databaseDirSearchTable,
dbDirNode->database,
dbDirNode->tablespace);
if (databaseDirEntry != NULL)
elog(ERROR, "Persistent database entry '%s' already exists in state '%s'",
GetDatabasePath(
dbDirNode->database,
dbDirNode->tablespace),
PersistentFileSysObjState_Name(databaseDirEntry->state));
addResult =
SharedOidSearch_Add(
&persistentDatabaseSharedData->databaseDirSearchTable,
dbDirNode->database,
dbDirNode->tablespace,
(SharedOidSearchObjHeader**)&databaseDirEntry);
if (addResult == SharedOidSearchAddResult_NoMemory)
{
/* 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 databases"),
errhint("You may need to increase the gp_max_databases and "
"gp_max_tablespaces value"),
errOmitLocation(true)));
}
else if (addResult == SharedOidSearchAddResult_Exists)
elog(PANIC, "Persistent database entry '%s' already exists in state '%s'",
GetDatabasePath(
dbDirNode->database,
dbDirNode->tablespace),
PersistentFileSysObjState_Name(databaseDirEntry->state));
else
Assert(addResult == SharedOidSearchAddResult_Ok);
databaseDirEntry->state = PersistentFileSysState_CreatePending;
databaseDirEntry->iteratorRefCount = 0;
PersistentDatabase_AddTuple(
databaseDirEntry,
/* reserved */ 0,
/* parentXid */ GetTopTransactionId(),
flushToXLog);
*persistentTid = databaseDirEntry->persistentTid;
*persistentSerialNum = databaseDirEntry->persistentSerialNum;
/*
* This XLOG must be generated under the persistent write-lock.
*/
#ifdef MASTER_MIRROR_SYNC
mmxlog_log_create_database(dbDirNode->tablespace, dbDirNode->database,
persistentTid, persistentSerialNum);
#endif
#ifdef FAULT_INJECTOR
FaultInjector_InjectFaultIfSet(
FaultBeforePendingDeleteDatabaseEntry,
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;
}
void PersistentDatabase_AddCreated(
DbDirNode *dbDirNode,
/* The tablespace and database OIDs for the create. */
ItemPointer persistentTid,
/* TID of the gp_persistent_rel_files tuple for the rel file */
bool flushToXLog)
/* When true, the XLOG record for this change will be flushed to disk. */
{
WRITE_PERSISTENT_STATE_ORDERED_LOCK_DECLARE;
PersistentFileSysObjName fsObjName;
DatabaseDirEntry databaseDirEntry;
SharedOidSearchAddResult addResult;
int64 persistentSerialNum;
if (!Persistent_BeforePersistenceWork())
elog(ERROR, "We can only add to persistent meta-data when special states");
// Verify PersistentFileSysObj_BuildInitScan has been called.
PersistentDatabase_VerifyInitScan();
PersistentFileSysObjName_SetDatabaseDir(&fsObjName,dbDirNode->tablespace,dbDirNode->database,is_tablespace_shared);
WRITE_PERSISTENT_STATE_ORDERED_LOCK;
/*
* GpIdentity.segindex
* In the initdb, GpIdentity.segindex is set to -10000. It will update this
* value to the correct GpIdentity.segindex.
*/
databaseDirEntry =
(DatabaseDirEntry)
SharedOidSearch_Find(
&persistentDatabaseSharedData->databaseDirSearchTable,
dbDirNode->database,
dbDirNode->tablespace);
if (databaseDirEntry != NULL)
elog(ERROR, "Persistent database entry '%s' already exists in state '%s'",
GetDatabasePath(
dbDirNode->database,
dbDirNode->tablespace),
PersistentFileSysObjState_Name(databaseDirEntry->state));
addResult =
SharedOidSearch_Add(
&persistentDatabaseSharedData->databaseDirSearchTable,
dbDirNode->database,
dbDirNode->tablespace,
(SharedOidSearchObjHeader**)&databaseDirEntry);
if (addResult == SharedOidSearchAddResult_NoMemory)
{
/* 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 databases"),
errhint("You may need to increase the gp_max_databases and "
"gp_max_tablespaces value"),
errOmitLocation(true)));
}
else if (addResult == SharedOidSearchAddResult_Exists)
elog(PANIC, "Persistent database entry '%s' already exists in state '%s'",
GetDatabasePath(
dbDirNode->database,
dbDirNode->tablespace),
PersistentFileSysObjState_Name(databaseDirEntry->state));
else
Assert(addResult == SharedOidSearchAddResult_Ok);
databaseDirEntry->state = PersistentFileSysState_Created;
databaseDirEntry->iteratorRefCount = 0;
PersistentDatabase_AddTuple(
databaseDirEntry,
/* reserved */ 0,
InvalidTransactionId,
flushToXLog);
*persistentTid = databaseDirEntry->persistentTid;
persistentSerialNum = databaseDirEntry->persistentSerialNum;
WRITE_PERSISTENT_STATE_ORDERED_UNLOCK;
if (Debug_persistent_print)
elog(Persistent_DebugPrintLevel(),
"Persistent database directory: Add '%s' in state 'Created', serial number " INT64_FORMAT " at TID %s",
PersistentFileSysObjName_ObjectName(&fsObjName),
persistentSerialNum,
ItemPointerToString(persistentTid));
}
void
xlog_create_database(DbDirNode *db)
{
DatabaseDirEntry dbe;
SharedOidSearchAddResult addResult;
WRITE_PERSISTENT_STATE_ORDERED_LOCK_DECLARE;
PersistentDatabase_VerifyInitScan();
WRITE_PERSISTENT_STATE_ORDERED_LOCK;
/*
* XXX:mat3: This is the dead code in HAWQ. There is no local recovery on
* segment. And master has its own rerecover code path.
*/
dbe = (DatabaseDirEntry) SharedOidSearch_Find(
&persistentDatabaseSharedData->databaseDirSearchTable,
db->database,
db->tablespace);
if (dbe != NULL)
elog(ERROR, "persistent database entry '%s' already exists "
"in state '%s'",
GetDatabasePath(
db->database,
db->tablespace),
PersistentFileSysObjState_Name(dbe->state));
addResult = SharedOidSearch_Add(
&persistentDatabaseSharedData->databaseDirSearchTable,
db->database,
db->tablespace,
(SharedOidSearchObjHeader**)&dbe);
if (addResult == SharedOidSearchAddResult_NoMemory)
elog(ERROR, "out of shared-memory for persistent databases");
else if (addResult == SharedOidSearchAddResult_Exists)
elog(PANIC, "persistent database entry '%s' already exists in "
"state '%s'",
GetDatabasePath(
db->database,
db->tablespace),
PersistentFileSysObjState_Name(dbe->state));
else
Insist(addResult == SharedOidSearchAddResult_Ok);
dbe->state = PersistentFileSysState_Created;
dbe->iteratorRefCount = 0;
WRITE_PERSISTENT_STATE_ORDERED_UNLOCK;
}
// -----------------------------------------------------------------------------
// Transaction End
// -----------------------------------------------------------------------------
/*
* Indicate the transaction commited and the relation is officially created.
*/
void PersistentDatabase_Created(
PersistentFileSysObjName *fsObjName,
/* The tablespace and database OIDs for the created relation. */
ItemPointer persistentTid,
/* TID of the gp_persistent_rel_files tuple for the rel file */
int64 persistentSerialNum,
/* Serial number for the relation. Distinquishes the uses of the tuple. */
bool retryPossible)
{
WRITE_PERSISTENT_STATE_ORDERED_LOCK_DECLARE;
DbDirNode *dbDirNode = &fsObjName->variant.dbDirNode;
DatabaseDirEntry databaseDirEntry;
PersistentFileSysObjStateChangeResult stateChangeResult;
if (Persistent_BeforePersistenceWork())
{
if (Debug_persistent_print)
elog(Persistent_DebugPrintLevel(),
"Skipping persistent database '%s' because we are before persistence work",
GetDatabasePath(
dbDirNode->database,
dbDirNode->tablespace));
return; // The initdb process will load the persistent table once we out of bootstrap mode.
}
PersistentDatabase_VerifyInitScan();
WRITE_PERSISTENT_STATE_ORDERED_LOCK;
PersistentDatabase_LookupExistingDbDir(
dbDirNode,
&databaseDirEntry);
if (databaseDirEntry->state != PersistentFileSysState_CreatePending)
elog(ERROR, "Persistent database entry %s expected to be in 'Create Pending' state (actual state '%s')",
GetDatabasePath(
dbDirNode->database,
dbDirNode->tablespace),
PersistentFileSysObjState_Name(databaseDirEntry->state));
stateChangeResult =
PersistentFileSysObj_StateChange(
fsObjName,
persistentTid,
persistentSerialNum,
PersistentFileSysState_Created,
retryPossible,
/* flushToXlog */ false,
/* oldState */ NULL,
/* verifiedActionCallback */ NULL);
databaseDirEntry->state = PersistentFileSysState_Created;
WRITE_PERSISTENT_STATE_ORDERED_UNLOCK;
if (Debug_persistent_print)
elog(Persistent_DebugPrintLevel(),
"Persistent database 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 relation file as part of the current transaction.
*
* This relation 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 PersistentDatabase_MarkDropPending(
PersistentFileSysObjName *fsObjName,
/* The tablespace and database OIDs for the drop. */
ItemPointer persistentTid,
/* TID of the gp_persistent_rel_files tuple for the rel file */
int64 persistentSerialNum,
/* Serial number for the relation. Distinquishes the uses of the tuple. */
bool retryPossible)
{
WRITE_PERSISTENT_STATE_ORDERED_LOCK_DECLARE;
DbDirNode *dbDirNode = &fsObjName->variant.dbDirNode;
DatabaseDirEntry databaseDirEntry;
PersistentFileSysObjStateChangeResult stateChangeResult;
if (Persistent_BeforePersistenceWork())
{
if (Debug_persistent_print)
elog(Persistent_DebugPrintLevel(),
"Skipping persistent database '%s' because we are before persistence work",
GetDatabasePath(
dbDirNode->database,
dbDirNode->tablespace));
return false; // The initdb process will load the persistent table once we out of bootstrap mode.
}
PersistentDatabase_VerifyInitScan();
WRITE_PERSISTENT_STATE_ORDERED_LOCK;
PersistentDatabase_LookupExistingDbDir(
dbDirNode,
&databaseDirEntry);
if (databaseDirEntry->state != PersistentFileSysState_CreatePending &&
databaseDirEntry->state != PersistentFileSysState_Created)
elog(ERROR, "Persistent database entry %s expected to be in 'Create Pending' or 'Created' state (actual state '%s')",
GetDatabasePath(
dbDirNode->database,
dbDirNode->tablespace),
PersistentFileSysObjState_Name(databaseDirEntry->state));
stateChangeResult =
PersistentFileSysObj_StateChange(
fsObjName,
persistentTid,
persistentSerialNum,
PersistentFileSysState_DropPending,
retryPossible,
/* flushToXlog */ false,
/* oldState */ NULL,
/* verifiedActionCallback */ NULL);
databaseDirEntry->state = PersistentFileSysState_DropPending;
WRITE_PERSISTENT_STATE_ORDERED_UNLOCK;
if (Debug_persistent_print)
elog(Persistent_DebugPrintLevel(),
"Persistent database 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;
}
/*
* Indicate we are aborting the create of a relation file.
*
* This state will make sure the relation gets dropped after a system crash.
*/
PersistentFileSysObjStateChangeResult PersistentDatabase_MarkAbortingCreate(
PersistentFileSysObjName *fsObjName,
/* The tablespace and database OIDs for the aborting create. */
ItemPointer persistentTid,
/* TID of the gp_persistent_rel_files tuple for the rel file */
int64 persistentSerialNum,
/* Serial number for the relation. Distinquishes the uses of the tuple. */
bool retryPossible)
{
WRITE_PERSISTENT_STATE_ORDERED_LOCK_DECLARE;
DbDirNode *dbDirNode = &fsObjName->variant.dbDirNode;
DatabaseDirEntry databaseDirEntry;
PersistentFileSysObjStateChangeResult stateChangeResult;
if (Persistent_BeforePersistenceWork())
{
if (Debug_persistent_print)
elog(Persistent_DebugPrintLevel(),
"Skipping persistent database '%s' because we are before persistence work",
GetDatabasePath(
dbDirNode->database,
dbDirNode->tablespace));
return false; // The initdb process will load the persistent table once we out of bootstrap mode.
}
PersistentDatabase_VerifyInitScan();
WRITE_PERSISTENT_STATE_ORDERED_LOCK;
PersistentDatabase_LookupExistingDbDir(
dbDirNode,
&databaseDirEntry);
if (databaseDirEntry->state != PersistentFileSysState_CreatePending)
elog(ERROR, "Persistent database entry %s expected to be in 'Create Pending' (actual state '%s')",
GetDatabasePath(
dbDirNode->database,
dbDirNode->tablespace),
PersistentFileSysObjState_Name(databaseDirEntry->state));
stateChangeResult =
PersistentFileSysObj_StateChange(
fsObjName,
persistentTid,
persistentSerialNum,
PersistentFileSysState_AbortingCreate,
retryPossible,
/* flushToXlog */ false,
/* oldState */ NULL,
/* verifiedActionCallback */ NULL);
databaseDirEntry->state = PersistentFileSysState_AbortingCreate;
WRITE_PERSISTENT_STATE_ORDERED_UNLOCK;
if (Debug_persistent_print)
elog(Persistent_DebugPrintLevel(),
"Persistent database 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
PersistentDatabase_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)
{
DbDirNode *dbDirNode = PersistentFileSysObjName_GetDbDirNodePtr(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_database(dbDirNode->tablespace, dbDirNode->database,
persistentTid, persistentSerialNum);
#endif
break;
default:
elog(ERROR, "Unexpected persistent object verify expected result: %d",
verifyExpectedResult);
}
}
/*
* Indicate we physically removed the relation file.
*/
void PersistentDatabase_Dropped(
PersistentFileSysObjName *fsObjName,
/* The tablespace and database OIDs for the dropped relation. */
ItemPointer persistentTid,
/* TID of the gp_persistent_rel_files tuple for the rel file */
int64 persistentSerialNum)
/* Serial number for the relation. Distinquishes the uses of the tuple. */
{
WRITE_PERSISTENT_STATE_ORDERED_LOCK_DECLARE;
DbDirNode *dbDirNode = &fsObjName->variant.dbDirNode;
DatabaseDirEntry databaseDirEntry;
PersistentFileSysState oldState;
PersistentFileSysObjStateChangeResult stateChangeResult;
if (Persistent_BeforePersistenceWork())
{
if (Debug_persistent_print)
elog(Persistent_DebugPrintLevel(),
"Skipping persistent database '%s' because we are before persistence work",
GetDatabasePath(
dbDirNode->database,
dbDirNode->tablespace));
return; // The initdb process will load the persistent table once we out of bootstrap mode.
}
PersistentDatabase_VerifyInitScan();
WRITE_PERSISTENT_STATE_ORDERED_LOCK;
PersistentDatabase_LookupExistingDbDir(
dbDirNode,
&databaseDirEntry);
if (databaseDirEntry->state != PersistentFileSysState_DropPending &&
databaseDirEntry->state != PersistentFileSysState_AbortingCreate)
elog(ERROR, "Persistent database entry %s expected to be in 'Drop Pending' or 'Aborting Create' (actual state '%s')",
GetDatabasePath(
dbDirNode->database,
dbDirNode->tablespace),
PersistentFileSysObjState_Name(databaseDirEntry->state));
stateChangeResult =
PersistentFileSysObj_StateChange(
fsObjName,
persistentTid,
persistentSerialNum,
PersistentFileSysState_Free,
/* retryPossible */ false,
/* flushToXlog */ false,
&oldState,
PersistentDatabase_DroppedVerifiedActionCallback);
databaseDirEntry->state = PersistentFileSysState_Free;
if (databaseDirEntry->iteratorRefCount == 0)
SharedOidSearch_Delete(
&persistentDatabaseSharedData->databaseDirSearchTable,
&databaseDirEntry->header);
WRITE_PERSISTENT_STATE_ORDERED_UNLOCK;
if (Debug_persistent_print)
elog(Persistent_DebugPrintLevel(),
"Persistent database 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));
}
bool
PersistentDatabase_DirIsCreated(DbDirNode *dbDirNode)
{
READ_PERSISTENT_STATE_ORDERED_LOCK_DECLARE;
DatabaseDirEntry databaseDirEntry;
bool result;
if (Persistent_BeforePersistenceWork())
{
if (Debug_persistent_print)
elog(Persistent_DebugPrintLevel(),
"Skipping persistent database '%s' because we are before "
"persistence work",
GetDatabasePath(
dbDirNode->database,
dbDirNode->tablespace));
/*
* The initdb process will load the persistent table once we out of
* bootstrap mode.
*/
return true;
}
PersistentDatabase_VerifyInitScan();
READ_PERSISTENT_STATE_ORDERED_LOCK;
databaseDirEntry =
(DatabaseDirEntry)
SharedOidSearch_Find(
&persistentDatabaseSharedData->databaseDirSearchTable,
dbDirNode->database,
dbDirNode->tablespace);
result = (databaseDirEntry != NULL);
if (result &&
databaseDirEntry->state != PersistentFileSysState_Created &&
databaseDirEntry->state != PersistentFileSysState_CreatePending &&
databaseDirEntry->state != PersistentFileSysState_JustInTimeCreatePending)
elog(ERROR, "Persistent database entry %s expected to be in 'Create Pending' or 'Created' (actual state '%s')",
GetDatabasePath(
dbDirNode->database,
dbDirNode->tablespace),
PersistentFileSysObjState_Name(databaseDirEntry->state));
READ_PERSISTENT_STATE_ORDERED_UNLOCK;
return result;
}
void PersistentDatabase_MarkJustInTimeCreatePending(
DbDirNode *dbDirNode,
ItemPointer persistentTid,
int64 *persistentSerialNum)
{
WRITE_PERSISTENT_STATE_ORDERED_LOCK_DECLARE;
PersistentFileSysObjName fsObjName;
DatabaseDirEntry databaseDirEntry;
SharedOidSearchAddResult addResult;
if (Persistent_BeforePersistenceWork())
{
if (Debug_persistent_print)
elog(Persistent_DebugPrintLevel(),
"Skipping persistent database '%s' because we are before persistence work",
GetDatabasePath(
dbDirNode->database,
dbDirNode->tablespace));
return; // The initdb process will load the persistent table once we out of bootstrap mode.
}
PersistentDatabase_VerifyInitScan();
PersistentFileSysObjName_SetDatabaseDir(&fsObjName,dbDirNode->tablespace,dbDirNode->database,is_tablespace_shared);
WRITE_PERSISTENT_STATE_ORDERED_LOCK;
databaseDirEntry =
(DatabaseDirEntry)
SharedOidSearch_Find(
&persistentDatabaseSharedData->databaseDirSearchTable,
dbDirNode->database,
dbDirNode->tablespace);
if (databaseDirEntry != NULL)
{
/*
* An existence check should have been done before calling this routine.
*/
elog(ERROR, "Persistent database entry '%s' already exists in state '%s'",
GetDatabasePath(
dbDirNode->database,
dbDirNode->tablespace),
PersistentFileSysObjState_Name(databaseDirEntry->state));
}
addResult =
SharedOidSearch_Add(
&persistentDatabaseSharedData->databaseDirSearchTable,
dbDirNode->database,
dbDirNode->tablespace,
(SharedOidSearchObjHeader**)&databaseDirEntry);
if (addResult == SharedOidSearchAddResult_NoMemory)
{
/* 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 databases"),
errhint("You may need to increase the gp_max_databases and "
"gp_max_tablespaces value"),
errOmitLocation(true)));
}
else if (addResult == SharedOidSearchAddResult_Exists)
elog(PANIC, "Persistent database entry '%s' already exists in state '%s'",
GetDatabasePath(
dbDirNode->database,
dbDirNode->tablespace),
PersistentFileSysObjState_Name(databaseDirEntry->state));
else
Assert(addResult == SharedOidSearchAddResult_Ok);
databaseDirEntry->state = PersistentFileSysState_JustInTimeCreatePending;
PersistentDatabase_AddTuple(
databaseDirEntry,
/* reserved */ 0,
/* parentXid */ InvalidTransactionId,
/* flushToXLog */ true);
*persistentTid = databaseDirEntry->persistentTid;
*persistentSerialNum = databaseDirEntry->persistentSerialNum;
/*
* This XLOG must be generated under the persistent write-lock.
*/
#ifdef MASTER_MIRROR_SYNC
mmxlog_log_create_database(dbDirNode->tablespace,
dbDirNode->database,
persistentTid, persistentSerialNum);
#endif
WRITE_PERSISTENT_STATE_ORDERED_UNLOCK;
}
/*
* Indicate the non-transaction just-in-time database create was successful.
*/
void PersistentDatabase_JustInTimeCreated(
DbDirNode *dbDirNode,
ItemPointer persistentTid,
/* TID of the gp_persistent_rel_files tuple for the rel file */
int64 persistentSerialNum)
/* Serial number for the relation. Distinquishes the uses of the tuple. */
{
WRITE_PERSISTENT_STATE_ORDERED_LOCK_DECLARE;
PersistentFileSysObjName fsObjName;
DatabaseDirEntry databaseDirEntry;
PersistentFileSysObjStateChangeResult stateChangeResult;
if (Persistent_BeforePersistenceWork())
{
if (Debug_persistent_print)
elog(Persistent_DebugPrintLevel(),
"Skipping persistent database '%s' because we are before persistence work",
GetDatabasePath(
dbDirNode->database,
dbDirNode->tablespace));
return; // The initdb process will load the persistent table once we out of bootstrap mode.
}
PersistentDatabase_VerifyInitScan();
PersistentFileSysObjName_SetDatabaseDir(&fsObjName,dbDirNode->tablespace,dbDirNode->database,is_tablespace_shared);
WRITE_PERSISTENT_STATE_ORDERED_LOCK;
PersistentDatabase_LookupExistingDbDir(
dbDirNode,
&databaseDirEntry);
if (databaseDirEntry->state != PersistentFileSysState_JustInTimeCreatePending)
elog(ERROR, "Persistent database entry %s expected to be in 'Just-In-Time Create Pending' state (actual state '%s')",
GetDatabasePath(
dbDirNode->database,
dbDirNode->tablespace),
PersistentFileSysObjState_Name(databaseDirEntry->state));
stateChangeResult =
PersistentFileSysObj_StateChange(
&fsObjName,
persistentTid,
persistentSerialNum,
PersistentFileSysState_Created,
/* retryPossible */ false,
/* flushToXlog */ false,
/* oldState */ NULL,
/* verifiedActionCallback */ NULL);
databaseDirEntry->state = PersistentFileSysState_Created;
WRITE_PERSISTENT_STATE_ORDERED_UNLOCK;
if (Debug_persistent_print)
elog(Persistent_DebugPrintLevel(),
"Persistent database directory: '%s' changed state from 'Just-In-Time 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 the non-transaction just-in-time database create was NOT successful.
*/
void PersistentDatabase_AbandonJustInTimeCreatePending(
DbDirNode *dbDirNode,
ItemPointer persistentTid,
/* TID of the gp_persistent_rel_files tuple for the rel file */
int64 persistentSerialNum)
/* Serial number for the relation. Distinquishes the uses of the tuple. */
{
WRITE_PERSISTENT_STATE_ORDERED_LOCK_DECLARE;
PersistentFileSysObjName fsObjName;
DatabaseDirEntry databaseDirEntry;
PersistentFileSysObjStateChangeResult stateChangeResult;
if (Persistent_BeforePersistenceWork())
{
if (Debug_persistent_print)
elog(Persistent_DebugPrintLevel(),
"Skipping persistent database '%s' because we are before persistence work",
GetDatabasePath(
dbDirNode->database,
dbDirNode->tablespace));
return; // The initdb process will load the persistent table once we out of bootstrap mode.
}
PersistentDatabase_VerifyInitScan();
PersistentFileSysObjName_SetDatabaseDir(&fsObjName,dbDirNode->tablespace,dbDirNode->database,is_tablespace_shared);
WRITE_PERSISTENT_STATE_ORDERED_LOCK;
PersistentDatabase_LookupExistingDbDir(
dbDirNode,
&databaseDirEntry);
if (databaseDirEntry->state != PersistentFileSysState_JustInTimeCreatePending)
elog(ERROR, "Persistent database entry %s expected to be in 'Just-In-Time Create Pending' state (actual state '%s')",
GetDatabasePath(
dbDirNode->database,
dbDirNode->tablespace),
PersistentFileSysObjState_Name(databaseDirEntry->state));
stateChangeResult =
PersistentFileSysObj_StateChange(
&fsObjName,
persistentTid,
persistentSerialNum,
PersistentFileSysState_Free,
/* retryPossible */ false,
/* flushToXlog */ false,
/* oldState */ NULL,
/* verifiedActionCallback */ NULL);
databaseDirEntry->state = PersistentFileSysState_Free;
if (databaseDirEntry->iteratorRefCount == 0)
SharedOidSearch_Delete(
&persistentDatabaseSharedData->databaseDirSearchTable,
&databaseDirEntry->header);
WRITE_PERSISTENT_STATE_ORDERED_UNLOCK;
if (Debug_persistent_print)
elog(Persistent_DebugPrintLevel(),
"Persistent database directory: Abandon '%s' in state 'Just-In-Time Create Pending', serial number " INT64_FORMAT " at TID %s (State-Change result '%s')",
PersistentFileSysObjName_ObjectName(&fsObjName),
persistentSerialNum,
ItemPointerToString(persistentTid),
PersistentFileSysObjStateChangeResult_Name(stateChangeResult));
}
// -----------------------------------------------------------------------------
// Shmem
// -----------------------------------------------------------------------------
static Size PersistentDatabase_SharedDataSize(void)
{
return MAXALIGN(
offsetof(PersistentDatabaseSharedData,databaseDirSearchTable)) +
SharedOidSearch_TableLen(
/* hashSize */ 127,
/* freeObjectCount */ MaxPersistentDatabaseDirectories,
/* objectLen */ sizeof(DatabaseDirEntryData));
}
/*
* Return the required shared-memory size for this module.
*/
Size PersistentDatabase_ShmemSize(void)
{
if (MaxPersistentDatabaseDirectories == 0)
MaxPersistentDatabaseDirectories = gp_max_databases * gp_max_tablespaces;
elog(LOG, "PersistentDatabase_ShmemSize: %zu = "
"PersistentDatabase_SharedDataSize(): %zu = "
"PersistentDatabaseSharedData: %zu + "
"MaxPersistentDatabaseDirectories: %d (db: %d * ts: %d) * "
"sizeof(DatabaseDirEntryData): %zu",
PersistentDatabase_SharedDataSize(),
PersistentDatabase_SharedDataSize(),
offsetof(PersistentDatabaseSharedData,databaseDirSearchTable),
MaxPersistentDatabaseDirectories, gp_max_databases, gp_max_tablespaces,
sizeof(DatabaseDirEntryData));
/* The shared-memory structure. */
return PersistentDatabase_SharedDataSize();
}
/*
* Initialize the shared-memory for this module.
*/
void PersistentDatabase_ShmemInit(void)
{
bool found;
/* Create the shared-memory structure. */
persistentDatabaseSharedData =
(PersistentDatabaseSharedData *)
ShmemInitStruct("Persistent Database Data",
PersistentDatabase_SharedDataSize(),
&found);
if (!found)
{
PersistentFileSysObj_InitShared(
&persistentDatabaseSharedData->fileSysObjSharedData);
SharedOidSearch_InitTable(
&persistentDatabaseSharedData->databaseDirSearchTable,
127,
MaxPersistentDatabaseDirectories,
sizeof(DatabaseDirEntryData));
}
PersistentFileSysObj_Init(
&persistentDatabaseData.fileSysObjData,
&persistentDatabaseSharedData->fileSysObjSharedData,
PersistentFsObjType_DatabaseDir,
PersistentDatabase_ScanTupleCallback);
Assert(persistentDatabaseSharedData != NULL);
}
void PersistentDatabase_CheckTablespace(
Oid tablespace,
int32 *useCount)
{
persistentDatabaseCheckTablespace = tablespace;
persistentDatabaseCheckTablespaceUseCount = 0;
PersistentFileSysObj_Scan(
PersistentFsObjType_DatabaseDir,
PersistentDatabase_CheckTablespaceScanTupleCallback);
*useCount = persistentDatabaseCheckTablespaceUseCount;
}
/*
* Pass shared data back to the caller. See add_tablespace_data() for why we do
* it like this.
*/
#ifdef MASTER_MIRROR_SYNC /* annotation to show that this is just for mmsync */
void
get_database_data(dbdir_agg_state **das, char *caller)
{
DatabaseDirEntry databaseDirEntry;
int maxCount;
Assert(*das == NULL);
mmxlog_add_database_init(das, &maxCount);
databaseDirEntry = NULL;
while (true)
{
SharedOidSearch_Iterate(
&persistentDatabaseSharedData->databaseDirSearchTable,
(SharedOidSearchObjHeader**)&databaseDirEntry);
if (databaseDirEntry == NULL)
{
break;
}
mmxlog_add_database(
das, &maxCount,
/* databaseoid */ databaseDirEntry->header.oid1,
/* tablespaceoid */ databaseDirEntry->header.oid2,
caller);
}
}
#endif