greenplumn CMDAccessor 源码

  • 2022-08-18
  • 浏览 (191)

greenplumn CMDAccessor 代码

文件路径:/src/backend/gporca/libgpopt/src/mdcache/CMDAccessor.cpp

//---------------------------------------------------------------------------
//	Greenplum Database
//	Copyright (C) 2011 Greenplum, Inc.
//
//	@filename:
//		CMDAccessor.cpp
//
//	@doc:
//		Implementation of the metadata accessor class handling accesses to
//		metadata objects in an optimization session
//---------------------------------------------------------------------------

#include "gpopt/mdcache/CMDAccessor.h"

#include "gpos/common/CAutoP.h"
#include "gpos/common/CAutoRef.h"
#include "gpos/common/CTimerUser.h"
#include "gpos/error/CAutoTrace.h"
#include "gpos/io/COstreamString.h"
#include "gpos/task/CAutoSuspendAbort.h"

#include "gpopt/base/CColRefSetIter.h"
#include "gpopt/base/CColRefTable.h"
#include "gpopt/exception.h"
#include "gpopt/mdcache/CMDAccessorUtils.h"
#include "naucrates/dxl/CDXLUtils.h"
#include "naucrates/exception.h"
#include "naucrates/md/CMDIdCast.h"
#include "naucrates/md/CMDIdColStats.h"
#include "naucrates/md/CMDIdRelStats.h"
#include "naucrates/md/CMDIdScCmp.h"
#include "naucrates/md/CMDProviderGeneric.h"
#include "naucrates/md/IMDAggregate.h"
#include "naucrates/md/IMDCacheObject.h"
#include "naucrates/md/IMDCast.h"
#include "naucrates/md/IMDCheckConstraint.h"
#include "naucrates/md/IMDColStats.h"
#include "naucrates/md/IMDFunction.h"
#include "naucrates/md/IMDIndex.h"
#include "naucrates/md/IMDProvider.h"
#include "naucrates/md/IMDRelStats.h"
#include "naucrates/md/IMDRelation.h"
#include "naucrates/md/IMDRelationExternal.h"
#include "naucrates/md/IMDScCmp.h"
#include "naucrates/md/IMDScalarOp.h"
#include "naucrates/md/IMDTrigger.h"
#include "naucrates/md/IMDType.h"
#include "naucrates/traceflags/traceflags.h"

using namespace gpos;
using namespace gpmd;
using namespace gpopt;
using namespace gpdxl;

// no. of hashtable buckets
#define GPOPT_CACHEACC_HT_NUM_OF_BUCKETS 128

// static member initialization

// invalid mdid pointer
const MdidPtr CMDAccessor::SMDAccessorElem::m_pmdidInvalid = nullptr;

// invalid md provider element
const CMDAccessor::SMDProviderElem
	CMDAccessor::SMDProviderElem::m_mdpelemInvalid(
		CSystemId(IMDId::EmdidSentinel, nullptr, 0), nullptr);

//---------------------------------------------------------------------------
//	@function:
//		CMDAccessor::SMDAccessorElem::SMDAccessorElem
//
//	@doc:
//		Constructs a metadata accessor element for the accessors hashtable
//
//---------------------------------------------------------------------------
CMDAccessor::SMDAccessorElem::SMDAccessorElem(IMDCacheObject *pimdobj,
											  IMDId *mdid)
	: m_imd_obj(pimdobj), m_mdid(mdid)
{
}

//---------------------------------------------------------------------------
//	@function:
//		CMDAccessor::SMDAccessorElem::~SMDAccessorElem
//
//	@doc:
//		Destructor for the metadata accessor element
//
//---------------------------------------------------------------------------
CMDAccessor::SMDAccessorElem::~SMDAccessorElem()
{
	// deleting the cache accessor will effectively unpin the cache entry for that object
	m_imd_obj->Release();
	m_mdid->Release();
}


//---------------------------------------------------------------------------
//	@function:
//		CMDAccessor::SMDAccessorElem::MDId
//
//	@doc:
//		Return the key for this hashtable element
//
//---------------------------------------------------------------------------
IMDId *
CMDAccessor::SMDAccessorElem::MDId() const
{
	return m_mdid;
}

//---------------------------------------------------------------------------
//	@function:
//		CMDAccessor::SMDAccessorElem::Equals
//
//	@doc:
//		Equality function for cache accessors hash table
//
//---------------------------------------------------------------------------
BOOL
CMDAccessor::SMDAccessorElem::Equals(const MdidPtr &left_mdid,
									 const MdidPtr &right_mdid)
{
	if (left_mdid == m_pmdidInvalid || right_mdid == m_pmdidInvalid)
	{
		return left_mdid == m_pmdidInvalid && right_mdid == m_pmdidInvalid;
	}

	return left_mdid->Equals(right_mdid);
}

//---------------------------------------------------------------------------
//	@function:
//		CMDAccessor::SMDAccessorElem::HashValue
//
//	@doc:
//		Hash function for cache accessors hash table
//
//---------------------------------------------------------------------------
ULONG
CMDAccessor::SMDAccessorElem::HashValue(const MdidPtr &mdid)
{
	GPOS_ASSERT(m_pmdidInvalid != mdid);

	return mdid->HashValue();
}

//---------------------------------------------------------------------------
//	@function:
//		CMDAccessor::SMDProviderElem::SMDProviderElem
//
//	@doc:
//		Constructs an MD provider element
//
//---------------------------------------------------------------------------
CMDAccessor::SMDProviderElem::SMDProviderElem(CSystemId sysid,
											  IMDProvider *pmdp)
	: m_sysid(sysid), m_pmdp(pmdp)
{
}

//---------------------------------------------------------------------------
//	@function:
//		CMDAccessor::SMDProviderElem::~SMDProviderElem
//
//	@doc:
//		Destructor for the MD provider element
//
//---------------------------------------------------------------------------
CMDAccessor::SMDProviderElem::~SMDProviderElem()
{
	CRefCount::SafeRelease(m_pmdp);
}

//---------------------------------------------------------------------------
//	@function:
//		CMDAccessor::SMDProviderElem::Pmdp
//
//	@doc:
//		Returns the MD provider for this hash table element
//
//---------------------------------------------------------------------------
IMDProvider *
CMDAccessor::SMDProviderElem::Pmdp()
{
	return m_pmdp;
}

//---------------------------------------------------------------------------
//	@function:
//		CMDAccessor::SMDProviderElem::Sysid
//
//	@doc:
//		Returns the system id for this hash table element
//
//---------------------------------------------------------------------------
CSystemId
CMDAccessor::SMDProviderElem::Sysid() const
{
	return m_sysid;
}

//---------------------------------------------------------------------------
//	@function:
//		CMDAccessor::SMDProviderElem::Equals
//
//	@doc:
//		Equality function for hash tables
//
//---------------------------------------------------------------------------
BOOL
CMDAccessor::SMDProviderElem::Equals(const SMDProviderElem &mdpelemLeft,
									 const SMDProviderElem &mdpelemRight)
{
	return mdpelemLeft.m_sysid.Equals(mdpelemRight.m_sysid);
}

//---------------------------------------------------------------------------
//	@function:
//		CMDAccessor::SMDProviderElem::HashValue
//
//	@doc:
//		Hash function for cost contexts hash table
//
//---------------------------------------------------------------------------
ULONG
CMDAccessor::SMDProviderElem::HashValue(const SMDProviderElem &mdpelem)
{
	GPOS_ASSERT(!Equals(mdpelem, m_mdpelemInvalid));

	return mdpelem.m_sysid.HashValue();
}

//---------------------------------------------------------------------------
//	@function:
//		CMDAccessor::CMDAccessor
//
//	@doc:
//		Constructs a metadata accessor
//
//---------------------------------------------------------------------------
CMDAccessor::CMDAccessor(CMemoryPool *mp, MDCache *pcache)
	: m_mp(mp), m_pcache(pcache), m_dLookupTime(0.0), m_dFetchTime(0.0)
{
	GPOS_ASSERT(nullptr != m_mp);
	GPOS_ASSERT(nullptr != m_pcache);

	m_pmdpGeneric = GPOS_NEW(mp) CMDProviderGeneric(mp);

	InitHashtables(mp);
}

//---------------------------------------------------------------------------
//	@function:
//		CMDAccessor::CMDAccessor
//
//	@doc:
//		Constructs a metadata accessor and registers an MD provider
//
//---------------------------------------------------------------------------
CMDAccessor::CMDAccessor(CMemoryPool *mp, MDCache *pcache, CSystemId sysid,
						 IMDProvider *pmdp)
	: m_mp(mp), m_pcache(pcache), m_dLookupTime(0.0), m_dFetchTime(0.0)
{
	GPOS_ASSERT(nullptr != m_mp);
	GPOS_ASSERT(nullptr != m_pcache);

	m_pmdpGeneric = GPOS_NEW(mp) CMDProviderGeneric(mp);

	InitHashtables(mp);

	RegisterProvider(sysid, pmdp);
}


//---------------------------------------------------------------------------
//	@function:
//		CMDAccessor::CMDAccessor
//
//	@doc:
//		Constructs a metadata accessor and registers MD providers
//
//---------------------------------------------------------------------------
CMDAccessor::CMDAccessor(CMemoryPool *mp, MDCache *pcache,
						 const CSystemIdArray *pdrgpsysid,
						 const CMDProviderArray *pdrgpmdp)
	: m_mp(mp), m_pcache(pcache), m_dLookupTime(0.0), m_dFetchTime(0.0)
{
	GPOS_ASSERT(nullptr != m_mp);
	GPOS_ASSERT(nullptr != m_pcache);

	m_pmdpGeneric = GPOS_NEW(mp) CMDProviderGeneric(mp);

	InitHashtables(mp);

	RegisterProviders(pdrgpsysid, pdrgpmdp);
}

//---------------------------------------------------------------------------
//	@function:
//		CMDAccessor::DestroyAccessorElement
//
//	@doc:
//		Destroy accessor element;
//		called only at destruction time
//
//---------------------------------------------------------------------------
void
CMDAccessor::DestroyAccessorElement(SMDAccessorElem *pmdaccelem)
{
	GPOS_ASSERT(nullptr != pmdaccelem);

	// remove deletion lock for mdid
	pmdaccelem->MDId()->RemoveDeletionLock();
	;

	GPOS_DELETE(pmdaccelem);
}

//---------------------------------------------------------------------------
//	@function:
//		CMDAccessor::DestroyProviderElement
//
//	@doc:
//		Destroy provider element;
//		called only at destruction time
//
//---------------------------------------------------------------------------
void
CMDAccessor::DestroyProviderElement(SMDProviderElem *pmdpelem)
{
	GPOS_DELETE(pmdpelem);
}

//---------------------------------------------------------------------------
//	@function:
//		CMDAccessor::InitHashtables
//
//	@doc:
//		Initializes the hash tables
//
//---------------------------------------------------------------------------
void
CMDAccessor::InitHashtables(CMemoryPool *mp)
{
	// initialize Cache accessors hash table
	m_shtCacheAccessors.Init(mp, GPOPT_CACHEACC_HT_NUM_OF_BUCKETS,
							 GPOS_OFFSET(SMDAccessorElem, m_link),
							 GPOS_OFFSET(SMDAccessorElem, m_mdid),
							 &(SMDAccessorElem::m_pmdidInvalid),
							 SMDAccessorElem::HashValue,
							 SMDAccessorElem::Equals);

	// initialize MD providers hash table
	m_shtProviders.Init(mp, GPOPT_CACHEACC_HT_NUM_OF_BUCKETS,
						GPOS_OFFSET(SMDProviderElem, m_link),
						0,	// the HT element is used as key
						&(SMDProviderElem::m_mdpelemInvalid),
						SMDProviderElem::HashValue, SMDProviderElem::Equals);
}

//---------------------------------------------------------------------------
//	@function:
//		CMDAccessor::~CMDAccessor
//
//	@doc:
//		Destructor
//
//---------------------------------------------------------------------------
CMDAccessor::~CMDAccessor()
{
	// release cache accessors and MD providers in hashtables
	m_shtCacheAccessors.DestroyEntries(DestroyAccessorElement);
	m_shtProviders.DestroyEntries(DestroyProviderElement);
	GPOS_DELETE(m_pmdpGeneric);

	if (GPOS_FTRACE(EopttracePrintOptimizationStatistics))
	{
		// print fetch time and lookup time
		CAutoTrace at(m_mp);
		at.Os() << "[OPT]: Total metadata fetch time: " << m_dFetchTime << "ms"
				<< std::endl;
		at.Os() << "[OPT]: Total metadata lookup time (including fetch time): "
				<< m_dLookupTime << "ms" << std::endl;
	}
}

//---------------------------------------------------------------------------
//	@function:
//		CMDAccessor::RegisterProvider
//
//	@doc:
//		Register a MD provider for the given source system id
//
//---------------------------------------------------------------------------
void
CMDAccessor::RegisterProvider(CSystemId sysid, IMDProvider *pmdp)
{
	CAutoP<SMDProviderElem> a_pmdpelem;
	a_pmdpelem = GPOS_NEW(m_mp) SMDProviderElem(sysid, pmdp);

	MDPHTAccessor mdhtacc(m_shtProviders, *(a_pmdpelem.Value()));

	// insert provider in the hash table
	mdhtacc.Insert(a_pmdpelem.Value());
	a_pmdpelem.Reset();
}


//---------------------------------------------------------------------------
//	@function:
//		CMDAccessor::RegisterProviders
//
//	@doc:
//		Register given MD providers
//
//---------------------------------------------------------------------------
void
CMDAccessor::RegisterProviders(const CSystemIdArray *pdrgpsysid,
							   const CMDProviderArray *pdrgpmdp)
{
	GPOS_ASSERT(nullptr != pdrgpmdp);
	GPOS_ASSERT(nullptr != pdrgpsysid);
	GPOS_ASSERT(pdrgpmdp->Size() == pdrgpsysid->Size());
	GPOS_ASSERT(0 < pdrgpmdp->Size());

	const ULONG ulProviders = pdrgpmdp->Size();
	for (ULONG ul = 0; ul < ulProviders; ul++)
	{
		IMDProvider *pmdp = (*pdrgpmdp)[ul];
		pmdp->AddRef();
		RegisterProvider(*((*pdrgpsysid)[ul]), pmdp);
	}
}


//---------------------------------------------------------------------------
//	@function:
//		CMDAccessor::Pmdp
//
//	@doc:
//		Retrieve the MD provider for the given source system id
//
//---------------------------------------------------------------------------
IMDProvider *
CMDAccessor::Pmdp(CSystemId sysid)
{
	SMDProviderElem *pmdpelem = nullptr;

	{
		// scope for HT accessor

		SMDProviderElem mdpelem(sysid, nullptr /*pmdp*/);
		MDPHTAccessor mdhtacc(m_shtProviders, mdpelem);

		pmdpelem = mdhtacc.Find();
	}

	GPOS_ASSERT(nullptr != pmdpelem && "Could not find MD provider");

	return pmdpelem->Pmdp();
}



//---------------------------------------------------------------------------
//	@function:
//		CMDAccessor::GetImdObj
//
//	@doc:
//		Retrieves a metadata cache object from the md cache, possibly retrieving
//		it from the external metadata provider and storing it in the cache first.
//		Main workhorse for retrieving the different types of md cache objects.
//
//---------------------------------------------------------------------------
const IMDCacheObject *
CMDAccessor::GetImdObj(IMDId *mdid)
{
	BOOL fPrintOptStats = GPOS_FTRACE(EopttracePrintOptimizationStatistics);
	CTimerUser timerLookup;	 // timer to measure lookup time
	if (fPrintOptStats)
	{
		timerLookup.Restart();
	}

	const IMDCacheObject *pimdobj = nullptr;

	// first, try to locate object in local hashtable
	{
		// scope for ht accessor
		MDHTAccessor mdhtacc(m_shtCacheAccessors, mdid);
		SMDAccessorElem *pmdaccelem = mdhtacc.Find();
		if (nullptr != pmdaccelem)
		{
			pimdobj = pmdaccelem->GetImdObj();
		}
	}

	if (nullptr == pimdobj)
	{
		// object not in local hashtable, try lookup in the MD cache

		// construct a key for cache lookup
		IMDProvider *pmdp = Pmdp(mdid->Sysid());

		CMDKey mdkey(mdid);

		CAutoP<CacheAccessorMD> a_pmdcacc;
		a_pmdcacc = GPOS_NEW(m_mp) CacheAccessorMD(m_pcache);
		a_pmdcacc->Lookup(&mdkey);
		IMDCacheObject *pmdobjNew = a_pmdcacc->Val();
		if (nullptr == pmdobjNew)
		{
			// object not found in MD cache: retrieve it from MD provider
			CTimerUser timerFetch;
			if (fPrintOptStats)
			{
				timerFetch.Restart();
			}

			// Any object to be inserted into the MD cache must be allocated in the
			// different memory pool, so that it is not destroyed at the end of the
			// query. Since the mdid passed to GetMDObj() may be saved in the object,
			// make a copy of it here in the right memory pool.
			// An exception is made for CTAS (see below).
			CMemoryPool *mp = m_mp;
			IMDId *mdidCopy = mdid;
			if (IMDId::EmdidGPDBCtas != mdid->MdidType())
			{
				// create the accessor memory pool
				mp = a_pmdcacc->Pmp();
				mdidCopy = mdid->Copy(mp);
				GPOS_ASSERT(mdidCopy->Equals(mdid));
			}

			pmdobjNew = pmdp->GetMDObj(mp, this, mdidCopy);
			GPOS_ASSERT(nullptr != pmdobjNew);

			if (fPrintOptStats)
			{
				// add fetch time in msec
				CDouble dFetch(timerFetch.ElapsedUS() /
							   CDouble(GPOS_USEC_IN_MSEC));
				m_dFetchTime = CDouble(m_dFetchTime.Get() + dFetch.Get());
			}

			// For CTAS mdid, we avoid adding the corresponding object to the MD cache
			// since those objects have a fixed id, and if caching is enabled and those
			// objects are cached, then a subsequent CTAS query will attempt to use
			// the cached object, which has a different schema, resulting in a crash.
			// so for such objects, we bypass the MD cache, getting them from the
			// MD provider, directly to the local hash table

			if (IMDId::EmdidGPDBCtas != mdid->MdidType())
			{
				// add to MD cache
				CAutoP<CMDKey> a_pmdkeyCache;
				// ref count of the new object is set to one and optimizer becomes its owner
				a_pmdkeyCache = GPOS_NEW(mp) CMDKey(pmdobjNew->MDId());

				// object gets pinned independent of whether insertion succeeded or
				// failed because object was already in cache

				IMDCacheObject *pmdobjInserted GPOS_ASSERTS_ONLY =
					a_pmdcacc->Insert(a_pmdkeyCache.Value(), pmdobjNew);

				GPOS_ASSERT(nullptr != pmdobjInserted);

				// safely inserted
				(void) a_pmdkeyCache.Reset();
			}
		}

		{
			// store in local hashtable
			GPOS_ASSERT(nullptr != pmdobjNew);
			IMDId *pmdidNew = pmdobjNew->MDId();
			pmdidNew->AddRef();

			CAutoP<SMDAccessorElem> a_pmdaccelem;
			a_pmdaccelem = GPOS_NEW(m_mp) SMDAccessorElem(pmdobjNew, pmdidNew);

			MDHTAccessor mdhtacc(m_shtCacheAccessors, pmdidNew);

			if (nullptr == mdhtacc.Find())
			{
				// object has not been inserted in the meantime
				mdhtacc.Insert(a_pmdaccelem.Value());

				// add deletion lock for mdid
				pmdidNew->AddDeletionLock();
				a_pmdaccelem.Reset();
			}
		}
	}

	// requested object must be in local hashtable already: retrieve it
	MDHTAccessor mdhtacc(m_shtCacheAccessors, mdid);
	SMDAccessorElem *pmdaccelem = mdhtacc.Find();

	GPOS_ASSERT(nullptr != pmdaccelem);

	pimdobj = pmdaccelem->GetImdObj();
	GPOS_ASSERT(nullptr != pimdobj);

	if (fPrintOptStats)
	{
		// add lookup time in msec
		CDouble dLookup(timerLookup.ElapsedUS() / CDouble(GPOS_USEC_IN_MSEC));
		m_dLookupTime = CDouble(m_dLookupTime.Get() + dLookup.Get());
	}

	return pimdobj;
}

//---------------------------------------------------------------------------
//	@function:
//		CMDAccessor::RetrieveRel
//
//	@doc:
//		Retrieves a metadata cache relation from the md cache, possibly retrieving
//		it from the external metadata provider and storing it in the cache first.
//
//---------------------------------------------------------------------------
const IMDRelation *
CMDAccessor::RetrieveRel(IMDId *mdid)
{
	const IMDCacheObject *pmdobj = GetImdObj(mdid);
	if (IMDCacheObject::EmdtRel != pmdobj->MDType())
	{
		GPOS_RAISE(gpdxl::ExmaMD, gpdxl::ExmiMDCacheEntryNotFound,
				   mdid->GetBuffer());
	}

	return dynamic_cast<const IMDRelation *>(pmdobj);
}

//---------------------------------------------------------------------------
//	@function:
//		CMDAccessor::RetrieveType
//
//	@doc:
//		Retrieves the metadata description for a type from the md cache,
//		possibly retrieving it from the external metadata provider and storing
//		it in the cache first.
//
//---------------------------------------------------------------------------
const IMDType *
CMDAccessor::RetrieveType(IMDId *mdid)
{
	const IMDCacheObject *pmdobj = GetImdObj(mdid);
	if (IMDCacheObject::EmdtType != pmdobj->MDType())
	{
		GPOS_RAISE(gpdxl::ExmaMD, gpdxl::ExmiMDCacheEntryNotFound,
				   mdid->GetBuffer());
	}

	return dynamic_cast<const IMDType *>(pmdobj);
}

//---------------------------------------------------------------------------
//	@function:
//		CMDAccessor::RetrieveType
//
//	@doc:
//		Retrieves the MD type from the md cache given the type info and source
//		system id,  possibly retrieving it from the external metadata provider
//		and storing it in the cache first.
//
//---------------------------------------------------------------------------
const IMDType *
CMDAccessor::RetrieveType(CSystemId sysid, IMDType::ETypeInfo type_info)
{
	GPOS_ASSERT(IMDType::EtiGeneric != type_info);
	IMDProvider *pmdp = Pmdp(sysid);
	CAutoRef<IMDId> a_pmdid;
	a_pmdid = pmdp->MDId(m_mp, sysid, type_info);
	const IMDCacheObject *pmdobj = GetImdObj(a_pmdid.Value());
	if (IMDCacheObject::EmdtType != pmdobj->MDType())
	{
		GPOS_RAISE(gpdxl::ExmaMD, gpdxl::ExmiMDCacheEntryNotFound,
				   a_pmdid.Value()->GetBuffer());
	}

	return dynamic_cast<const IMDType *>(pmdobj);
}

//---------------------------------------------------------------------------
//	@function:
//		CMDAccessor::RetrieveType
//
//	@doc:
//		Retrieves the generic MD type from the md cache given the
//		type info,  possibly retrieving it from the external metadata provider
//		and storing it in the cache first.
//
//---------------------------------------------------------------------------
const IMDType *
CMDAccessor::RetrieveType(IMDType::ETypeInfo type_info)
{
	GPOS_ASSERT(IMDType::EtiGeneric != type_info);

	IMDId *mdid = m_pmdpGeneric->MDId(type_info);
	GPOS_ASSERT(nullptr != mdid);
	const IMDCacheObject *pmdobj = GetImdObj(mdid);

	if (IMDCacheObject::EmdtType != pmdobj->MDType())
	{
		GPOS_RAISE(gpdxl::ExmaMD, gpdxl::ExmiMDCacheEntryNotFound,
				   mdid->GetBuffer());
	}

	return dynamic_cast<const IMDType *>(pmdobj);
}

//---------------------------------------------------------------------------
//	@function:
//		CMDAccessor::RetrieveScOp
//
//	@doc:
//		Retrieves the metadata description for a scalar operator from the md cache,
//		possibly retrieving it from the external metadata provider and storing
//		it in the cache first.
//
//---------------------------------------------------------------------------
const IMDScalarOp *
CMDAccessor::RetrieveScOp(IMDId *mdid)
{
	const IMDCacheObject *pmdobj = GetImdObj(mdid);
	if (IMDCacheObject::EmdtOp != pmdobj->MDType())
	{
		GPOS_RAISE(gpdxl::ExmaMD, gpdxl::ExmiMDCacheEntryNotFound,
				   mdid->GetBuffer());
	}

	return dynamic_cast<const IMDScalarOp *>(pmdobj);
}

//---------------------------------------------------------------------------
//	@function:
//		CMDAccessor::RetrieveFunc
//
//	@doc:
//		Retrieves the metadata description for a function from the md cache,
//		possibly retrieving it from the external metadata provider and storing
//		it in the cache first.
//
//---------------------------------------------------------------------------
const IMDFunction *
CMDAccessor::RetrieveFunc(IMDId *mdid)
{
	const IMDCacheObject *pmdobj = GetImdObj(mdid);
	if (IMDCacheObject::EmdtFunc != pmdobj->MDType())
	{
		GPOS_RAISE(gpdxl::ExmaMD, gpdxl::ExmiMDCacheEntryNotFound,
				   mdid->GetBuffer());
	}

	return dynamic_cast<const IMDFunction *>(pmdobj);
}

//---------------------------------------------------------------------------
//	@function:
//		CMDAccessor::FaggWindowFunc
//
//	@doc:
//		Check if the retrieved the window function metadata description from
//		the md cache is an aggregate window function. Internally this function
//		may retrieve it from the external metadata provider and storing
//		it in the cache.
//
//---------------------------------------------------------------------------
BOOL
CMDAccessor::FAggWindowFunc(IMDId *mdid)
{
	const IMDCacheObject *pmdobj = GetImdObj(mdid);

	return (IMDCacheObject::EmdtAgg == pmdobj->MDType());
}

//---------------------------------------------------------------------------
//	@function:
//		CMDAccessor::RetrieveAgg
//
//	@doc:
//		Retrieves the metadata description for an aggregate from the md cache,
//		possibly retrieving it from the external metadata provider and storing
//		it in the cache first.
//
//---------------------------------------------------------------------------
const IMDAggregate *
CMDAccessor::RetrieveAgg(IMDId *mdid)
{
	const IMDCacheObject *pmdobj = GetImdObj(mdid);
	if (IMDCacheObject::EmdtAgg != pmdobj->MDType())
	{
		GPOS_RAISE(gpdxl::ExmaMD, gpdxl::ExmiMDCacheEntryNotFound,
				   mdid->GetBuffer());
	}

	return dynamic_cast<const IMDAggregate *>(pmdobj);
}

//---------------------------------------------------------------------------
//	@function:
//		CMDAccessor::RetrieveTrigger
//
//	@doc:
//		Retrieves the metadata description for a trigger from the md cache,
//		possibly retrieving it from the external metadata provider and storing
//		it in the cache first.
//
//---------------------------------------------------------------------------
const IMDTrigger *
CMDAccessor::RetrieveTrigger(IMDId *mdid)
{
	const IMDCacheObject *pmdobj = GetImdObj(mdid);
	if (IMDCacheObject::EmdtTrigger != pmdobj->MDType())
	{
		GPOS_RAISE(gpdxl::ExmaMD, gpdxl::ExmiMDCacheEntryNotFound,
				   mdid->GetBuffer());
	}

	return dynamic_cast<const IMDTrigger *>(pmdobj);
}

//---------------------------------------------------------------------------
//	@function:
//		CMDAccessor::RetrieveIndex
//
//	@doc:
//		Retrieves the metadata description for an index from the md cache,
//		possibly retrieving it from the external metadata provider and storing
//		it in the cache first.
//
//---------------------------------------------------------------------------
const IMDIndex *
CMDAccessor::RetrieveIndex(IMDId *mdid)
{
	const IMDCacheObject *pmdobj = GetImdObj(mdid);
	if (IMDCacheObject::EmdtInd != pmdobj->MDType())
	{
		GPOS_RAISE(gpdxl::ExmaMD, gpdxl::ExmiMDCacheEntryNotFound,
				   mdid->GetBuffer());
	}

	return dynamic_cast<const IMDIndex *>(pmdobj);
}

//---------------------------------------------------------------------------
//	@function:
//		CMDAccessor::RetrieveCheckConstraints
//
//	@doc:
//		Retrieves the metadata description for a check constraint from the md cache,
//		possibly retrieving it from the external metadata provider and storing
//		it in the cache first.
//
//---------------------------------------------------------------------------
const IMDCheckConstraint *
CMDAccessor::RetrieveCheckConstraints(IMDId *mdid)
{
	const IMDCacheObject *pmdobj = GetImdObj(mdid);
	if (IMDCacheObject::EmdtCheckConstraint != pmdobj->MDType())
	{
		GPOS_RAISE(gpdxl::ExmaMD, gpdxl::ExmiMDCacheEntryNotFound,
				   mdid->GetBuffer());
	}

	return dynamic_cast<const IMDCheckConstraint *>(pmdobj);
}

//---------------------------------------------------------------------------
//	@function:
//		CMDAccessor::Pmdcolstats
//
//	@doc:
//		Retrieves column statistics from the md cache, possibly retrieving it
//		from the external metadata provider and storing it in the cache first.
//
//---------------------------------------------------------------------------
const IMDColStats *
CMDAccessor::Pmdcolstats(IMDId *mdid)
{
	const IMDCacheObject *pmdobj = GetImdObj(mdid);
	if (IMDCacheObject::EmdtColStats != pmdobj->MDType())
	{
		GPOS_RAISE(gpdxl::ExmaMD, gpdxl::ExmiMDCacheEntryNotFound,
				   mdid->GetBuffer());
	}

	return dynamic_cast<const IMDColStats *>(pmdobj);
}

//---------------------------------------------------------------------------
//	@function:
//		CMDAccessor::Pmdrelstats
//
//	@doc:
//		Retrieves relation statistics from the md cache, possibly retrieving it
//		from the external metadata provider and storing it in the cache first.
//
//---------------------------------------------------------------------------
const IMDRelStats *
CMDAccessor::Pmdrelstats(IMDId *mdid)
{
	const IMDCacheObject *pmdobj = GetImdObj(mdid);
	if (IMDCacheObject::EmdtRelStats != pmdobj->MDType())
	{
		GPOS_RAISE(gpdxl::ExmaMD, gpdxl::ExmiMDCacheEntryNotFound,
				   mdid->GetBuffer());
	}

	return dynamic_cast<const IMDRelStats *>(pmdobj);
}

//---------------------------------------------------------------------------
//	@function:
//		CMDAccessor::Pmdcast
//
//	@doc:
//		Retrieve cast object between given source and destination types
//
//---------------------------------------------------------------------------
const IMDCast *
CMDAccessor::Pmdcast(IMDId *mdid_src, IMDId *mdid_dest)
{
	GPOS_ASSERT(nullptr != mdid_src);
	GPOS_ASSERT(nullptr != mdid_dest);

	mdid_src->AddRef();
	mdid_dest->AddRef();

	CAutoP<IMDId> a_pmdidCast;
	a_pmdidCast = GPOS_NEW(m_mp) CMDIdCast(CMDIdGPDB::CastMdid(mdid_src),
										   CMDIdGPDB::CastMdid(mdid_dest));

	const IMDCacheObject *pmdobj = GetImdObj(a_pmdidCast.Value());

	if (IMDCacheObject::EmdtCastFunc != pmdobj->MDType())
	{
		GPOS_RAISE(gpdxl::ExmaMD, gpdxl::ExmiMDCacheEntryNotFound,
				   a_pmdidCast->GetBuffer());
	}
	a_pmdidCast.Reset()->Release();

	return dynamic_cast<const IMDCast *>(pmdobj);
}

//---------------------------------------------------------------------------
//	@function:
//		CMDAccessor::Pmdsccmp
//
//	@doc:
//		Retrieve scalar comparison object between given types
//
//---------------------------------------------------------------------------
const IMDScCmp *
CMDAccessor::Pmdsccmp(IMDId *left_mdid, IMDId *right_mdid,
					  IMDType::ECmpType cmp_type)
{
	GPOS_ASSERT(nullptr != left_mdid);
	GPOS_ASSERT(nullptr != left_mdid);
	GPOS_ASSERT(IMDType::EcmptOther > cmp_type);

	left_mdid->AddRef();
	right_mdid->AddRef();

	CAutoP<IMDId> a_pmdidScCmp;
	a_pmdidScCmp =
		GPOS_NEW(m_mp) CMDIdScCmp(CMDIdGPDB::CastMdid(left_mdid),
								  CMDIdGPDB::CastMdid(right_mdid), cmp_type);

	const IMDCacheObject *pmdobj = GetImdObj(a_pmdidScCmp.Value());

	if (IMDCacheObject::EmdtScCmp != pmdobj->MDType())
	{
		GPOS_RAISE(gpdxl::ExmaMD, gpdxl::ExmiMDCacheEntryNotFound,
				   a_pmdidScCmp->GetBuffer());
	}
	a_pmdidScCmp.Reset()->Release();

	return dynamic_cast<const IMDScCmp *>(pmdobj);
}

//---------------------------------------------------------------------------
//	@function:
//		CMDAccessor::ExtractColumnHistWidth
//
//	@doc:
//		Record histogram and width information for a given column of a table
//
//---------------------------------------------------------------------------
void
CMDAccessor::RecordColumnStats(CMemoryPool *mp, IMDId *rel_mdid, ULONG colid,
							   ULONG ulPos, BOOL isSystemCol, BOOL isEmptyTable,
							   UlongToHistogramMap *col_histogram_mapping,
							   UlongToDoubleMap *colid_width_mapping,
							   CStatisticsConfig *stats_config)
{
	GPOS_ASSERT(nullptr != rel_mdid);
	GPOS_ASSERT(nullptr != col_histogram_mapping);
	GPOS_ASSERT(nullptr != colid_width_mapping);

	// get the column statistics
	const IMDColStats *pmdcolstats = Pmdcolstats(mp, rel_mdid, ulPos);
	GPOS_ASSERT(nullptr != pmdcolstats);

	// fetch the column width and insert it into the hashmap
	CDouble *width = GPOS_NEW(mp) CDouble(pmdcolstats->Width());
	colid_width_mapping->Insert(GPOS_NEW(mp) ULONG(colid), width);

	// extract the the histogram and insert it into the hashmap
	const IMDRelation *pmdrel = RetrieveRel(rel_mdid);
	IMDId *mdid_type = pmdrel->GetMdCol(ulPos)->MdidType();
	CHistogram *histogram = GetHistogram(mp, mdid_type, pmdcolstats);
	GPOS_ASSERT(nullptr != histogram);
	col_histogram_mapping->Insert(GPOS_NEW(mp) ULONG(colid), histogram);

	BOOL fGuc = GPOS_FTRACE(EopttracePrintColsWithMissingStats);
	BOOL fRecordMissingStats = !isEmptyTable && fGuc && !isSystemCol &&
							   (nullptr != stats_config) &&
							   histogram->IsColStatsMissing();
	if (fRecordMissingStats)
	{
		// record the columns with missing (dummy) statistics information
		rel_mdid->AddRef();
		CMDIdColStats *pmdidCol =
			GPOS_NEW(mp) CMDIdColStats(CMDIdGPDB::CastMdid(rel_mdid), ulPos);
		stats_config->AddMissingStatsColumn(pmdidCol);
		pmdidCol->Release();
	}
}


// Return the column statistics meta data object for a given column of a table
const IMDColStats *
CMDAccessor::Pmdcolstats(CMemoryPool *mp, IMDId *rel_mdid, ULONG ulPos)
{
	rel_mdid->AddRef();
	CMDIdColStats *mdid_col_stats =
		GPOS_NEW(mp) CMDIdColStats(CMDIdGPDB::CastMdid(rel_mdid), ulPos);
	const IMDColStats *pmdcolstats = Pmdcolstats(mdid_col_stats);
	mdid_col_stats->Release();

	return pmdcolstats;
}

//---------------------------------------------------------------------------
//	@function:
//		CMDAccessor::Pstats
//
//	@doc:
//		Construct a statistics object for the columns of the given relation
//
//---------------------------------------------------------------------------
IStatistics *
CMDAccessor::Pstats(CMemoryPool *mp, IMDId *rel_mdid, CColRefSet *pcrsHist,
					CColRefSet *pcrsWidth, CStatisticsConfig *stats_config)
{
	GPOS_ASSERT(nullptr != rel_mdid);
	GPOS_ASSERT(nullptr != pcrsHist);
	GPOS_ASSERT(nullptr != pcrsWidth);

	// retrieve MD relation and MD relation stats objects
	rel_mdid->AddRef();
	CMDIdRelStats *rel_stats_mdid =
		GPOS_NEW(mp) CMDIdRelStats(CMDIdGPDB::CastMdid(rel_mdid));
	const IMDRelStats *pmdRelStats = Pmdrelstats(rel_stats_mdid);
	rel_stats_mdid->Release();

	BOOL fEmptyTable = pmdRelStats->IsEmpty();
	const IMDRelation *pmdrel = RetrieveRel(rel_mdid);

	UlongToHistogramMap *col_histogram_mapping =
		GPOS_NEW(mp) UlongToHistogramMap(mp);
	UlongToDoubleMap *colid_width_mapping = GPOS_NEW(mp) UlongToDoubleMap(mp);

	CColRefSetIter crsiHist(*pcrsHist);
	while (crsiHist.Advance())
	{
		CColRef *pcrHist = crsiHist.Pcr();

		// colref must be one of the base table
		CColRefTable *pcrtable = CColRefTable::PcrConvert(pcrHist);

		// extract the column identifier, position of the attribute in the system catalog
		ULONG colid = pcrtable->Id();
		INT attno = pcrtable->AttrNum();
		ULONG ulPos = pmdrel->GetPosFromAttno(attno);

		RecordColumnStats(mp, rel_mdid, colid, ulPos, pcrtable->IsSystemCol(),
						  fEmptyTable, col_histogram_mapping,
						  colid_width_mapping, stats_config);
	}

	// extract column widths
	CColRefSetIter crsiWidth(*pcrsWidth);

	while (crsiWidth.Advance())
	{
		CColRef *pcrWidth = crsiWidth.Pcr();

		// colref must be one of the base table
		CColRefTable *pcrtable = CColRefTable::PcrConvert(pcrWidth);

		// extract the column identifier, position of the attribute in the system catalog
		ULONG colid = pcrtable->Id();
		INT attno = pcrtable->AttrNum();
		ULONG ulPos = pmdrel->GetPosFromAttno(attno);

		CDouble *width = GPOS_NEW(mp) CDouble(pmdrel->ColWidth(ulPos));
		colid_width_mapping->Insert(GPOS_NEW(mp) ULONG(colid), width);
	}

	CDouble rows = std::max(DOUBLE(1.0), pmdRelStats->Rows().Get());

	return GPOS_NEW(mp) CStatistics(
		mp, col_histogram_mapping, colid_width_mapping, rows, fEmptyTable,
		pmdRelStats->RelPages(), pmdRelStats->RelAllVisible(),
		1.0 /* default rebinds */, 0 /* default predicates*/);
}


//---------------------------------------------------------------------------
//	@function:
//		CMDAccessor::GetHistogram
//
//	@doc:
//		Construct a histogram from the given MD column stats object
//
//---------------------------------------------------------------------------
CHistogram *
CMDAccessor::GetHistogram(CMemoryPool *mp, IMDId *mdid_type,
						  const IMDColStats *pmdcolstats)
{
	GPOS_ASSERT(nullptr != mdid_type);
	GPOS_ASSERT(nullptr != pmdcolstats);

	BOOL is_col_stats_missing = pmdcolstats->IsColStatsMissing();
	const ULONG num_of_buckets = pmdcolstats->Buckets();
	BOOL fBoolType = CMDAccessorUtils::FBoolType(this, mdid_type);
	if (is_col_stats_missing && fBoolType)
	{
		GPOS_ASSERT(0 == num_of_buckets);

		return CHistogram::MakeDefaultBoolHistogram(mp);
	}

	CBucketArray *buckets = GPOS_NEW(mp) CBucketArray(mp);
	for (ULONG ul = 0; ul < num_of_buckets; ul++)
	{
		const CDXLBucket *dxl_bucket = pmdcolstats->GetDXLBucketAt(ul);
		CBucket *bucket = Pbucket(mp, mdid_type, dxl_bucket);
		buckets->Append(bucket);
	}

	CDouble null_freq = pmdcolstats->GetNullFreq();
	CDouble distinct_remaining = pmdcolstats->GetDistinctRemain();
	CDouble freq_remaining = pmdcolstats->GetFreqRemain();

	CHistogram *histogram = GPOS_NEW(mp)
		CHistogram(mp, buckets, true /*is_well_defined*/, null_freq,
				   distinct_remaining, freq_remaining, is_col_stats_missing);
	GPOS_ASSERT_IMP(fBoolType,
					3 >= histogram->GetNumDistinct() - CStatistics::Epsilon);

	return histogram;
}

//---------------------------------------------------------------------------
//	@function:
//		CMDAccessor::Pbucket
//
//	@doc:
//		Construct a typed bucket from a DXL bucket
//
//---------------------------------------------------------------------------
CBucket *
CMDAccessor::Pbucket(CMemoryPool *mp, IMDId *mdid_type,
					 const CDXLBucket *dxl_bucket)
{
	IDatum *pdatumLower =
		GetDatum(mp, mdid_type, dxl_bucket->GetDXLDatumLower());
	IDatum *pdatumUpper =
		GetDatum(mp, mdid_type, dxl_bucket->GetDXLDatumUpper());

	CPoint *bucket_lower_bound = GPOS_NEW(mp) CPoint(pdatumLower);
	CPoint *bucket_upper_bound = GPOS_NEW(mp) CPoint(pdatumUpper);

	return GPOS_NEW(mp)
		CBucket(bucket_lower_bound, bucket_upper_bound,
				dxl_bucket->IsLowerClosed(), dxl_bucket->IsUpperClosed(),
				dxl_bucket->GetFrequency(), dxl_bucket->GetNumDistinct());
}

//---------------------------------------------------------------------------
//	@function:
//		CMDAccessor::GetDatum
//
//	@doc:
//		Construct a typed bucket from a DXL bucket
//
//---------------------------------------------------------------------------
IDatum *
CMDAccessor::GetDatum(CMemoryPool *mp, IMDId *mdid_type,
					  const CDXLDatum *dxl_datum)
{
	const IMDType *pmdtype = RetrieveType(mdid_type);

	return pmdtype->GetDatumForDXLDatum(mp, dxl_datum);
}

//---------------------------------------------------------------------------
//	@function:
//		CMDAccessor::Serialize
//
//	@doc:
//		Serialize MD object into provided stream
//
//---------------------------------------------------------------------------
void
CMDAccessor::Serialize(COstream &oos)
{
	ULONG nentries = m_shtCacheAccessors.Size();
	IMDCacheObject **cacheEntries;
	CAutoRg<IMDCacheObject *> aCacheEntries;
	ULONG ul;

	// Iterate the hash table and insert all entries to the array.
	// The iterator holds a lock on the hash table, so we must not
	// do anything non-trivial that might e.g. allocate memory,
	// while iterating.
	cacheEntries = GPOS_NEW_ARRAY(m_mp, IMDCacheObject *, nentries);
	aCacheEntries = cacheEntries;
	{
		MDHTIter mdhtit(m_shtCacheAccessors);
		ul = 0;
		while (mdhtit.Advance())
		{
			MDHTIterAccessor mdhtitacc(mdhtit);
			SMDAccessorElem *pmdaccelem = mdhtitacc.Value();
			GPOS_ASSERT(nullptr != pmdaccelem);
			cacheEntries[ul++] = pmdaccelem->GetImdObj();
		}
		GPOS_ASSERT(ul == nentries);
	}

	// Now that we're done iterating and no longer hold the lock,
	// serialize the entries.
	for (ul = 0; ul < nentries; ul++)
	{
		oos << cacheEntries[ul]->GetStrRepr()->GetBuffer();
	}
}

//---------------------------------------------------------------------------
//	@function:
//		CMDAccessor::SerializeSysid
//
//	@doc:
//		Serialize the system ids into provided stream
//
//---------------------------------------------------------------------------
void
CMDAccessor::SerializeSysid(COstream &oos)
{
	ULONG ul = 0;
	MDPHTIter mdhtit(m_shtProviders);

	while (mdhtit.Advance())
	{
		MDPHTIterAccessor mdhtitacc(mdhtit);
		SMDProviderElem *pmdpelem = mdhtitacc.Value();
		CSystemId sysid = pmdpelem->Sysid();


		WCHAR wszSysId[GPDXL_MDID_LENGTH];
		CWStringStatic str(wszSysId, GPOS_ARRAY_SIZE(wszSysId));

		if (0 < ul)
		{
			str.AppendFormat(GPOS_WSZ_LIT("%s"), ",");
		}

		str.AppendFormat(GPOS_WSZ_LIT("%d.%ls"), sysid.MdidType(),
						 sysid.GetBuffer());

		oos << str.GetBuffer();
		ul++;
	}
}


// EOF

相关信息

greenplumn 源码目录

相关文章

greenplumn CMDAccessorUtils 源码

greenplumn CMDCache 源码

greenplumn CMDKey 源码

0  赞