blob: 28aff4ebba47481dbb5441843c257f06fa2e65a2 [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: RuTblEquivSetBuilder.cpp
* Description: Implementation of class CRUTblEquivSetBuilder
*
* Created: 11/23/2000
* Language: C++
*
*
******************************************************************************
*/
#include "RuTblEquivSetBuilder.h"
#include "RuGlobals.h"
#include "RuOptions.h"
#include "RuJournal.h"
//--------------------------------------------------------------------------//
// Constructor & Destructors
//--------------------------------------------------------------------------//
CRUTblEquivSetBuilder::CRUTblEquivSetBuilder()
: syncTablesList_(eItemsArentOwned),
onRequestMVsList_(eItemsArentOwned),
recomputeMVsList_(eItemsArentOwned),
equivSetsList_(eItemsAreOwned)
{}
CRUTblEquivSetBuilder::~CRUTblEquivSetBuilder()
{}
//--------------------------------------------------------------------------//
// CRUTblEquivSetBuilder::AddMV()
//
// Add the given mv and categorize it by adding it to the proper list
//--------------------------------------------------------------------------//
void CRUTblEquivSetBuilder::AddMV(CRUMV *pMV)
{
RUASSERT(pMV != NULL);
switch (pMV->GetRefreshType())
{
case CDDObject::eON_STATEMENT:
{
// on statment does not need syncronization
break;
}
case CDDObject::eON_REQUEST:
{
onRequestMVsList_.AddTail(pMV);
break;
}
case CDDObject::eRECOMPUTE:
{
recomputeMVsList_.AddTail(pMV);
break;
}
default: RUASSERT(FALSE);
}
}
//--------------------------------------------------------------------------//
// CRUTblEquivSetBuilder::GetSet()
//--------------------------------------------------------------------------//
CRUTblList& CRUTblEquivSetBuilder::GetSet(Int32 num)
{
RUASSERT (GetNumOfSets() >= num && 0 <= num );
CRUTblList *pTblList = equivSetsList_.GetAt(num);
RUASSERT (NULL != pTblList);
return *pTblList;
}
//--------------------------------------------------------------------------//
// CRUTblEquivSetBuilder::Run()
//
// Main execution function
//--------------------------------------------------------------------------//
void CRUTblEquivSetBuilder::Run()
{
// Iterate through all the given mv's and add all the nessesary used
// objects to the graph.This function also builds the syncronized table
// list
BuildDisJointGraph();
// Analyze the graph with the disjoint graph helper class
GetDisJointAlg().Run();
// Iterate through all the syncronized tables and build syncronized table
// sets
BuildSets();
}
//--------------------------------------------------------------------------//
// CRUTblEquivSetBuilder::BuildDisJointGraph()
//
// Iterate through all the given mv's and add all the nessesary used
// objects to the graph.This function also builds the syncronized table
// list
//--------------------------------------------------------------------------//
void CRUTblEquivSetBuilder::BuildDisJointGraph()
{
//phase 0 :: Add only on request mv's and their used tables
AddOnRequestMVs();
//phase 1 :: Add all recomputed mv's that needs tables syncronization
// and their used tables
AddRecomputedMVs();
}
//--------------------------------------------------------------------------//
// CRUTblEquivSetBuilder::AddOnRequestMVs()
//
//--------------------------------------------------------------------------//
void CRUTblEquivSetBuilder::AddOnRequestMVs()
{
DSListPosition mvPos = onRequestMVsList_.GetHeadPosition();
while (NULL != mvPos)
{
CRUMV *pMV = onRequestMVsList_.GetNext(mvPos);
AddOnRequestMV(pMV);
}
}
//--------------------------------------------------------------------------//
// CRUTblEquivSetBuilder::AddOnRequestMV()
//
// We go over all the involved on request mv's and for each mv ,
// we first add it as a vertex to the disjointsets alg' and than
// go over all of his tables and add to the disjointsets alg' those who
// are not an involved mv's but are an involved tables
//
// We make exception for an involved table that is a not involved mv
// This will be explain in more detail in the function body
//--------------------------------------------------------------------------//
void CRUTblEquivSetBuilder::AddOnRequestMV(CRUMV *pMV)
{
RUASSERT(CDDObject::eON_REQUEST == pMV->GetRefreshType());
GetDisJointAlg().AddVertex(pMV->GetUID());
// All tables in this list are involved tables by definition
CRUTblList &tblList = pMV->GetTablesUsedByMe();
DSListPosition tblPos = tblList.GetHeadPosition();
while (NULL != tblPos)
{
CRUTbl *pTbl = tblList.GetNext(tblPos);
if (TRUE == pTbl->IsFullySynchronized())
{
// This is as syncronized table ,we must place it in the
// syncronized table list and in the disjoint graph
AddSyncTable(pTbl);
GetDisJointAlg().AddEdge(pTbl->GetUID(),pMV->GetUID());
}
if (FALSE == pTbl->IsInvolvedMV())
{
// This is not an involved mv do not add it to the set.
// A not involved mv does not require syncronization
// because it may only be changed by the refresh utility
// and this is prevented by the ddl locks that are place on this
// object
continue;
}
GetDisJointAlg().AddEdge(pTbl->GetUID(),pMV->GetUID());
}
}
//--------------------------------------------------------------------------//
// CRUTblEquivSetBuilder::AddRecomputedMVs()
//
// We only add a recompute mv that obeys the rule :
// the mv is based on more than two objects and at least on is an mv.
//--------------------------------------------------------------------------//
void CRUTblEquivSetBuilder::AddRecomputedMVs()
{
DSListPosition mvPos = recomputeMVsList_.GetHeadPosition();
while (NULL != mvPos)
{
CRUMV *pMV = recomputeMVsList_.GetNext(mvPos);
if (0 == pMV->GetNumDirectlyUsedMVs() ||
1 == pMV->GetTablesUsedByMe().GetCount())
{
continue;
}
AddRecomputeTree(pMV);
}
}
//--------------------------------------------------------------------------//
// CRUTblEquivSetBuilder::AddRecomputeTree()
//
// If the mv is already in the graph we have nothing more to do,otherwise
// We should add recursively the tree beneath the given mv. We should also
// force long lock on all syncronized tables that are in the tree.
// It is important to remember that every on-request mv we encounter is
// already in the graph (and his sub-tree) so we just need to add the edge
// to it
//--------------------------------------------------------------------------//
void CRUTblEquivSetBuilder::AddRecomputeTree(CRUMV *pMV)
{
RUASSERT(CDDObject::eRECOMPUTE == pMV->GetRefreshType());
if (TRUE == GetDisJointAlg().HasVertex(pMV->GetUID()))
{
// The mv is already in the graph and his sub tree must also be there
// by induction
return;
}
GetDisJointAlg().AddVertex(pMV->GetUID());
// Go over all the childs
CRUTblList &tblList = pMV->GetTablesUsedByMe();
DSListPosition tblPos = tblList.GetHeadPosition();
while (NULL != tblPos)
{
CRUTbl *pTbl = tblList.GetNext(tblPos);
if (TRUE == pTbl->IsFullySynchronized())
{
GetDisJointAlg().AddEdge(pTbl->GetUID(),pMV->GetUID());
AddSyncTable(pTbl);
pTbl->SetLongLockIsNeeded();
continue;
}
if (FALSE == pTbl->IsInvolvedMV())
{
// This is not an involved mv do not add it to the set.
// A not involved mv does not require syncronization
// because it may only be changed by the refresh utility
// and this is prevented by the ddl locks that are place on this
// object
continue;
}
// The object is an mv - if its on request we should do nothing
// forcing lock may be skipped and all involved on request
// are already in the graph
GetDisJointAlg().AddEdge(pTbl->GetUID(),pMV->GetUID());
CRUMV *pNextMV = pTbl->GetMVInterface();
RUASSERT(NULL != pNextMV);
if (CDDObject::eON_REQUEST == pNextMV->GetRefreshType() )
{
// All on requests mv's are already in the graph
continue;
}
RUASSERT(CDDObject::eRECOMPUTE ==
pNextMV->GetRefreshType());
// call this function recursively for adding all sub tree
AddRecomputeTree(pNextMV);
}
}
//--------------------------------------------------------------------------//
// CRUTblEquivSetBuilder::AddSyncTable()
//--------------------------------------------------------------------------//
void CRUTblEquivSetBuilder::AddSyncTable(CRUTbl *pTbl)
{
RUASSERT(pTbl != NULL);
if (FALSE == GetDisJointAlg().HasVertex(pTbl->GetUID()))
{
// We should add all base tables to the disjoint graph
// because the same table can be used by several mv's
// and there for be a connection point
GetDisJointAlg().AddVertex(pTbl->GetUID());
// This is the first encounter with this table
// lets add it to the table list
syncTablesList_.AddTail(pTbl);
}
}
//--------------------------------------------------------------------------//
// CRUTblEquivSetBuilder::BuildSets()
//
// Collect the output from the disjoint set algorithm and prepare the sets
//--------------------------------------------------------------------------//
void CRUTblEquivSetBuilder::BuildSets()
{
// Initialize the array of sets of CRUTbl
Int32 equivSetsSize = GetDisJointAlg().GetNumOfSets();
// Initialize the sets of CRUTbl
for (Int32 i=0;i<equivSetsSize;i++)
{
equivSetsList_.AddTail(
new CRUTblList(eItemsArentOwned));
}
// Pass all regular tables and add them to the appropriate list
DSListPosition tblPos = syncTablesList_.GetHeadPosition();
while (NULL != tblPos)
{
CRUTbl *pTbl = syncTablesList_.GetNext(tblPos);
Int32 setId = GetDisJointAlg().GetNodeSetId(pTbl->GetUID());
equivSetsList_.GetAt(setId)->AddTail(pTbl);
}
// Remove set with zero size
DSListPosition setsPos = equivSetsList_.GetHeadPosition();
while (NULL != setsPos)
{
DSListPosition setsPrevpos = setsPos;
CRUTblList *pTblList = equivSetsList_.GetNext(setsPos);
if (0 == pTblList->GetCount())
{
equivSetsList_.RemoveAt(setsPrevpos);
}
}
}
#ifdef _DEBUG
//--------------------------------------------------------------------------//
// CRUTblEquivSetBuilder::DumpSets()
//--------------------------------------------------------------------------//
void CRUTblEquivSetBuilder::DumpSets()
{
CDSString msg;
msg = "\n Equivalent sets: \n" ;
CRUGlobals::GetInstance()->GetJournal().LogMessage(msg);
for (Int32 i=0;i<GetNumOfSets();i++)
{
msg = "\n Table Set: \n" ;
CRUGlobals::GetInstance()->GetJournal().LogMessage(msg);
DSListPosition tblPos = GetSet(i).GetHeadPosition();
while (NULL != tblPos)
{
CRUTbl *pTbl = GetSet(i).GetNext(tblPos);
CRUGlobals::GetInstance()->GetJournal().
LogMessage(pTbl->GetFullName());
}
}
}
#endif