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; }
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; }
/* * ProcessCommittedInvalidationMessages is executed by xact_redo_commit() * to process invalidation messages added to commit records. * * Relcache init file invalidation requires processing both * before and after we send the SI messages. See AtEOXact_Inval() */ void ProcessCommittedInvalidationMessages(SharedInvalidationMessage *msgs, int nmsgs, bool RelcacheInitFileInval, Oid dbid, Oid tsid) { if (nmsgs <= 0) return; elog(trace_recovery(DEBUG4), "replaying commit with %d messages%s", nmsgs, (RelcacheInitFileInval ? " and relcache file invalidation" : "")); if (RelcacheInitFileInval) { /* * RelationCacheInitFilePreInvalidate requires DatabasePath to be set, * but we should not use SetDatabasePath during recovery, since it is * intended to be used only once by normal backends. Hence, a quick * hack: set DatabasePath directly then unset after use. */ DatabasePath = GetDatabasePath(dbid, tsid); elog(trace_recovery(DEBUG4), "removing relcache init file in \"%s\"", DatabasePath); RelationCacheInitFilePreInvalidate(); pfree(DatabasePath); DatabasePath = NULL; } SendSharedInvalidMessages(msgs, nmsgs); if (RelcacheInitFileInval) RelationCacheInitFilePostInvalidate(); }
Datum database_size(PG_FUNCTION_ARGS) { Name dbname = PG_GETARG_NAME(0); Oid dbid; char *dbpath; DIR *dirdesc; struct dirent *direntry; int64 totalsize; dbid = get_database_oid(NameStr(*dbname)); if (!OidIsValid(dbid)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_DATABASE), errmsg("database \"%s\" does not exist", NameStr(*dbname)))); dbpath = GetDatabasePath(dbid); dirdesc = AllocateDir(dbpath); if (!dirdesc) ereport(ERROR, (errcode_for_file_access(), errmsg("could not open directory \"%s\": %m", dbpath))); totalsize = 0; for (;;) { char *fullname; struct stat statbuf; errno = 0; direntry = readdir(dirdesc); if (!direntry) { if (errno) ereport(ERROR, (errcode_for_file_access(), errmsg("error reading directory: %m"))); else break; } fullname = psnprintf(strlen(dbpath) + 1 + strlen(direntry->d_name) + 1, "%s/%s", dbpath, direntry->d_name); if (stat(fullname, &statbuf) == -1) ereport(ERROR, (errcode_for_file_access(), errmsg("could not stat \"%s\": %m", fullname))); totalsize += statbuf.st_size; pfree(fullname); } FreeDir(dirdesc); PG_RETURN_INT64(totalsize); }
//-------------------------------------------------------------------// // GetDBBackupPath() // //-------------------------------------------------------------------// void DatabaseArray::GetDBBackupPath( CString* pstrPath ) { GetDatabasePath( pstrPath ); *pstrPath += _T("Backup\\"); // Make sure it exists. _tmkdir( LPCTSTR( *pstrPath ) ); }
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)); }
void FileRepSubProcess_InitHeapAccess(void) { char *fullpath; static bool heapAccessInitialized = false; if (heapAccessInitialized) return; /* heap access requires the rel-cache */ RelationCacheInitialize(); InitCatalogCache(); /* * It's now possible to do real access to the system catalogs. * * Load relcache entries for the system catalogs. This must create at * least the minimum set of "nailed-in" cache entries. */ RelationCacheInitializePhase2(); /* * In order to access the catalog, we need a database, and a tablespace; * our access to the heap is going to be slightly limited, so we'll just * use some defaults. */ MyDatabaseId = TemplateDbOid; MyDatabaseTableSpace = DEFAULTTABLESPACE_OID; /* Now we can mark our PGPROC entry with the database ID */ /* (We assume this is an atomic store so no lock is needed) */ MyProc->databaseId = MyDatabaseId; fullpath = GetDatabasePath(MyDatabaseId, MyDatabaseTableSpace); SetDatabasePath(fullpath); RelationCacheInitializePhase3(); heapAccessInitialized = true; }
/* * RELMAP resource manager's routines */ void relmap_redo(XLogRecPtr lsn, XLogRecord *record) { uint8 info = record->xl_info & ~XLR_INFO_MASK; /* Backup blocks are not used in relmap records */ Assert(!(record->xl_info & XLR_BKP_BLOCK_MASK)); if (info == XLOG_RELMAP_UPDATE) { xl_relmap_update *xlrec = (xl_relmap_update *) XLogRecGetData(record); RelMapFile newmap; char *dbpath; if (xlrec->nbytes != sizeof(RelMapFile)) elog(PANIC, "relmap_redo: wrong size %u in relmap update record", xlrec->nbytes); memcpy(&newmap, xlrec->data, sizeof(newmap)); /* We need to construct the pathname for this database */ dbpath = GetDatabasePath(xlrec->dbid, xlrec->tsid); /* * Write out the new map and send sinval, but of course don't write a * new WAL entry. There's no surrounding transaction to tell to * preserve files, either. * * There shouldn't be anyone else updating relmaps during WAL replay, * so we don't bother to take the RelationMappingLock. We would need * to do so if load_relmap_file needed to interlock against writers. */ write_relmap_file((xlrec->dbid == InvalidOid), &newmap, false, true, false, xlrec->dbid, xlrec->tsid, dbpath); pfree(dbpath); } else elog(PANIC, "relmap_redo: unknown op code %u", info); }
void wxZRColaFrame::OnHelpShortcuts(wxCommandEvent& event) { winstd::tstring pdf_path; #ifdef __WXMSW__ // Search and try to launch installed PDF. INSTALLSTATE pdf_is = ::MsiGetComponentPath(_T(PRODUCT_VERSION_GUID), _T("{68AC2C38-10E2-41A3-B92C-844C03FFDF6A}"), pdf_path); if ((pdf_is == INSTALLSTATE_LOCAL || pdf_is == INSTALLSTATE_SOURCE) && wxFileExists(pdf_path) && (int)::ShellExecute(GetHWND(), NULL, pdf_path.c_str(), NULL, NULL, SW_SHOWNORMAL) > 32) return; #endif // Search and try to launch local PDF copy. auto app = dynamic_cast<ZRColaApp*>(wxTheApp); pdf_path = app->GetDatabasePath(); pdf_path += _T("ZRCola_keyboard.pdf"); if (wxFileExists(pdf_path) && (int)::ShellExecute(GetHWND(), NULL, pdf_path.c_str(), NULL, NULL, SW_SHOWNORMAL) > 32) return; // When everything else fail, try the online version. wxLaunchDefaultBrowser(_("http://zrcola.zrc-sazu.si/wp-content/uploads/2016/06/ZRCola_tipkovnica_Jun2016.pdf")); }
/* -------------------------------- * InitPostgres * Initialize POSTGRES. * * The database can be specified by name, using the in_dbname parameter, or by * OID, using the dboid parameter. In the latter case, the computed database * name is passed out to the caller as a palloc'ed string in out_dbname. * * In bootstrap mode no parameters are used. * * The return value indicates whether the userID is a superuser. (That * can only be tested inside a transaction, so we want to do it during * the startup transaction rather than doing a separate one in postgres.c.) * * As of PostgreSQL 8.2, we expect InitProcess() was already called, so we * already have a PGPROC struct ... but it's not filled in yet. * * Note: * Be very careful with the order of calls in the InitPostgres function. * -------------------------------- */ bool InitPostgres(const char *in_dbname, Oid dboid, const char *username, char **out_dbname) { bool bootstrap = IsBootstrapProcessingMode(); bool autovacuum = IsAutoVacuumWorkerProcess(); bool am_superuser; char *fullpath; char dbname[NAMEDATALEN]; /* * Set up the global variables holding database id and path. But note we * won't actually try to touch the database just yet. * * We take a shortcut in the bootstrap case, otherwise we have to look up * the db name in pg_database. */ if (bootstrap) { MyDatabaseId = TemplateDbOid; MyDatabaseTableSpace = DEFAULTTABLESPACE_OID; } else { /* * Find tablespace of the database we're about to open. Since we're * not yet up and running we have to use one of the hackish * FindMyDatabase variants, which look in the flat-file copy of * pg_database. * * If the in_dbname param is NULL, lookup database by OID. */ if (in_dbname == NULL) { if (!FindMyDatabaseByOid(dboid, dbname, &MyDatabaseTableSpace)) ereport(FATAL, (errcode(ERRCODE_UNDEFINED_DATABASE), errmsg("database %u does not exist", dboid))); MyDatabaseId = dboid; /* pass the database name to the caller */ *out_dbname = pstrdup(dbname); } else { if (!FindMyDatabase(in_dbname, &MyDatabaseId, &MyDatabaseTableSpace)) ereport(FATAL, (errcode(ERRCODE_UNDEFINED_DATABASE), errmsg("database \"%s\" does not exist", in_dbname))); /* our database name is gotten from the caller */ strlcpy(dbname, in_dbname, NAMEDATALEN); } } fullpath = GetDatabasePath(MyDatabaseId, MyDatabaseTableSpace); SetDatabasePath(fullpath); /* * Finish filling in the PGPROC struct, and add it to the ProcArray. (We * need to know MyDatabaseId before we can do this, since it's entered * into the PGPROC struct.) * * Once I have done this, I am visible to other backends! */ InitProcessPhase2(); /* * Initialize my entry in the shared-invalidation manager's array of * per-backend data. * * Sets up MyBackendId, a unique backend identifier. */ MyBackendId = InvalidBackendId; SharedInvalBackendInit(); if (MyBackendId > MaxBackends || MyBackendId <= 0) elog(FATAL, "bad backend id: %d", MyBackendId); /* * bufmgr needs another initialization call too */ InitBufferPoolBackend(); /* * Initialize local process's access to XLOG. In bootstrap case we may * skip this since StartupXLOG() was run instead. */ if (!bootstrap) InitXLOGAccess(); /* * Initialize the relation cache and the system catalog caches. Note that * no catalog access happens here; we only set up the hashtable structure. * We must do this before starting a transaction because transaction abort * would try to touch these hashtables. */ RelationCacheInitialize(); InitCatalogCache(); InitPlanCache(); /* Initialize portal manager */ EnablePortalManager(); /* Initialize stats collection --- must happen before first xact */ if (!bootstrap) pgstat_initialize(); /* * Set up process-exit callback to do pre-shutdown cleanup. This has to * be after we've initialized all the low-level modules like the buffer * manager, because during shutdown this has to run before the low-level * modules start to close down. On the other hand, we want it in place * before we begin our first transaction --- if we fail during the * initialization transaction, as is entirely possible, we need the * AbortTransaction call to clean up. */ on_shmem_exit(ShutdownPostgres, 0); /* * Start a new transaction here before first access to db, and get a * snapshot. We don't have a use for the snapshot itself, but we're * interested in the secondary effect that it sets RecentGlobalXmin. */ if (!bootstrap) { StartTransactionCommand(); (void) GetTransactionSnapshot(); } /* * Now that we have a transaction, we can take locks. Take a writer's * lock on the database we are trying to connect to. If there is a * concurrently running DROP DATABASE on that database, this will block us * until it finishes (and has updated the flat file copy of pg_database). * * Note that the lock is not held long, only until the end of this startup * transaction. This is OK since we are already advertising our use of * the database in the PGPROC array; anyone trying a DROP DATABASE after * this point will see us there. * * Note: use of RowExclusiveLock here is reasonable because we envision * our session as being a concurrent writer of the database. If we had a * way of declaring a session as being guaranteed-read-only, we could use * AccessShareLock for such sessions and thereby not conflict against * CREATE DATABASE. */ if (!bootstrap) LockSharedObject(DatabaseRelationId, MyDatabaseId, 0, RowExclusiveLock); /* * Recheck the flat file copy of pg_database to make sure the target * database hasn't gone away. If there was a concurrent DROP DATABASE, * this ensures we will die cleanly without creating a mess. */ if (!bootstrap) { Oid dbid2; Oid tsid2; if (!FindMyDatabase(dbname, &dbid2, &tsid2) || dbid2 != MyDatabaseId || tsid2 != MyDatabaseTableSpace) ereport(FATAL, (errcode(ERRCODE_UNDEFINED_DATABASE), errmsg("database \"%s\" does not exist", dbname), errdetail("It seems to have just been dropped or renamed."))); } /* * Now we should be able to access the database directory safely. Verify * it's there and looks reasonable. */ if (!bootstrap) { if (access(fullpath, F_OK) == -1) { if (errno == ENOENT) ereport(FATAL, (errcode(ERRCODE_UNDEFINED_DATABASE), errmsg("database \"%s\" does not exist", dbname), errdetail("The database subdirectory \"%s\" is missing.", fullpath))); else ereport(FATAL, (errcode_for_file_access(), errmsg("could not access directory \"%s\": %m", fullpath))); } ValidatePgVersion(fullpath); } /* * It's now possible to do real access to the system catalogs. * * Load relcache entries for the system catalogs. This must create at * least the minimum set of "nailed-in" cache entries. */ RelationCacheInitializePhase2(); /* * Figure out our postgres user id, and see if we are a superuser. * * In standalone mode and in the autovacuum process, we use a fixed id, * otherwise we figure it out from the authenticated user name. */ if (bootstrap || autovacuum) { InitializeSessionUserIdStandalone(); am_superuser = true; } else if (!IsUnderPostmaster) { InitializeSessionUserIdStandalone(); am_superuser = true; if (!ThereIsAtLeastOneRole()) ereport(WARNING, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("no roles are defined in this database system"), errhint("You should immediately run CREATE USER \"%s\" CREATEUSER;.", username))); } else { /* normal multiuser case */ InitializeSessionUserId(username); am_superuser = superuser(); } /* set up ACL framework (so CheckMyDatabase can check permissions) */ initialize_acl(); /* * Read the real pg_database row for our database, check permissions and * set up database-specific GUC settings. We can't do this until all the * database-access infrastructure is up. (Also, it wants to know if the * user is a superuser, so the above stuff has to happen first.) */ if (!bootstrap) CheckMyDatabase(dbname, am_superuser); /* * If we're trying to shut down, only superusers can connect. */ if (!am_superuser && MyProcPort != NULL && MyProcPort->canAcceptConnections == CAC_WAITBACKUP) ereport(FATAL, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("must be superuser to connect during database shutdown"))); /* * Check a normal user hasn't connected to a superuser reserved slot. */ if (!am_superuser && ReservedBackends > 0 && !HaveNFreeProcs(ReservedBackends)) ereport(FATAL, (errcode(ERRCODE_TOO_MANY_CONNECTIONS), errmsg("connection limit exceeded for non-superusers"))); /* * Initialize various default states that can't be set up until we've * selected the active user and gotten the right GUC settings. */ /* set default namespace search path */ InitializeSearchPath(); /* initialize client encoding */ InitializeClientEncoding(); /* report this backend in the PgBackendStatus array */ if (!bootstrap) pgstat_bestart(); /* close the transaction we started above */ if (!bootstrap) CommitTransactionCommand(); return am_superuser; }
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. }
/* * 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; }
/* * Each database using a table space is isolated into its own name space * by a subdirectory named for the database OID. On first creation of an * object in the tablespace, create the subdirectory. If the subdirectory * already exists, just fall through quietly. * * isRedo indicates that we are creating an object during WAL replay. * In this case we will cope with the possibility of the tablespace * directory not being there either --- this could happen if we are * replaying an operation on a table in a subsequently-dropped tablespace. * We handle this by making a directory in the place where the tablespace * symlink would normally be. This isn't an exact replay of course, but * it's the best we can do given the available information. * * If tablespaces are not supported, you might think this could be a no-op, * but you'd be wrong: we still need it in case we have to re-create a * database subdirectory (of $PGDATA/base) during WAL replay. */ void TablespaceCreateDbspace(Oid spcNode, Oid dbNode, bool isRedo) { struct stat st; char *dir; /* * The global tablespace doesn't have per-database subdirectories, so * nothing to do for it. */ if (spcNode == GLOBALTABLESPACE_OID) return; Assert(OidIsValid(spcNode)); Assert(OidIsValid(dbNode)); dir = GetDatabasePath(dbNode, spcNode); if (stat(dir, &st) < 0) { if (errno == ENOENT) { /* * Acquire TablespaceCreateLock to ensure that no DROP TABLESPACE * or TablespaceCreateDbspace is running concurrently. */ LWLockAcquire(TablespaceCreateLock, LW_EXCLUSIVE); /* * Recheck to see if someone created the directory while we were * waiting for lock. */ if (stat(dir, &st) == 0 && S_ISDIR(st.st_mode)) { /* need not do anything */ } else { /* OK, go for it */ if (mkdir(dir, S_IRWXU) < 0) { char *parentdir; if (errno != ENOENT || !isRedo) ereport(ERROR, (errcode_for_file_access(), errmsg("could not create directory \"%s\": %m", dir))); /* Try to make parent directory too */ parentdir = pstrdup(dir); get_parent_directory(parentdir); if (mkdir(parentdir, S_IRWXU) < 0) ereport(ERROR, (errcode_for_file_access(), errmsg("could not create directory \"%s\": %m", parentdir))); pfree(parentdir); if (mkdir(dir, S_IRWXU) < 0) ereport(ERROR, (errcode_for_file_access(), errmsg("could not create directory \"%s\": %m", dir))); } } LWLockRelease(TablespaceCreateLock); } else { ereport(ERROR, (errcode_for_file_access(), errmsg("could not stat directory \"%s\": %m", dir))); } } else { /* be paranoid */ if (!S_ISDIR(st.st_mode)) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("\"%s\" exists but is not a directory", dir))); } pfree(dir); }
bool SQLiteDb::Open(string_view const DbFile, bool Local, bool WAL) { const auto& v1_opener = [](string_view const Name, database_ptr& Db) { return sqlite::sqlite3_open16(null_terminated(Name).c_str(), &ptr_setter(Db)) == SQLITE_OK; }; const auto& v2_opener = [WAL](string_view const Name, database_ptr& Db) { return sqlite::sqlite3_open_v2(encoding::utf8::get_bytes(Name).c_str(), &ptr_setter(Db), WAL? SQLITE_OPEN_READWRITE : SQLITE_OPEN_READONLY, nullptr) == SQLITE_OK; }; m_Path = GetDatabasePath(DbFile, Local); const auto mem_db = DbFile == MemoryDbName; if (!Global->Opt->ReadOnlyConfig || mem_db) { if (!mem_db && db_exists < 0) { db_exists = os::fs::is_file(m_Path)? +1 : 0; } if (!v1_opener(m_Path, m_Db)) return false; sqlite::sqlite3_busy_timeout(m_Db.get(), 1000); return true; } // copy db to memory // if (!v1_opener(MemoryDbName, m_Db)) return false; bool ok = true, copied = false; if (os::fs::is_file(m_Path)) { database_ptr db_source; if (db_exists < 0) db_exists = +1; if (WAL && !can_create_file(concat(m_Path, L'.', GuidToStr(CreateUuid())))) // can't open db -- copy to %TEMP% { string strTmp; os::fs::GetTempPath(strTmp); append(strTmp, str(GetCurrentProcessId()), L'-', DbFile); ok = copied = os::fs::copy_file(m_Path, strTmp, nullptr, nullptr, nullptr, 0); if (ok) { os::fs::set_file_attributes(strTmp, FILE_ATTRIBUTE_NORMAL); m_Path = strTmp; ok = v1_opener(m_Path, db_source); } } else { ok = v2_opener(m_Path, db_source); } if (ok) { sqlite::sqlite3_busy_timeout(db_source.get(), 1000); const auto db_backup = sqlite::sqlite3_backup_init(m_Db.get(), "main", db_source.get(), "main"); ok = (nullptr != db_backup); if (ok) { sqlite::sqlite3_backup_step(db_backup, -1); sqlite::sqlite3_backup_finish(db_backup); ok = sqlite::sqlite3_errcode(m_Db.get()) == SQLITE_OK; } } } if (copied) os::fs::delete_file(m_Path); assign(m_Path, MemoryDbName); if (!ok) Close(); return ok; }
/* -------------------------------- * InitPostgres * Initialize POSTGRES. * * The database can be specified by name, using the in_dbname parameter, or by * OID, using the dboid parameter. In the latter case, the actual database * name can be returned to the caller in out_dbname. If out_dbname isn't * NULL, it must point to a buffer of size NAMEDATALEN. * * In bootstrap mode no parameters are used. The autovacuum launcher process * doesn't use any parameters either, because it only goes far enough to be * able to read pg_database; it doesn't connect to any particular database. * In walsender mode only username is used. * * As of PostgreSQL 8.2, we expect InitProcess() was already called, so we * already have a PGPROC struct ... but it's not completely filled in yet. * * Note: * Be very careful with the order of calls in the InitPostgres function. * -------------------------------- */ void InitPostgres(const char *in_dbname, Oid dboid, const char *username, char *out_dbname) { bool bootstrap = IsBootstrapProcessingMode(); bool am_superuser; GucContext gucctx; char *fullpath; char dbname[NAMEDATALEN]; elog(DEBUG3, "InitPostgres"); /* * Add my PGPROC struct to the ProcArray. * * Once I have done this, I am visible to other backends! */ InitProcessPhase2(); /* * Initialize my entry in the shared-invalidation manager's array of * per-backend data. * * Sets up MyBackendId, a unique backend identifier. */ MyBackendId = InvalidBackendId; SharedInvalBackendInit(false); if (MyBackendId > MaxBackends || MyBackendId <= 0) elog(FATAL, "bad backend id: %d", MyBackendId); /* Now that we have a BackendId, we can participate in ProcSignal */ ProcSignalInit(MyBackendId); /* * bufmgr needs another initialization call too */ InitBufferPoolBackend(); /* * Initialize local process's access to XLOG, if appropriate. In * bootstrap case we skip this since StartupXLOG() was run instead. */ if (!bootstrap) (void) RecoveryInProgress(); /* * Initialize the relation cache and the system catalog caches. Note that * no catalog access happens here; we only set up the hashtable structure. * We must do this before starting a transaction because transaction abort * would try to touch these hashtables. */ RelationCacheInitialize(); InitCatalogCache(); InitPlanCache(); /* Initialize portal manager */ EnablePortalManager(); /* Initialize stats collection --- must happen before first xact */ if (!bootstrap) pgstat_initialize(); /* * Load relcache entries for the shared system catalogs. This must create * at least an entry for pg_database. */ RelationCacheInitializePhase2(); /* * Set up process-exit callback to do pre-shutdown cleanup. This has to * be after we've initialized all the low-level modules like the buffer * manager, because during shutdown this has to run before the low-level * modules start to close down. On the other hand, we want it in place * before we begin our first transaction --- if we fail during the * initialization transaction, as is entirely possible, we need the * AbortTransaction call to clean up. */ on_shmem_exit(ShutdownPostgres, 0); /* The autovacuum launcher is done here */ if (IsAutoVacuumLauncherProcess()) return; /* * Start a new transaction here before first access to db, and get a * snapshot. We don't have a use for the snapshot itself, but we're * interested in the secondary effect that it sets RecentGlobalXmin. (This * is critical for anything that reads heap pages, because HOT may decide * to prune them even if the process doesn't attempt to modify any * tuples.) */ if (!bootstrap) { StartTransactionCommand(); (void) GetTransactionSnapshot(); } /* * Set up the global variables holding database id and default tablespace. * But note we won't actually try to touch the database just yet. * * We take a shortcut in the bootstrap and walsender case, otherwise we * have to look up the db's entry in pg_database. */ if (bootstrap || am_walsender) { MyDatabaseId = TemplateDbOid; MyDatabaseTableSpace = DEFAULTTABLESPACE_OID; } else if (in_dbname != NULL) { HeapTuple tuple; Form_pg_database dbform; tuple = GetDatabaseTuple(in_dbname); if (!HeapTupleIsValid(tuple)) ereport(FATAL, (errcode(ERRCODE_UNDEFINED_DATABASE), errmsg("database \"%s\" does not exist", in_dbname))); dbform = (Form_pg_database) GETSTRUCT(tuple); MyDatabaseId = HeapTupleGetOid(tuple); MyDatabaseTableSpace = dbform->dattablespace; /* take database name from the caller, just for paranoia */ strlcpy(dbname, in_dbname, sizeof(dbname)); } else { /* caller specified database by OID */ HeapTuple tuple; Form_pg_database dbform; tuple = GetDatabaseTupleByOid(dboid); if (!HeapTupleIsValid(tuple)) ereport(FATAL, (errcode(ERRCODE_UNDEFINED_DATABASE), errmsg("database %u does not exist", dboid))); dbform = (Form_pg_database) GETSTRUCT(tuple); MyDatabaseId = HeapTupleGetOid(tuple); MyDatabaseTableSpace = dbform->dattablespace; Assert(MyDatabaseId == dboid); strlcpy(dbname, NameStr(dbform->datname), sizeof(dbname)); /* pass the database name back to the caller */ if (out_dbname) strcpy(out_dbname, dbname); } /* Now we can mark our PGPROC entry with the database ID */ /* (We assume this is an atomic store so no lock is needed) */ MyProc->databaseId = MyDatabaseId; /* * Now, take a writer's lock on the database we are trying to connect to. * If there is a concurrently running DROP DATABASE on that database, this * will block us until it finishes (and has committed its update of * pg_database). * * Note that the lock is not held long, only until the end of this startup * transaction. This is OK since we are already advertising our use of * the database in the PGPROC array; anyone trying a DROP DATABASE after * this point will see us there. * * Note: use of RowExclusiveLock here is reasonable because we envision * our session as being a concurrent writer of the database. If we had a * way of declaring a session as being guaranteed-read-only, we could use * AccessShareLock for such sessions and thereby not conflict against * CREATE DATABASE. */ if (!bootstrap && !am_walsender) LockSharedObject(DatabaseRelationId, MyDatabaseId, 0, RowExclusiveLock); /* * Recheck pg_database to make sure the target database hasn't gone away. * If there was a concurrent DROP DATABASE, this ensures we will die * cleanly without creating a mess. */ if (!bootstrap && !am_walsender) { HeapTuple tuple; tuple = GetDatabaseTuple(dbname); if (!HeapTupleIsValid(tuple) || MyDatabaseId != HeapTupleGetOid(tuple) || MyDatabaseTableSpace != ((Form_pg_database) GETSTRUCT(tuple))->dattablespace) ereport(FATAL, (errcode(ERRCODE_UNDEFINED_DATABASE), errmsg("database \"%s\" does not exist", dbname), errdetail("It seems to have just been dropped or renamed."))); } /* * Now we should be able to access the database directory safely. Verify * it's there and looks reasonable. */ fullpath = GetDatabasePath(MyDatabaseId, MyDatabaseTableSpace); if (!bootstrap && !am_walsender) { if (access(fullpath, F_OK) == -1) { if (errno == ENOENT) ereport(FATAL, (errcode(ERRCODE_UNDEFINED_DATABASE), errmsg("database \"%s\" does not exist", dbname), errdetail("The database subdirectory \"%s\" is missing.", fullpath))); else ereport(FATAL, (errcode_for_file_access(), errmsg("could not access directory \"%s\": %m", fullpath))); } ValidatePgVersion(fullpath); } SetDatabasePath(fullpath); /* * It's now possible to do real access to the system catalogs. * * Load relcache entries for the system catalogs. This must create at * least the minimum set of "nailed-in" cache entries. */ RelationCacheInitializePhase3(); /* * Perform client authentication if necessary, then figure out our * postgres user ID, and see if we are a superuser. * * In standalone mode and in autovacuum worker processes, we use a fixed * ID, otherwise we figure it out from the authenticated user name. */ if (bootstrap || IsAutoVacuumWorkerProcess()) { InitializeSessionUserIdStandalone(); am_superuser = true; } else if (!IsUnderPostmaster) { InitializeSessionUserIdStandalone(); am_superuser = true; if (!ThereIsAtLeastOneRole()) ereport(WARNING, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("no roles are defined in this database system"), errhint("You should immediately run CREATE USER \"%s\" SUPERUSER;.", username))); } else { /* normal multiuser case */ Assert(MyProcPort != NULL); PerformAuthentication(MyProcPort); InitializeSessionUserId(username); am_superuser = superuser(); } /* set up ACL framework (so CheckMyDatabase can check permissions) */ initialize_acl(); /* Process pg_db_role_setting options */ process_settings(MyDatabaseId, GetSessionUserId()); /* * Re-read the pg_database row for our database, check permissions and set * up database-specific GUC settings. We can't do this until all the * database-access infrastructure is up. (Also, it wants to know if the * user is a superuser, so the above stuff has to happen first.) */ if (!bootstrap && !am_walsender) CheckMyDatabase(dbname, am_superuser); /* * If we're trying to shut down, only superusers can connect. */ if (!am_superuser && MyProcPort != NULL && MyProcPort->canAcceptConnections == CAC_WAITBACKUP) ereport(FATAL, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("must be superuser to connect during database shutdown"))); /* * Check a normal user hasn't connected to a superuser reserved slot. */ if (!am_superuser && ReservedBackends > 0 && !HaveNFreeProcs(ReservedBackends)) ereport(FATAL, (errcode(ERRCODE_TOO_MANY_CONNECTIONS), errmsg("connection limit exceeded for non-superusers"))); /* * Now process any command-line switches that were included in the startup * packet, if we are in a regular backend. We couldn't do this before * because we didn't know if client is a superuser. */ gucctx = am_superuser ? PGC_SUSET : PGC_BACKEND; if (MyProcPort != NULL && MyProcPort->cmdline_options != NULL) { /* * The maximum possible number of commandline arguments that could * come from MyProcPort->cmdline_options is (strlen + 1) / 2; see * pg_split_opts(). */ char **av; int maxac; int ac; maxac = 2 + (strlen(MyProcPort->cmdline_options) + 1) / 2; av = (char **) palloc(maxac * sizeof(char *)); ac = 0; av[ac++] = "postgres"; /* Note this mangles MyProcPort->cmdline_options */ pg_split_opts(av, &ac, MyProcPort->cmdline_options); av[ac] = NULL; Assert(ac < maxac); (void) process_postgres_switches(ac, av, gucctx); } /* * Process any additional GUC variable settings passed in startup packet. * These are handled exactly like command-line variables. */ if (MyProcPort != NULL) { ListCell *gucopts = list_head(MyProcPort->guc_options); while (gucopts) { char *name; char *value; name = lfirst(gucopts); gucopts = lnext(gucopts); value = lfirst(gucopts); gucopts = lnext(gucopts); SetConfigOption(name, value, gucctx, PGC_S_CLIENT); } } /* Apply PostAuthDelay as soon as we've read all options */ if (PostAuthDelay > 0) pg_usleep(PostAuthDelay * 1000000L); /* * Initialize various default states that can't be set up until we've * selected the active user and gotten the right GUC settings. */ /* set default namespace search path */ InitializeSearchPath(); /* initialize client encoding */ InitializeClientEncoding(); /* reset the database for walsender */ if (am_walsender) MyProc->databaseId = MyDatabaseId = InvalidOid; /* report this backend in the PgBackendStatus array */ if (!bootstrap) pgstat_bestart(); /* close the transaction we started above */ if (!bootstrap) CommitTransactionCommand(); }
/* -------------------------------- * InitPostgres * Initialize POSTGRES. * * Note: * Be very careful with the order of calls in the InitPostgres function. * -------------------------------- */ void InitPostgres(const char *dbname, const char *username) { bool bootstrap = IsBootstrapProcessingMode(); /* * Set up the global variables holding database id and path. * * We take a shortcut in the bootstrap case, otherwise we have to look up * the db name in pg_database. */ if (bootstrap) { MyDatabaseId = TemplateDbOid; SetDatabasePath(GetDatabasePath(MyDatabaseId)); } else { char *fullpath, datpath[MAXPGPATH]; /* * Formerly we validated DataDir here, but now that's done * earlier. */ /* * Find oid and path of the database we're about to open. Since * we're not yet up and running we have to use the hackish * GetRawDatabaseInfo. */ GetRawDatabaseInfo(dbname, &MyDatabaseId, datpath); if (!OidIsValid(MyDatabaseId)) ereport(FATAL, (errcode(ERRCODE_UNDEFINED_DATABASE), errmsg("database \"%s\" does not exist", dbname))); fullpath = GetDatabasePath(MyDatabaseId); /* Verify the database path */ if (access(fullpath, F_OK) == -1) { if (errno == ENOENT) ereport(FATAL, (errcode(ERRCODE_UNDEFINED_DATABASE), errmsg("database \"%s\" does not exist", dbname), errdetail("The database subdirectory \"%s\" is missing.", fullpath))); else ereport(FATAL, (errcode_for_file_access(), errmsg("could not access directory \"%s\": %m", fullpath))); } ValidatePgVersion(fullpath); if (chdir(fullpath) == -1) ereport(FATAL, (errcode_for_file_access(), errmsg("could not change directory to \"%s\": %m", fullpath))); SetDatabasePath(fullpath); } /* * Code after this point assumes we are in the proper directory! */ /* * Set up my per-backend PGPROC struct in shared memory. (We need * to know MyDatabaseId before we can do this, since it's entered into * the PGPROC struct.) */ InitProcess(); /* * Initialize my entry in the shared-invalidation manager's array of * per-backend data. (Formerly this came before InitProcess, but now * it must happen after, because it uses MyProc.) Once I have done * this, I am visible to other backends! * * Sets up MyBackendId, a unique backend identifier. */ MyBackendId = InvalidBackendId; InitBackendSharedInvalidationState(); if (MyBackendId > MaxBackends || MyBackendId <= 0) elog(FATAL, "bad backend id: %d", MyBackendId); /* * Initialize the transaction system override state. */ AmiTransactionOverride(bootstrap); /* * Initialize the relation descriptor cache. This must create at * least the minimum set of "nailed-in" cache entries. No catalog * access happens here. */ RelationCacheInitialize(); /* * Initialize all the system catalog caches. Note that no catalog * access happens here; we only set up the cache structure. */ InitCatalogCache(); /* Initialize portal manager */ EnablePortalManager(); /* * Initialize the deferred trigger manager --- must happen before * first transaction start. */ DeferredTriggerInit(); /* start a new transaction here before access to db */ if (!bootstrap) StartTransactionCommand(); /* * It's now possible to do real access to the system catalogs. * * Replace faked-up relcache entries with correct info. */ RelationCacheInitializePhase2(); /* * Figure out our postgres user id. In standalone mode we use a fixed * id, otherwise we figure it out from the authenticated user name. */ if (bootstrap) InitializeSessionUserIdStandalone(); else if (!IsUnderPostmaster) { InitializeSessionUserIdStandalone(); if (!ThereIsAtLeastOneUser()) ereport(WARNING, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("no users are defined in this database system"), errhint("You should immediately run CREATE USER \"%s\" WITH SYSID %d CREATEUSER;.", username, BOOTSTRAP_USESYSID))); } else { /* normal multiuser case */ InitializeSessionUserId(username); } /* * Unless we are bootstrapping, double-check that InitMyDatabaseInfo() * got a correct result. We can't do this until all the * database-access infrastructure is up. */ if (!bootstrap) ReverifyMyDatabase(dbname); /* * Final phase of relation cache startup: write a new cache file if * necessary. This is done after ReverifyMyDatabase to avoid writing * a cache file into a dead database. */ RelationCacheInitializePhase3(); /* * Check a normal user hasn't connected to a superuser reserved slot. * We can't do this till after we've read the user information, and we * must do it inside a transaction since checking superuserness may * require database access. The superuser check is probably the most * expensive part; don't do it until necessary. */ if (ReservedBackends > 0 && CountEmptyBackendSlots() < ReservedBackends && !superuser()) ereport(FATAL, (errcode(ERRCODE_TOO_MANY_CONNECTIONS), errmsg("connection limit exceeded for non-superusers"))); /* * Initialize various default states that can't be set up until we've * selected the active user and done ReverifyMyDatabase. */ /* set default namespace search path */ InitializeSearchPath(); /* initialize client encoding */ InitializeClientEncoding(); /* * Now all default states are fully set up. Report them to client if * appropriate. */ BeginReportingGUCOptions(); /* * Set up process-exit callback to do pre-shutdown cleanup. This * should be last because we want shmem_exit to call this routine * before the exit callbacks that are registered by buffer manager, * lock manager, etc. We need to run this code before we close down * database access! */ on_shmem_exit(ShutdownPostgres, 0); /* close the transaction we started above */ if (!bootstrap) CommitTransactionCommand(); }
/* * DatabaseInfo_Scan() * Scans the file-system to fill the DatabaseInfo with: * - miscEntry : non-relation database files * - physicalSegmentFiles : relation segment files */ static void DatabaseInfo_Scan( DatabaseInfo *info, HTAB *dbInfoRelHashTable, Oid tablespace, Oid database) { char *dbDirPath; DIR *xldir; struct dirent *xlde; char fromfile[MAXPGPATH]; /* Lookup the database path and allocate a directory scan structure */ dbDirPath = GetDatabasePath( (tablespace == GLOBALTABLESPACE_OID ? 0 : database), tablespace); xldir = AllocateDir(dbDirPath); if (xldir == NULL) ereport(ERROR, (errcode_for_file_access(), errmsg("Could not open database directory \"%s\": %m", dbDirPath))); /* Scan through the directory */ while ((xlde = ReadDir(xldir, dbDirPath)) != NULL) { struct stat fst; if (strcmp(xlde->d_name, ".") == 0 || strcmp(xlde->d_name, "..") == 0) continue; /* Odd... On snow leopard, we get back "/" as a subdir, which is wrong. Ingore it */ if (xlde->d_name[0] == '/' && xlde->d_name[1] == '\0') continue; snprintf(fromfile, MAXPGPATH, "%s/%s", dbDirPath, xlde->d_name); if (lstat(fromfile, &fst) < 0) { if (errno != ENOENT) ereport(ERROR, (errcode_for_file_access(), errmsg("could not stat file \"%s\": %m", fromfile))); /* * If the file went away while scanning, it's no error. * This could happen especillay with shared relcache init file * that is stored in global tablespace. */ elog(LOG, "skipping missing file %s", fromfile); continue; } if (S_ISDIR(fst.st_mode)) { DatabaseInfo_AddMiscEntry( info, tablespace, /* isDir */ true, xlde->d_name); } else if (S_ISREG(fst.st_mode)) { DatabaseInfo_AddFile( info, dbInfoRelHashTable, tablespace, dbDirPath, xlde->d_name); } } FreeDir(xldir); }
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); #endif WRITE_PERSISTENT_STATE_ORDERED_UNLOCK; }
/* * 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)); }
/* * Each database using a table space is isolated into its own name space * by a subdirectory named for the database OID. On first creation of an * object in the tablespace, create the subdirectory. If the subdirectory * already exists, just fall through quietly. * * If tablespaces are not supported, this is just a no-op; CREATE DATABASE * is expected to create the default subdirectory for the database. * * isRedo indicates that we are creating an object during WAL replay; * we can skip doing locking in that case (and should do so to avoid * any possible problems with pg_tablespace not being valid). * * Also, when isRedo is true, we will cope with the possibility of the * tablespace not being there either --- this could happen if we are * replaying an operation on a table in a subsequently-dropped tablespace. * We handle this by making a directory in the place where the tablespace * symlink would normally be. This isn't an exact replay of course, but * it's the best we can do given the available information. */ void TablespaceCreateDbspace(Oid spcNode, Oid dbNode, bool isRedo) { #ifdef HAVE_SYMLINK struct stat st; char *dir; /* * The global tablespace doesn't have per-database subdirectories, so * nothing to do for it. */ if (spcNode == GLOBALTABLESPACE_OID) return; Assert(OidIsValid(spcNode)); Assert(OidIsValid(dbNode)); dir = GetDatabasePath(dbNode, spcNode); if (stat(dir, &st) < 0) { if (errno == ENOENT) { /* * Acquire ExclusiveLock on pg_tablespace to ensure that no DROP * TABLESPACE or TablespaceCreateDbspace is running concurrently. * Simple reads from pg_tablespace are OK. */ Relation rel; if (!isRedo) rel = heap_open(TableSpaceRelationId, ExclusiveLock); else rel = NULL; /* * Recheck to see if someone created the directory while we were * waiting for lock. */ if (stat(dir, &st) == 0 && S_ISDIR(st.st_mode)) { /* need not do anything */ } else { /* OK, go for it */ if (mkdir(dir, S_IRWXU) < 0) { char *parentdir; if (errno != ENOENT || !isRedo) ereport(ERROR, (errcode_for_file_access(), errmsg("could not create directory \"%s\": %m", dir))); /* Try to make parent directory too */ parentdir = pstrdup(dir); get_parent_directory(parentdir); if (mkdir(parentdir, S_IRWXU) < 0) ereport(ERROR, (errcode_for_file_access(), errmsg("could not create directory \"%s\": %m", parentdir))); pfree(parentdir); if (mkdir(dir, S_IRWXU) < 0) ereport(ERROR, (errcode_for_file_access(), errmsg("could not create directory \"%s\": %m", dir))); } } /* OK to drop the exclusive lock */ if (!isRedo) heap_close(rel, ExclusiveLock); } else { ereport(ERROR, (errcode_for_file_access(), errmsg("could not stat directory \"%s\": %m", dir))); } } else { /* be paranoid */ if (!S_ISDIR(st.st_mode)) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("\"%s\" exists but is not a directory", dir))); } pfree(dir); #endif /* HAVE_SYMLINK */ }
/* * Each database using a table space is isolated into its own name space * by a subdirectory named for the database OID. On first creation of an * object in the tablespace, create the subdirectory. If the subdirectory * already exists, fall through quietly. * * isRedo indicates that we are creating an object during WAL replay. * In this case we will cope with the possibility of the tablespace * directory not being there either --- this could happen if we are * replaying an operation on a table in a subsequently-dropped tablespace. * We handle this by making a directory in the place where the tablespace * symlink would normally be. This isn't an exact replay of course, but * it's the best we can do given the available information. * * If tablespaces are not supported, we still need it in case we have to * re-create a database subdirectory (of $PGDATA/base) during WAL replay. */ void TablespaceCreateDbspace(Oid spcNode, Oid dbNode, bool isRedo) { struct stat st; char *dir; /* * The global tablespace doesn't have per-database subdirectories, so * nothing to do for it. */ if (spcNode == GLOBALTABLESPACE_OID) return; Assert(OidIsValid(spcNode)); Assert(OidIsValid(dbNode)); dir = GetDatabasePath(dbNode, spcNode); if (stat(dir, &st) < 0) { /* Directory does not exist? */ if (errno == ENOENT) { /* * Acquire TablespaceCreateLock to ensure that no DROP TABLESPACE * or TablespaceCreateDbspace is running concurrently. */ LWLockAcquire(TablespaceCreateLock, LW_EXCLUSIVE); /* * Recheck to see if someone created the directory while we were * waiting for lock. */ if (stat(dir, &st) == 0 && S_ISDIR(st.st_mode)) { /* Directory was created */ } else { /* Directory creation failed? */ if (mkdir(dir, S_IRWXU) < 0) { char *parentdir; /* Failure other than not exists or not in WAL replay? */ if (errno != ENOENT || !isRedo) ereport(ERROR, (errcode_for_file_access(), errmsg("could not create directory \"%s\": %m", dir))); /* * Parent directories are missing during WAL replay, so * continue by creating simple parent directories rather * than a symlink. */ /* create two parents up if not exist */ parentdir = pstrdup(dir); get_parent_directory(parentdir); get_parent_directory(parentdir); /* Can't create parent and it doesn't already exist? */ if (mkdir(parentdir, S_IRWXU) < 0 && errno != EEXIST) ereport(ERROR, (errcode_for_file_access(), errmsg("could not create directory \"%s\": %m", parentdir))); pfree(parentdir); /* create one parent up if not exist */ parentdir = pstrdup(dir); get_parent_directory(parentdir); /* Can't create parent and it doesn't already exist? */ if (mkdir(parentdir, S_IRWXU) < 0 && errno != EEXIST) ereport(ERROR, (errcode_for_file_access(), errmsg("could not create directory \"%s\": %m", parentdir))); pfree(parentdir); /* Create database directory */ if (mkdir(dir, S_IRWXU) < 0) ereport(ERROR, (errcode_for_file_access(), errmsg("could not create directory \"%s\": %m", dir))); } } LWLockRelease(TablespaceCreateLock); } else { ereport(ERROR, (errcode_for_file_access(), errmsg("could not stat directory \"%s\": %m", dir))); } } else { /* Is it not a directory? */ if (!S_ISDIR(st.st_mode)) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("\"%s\" exists but is not a directory", dir))); } pfree(dir); }
/* * 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); #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; }
/* -------------------------------- * InitPostgres * Initialize POSTGRES. * * The database can be specified by name, using the in_dbname parameter, or by * OID, using the dboid parameter. In the latter case, the actual database * name can be returned to the caller in out_dbname. If out_dbname isn't * NULL, it must point to a buffer of size NAMEDATALEN. * * In bootstrap mode no parameters are used. * * The return value indicates whether the userID is a superuser. (That * can only be tested inside a transaction, so we want to do it during * the startup transaction rather than doing a separate one in postgres.c.) * * As of PostgreSQL 8.2, we expect InitProcess() was already called, so we * already have a PGPROC struct ... but it's not filled in yet. * * Note: * Be very careful with the order of calls in the InitPostgres function. * -------------------------------- */ void InitPostgres(const char *in_dbname, Oid dboid, const char *username, char *out_dbname) { bool bootstrap = IsBootstrapProcessingMode(); bool autovacuum = IsAutoVacuumProcess(); bool am_superuser; char *fullpath; char dbname[NAMEDATALEN]; /* * Add my PGPROC struct to the ProcArray. * * Once I have done this, I am visible to other backends! */ InitProcessPhase2(); /* Initialize SessionState entry */ SessionState_Init(); /* Initialize memory protection */ GPMemoryProtect_Init(); /* * Initialize my entry in the shared-invalidation manager's array of * per-backend data. * * Sets up MyBackendId, a unique backend identifier. */ MyBackendId = InvalidBackendId; SharedInvalBackendInit(false); if (MyBackendId > MaxBackends || MyBackendId <= 0) elog(FATAL, "bad backend id: %d", MyBackendId); /* Now that we have a BackendId, we can participate in ProcSignal */ ProcSignalInit(MyBackendId); /* * bufmgr needs another initialization call too */ InitBufferPoolBackend(); /* * Initialize local process's access to XLOG. In bootstrap case we may * skip this since StartupXLOG() was run instead. */ if (!bootstrap) InitXLOGAccess(); /* * Initialize the relation cache and the system catalog caches. Note that * no catalog access happens here; we only set up the hashtable structure. * We must do this before starting a transaction because transaction abort * would try to touch these hashtables. */ RelationCacheInitialize(); InitCatalogCache(); /* Initialize portal manager */ EnablePortalManager(); /* Initialize stats collection --- must happen before first xact */ if (!bootstrap) pgstat_initialize(); /* * Load relcache entries for the shared system catalogs. This must create * at least entries for pg_database and catalogs used for authentication. */ RelationCacheInitializePhase2(); /* * Set up process-exit callback to do pre-shutdown cleanup. This has to * be after we've initialized all the low-level modules like the buffer * manager, because during shutdown this has to run before the low-level * modules start to close down. On the other hand, we want it in place * before we begin our first transaction --- if we fail during the * initialization transaction, as is entirely possible, we need the * AbortTransaction call to clean up. */ on_shmem_exit(ShutdownPostgres, 0); /* TODO: autovacuum launcher should be done here? */ /* * Start a new transaction here before first access to db, and get a * snapshot. We don't have a use for the snapshot itself, but we're * interested in the secondary effect that it sets RecentGlobalXmin. */ if (!bootstrap) { StartTransactionCommand(); (void) GetTransactionSnapshot(); } /* * Figure out our postgres user id, and see if we are a superuser. * * In standalone mode and in the autovacuum process, we use a fixed id, * otherwise we figure it out from the authenticated user name. */ if (bootstrap || autovacuum) { InitializeSessionUserIdStandalone(); am_superuser = true; } else if (!IsUnderPostmaster) { InitializeSessionUserIdStandalone(); am_superuser = true; if (!ThereIsAtLeastOneRole()) ereport(WARNING, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("no roles are defined in this database system"), errhint("You should immediately run CREATE USER \"%s\" CREATEUSER;.", username))); } else { /* normal multiuser case */ Assert(MyProcPort != NULL); PerformAuthentication(MyProcPort); InitializeSessionUserId(username); am_superuser = superuser(); } /* * Check a normal user hasn't connected to a superuser reserved slot. */ if (!am_superuser && ReservedBackends > 0 && !HaveNFreeProcs(ReservedBackends)) ereport(FATAL, (errcode(ERRCODE_TOO_MANY_CONNECTIONS), errmsg("connection limit exceeded for non-superusers"), errSendAlert(true))); /* * If walsender, we don't want to connect to any particular database. Just * finish the backend startup by processing any options from the startup * packet, and we're done. */ if (am_walsender) { Assert(!bootstrap); /* * We don't have replication role, which existed in postgres. */ if (!superuser()) ereport(FATAL, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("must be superuser role to start walsender"))); /* process any options passed in the startup packet */ if (MyProcPort != NULL) process_startup_options(MyProcPort, am_superuser); /* Apply PostAuthDelay as soon as we've read all options */ if (PostAuthDelay > 0) pg_usleep(PostAuthDelay * 1000000L); /* initialize client encoding */ InitializeClientEncoding(); /* report this backend in the PgBackendStatus array */ pgstat_bestart(); /* close the transaction we started above */ CommitTransactionCommand(); return; } /* * Set up the global variables holding database id and path. But note we * won't actually try to touch the database just yet. * * We take a shortcut in the bootstrap case, otherwise we have to look up * the db name in pg_database. */ if (bootstrap) { MyDatabaseId = TemplateDbOid; MyDatabaseTableSpace = DEFAULTTABLESPACE_OID; } else if (in_dbname != NULL) { HeapTuple tuple; Form_pg_database dbform; tuple = GetDatabaseTuple(in_dbname); if (!HeapTupleIsValid(tuple)) ereport(FATAL, (errcode(ERRCODE_UNDEFINED_DATABASE), errmsg("database \"%s\" does not exist", in_dbname))); dbform = (Form_pg_database) GETSTRUCT(tuple); MyDatabaseId = HeapTupleGetOid(tuple); MyDatabaseTableSpace = dbform->dattablespace; /* take database name from the caller, just for paranoia */ strlcpy(dbname, in_dbname, sizeof(dbname)); pfree(tuple); } else { /* caller specified database by OID */ HeapTuple tuple; Form_pg_database dbform; tuple = GetDatabaseTupleByOid(dboid); if (!HeapTupleIsValid(tuple)) ereport(FATAL, (errcode(ERRCODE_UNDEFINED_DATABASE), errmsg("database %u does not exist", dboid))); dbform = (Form_pg_database) GETSTRUCT(tuple); MyDatabaseId = HeapTupleGetOid(tuple); MyDatabaseTableSpace = dbform->dattablespace; Assert(MyDatabaseId == dboid); strlcpy(dbname, NameStr(dbform->datname), sizeof(dbname)); /* pass the database name back to the caller */ if (out_dbname) strcpy(out_dbname, dbname); pfree(tuple); } /* Now we can mark our PGPROC entry with the database ID */ /* (We assume this is an atomic store so no lock is needed) */ MyProc->databaseId = MyDatabaseId; /* * Now, take a writer's lock on the database we are trying to connect to. * If there is a concurrently running DROP DATABASE on that database, this * will block us until it finishes (and has committed its update of * pg_database). * * Note that the lock is not held long, only until the end of this startup * transaction. This is OK since we are already advertising our use of * the database in the PGPROC array; anyone trying a DROP DATABASE after * this point will see us there. * * Note: use of RowExclusiveLock here is reasonable because we envision * our session as being a concurrent writer of the database. If we had a * way of declaring a session as being guaranteed-read-only, we could use * AccessShareLock for such sessions and thereby not conflict against * CREATE DATABASE. */ if (!bootstrap) LockSharedObject(DatabaseRelationId, MyDatabaseId, 0, RowExclusiveLock); /* * Recheck pg_database to make sure the target database hasn't gone away. * If there was a concurrent DROP DATABASE, this ensures we will die * cleanly without creating a mess. */ if (!bootstrap) { HeapTuple tuple; tuple = GetDatabaseTuple(dbname); if (!HeapTupleIsValid(tuple) || MyDatabaseId != HeapTupleGetOid(tuple) || MyDatabaseTableSpace != ((Form_pg_database) GETSTRUCT(tuple))->dattablespace) ereport(FATAL, (errcode(ERRCODE_UNDEFINED_DATABASE), errmsg("database \"%s\" does not exist", dbname), errdetail("It seems to have just been dropped or renamed."))); } fullpath = GetDatabasePath(MyDatabaseId, MyDatabaseTableSpace); if (!bootstrap) { if (access(fullpath, F_OK) == -1) { if (errno == ENOENT) ereport(FATAL, (errcode(ERRCODE_UNDEFINED_DATABASE), errmsg("database \"%s\" does not exist", dbname), errdetail("The database subdirectory \"%s\" is missing.", fullpath))); else ereport(FATAL, (errcode_for_file_access(), errmsg("could not access directory \"%s\": %m", fullpath))); } ValidatePgVersion(fullpath); } SetDatabasePath(fullpath); /* * It's now possible to do real access to the system catalogs. * * Load relcache entries for the system catalogs. This must create at * least the minimum set of "nailed-in" cache entries. */ RelationCacheInitializePhase3(); /* * Now we have full access to catalog including toast tables, * we can process pg_authid.rolconfig. This ought to come before * processing startup options so that it can override the settings. */ if (!bootstrap) ProcessRoleGUC(); /* set up ACL framework (so CheckMyDatabase can check permissions) */ initialize_acl(); /* * Re-read the pg_database row for our database, check permissions and set * up database-specific GUC settings. We can't do this until all the * database-access infrastructure is up. (Also, it wants to know if the * user is a superuser, so the above stuff has to happen first.) */ if (!bootstrap) CheckMyDatabase(dbname, am_superuser); /* * Now process any command-line switches and any additional GUC variable * settings passed in the startup packet. We couldn't do this before * because we didn't know if client is a superuser. */ if (MyProcPort != NULL) process_startup_options(MyProcPort, am_superuser); /* * Maintenance Mode: allow superuser to connect when * gp_maintenance_conn GUC is set. We cannot check it until * process_startup_options parses the GUC. */ if (gp_maintenance_mode && Gp_role == GP_ROLE_DISPATCH && !(superuser() && gp_maintenance_conn)) ereport(FATAL, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("maintenance mode: connected by superuser only"), errSendAlert(false))); /* * MPP: If we were started in utility mode then we only want to allow * incoming sessions that specify gp_session_role=utility as well. This * lets the bash scripts start the QD in utility mode and connect in but * protect ourselves from normal clients who might be trying to connect to * the system while we startup. */ if ((Gp_role == GP_ROLE_UTILITY) && (Gp_session_role != GP_ROLE_UTILITY)) { ereport(FATAL, (errcode(ERRCODE_CANNOT_CONNECT_NOW), errmsg("System was started in master-only utility mode - only utility mode connections are allowed"))); } /* Apply PostAuthDelay as soon as we've read all options */ if (PostAuthDelay > 0) pg_usleep(PostAuthDelay * 1000000L); /* set default namespace search path */ InitializeSearchPath(); /* initialize client encoding */ InitializeClientEncoding(); /* report this backend in the PgBackendStatus array */ if (!bootstrap) pgstat_bestart(); /* * MPP package setup * * Primary function is to establish connctions to the qExecs. * This is SKIPPED when the database is in bootstrap mode or * Is not UnderPostmaster. */ if (!bootstrap && IsUnderPostmaster) { cdb_setup(); on_proc_exit( cdb_cleanup, 0 ); } /* * MPP SharedSnapshot Setup */ if (Gp_role == GP_ROLE_DISPATCH) { addSharedSnapshot("Query Dispatcher", gp_session_id); } else if (Gp_role == GP_ROLE_DISPATCHAGENT) { SharedLocalSnapshotSlot = NULL; } else if (Gp_segment == -1 && Gp_role == GP_ROLE_EXECUTE && !Gp_is_writer) { /* * Entry db singleton QE is a user of the shared snapshot -- not a creator. * The lookup will occur once the distributed snapshot has been received. */ lookupSharedSnapshot("Entry DB Singleton", "Query Dispatcher", gp_session_id); } else if (Gp_role == GP_ROLE_EXECUTE) { if (Gp_is_writer) { addSharedSnapshot("Writer qExec", gp_session_id); } else { /* * NOTE: This assumes that the Slot has already been * allocated by the writer. Need to make sure we * always allocate the writer qExec first. */ lookupSharedSnapshot("Reader qExec", "Writer qExec", gp_session_id); } } /* close the transaction we started above */ if (!bootstrap) CommitTransactionCommand(); return; }
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)); }
/* * 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)); }
bool SQLiteDb::Open(const wchar_t *DbFile, bool Local) { GetDatabasePath(DbFile, strPath, Local); return sqlite3_open16(strPath.CPtr(), &pDb) == SQLITE_OK; }
/* -------------------------------- * InitPostgres * Initialize POSTGRES. * * The database can be specified by name, using the in_dbname parameter, or by * OID, using the dboid parameter. In the latter case, the actual database * name can be returned to the caller in out_dbname. If out_dbname isn't * NULL, it must point to a buffer of size NAMEDATALEN. * * In bootstrap mode no parameters are used. The autovacuum launcher process * doesn't use any parameters either, because it only goes far enough to be * able to read pg_database; it doesn't connect to any particular database. * In walsender mode only username is used. * * As of PostgreSQL 8.2, we expect InitProcess() was already called, so we * already have a PGPROC struct ... but it's not completely filled in yet. * * Note: * Be very careful with the order of calls in the InitPostgres function. * -------------------------------- */ void InitPostgres(const char *in_dbname, Oid dboid, const char *username, char *out_dbname) { bool bootstrap = IsBootstrapProcessingMode(); bool am_superuser; char *fullpath; char dbname[NAMEDATALEN]; elog(DEBUG3, "InitPostgres"); /* * Add my PGPROC struct to the ProcArray. * * Once I have done this, I am visible to other backends! */ InitProcessPhase2(); /* * Initialize my entry in the shared-invalidation manager's array of * per-backend data. * * Sets up MyBackendId, a unique backend identifier. */ MyBackendId = InvalidBackendId; SharedInvalBackendInit(false); if (MyBackendId > MaxBackends || MyBackendId <= 0) elog(FATAL, "bad backend ID: %d", MyBackendId); /* Now that we have a BackendId, we can participate in ProcSignal */ ProcSignalInit(MyBackendId); /* * Also set up timeout handlers needed for backend operation. We need * these in every case except bootstrap. */ if (!bootstrap) { RegisterTimeout(DEADLOCK_TIMEOUT, CheckDeadLock); RegisterTimeout(STATEMENT_TIMEOUT, StatementTimeoutHandler); RegisterTimeout(LOCK_TIMEOUT, LockTimeoutHandler); } /* * bufmgr needs another initialization call too */ InitBufferPoolBackend(); /* * Initialize local process's access to XLOG. */ if (IsUnderPostmaster) { /* * The postmaster already started the XLOG machinery, but we need to * call InitXLOGAccess(), if the system isn't in hot-standby mode. * This is handled by calling RecoveryInProgress and ignoring the * result. */ (void) RecoveryInProgress(); } else { /* * We are either a bootstrap process or a standalone backend. Either * way, start up the XLOG machinery, and register to have it closed * down at exit. */ StartupXLOG(); on_shmem_exit(ShutdownXLOG, 0); } /* * Initialize the relation cache and the system catalog caches. Note that * no catalog access happens here; we only set up the hashtable structure. * We must do this before starting a transaction because transaction abort * would try to touch these hashtables. */ RelationCacheInitialize(); InitCatalogCache(); InitPlanCache(); /* Initialize portal manager */ EnablePortalManager(); /* Initialize stats collection --- must happen before first xact */ if (!bootstrap) pgstat_initialize(); /* * Load relcache entries for the shared system catalogs. This must create * at least entries for pg_database and catalogs used for authentication. */ RelationCacheInitializePhase2(); /* * Set up process-exit callback to do pre-shutdown cleanup. This is the * first before_shmem_exit callback we register; thus, this will be the * last thing we do before low-level modules like the buffer manager begin * to close down. We need to have this in place before we begin our first * transaction --- if we fail during the initialization transaction, as is * entirely possible, we need the AbortTransaction call to clean up. */ before_shmem_exit(ShutdownPostgres, 0); /* The autovacuum launcher is done here */ if (IsAutoVacuumLauncherProcess()) return; /* * Start a new transaction here before first access to db, and get a * snapshot. We don't have a use for the snapshot itself, but we're * interested in the secondary effect that it sets RecentGlobalXmin. (This * is critical for anything that reads heap pages, because HOT may decide * to prune them even if the process doesn't attempt to modify any * tuples.) */ if (!bootstrap) { /* statement_timestamp must be set for timeouts to work correctly */ SetCurrentStatementStartTimestamp(); StartTransactionCommand(); /* * transaction_isolation will have been set to the default by the * above. If the default is "serializable", and we are in hot * standby, we will fail if we don't change it to something lower. * Fortunately, "read committed" is plenty good enough. */ XactIsoLevel = XACT_READ_COMMITTED; (void) GetTransactionSnapshot(); } /* * Perform client authentication if necessary, then figure out our * postgres user ID, and see if we are a superuser. * * In standalone mode and in autovacuum worker processes, we use a fixed * ID, otherwise we figure it out from the authenticated user name. */ if (bootstrap || IsAutoVacuumWorkerProcess()) { InitializeSessionUserIdStandalone(); am_superuser = true; } else if (!IsUnderPostmaster) { InitializeSessionUserIdStandalone(); am_superuser = true; if (!ThereIsAtLeastOneRole()) ereport(WARNING, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("no roles are defined in this database system"), errhint("You should immediately run CREATE USER \"%s\" SUPERUSER;.", username))); } else if (IsBackgroundWorker) { if (username == NULL) { InitializeSessionUserIdStandalone(); am_superuser = true; } else { InitializeSessionUserId(username); am_superuser = superuser(); } } else { /* normal multiuser case */ Assert(MyProcPort != NULL); PerformAuthentication(MyProcPort); InitializeSessionUserId(username); am_superuser = superuser(); } /* * If we're trying to shut down, only superusers can connect, and new * replication connections are not allowed. */ if ((!am_superuser || am_walsender) && MyProcPort != NULL && MyProcPort->canAcceptConnections == CAC_WAITBACKUP) { if (am_walsender) ereport(FATAL, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("new replication connections are not allowed during database shutdown"))); else ereport(FATAL, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("must be superuser to connect during database shutdown"))); } /* * Binary upgrades only allowed super-user connections */ if (IsBinaryUpgrade && !am_superuser) { ereport(FATAL, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("must be superuser to connect in binary upgrade mode"))); } /* * The last few connections slots are reserved for superusers. Although * replication connections currently require superuser privileges, we * don't allow them to consume the reserved slots, which are intended for * interactive use. */ if ((!am_superuser || am_walsender) && ReservedBackends > 0 && !HaveNFreeProcs(ReservedBackends)) ereport(FATAL, (errcode(ERRCODE_TOO_MANY_CONNECTIONS), errmsg("remaining connection slots are reserved for non-replication superuser connections"))); /* Check replication permissions needed for walsender processes. */ if (am_walsender) { Assert(!bootstrap); if (!superuser() && !has_rolreplication(GetUserId())) ereport(FATAL, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("must be superuser or replication role to start walsender"))); } /* * If this is a plain walsender only supporting physical replication, we * don't want to connect to any particular database. Just finish the * backend startup by processing any options from the startup packet, and * we're done. */ if (am_walsender && !am_db_walsender) { /* process any options passed in the startup packet */ if (MyProcPort != NULL) process_startup_options(MyProcPort, am_superuser); /* Apply PostAuthDelay as soon as we've read all options */ if (PostAuthDelay > 0) pg_usleep(PostAuthDelay * 1000000L); /* initialize client encoding */ InitializeClientEncoding(); /* report this backend in the PgBackendStatus array */ pgstat_bestart(); /* close the transaction we started above */ CommitTransactionCommand(); return; } /* * Set up the global variables holding database id and default tablespace. * But note we won't actually try to touch the database just yet. * * We take a shortcut in the bootstrap case, otherwise we have to look up * the db's entry in pg_database. */ if (bootstrap) { MyDatabaseId = TemplateDbOid; MyDatabaseTableSpace = DEFAULTTABLESPACE_OID; } else if (in_dbname != NULL) { HeapTuple tuple; Form_pg_database dbform; tuple = GetDatabaseTuple(in_dbname); if (!HeapTupleIsValid(tuple)) ereport(FATAL, (errcode(ERRCODE_UNDEFINED_DATABASE), errmsg("database \"%s\" does not exist", in_dbname))); dbform = (Form_pg_database) GETSTRUCT(tuple); MyDatabaseId = HeapTupleGetOid(tuple); MyDatabaseTableSpace = dbform->dattablespace; /* take database name from the caller, just for paranoia */ strlcpy(dbname, in_dbname, sizeof(dbname)); } else if (OidIsValid(dboid)) { /* caller specified database by OID */ HeapTuple tuple; Form_pg_database dbform; tuple = GetDatabaseTupleByOid(dboid); if (!HeapTupleIsValid(tuple)) ereport(FATAL, (errcode(ERRCODE_UNDEFINED_DATABASE), errmsg("database %u does not exist", dboid))); dbform = (Form_pg_database) GETSTRUCT(tuple); MyDatabaseId = HeapTupleGetOid(tuple); MyDatabaseTableSpace = dbform->dattablespace; Assert(MyDatabaseId == dboid); strlcpy(dbname, NameStr(dbform->datname), sizeof(dbname)); /* pass the database name back to the caller */ if (out_dbname) strcpy(out_dbname, dbname); } else { /* * If this is a background worker not bound to any particular * database, we're done now. Everything that follows only makes * sense if we are bound to a specific database. We do need to * close the transaction we started before returning. */ if (!bootstrap) CommitTransactionCommand(); return; } /* * Now, take a writer's lock on the database we are trying to connect to. * If there is a concurrently running DROP DATABASE on that database, this * will block us until it finishes (and has committed its update of * pg_database). * * Note that the lock is not held long, only until the end of this startup * transaction. This is OK since we will advertise our use of the * database in the ProcArray before dropping the lock (in fact, that's the * next thing to do). Anyone trying a DROP DATABASE after this point will * see us in the array once they have the lock. Ordering is important for * this because we don't want to advertise ourselves as being in this * database until we have the lock; otherwise we create what amounts to a * deadlock with CountOtherDBBackends(). * * Note: use of RowExclusiveLock here is reasonable because we envision * our session as being a concurrent writer of the database. If we had a * way of declaring a session as being guaranteed-read-only, we could use * AccessShareLock for such sessions and thereby not conflict against * CREATE DATABASE. */ if (!bootstrap) LockSharedObject(DatabaseRelationId, MyDatabaseId, 0, RowExclusiveLock); /* * Now we can mark our PGPROC entry with the database ID. * * We assume this is an atomic store so no lock is needed; though actually * things would work fine even if it weren't atomic. Anyone searching the * ProcArray for this database's ID should hold the database lock, so they * would not be executing concurrently with this store. A process looking * for another database's ID could in theory see a chance match if it read * a partially-updated databaseId value; but as long as all such searches * wait and retry, as in CountOtherDBBackends(), they will certainly see * the correct value on their next try. */ MyProc->databaseId = MyDatabaseId; /* * We established a catalog snapshot while reading pg_authid and/or * pg_database; but until we have set up MyDatabaseId, we won't react to * incoming sinval messages for unshared catalogs, so we won't realize it * if the snapshot has been invalidated. Assume it's no good anymore. */ InvalidateCatalogSnapshot(); /* * Recheck pg_database to make sure the target database hasn't gone away. * If there was a concurrent DROP DATABASE, this ensures we will die * cleanly without creating a mess. */ if (!bootstrap) { HeapTuple tuple; tuple = GetDatabaseTuple(dbname); if (!HeapTupleIsValid(tuple) || MyDatabaseId != HeapTupleGetOid(tuple) || MyDatabaseTableSpace != ((Form_pg_database) GETSTRUCT(tuple))->dattablespace) ereport(FATAL, (errcode(ERRCODE_UNDEFINED_DATABASE), errmsg("database \"%s\" does not exist", dbname), errdetail("It seems to have just been dropped or renamed."))); } /* * Now we should be able to access the database directory safely. Verify * it's there and looks reasonable. */ fullpath = GetDatabasePath(MyDatabaseId, MyDatabaseTableSpace); if (!bootstrap) { if (access(fullpath, F_OK) == -1) { if (errno == ENOENT) ereport(FATAL, (errcode(ERRCODE_UNDEFINED_DATABASE), errmsg("database \"%s\" does not exist", dbname), errdetail("The database subdirectory \"%s\" is missing.", fullpath))); else ereport(FATAL, (errcode_for_file_access(), errmsg("could not access directory \"%s\": %m", fullpath))); } ValidatePgVersion(fullpath); } SetDatabasePath(fullpath); /* * It's now possible to do real access to the system catalogs. * * Load relcache entries for the system catalogs. This must create at * least the minimum set of "nailed-in" cache entries. */ RelationCacheInitializePhase3(); /* set up ACL framework (so CheckMyDatabase can check permissions) */ initialize_acl(); /* * Re-read the pg_database row for our database, check permissions and set * up database-specific GUC settings. We can't do this until all the * database-access infrastructure is up. (Also, it wants to know if the * user is a superuser, so the above stuff has to happen first.) */ if (!bootstrap) CheckMyDatabase(dbname, am_superuser); /* * Now process any command-line switches and any additional GUC variable * settings passed in the startup packet. We couldn't do this before * because we didn't know if client is a superuser. */ if (MyProcPort != NULL) process_startup_options(MyProcPort, am_superuser); /* Process pg_db_role_setting options */ process_settings(MyDatabaseId, GetSessionUserId()); /* Apply PostAuthDelay as soon as we've read all options */ if (PostAuthDelay > 0) pg_usleep(PostAuthDelay * 1000000L); /* * Initialize various default states that can't be set up until we've * selected the active user and gotten the right GUC settings. */ /* set default namespace search path */ InitializeSearchPath(); /* initialize client encoding */ InitializeClientEncoding(); /* report this backend in the PgBackendStatus array */ if (!bootstrap) pgstat_bestart(); /* close the transaction we started above */ if (!bootstrap) CommitTransactionCommand(); }
/* * FtsProbeMain */ NON_EXEC_STATIC void ftsMain(int argc, char *argv[]) { sigjmp_buf local_sigjmp_buf; char *fullpath; IsUnderPostmaster = true; am_ftsprobe = true; /* Stay away from PMChildSlot */ MyPMChildSlot = -1; /* reset MyProcPid */ MyProcPid = getpid(); /* Lose the postmaster's on-exit routines */ on_exit_reset(); /* Identify myself via ps */ init_ps_display("ftsprobe process", "", "", ""); SetProcessingMode(InitProcessing); /* * reread postgresql.conf if requested */ pqsignal(SIGHUP, sigHupHandler); /* * Presently, SIGINT will lead to autovacuum shutdown, because that's how * we handle ereport(ERROR). It could be improved however. */ pqsignal(SIGINT, ReqFtsFullScan); /* request full-scan */ pqsignal(SIGTERM, die); pqsignal(SIGQUIT, quickdie); /* we don't do any ftsprobe specific cleanup, just use the standard. */ pqsignal(SIGALRM, handle_sig_alarm); pqsignal(SIGPIPE, SIG_IGN); pqsignal(SIGUSR1, procsignal_sigusr1_handler); /* We don't listen for async notifies */ pqsignal(SIGUSR2, RequestShutdown); pqsignal(SIGFPE, FloatExceptionHandler); pqsignal(SIGCHLD, SIG_DFL); /* * Copied from bgwriter */ CurrentResourceOwner = ResourceOwnerCreate(NULL, "FTS Probe"); /* Early initialization */ BaseInit(); /* See InitPostgres()... */ InitProcess(); InitBufferPoolBackend(); InitXLOGAccess(); SetProcessingMode(NormalProcessing); /* * If an exception is encountered, processing resumes here. * * See notes in postgres.c about the design of this coding. */ if (sigsetjmp(local_sigjmp_buf, 1) != 0) { /* Prevents interrupts while cleaning up */ HOLD_INTERRUPTS(); /* Report the error to the server log */ EmitErrorReport(); /* * We can now go away. Note that because we'll call InitProcess, a * callback will be registered to do ProcKill, which will clean up * necessary state. */ proc_exit(0); } /* We can now handle ereport(ERROR) */ PG_exception_stack = &local_sigjmp_buf; PG_SETMASK(&UnBlockSig); /* * Add my PGPROC struct to the ProcArray. * * Once I have done this, I am visible to other backends! */ InitProcessPhase2(); /* * Initialize my entry in the shared-invalidation manager's array of * per-backend data. * * Sets up MyBackendId, a unique backend identifier. */ MyBackendId = InvalidBackendId; SharedInvalBackendInit(false); if (MyBackendId > MaxBackends || MyBackendId <= 0) elog(FATAL, "bad backend id: %d", MyBackendId); /* * bufmgr needs another initialization call too */ InitBufferPoolBackend(); /* heap access requires the rel-cache */ RelationCacheInitialize(); InitCatalogCache(); /* * It's now possible to do real access to the system catalogs. * * Load relcache entries for the system catalogs. This must create at * least the minimum set of "nailed-in" cache entries. */ RelationCacheInitializePhase2(); /* * In order to access the catalog, we need a database, and a * tablespace; our access to the heap is going to be slightly * limited, so we'll just use some defaults. */ if (!FindMyDatabase(probeDatabase, &MyDatabaseId, &MyDatabaseTableSpace)) ereport(FATAL, (errcode(ERRCODE_UNDEFINED_DATABASE), errmsg("database \"%s\" does not exit", probeDatabase))); /* Now we can mark our PGPROC entry with the database ID */ /* (We assume this is an atomic store so no lock is needed) */ MyProc->databaseId = MyDatabaseId; fullpath = GetDatabasePath(MyDatabaseId, MyDatabaseTableSpace); SetDatabasePath(fullpath); RelationCacheInitializePhase3(); /* shmem: publish probe pid */ ftsProbeInfo->fts_probePid = MyProcPid; /* main loop */ FtsLoop(); /* One iteration done, go away */ proc_exit(0); }