Arrange to cache FdwRoutine structs in foreign tables' relcache entries.

This saves several catalog lookups per reference.  It's not all that
exciting right now, because we'd managed to minimize the number of places
that need to fetch the data; but the upcoming writable-foreign-tables patch
needs this info in a lot more places.
This commit is contained in:
Tom Lane 2013-03-06 23:47:38 -05:00
parent 9795113916
commit 1908abc4a3
8 changed files with 72 additions and 6 deletions

View File

@ -227,7 +227,7 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt, BufferAccessStrategy bstrategy)
FdwRoutine *fdwroutine;
bool ok = false;
fdwroutine = GetFdwRoutineByRelId(RelationGetRelid(onerel));
fdwroutine = GetFdwRoutineForRelation(onerel, false);
if (fdwroutine->AnalyzeForeignTable != NULL)
ok = fdwroutine->AnalyzeForeignTable(onerel,

View File

@ -160,7 +160,7 @@ ExecInitForeignScan(ForeignScan *node, EState *estate, int eflags)
/*
* Acquire function pointers from the FDW's handler, and init fdw_state.
*/
fdwroutine = GetFdwRoutineByRelId(RelationGetRelid(currentRelation));
fdwroutine = GetFdwRoutineForRelation(currentRelation, true);
scanstate->fdwroutine = fdwroutine;
scanstate->fdw_state = NULL;

View File

@ -23,6 +23,8 @@
#include "lib/stringinfo.h"
#include "miscadmin.h"
#include "utils/builtins.h"
#include "utils/memutils.h"
#include "utils/rel.h"
#include "utils/syscache.h"
@ -352,6 +354,50 @@ GetFdwRoutineByRelId(Oid relid)
return GetFdwRoutine(fdwhandler);
}
/*
* GetFdwRoutineForRelation - look up the handler of the foreign-data wrapper
* for the given foreign table, and retrieve its FdwRoutine struct.
*
* This function is preferred over GetFdwRoutineByRelId because it caches
* the data in the relcache entry, saving a number of catalog lookups.
*
* If makecopy is true then the returned data is freshly palloc'd in the
* caller's memory context. Otherwise, it's a pointer to the relcache data,
* which will be lost in any relcache reset --- so don't rely on it long.
*/
FdwRoutine *
GetFdwRoutineForRelation(Relation relation, bool makecopy)
{
FdwRoutine *fdwroutine;
FdwRoutine *cfdwroutine;
if (relation->rd_fdwroutine == NULL)
{
/* Get the info by consulting the catalogs and the FDW code */
fdwroutine = GetFdwRoutineByRelId(RelationGetRelid(relation));
/* Save the data for later reuse in CacheMemoryContext */
cfdwroutine = (FdwRoutine *) MemoryContextAlloc(CacheMemoryContext,
sizeof(FdwRoutine));
memcpy(cfdwroutine, fdwroutine, sizeof(FdwRoutine));
relation->rd_fdwroutine = cfdwroutine;
/* Give back the locally palloc'd copy regardless of makecopy */
return fdwroutine;
}
/* We have valid cached data --- does the caller want a copy? */
if (makecopy)
{
fdwroutine = (FdwRoutine *) palloc(sizeof(FdwRoutine));
memcpy(fdwroutine, relation->rd_fdwroutine, sizeof(FdwRoutine));
return fdwroutine;
}
/* Only a short-lived reference is needed, so just hand back cached copy */
return relation->rd_fdwroutine;
}
/*
* deflist_to_tuplestore - Helper function to convert DefElem list to

View File

@ -410,9 +410,6 @@ set_foreign_size(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte)
/* Mark rel with estimated output rows, width, etc */
set_foreign_size_estimates(root, rel);
/* Get FDW routine pointers for the rel */
rel->fdwroutine = GetFdwRoutineByRelId(rte->relid);
/* Let FDW adjust the size estimates, if it can */
rel->fdwroutine->GetForeignRelSize(root, rel, rte->relid);
}

View File

@ -26,6 +26,7 @@
#include "access/xlog.h"
#include "catalog/catalog.h"
#include "catalog/heap.h"
#include "foreign/fdwapi.h"
#include "miscadmin.h"
#include "nodes/makefuncs.h"
#include "optimizer/clauses.h"
@ -67,6 +68,7 @@ static List *build_index_tlist(PlannerInfo *root, IndexOptInfo *index,
* min_attr lowest valid AttrNumber
* max_attr highest valid AttrNumber
* indexlist list of IndexOptInfos for relation's indexes
* fdwroutine if it's a foreign table, the FDW function pointers
* pages number of pages
* tuples number of tuples
*
@ -374,6 +376,12 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
rel->indexlist = indexinfos;
/* Grab the fdwroutine info using the relcache, while we have it */
if (relation->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
rel->fdwroutine = GetFdwRoutineForRelation(relation, true);
else
rel->fdwroutine = NULL;
heap_close(relation, NoLock);
/*

View File

@ -1846,6 +1846,8 @@ RelationDestroyRelation(Relation relation)
MemoryContextDelete(relation->rd_indexcxt);
if (relation->rd_rulescxt)
MemoryContextDelete(relation->rd_rulescxt);
if (relation->rd_fdwroutine)
pfree(relation->rd_fdwroutine);
pfree(relation);
}
@ -4410,7 +4412,7 @@ load_relcache_init_file(bool shared)
* format is complex and subject to change). They must be rebuilt if
* needed by RelationCacheInitializePhase3. This is not expected to
* be a big performance hit since few system catalogs have such. Ditto
* for index expressions, predicates, and exclusion info.
* for index expressions, predicates, exclusion info, and FDW info.
*/
rel->rd_rules = NULL;
rel->rd_rulescxt = NULL;
@ -4420,6 +4422,7 @@ load_relcache_init_file(bool shared)
rel->rd_exclops = NULL;
rel->rd_exclprocs = NULL;
rel->rd_exclstrats = NULL;
rel->rd_fdwroutine = NULL;
/*
* Reset transient-state fields in the relcache entry

View File

@ -96,5 +96,6 @@ typedef struct FdwRoutine
/* Functions in foreign/foreign.c */
extern FdwRoutine *GetFdwRoutine(Oid fdwhandler);
extern FdwRoutine *GetFdwRoutineByRelId(Oid relid);
extern FdwRoutine *GetFdwRoutineForRelation(Relation relation, bool makecopy);
#endif /* FDWAPI_H */

View File

@ -165,6 +165,17 @@ typedef struct RelationData
void *rd_amcache; /* available for use by index AM */
Oid *rd_indcollation; /* OIDs of index collations */
/*
* foreign-table support
*
* rd_fdwroutine must point to a single memory chunk palloc'd in
* CacheMemoryContext. It will be freed and reset to NULL on a relcache
* reset.
*/
/* use "struct" here to avoid needing to include fdwapi.h: */
struct FdwRoutine *rd_fdwroutine; /* cached function pointers, or NULL */
/*
* Hack for CLUSTER, rewriting ALTER TABLE, etc: when writing a new
* version of a table, we need to make any toast pointers inserted into it