Пример #1
0
//---------------------------------------------------------------------------
//	@function:
//		CPhysicalPartitionSelector::PpimDerive
//
//	@doc:
//		Derive partition index map
//
//---------------------------------------------------------------------------
CPartIndexMap *
CPhysicalPartitionSelector::PpimDerive
	(
	IMemoryPool *mp,
	CExpressionHandle &exprhdl,
	CDrvdPropCtxt *pdpctxt
	)
	const
{
	GPOS_ASSERT(NULL != pdpctxt);

	CDrvdPropPlan *pdpplan = exprhdl.Pdpplan(0 /*child_index*/);
	CPartIndexMap *ppimInput = pdpplan->Ppim();
	GPOS_ASSERT(NULL != ppimInput);

	ULONG ulExpectedPartitionSelectors = CDrvdPropCtxtPlan::PdpctxtplanConvert(pdpctxt)->UlExpectedPartitionSelectors();

	CPartIndexMap *ppim = ppimInput->PpimPartitionSelector(mp, m_scan_id, ulExpectedPartitionSelectors);
	if (!ppim->Contains(m_scan_id))
	{
		// the consumer of this scan id does not come from the child, i.e. it
		// is on the other side of a join
		MDId()->AddRef();
		m_pdrgpdrgpcr->AddRef();
		m_ppartcnstrmap->AddRef();
		m_part_constraint->AddRef();

		CPartKeysArray *pdrgppartkeys = GPOS_NEW(mp) CPartKeysArray(mp);
		pdrgppartkeys->Append(GPOS_NEW(mp) CPartKeys(m_pdrgpdrgpcr));

		ppim->Insert(m_scan_id, m_ppartcnstrmap, CPartIndexMap::EpimPropagator, 0 /*ulExpectedPropagators*/, MDId(), pdrgppartkeys, m_part_constraint);
	}

	return ppim;
}
Пример #2
0
//---------------------------------------------------------------------------
//	@function:
//		CPhysicalPartitionSelector::EpetDistribution
//
//	@doc:
//		Return the enforcing type for distribution property based on this operator
//
//---------------------------------------------------------------------------
CEnfdProp::EPropEnforcingType
CPhysicalPartitionSelector::EpetDistribution
	(
	CExpressionHandle &exprhdl,
	const CEnfdDistribution *ped
	)
	const
{
	CDrvdPropPlan *pdpplan = exprhdl.Pdpplan(0 /* child_index */);

	if (ped->FCompatible(pdpplan->Pds()))
	{
		// required distribution established by the operator
		return CEnfdProp::EpetUnnecessary;
	}

	CPartIndexMap *ppimDrvd = pdpplan->Ppim();
	if (!ppimDrvd->Contains(m_scan_id))
	{
		// part consumer is defined above: prohibit adding a motion on top of the
		// part resolver as this will create two slices
		return CEnfdProp::EpetProhibited;
	}

	GPOS_ASSERT(CPartIndexMap::EpimConsumer == ppimDrvd->Epim(m_scan_id));

	// part consumer found below: enforce distribution on top of part resolver
	return CEnfdProp::EpetRequired;
}
Пример #3
0
//---------------------------------------------------------------------------
//	@function:
//		CDrvdPropCtxtPlan::PdpctxtCopy
//
//	@doc:
//		Copy function
//
//---------------------------------------------------------------------------
CDrvdPropCtxt *
CDrvdPropCtxtPlan::PdpctxtCopy
(
    IMemoryPool *pmp
)
const
{
    CDrvdPropCtxtPlan *pdpctxtplan = GPOS_NEW(pmp) CDrvdPropCtxtPlan(pmp);
    pdpctxtplan->m_ulExpectedPartitionSelectors = m_ulExpectedPartitionSelectors;

    HMUlPdpIter hmulpdpiter(m_phmulpdpCTEs);
    while (hmulpdpiter.FAdvance())
    {
        ULONG ulId = *(hmulpdpiter.Pk());
        CDrvdPropPlan *pdpplan = const_cast<CDrvdPropPlan *>(hmulpdpiter.Pt());
        pdpplan->AddRef();
#ifdef GPOS_DEBUG
        BOOL fInserted =
#endif // GPOS_DEBUG
            pdpctxtplan->m_phmulpdpCTEs->FInsert(GPOS_NEW(m_pmp) ULONG(ulId), pdpplan);
        GPOS_ASSERT(fInserted);
    }

    return pdpctxtplan;
}
Пример #4
0
//---------------------------------------------------------------------------
//	@function:
//		CCTEReq::PcterUnresolved
//
//	@doc:
//		Unresolved CTE requirements given a derived CTE map
//
//---------------------------------------------------------------------------
CCTEReq *
CCTEReq::PcterUnresolved
	(
	IMemoryPool *pmp,
	CCTEMap *pcm
	)
{
	GPOS_ASSERT(NULL != pcm);
	CCTEReq *pcterUnresolved = GPOS_NEW(pmp) CCTEReq(pmp);

	HMCteReqIter hmcri(m_phmcter);
	while (hmcri.FAdvance())
	{
		// if a cte is marked as required and it is not found in the given map
		// then keep it as required, else make it optional
		const CCTEReqEntry *pcre = hmcri.Pt();
		ULONG ulId = pcre->UlId();
		BOOL fRequired = pcre->FRequired() && CCTEMap::EctSentinel == pcm->Ect(ulId);
		CDrvdPropPlan *pdpplan = pcre->PdpplanProducer();
		if (NULL != pdpplan)
		{
			pdpplan->AddRef();
		}

		pcterUnresolved->Insert(ulId, pcre->Ect(), fRequired, pdpplan);
	}

	return pcterUnresolved;
}
Пример #5
0
//---------------------------------------------------------------------------
//	@function:
//		CDrvdPropCtxtPlan::AddProps
//
//	@doc:
//		Add props to context
//
//---------------------------------------------------------------------------
void
CDrvdPropCtxtPlan::AddProps
(
    CDrvdProp *pdp
)
{
    if (CDrvdProp::EptPlan != pdp->Ept())
    {
        // passed property is not a plan property container
        return;
    }

    CDrvdPropPlan *pdpplan = CDrvdPropPlan::Pdpplan(pdp);

    ULONG ulProducerId = ULONG_MAX;
    CDrvdPropPlan *pdpplanProducer = pdpplan->Pcm()->PdpplanProducer(&ulProducerId);
    if (NULL == pdpplanProducer)
    {
        return;
    }

    if (m_fUpdateCTEMap)
    {
        pdpplanProducer->AddRef();
#ifdef GPOS_DEBUG
        BOOL fInserted =
#endif // GPOS_DEBUG
            m_phmulpdpCTEs->FInsert(GPOS_NEW(m_pmp) ULONG(ulProducerId), pdpplanProducer);
        GPOS_ASSERT(fInserted);
    }
}
Пример #6
0
//---------------------------------------------------------------------------
//	@function:
//		CExpressionHandle::DerivePlanProps
//
//	@doc:
//		Derive the properties of the plan carried by attached cost context
//
//---------------------------------------------------------------------------
void
CExpressionHandle::DerivePlanProps
	(
	CDrvdPropCtxtPlan *pdpctxtplan
	)
{
	GPOS_ASSERT(NULL != m_pcc);
	GPOS_ASSERT(NULL != m_pgexpr);
	GPOS_ASSERT(NULL == m_pdrgpdp);
	GPOS_ASSERT(NULL == m_pdp);
	GPOS_CHECK_ABORT;

	// check if properties have been already derived
	if (NULL != m_pcc->Pdpplan())
	{
		CopyCostCtxtProps();
		return;
	}
	GPOS_ASSERT(NULL != pdpctxtplan);

	// extract children's properties
	m_pdrgpdp = GPOS_NEW(m_pmp) DrgPdp(m_pmp);
	const ULONG ulArity = m_pcc->Pdrgpoc()->UlLength();
	for (ULONG ul = 0; ul < ulArity; ul++)
	{
		COptimizationContext *pocChild = (*m_pcc->Pdrgpoc())[ul];
		CDrvdPropPlan *pdpplan = pocChild->PccBest()->Pdpplan();
		GPOS_ASSERT(NULL != pdpplan);

		pdpplan->AddRef();
		m_pdrgpdp->Append(pdpplan);

		// add child props to derivation context
		CDrvdPropCtxt::AddDerivedProps(pdpplan, pdpctxtplan);
	}

	COperator *pop = m_pgexpr->Pop();
	if (COperator::EopPhysicalCTEConsumer == pop->Eopid())
	{
		// copy producer plan properties to passed derived plan properties context
		ULONG ulCTEId = CPhysicalCTEConsumer::PopConvert(pop)->UlCTEId();
		CDrvdPropPlan *pdpplan = m_pcc->Poc()->Prpp()->Pcter()->Pdpplan(ulCTEId);
		if (NULL != pdpplan)
		{
			pdpctxtplan->CopyCTEProducerProps(pdpplan, ulCTEId);
		}
	}

	// set the number of expected partition selectors in the context
	pdpctxtplan->SetExpectedPartitionSelectors(pop, m_pcc);

	// create/derive local properties
	m_pdp = Pop()->PdpCreate(m_pmp);
	m_pdp->Derive(m_pmp, *this, pdpctxtplan);
}
Пример #7
0
//---------------------------------------------------------------------------
//	@function:
//		CCTEReq::InsertConsumer
//
//	@doc:
//		Insert a new consumer entry. with the given id. The plan properties are
//		taken from the given context
//
//---------------------------------------------------------------------------
void
CCTEReq::InsertConsumer
	(
	ULONG ulId,
	DrgPdp *pdrgpdpCtxt
	)
{
	ULONG ulProducerId = ULONG_MAX;
	CDrvdPropPlan *pdpplan = CDrvdPropPlan::Pdpplan((*pdrgpdpCtxt)[0])->Pcm()->PdpplanProducer(&ulProducerId);
	GPOS_ASSERT(NULL != pdpplan);
	GPOS_ASSERT(ulProducerId == ulId && "unexpected CTE producer plan properties");

	pdpplan->AddRef();
	Insert(ulId, CCTEMap::EctConsumer, true /*fRequired*/, pdpplan);
}
Пример #8
0
//---------------------------------------------------------------------------
//	@function:
//		CDrvdPropPlan::CopyCTEProducerPlanProps
//
//	@doc:
//		Copy CTE producer plan properties from given context to current object
//
//---------------------------------------------------------------------------
void
CDrvdPropPlan::CopyCTEProducerPlanProps
	(
	IMemoryPool *pmp,
	CDrvdPropCtxt *pdpctxt,
	COperator *pop
	)
{
	CDrvdPropCtxtPlan *pdpctxtplan = CDrvdPropCtxtPlan::PdpctxtplanConvert(pdpctxt);
	CPhysicalCTEConsumer *popCTEConsumer = CPhysicalCTEConsumer::PopConvert(pop);
	ULONG ulCTEId = popCTEConsumer->UlCTEId();
	HMUlCr *phmulcr = popCTEConsumer->Phmulcr();
	CDrvdPropPlan *pdpplan = pdpctxtplan->PdpplanCTEProducer(ulCTEId);
	if (NULL != pdpplan)
	{
		// copy producer plan properties after remapping columns
		m_pos = pdpplan->Pos()->PosCopyWithRemappedColumns(pmp, phmulcr, true /*fMustExist*/);
		m_pds = pdpplan->Pds()->PdsCopyWithRemappedColumns(pmp, phmulcr, true /*fMustExist*/);

		// rewindability and partition filter map do not need column remapping,
		// we add-ref producer's properties directly
		pdpplan->Prs()->AddRef();
		m_prs = pdpplan->Prs();

		pdpplan->Ppfm()->AddRef();
		m_ppfm = pdpplan->Ppfm();

		// no need to copy the part index map. return an empty one. This is to
		// distinguish between a CTE consumer and the inlined expression
		m_ppim = GPOS_NEW(pmp) CPartIndexMap(pmp);

		GPOS_ASSERT(CDistributionSpec::EdtAny != m_pds->Edt() && "CDistributionAny is a require-only, cannot be derived");
	}
}
Пример #9
0
//---------------------------------------------------------------------------
//	@function:
//		CPhysical::FChildrenHaveCompatibleDistributions
//
//	@doc:
//		Returns true iff the delivered distributions of the children are
//		compatible among themselves.
//
//---------------------------------------------------------------------------
BOOL
CPhysical::FCompatibleChildrenDistributions
	(
	const CExpressionHandle &exprhdl
	)
	const
{
	GPOS_ASSERT(exprhdl.Pop() == this);
	BOOL fSingletonOrUniversalChild = false;
	BOOL fNotSingletonOrUniversalDistributedChild = false;
	const ULONG arity = exprhdl.Arity();
	for (ULONG ul = 0; ul < arity; ul++)
	{
		if (!exprhdl.FScalarChild(ul))
		{
			CDrvdPropPlan *pdpplanChild = exprhdl.Pdpplan(ul);

			// an operator cannot have a singleton or universal distributed child
			// and one distributed on multiple nodes
			// this assumption is safe for all current operators, but it can be
			// too conservative: we could allow for instance the following cases
			// * LeftOuterJoin (universal, distributed)
			// * AntiSemiJoin  (universal, distributed)
			// These cases can be enabled if considered necessary by overriding
			// this function.
			if (CDistributionSpec::EdtUniversal == pdpplanChild->Pds()->Edt() ||
				pdpplanChild->Pds()->FSingletonOrStrictSingleton())
			{
				fSingletonOrUniversalChild = true;
			}
			else
			{
				fNotSingletonOrUniversalDistributedChild = true;
			}
			if (fSingletonOrUniversalChild && fNotSingletonOrUniversalDistributedChild)
			{

				return false;
			}
		}
	}

	return true;
}
Пример #10
0
//---------------------------------------------------------------------------
//	@function:
//		CPhysicalMotion::FValidContext
//
//	@doc:
//		Check if optimization context is valid
//
//---------------------------------------------------------------------------
BOOL
CPhysicalMotion::FValidContext
	(
	IMemoryPool *pmp,
	COptimizationContext *poc,
	DrgPoc *pdrgpocChild
	)
	const
{
	GPOS_ASSERT(NULL != pdrgpocChild);
	GPOS_ASSERT(1 == pdrgpocChild->UlLength());

	COptimizationContext *pocChild = (*pdrgpocChild)[0];
	CCostContext *pccBest = pocChild->PccBest();
	GPOS_ASSERT(NULL != pccBest);

	CDrvdPropPlan *pdpplanChild = pccBest->Pdpplan();
	if (pdpplanChild->Ppim()->FContainsUnresolved())
	{
		return false;
	}

	CExpressionHandle exprhdl(pmp);
	exprhdl.Attach(pccBest);
	exprhdl.DeriveProps(NULL /*CDrvdPropCtxt*/);
	if (exprhdl.FHasOuterRefs())
	{
		// disallow plans with outer references below motion operator
		return false;
	}

	CEnfdDistribution *ped = poc->Prpp()->Ped();
	if (ped->FCompatible(this->Pds()) && ped->FCompatible(pdpplanChild->Pds()))
	{
		// required distribution is compatible with the distribution delivered by Motion and its child plan,
		// in this case, Motion is redundant since child plan delivers the required distribution
		return false;
	}

	return true;
}
Пример #11
0
//---------------------------------------------------------------------------
//	@function:
//		CCTEReq::PcterAllOptional
//
//	@doc:
//		Create a copy of the current requirement where all the entries are marked optional
//
//---------------------------------------------------------------------------
CCTEReq *
CCTEReq::PcterAllOptional
	(
	IMemoryPool *pmp
	)
{
	CCTEReq *pcter = GPOS_NEW(pmp) CCTEReq(pmp);

	HMCteReqIter hmcri(m_phmcter);
	while (hmcri.FAdvance())
	{
		const CCTEReqEntry *pcre = hmcri.Pt();
		CDrvdPropPlan *pdpplan = pcre->PdpplanProducer();
		if (NULL != pdpplan)
		{
			pdpplan->AddRef();
		}
		pcter->Insert(pcre->UlId(), pcre->Ect(), false /*fRequired*/, pdpplan);
	}

	return pcter;
}
Пример #12
0
//---------------------------------------------------------------------------
//	@function:
//		CCostContext::DerivePlanProps
//
//	@doc:
//		Derive properties of the plan carried by cost context
//
//---------------------------------------------------------------------------
void
CCostContext::DerivePlanProps
	(
	IMemoryPool *pmp
	)
{
	GPOS_ASSERT(NULL != m_pdrgpoc);

	if (NULL == m_pdpplan)
	{
		// derive properties of the plan carried by cost context
		CExpressionHandle exprhdl(pmp);
		exprhdl.Attach(this);
		exprhdl.DerivePlanProps();
		CDrvdPropPlan *pdpplan = CDrvdPropPlan::Pdpplan(exprhdl.Pdp());
		GPOS_ASSERT(NULL != pdpplan);

		// set derived plan properties
		pdpplan->AddRef();
		m_pdpplan = pdpplan;
		GPOS_ASSERT(NULL != m_pdpplan);
	}
}
Пример #13
0
//---------------------------------------------------------------------------
//	@function:
//		CCTEReq::PcterUnresolvedSequence
//
//	@doc:
//		Unresolved CTE requirements given a derived CTE map for a sequence
//		operator
//
//---------------------------------------------------------------------------
CCTEReq *
CCTEReq::PcterUnresolvedSequence
	(
	IMemoryPool *pmp,
	CCTEMap *pcm,
	DrgPdp *pdrgpdpCtxt // context contains derived plan properties of producer tree
	)
{
	GPOS_ASSERT(NULL != pcm);
	CCTEReq *pcterUnresolved = GPOS_NEW(pmp) CCTEReq(pmp);

	HMCteReqIter hmcri(m_phmcter);
	while (hmcri.FAdvance())
	{
		const CCTEReqEntry *pcre = hmcri.Pt();

		ULONG ulId = pcre->UlId();
		CCTEMap::ECteType ect = pcre->Ect();
		BOOL fRequired = pcre->FRequired();

		CCTEMap::ECteType ectDrvd = pcm->Ect(ulId);
		if (fRequired && CCTEMap::EctSentinel != ectDrvd)
		{
			GPOS_ASSERT(CCTEMap::EctConsumer == ect);
			GPOS_ASSERT(CCTEMap::EctConsumer == ectDrvd);
			// already found, so mark it as optional
			CDrvdPropPlan *pdpplan = pcre->PdpplanProducer();
			GPOS_ASSERT(NULL != pdpplan);
			pdpplan->AddRef();
			pcterUnresolved->Insert(ulId, ect, false /*fReqiored*/, pdpplan);
		}
		else if (!fRequired && CCTEMap::EctProducer == ect && CCTEMap::EctSentinel != ectDrvd)
		{
			GPOS_ASSERT(CCTEMap::EctProducer == ectDrvd);

			// found a producer. require the corresponding consumer and
			// extract producer plan properties from passed context
			pcterUnresolved->InsertConsumer(ulId, pdrgpdpCtxt);
		}
		else
		{
			// either required and not found yet, or optional
			// in both cases, pass it down as is
			CDrvdPropPlan *pdpplan = pcre->PdpplanProducer();
			GPOS_ASSERT_IMP(NULL == pdpplan, CCTEMap::EctProducer == ect);
			if (NULL != pdpplan)
			{
				pdpplan->AddRef();
			}
			pcterUnresolved->Insert(ulId, ect, fRequired, pdpplan);
		}
	}

	// if something is in pcm and not in the requirments, it has to be a producer
	// in which case, add the corresponding consumer as unresolved
	DrgPul *pdrgpulProducers = pcm->PdrgpulAdditionalProducers(pmp, this);
	const ULONG ulLen = pdrgpulProducers->UlLength();
	for (ULONG ul = 0; ul < ulLen; ul++)
	{
		ULONG *pulId = (*pdrgpulProducers)[ul];
		pcterUnresolved->InsertConsumer(*pulId, pdrgpdpCtxt);
	}
	pdrgpulProducers->Release();

	return pcterUnresolved;
}
Пример #14
0
BOOL
CPhysicalSpool::FValidContext
	(
	IMemoryPool *,
	COptimizationContext *poc,
	COptimizationContextArray *pdrgpocChild
	)
	const
{
	GPOS_ASSERT(NULL != pdrgpocChild);
	GPOS_ASSERT(1 == pdrgpocChild->Size());

	COptimizationContext *pocChild = (*pdrgpocChild)[0];
	CCostContext *pccBest = pocChild->PccBest();
	GPOS_ASSERT(NULL != pccBest);

	// partition selections that happen outside of a physical spool does not do
	// any good on rescan: a physical spool blocks the rescan from the entire
	// subtree (in particular, any dynamic scan) underneath it. That means when
	// we have a dynamic scan under a spool, and a corresponding partition
	// selector outside the spool, we run the risk of materializing the wrong
	// results.

	// For example, the following plan is invalid because the partition selector
	// won't be able to influence inner side of the nested loop join as intended
	// ("blocked" by the spool):

	// +--CPhysicalMotionGather(master)
	//    +--CPhysicalInnerNLJoin
	//       |--CPhysicalPartitionSelector
	//       |  +--CPhysicalMotionBroadcast
	//       |     +--CPhysicalTableScan "foo" ("foo")
	//       |--CPhysicalSpool
	//       |  +--CPhysicalLeftOuterHashJoin
	//       |     |--CPhysicalDynamicTableScan "pt" ("pt")
	//       |     |--CPhysicalMotionHashDistribute
	//       |     |  +--CPhysicalTableScan "bar" ("bar")
	//       |     +--CScalarCmp (=)
	//       |        |--CScalarIdent "d" (19)
	//       |        +--CScalarIdent "dk" (9)
	//       +--CScalarCmp (<)
	//          |--CScalarIdent "a" (0)
	//          +--CScalarIdent "partkey" (10)

	CDrvdPropPlan *pdpplanChild = pccBest->Pdpplan();
	if (pdpplanChild->Ppim()->FContainsUnresolved())
	{
		return false;
	}

	// Discard any context that is requesting for rewindability with motion hazard handling and
	// the physical spool is streaming with a motion underneath it.
	// We do not want to add a blocking spool over a spool as spooling twice will be expensive,
	// hence invalidate this context.
	CEnfdRewindability *per = poc->Prpp()->Per();
	if(per->PrsRequired()->HasMotionHazard() &&
	   pdpplanChild->Prs()->HasMotionHazard())
	{
		return FEager();
	}

	return true;
}
Пример #15
0
//---------------------------------------------------------------------------
//	@function:
//		CPhysicalSequence::PdsRequired
//
//	@doc:
//		Compute required distribution of the n-th child
//
//---------------------------------------------------------------------------
CDistributionSpec *
CPhysicalSequence::PdsRequired
	(
	IMemoryPool *pmp,
	CExpressionHandle &
#ifdef GPOS_DEBUG
	exprhdl
#endif // GPOS_DEBUG
	,
	CDistributionSpec *pdsRequired,
	ULONG  ulChildIndex,
	DrgPdp *pdrgpdpCtxt,
	ULONG  ulOptReq
	)
	const
{
	GPOS_ASSERT(2 == exprhdl.UlArity());
	GPOS_ASSERT(ulChildIndex < exprhdl.UlArity());
	GPOS_ASSERT(ulOptReq < UlDistrRequests());

	if (0 == ulOptReq)
	{
		if (CDistributionSpec::EdtSingleton == pdsRequired->Edt() ||
			CDistributionSpec::EdtStrictSingleton == pdsRequired->Edt())
		{
			// incoming request is a singleton, request singleton on all children
			CDistributionSpecSingleton *pdss = CDistributionSpecSingleton::PdssConvert(pdsRequired);
			return GPOS_NEW(pmp) CDistributionSpecSingleton(pdss->Est());
		}

		// incoming request is a non-singleton, request non-singleton on all children
		return GPOS_NEW(pmp) CDistributionSpecNonSingleton();
	}
	GPOS_ASSERT(1 == ulOptReq);

	if (0 == ulChildIndex)
	{
		// no distribution requirement on first child
		return GPOS_NEW(pmp) CDistributionSpecAny(this->Eopid());
	}

	// get derived plan properties of first child
	CDrvdPropPlan *pdpplan = CDrvdPropPlan::Pdpplan((*pdrgpdpCtxt)[0]);
	CDistributionSpec *pds = pdpplan->Pds();

	if (pds->FSingletonOrStrictSingleton())
	{
		// first child is singleton, request singleton distribution on second child
		CDistributionSpecSingleton *pdss = CDistributionSpecSingleton::PdssConvert(pds);
		return GPOS_NEW(pmp) CDistributionSpecSingleton(pdss->Est());
	}

	if (CDistributionSpec::EdtUniversal == pds->Edt())
	{
		// first child is universal, impose no requirements on second child
		return GPOS_NEW(pmp) CDistributionSpecAny(this->Eopid());
	}

	// first child is non-singleton, request a non-singleton distribution on second child
	return GPOS_NEW(pmp) CDistributionSpecNonSingleton();
}