bool
PersistentFilespace_TryGetPrimaryAndMirror(
										   Oid filespaceOid,
 /* The filespace OID to lookup. */

										   char **primaryFilespaceLocation,
 /* The primary filespace directory path.  Return NULL for global and base. */

										   char **mirrorFilespaceLocation)

 /*
  * The primary filespace directory path.  Return NULL for global and base.
  * Or, returns NULL when mirror not configured.
  */
{
	FilespaceDirEntry filespaceDirEntry;
	bool		result = false;

	*primaryFilespaceLocation = NULL;
	*mirrorFilespaceLocation = NULL;

#ifdef MASTER_MIRROR_SYNC

	/*
	 * Can't rely on persistent tables or memory structures on the standby so
	 * get it from the cache maintained by the master mirror sync code
	 */
	if (IsStandbyMode())
	{
		return mmxlog_filespace_get_path(
										 filespaceOid,
										 primaryFilespaceLocation);
	}
#endif

	/*
	 * Important to make this call AFTER we check if we are the Standby
	 * Master.
	 */
	PersistentFilespace_VerifyInitScan();

	LWLockAcquire(FilespaceHashLock, LW_SHARED);
	filespaceDirEntry = PersistentFilespace_FindDirUnderLock(filespaceOid);
	if (filespaceDirEntry)
	{
		PersistentFilespace_GetPaths(filespaceDirEntry,
									 primaryFilespaceLocation,
									 mirrorFilespaceLocation);
		result = true;
	}
	LWLockRelease(FilespaceHashLock);

	return result;
}
PersistentTablespaceGetFilespaces
PersistentTablespace_TryGetPrimaryAndMirrorFilespaces(
													  Oid tablespaceOid,
 /* The tablespace OID for the create. */

													  char **primaryFilespaceLocation,
 /* The primary filespace directory path.  Return NULL for global and base. */

													  char **mirrorFilespaceLocation,

 /*
  * The primary filespace directory path.  Return NULL for global and base.
  * Or, returns NULL when mirror not configured.
  */

													  Oid *filespaceOid)
{
	*primaryFilespaceLocation = NULL;
	*mirrorFilespaceLocation = NULL;
	*filespaceOid = InvalidOid;

	if (IsBuiltinTablespace(tablespaceOid))
	{
		/*
		 * Optimize out the common cases.
		 */
		return PersistentTablespaceGetFilespaces_Ok;
	}

#ifdef MASTER_MIRROR_SYNC

	/*
	 * Can't rely on persistent tables or memory structures on the standby so
	 * get it from the cache maintained by the master mirror sync code
	 */
	if (IsStandbyMode())
	{
		if (!mmxlog_tablespace_get_filespace(
											 tablespaceOid,
											 filespaceOid))
		{
			if (!Debug_persistent_recovery_print)
			{
				/* Print this information when we are not doing other tracing. */
				mmxlog_print_tablespaces(
										 LOG,
										 "Standby Get Filespace for Tablespace");
			}
			return PersistentTablespaceGetFilespaces_TablespaceNotFound;
		}

		if (!mmxlog_filespace_get_path(
									   *filespaceOid,
									   primaryFilespaceLocation))
		{
			if (!Debug_persistent_recovery_print)
			{
				/* Print this information when we are not doing other tracing. */
				mmxlog_print_filespaces(
										LOG,
										"Standby Get Filespace Location");
			}
			return PersistentTablespaceGetFilespaces_FilespaceNotFound;
		}

		return PersistentTablespaceGetFilespaces_Ok;
	}
#endif

	/*
	 * MPP-10111 - There is a point during gpexpand where we need to bring the
	 * database up to fix the filespace locations for a segment.  At this
	 * point in time the old filespace locations are wrong and we should not
	 * trust anything currently stored there.  If the guc is set we prevent
	 * the lookup of a any non builtin filespaces.
	 */
	if (gp_before_filespace_setup)
		elog(ERROR, "can not lookup tablespace location: gp_before_filespace_setup=true");

	/*
	 * Important to make this call AFTER we check if we are the Standby
	 * Master.
	 */
	PersistentTablespace_VerifyInitScan();

	return PersistentFilespace_GetFilespaceFromTablespace(
														  tablespaceOid, primaryFilespaceLocation,
														  mirrorFilespaceLocation, filespaceOid);
}
Esempio n. 3
0
/*
 * Open a relation during XLOG replay
 *
 * Note: this once had an API that allowed NULL return on failure, but it
 * no longer does; any failure results in elog().
 */
Relation
XLogOpenRelation(RelFileNode rnode)
{
	XLogRelDesc *res;
	XLogRelCacheEntry *hentry;
	bool		found;

	hentry = (XLogRelCacheEntry *)
		hash_search(_xlrelcache, (void *) &rnode, HASH_FIND, NULL);

	if (hentry)
	{
		res = hentry->rdesc;

		res->lessRecently->moreRecently = res->moreRecently;
		res->moreRecently->lessRecently = res->lessRecently;
	}
	else
	{
		/*
		 * We need to fault in the database directory on the standby.
		 */
		if (rnode.spcNode != GLOBALTABLESPACE_OID && IsStandbyMode())
		{
			char *primaryFilespaceLocation = NULL;

			char *dbPath;
			
			if (IsBuiltinTablespace(rnode.spcNode))
			{
				/*
				 * No filespace to fetch.
				 */
			}
			else
			{		
				char *mirrorFilespaceLocation = NULL;
			
				/*
				 * Investigate whether the containing directories exist to give more detail.
				 */
				PersistentTablespace_GetPrimaryAndMirrorFilespaces(
													rnode.spcNode,
													&primaryFilespaceLocation,
													&mirrorFilespaceLocation);
				if (primaryFilespaceLocation == NULL ||
					strlen(primaryFilespaceLocation) == 0)
				{
					elog(ERROR, "Empty primary filespace directory location");
				}
			
				if (mirrorFilespaceLocation != NULL)
				{
					pfree(mirrorFilespaceLocation);
					mirrorFilespaceLocation = NULL;
				}
			}
			
			dbPath = (char*)palloc(MAXPGPATH + 1);
			
			FormDatabasePath(
						dbPath,
						primaryFilespaceLocation,
						rnode.spcNode,
						rnode.dbNode);

			if (primaryFilespaceLocation != NULL)
			{
				pfree(primaryFilespaceLocation);
				primaryFilespaceLocation = NULL;
			}
			
			if (mkdir(dbPath, 0700) == 0)
			{
				if (Debug_persistent_recovery_print)
				{
					elog(PersistentRecovery_DebugPrintLevel(), 
						 "XLogOpenRelation: Re-created database directory \"%s\"",
						 dbPath);
				}
			}
			else
			{
				/*
				 * Allowed to already exist.
				 */
				if (errno != EEXIST)
				{
					elog(ERROR, "could not create database directory \"%s\": %m",
						 dbPath);
				}
				else
				{
					if (Debug_persistent_recovery_print)
					{
						elog(PersistentRecovery_DebugPrintLevel(), 
							 "XLogOpenRelation: Database directory \"%s\" already exists",
							 dbPath);
					}
				}
			}

			pfree(dbPath);
		}
		
		res = _xl_new_reldesc();

		sprintf(RelationGetRelationName(&(res->reldata)), "%u", rnode.relNode);

		res->reldata.rd_node = rnode;

		/*
		 * We set up the lockRelId in case anything tries to lock the dummy
		 * relation.  Note that this is fairly bogus since relNode may be
		 * different from the relation's OID.  It shouldn't really matter
		 * though, since we are presumably running by ourselves and can't have
		 * any lock conflicts ...
		 */
		res->reldata.rd_lockInfo.lockRelId.dbId = rnode.dbNode;
		res->reldata.rd_lockInfo.lockRelId.relId = rnode.relNode;

		hentry = (XLogRelCacheEntry *)
			hash_search(_xlrelcache, (void *) &rnode, HASH_ENTER, &found);

		if (found)
			elog(PANIC, "xlog relation already present on insert into cache");

		hentry->rdesc = res;

		res->reldata.rd_targblock = InvalidBlockNumber;
		res->reldata.rd_smgr = NULL;
		RelationOpenSmgr(&(res->reldata));

		/*
		 * Create the target file if it doesn't already exist.  This lets us
		 * cope if the replay sequence contains writes to a relation that is
		 * later deleted.  (The original coding of this routine would instead
		 * return NULL, causing the writes to be suppressed. But that seems
		 * like it risks losing valuable data if the filesystem loses an inode
		 * during a crash.	Better to write the data until we are actually
		 * told to delete the file.)
		 */
		// NOTE: We no longer re-create files automatically because
		// new FileRep persistent objects will ensure files exist.

		// UNDONE: Can't remove this block of code yet until boot time calls to this routine are analyzed...
		{
			MirrorDataLossTrackingState mirrorDataLossTrackingState;
			int64 mirrorDataLossTrackingSessionNum;
			bool mirrorDataLossOccurred;
			
			// UNDONE: What about the persistent rel files table???
			// UNDONE: This condition should not occur anymore.
			// UNDONE: segmentFileNum and AO?
			mirrorDataLossTrackingState = 
						FileRepPrimary_GetMirrorDataLossTrackingSessionNum(
														&mirrorDataLossTrackingSessionNum);
			smgrcreate(
				res->reldata.rd_smgr, 
				res->reldata.rd_isLocalBuf, 
				/* relationName */ NULL,		// Ok to be NULL -- we don't know the name here.
				mirrorDataLossTrackingState,
				mirrorDataLossTrackingSessionNum,
				/* ignoreAlreadyExists */ true,
				&mirrorDataLossOccurred);
			
		}
	}

	res->moreRecently = &(_xlrelarr[0]);
	res->lessRecently = _xlrelarr[0].lessRecently;
	_xlrelarr[0].lessRecently = res;
	res->lessRecently->moreRecently = res;

	Assert(&(res->reldata) != NULL);	// Assert what it says in the interface -- we don't return NULL anymore.

	return &(res->reldata);
}
Esempio n. 4
0
bool PersistentFilespace_TryGetPrimaryAndMirrorUnderLock(
	Oid 		filespaceOid,
				/* The filespace OID to lookup. */

	char **primaryFilespaceLocation,
				/* The primary filespace directory path.  Return NULL for global and base. */

	char **mirrorFilespaceLocation)
				/* The primary filespace directory path.  Return NULL for global and base.
				 * Or, returns NULL when mirror not configured. */
{
	FilespaceDirEntry filespaceDirEntry;

	int16 primaryDbId;

	char *primaryBlankPadded = NULL;
	char *mirrorBlankPadded = NULL;

	*primaryFilespaceLocation = NULL;
	*mirrorFilespaceLocation = NULL;

#ifdef MASTER_MIRROR_SYNC
	/*
	 * Can't rely on persistent tables or memory structures on the standby so
	 * get it from the cache maintained by the master mirror sync code
	 */
	if (IsStandbyMode())
	{
		return mmxlog_filespace_get_path(
									filespaceOid,
									primaryFilespaceLocation);
	}
#endif

	/*
	 * Important to make this call AFTER we check if we are the Standby Master.
	 */
	PersistentFilespace_VerifyInitScan();

	filespaceDirEntry =
				PersistentFilespace_FindDirUnderLock(
												filespaceOid);
	if (filespaceDirEntry == NULL)
		return false;

	/*
	 * The persistent_filespace_node_table contains the paths for both the
	 * primary and mirror nodes, and the table is the same on both sides of the
	 * mirror.  When it was first created the primary put its location first,
	 * but we don't know if we were the primary when it was created or not.  To
	 * determine which path corresponds to this node we compare our dbid to the
	 * one stored in the table.
	 */
	primaryDbId = GpIdentity.dbid;
	if (filespaceDirEntry->dbId1 == primaryDbId)
	{
		/* dbid == dbid1 */
		primaryBlankPadded = filespaceDirEntry->locationBlankPadded1;
		mirrorBlankPadded = filespaceDirEntry->locationBlankPadded2;
	}
	else if (filespaceDirEntry->dbId2 == primaryDbId)
	{
		/* dbid == dbid2 */
		primaryBlankPadded = filespaceDirEntry->locationBlankPadded2;
		mirrorBlankPadded = filespaceDirEntry->locationBlankPadded1;
	}
	else
	{
		/*
		 * The dbid check above does not work for the Master Node during
		 * initial startup, because the master doesn't yet know its own dbid.
		 * To handle this we special case for the master node the master
		 * always considers the first entry as the correct location.
		 *
		 * Note: This design may need to  be reconsidered to handle standby
		 * masters!
		 */
		PrimaryMirrorMode mode;

		getPrimaryMirrorStatusCodes(&mode, NULL, NULL, NULL);

		if (mode == PMModeMaster)
		{
			/* Master node */
			primaryBlankPadded = filespaceDirEntry->locationBlankPadded1;
			mirrorBlankPadded = filespaceDirEntry->locationBlankPadded2;
		}
		else
		{
			/*
			 * Current dbid matches neither dbid in table and was not started
			 * as a master node.
			 */
			ereport(FATAL,
					(errcode(ERRCODE_INTERNAL_ERROR),
					 errmsg("Unable to determine dbid for filespace lookup")));
		}
	}

	/* These should both have been populated by one of the cases above */
	Assert(primaryBlankPadded);
	Assert(mirrorBlankPadded);

	PersistentFilespace_ConvertBlankPaddedLocation(
											primaryFilespaceLocation,
											primaryBlankPadded,
											/* isPrimary */ true);

	PersistentFilespace_ConvertBlankPaddedLocation(
											mirrorFilespaceLocation,
											mirrorBlankPadded,
											/* isPrimary */ false);

	return true;
}