Beispiel #1
0
/*
 * ExecutorStart hook: start up tracking if needed
 */
static void
pgss_ExecutorStart(QueryDesc *queryDesc, int eflags)
{
	if (prev_ExecutorStart)
		prev_ExecutorStart(queryDesc, eflags);
	else
		standard_ExecutorStart(queryDesc, eflags);

	if (pgss_enabled())
	{
		/*
		 * Set up to track total elapsed time in ExecutorRun.  Make sure the
		 * space is allocated in the per-query context so it will go away at
		 * ExecutorEnd.
		 */
		if (queryDesc->totaltime == NULL)
		{
			MemoryContext oldcxt;

			oldcxt = MemoryContextSwitchTo(queryDesc->estate->es_query_cxt);
			queryDesc->totaltime = InstrAlloc(1, INSTRUMENT_ALL);
			MemoryContextSwitchTo(oldcxt);
		}
	}
}
Beispiel #2
0
/*
 * ExecutorStart hook: start up logging if needed
 */
static void
explain_ExecutorStart(QueryDesc *queryDesc, int eflags)
{
    /* decide */
    collect = collecting_enabled();
    
    if (collect) {
        gettimeofday(&start_time, NULL);
    }
    
    if (prev_ExecutorStart)
        prev_ExecutorStart(queryDesc, eflags);
    else
        standard_ExecutorStart(queryDesc, eflags);

    /* Enable the histogram whenever the histogram is dynamic or (bins>0). */
    if (collect)
    {
        /*
         * Set up to track total elapsed time in ExecutorRun.  Make sure the
         * space is allocated in the per-query context so it will go away at
         * ExecutorEnd.
         */
        if (queryDesc->totaltime == NULL)
        {
            MemoryContext oldcxt;

            oldcxt = MemoryContextSwitchTo(queryDesc->estate->es_query_cxt);
            queryDesc->totaltime = InstrAlloc(1, INSTRUMENT_ALL);
            MemoryContextSwitchTo(oldcxt);
        }
    }
}
Beispiel #3
0
static void
collectLocalMemoryStats(QueryDesc *queryDesc, int eflags)
{
	BackendMemoryStat			*myStat;
	MemoryContextIteratorState	state;

	if (prev_ExecutorStart)
		prev_ExecutorStart(queryDesc, eflags);
	else
		standard_ExecutorStart(queryDesc, eflags);

	if (MyBackendProcNo < 0)
	{
		on_proc_exit(cleanupMyStat, 0);
		MyBackendProcNo = MyProc->pgprocno;
		Assert(MyBackendProcNo >= 0);
	}

	if (checkTick() == false)
		return;

	Assert(MyBackendProcNo < PROCARRAY_MAXPROCS);
	myStat = NthBMS(MyBackendProcNo);

	/*
	 * do not wait if reader currently locks our slot
	 */
	if (LWLockConditionalAcquire(myStat->lock, LW_EXCLUSIVE) == false)
		return;

	myStat->pid = MyProc->pid;
	myStat->nContext = 0;
	state.context = TopMemoryContext;
	state.level = 0;

	/*
	 * walk through all memory context and fill stat table in shared memory
	 */
	do {
		MemoryContextStat	*mcs = myStat->stats + myStat->nContext;
		int					namelen = strlen(state.context->name);

		if (namelen > NAMEDATALEN - 1)
			namelen = NAMEDATALEN - 1;
		memcpy(mcs->name.data, state.context->name, namelen);
		mcs->name.data[namelen] = '\0';

		mcs->level = state.level;

		getMemoryContextStat(state.context, &mcs->stat);
		myStat->nContext++;

		iterateMemoryContext(&state);
	} while (state.context && myStat->nContext < N_MC_STAT);

	LWLockRelease(myStat->lock);
}
static void
grab_ExecutorStart(QueryDesc * queryDesc, int eflags)
{
	if (prev_ExecutorStart)
		prev_ExecutorStart(queryDesc, eflags);
	else
		standard_ExecutorStart(queryDesc, eflags);

	if (queryDesc->totaltime == NULL) {
		MemoryContext   oldcxt;

		oldcxt = MemoryContextSwitchTo(queryDesc->estate->es_query_cxt);
		queryDesc->totaltime = InstrAlloc(1, INSTRUMENT_ALL);
		MemoryContextSwitchTo(oldcxt);
	}
}
Beispiel #5
0
/*
 * ExecutorStart hook: start up logging if needed
 */
static void
explain_ExecutorStart(QueryDesc *queryDesc, int eflags)
{
	/*
	 * For rate sampling, randomly choose top-level statement. Either all
	 * nested statements will be explained or none will.
	 */
	if (auto_explain_log_min_duration >= 0 && nesting_level == 0)
		current_query_sampled = (random() < auto_explain_sample_rate *
								 MAX_RANDOM_VALUE);

	if (auto_explain_enabled() && current_query_sampled)
	{
		/* Enable per-node instrumentation iff log_analyze is required. */
		if (auto_explain_log_analyze && (eflags & EXEC_FLAG_EXPLAIN_ONLY) == 0)
		{
			if (auto_explain_log_timing)
				queryDesc->instrument_options |= INSTRUMENT_TIMER;
			else
				queryDesc->instrument_options |= INSTRUMENT_ROWS;
			if (auto_explain_log_buffers)
				queryDesc->instrument_options |= INSTRUMENT_BUFFERS;
		}
	}

	if (prev_ExecutorStart)
		prev_ExecutorStart(queryDesc, eflags);
	else
		standard_ExecutorStart(queryDesc, eflags);

	if (auto_explain_enabled() && current_query_sampled)
	{
		/*
		 * Set up to track total elapsed time in ExecutorRun.  Make sure the
		 * space is allocated in the per-query context so it will go away at
		 * ExecutorEnd.
		 */
		if (queryDesc->totaltime == NULL)
		{
			MemoryContext oldcxt;

			oldcxt = MemoryContextSwitchTo(queryDesc->estate->es_query_cxt);
			queryDesc->totaltime = InstrAlloc(1, INSTRUMENT_ALL);
			MemoryContextSwitchTo(oldcxt);
		}
	}
}
Beispiel #6
0
/*
 * ExecutorStart hook: start up logging if needed
 */
static void
explain_ExecutorStart(QueryDesc *queryDesc, int eflags)
{
	if (auto_explain_enabled())
	{
		/* Enable per-node instrumentation iff log_analyze is required. */
		if (auto_explain_log_analyze && (eflags & EXEC_FLAG_EXPLAIN_ONLY) == 0)
		{
			if (auto_explain_log_timing)
				queryDesc->instrument_options |= INSTRUMENT_TIMER;
			else
				queryDesc->instrument_options |= INSTRUMENT_ROWS;


			if (auto_explain_log_buffers)
				queryDesc->instrument_options |= INSTRUMENT_BUFFERS;
		}
	}

	if (prev_ExecutorStart)
		prev_ExecutorStart(queryDesc, eflags);
	else
		standard_ExecutorStart(queryDesc, eflags);

	if (auto_explain_enabled())
	{
		/*
		 * Set up to track total elapsed time in ExecutorRun.  Make sure the
		 * space is allocated in the per-query context so it will go away at
		 * ExecutorEnd.
		 */
		if (queryDesc->totaltime == NULL)
		{
			MemoryContext oldcxt;

			oldcxt = MemoryContextSwitchTo(queryDesc->estate->es_query_cxt);
			queryDesc->totaltime = InstrAlloc(1, INSTRUMENT_ALL);
			MemoryContextSwitchTo(oldcxt);
		}
	}
}
Beispiel #7
0
/*
 * PgPaxosExecutorStart blocks until the table is ready to read.
 */
static void
PgPaxosExecutorStart(QueryDesc *queryDesc, int eflags)
{
	PlannedStmt *plannedStmt = queryDesc->plannedstmt;
	List *rangeTableList = plannedStmt->rtable;
	CmdType commandType = queryDesc->operation;

	if (IsPgPaxosActive() && HasPaxosTable(rangeTableList))
	{
		char *sqlQuery = (char *) queryDesc->sourceText;
		char *groupId = NULL;
		bool topLevel = true;

		/* disallow transactions during paxos commands */
		PreventTransactionChain(topLevel, "paxos commands");

		groupId = DeterminePaxosGroup(rangeTableList);

		if (commandType == CMD_INSERT || commandType == CMD_UPDATE ||
			commandType == CMD_DELETE)
		{
			PrepareConsistentWrite(groupId, sqlQuery);
		}
		else
		{
			PrepareConsistentRead(groupId);
		}

		queryDesc->snapshot->curcid = GetCurrentCommandId(false);
	}

	/* call into the standard executor start, or hook if set */
	if (PreviousExecutorStartHook != NULL)
	{
		PreviousExecutorStartHook(queryDesc, eflags);
	}
	else
	{
		standard_ExecutorStart(queryDesc, eflags);
	}
}
Beispiel #8
0
/*
 * multi_ExecutorStart is a hook called at at the beginning of any execution
 * of any query plan.
 *
 * If a distributed relation is the target of the query, perform some validity
 * checks. If a legal statement, start the distributed execution. After that
 * the to-be-executed query is replaced with the portion executing solely on
 * the master.
 */
void
multi_ExecutorStart(QueryDesc *queryDesc, int eflags)
{
	PlannedStmt *planStatement = queryDesc->plannedstmt;

	if (HasCitusToplevelNode(planStatement))
	{
		MultiPlan *multiPlan = GetMultiPlan(planStatement);
		MultiExecutorType executorType = MULTI_EXECUTOR_INVALID_FIRST;
		Job *workerJob = multiPlan->workerJob;

		ExecCheckRTPerms(planStatement->rtable, true);

		executorType = JobExecutorType(multiPlan);
		if (executorType == MULTI_EXECUTOR_ROUTER)
		{
			Task *task = NULL;
			List *taskList = workerJob->taskList;
			TupleDesc tupleDescriptor = ExecCleanTypeFromTL(
				planStatement->planTree->targetlist, false);
			List *dependendJobList PG_USED_FOR_ASSERTS_ONLY = workerJob->dependedJobList;

			/* router executor can only execute distributed plans with a single task */
			Assert(list_length(taskList) == 1);
			Assert(dependendJobList == NIL);

			task = (Task *) linitial(taskList);

			/* we need to set tupleDesc in executorStart */
			queryDesc->tupDesc = tupleDescriptor;

			/* drop into the router executor */
			RouterExecutorStart(queryDesc, eflags, task);
		}
		else
		{
			PlannedStmt *masterSelectPlan = MasterNodeSelectPlan(multiPlan);
			CreateStmt *masterCreateStmt = MasterNodeCreateStatement(multiPlan);
			List *masterCopyStmtList = MasterNodeCopyStatementList(multiPlan);
			RangeTblEntry *masterRangeTableEntry = NULL;
			StringInfo jobDirectoryName = NULL;

			/*
			 * We create a directory on the master node to keep task execution results.
			 * We also register this directory for automatic cleanup on portal delete.
			 */
			jobDirectoryName = JobDirectoryName(workerJob->jobId);
			CreateDirectory(jobDirectoryName);

			ResourceOwnerEnlargeJobDirectories(CurrentResourceOwner);
			ResourceOwnerRememberJobDirectory(CurrentResourceOwner, workerJob->jobId);

			/* pick distributed executor to use */
			if (eflags & EXEC_FLAG_EXPLAIN_ONLY)
			{
				/* skip distributed query execution for EXPLAIN commands */
			}
			else if (executorType == MULTI_EXECUTOR_REAL_TIME)
			{
				MultiRealTimeExecute(workerJob);
			}
			else if (executorType == MULTI_EXECUTOR_TASK_TRACKER)
			{
				MultiTaskTrackerExecute(workerJob);
			}

			/* then create the result relation */
			ProcessUtility((Node *) masterCreateStmt,
						   "(temp table creation)",
						   PROCESS_UTILITY_QUERY,
						   NULL,
						   None_Receiver,
						   NULL);

			/* make the temporary table visible */
			CommandCounterIncrement();

			if (!(eflags & EXEC_FLAG_EXPLAIN_ONLY))
			{
				CopyQueryResults(masterCopyStmtList);
			}

			/*
			 * Update the QueryDesc's snapshot so it sees the table. That's not
			 * particularly pretty, but we don't have much of a choice.  One might
			 * think we could unregister the snapshot, push a new active one,
			 * update it, register it, and be happy. That only works if it's only
			 * registered once though...
			 */
			queryDesc->snapshot->curcid = GetCurrentCommandId(false);

			/*
			 * Set the OID of the RTE used in the master select statement to point
			 * to the now created (and filled) temporary table. The target
			 * relation's oid is only known now.
			 */
			masterRangeTableEntry =
				(RangeTblEntry *) linitial(masterSelectPlan->rtable);
			masterRangeTableEntry->relid =
				RelnameGetRelid(masterRangeTableEntry->eref->aliasname);

			/*
			 * Replace to-be-run query with the master select query. As the
			 * planned statement is now replaced we can't call GetMultiPlan() in
			 * the later hooks, so we set a flag marking this as a distributed
			 * statement running on the master. That e.g. allows us to drop the
			 * temp table later.
			 *
			 * We copy the original statement's queryId, to allow
			 * pg_stat_statements and similar extension to associate the
			 * statement with the toplevel statement.
			 */
			masterSelectPlan->queryId = queryDesc->plannedstmt->queryId;
			queryDesc->plannedstmt = masterSelectPlan;

			eflags |= EXEC_FLAG_CITUS_MASTER_SELECT;
		}
	}

	/* if the execution is not done for router executor, drop into standard executor */
	if (queryDesc->estate == NULL ||
		!(queryDesc->estate->es_top_eflags & EXEC_FLAG_CITUS_ROUTER_EXECUTOR))
	{
		standard_ExecutorStart(queryDesc, eflags);
	}
}