greenplumn CTreeMapTest 代码
文件路径:/src/backend/gporca/server/src/unittest/gpopt/search/CTreeMapTest.cpp
/---------------------------------------------------------------------------
/ Greenplum Database
/ Copyright (C) 2011 EMC Corp.
/
/ @filename:
/ CTreeMapTest.cpp
/
/ @doc:
/ Test of tree map facility
/---------------------------------------------------------------------------
#include "unittest/gpopt/search/CTreeMapTest.h"
#include "gpos/error/CAutoTrace.h"
#include "gpos/io/COstreamString.h"
#include "gpos/string/CWStringDynamic.h"
#include "gpos/task/CAutoTraceFlag.h"
#include "gpos/task/CTask.h"
#include "gpos/types.h"
#include "gpopt/base/CDrvdPropCtxtPlan.h"
#include "gpopt/engine/CEngine.h"
#include "gpopt/eval/CConstExprEvaluatorDefault.h"
#include "gpopt/exception.h"
#include "gpopt/operators/CLogicalInnerJoin.h"
#include "unittest/base.h"
#include "unittest/gpopt/CTestUtils.h"
ULONG CTreeMapTest::m_ulTestCounter = 0; / start from first test
/---------------------------------------------------------------------------
/ raw data for test
/---------------------------------------------------------------------------
const ULONG ulElems = 10;
static ULONG rgul[ulElems];
/---------------------------------------------------------------------------
/ @function:
/ CTreeMapTest::EresUnittest
/
/ @doc:
/ Unittest for state machine
/
/---------------------------------------------------------------------------
GPOS_RESULT
CTreeMapTest::EresUnittest()
{
CUnittest rgut[] = {
GPOS_UNITTEST_FUNC(CTreeMapTest::EresUnittest_Basic),
GPOS_UNITTEST_FUNC(CTreeMapTest::EresUnittest_Count),
GPOS_UNITTEST_FUNC(CTreeMapTest::EresUnittest_Unrank),
GPOS_UNITTEST_FUNC(CTreeMapTest::EresUnittest_Memo),
#ifdef GPOS_DEBUG
GPOS_UNITTEST_FUNC_ASSERT(CTreeMapTest::EresUnittest_Cycle),
#endif / GPOS_DEBUG
};
return CUnittest::EresExecute(rgut, GPOS_ARRAY_SIZE(rgut));
}
/---------------------------------------------------------------------------
/ @function:
/ CTreeMapTest::CNode::OsPrint
/
/ @doc:
/ Debug print function
/
/---------------------------------------------------------------------------
IOstream &
CTreeMapTest::CNode::OsPrintWithIndent(IOstream &os, ULONG ulIndent) const
{
for (ULONG ul = 0; ul < ulIndent; ul++)
{
os << " ";
}
os << "node: " << m_ulData << std::endl;
for (ULONG ulChild = 0; ulChild < m_pdrgpnd->Size(); ulChild++)
{
(void) (*m_pdrgpnd)[ulChild]->OsPrintWithIndent(os, ulIndent + 2);
}
return os;
}
/---------------------------------------------------------------------------
/ @function:
/ CTreeMapTest::CNode::CNode
/
/ @doc:
/ ctor
/
/---------------------------------------------------------------------------
CTreeMapTest::CNode::CNode(CMemoryPool *, / mp
const ULONG *pulData, CNodeArray *pdrgpnd)
: m_ulData(gpos::ulong_max), m_pdrgpnd(pdrgpnd)
{
if (nullptr != pulData)
{
m_ulData = *pulData;
}
}
/---------------------------------------------------------------------------
/ @function:
/ CTreeMapTest::CNode::~CNode
/
/ @doc:
/ ctor
/
/---------------------------------------------------------------------------
CTreeMapTest::CNode::~CNode()
{
CRefCount::SafeRelease(m_pdrgpnd);
}
/---------------------------------------------------------------------------
/ @function:
/ CTreeMapTest::Pnd
/
/ @doc:
/ Constructor function for result tree
/
/---------------------------------------------------------------------------
CTreeMapTest::CNode *
CTreeMapTest::Pnd(CMemoryPool *mp, ULONG *pul, CNodeArray *pdrgpnd,
BOOL *fTestTrue)
{
/ The test passes 'true' to PrUnrank and the rehydrate function expects to find it here.
GPOS_ASSERT(nullptr != fTestTrue);
GPOS_ASSERT(*fTestTrue && "Flag is expected to be true");
*fTestTrue = true;
return GPOS_NEW(mp) CNode(mp, pul, pdrgpnd);
}
/---------------------------------------------------------------------------
/ @function:
/ CTreeMapTest::PtmapLoad
/
/ @doc:
/ Create a semantically meaningful tree map by simulating a MEMO
/ layout
/
/---------------------------------------------------------------------------
CTreeMapTest::TestMap *
CTreeMapTest::PtmapLoad(CMemoryPool *mp)
{
TestMap *ptmap = GPOS_NEW(mp) TestMap(mp, &Pnd);
/ init raw data
for (ULONG pos = 0; pos < ulElems; pos++)
{
rgul[pos] = pos;
}
/ simulate the following MEMO with individual edge insertions
struct SEdge
{
/ number of parent node
ULONG m_ulParent;
/ position of child
ULONG m_ulPos;
/ number of child node
ULONG m_ulChild;
} rgedge[] = {
/ root group: Join [4,3], HashJoin[4,3]{8}, HashJoin[3,4]{9}
{9, 1, 7},
{9, 0, 6},
{9, 0, 5},
{8, 0, 7},
{8, 1, 5},
{8, 1, 6},
/ group 4: C, TabScan{7}
/ group 3: Join[1,2], HashJoin[1,2]{5}, SortMergeJoin[1,2]{6}
{5, 0, 0},
{5, 0, 1},
{5, 1, 2},
{5, 1, 3},
{5, 1, 4},
{6, 0, 1},
{6, 1, 3},
{6, 1, 4},
/ group 2: B, TabScan{2}, IndexScan{3}, Sort[2]{4}
{4, 0, 2}
/ group 1: A, TabScan{0}, IndexScan{1}
};
for (ULONG ul = 0; ul < GPOS_ARRAY_SIZE(rgedge); ul++)
{
SEdge &edge = rgedge[ul];
ptmap->Insert(&rgul[edge.m_ulParent], edge.m_ulPos,
&rgul[edge.m_ulChild]);
}
return ptmap;
}
/---------------------------------------------------------------------------
/ @function:
/ CTreeMapTest::EresUnittest_Basic
/
/ @doc:
/ Basic test
/
/---------------------------------------------------------------------------
GPOS_RESULT
CTreeMapTest::EresUnittest_Basic()
{
CAutoMemoryPool amp;
CMemoryPool *mp = amp.Pmp();
TestMap *ptmap = nullptr;
/ create blank map
ptmap = GPOS_NEW(mp) TestMap(mp, &Pnd);
GPOS_ASSERT(0 == ptmap->UllCount());
GPOS_DELETE(ptmap);
/ create map with test data
ptmap = PtmapLoad(mp);
GPOS_DELETE(ptmap);
return GPOS_OK;
}
/---------------------------------------------------------------------------
/ @function:
/ CTreeMapTest::EresUnittest_Count
/
/ @doc:
/ Count and debug output of all counts at various nodes
/
/---------------------------------------------------------------------------
GPOS_RESULT
CTreeMapTest::EresUnittest_Count()
{
CAutoMemoryPool amp;
CMemoryPool *mp = amp.Pmp();
TestMap *ptmap = PtmapLoad(mp);
/ debug print
CWStringDynamic str(mp);
COstreamString oss(&str);
ULLONG ullCount = ptmap->UllCount();
oss << "total number of trees: " << ullCount << std::endl;
#ifdef GPOS_DEBUG
for (ULONG ul = 0; ul < ulElems; ul++)
{
oss << "node: " << ul << " count: " << ptmap->UllCount(&rgul[ul])
<< std::endl;
}
(void) ptmap->OsPrint(oss);
#endif / GPOS_DEBUG
GPOS_TRACE(str.GetBuffer());
GPOS_DELETE(ptmap);
return GPOS_OK;
}
/---------------------------------------------------------------------------
/ @function:
/ CTreeMapTest::EresUnittest_Unrank
/
/ @doc:
/ Rehydrate all trees encoded in the map
/
/---------------------------------------------------------------------------
GPOS_RESULT
CTreeMapTest::EresUnittest_Unrank()
{
CAutoMemoryPool amp;
CMemoryPool *mp = amp.Pmp();
TestMap *ptmap = PtmapLoad(mp);
/ debug print
CWStringDynamic str(mp);
COstreamString oss(&str);
ULLONG ullCount = ptmap->UllCount();
for (ULONG ulRank = 0; ulRank < ullCount; ulRank++)
{
oss << "=== tree rank: " << ulRank << " ===" << std::endl;
BOOL fFlag = true;
CNode *pnd = ptmap->PrUnrank(mp, &fFlag, ulRank);
pnd->Release();
}
GPOS_TRACE(str.GetBuffer());
GPOS_DELETE(ptmap);
return GPOS_OK;
}
/---------------------------------------------------------------------------
/ @function:
/ CTreeMapTest::EresUnittest_Memo
/
/ @doc:
/ Test loading map from actual memo
/
/---------------------------------------------------------------------------
GPOS_RESULT
CTreeMapTest::EresUnittest_Memo()
{
GPOS_SET_TRACE(EtraceDisablePrintMemoryLeak);
CAutoMemoryPool amp;
CMemoryPool *mp = amp.Pmp();
/ setup a file-based provider
CMDProviderMemory *pmdp = CTestUtils::m_pmdpf;
pmdp->AddRef();
CMDAccessor mda(mp, CMDCache::Pcache(), CTestUtils::m_sysidDefault, pmdp);
CEngine *peng = nullptr;
CExpression *pexpr = nullptr;
CQueryContext *pqc = nullptr;
CExpression *pexprPlan = nullptr;
{
/ install opt context in TLS
CAutoOptCtxt aoc(mp, &mda, nullptr, /* pceeval */
CTestUtils::GetCostModel(mp));
CAutoTraceFlag atf(EopttraceEnumeratePlans, true);
peng = GPOS_NEW(mp) CEngine(mp);
/ generate join expression
pexpr = CTestUtils::PexprLogicalJoin<CLogicalInnerJoin>(mp);
/ generate query context
pqc = CTestUtils::PqcGenerate(mp, pexpr);
/ Initialize engine
peng->Init(pqc, nullptr /*search_stage_array*/);
/ optimize query
peng->Optimize();
/ extract plan
pexprPlan = peng->PexprExtractPlan();
GPOS_ASSERT(nullptr != pexprPlan);
peng->Trace();
{
CAutoTrace at(mp);
ULLONG ullCount = peng->Pmemotmap()->UllCount();
#ifdef GPOS_DEBUG
/ test resetting map and re-creating it
peng->ResetTreeMap();
ULLONG ullCount2 = peng->Pmemotmap()->UllCount();
GPOS_ASSERT(ullCount == ullCount2);
#endif / GPOS_DEBUG
for (ULONG ulRank = 0; ulRank < ullCount; ulRank++)
{
CDrvdPropCtxtPlan *pdpctxtplan =
GPOS_NEW(mp) CDrvdPropCtxtPlan(mp, false /*fUpdateCTEMap*/);
CExpression *pexprAlt = nullptr;
GPOS_TRY
{
pexprAlt =
peng->Pmemotmap()->PrUnrank(mp, pdpctxtplan, ulRank);
at.Os() << std::endl
<< "ALTERNATIVE [" << ulRank << "]:" << std::endl
<< *pexprAlt << std::endl;
}
GPOS_CATCH_EX(ex)
{
if (!GPOS_MATCH_EX(
ex, gpopt::ExmaGPOPT,
gpopt::ExmiUnsatisfiedRequiredProperties))
{
GPOS_RETHROW(ex);
}
IErrorContext *perrctxt = CTask::Self()->GetErrCtxt();
at.Os() << perrctxt->GetErrorMsg() << std::endl;
GPOS_RESET_EX;
}
GPOS_CATCH_END;
CRefCount::SafeRelease(pexprAlt);
CRefCount::SafeRelease(pdpctxtplan);
}
}
}
/ clean up
CRefCount::SafeRelease(pexprPlan);
GPOS_DELETE(pqc);
CRefCount::SafeRelease(pexpr);
GPOS_DELETE(peng);
return GPOS_OK;
}
#ifdef GPOS_DEBUG
/---------------------------------------------------------------------------
/ @function:
/ CTreeMapTest::EresUnittest_Cycle
/
/ @doc:
/ Introduce cycle in graph; counting must assert
/
/---------------------------------------------------------------------------
GPOS_RESULT
CTreeMapTest::EresUnittest_Cycle()
{
CAutoMemoryPool amp;
CMemoryPool *mp = amp.Pmp();
TestMap *ptmap = GPOS_NEW(mp) TestMap(mp, &Pnd);
CAutoP<TestMap> a_ptmap;
a_ptmap = ptmap;
/ build cycle
ptmap->Insert(&rgul[0], 0, &rgul[1]);
ptmap->Insert(&rgul[1], 0, &rgul[2]);
ptmap->Insert(&rgul[2], 0, &rgul[1]);
(void) ptmap->UllCount();
return GPOS_FAILED;
}
#endif / GPOS_FAILED
/ EOF