blob: c1b0c6169344841c72af0cdd26adc3bcab828814 [file] [log] [blame]
/**********************************************************************
// @@@ START COPYRIGHT @@@
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//
// @@@ END COPYRIGHT @@@
//
**********************************************************************/
/* -*-C++-*-
******************************************************************************
*
* File: RuCache.cpp
* Description: Implementation of class CRUCache.
*
*
* Created: 02/27/2000
* Language: C++
*
*
*
******************************************************************************
*/
#include "dsutilitywa.h"
#include "ddschema.h"
#include "ddtable.h"
#include "ddMVGroup.h"
#include "dddefaults.h"
#include "ddattribute.h"
#include "uofsSystem.h"
#include "uofsProcessPool.h"
#include "RuCache.h"
#include "RuException.h"
#include "RuGlobals.h"
#include "RuForceOptionsParser.h"
//--------------------------------------------------------------------------//
// PUBLIC METHODS
//--------------------------------------------------------------------------//
//--------------------------------------------------------------------------//
// CRUCache constructor and destructor
//--------------------------------------------------------------------------//
CRUCache::CRUCache() :
sqlNode_(FALSE), // Do not let DDOL control the txns
mvList_(), // Items are owned
tableList_(), // Items are owned
ddlLockHandler_(),
isCancelOnly_(FALSE),
isTotalRecompute_(FALSE),
lcType_(CRUOptions::DONTCARE_LC),
currentUser_(""),
maxParallelism_(1),
maxPipelining_(1)
{}
CRUCache::~CRUCache()
{
// Normally, all of the DDOL MV/table objects are in
// the eClosed state at this point. However,
// if the destructor is called from inside an exception
// handler when some DDOL object is left in the eModified
// state, the utility should not attempt to save the object
// to the catalog.
DSListPosition pos = mvList_.GetHeadPosition();
while (NULL != pos)
{
CRUMV *pMV = mvList_.GetNext(pos);
pMV->CancelChanges();
}
pos = tableList_.GetHeadPosition();
while (NULL != pos)
{
CRUTbl *pTbl = tableList_.GetNext(pos);
pTbl->CancelChanges();
}
// Since sqlNode_ is an object (not a pointer),
// its destructor is called automatically,
// therefore disposing the cloud of DD objects.
// Since mvList_ and tableList_ *own* the referenced objects,
// there is no need to apply the RemoveAll() method to them.
}
//--------------------------------------------------------------------------//
// Lookup methods
//--------------------------------------------------------------------------//
//--------------------------------------------------------------------------//
// CRUCache::GetMV()
//--------------------------------------------------------------------------//
CRUMV *CRUCache::GetMV(TInt64 objUid) const
{
DSListPosition pos = mvList_.GetHeadPosition();
while (NULL != pos)
{
CRUMV *pMV = mvList_.GetNext(pos);
if (pMV->GetUID() == objUid)
{
return pMV;
}
}
return NULL;
}
//--------------------------------------------------------------------------//
// CRUCache::GetTable()
//--------------------------------------------------------------------------//
CRUTbl *CRUCache::GetTable(TInt64 objUid) const
{
DSListPosition pos = tableList_.GetHeadPosition();
while (NULL != pos)
{
CRUTbl *pTbl = tableList_.GetNext(pos);
if (pTbl->GetUID() == objUid)
{
return pTbl;
}
}
return NULL;
}
//--------------------------------------------------------------------------//
// CRUCache::Build()
//
// Populate the MV list and the table (used object) list.
// The objects are classified as follows:
//
// (1) Involved MVs - the MVs that should be refreshed by the current
// invocation of the utility.
// (2) Non-involved MVs - the ON REQUEST MVs that use the involved
// tables, but are not being refreshed themselves (used by the
// log cleanup logic).
//
// (3) Involved used objects - objects that are directly used
// by the involved MVs.
// (4) Non-involved used objects - a CRUTbl interface for every
// involved ON REQUEST MV that is not used by the other involved
// MVs.
//
//--------------------------------------------------------------------------//
void CRUCache::Build()
{
InitBuild();
// Fill the cache by involved MVs
FetchInvolvedMVsMetadata();
if (FALSE == isCancelOnly_)
{
// Check that there is at least one log to clean,
// if the user requested log cleanup.
CheckLogCleanupApplicability();
}
// Fill the cache by involved tables, setup the usage lists
FetchInvolvedUsedObjectsMetadata();
// For every involved MV, decide whether it will be recomputed now.
// Consider to perform popindex/purgedata
if (FALSE == isCancelOnly_)
{
SetupRecomputeProperty();
}
// Cancel/Aquire/Replace the DDL locks ...
ddlLockHandler_.HandleDDLLocks(isCancelOnly_);
if (TRUE == isCancelOnly_)
{
// Short path - the utility was applied with the CANCEL option.
// The DDL locks were cancelled after fetching the involved objects
return;
}
// Read the MV_REFRESH_MAX_PIPELINING
// and MV_REFRESH_MAX_PARALLELISM defaults
FetchDefaults();
// Add the non-involved MVs to the cache
FetchNonInvolvedMVsMetadata();
if (CRUOptions::DO_ONLY_LC == lcType_)
{
// Nothing more is required for DO ONLY LOG CLEANUP
return;
}
// Complete the job for the "real" run!
FetchNonInvolvedUsedObjectsMetadata();
// For each involved MV, setup the cross-pointers
// between the CRUMV and CRUTbl objects corresponding to it.
FixupMVTblInterfaces();
if (FALSE == CRUGlobals::GetInstance()->GetOptions().GetForceFilename().IsEmpty())
{
FetchForceData();
}
}
#ifdef _DEBUG
//--------------------------------------------------------------------------//
// CRUCache::Dump()
//--------------------------------------------------------------------------//
void CRUCache::Dump(CDSString &to, BOOL isExtended) const
{
to += "\n\t\tCACHE DUMP\n";
DSListPosition pos = mvList_.GetHeadPosition();
while (NULL != pos)
{
CRUMV *pMV = mvList_.GetNext(pos);
pMV->Dump(to, isExtended);
}
pos = tableList_.GetHeadPosition();
while (NULL != pos)
{
CRUTbl *pTbl = tableList_.GetNext(pos);
pTbl->Dump(to, isExtended);
}
}
#endif
//--------------------------------------------------------------------------//
// PRIVATE METHODS
//--------------------------------------------------------------------------//
//--------------------------------------------------------------------------//
// CRUCache::InitBuild()
//--------------------------------------------------------------------------//
void CRUCache::InitBuild()
{
CRUGlobals *pGlobals = CRUGlobals::GetInstance();
CRUOptions &options = pGlobals->GetOptions();
// Should this be the machine name when the code is ported?
sqlNode_.Open("NSK");
lcType_ = options.GetLogCleanupType();
isCancelOnly_ = options.IsCancel();
isTotalRecompute_ = options.IsRecompute();
if (FALSE == isCancelOnly_)
{
currentUser_ = CRUGlobals::GetCurrentUser();
}
}
//--------------------------------------------------------------------------//
// CRUCache::FetchInvolvedMVsMetadata()
//
// Retrieve the metadata about all the involved MVs. Construct the wrapper
// CRUMV objects (one for each MV) and place them to the list of MVs.
//
// Split by cases (single-MV refresh, cascaded refresh, MV group refresh).
//--------------------------------------------------------------------------//
void CRUCache::FetchInvolvedMVsMetadata()
{
CRUOptions &options = CRUGlobals::GetInstance()->GetOptions();
// Retrieve the schema that hosts the MV/MV group
CDDSchema *pddSch =
GetDDSchemaByName(options.GetCatalogName(),
options.GetSchemaName());
CDSString objName = options.GetObjectName();
CRUOptions::InvocType invocType = options.GetInvocType();
switch (invocType) {
case CRUOptions::SINGLE_MV:
{
CDDMV *pddMV = GetDDMVByName(pddSch, objName);
FetchSingleInvolvedMV(pddMV);
break;
}
case CRUOptions::CASCADE:
{
FetchCascadedMVs(pddSch, objName);
break;
}
case CRUOptions::MV_GROUP:
{
FetchMVsInGroup(pddSch, objName);
break;
}
default: RUASSERT(FALSE);
}
}
//--------------------------------------------------------------------------//
// CRUCache::FetchCascadedMVs()
//
// Fetch the metadata for all the involved MVs if REFRESH is run
// with CASCADE option. The involved MVs are all the ON REQUEST
// or RECOMPUTE MVs used by the "root" MV directly or indirectly.
//--------------------------------------------------------------------------//
void CRUCache::FetchCascadedMVs(CDDSchema *pddSch, const CDSString& mvName)
{
CDDMV *pddRootMV = GetDDMVByName(pddSch, mvName);
if (CDDMV::eON_STATEMENT == pddRootMV->GetRefreshType())
{
// The CASCADE option is not allowed for ON STATEMENT MVs
CRUException e;
e.SetError(IDS_RU_ILLEGAL_CASCADE);
e.AddArgument(pddRootMV->GetFullName());
throw e;
}
// Start the recursive seacrh
RecursiveFetchCascadedMVs(pddRootMV);
}
//--------------------------------------------------------------------------//
// CRUCache::RecursiveFetchCascadedMVs()
//
// Fetch the expanded tree of MV objects starting from a "root" MV.
// Algorithm:
// Fetch the ON REQUEST/RECOMPUTED MVs directly used by the root MV,
// and continue drilling recursively.
//--------------------------------------------------------------------------//
void CRUCache::RecursiveFetchCascadedMVs(CDDMV *pddRootMV)
{
// Setup the wrapper object for the MV
FetchSingleInvolvedMV(pddRootMV);
CDDUIDTripleList &uList = pddRootMV->GetUsedObjects();
DSListPosition pos = uList.GetHeadPosition();
while (NULL != pos)
{
CDDUIDTriple& uidt = uList.GetNext(pos);
// Skip the regular tables
if (FALSE == pddRootMV->IsUsedObjectAnMV(uidt.objUID))
{
continue;
}
CDDMV *pddMV = GetDDMVByUID(uidt);
// An ON STATEMENT MV is a regular table
// for the purpose of cascade. Stop drilling inside.
if (CDDObject::eON_STATEMENT == pddMV->GetRefreshType())
{
continue;
}
// Since the same object cannot be used twice by the same MV,
// the used MV should not have been referenced before
// (and placed in the MV list).
RUASSERT (NULL != GetMV(pddRootMV->GetUID()));
RecursiveFetchCascadedMVs(pddMV);
}
}
//--------------------------------------------------------------------------//
// CRUCache::FetchMVsInGroup()
//
// Fetch the metadata for all the MVs in the MVGROUP
//--------------------------------------------------------------------------//
void CRUCache::FetchMVsInGroup(CDDSchema *pddSch, const CDSString& mvgName)
{
CDDMVGroup *pddMVG = GetDDMVGroupByName(pddSch, mvgName);
if (TRUE == pddMVG->IsEmpty())
{
// The source MVGROUP is empty
CRUException e;
e.SetError(IDS_RU_MVGROUP_EMPTY);
e.AddArgument(pddMVG->GetFullName());
throw e;
}
CDDUIDTripleList& uidList = pddMVG->GetAllMVs();
DSListPosition pos = uidList.GetHeadPosition();
while (NULL != pos)
{
// Retrieve the DD object
CDDUIDTriple uidt = uidList.GetNext(pos);
CDDMV *pddMV = GetDDMVByUID(uidt);
// Setup the CRUMV wrapper object
FetchSingleInvolvedMV(pddMV);
}
}
//--------------------------------------------------------------------------//
// CRUCache::FetchSingleInvolvedMV()
//
// Least common denominator for all the paths to MV metadata.
//
// (1) Allocate a single CRUMV object and put it to the global list.
// (2) Fetch the Refresh-related metadata.
// (3) If we are in the CANCEL mode - done. Otherwise, check the user's
// privileges for this MV.
//
//--------------------------------------------------------------------------//
void CRUCache::FetchSingleInvolvedMV(CDDMV *pddMV)
{
CRUMV *pMV = new CRUMV(pddMV);
pMV->SetInvolved();
// Read the REFRESH-specific metadata
pMV->FetchMetadata();
// Take care not to cancel the dangling DDL lock accidentally.
// For example, if the MV is multi-transactional, and has a
// DDL lock following the previous Refresh failure - it is
// forbidden to remove the DDL lock as long as the MV is not
// refreshed successfully.
pMV->SetReleaseDDLLock(pddMV->CanCancelDDLLock());
// Ignore User Maintainable MVs.
if (CDDObject::eBY_USER == pMV->GetRefreshType())
{
delete pMV;
return;
}
mvList_.AddTail(pMV);
// Register the MV for the further DDL lock handling
ddlLockHandler_.AddObject(pMV);
if (TRUE == isCancelOnly_)
{
return;
}
// Retrieve whether the user has Insert/Select/Delete privilege for this MV
pMV->FetchPrivileges();
}
//--------------------------------------------------------------------------//
// CRUCache::FetchInvolvedUsedObjectsMetadata()
//
// Fetch the metadata for all the objects used by the involved MVs.
// For each used object, create a CRUTbl wrapper and place it to the
// list of used objects (aka tables).
//
// Establish the cross-references of type "tables used by me" and "MVs
// using me" between the individual CRUMV and CRUTbl objects.
// The cross-references are implemented as lists of PHYSICAL pointers,
// rather that LOGICAL ones (UID triples) at the DDOL level.
//
//--------------------------------------------------------------------------//
void CRUCache::FetchInvolvedUsedObjectsMetadata()
{
DSListPosition pos = mvList_.GetHeadPosition();
while (NULL != pos)
{
CRUMV *pMV = mvList_.GetNext(pos);
FetchUsedObjectsMetadataForSingleMV(pMV);
}
}
//--------------------------------------------------------------------------//
// CRUCache::FetchUsedObjectsMetadataForSingleMV()
//
// Fetch the metadata for all the objects used by a single MV.
//
// Use the "global" list of CRUTbl wrappers as a cache. Create a wrapper
// once a used object is referenced first.
//
// Establish the cross-references of type "tables used by me" and "MVs
// using me" between the using and used objects.
//--------------------------------------------------------------------------//
void CRUCache::FetchUsedObjectsMetadataForSingleMV(CRUMV *pMV)
{
CDDUIDTripleList &uList = pMV->GetAllUsedObjectsUIDs();
DSListPosition pos = uList.GetHeadPosition();
while (NULL != pos)
{
CDDUIDTriple& uidt = uList.GetNext(pos);
TInt64 objUid = uidt.objUID;
// Tables that are IGNORE CHANGES and UDFs do not interest us
// for the purpose of REFRESH
if (TRUE == pMV->IsIgnoreChanges(objUid) ||
TRUE == pMV->IsUsedObjectUDF(objUid))
{
continue;
}
// Fetch the pointer to the used table's wrapper object
// (create the wrapper if the table is referenced first)
CRUTbl *pTbl = GetTable(objUid);
if (NULL == pTbl)
{
pTbl = FetchSingleUsedObject(pMV, uidt);
}
// Add the pointer to the table to the MV's list of dependencies.
pMV->AddRefToUsedObject(pTbl);
// Add the pointer to the MV to the table's list of dependencies.
pTbl->AddRefToUsingMV(pMV);
// Register the used object for the DDL lock handling ...
SetupUsedObject(pTbl);
}
}
//--------------------------------------------------------------------------//
// CRUCache::FetchSingleUsedObject()
//
// Create a wrapper for a single used object that is referenced first,
// and add it to the list of used tables.
//
// Split by cases: the object can be an MV or a regular table.
//--------------------------------------------------------------------------//
CRUTbl *CRUCache::FetchSingleUsedObject(CRUMV *pUsingMV,
const CDDUIDTriple &uidt)
{
CRUTbl *pTbl;
BOOL isMV = pUsingMV->IsUsedObjectAnMV(uidt.objUID);
if (FALSE == isMV)
{
CDDTable *pddTable = GetDDTableByUID(uidt);
pTbl = new CRURegularTbl(pddTable);
}
else
{
CDDMV *pddMV = GetDDMVByUID(uidt);
pTbl = new CRUMVTbl(pddMV);
// Read the REFRESH-specific metadata
pddMV->FetchMVRefreshMetadata();
// A table based on MV will always inherit the MV's timestamp
pTbl->SetTimestamp(pddMV->GetRefreshedAtTimestamp());
// Inherit the MV's feature.
// If a table is NOT an involved MV, take care not to remove
// its dangling DDL lock (if any) accidentally.
pTbl->SetReleaseDDLLock(pddMV->CanCancelDDLLock());
}
pTbl->SetInvolved();
tableList_.AddTail(pTbl);
return pTbl;
}
//--------------------------------------------------------------------------//
// CRUCache::SetupUsedObject()
//
// (1) Register the used object for DDL lock handling.
//
// (2) For the first ON REQUEST MV using the table:
// - Fetch the epoch metadata from the MVS_TABLE_INFO_UMD table.
// - Fixup its pointer to the IUD log table's object in DDOL.
//
//--------------------------------------------------------------------------//
void CRUCache::SetupUsedObject(CRUTbl *pTbl)
{
// If the table is also an involved MV, the DDL lock is already handled
if (NULL == GetMV(pTbl->GetUID()))
{
// Register the table for the further DDL lock handling
ddlLockHandler_.AddObject(pTbl);
}
if (TRUE == isCancelOnly_)
{
return; // No more processing is required
}
if (1 == pTbl->GetOnRequestMVsUsingMe().GetCount())
{
// Fetch the epochs' metadata
pTbl->FetchMetadata();
// Fixup the pointer to the IUD log table
FixupLogTblReference(pTbl);
}
}
//--------------------------------------------------------------------------//
// CRUCache::FixupLogTblReference()
//
// Fixup the pointer to the IUD log object from the table
//--------------------------------------------------------------------------//
void CRUCache::FixupLogTblReference(CRUTbl *pTbl)
{
const CDSString &catName = pTbl->GetCatName();
const CDSString &schName = pTbl->GetSchName();
CDDSchema *pddSch = GetDDSchemaByName(catName, schName);
// Compose the IUD log table's name
CDSString logName(pTbl->GetLogShortName(CRUTbl::iudNmspPrefix));
CDDTable *pddLogTable = GetDDIUDLogTableByName(pddSch, logName);
// Dummy fetch, just force DDOL to fetch the data
pddLogTable->GetColumnList();
pTbl->FixupIUDLogTbl(pddLogTable);
}
//--------------------------------------------------------------------------//
// CRUCache::SetupRecomputeProperty()
//
// For each involved MV, determine whether the MV must be recomputed,
// and consider purgedata/popindex as part of recompute
//
//--------------------------------------------------------------------------//
void CRUCache::SetupRecomputeProperty()
{
DSListPosition pos = mvList_.GetHeadPosition();
while (NULL != pos)
{
CRUMV *pMV = mvList_.GetNext(pos);
pMV->SetupRecomputeProperty(isTotalRecompute_);
}
}
//--------------------------------------------------------------------------//
// CRUCache::FetchNonInvolvedMVsMetadata()
//
// Fetch the epoch metadata for ON REQUEST MVs that are using the involved
// tables, but are not refreshed in this invocation of the utility.
//
// This metadata is required for Log Cleanup and Delta Pipelining
// decisions.
//
//--------------------------------------------------------------------------//
void CRUCache::FetchNonInvolvedMVsMetadata()
{
DSListPosition tpos = tableList_.GetHeadPosition();
while (NULL != tpos)
{
CRUTbl *pTbl = tableList_.GetNext(tpos);
// Retrieve the table's private dependency list
CDDUIDTripleList &privTblList = pTbl->GetUIDsOfAllMVsUsingMe();
DSListPosition mvpos = privTblList.GetHeadPosition();
while (NULL != mvpos)
{
CDDUIDTriple &uidt = privTblList.GetNext(mvpos);
CRUMV *pMV = GetMV(uidt.objUID);
if (NULL == pMV)
{
// The MV is non-involved, fetch the DD object
CDDMV *pddMV = GetDDMVByUID(uidt);
// If the MV is not ON REQUEST, skip it
if (CDDObject::eON_REQUEST != pddMV->GetRefreshType())
{
continue;
}
pMV = FetchSingleNonInvolvedMV(pddMV);
}
if (FALSE == pMV->IsInvolved())
{
// If the MV is involved, the pointer exists already
pTbl->AddRefToUsingMV(pMV);
}
}
}
}
//--------------------------------------------------------------------------//
// CRUCache::FetchSingleNonInvolvedMV()
//
// Fetch a newly-referenced non-involved ON REQUEST MV.
//--------------------------------------------------------------------------//
CRUMV *CRUCache::FetchSingleNonInvolvedMV(CDDMV *pddMV)
{
// Create a new wrapper object for a non-involved MV,
// leave its reference list empty
CRUMV *pMV = new CRUMV(pddMV);
mvList_.AddTail(pMV);
// Fetch the epoch data
pMV->FetchMetadata();
return pMV;
}
//--------------------------------------------------------------------------//
// CRUCache::FetchNonInvolvedUsedObjectsMetadata()
//
// Create a CRUTbl object for each involved ON REQUEST MV that
// does not have a corresponding CRUTbl object in the table list
// (i.e., is not used by the other involved MVs).
//
//-------------------------------------------------------------------------//
void CRUCache::FetchNonInvolvedUsedObjectsMetadata()
{
DSListPosition pos = mvList_.GetHeadPosition();
while (NULL != pos)
{
CRUMV *pMV = mvList_.GetNext(pos);
if (FALSE == pMV->IsInvolved()
||
CDDObject::eON_REQUEST != pMV->GetRefreshType())
{
continue;
}
if (NULL == GetTable(pMV->GetUID()))
{
CDDSchema *pddSch =
GetDDSchemaByName(pMV->GetCatName(), pMV->GetSchName());
CDDMV *pddMV = GetDDMVByName(pddSch, pMV->GetName());
CRUTbl *pTbl = new CRUMVTbl(pddMV);
pTbl->FetchMetadata();
tableList_.AddTail(pTbl);
}
}
}
//--------------------------------------------------------------------------//
// CRUCache::CheckLogCleanupApplicability()
//
// Check the applicability of the {WITH | DO ONLY} LOG CLEANUP option.
//
// If there is no involved ON REQUEST MV, then the involved tables
// mignt not have logs, and the option is not legal.
//
// The method also resolves the LOG CLEANUP option, if it does not appear
// in the command: if there is no involved ON REQUEST MV, it is resolved
// to WITHOUT LOG CLEANUP, otherwise to WITH LOG CLEANUP.
//
//--------------------------------------------------------------------------//
void CRUCache::CheckLogCleanupApplicability()
{
switch (lcType_)
{
case CRUOptions::WITHOUT_LC:
break; // Nothing to check
case CRUOptions::DONTCARE_LC:
{
lcType_ = (TRUE == IsOnRequestMVInvolved()) ?
CRUOptions::WITH_LC :
CRUOptions::WITHOUT_LC;
CRUOptions &options = CRUGlobals::GetInstance()->GetOptions();
options.SetLogCleanupType(lcType_);
break;
}
case CRUOptions::WITH_LC:
case CRUOptions::DO_ONLY_LC:
{
if (FALSE == IsOnRequestMVInvolved())
{
// No candidate for log cleanup
CRUException ex;
ex.SetError(IDS_RU_EMPTY_CLEANUP_LIST);
throw ex;
}
break;
}
default: RUASSERT(FALSE);
}
}
//--------------------------------------------------------------------------//
// CRUCache::IsOnRequestMVInvolved()
//--------------------------------------------------------------------------//
BOOL CRUCache::IsOnRequestMVInvolved()
{
DSListPosition pos = mvList_.GetHeadPosition();
while (NULL != pos)
{
CRUMV *pMV = mvList_.GetNext(pos);
if (TRUE == pMV->IsInvolved()
&&
CDDMV::eON_REQUEST == pMV->GetRefreshType()
)
{
return TRUE;
}
}
return FALSE;
}
//--------------------------------------------------------------------------//
// CRUCache::FetchDefaults()
//
// Read the MV_REFRESH_MAX_PIPELINING and MV_REFRESH_MAX_PARALLELISM
// defaults from the SYSTEM_DEFAULTS table.
//
//--------------------------------------------------------------------------//
void CRUCache::FetchDefaults()
{
CDSString maxPiplining("MV_REFRESH_MAX_PIPELINING");
FetchSingleDefault(
maxPiplining,
maxPipelining_);
CDSString maxParallelism("MV_REFRESH_MAX_PARALLELISM");
FetchSingleDefault(
maxParallelism,
maxParallelism_);
if (0 == maxParallelism_
||
maxParallelism_ > CUOFsTaskProcessPool::MaxProcesses)
{
// We have a limited capacity for parallelism
maxParallelism_ = CUOFsTaskProcessPool::MaxProcesses;
}
#ifdef NA_LINUX
// temporary workaround until we get tdm_arkutp to work
// maxPipelining_ = 1;
maxParallelism_ = 1;
#endif
}
//--------------------------------------------------------------------------//
// CRUCache::FetchSingleDefault()
//
// The default value of each default is 1.
//--------------------------------------------------------------------------//
void CRUCache::FetchSingleDefault( CDSString &name,
TInt32 &to)
{
to = 1;
CDDControlQueryDefault cqd(name);
CDSString stringVal = cqd.RetrieveCQDValue();
// this should not happen since the cqd is defined in the code but just in case
if (stringVal.IsEmpty())
{
return;
}
const char *attrVal = stringVal.c_string();
TInt32 numericVal;
if (0 == sscanf(attrVal, "%d", &numericVal) // Invalid value
||
numericVal < 0 // negative value
)
{
return;
}
to = numericVal;
}
//--------------------------------------------------------------------------//
// CRUCache::FixupMVTblInterfaces()
//
// For each involved MV in the cache such that there is also
// a table object in the cache for the same UID (for example,
// if the MV is used by another involved MV): set the pointer
// from the MV object to the table object, and back.
//
//--------------------------------------------------------------------------//
void CRUCache::FixupMVTblInterfaces()
{
DSListPosition pos = mvList_.GetHeadPosition();
while (NULL != pos)
{
CRUMV *pMV = mvList_.GetNext(pos);
if (FALSE == pMV->IsInvolved())
{
continue; // Skip the non-involved MVs
}
CRUTbl *pTbl = GetTable(pMV->GetUID());
if (NULL == pTbl)
{
continue; // No table object in the cache, skip
}
// Setup pointers MV <---> table
pMV->SetTblInterface(pTbl);
pTbl->SetMVInterface(pMV);
}
}
//--------------------------------------------------------------------------//
// CRUCache::FetchForceData()
//
//--------------------------------------------------------------------------//
void CRUCache::FetchForceData()
{
CRUForceOptionsParser forceParser;
forceParser.SetFile(
CRUGlobals::GetInstance()->GetOptions().GetForceFilename());
forceParser.Parse();
CRUForceOptions& forceOption = forceParser.GetForceOptions();
// Place the force data on the involved mv's.
CRUMVList &mvList = GetMVList();
DSListPosition pos = mvList.GetHeadPosition();
while (NULL != pos)
{
CRUMV *pMV = mvList.GetNext(pos);
if (FALSE == pMV->IsInvolved())
{
continue;
}
UpdateForceOptionForMV(forceOption, pMV);
}
}
//--------------------------------------------------------------------------//
// CRUCache::UpdateForceOptionForMV()
//--------------------------------------------------------------------------//
void CRUCache::UpdateForceOptionForMV(CRUForceOptions& forceOptions,
CRUMV *pMV)
{
CRUMVForceOptionsList& mvForceOptionsList =
forceOptions.GetMVForceOptionsList();
DSListPosition prevpos = NULL;
DSListPosition pos = mvForceOptionsList.GetHeadPosition();
while (NULL != pos)
{
prevpos = pos;
CRUMVForceOptions *pMVForceOptions = mvForceOptionsList.GetNext(pos);
if (pMV->GetFullName() == pMVForceOptions->GetMVName())
{
pMV->SetMVForceOption(pMVForceOptions);
if (NULL == prevpos)
{
mvForceOptionsList.RemoveHead();
}
else
{
mvForceOptionsList.RemoveAt(prevpos);
}
return;
}
}
}
//--------------------------------------------------------------------------//
// Various DD objects retrieval
//--------------------------------------------------------------------------//
//--------------------------------------------------------------------------//
// CRUCache::GetDDSchemaByName()
// Retrieving the schema by catalog + schema name
//--------------------------------------------------------------------------//
CDDSchema *CRUCache::GetDDSchemaByName(const CDSString& catName,
const CDSString& schName)
{
// check for DEFAULT_SCHEMA_ACCESS_ONLY
// get default catalog & schema
CRUOptions &options = CRUGlobals::GetInstance()->GetOptions();
CDSString curCatSch = catName + "." + schName;
if (CDDControlQueryDefault::ViolateDefaultSchemaAccessOnly(
options.GetDefaultSchema(), curCatSch))
{
CRUException e;
e.SetError(IDS_RU_SCHEMA_ACCESS_VIOLATION);
throw e;
}
CDDCatalog *pddCat = sqlNode_.GetCatalog(catName);
if (NULL == pddCat)
{
// Source catalog does not exist
CRUException e;
e.SetError(IDS_RU_INVALID_CATALOG_NAME);
e.AddArgument(catName.c_string());
throw e;
}
CDDSchema *pddSch = pddCat->GetSchema(schName, TRUE);
if (NULL == pddSch)
{
// Source schema does not exist
CRUException e;
e.SetError(IDS_RU_INVALID_SCHEMA_NAME);
CDSString fname = catName + "." + schName;
e.AddArgument(fname.c_string());
throw e;
}
return pddSch;
}
//--------------------------------------------------------------------------//
// CRUCache::GetDDSchemaByUID()
// Retrieving the schema by catalog + schema UID
//--------------------------------------------------------------------------//
CDDSchema *CRUCache::GetDDSchemaByUID(TInt64 catUid, TInt64 schUid)
{
CDDCatalog *pddCat = sqlNode_.GetCatalog(catUid);
if (NULL == pddCat)
{
// Catalog does not exist, metadata inconsistency
CRUException e;
e.SetError(IDS_RU_INCONSISTENT_CAT);
throw e;
}
CDDSchema *pddSch = pddCat->GetSchema(schUid);
if (NULL == pddSch)
{
// Schema does not exist, metadata inconsistency
CRUException e;
e.SetError(IDS_RU_INCONSISTENT_CAT);
throw e;
}
return pddSch;
}
//--------------------------------------------------------------------------//
// CRUCache::GetDDMVByName()
//--------------------------------------------------------------------------//
CDDMV *CRUCache::GetDDMVByName(CDDSchema *pddSch, const CDSString& mvName)
{
CDDMV *pddMV = pddSch->GetMV(mvName);
if (NULL == pddMV) // try public schema if necessary
{
CDDSchema *pddSchP = GetPublicSchema();
if (pddSchP)
{
pddMV = pddSchP->GetMV(mvName);
if (pddMV)
{ // if can be found in the public schema
// update the catalog and schema
CRUOptions &options = CRUGlobals::GetInstance()->GetOptions();
options.SetCatalogName(pddSchP->GetCatName());
options.SetSchemaName(pddSchP->GetName());
}
}
}
if (NULL == pddMV)
{
// Source MV does not exist
CRUException e;
e.SetError(IDS_RU_INVALID_MV_NAME);
CDSString fname = pddSch->GetFullName() + "." + mvName;
e.AddArgument(fname.c_string());
throw e;
}
return pddMV;
}
//--------------------------------------------------------------------------//
// CRUCache::GetDDIUDLogTableByName()
//--------------------------------------------------------------------------//
CDDTable *CRUCache::GetDDIUDLogTableByName(CDDSchema *pddSch,
const CDSString& logName)
{
CDDTable *pddTable = pddSch->GetIUDLogTable(logName);
if (NULL == pddTable) // try public schema if necessary
{
CDDSchema *pddSchP = GetPublicSchema();
if (pddSchP)
{
pddTable = pddSch->GetIUDLogTable(logName);
if (pddTable)
{ // if can be found in the public schema
// update the catalog and schema
CRUOptions &options = CRUGlobals::GetInstance()->GetOptions();
options.SetCatalogName(pddSchP->GetCatName());
options.SetSchemaName(pddSchP->GetName());
}
}
}
if (NULL == pddTable)
{
// Table does not exist, metadata inconsistency
CRUException e;
e.SetError(IDS_RU_INCONSISTENT_CAT);
throw e;
}
return pddTable;
}
//--------------------------------------------------------------------------//
// CRUCache::GetDDMVGroupByName()
//--------------------------------------------------------------------------//
CDDMVGroup *CRUCache::GetDDMVGroupByName(CDDSchema *pddSch, const CDSString& mvgName)
{
CDDMVGroup *pddMVG = pddSch->GetMVGroup(mvgName);
if (NULL == pddMVG) // try public schema if necessary
{
CDDSchema *pddSchP = GetPublicSchema();
if (pddSchP)
{
pddMVG = pddSchP->GetMVGroup(mvgName);
if (pddMVG)
{ // if can be found in the public schema
// update the catalog and schema
CRUOptions &options = CRUGlobals::GetInstance()->GetOptions();
options.SetCatalogName(pddSchP->GetCatName());
options.SetSchemaName(pddSchP->GetName());
}
}
}
if (NULL == pddMVG)
{
// Source MV group does not exist
CRUException e;
e.SetError(IDS_RU_INVALID_MVGROUP_NAME);
CDSString fname = pddSch->GetFullName() + "." + mvgName;
e.AddArgument(fname.c_string());
throw e;
}
return pddMVG;
}
//--------------------------------------------------------------------------//
// CRUCache::GetDDMVByUID()
//--------------------------------------------------------------------------//
CDDMV *CRUCache::GetDDMVByUID(const CDDUIDTriple &uidt)
{
CDDSchema *pddSch = GetDDSchemaByUID(uidt.catUID, uidt.schUID);
CDDMV *pddMV = pddSch->GetMV(uidt.objUID);
if (NULL == pddMV)
{
// MV does not exist, metadata inconsistency
CRUException e;
e.SetError(IDS_RU_INCONSISTENT_CAT);
throw e;
}
return pddMV;
}
//--------------------------------------------------------------------------//
// CRUCache::GetDDTableByUID()
//--------------------------------------------------------------------------//
CDDTable *CRUCache::GetDDTableByUID(const CDDUIDTriple &uidt)
{
CDDSchema *pddSch = GetDDSchemaByUID(uidt.catUID, uidt.schUID);
CDDTable *pddTbl = pddSch->GetTable(uidt.objUID);
if (NULL == pddTbl)
{
// Table does not exist, metadata inconsistency
CRUException e;
e.SetError(IDS_RU_INCONSISTENT_CAT);
throw e;
}
return pddTbl;
}
// for public schema
// return a CDDSchema pointer if need to check public schema
CDDSchema *CRUCache::GetPublicSchema()
{
CRUOptions &options = CRUGlobals::GetInstance()->GetOptions();
if (FALSE == options.IsQualified()) // only when the object is not qualified
return NULL;
CDSString pubCat;
CDSString pubSch;
Int32 retPubSch = CDDControlQueryDefault::RetrievePublicSchema(
options.GetDefaultSchema(), pubCat, pubSch);
if (retPubSch == 0)
return NULL;
CDDCatalog *pddCat = sqlNode_.GetCatalog(pubCat);
if (NULL == pddCat)
return NULL;
// retPubSch must be 1 or 2 here
CDDSchema *pddSchp = pddCat->GetSchema(pubSch, TRUE);
return pddSchp;
}