Logo Search packages:      
Sourcecode: condor version File versions  Download package

view.cpp

/***************************************************************
 *
 * Copyright (C) 1990-2007, Condor Team, Computer Sciences Department,
 * University of Wisconsin-Madison, WI.
 * 
 * Licensed 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.
 *
 ***************************************************************/


#include "classad/common.h"
#include "classad/view.h"
#include "classad/collection.h"
#include "classad/collectionBase.h"

using namespace std;

// ----------- <implementation of ViewMember class> -----------------

BEGIN_NAMESPACE( classad )

ViewMember::
ViewMember( )
{
      rank.SetUndefinedValue( );
}

ViewMember::ViewMember(const ViewMember &other)
{
      key = other.key;
      rank.CopyFrom( (Value&) other.rank );
      return;
}

ViewMember::
~ViewMember( )
{
      return;
}


void ViewMember::
SetRankValue( const Value &rankValue )
{
      rank.CopyFrom( (Value&) rankValue );
}


void ViewMember::
SetKey( const string &adKey )
{
      key = adKey;
}


void ViewMember::
GetKey( string &adKey ) const 
{
      adKey = key;
}


void ViewMember::
GetRankValue( Value &rankValue ) const
{
      rankValue.CopyFrom( rank );
}


ViewMember ViewMember::
operator=( const ViewMember &vm )
{
      key = vm.key;
      rank.CopyFrom( (Value&) vm.rank );
      return( *this );
}

bool operator<(const ViewMember &vm1, const ViewMember &vm2)
{
      bool                lessThan;
      bool                isEqual;
      Value                   val1, val2;
      Value::ValueType  vt1, vt2;

      vm1.GetRankValue( val1 );
      vm2.GetRankValue( val2 );

      vt1 = val1.GetType( );
      vt2 = val2.GetType( );

      // if the values are of the same scalar type, or if they are both
      // numbers, use the builtin < comparison operator
      if( ( vt1==vt2 && vt1!=Value::CLASSAD_VALUE && vt2!=Value::LIST_VALUE ) ||
                  ( vt1==Value::INTEGER_VALUE && vt2==Value::REAL_VALUE )                 ||
                  ( vt1 == Value::REAL_VALUE && vt2 == Value::INTEGER_VALUE ) ) {
            Value lessThanResult, equalResult;
            Operation::Operate( Operation::LESS_THAN_OP, val1, val2, lessThanResult );
            Operation::Operate( Operation::EQUAL_OP, val1, val2, equalResult);
            lessThan = lessThanResult.IsBooleanValue( lessThan ) && lessThan;
            isEqual  = equalResult.IsBooleanValue( isEqual) && isEqual;
      } else {
            // otherwise, rank them by their type numbers
            lessThan = (vt1 < vt2);
            isEqual  = false;
      }

      // If they are equal, rank them by key.  This is important,
      // because otherwise two members with the same rank are considered
      // to be equal, but they may have different keys, and when we try
      // to erase a single member from the viewMembers, it will erase
      // everything with the same rank, whether or not they have the
      // same key.
      if (isEqual) {
            lessThan = (vm1.key < vm2.key);
      }
      
      return lessThan;
}

// ---------------- </implementation of ViewMember class> ------------------


// ----------------- <implementation of View class> -------------------

View::
View( View *parentView )
{
      Value                   val;
      vector<ExprTree*> vec;

      ClassAd     *ad = evalEnviron.GetLeftAd( );
      parent = parentView;
      ad->InsertAttr( ATTR_REQUIREMENTS, true );
      ad->Insert( ATTR_RANK, Literal::MakeLiteral( val ) );
      ad->Insert( ATTR_PARTITION_EXPRS, ExprList::MakeExprList( vec ) );
      if( parentView ) {
            ad->InsertAttr( "ParentViewName", parentView->GetViewName( ) );
      }
}


View::
~View( )
{
      SubordinateViews::iterator    xi;
      PartitionedViews::iterator    mi;

            // recursively delete subordinate child views ...
      for( xi = subordinateViews.begin( ); xi != subordinateViews.end( ); xi++ ) {
            delete (*xi);
      }

            // ... and partitioned child views
      for( mi = partitionedViews.begin( ); mi != partitionedViews.end( ); mi++ ) {
            delete mi->second;
      }
}


bool View::
SetViewName( const ViewName &name )
{
      ClassAd     *ad;
      viewName = name;
      if( !(ad=evalEnviron.GetLeftAd( )) || !ad->InsertAttr("ViewName", name) ) {
            CondorErrno = ERR_FAILED_SET_VIEW_NAME;
            return( false );
      }
      return( true );
}


bool View::
SetViewInfo( ClassAdCollection *coll, ClassAd *ad )
{
      ExprTree    *rankExpr=NULL, *constraintExpr=NULL, *tmp=NULL;
      ExprList    *partitionExprs=NULL;

      if( !( rankExpr = ad->Remove( ATTR_RANK ) ) ) {
            Value val;
            val.SetUndefinedValue( );
            rankExpr = Literal::MakeLiteral( val );
      }

      if( !( constraintExpr = ad->Remove( ATTR_REQUIREMENTS ) ) ) {
            Value val;
            val.SetBooleanValue( true );
            constraintExpr = Literal::MakeLiteral( val );
      }
      
      if( ( ( tmp = ad->Remove( ATTR_PARTITION_EXPRS ) ) &&
                  tmp->GetKind( ) != ExprTree::EXPR_LIST_NODE ) || !tmp ) {
            vector<ExprTree*> vec;
            if( tmp ) delete tmp;
            partitionExprs = ExprList::MakeExprList( vec );
      } else {
            partitionExprs = (ExprList*) tmp;
      }

      // Preserve the view name and parent view name.
      ClassAd  *eval;
      string view_name, parent_view_name;

      eval = evalEnviron.GetLeftAd();
      eval->EvaluateAttrString("ViewName", view_name);
      eval->EvaluateAttrString("ParentViewName", parent_view_name);

      ad->InsertAttr("ViewName", view_name);
      ad->InsertAttr("ParentViewName", parent_view_name);

      if( !evalEnviron.ReplaceLeftAd( ad ) ) {
            CondorErrMsg+="; could not replace view info; failed to set view info";
            return( false );
      }

      if( constraintExpr && !SetConstraintExpr( coll, constraintExpr ) ) {
            CondorErrMsg += "; failed to set view info";
            delete constraintExpr;
            delete rankExpr;
            delete partitionExprs;
            return( false );
      }

      if( !SetRankExpr( coll, rankExpr ) ) {
            CondorErrMsg += "; failed to set view info";
            delete rankExpr;
            delete partitionExprs;
            return( false );
      }

      if( !SetPartitionExprs( coll, partitionExprs ) ) {
            CondorErrMsg += "; failed to set view info";
            delete partitionExprs;
            return( false );
      }

      return( true );
}


ClassAd *View::
GetViewInfo( )
{
      ClassAd                       *newAd, *ad = evalEnviron.GetLeftAd( );
      vector<ExprTree*>       viewNames;
      Literal                       *lit;

      if( !ad ) {
            CLASSAD_EXCEPT( "internal error: view has no view info!" );
      }
      
      if( !( newAd = (ClassAd*) ad->Copy( ) ) ) {
            CondorErrno = ERR_MEM_ALLOC_FAILED;
            CondorErrMsg = "";
            if( newAd ) delete newAd;
            return( NULL );
      }
            // insert number of members
      newAd->InsertAttr( "NumMembers", (int) viewMembers.size( ) );

      
            // insert names of subordinate views
      viewNames.clear( );
      SubordinateViews::iterator    si;
      for( si=subordinateViews.begin(); si!=subordinateViews.end(); si++ ) {
            Value val;
            val.SetStringValue( (*si)->GetViewName( ) );
            if( !( lit = Literal::MakeLiteral( val ) ) ) {
                  delete newAd;
                  return( NULL );
            }
            viewNames.push_back( lit );
      }
      newAd->Insert(ATTR_SUBORDINATE_VIEWS,ExprList::MakeExprList(viewNames));
      

            // insert names of partitioned views
      viewNames.clear( );
      PartitionedViews::iterator    pi;
      for( pi = partitionedViews.begin( ); pi != partitionedViews.end( ); pi++ ) {
            Value val;
            val.SetStringValue( pi->second->GetViewName( ) );
            if( !( lit = Literal::MakeLiteral( val ) ) ) {
                  delete newAd;
                  return( NULL );
            }
            viewNames.push_back( lit );
      }
      newAd->Insert(ATTR_PARTITIONED_VIEWS,ExprList::MakeExprList(viewNames));


      return( newAd );
}


bool View::
SetConstraintExpr( ClassAdCollection *coll, const string &expr )
{
      ExprTree          *constraint;

            // parse the expression and insert it into ad in left context
      if( !coll->parser.ParseExpression( expr, constraint ) ) {
            CondorErrMsg += "; failed to set constraint on view";
            return( false );
      }
      return( SetConstraintExpr( coll, constraint ) );
}


bool View::
SetConstraintExpr( ClassAdCollection *coll, ExprTree *constraint )
{
      ClassAd                             *ad;
      ViewMembers::iterator   vmi;
      bool                          match;
      string                              key;

            // insert expression into ad in left context
      if( !( ad=evalEnviron.GetLeftAd() ) ||
            !ad->Insert( ATTR_REQUIREMENTS, constraint ) ) {
            CondorErrMsg += "; failed to set constraint on view";
            return( false );
      }

            // check if all members still belong to the view
      for( vmi = viewMembers.begin( ); vmi != viewMembers.end( ); vmi++ ) {
            vmi->GetKey( key );
            if( ( ad = coll->GetClassAd( key ) ) == NULL ) {
                  CLASSAD_EXCEPT( "internal error: classad in view but not in collection" );
            }
            evalEnviron.ReplaceRightAd( ad );
            match = evalEnviron.EvaluateAttrBool("RightMatchesLeft",match) && match;
            evalEnviron.RemoveRightAd( );
                  // if classad doesn't match constraint remove from view
            if( !match ) {
                  ClassAdDeleted( coll, key, ad );
            }
      }

      return( true );
}

bool View::
SetRankExpr( ClassAdCollection *coll, const string &expr )
{
      ExprTree    *rank;

            // parse the expression and insert it into ad in left context
      if( !coll->parser.ParseExpression( expr, rank ) ) {
            CondorErrMsg += "; failed to set rank on view";
            return( false );
      }
      return( SetRankExpr( coll, rank ) );
}


bool View::
SetRankExpr( ClassAdCollection *coll, ExprTree *rank )
{
      ClassAd                             *ad;
      ViewMember                    vm;
      MemberIndex::iterator   mIdxItr;
      ViewMembers::iterator   vmi;
      string                              key;
      Value                         rankValue;

            // insert expression into ad in left context
      if( !( ad=evalEnviron.GetLeftAd() ) ) {
            CLASSAD_EXCEPT( "internal error:  view has no view info" );
      }
      
      if( !ad->Insert( ATTR_RANK, rank ) ) {
            CondorErrMsg += "failed to set rank on view";
            return( false );
      }

            // clear out member list
      viewMembers.clear( );

            // re-order content by new rank expression
      for( mIdxItr=memberIndex.begin(); mIdxItr!=memberIndex.end(); mIdxItr++ ) {
            key = mIdxItr->first;
            if( ( ad = coll->GetClassAd( key ) ) == NULL    ||
                  !evalEnviron.ReplaceRightAd( ad )               ||
                  !evalEnviron.EvaluateAttr( "LeftRankValue", rankValue ) ) {
                        // internal error
                  CLASSAD_EXCEPT( "internal error:  could not determine 'Rank' value" );
            }

                  // insert into member list
            vm.SetKey( key );
            vm.SetRankValue( rankValue );
            viewMembers.insert( vm );
      }

            // now re-do the index
      memberIndex.clear( );
      for( vmi = viewMembers.begin( ); vmi != viewMembers.end( ); vmi++ ) {
            vmi->GetKey( key );
            memberIndex[key] = vmi;
      }

      return( true );
}


bool View::
SetPartitionExprs( ClassAdCollection *coll, const string &expr )
{
      ExprTree    *exprList=NULL;

            // parse the expression and insert it into ad in left context
      if( !coll->parser.ParseExpression( expr, exprList ) || 
                  (exprList->GetKind( ) != ExprTree::EXPR_LIST_NODE) ) {
            if( exprList ) delete exprList;
            CondorErrno = ERR_BAD_PARTITION_EXPRS;
            CondorErrMsg += "; failed to set partition expresssions";
            return( false );
      }
      
      return( SetPartitionExprs( coll, (ExprList*)exprList ) );
}


bool View::
SetPartitionExprs( ClassAdCollection *coll, ExprList *el )
{
            // insert expression list into view info
      ClassAd *ad = evalEnviron.GetLeftAd( );
      if( !el ) {
            CondorErrno = ERR_BAD_PARTITION_EXPRS;
            CondorErrMsg = "invalid 'PartitionExprs'; failed to partition";
            return( false );
      }
      if( !( ad->Insert( ATTR_PARTITION_EXPRS, el ) ) ) {
            CondorErrMsg += "failed to set partition expressions on view";
            return( false );
      }

            // re-establish partition views; first delete all partition views
      PartitionedViews::iterator  mi;
      for( mi = partitionedViews.begin( ); mi != partitionedViews.end( ); mi++ ) {
            mi->second->DeleteView( coll );
            delete mi->second;
      }
      partitionedViews.clear( );

            // if the partition expressions list is empty, we're done
      vector<ExprTree*> components;
      el->GetComponents( components );
      if( components.size( ) == 0 ) return( true );
      
            // re-partition content
      ViewMembers::iterator   vmi;
      string                              key, signature;
      View                          *partition;

      for( vmi = viewMembers.begin( ); vmi != viewMembers.end( ); vmi++ ) {
                  // get signature of this ad
            vmi->GetKey( key );
            if( ( ad = coll->GetClassAd( key ) ) == NULL ) {
                  CLASSAD_EXCEPT( "internal error:  classad %s in view but not in collection",
                        key.c_str( ) );
            }
            signature = makePartitionSignature( ad );

                  // check if we have a partition with this signature
            if( partitionedViews.find( signature ) == partitionedViews.end( ) ) {
                        // no partition ... make a new one
                  if( ( partition = new View( this ) ) == NULL ) {
                        CondorErrno = ERR_MEM_ALLOC_FAILED;
                        CondorErrMsg = "";
                        return( false );
                  }
                  if( !coll->RegisterView( viewName + ":" + signature, partition ) ) {
                        CondorErrMsg += "; could not complete partitioning";
                        return( false );
                  }
                  partition->SetViewName( viewName + ":" + signature );
                  partitionedViews[signature] = partition;
            } else {
                        // use the partition that's already there
                  partition = partitionedViews[signature];
            }

                  // add classad to the partition
            if( !partition->ClassAdInserted( coll, key, ad ) ) {
                  CondorErrMsg += "; failed to set partition expressions";
                  return( false );
            }
      }

      return( true );
}


ExprTree *View::
GetConstraintExpr( )
{
      ClassAd           *lAd;
      ExprTree    *tree;
            // get requirements expression from ad in left context
      if( !(lAd = evalEnviron.GetLeftAd( ) ) ) {
            CLASSAD_EXCEPT( "internal error:  no view info in view" );
      }
      if( !(tree = lAd->Lookup( ATTR_REQUIREMENTS ) ) ) {
            CondorErrno = ERR_NO_REQUIREMENTS_EXPR;
            CondorErrMsg = "no 'Requirements' expression in view info";
            return( (ExprTree*) NULL );
      }
      return( tree );
}


ExprTree *View::
GetRankExpr( )
{
      ClassAd           *lAd;
      ExprTree    *tree;
            // get rank expression from ad in left context
      if( !(lAd = evalEnviron.GetLeftAd( ) ) ) {
            CLASSAD_EXCEPT( "internal error:  no view info in view" );
      }
      if( !(tree = lAd->Lookup( ATTR_RANK ) ) ) {
            CondorErrno = ERR_NO_RANK_EXPR;
            CondorErrMsg = "no 'Rank' expression in view info";
            return( (ExprTree*) NULL );
      }
      return( tree );
}



bool View::
IsMember( const string &key )
{
      return( memberIndex.find( key ) != memberIndex.end( ) );
}


bool View::
FindPartition( ClassAd *rep, ViewName &partition )
{
      PartitionedViews::iterator    itr;
      string sig = makePartitionSignature( rep );

      if( sig.empty( ) || sig == "ERROR" || 
                  ( itr = partitionedViews.find( sig ) ) == partitionedViews.end( ) ){
            CondorErrno = ERR_NO_SUCH_VIEW;
            CondorErrMsg = "no partition matching representative found";
            return( false );
      }
      partition = itr->second->GetViewName( );
      return( true );
}


bool View::
InsertSubordinateView( ClassAdCollection *coll, ClassAd *viewInfo )
{
      View                          *newView = new View( this );
      ViewMembers::iterator   vmi;
      string                              key;
      ClassAd                             *ad;
      string                              name;;

      if( !newView ) {
            CondorErrno = ERR_MEM_ALLOC_FAILED;
            CondorErrMsg = "";
            return( false );
      }

      if( viewInfo ) {
            viewInfo->EvaluateAttrString( ATTR_VIEW_NAME, name );
            newView->evalEnviron.ReplaceLeftAd( viewInfo );
      } 

      newView->SetViewName( name );
      if( !coll->RegisterView( name, newView ) ) {
            CondorErrMsg += "; failed to insert new view";
            delete newView;
            return( false );
      }
      subordinateViews.push_front( newView );

            // insert current view content into new view
      for( vmi = viewMembers.begin( ); vmi != viewMembers.end( ); vmi++ ) {
            vmi->GetKey( key );
            if( ( ad = coll->GetClassAd( key ) ) == NULL ) {
                  CLASSAD_EXCEPT( "internal error:  classad %s in view but not in collection",
                        key.c_str( ) );
            }
            if( !newView->ClassAdInserted( coll, key, ad ) ) {
                  CondorErrMsg += "; failed to insert content into new view";
                  return( false );
            }
      }

      return( true );
}


bool View::
InsertPartitionedView( ClassAdCollection *coll, ClassAd *viewInfo, 
      ClassAd *rep )
{
      string      signature;
      View  *partition;
      string      tmp;

      signature = makePartitionSignature( rep );
      delete rep;

            // must have a partitioning
      if( signature.empty( ) ) {
            delete viewInfo;
            CondorErrno = ERR_BAD_PARTITION_EXPRS;
            CondorErrMsg = "missing or bad partition expressions; cannot add "
                  "partition";
            return( false );
      }

            // check if a partition with the given signature already exists
      if( partitionedViews.find( signature ) != partitionedViews.end( ) ) {
                  // partition already exists
            delete viewInfo;
            CondorErrno = ERR_PARTITION_EXISTS;
            CondorErrMsg = "partition " + signature + " already exists";
            return( false );
      }
            // create new partition
      if( ( partition = new View( this ) ) == NULL ) {
            CondorErrno = ERR_MEM_ALLOC_FAILED;
            CondorErrMsg = "";
            return( false );
      }

      if( viewInfo && viewInfo->EvaluateAttrString( ATTR_VIEW_NAME, tmp ) ) {
            partition->SetViewName( tmp );
            if( !coll->RegisterView( tmp, partition ) ) {
                  delete viewInfo;
                  delete partition;
                  CondorErrMsg += "; failed to add partition " + tmp;
                  return( false );
            }
      } else {
            partition->SetViewName( viewName + ":" + signature );
            if( !coll->RegisterView( viewName + ":" + signature, partition ) ) {
                  delete viewInfo;
                  delete partition;
                  CondorErrMsg += "; failed to add partition " + tmp;
                  return( false );
            }
      }

            // enter into hash_map
      partitionedViews[signature] = partition;

            // setup view info of partition
      if( viewInfo ) {
            partition->evalEnviron.ReplaceLeftAd( viewInfo );
      } 

            // NOTE:  since this is a partition which hasn't been created 
            // previously, none of the classads in this view need be inserted
            // into the new partition
      return( true );
}


bool View::
DeleteChildView( ClassAdCollection *coll, const ViewName &vName )
{
      if( !DeleteSubordinateView( coll, vName ) && 
                  !DeletePartitionedView( coll, vName ) ) {
            return( false );
      }
      CondorErrno = ERR_OK;
      CondorErrMsg = "";
      return( true );
}


bool View::
DeleteSubordinateView( ClassAdCollection *coll, const ViewName &vName )
{
      SubordinateViews::iterator    xi;

      for( xi = subordinateViews.begin( ); xi != subordinateViews.end( ); xi++ ) {
            if( (*xi)->GetViewName( ) == vName ) {
                  (*xi)->DeleteView( coll );
                  delete (*xi);
                  subordinateViews.erase( xi );
                  return( true );
            }
      }
      CondorErrno = ERR_NO_SUCH_VIEW;
      CondorErrMsg = "no child view named " + vName + " in view";
      return( false );
}


bool View::
DeletePartitionedView( ClassAdCollection *coll, const ViewName &vName )
{
      PartitionedViews::iterator    mi;

      for( mi = partitionedViews.begin( ); mi != partitionedViews.end( ); mi++ ) {
            if( mi->second->GetViewName( ) == vName ) {
                        // check if the partition is non-empty ...
                  if( mi->second->Size( ) != 0 ) {
                              // remove all child views and reset view info
                        View                                *view = mi->second;
                        SubordinateViews::iterator    svi;
                        PartitionedViews::iterator    pvi;

                              // delete subordinate views
                        for( svi = view->subordinateViews.begin( ); 
                                    svi != view->subordinateViews.end( ); svi++ ) {
                              (*svi)->DeleteView( coll );
                              delete (*svi);
                        }
                        view->subordinateViews.clear( );

                              // delete partitioned views
                        for( pvi = view->partitionedViews.begin( ); 
                                    pvi != view->partitionedViews.end( ); pvi++ ) {
                              pvi->second->DeleteView( coll );
                              delete pvi->second;
                        }
                        view->partitionedViews.clear( );

                              // reset name of view
                        coll->UnregisterView( vName );
                        coll->RegisterView( viewName + ":" + mi->first, view );

                              // reset other view info
                        vector<ExprTree*> vec;
                        ClassAd *ad = new ClassAd( );
                        if( !ad ) {
                              CondorErrno = ERR_MEM_ALLOC_FAILED;
                              CondorErrMsg = "";
                              return( false );
                        }
                        if( !ad->InsertAttr( ATTR_REQUIREMENTS, true )  ||
                                    !ad->InsertAttr( ATTR_RANK, 0 )                       ||
                                    !ad->Insert(ATTR_PARTITION_EXPRS,
                                          ExprList::MakeExprList( vec ) )     ||
                                    !view->SetViewInfo( coll, ad ) ) {
                              CondorErrMsg += "; failed to delete partition view " +
                                    vName;
                              return( false );
                        }
                        return( true );
                  }

                        // empty partition ... can just delete it
                  mi->second->DeleteView( coll );
                  delete mi->second;
                  partitionedViews.erase( mi );
                  return( true );
            }
      }
      CondorErrno = ERR_NO_SUCH_VIEW;
      CondorErrMsg = "no partition child view named " + vName + " in view";
      return( false );
}


void View::
DeleteView( ClassAdCollection *coll )
{
      SubordinateViews::iterator    si;
      PartitionedViews::iterator    pi;

      coll->UnregisterView( viewName );

      for( si = subordinateViews.begin( ); si != subordinateViews.end( ); si++ ) {
            (*si)->DeleteView( coll );
            delete (*si);
      }

      for( pi = partitionedViews.begin( ); pi != partitionedViews.end( ); pi++ ) {
            pi->second->DeleteView( coll );
            delete pi->second;
      }
}



bool View::
DeletePartitionedView( ClassAdCollection *coll, ClassAd *rep )
{
      string signature = makePartitionSignature( rep );

      if( signature.empty( ) ) {
            CondorErrno = ERR_NO_SUCH_VIEW;
            CondorErrMsg = "no partition corresponds to representative";
            return( false );
      }

      ViewName vName = viewName + ":" + signature;
      return( DeletePartitionedView( coll, vName ) );
}


// The convention is that each view verifies its constraint before accepting
// an ad.  However, the view assumes that in the case of view partitions, the
// parent view will have identified the correct child partition to use.
bool View::
ClassAdInserted( ClassAdCollection *coll, const string &key, 
      ClassAd *ad )
{
      PartitionedViews::iterator    partition;
      string                                    signature;
      ViewMember                          vm;
      bool                                match;
      Value                               rankValue;
      View                                *childView;

            // check if the ad satisfies the view's constraint; if the constraint 
            // was not satisfied, the ad can be ignored
      evalEnviron.ReplaceRightAd( ad );
      match = evalEnviron.EvaluateAttrBool("RightMatchesLeft",match) && match;
      if( !match ) {
            evalEnviron.RemoveRightAd( );
            return( true );
      }

            // obtain the rank value of the ad
      if( !evalEnviron.EvaluateAttr( "LeftRankValue", rankValue ) ) {
            CondorErrMsg += "; could not get 'Rank' value; failed to insert "
                  "classad " + key + "in view " + viewName;
            return( false );
      }
      evalEnviron.RemoveRightAd( );

            // insert into every subordinate child view
      SubordinateViews::iterator    xi;
      for( xi = subordinateViews.begin( ); xi != subordinateViews.end( ); xi++ ) {
            if( !(*xi)->ClassAdInserted( coll, key, ad ) ) {
                  return( false );
            }
      }

            // find partition to insert into
      signature = makePartitionSignature( ad );
      if( !signature.empty( ) ) {
            partition = partitionedViews.find( signature );
            if( partition == partitionedViews.end( ) ) {
                        // no appropriate partition --- create one and insert
                  if( ( childView = new View( this ) ) == 0 ) {
                        CondorErrno = ERR_MEM_ALLOC_FAILED;
                        CondorErrMsg = "";
                        return( false );
                  }

                  if( !coll->RegisterView( viewName + ":" + signature, childView ) ) {
                        if( childView ) delete childView;
                        CondorErrMsg += "; failed to create view; failed to insert "
                              "classad " + key + "in view";
                        return( false );
                  }
                  childView->SetViewName( viewName + ":" + signature );
                  partitionedViews[signature] = childView;
            } else {
                  childView = partitionedViews[signature];
            }

                  // update the partition
            if( !childView->ClassAdInserted( coll, key, ad ) ) {
                  return( false );
            }
      }

            // insert ad into list of view members and update index
      vm.SetKey( key );
      vm.SetRankValue( rankValue );
      memberIndex[key] = viewMembers.insert(vm);

      return( true );
}



void View::
ClassAdPreModify( ClassAdCollection *coll, ClassAd *ad )
{
      SubordinateViews::iterator    xi;
      PartitionedViews::iterator    mi;
      
            // stash signature of ad
      oldAdSignature = makePartitionSignature( ad );

            // perform premodify on all subordinate children ...
      for( xi = subordinateViews.begin( ); xi != subordinateViews.end( ); xi++ ) {
            (*xi)->ClassAdPreModify( coll, ad );
      }

            // ... and partition children
      for( mi = partitionedViews.begin( ); mi != partitionedViews.end( ); mi++ ) {
            mi->second->ClassAdPreModify( coll, ad );
      }

}


bool View::
ClassAdModified( ClassAdCollection *coll, const string &key, 
      ClassAd *mad )
{
      bool  match, wasMember, sameRank, rval = true;
      Value rankValue, oldAdRank, equal;
      MemberIndex::iterator   itr = memberIndex.find( key );

            // check if classad is currently a member of this view
      if( itr == memberIndex.end( ) ) {
            wasMember = false;
      } else {
            wasMember = true;
            ((ViewMember) *(itr->second)).GetRankValue( oldAdRank );
      }

            // evaluate constraint and get new rank value
      evalEnviron.ReplaceRightAd( mad );
      match = evalEnviron.EvaluateAttrBool("RightMatchesLeft",match) && match;
      if( !evalEnviron.EvaluateAttr( "LeftRankValue", rankValue ) ) {
            rankValue.SetUndefinedValue( );
      }
      evalEnviron.RemoveRightAd( );

      if( wasMember && match ) {
            string      sig;
                  // was and still is a member; check if rank has changed
            Operation::Operate( Operation::IS_OP, rankValue, oldAdRank, equal );
            if( !equal.IsBooleanValue( sameRank ) || !sameRank ) {
                        // rank changed ... need to re-order
                  ViewMember  vm;

                        // remove old view member ...
                  vm.SetRankValue( oldAdRank );
                  vm.SetKey(key);
                  viewMembers.erase( vm );
                        // re-insert with new rank value and update member index
                  vm.SetRankValue( rankValue );
                  memberIndex[key] = viewMembers.insert( vm );
            }

                  // check if the signature has changed
            sig = makePartitionSignature( mad );
            if( sig != oldAdSignature ) {
                  PartitionedViews::iterator    mi;
                  View                                *newPartition;
                        // yes ... remove from old partition and insert into new
                  if( !oldAdSignature.empty( ) ) {
                        mi = partitionedViews.find( oldAdSignature );
                        if( mi == partitionedViews.end( ) ) {
                                    // partition of ad not found; some internal error
                              CLASSAD_EXCEPT( "internal error:  partition of classad with "
                                    "signature %s not found", oldAdSignature.c_str( ) );
                        }
                              // delete from old partition
                        mi->second->ClassAdDeleted( coll, key, mad );
                  }

                        // is there a partition with the new signature?
                  if( !sig.empty( ) ) {
                        mi = partitionedViews.find( sig );
                        if( mi != partitionedViews.end( ) ) {
                                    // yes ... insert into this partition
                              if( !mi->second->ClassAdInserted(coll, key, mad) ) {
                                    CondorErrMsg+="; failed to relocate ad on modification";
                                    return( false );
                              }
                        } else {
                                    // no ... create a new partition
                              if( ( newPartition = new View( this ) ) == 0 ) {
                                    oldAdSignature.erase( oldAdSignature.begin( ), 
                                          oldAdSignature.end( ) );
                                    CondorErrno = ERR_MEM_ALLOC_FAILED;
                                    CondorErrMsg = "";
                                    return( false );
                              } 
                              if( !coll->RegisterView( viewName+":"+sig, newPartition ) ){
                                    delete newPartition;
                                    CondorErrMsg += "; failed to create new partition for "
                                          " modified ad";
                                    return( false );
                              }
                              newPartition->SetViewName( viewName + ":" + sig );
                              if( !newPartition->ClassAdInserted(coll, key, mad) ) {
                                    CondorErrMsg+="; failed to relocate ad on modification";
                                    return( false );
                              }
                              partitionedViews[sig] = newPartition;
                        }
                  }
            }

                  // send modification notification to all subordinate children
            SubordinateViews::iterator xi;
            for( xi=subordinateViews.begin( ); xi!=subordinateViews.end( ); xi++ ){
                  if( !(*xi)->ClassAdModified( coll, key, mad ) ) {
                        return( false );
                  }
            }
      } else if( !wasMember && match ) {
                  // wasn't a member, but now is --- insert the ad
            rval = ClassAdInserted( coll, key, mad );
      } else if( wasMember && !match ) {
                  // was a member, but now isnt --- delete the ad
            ClassAdDeleted( coll, key, mad );
            rval = true;
      } else {
            // wasn't a member and still isn't --- nothing to do
      }

      oldAdSignature.erase( oldAdSignature.begin( ), oldAdSignature.end( ) );
      if( !rval ) {
            CondorErrMsg += "; failed to modify ad";
      }
      return( rval );
}


void View::
ClassAdDeleted( ClassAdCollection *coll, const string &key, 
      ClassAd *ad )
{
      ViewMembers::iterator   vmi;

            // check if the classad is in the view
      if( memberIndex.find( key ) == memberIndex.end( ) ) {
                  // not in view; nothing to do
            return;
      }

            // delete from member index and member list
      vmi = memberIndex[key];
      memberIndex.erase( key );
      viewMembers.erase( vmi );

            // delete from every subordinate child view
      SubordinateViews::iterator    xi;
      for( xi = subordinateViews.begin( ); xi != subordinateViews.end( ); xi++ ) {
            (*xi)->ClassAdDeleted( coll, key, ad );
      }

            // delete from partition view
      string signature = makePartitionSignature( ad );
      if( !signature.empty( ) ) {
            PartitionedViews::iterator mi = partitionedViews.find( signature );
            if( mi == partitionedViews.end( ) ) {
                        // an internal error
                  CLASSAD_EXCEPT( "classad %s doesn't have a partition", signature.c_str( ) );
            }

                  // delete from the partition
            mi->second->ClassAdDeleted( coll, key, ad );
      }
}


string View::
makePartitionSignature( ClassAd *ad )
{
      ClassAdUnParser         unparser;
      ExprListIterator  itr;
      string                        signature;
    Value                     value;
      ClassAd                       *oad, *info;
      const ExprList          *el = NULL;

            // stash the old ad from the environment and insert the new ad in
      oad = evalEnviron.RemoveRightAd( );
      evalEnviron.ReplaceRightAd( ad );
      if( !( info = evalEnviron.GetLeftAd( ) ) ) {
            CLASSAD_EXCEPT( "internal error:  view doesn't have view info" );
      }
      vector<ExprTree*> exprs;
      if( !info->EvaluateAttr( ATTR_PARTITION_EXPRS, value ) ||
                  !value.IsListValue( el ) ) {
            evalEnviron.RemoveRightAd( );
            return( string( "" ) );
      }
      el->GetComponents( exprs );
      if( exprs.size( ) == 0 ) {
            evalEnviron.RemoveRightAd( );
            return( string( "" ) );
      }

            // go through the expression list and form a value vector
      signature = "<|";
      itr.Initialize( el );
      while( !itr.IsAfterLast( ) ) {
            itr.CurrentValue( value );
            unparser.Unparse( signature, value );
            signature += "|";
            itr.NextExpr( );
    }
      signature += ">";

            // put the old ad back in the environmnet
      evalEnviron.RemoveRightAd( );
      evalEnviron.ReplaceRightAd( oad );

            // return the computed signature
    return( signature );
}


bool View::
Display( FILE *file )
{
      ViewMembers::iterator   vmi;
      ClassAdUnParser               unparser;
      Value                         val;
      ClassAd                             *viewInfo;
      string                              buf;

            // display view info
      if( !( viewInfo = GetViewInfo( ) ) ) return( false );
      unparser.Unparse( buf, viewInfo );
      fprintf( file, "%s\n", buf.c_str( ) );
      delete viewInfo;

      for( vmi = viewMembers.begin( ); vmi != viewMembers.end( ); vmi++ ) {
            vmi->GetKey( buf );
            vmi->GetRankValue( val );
            buf += ": ";
            unparser.Unparse( buf, val );
            fprintf( file, "%s\n", buf.c_str() );
      }

      return( true );
}

void View::
GetSubordinateViewNames( vector<string>& views )
{
      SubordinateViews::iterator    itr;

      views.clear( );
      for( itr=subordinateViews.begin( ); itr!=subordinateViews.end( ); itr++ ) {
            views.push_back( (*itr)->GetViewName( ) );
      }
}

void View::
GetPartitionedViewNames( vector<string>& views )
{
      PartitionedViews::iterator    itr;

      views.clear( );
      for( itr=partitionedViews.begin( ); itr!=partitionedViews.end( ); itr++ ) {
            views.push_back( itr->second->GetViewName( ) );
      }
}


bool ViewMemberLT::
operator()( const ViewMember &vm1, const ViewMember &vm2 ) const
{
      bool                lessThan;

      lessThan = vm1 < vm2;

      return lessThan;
}

END_NAMESPACE

Generated by  Doxygen 1.6.0   Back to index