diff options
21 files changed, 1557 insertions, 408 deletions
diff --git a/TAO/orbsvcs/orbsvcs/LB_LeastLoaded.inl b/TAO/orbsvcs/orbsvcs/LB_LeastLoaded.inl index d2d3dc420cd..cb650c93ba0 100644 --- a/TAO/orbsvcs/orbsvcs/LB_LeastLoaded.inl +++ b/TAO/orbsvcs/orbsvcs/LB_LeastLoaded.inl @@ -2,19 +2,6 @@ // // $Id$ -ACE_INLINE CORBA::Float -TAO_LB_LeastLoaded::raw_load (CORBA::Float load) -{ - return this->dampened_load (load + this->per_balance_load_); -} - - -ACE_INLINE CORBA::Float -TAO_LB_LeastLoaded::raw_load (CORBA::Float load) -{ - return this->dampened_load (load + this->per_balance_load_); -} - ACE_INLINE CORBA::Float TAO_LB_LeastLoaded::effective_load (CORBA::Float previous_load, @@ -29,8 +16,8 @@ TAO_LB_LeastLoaded::effective_load (CORBA::Float previous_load, ACE_ASSERT (this->tolerance_ != 0); - // Compute th effective load. - result = raw_load / this->tolerance_; + // Compute the effective load. + result /= this->tolerance_; return result; } diff --git a/TAO/orbsvcs/orbsvcs/LB_LoadAlert.inl b/TAO/orbsvcs/orbsvcs/LB_LoadAlert.inl new file mode 100644 index 00000000000..2099eae3096 --- /dev/null +++ b/TAO/orbsvcs/orbsvcs/LB_LoadAlert.inl @@ -0,0 +1,15 @@ +// -*- C++ -*- +// +// $Id$ + +ACE_INLINE CORBA::Boolean +TAO_LB_LoadAlert::alerted (void) const +{ + return this->alerted_; +} + +ACE_INLINE CORBA::Object_ptr +TAO_LB_LoadAlert::forward (void) +{ + return CORBA::Object::_duplicate (this->forward_.in ()); +} diff --git a/TAO/orbsvcs/orbsvcs/LoadBalancing/LB_LeastLoaded.cpp b/TAO/orbsvcs/orbsvcs/LoadBalancing/LB_LeastLoaded.cpp index 6ff77419e3a..28a2b745f27 100644 --- a/TAO/orbsvcs/orbsvcs/LoadBalancing/LB_LeastLoaded.cpp +++ b/TAO/orbsvcs/orbsvcs/LoadBalancing/LB_LeastLoaded.cpp @@ -1,6 +1,7 @@ // -*- C++ -*- #include "LB_LeastLoaded.h" +#include "LB_LoadMap.h" #include "orbsvcs/PortableGroup/PG_conf.h" #include "tao/debug.h" @@ -20,30 +21,34 @@ TAO_LB_LeastLoaded::TAO_LB_LeastLoaded (CORBA::Float critical_threshold, CORBA::Float dampening, CORBA::Float per_balance_load) : load_map_ (0), - lock_ (), - critical_threshold_ (0), - reject_threshold_ (0), - tolerance_ (1), - dampening_ (0), - per_balance_load_ (0) + lock_ (0), + critical_threshold_ (critical_threshold), + reject_threshold_ (reject_threshold), + tolerance_ (tolerance == 0 ? 1 : tolerance), + dampening_ (dampening), + per_balance_load_ (per_balance_load) { // A load map that retains previous load values at a given location - // is only needed if dampening is enabled, i.e. non-zero. + // and lock are only needed if dampening is enabled, i.e. non-zero. if (this->dampening_ != 0) - ACE_NEW (this->load_map_, - LoadMap (TAO_PG_MAX_LOCATIONS)); + { + ACE_NEW (this->load_map_, TAO_LB_LoadMap (TAO_PG_MAX_LOCATIONS)); + + ACE_NEW (this->lock_, TAO_SYNCH_MUTEX); + } } TAO_LB_LeastLoaded::~TAO_LB_LeastLoaded (void) { delete this->load_map_; + delete this->lock_; } char * TAO_LB_LeastLoaded::name (ACE_ENV_SINGLE_ARG_DECL_NOT_USED) ACE_THROW_SPEC ((CORBA::SystemException)) { - return CORBA::string_dup ("TAO_LB_LeastLoaded"); + return CORBA::string_dup ("LeastLoaded"); } CosLoadBalancing::Properties * @@ -74,14 +79,35 @@ TAO_LB_LeastLoaded::push_loads ( if (loads.length () == 0) ACE_THROW (CORBA::BAD_PARAM ()); + CosLoadBalancing::Load load; // Unused + + this->push_loads (the_location, + loads, + load + ACE_ENV_ARG_PARAMETER); +} + +void +TAO_LB_LeastLoaded::push_loads ( + const PortableGroup::Location & the_location, + const CosLoadBalancing::LoadList & loads, + CosLoadBalancing::Load & load + ACE_ENV_ARG_DECL) +{ + if (loads.length () == 0) + ACE_THROW (CORBA::BAD_PARAM ()); + + // Only the first load is used by this load balancing strategy. const CosLoadBalancing::Load & new_load = loads[0]; if (this->load_map_ != 0) { - TAO_LB_LoadMap::ENTRY * load; - if (this->load_map_->find (the_location, load) == 0) + ACE_GUARD (TAO_SYNCH_MUTEX, guard, *this->lock_); + + TAO_LB_LoadMap::ENTRY * entry; + if (this->load_map_->find (the_location, entry) == 0) { - CosLoadBalancing::Load & previous_load = load->int_id_; + CosLoadBalancing::Load & previous_load = entry->int_id_; if (previous_load.id != new_load.id) ACE_THROW (CORBA::BAD_PARAM ()); // Somebody switched @@ -89,13 +115,15 @@ TAO_LB_LeastLoaded::push_loads ( previous_load.value = this->effective_load (previous_load.value, new_load.value); + + load = previous_load; } else { const CosLoadBalancing::Load eff_load = { new_load.id, - this->effective_load (0, new_load.value); + this->effective_load (0, new_load.value) }; if (this->load_map_->bind (the_location, eff_load) != 0) @@ -107,10 +135,17 @@ TAO_LB_LeastLoaded::push_loads ( ACE_THROW (CORBA::INTERNAL ()); } + + load = eff_load; } } + else + { + load.id = new_load.id; + load.value = this->effective_load (0, new_load.value); + } } - + CORBA::Object_ptr TAO_LB_LeastLoaded::next_member ( PortableGroup::ObjectGroup_ptr object_group, @@ -138,7 +173,10 @@ TAO_LB_LeastLoaded::next_member ( PortableGroup::Location location; CORBA::Boolean found_location = - this->get_location (locations.in (), location); + this->get_location (object_group, + load_manager, + locations.in (), + location); if (found_location) { @@ -154,89 +192,9 @@ TAO_LB_LeastLoaded::next_member ( } } -void -TAO_LB_LeastLoaded::analyze_loads ( - PortableGroup::ObjectGroup_ptr object_group, - CosLoadBalancing::LoadManager_ptr load_manager - ACE_ENV_ARG_DECL) - ACE_THROW_SPEC ((CORBA::SystemException)) -{ - int send_load_advisory = 0; - - { - ACE_GUARD (TAO_SYNCH_MUTEX, guard, this->lock_); - - - TAO_LB_Location_Map::iterator begin = - location_map.begin (); - - TAO_LB_Location_Map::iterator end = - location_map.end (); - - float s = 0; - CORBA::ULong n = 0; - TAO_LB_Location_Map::iterator i = begin; - for ( ; i != end; ++i) - { - s += (*i)->int_id_.load_list[0].value; // @@ Hard coded to - // get things - // going. - n++; - } - - float avg = (n == 0 ? s : s / n); - float cl = proxy->current_load (); - - if (avg == 0) - return; - - float relative_load = cl / avg; - - // @@ Ossama: Make the 1.5 factor adjustable, it is how much - // dispersion we tolerate before starting to send advisories. - if (relative_load > 1 + 1.5F / n) - { - proxy->has_high_load_ = 1; - send_load_advisory = 2; // 2 == Send high load advisory - } - - if (send_load_advisory == 1 && relative_load < 1 + 0.9F / n) - { - proxy->has_high_load_ = 0; - send_load_advisory = 1; // 1 == Send nominal load advisory - } - } - - // @@ Ossama: no debug messages in production code, my fault.... - // ACE_DEBUG ((LM_DEBUG, "Load[%x] %f %f %f\n", - // proxy, cl, avg, relative_load)); - - // @@ Ossama: Make the 1.5 factor adjustable, it is how much - // dispersion we tolerate before starting to send advisories. - if (send_load_advisory == 2) - { - proxy->control_->high_load_advisory (ACE_ENV_SINGLE_ARG_PARAMETER); - ACE_CHECK; - - return; // We may not throw an exception, so explicitly return. - } - - // @@ Ossama: notice that we wait until the load is signifcantly - // lower before sending the nominal load advisory, it does not - // matter that much because the replicas automatically restart after - // rejecting one client.... - // @@ Ossama: make the 0.9 factor adjustable, at least at - // construction time... - if (send_load_advisory == 1) - { - proxy->control_->nominal_load_advisory (ACE_ENV_SINGLE_ARG_PARAMETE); - ACE_CHECK; - } - -} - CORBA::Boolean TAO_LB_LeastLoaded::get_location ( + PortableGroup::ObjectGroup_ptr object_group, const CosLoadBalancing::LoadManager_ptr load_manager, const PortableGroup::Locations & locations, PortableGroup::Location & location) @@ -247,196 +205,59 @@ TAO_LB_LeastLoaded::get_location ( const CORBA::ULong len = locations.length (); - { - ACE_GUARD_RETURN (TAO_SYNCH_MUTEX, - guard, - this->lock_, - 0); - - for (CORBA::ULong i = 0; i < len; ++i) - { - const PortableGroup::Location & loc = locations[i]; - - // Retrieve the load list for the location from the - // LoadManager and push it to this Strategy's load processor. - CosLoadBalancing::LoadList_var current_loads = - load_manager->get_loads (loc - ACE_ENV_ARG_PARAMETER); - ACE_TRY_CHECK; - - this->push_loads (loc, - current_loads.in () - ACE_ENV_ARG_PARAMETER); - ACE_TRY_CHECK; - - // WRONG!!! THIS IS LEAST LOADED, NOT MINIMUM DISPERSION! - LoadMap::ENTRY * entry; - if (this->load_map_.find (locations[i], entry) == 0 - && (i == 0 || entry.value < min_load)) - { - min_load = entry->value; - location_index = i; - found_location = 1; - } - } - } - - if (found_location) - location = locations[location_index]; - - return found_location; -} - -CORBA::Object_ptr -TAO_LB_LeastLoaded::replica ( - TAO_LB_ObjectGroup_Map_Entry *entry - ACE_ENV_ARG_DECL) - ACE_THROW_SPEC ((CORBA::SystemException)) -{ - for ( ; ; ) + for (CORBA::ULong i = 0; i < len; ++i) { - ACE_GUARD_RETURN (TAO_SYNCH_MUTEX, - guard, - entry->lock, - CORBA::Object::_nil ()); - - if (entry->replica_infos.is_empty ()) - // @@ What do we do if the set is empty? - ACE_THROW_RETURN (CORBA::OBJECT_NOT_EXIST (), - CORBA::Object::_nil ()); - - TAO_LB_ReplicaInfo_Set::iterator begin = entry->replica_infos.begin (); - TAO_LB_ReplicaInfo_Set::iterator end = entry->replica_infos.end (); - - TAO_LB_ReplicaInfo_Set::iterator i = begin; - TAO_LB_ReplicaInfo *replica_info = (*i); - - LoadBalancing::LoadList *d = - replica_info->location_entry->load_list.ptr (); - - for (++i ; i != end; ++i) + const PortableGroup::Location & loc = locations[i]; + + // Retrieve the load list for the location from the LoadManager + // and push it to this Strategy's load processor. + CosLoadBalancing::LoadList_var current_loads = + load_manager->get_loads (loc + ACE_ENV_ARG_PARAMETER); + ACE_TRY_CHECK; + + CosLoadBalancing::Load load; + this->push_loads (loc, + current_loads.in (), + load + ACE_ENV_ARG_PARAMETER); + ACE_TRY_CHECK; + + if (load.value < this->reject_threshold_ + && (i == 0 || load.value < min_load)) { - LoadBalancing::LoadList *load = - (*i)->location_entry->load_list.ptr (); - - // @@ Hardcode one load and don't bother checking the - // LoadId, for now. (just to get things going) - if ((*d)[CORBA::ULong (0)].value > (*load)[CORBA::ULong (0)].value) - { - replica_info = *i; - d = (*i)->location_entry->load_list.ptr (); - } + min_load = load.value; + location_index = i; + found_location = 1; + } + else if (load.value > this->critical_threshold_) + { + // The location is overloaded. Perform load shedding by + // informing the LoadAlert object associated with the member + // at that location it should redirect client requests back + // to the LoadManager. + // + // AMI is used to improve member selection times and overall + // throughput since the LoadAlert object need not be alerted + // synchronously. In particular, the load alert can and + // should be performed in parallel to the member selection. + load_manager->enable_alert (object_group, + loc + ACE_ENV_ARG_PARAMETER); + ACE_TRY_CHECK; + } + else if (load.value <= this->critical_threshold_) + { + // The location is not overloaded + load_manager->disable_alert (object_group, + loc + ACE_ENV_ARG_PARAMETER); + ACE_TRY_CHECK; } - - // Before returning an object reference to the client - // validate it first. - CORBA::Object_ptr object = replica_info->replica.in (); - - { - ACE_Reverse_Lock<TAO_SYNCH_MUTEX> reverse_lock (entry->lock); - - ACE_GUARD_RETURN (ACE_Reverse_Lock<TAO_SYNCH_MUTEX>, - reverse_guard, - reverse_lock, - CORBA::Object::_nil ()); - - // @@ Ossama: we should setup a timeout policy here... - ACE_TRY - { - CORBA::Boolean non_existent = - object->_non_existent (ACE_ENV_SINGLE_ARG_PARAMETER); - ACE_TRY_CHECK; - if (!non_existent) - { - return CORBA::Object::_duplicate (object); - } - } - ACE_CATCHANY - { - // @@ HACK! Do the right thing! - return CORBA::Object::_duplicate (object); - } - ACE_ENDTRY; - } } -} - -void -TAO_LB_LeastLoaded::analyze_loads ( - TAO_LB_Location_Map &location_map - ACE_ENV_ARG_DECL) -{ - int send_load_advisory = 0; - - { - ACE_MT (ACE_GUARD (TAO_SYNCH_MUTEX, - guard, - this->lock_)); - - - TAO_LB_Location_Map::iterator begin = - location_map.begin (); - - TAO_LB_Location_Map::iterator end = - location_map.end (); - - float s = 0; - CORBA::ULong n = 0; - TAO_LB_Location_Map::iterator i = begin; - for ( ; i != end; ++i) - { - s += (*i)->int_id_.load_list[0].value; // @@ Hard coded to - // get things - // going. - n++; - } - - float avg = (n == 0 ? s : s / n); - float cl = proxy->current_load (); - - if (avg == 0) - return; - - float relative_load = cl / avg; - - // @@ Ossama: Make the 1.5 factor adjustable, it is how much - // dispersion we tolerate before starting to send advisories. - if (relative_load > 1 + 1.5F / n) - { - proxy->has_high_load_ = 1; - send_load_advisory = 2; // 2 == Send high load advisory - } - - if (send_load_advisory == 1 && relative_load < 1 + 0.9F / n) - { - proxy->has_high_load_ = 0; - send_load_advisory = 1; // 1 == Send nominal load advisory - } - } - - // @@ Ossama: no debug messages in production code, my fault.... - // ACE_DEBUG ((LM_DEBUG, "Load[%x] %f %f %f\n", - // proxy, cl, avg, relative_load)); - - // @@ Ossama: Make the 1.5 factor adjustable, it is how much - // dispersion we tolerate before starting to send advisories. - if (send_load_advisory == 2) - { - proxy->control_->high_load_advisory (ACE_ENV_SINGLE_ARG_PARAMETER); - ACE_CHECK; - return; // We may not throw an exception, so explicitly return. - } + if (found_location) + location = locations[location_index]; - // @@ Ossama: notice that we wait until the load is signifcantly - // lower before sending the nominal load advisory, it does not - // matter that much because the replicas automatically restart after - // rejecting one client.... - // @@ Ossama: make the 0.9 factor adjustable, at least at - // construction time... - if (send_load_advisory == 1) - { - proxy->control_->nominal_load_advisory (ACE_ENV_SINGLE_ARG_PARAMETER); - ACE_CHECK; - } + return found_location; } diff --git a/TAO/orbsvcs/orbsvcs/LoadBalancing/LB_LeastLoaded.h b/TAO/orbsvcs/orbsvcs/LoadBalancing/LB_LeastLoaded.h index fd74cd698d3..25c2ae91240 100644 --- a/TAO/orbsvcs/orbsvcs/LoadBalancing/LB_LeastLoaded.h +++ b/TAO/orbsvcs/orbsvcs/LoadBalancing/LB_LeastLoaded.h @@ -22,10 +22,24 @@ # pragma once # endif /* ACE_LACKS_PRAGMA_ONCE */ -#include "orbsvcs/CosLoadBalancingS.h" +#include "orbsvcs/CosLoadBalancingC.h" #include "ace/Synch.h" +namespace TAO_LB +{ + /** + * @name Default LeastLoaded strategy parameters. + * + * Defaults defined by the Load Balancing specification. + */ + const CORBA::Float LL_DEFAULT_CRITICAL_THRESHOLD = 0; + const CORBA::Float LL_DEFAULT_REJECT_THRESHOLD = 0; + const CORBA::Float LL_DEFAULT_TOLERANCE = 1; + const CORBA::Float LL_DEFAULT_DAMPENING = 0; + const CORBA::Float LL_DEFAULT_PER_BALANCE_LOAD = 0; +} + /** * @class TAO_LB_LeastLoaded * @@ -34,16 +48,21 @@ * This load balancing strategy is designed to select an object group * member residing at a location with the smallest load. */ -class TAO_LoadBalancing_Export TAO_LB_LeastLoaded - : public virtual POA_CosLoadBalancing::Strategy +class TAO_LB_LeastLoaded + : public virtual CosLoadBalancing::Strategy, + public virtual CORBA::LocalObject { public: - typedef TAO_LB_LoadMap LoadMap; /// Constructor. - TAO_LB_LeastLoaded (void); - - /// Destructor + TAO_LB_LeastLoaded ( + CORBA::Float critical_threshold = TAO_LB::LL_DEFAULT_CRITICAL_THRESHOLD, + CORBA::Float reject_threshold = TAO_LB::LL_DEFAULT_REJECT_THRESHOLD, + CORBA::Float tolerance = TAO_LB::LL_DEFAULT_TOLERANCE, + CORBA::Float dampening = TAO_LB::LL_DEFAULT_DAMPENING, + CORBA::Float per_balance_load = TAO_LB::LL_DEFAULT_PER_BALANCE_LOAD); + + /// Destructor. ~TAO_LB_LeastLoaded (void); /** @@ -73,42 +92,42 @@ public: PortableGroup::ObjectGroupNotFound, PortableGroup::MemberNotFound)); - virtual void analyze_loads ( - PortableGroup::ObjectGroup_ptr object_group, - CosLoadBalancing::LoadManager_ptr load_manager - ACE_ENV_ARG_DECL_WITH_DEFAULTS) - ACE_THROW_SPEC ((CORBA::SystemException)); +// virtual void analyze_loads ( +// PortableGroup::ObjectGroup_ptr object_group, +// CosLoadBalancing::LoadManager_ptr load_manager +// ACE_ENV_ARG_DECL_WITH_DEFAULTS) +// ACE_THROW_SPEC ((CORBA::SystemException)); //@} protected: /// Retrieve the least loaded location from the given list of /// locations. - CORBA::Boolean get_location (const PortableGroup::Locations & locations, + CORBA::Boolean get_location (PortableGroup::ObjectGroup_ptr object_group, + CosLoadBalancing::LoadManager_ptr load_manager, + const PortableGroup::Locations & locations, PortableGroup::Location & location); - /// Return the effective load. CORBA::Float effective_load (CORBA::Float previous_load, CORBA::Float new_load); - /// - void push_load ( + /// Push the new load into this Strategy's load processor, and + /// return the corresponding effective load. + void push_loads ( const PortableGroup::Location & the_location, - const CosLoadBalancing::Load & new_load + const CosLoadBalancing::LoadList & loads, CosLoadBalancing::Load & effective_load - ACE_ENV_ARG_DECL) - ACE_THROW_SPEC ((CORBA::SystemException)); - + ACE_ENV_ARG_DECL); private: - /// Container that maps location to load list. - LoadMap load_map_; + /// Table that maps location to load list. + TAO_LB_LoadMap * load_map_; /// Lock used to ensure atomic access to state retained by this /// class. - TAO_SYNCH_MUTEX lock_; + TAO_SYNCH_MUTEX * lock_; CORBA::Float critical_threshold_; CORBA::Float reject_threshold_; diff --git a/TAO/orbsvcs/orbsvcs/LoadBalancing/LB_LeastLoaded.inl b/TAO/orbsvcs/orbsvcs/LoadBalancing/LB_LeastLoaded.inl index d2d3dc420cd..cb650c93ba0 100644 --- a/TAO/orbsvcs/orbsvcs/LoadBalancing/LB_LeastLoaded.inl +++ b/TAO/orbsvcs/orbsvcs/LoadBalancing/LB_LeastLoaded.inl @@ -2,19 +2,6 @@ // // $Id$ -ACE_INLINE CORBA::Float -TAO_LB_LeastLoaded::raw_load (CORBA::Float load) -{ - return this->dampened_load (load + this->per_balance_load_); -} - - -ACE_INLINE CORBA::Float -TAO_LB_LeastLoaded::raw_load (CORBA::Float load) -{ - return this->dampened_load (load + this->per_balance_load_); -} - ACE_INLINE CORBA::Float TAO_LB_LeastLoaded::effective_load (CORBA::Float previous_load, @@ -29,8 +16,8 @@ TAO_LB_LeastLoaded::effective_load (CORBA::Float previous_load, ACE_ASSERT (this->tolerance_ != 0); - // Compute th effective load. - result = raw_load / this->tolerance_; + // Compute the effective load. + result /= this->tolerance_; return result; } diff --git a/TAO/orbsvcs/orbsvcs/LoadBalancing/LB_LoadAlert.cpp b/TAO/orbsvcs/orbsvcs/LoadBalancing/LB_LoadAlert.cpp new file mode 100644 index 00000000000..c46a044c271 --- /dev/null +++ b/TAO/orbsvcs/orbsvcs/LoadBalancing/LB_LoadAlert.cpp @@ -0,0 +1,35 @@ +#include "LB_LoadAlert.h" + + +ACE_RCSID (LoadBalancer, + LB_LoadAlert, + "$Id$") + +#if !defined (__ACE_INLINE__) +# include "LB_LoadAlert.inl" +#endif /* __ACE_INLINE__ */ + +TAO_LB_LoadAlert::TAO_LB_LoadAlert (void) + : alerted_ (0), + forward_ () +{ +} + +TAO_LB_LoadAlert::~TAO_LB_LoadAlert (void) +{ +} + +void +TAO_LB_LoadAlert::enable_alert (CORBA::Object /* object_group */ + ACE_ENV_ARG_DECL_NOT_USED) + ACE_THROW_SPEC ((CORBA::SystemException)) +{ + this->alerted_ = 1; +} + +void +TAO_LB_LoadAlert::disable_alert (ACE_ENV_ARG_DECL_NOT_USED) + ACE_THROW_SPEC ((CORBA::SystemException)) +{ + this->alerted_ = 0; +} diff --git a/TAO/orbsvcs/orbsvcs/LoadBalancing/LB_LoadAlert.h b/TAO/orbsvcs/orbsvcs/LoadBalancing/LB_LoadAlert.h new file mode 100644 index 00000000000..0f8001ec47d --- /dev/null +++ b/TAO/orbsvcs/orbsvcs/LoadBalancing/LB_LoadAlert.h @@ -0,0 +1,90 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file LB_LoadAlert.h + * + * $Id$ + * + * @author Ossama Othman <ossama@uci.edu> + */ +//============================================================================= + + +#ifndef TAO_LB_LOAD_ALERT_H +#define TAO_LB_LOAD_ALERT_H + +#include "ace/pre.h" + +#include "orbsvcs/CosLoadBalancingS.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +#pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "orbsvcs/PortableGroupC.h" + + +class TAO_LoadBalancing_Export TAO_LB_LoadAlert + : public virtual POA_CosLoadBalancing::LoadAlert, + public virtual PortableServer::RefCountServantBase +{ +public: + + /// Constructor. + TAO_LB_LoadAlert (void); + + /** + * @name CosLoadBalancing::LoadAlert Methods + * + * Methods required by the CosLoadBalancing::LoadAlert interface. + */ + //@{ + + /// Forward requests back to the load manager via the object group + /// reference. + virtual void enable_alert (CORBA::Object object_group + ACE_ENV_ARG_DECL_WITH_DEFAULTS) + ACE_THROW_SPEC ((CORBA::SystemException)); + + /// Stop forwarding requests, and begin accepting them again. + virtual void disable_alert (ACE_ENV_SINGLE_ARG_DECL_WITH_DEFAULTS) + ACE_THROW_SPEC ((CORBA::SystemException)); + + //@} + + /// Has this LoadAlert servant been alerted of a high load condition + /// by the LoadManager. + CORBA::Boolean alerted (void) const; + + CORBA::Object_ptr forward (void); + +protected: + + /// Destructor. + /** + * Protected destructor to enforce correct memory management via + * reference counting. + */ + ~TAO_LB_LoadAlert (void); + +private: + + /// Has this LoadAlert servant been alerted of a high load condition + /// by the LoadManager? + CORBA::Boolean alerted_; + + /// Reference to the object which clients will be forwarded to if an + /// "alert" condition exists. + CORBA::Object_var forward_; + +}; + + +#if defined (__ACE_INLINE__) +# include "LB_LoadAlert.inl" +#endif /* __ACE_INLINE__ */ + +#include "ace/post.h" + +#endif /* TAO_LB_LOAD_ALERT_H */ diff --git a/TAO/orbsvcs/orbsvcs/LoadBalancing/LB_LoadAlert.inl b/TAO/orbsvcs/orbsvcs/LoadBalancing/LB_LoadAlert.inl new file mode 100644 index 00000000000..2099eae3096 --- /dev/null +++ b/TAO/orbsvcs/orbsvcs/LoadBalancing/LB_LoadAlert.inl @@ -0,0 +1,15 @@ +// -*- C++ -*- +// +// $Id$ + +ACE_INLINE CORBA::Boolean +TAO_LB_LoadAlert::alerted (void) const +{ + return this->alerted_; +} + +ACE_INLINE CORBA::Object_ptr +TAO_LB_LoadAlert::forward (void) +{ + return CORBA::Object::_duplicate (this->forward_.in ()); +} diff --git a/TAO/orbsvcs/orbsvcs/LoadBalancing/LB_LoadAlertInfo.cpp b/TAO/orbsvcs/orbsvcs/LoadBalancing/LB_LoadAlertInfo.cpp new file mode 100644 index 00000000000..48dc8296aa8 --- /dev/null +++ b/TAO/orbsvcs/orbsvcs/LoadBalancing/LB_LoadAlertInfo.cpp @@ -0,0 +1,36 @@ +#include "LB_LoadAlertInfo.h" +#include "orbsvcs/PortableGroup/PG_Operators.h" + +ACE_RCSID (LoadBalancing, + LB_LoadAlertInfo, + "$Id$") + +TAO_LB_LoadAlertInfo::TAO_LB_LoadAlertInfo (void) + : load_alert (), + location (), + alerted (0) +{ +} + +int +TAO_LB_LoadAlertInfo::operator== (const TAO_LB_LoadAlertInfo & rhs) +{ + // For the purposes of the LoadAlert info set, only the location is + // important. + return this->location == rhs.location; +} + + +#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION) + +template class ACE_Node<TAO_LB_LoadAlertInfo>; +template class ACE_Unbounded_Set<TAO_LB_LoadAlertInfo>; +template class ACE_Unbounded_Set_Iterator<TAO_LB_LoadAlertInfo>; + +#elif defined(ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA) + +#pragma instantiate ACE_Node<TAO_LB_LoadAlertInfo> +#pragma instantiate ACE_Unbounded_Set<TAO_LB_LoadAlertInfo> +#pragma instantiate ACE_Unbounded_Set_Iterator<TAO_LB_LoadAlertInfo> + +#endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */ diff --git a/TAO/orbsvcs/orbsvcs/LoadBalancing/LB_LoadAlertInfo.h b/TAO/orbsvcs/orbsvcs/LoadBalancing/LB_LoadAlertInfo.h new file mode 100644 index 00000000000..93a7ae4b9f6 --- /dev/null +++ b/TAO/orbsvcs/orbsvcs/LoadBalancing/LB_LoadAlertInfo.h @@ -0,0 +1,67 @@ +// -*- C++ -*- + +//======================================================================= +/** + * @file LB_LoadAlertInfo.h + * + * $Id$ + * + * @author Ossama Othman <ossama@uci.edu> + */ +//======================================================================= + + +#ifndef TAO_LB_LOAD_ALERT_INFO_H +#define TAO_LB_LOAD_ALERT_INFO_H + +#include "ace/pre.h" + +#include "ace/config-all.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "orbsvcs/CosLoadBalancingC.h" + + +/** + * @class TAO_LB_LoadAlertInfo + * + * @brief Structure that contains all LoadAlert-specific information. + * + * Structure that contains all LoadAlert-specific information. + */ +struct TAO_LB_LoadAlertInfo +{ + /// Constructor. + TAO_LB_LoadAlertInfo (void); + + /// Reference to the LoadAlert object. + CosLoadBalancing::LoadAlert_var load_alert; + + /// The location at which the member resides. + PortableGroup::Location location; + + /// True if the LoadAlert object has been alerted about a given load + /// condition. False otherwise. + CORBA::Boolean alerted; + + /// Equality operator. + /** + * For the purposes of the LoadAlert info set, only the location is + * important. In particular, if a LoadAlert object already resides + * at the given location for a particular object group, this + * equality operator will return true. + */ + int operator== (const TAO_LB_LoadAlertInfo & rhs); + +}; + + +typedef ACE_Unbounded_Set<TAO_LB_LoadAlertInfo> TAO_LB_LoadAlertInfoSet; + + +#include "ace/post.h" + +#endif /* TAO_LB_LOAD_ALERT_INFO_H */ diff --git a/TAO/orbsvcs/orbsvcs/LoadBalancing/LB_LoadAlertMap.cpp b/TAO/orbsvcs/orbsvcs/LoadBalancing/LB_LoadAlertMap.cpp new file mode 100644 index 00000000000..878de1e4d2f --- /dev/null +++ b/TAO/orbsvcs/orbsvcs/LoadBalancing/LB_LoadAlertMap.cpp @@ -0,0 +1,27 @@ +// -*- C++ -*- + +#include "LB_LoadAlertMap.h" + + +ACE_RCSID (LoadBalancing, + LB_LoadAlertMap, + "$Id$") + + +#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION) + +template class ACE_Hash_Map_Entry<ACE_UINT32, TAO_LB_LoadAlertInfoSet>; +template class ACE_Hash_Map_Manager_Ex<ACE_UINT32, TAO_LB_LoadAlertInfoSet, ACE_Hash<ACE_UINT32>, ACE_Equal_To<ACE_UINT32>, ACE_Null_Mutex>; +template class ACE_Hash_Map_Iterator_Base_Ex<ACE_UINT32, TAO_LB_LoadAlertInfoSet, ACE_Hash<ACE_UINT32>, ACE_Equal_To<ACE_UINT32>, ACE_Null_Mutex>; +template class ACE_Hash_Map_Iterator_Ex<ACE_UINT32, TAO_LB_LoadAlertInfoSet, ACE_Hash<ACE_UINT32>, ACE_Equal_To<ACE_UINT32>, ACE_Null_Mutex>; +template class ACE_Hash_Map_Reverse_Iterator_Ex<ACE_UINT32, TAO_LB_LoadAlertInfoSet, ACE_Hash<ACE_UINT32>, ACE_Equal_To<ACE_UINT32>, ACE_Null_Mutex>; + +#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA) + +#pragma instantiate ACE_Hash_Map_Entry<ACE_UINT32, TAO_LB_LoadAlertInfoSet> +#pragma instantiate ACE_Hash_Map_Manager_Ex<ACE_UINT32, TAO_LB_LoadAlertInfoSet, ACE_Hash<ACE_UINT32>, ACE_Equal_To<ACE_UINT32>, ACE_Null_Mutex> +#pragma instantiate ACE_Hash_Map_Iterator_Base_Ex<ACE_UINT32, TAO_LB_LoadAlertInfoSet, ACE_Hash<ACE_UINT32>, ACE_Equal_To<ACE_UINT32>, ACE_Null_Mutex> +#pragma instantiate ACE_Hash_Map_Iterator_Ex<ACE_UINT32, TAO_LB_LoadAlertInfoSet, ACE_Hash<ACE_UINT32>, ACE_Equal_To<ACE_UINT32>, ACE_Null_Mutex> +#pragma instantiate ACE_Hash_Map_Reverse_Iterator_Ex<ACE_UINT32, TAO_LB_LoadAlertInfoSet, ACE_Hash<ACE_UINT32>, ACE_Equal_To<ACE_UINT32>, ACE_Null_Mutex> + +#endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */ diff --git a/TAO/orbsvcs/orbsvcs/LoadBalancing/LB_LoadAlertMap.h b/TAO/orbsvcs/orbsvcs/LoadBalancing/LB_LoadAlertMap.h new file mode 100644 index 00000000000..79e2e6bac53 --- /dev/null +++ b/TAO/orbsvcs/orbsvcs/LoadBalancing/LB_LoadAlertMap.h @@ -0,0 +1,44 @@ +// -*- C++ -*- + +//======================================================================= +/** + * @file LB_LoadAlertMap.h + * + * $Id$ + * + * @author Ossama Othman <ossama@uci.edu> + */ +//======================================================================= + + +#ifndef TAO_LB_LOAD_ALERT_MAP_H +#define TAO_LB_LOAD_ALERT_MAP_H + +#include "ace/pre.h" + +#include "ace/config-all.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "LB_LoadAlertInfo.h" + +#include "tao/PortableServer/Key_Adapters.h" +#include "tao/PortableServer/PortableServerC.h" + +#include "ace/Hash_Map_Manager_T.h" + + +/// LoadAlertInfo hash map typedef. +typedef ACE_Hash_Map_Manager_Ex< + ACE_UINT32, + TAO_LB_LoadAlertInfoSet, + ACE_Hash<ACE_UINT32>, + ACE_Equal_To<ACE_UINT32>, + ACE_Null_Mutex> TAO_LB_LoadAlertMap; + + +#include "ace/post.h" + +#endif /* TAO_LB_LOAD_ALERT_MAP_H */ diff --git a/TAO/orbsvcs/orbsvcs/LoadBalancing/LB_LoadListMap.cpp b/TAO/orbsvcs/orbsvcs/LoadBalancing/LB_LoadListMap.cpp new file mode 100644 index 00000000000..75ed8e3a833 --- /dev/null +++ b/TAO/orbsvcs/orbsvcs/LoadBalancing/LB_LoadListMap.cpp @@ -0,0 +1,26 @@ +// -*- C++ -*- + +#include "LB_LoadListMap.h" + +ACE_RCSID (LoadBalancing, + LB_LoadListMap, + "$Id$") + + +#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION) + +template class ACE_Hash_Map_Entry<PortableGroup::Location, CosLoadBalancing::LoadList>; +template class ACE_Hash_Map_Manager_Ex<PortableGroup::Location, CosLoadBalancing::LoadList, TAO_PG_Location_Hash, TAO_PG_Location_Equal_To, ACE_Null_Mutex>; +template class ACE_Hash_Map_Iterator_Base_Ex<PortableGroup::Location, CosLoadBalancing::LoadList, TAO_PG_Location_Hash, TAO_PG_Location_Equal_To, ACE_Null_Mutex>; +template class ACE_Hash_Map_Iterator_Ex<PortableGroup::Location, CosLoadBalancing::LoadList, TAO_PG_Location_Hash, TAO_PG_Location_Equal_To, ACE_Null_Mutex>; +template class ACE_Hash_Map_Reverse_Iterator_Ex<PortableGroup::Location, CosLoadBalancing::LoadList, TAO_PG_Location_Hash, TAO_PG_Location_Equal_To, ACE_Null_Mutex>; + +#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA) + +#pragma instantiate ACE_Hash_Map_Entry<PortableGroup::Location, CosLoadBalancing::LoadList> +#pragma instantiate ACE_Hash_Map_Manager_Ex<PortableGroup::Location, CosLoadBalancing::LoadList, TAO_PG_Location_Hash, TAO_PG_Location_Equal_To, ACE_Null_Mutex> +#pragma instantiate ACE_Hash_Map_Iterator_Base_Ex<PortableGroup::Location, CosLoadBalancing::LoadList, TAO_PG_Location_Hash, TAO_PG_Location_Equal_To, ACE_Null_Mutex> +#pragma instantiate ACE_Hash_Map_Iterator_Ex<PortableGroup::Location, CosLoadBalancing::LoadList, TAO_PG_Location_Hash, TAO_PG_Location_Equal_To, ACE_Null_Mutex> +#pragma instantiate ACE_Hash_Map_Reverse_Iterator_Ex<PortableGroup::Location, CosLoadBalancing::LoadList, TAO_PG_Location_Hash, TAO_PG_Location_Equal_To, ACE_Null_Mutex> + +#endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */ diff --git a/TAO/orbsvcs/orbsvcs/LoadBalancing/LB_LoadListMap.h b/TAO/orbsvcs/orbsvcs/LoadBalancing/LB_LoadListMap.h new file mode 100644 index 00000000000..7382bcda92d --- /dev/null +++ b/TAO/orbsvcs/orbsvcs/LoadBalancing/LB_LoadListMap.h @@ -0,0 +1,43 @@ +// -*- C++ -*- + +//======================================================================= +/** + * @file LB_LoadListMap.h + * + * $Id$ + * + * @author Ossama Othman <ossama@uci.edu> + */ +//======================================================================= + + +#ifndef TAO_LB_LOAD_LIST_MAP_H +#define TAO_LB_LOAD_LIST_MAP_H + +#include "ace/pre.h" + +#include "orbsvcs/CosLoadBalancingC.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "orbsvcs/PortableGroupC.h" + +#include "orbsvcs/PortableGroup/PG_Location_Hash.h" +#include "orbsvcs/PortableGroup/PG_Location_Equal_To.h" + +#include "ace/Hash_Map_Manager_T.h" + + +/// LoadList hash map. +typedef ACE_Hash_Map_Manager_Ex< + PortableGroup::Location, + CosLoadBalancing::LoadList, + TAO_PG_Location_Hash, + TAO_PG_Location_Equal_To, + ACE_Null_Mutex> TAO_LB_LoadListMap; + +#include "ace/post.h" + +#endif /* TAO_LB_LOAD_LIST_MAP_H */ diff --git a/TAO/orbsvcs/orbsvcs/LoadBalancing/LB_LoadManager.cpp b/TAO/orbsvcs/orbsvcs/LoadBalancing/LB_LoadManager.cpp index 568d2834c52..c0f95b2023c 100644 --- a/TAO/orbsvcs/orbsvcs/LoadBalancing/LB_LoadManager.cpp +++ b/TAO/orbsvcs/orbsvcs/LoadBalancing/LB_LoadManager.cpp @@ -1,14 +1,17 @@ #include "LB_LoadManager.h" #include "LB_MemberLocator.h" +#include "LB_LoadAlert_Handler.h" +#include "LB_RoundRobin.h" +#include "LB_Random.h" +#include "LB_LeastLoaded.h" #include "LB_conf.h" #include "orbsvcs/PortableGroup/PG_Property_Utils.h" #include "orbsvcs/PortableGroup/PG_conf.h" -#include "tao/ORB_Core.h" - -//#include "ace/Auto_Ptr.h" +#include "tao/Messaging/Messaging.h" +#include "tao/debug.h" ACE_RCSID (LoadBalancing, LB_LoadManager, @@ -18,36 +21,404 @@ ACE_RCSID (LoadBalancing, TAO_LB_LoadManager::TAO_LB_LoadManager (void) : reactor_ (0), poa_ (), + monitor_lock_ (), + load_lock_ (), + load_alert_lock_ (), lock_ (), monitor_map_ (TAO_PG_MAX_LOCATIONS), + load_map_ (TAO_PG_MAX_LOCATIONS), + load_alert_map_ (TAO_PG_MAX_OBJECT_GROUPS), object_group_manager_ (), property_manager_ (object_group_manager_), generic_factory_ (object_group_manager_, property_manager_), pull_handler_ (), timer_id_ (-1), - lm_ref_ () + lm_ref_ (), + round_robin_ (0), + random_ (0), + least_loaded_ (0), + built_in_balancing_strategy_name_ (1), + custom_balancing_strategy_name_ (1) { this->pull_handler_.initialize (&this->monitor_map_, this); + + // @note "this->init()" is not called here (in the constructor) + // since it may thrown in an exception. Throwing an exception + // in a constructor in an emulated exception environment is + // problematic since native exception semantics cannot be + // reproduced in such a case. As such, init() must be called + // by whatever code instantiates this LoadManager. } TAO_LB_LoadManager::~TAO_LB_LoadManager (void) { + delete this->round_robin_; + delete this->random_; + delete this->least_loaded_; } void TAO_LB_LoadManager::push_loads ( - const PortableGroup::Location & /* the_location */, - const CosLoadBalancing::LoadList & /* loads */ + const PortableGroup::Location & the_location, + const CosLoadBalancing::LoadList & loads ACE_ENV_ARG_DECL) ACE_THROW_SPEC ((CORBA::SystemException)) { -#if 0 - // Only the first load is used by this load balancing strategy. if (loads.length () == 0) ACE_THROW (CORBA::BAD_PARAM ()); -#endif /* 0 */ - ACE_THROW (CORBA::NO_IMPLEMENT ()); + ACE_GUARD (TAO_SYNCH_MUTEX, + guard, + this->load_lock_); + + if (this->load_map_.rebind (the_location, loads) == -1) + ACE_THROW (CORBA::INTERNAL ()); +} + +CosLoadBalancing::LoadList * +TAO_LB_LoadManager::get_loads (const PortableGroup::Location & the_location + ACE_ENV_ARG_DECL) + ACE_THROW_SPEC ((CORBA::SystemException, + CosLoadBalancing::LocationNotFound)) +{ + CosLoadBalancing::LoadList * tmp; + ACE_NEW_THROW_EX (tmp, + CosLoadBalancing::LoadList, + CORBA::NO_MEMORY ( + CORBA::SystemException::_tao_minor_code ( + TAO_DEFAULT_MINOR_CODE, + ENOMEM), + CORBA::COMPLETED_NO)); + ACE_CHECK_RETURN (0); + + CosLoadBalancing::LoadList_var loads = tmp; + + ACE_GUARD_RETURN (TAO_SYNCH_MUTEX, + guard, + this->load_lock_, + 0); + + if (this->load_map_.find (the_location, *tmp) == 0) + return loads._retn (); + else + ACE_THROW_RETURN (CosLoadBalancing::LocationNotFound (), 0); +} + +void +TAO_LB_LoadManager::enable_alert (PortableGroup::ObjectGroup_ptr object_group, + const PortableGroup::Location & the_location + ACE_ENV_ARG_DECL) + ACE_THROW_SPEC ((PortableGroup::ObjectGroupNotFound, + CosLoadBalancing::LoadAlertNotFound)) +{ + ACE_GUARD (TAO_SYNCH_MUTEX, guard, this->load_alert_lock_); + + // TAO's PortableGroup library only uses the lower 32 bits of the + // ObjectGroupId, so this cast is safe. + ACE_UINT32 group_id = + ACE_static_cast (ACE_UINT32, + this->get_object_group_id (object_group + ACE_ENV_ARG_PARAMETER)); + ACE_CHECK; + + TAO_LB_LoadAlertMap::ENTRY * entry; + if (this->load_alert_map_.find (group_id, entry) == 0) + { + // A LoadAlert list for the given ObjectGroup exists. Find the + // reference to the LoadAlert object residing at the given + // location. + TAO_LB_LoadAlertInfoSet & alert_set = entry->int_id_; + + TAO_LB_LoadAlertInfoSet::iterator end = + alert_set.end (); + + for (TAO_LB_LoadAlertInfoSet::iterator i = alert_set.begin (); + i != end; + ++i) + { + if ((*i).location == the_location) + { + // Duplicate before releasing the LoadAlertMap lock to + // prevent a race condition from occuring. The + // LoadAlertInfoSet may be altered prior to invoking an + // operation on the LoadAlert object. + CosLoadBalancing::LoadAlert_var load_alert = + CosLoadBalancing::LoadAlert::_duplicate ( + (*i).load_alert.in ()); + + // The alert condition will be enabled. + // @note There is a subtle problem here. If the below + // remote invocation fails, this variable will be + // incorrectly to "true." + (*i).alerted = 1; + + // Release the lock prior to making the below remote + // invocation. + ACE_Reverse_Lock<TAO_SYNCH_MUTEX> reverse_lock ( + this->load_alert_lock_); + ACE_GUARD (ACE_Reverse_Lock<TAO_SYNCH_MUTEX>, + reverse_guard, + reverse_lock); + + // Use AMI to make the following operation + // "non-blocking," allowing the caller to continue + // without being forced to wait for a response. + load_alert->sendc_enable_alert (this->load_alert_handler_.in (), + object_group + ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + + return; + } + } + + ACE_THROW (CosLoadBalancing::LoadAlertNotFound ()); + } + else + { + ACE_THROW (PortableGroup::ObjectGroupNotFound ()); + } +} + +void +TAO_LB_LoadManager::disable_alert (PortableGroup::ObjectGroup_ptr object_group, + const PortableGroup::Location & the_location + ACE_ENV_ARG_DECL) + ACE_THROW_SPEC ((PortableGroup::ObjectGroupNotFound, + CosLoadBalancing::LoadAlertNotFound)) +{ + ACE_GUARD (TAO_SYNCH_MUTEX, guard, this->load_alert_lock_); + + // TAO's PortableGroup library only uses the lower 32 bits of the + // ObjectGroupId, so this cast is safe. + ACE_UINT32 group_id = + ACE_static_cast (ACE_UINT32, + this->get_object_group_id (object_group + ACE_ENV_ARG_PARAMETER)); + ACE_CHECK; + + TAO_LB_LoadAlertMap::ENTRY * entry; + if (this->load_alert_map_.find (group_id, entry) == 0) + { + // A LoadAlert list for the given ObjectGroup exists. Find the + // reference to the LoadAlert object residing at the given + // location. + TAO_LB_LoadAlertInfoSet & alert_set = entry->int_id_; + + TAO_LB_LoadAlertInfoSet::iterator end = + alert_set.end (); + + for (TAO_LB_LoadAlertInfoSet::iterator i = alert_set.begin (); + i != end; + ++i) + { + // Only perform a remote invocation if the LoadAlert object + // was previously alerted. + if ((*i).location == the_location && (*i).alerted) + { + // Duplicate before releasing the LoadAlertMap lock to + // prevent a race condition on the iterator from + // occuring. The LoadAlertInfoSet may be altered prior + // to invoking an operation on the LoadAlert object. + CosLoadBalancing::LoadAlert_var load_alert = + CosLoadBalancing::LoadAlert::_duplicate ( + (*i).load_alert.in ()); + + // @note There is a subtle problem here. If the below + // remote invocation fails, this variable will be + // incorrectly to "false." + (*i).alerted = 0; // The alert condition will be disabled. + + // Release the lock prior to making the below remote + // invocation. + ACE_Reverse_Lock<TAO_SYNCH_MUTEX> reverse_lock ( + this->load_alert_lock_); + ACE_GUARD (ACE_Reverse_Lock<TAO_SYNCH_MUTEX>, + reverse_guard, + reverse_lock); + + // Use AMI to make the following operation + // "non-blocking," allowing the caller to continue + // without being forced to wait for a response. + load_alert->sendc_disable_alert (this->load_alert_handler_.in () + ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + + return; + } + } + + ACE_THROW (CosLoadBalancing::LoadAlertNotFound ()); + } + else + { + ACE_THROW (PortableGroup::ObjectGroupNotFound ()); + } +} + +void +TAO_LB_LoadManager::register_load_alert ( + PortableGroup::ObjectGroup_ptr object_group, + const PortableGroup::Location & the_location, + CosLoadBalancing::LoadAlert_ptr load_alert + ACE_ENV_ARG_DECL) + ACE_THROW_SPEC ((CORBA::SystemException, + PortableGroup::ObjectGroupNotFound, + CosLoadBalancing::LoadAlertAlreadyPresent, + CosLoadBalancing::LoadAlertNotAdded)) +{ + if (CORBA::is_nil (load_alert)) + ACE_THROW (CORBA::BAD_PARAM ()); + + // @todo Verify that a member of the given object group actually + // exists at "the_location." It doesn't make much sense to + // register a LoadAlert object for a non-existent member. + + ACE_GUARD (TAO_SYNCH_MUTEX, guard, this->load_alert_lock_); + + // TAO's PortableGroup library only uses the lower 32 bits of the + // ObjectGroupId, so this cast is safe. + ACE_UINT32 group_id = + ACE_static_cast (ACE_UINT32, + this->get_object_group_id (object_group + ACE_ENV_ARG_PARAMETER)); + ACE_CHECK; + + TAO_LB_LoadAlertMap::ENTRY * entry; + if (this->load_alert_map_.find (group_id, entry) == 0) + { + // A LoadAlert list for the given ObjectGroup exists. Verify + // that no LoadAlert object for the member residing at the given + // location exists. + + TAO_LB_LoadAlertInfoSet & alert_set = entry->int_id_; + + TAO_LB_LoadAlertInfoSet::iterator end = + alert_set.end (); + + for (TAO_LB_LoadAlertInfoSet::iterator i = alert_set.begin (); + i != end; + ++i) + { + if ((*i).location == the_location) + ACE_THROW (CosLoadBalancing::LoadAlertAlreadyPresent ()); + } + + TAO_LB_LoadAlertInfo load_alert_info; + load_alert_info.load_alert = + CosLoadBalancing::LoadAlert::_duplicate (load_alert); + load_alert_info.location = the_location; + + if (alert_set.insert_tail (load_alert_info) != 0) + ACE_THROW (CosLoadBalancing::LoadAlertNotAdded ()); + } + else + { + // No LoadAlert list exists for the given ObjectGroup. Create + // one and insert its initial member. + + TAO_LB_LoadAlertInfo load_alert_info; + load_alert_info.load_alert = + CosLoadBalancing::LoadAlert::_duplicate (load_alert); + load_alert_info.location = the_location; + + TAO_LB_LoadAlertInfoSet alert_set; + if (alert_set.insert_tail (load_alert_info) != 0 + || this->load_alert_map_.bind (group_id, alert_set) != 0) + ACE_THROW (CosLoadBalancing::LoadAlertNotAdded ()); + } +} + +CosLoadBalancing::LoadAlert_ptr +TAO_LB_LoadManager::get_load_alert ( + PortableGroup::ObjectGroup_ptr object_group, + const PortableGroup::Location & the_location + ACE_ENV_ARG_DECL) + ACE_THROW_SPEC ((CORBA::SystemException, + PortableGroup::ObjectGroupNotFound, + CosLoadBalancing::LoadAlertNotFound)) +{ + ACE_GUARD_RETURN (TAO_SYNCH_MUTEX, + guard, + this->load_alert_lock_, + CosLoadBalancing::LoadAlert::_nil ()); + + // TAO's PortableGroup library only uses the lower 32 bits of the + // ObjectGroupId, so this cast is safe. + ACE_UINT32 group_id = + ACE_static_cast (ACE_UINT32, + this->get_object_group_id (object_group + ACE_ENV_ARG_PARAMETER)); + ACE_CHECK_RETURN (CosLoadBalancing::LoadAlert::_nil ()); + + TAO_LB_LoadAlertMap::ENTRY * entry; + if (this->load_alert_map_.find (group_id, entry) == 0) + { + // A LoadAlert list for the given ObjectGroup exists. Find the + // LoadAlert object for the member residing at the given + // location. + + TAO_LB_LoadAlertInfoSet & alert_set = entry->int_id_; + + TAO_LB_LoadAlertInfoSet::iterator end = + alert_set.end (); + + for (TAO_LB_LoadAlertInfoSet::iterator i = alert_set.begin (); + i != end; + ++i) + { + if ((*i).location == the_location) + return + CosLoadBalancing::LoadAlert::_duplicate ((*i).load_alert.in ()); + } + + ACE_THROW_RETURN (CosLoadBalancing::LoadAlertNotFound (), + CosLoadBalancing::LoadAlert::_nil ()); + } + else + ACE_THROW_RETURN (PortableGroup::ObjectGroupNotFound (), + CosLoadBalancing::LoadAlert::_nil ()); +} + +void +TAO_LB_LoadManager::remove_load_alert ( + PortableGroup::ObjectGroup_ptr object_group, + const PortableGroup::Location & the_location + ACE_ENV_ARG_DECL) + ACE_THROW_SPEC ((CORBA::SystemException, + PortableGroup::ObjectGroupNotFound, + CosLoadBalancing::LoadAlertNotFound)) +{ + ACE_GUARD (TAO_SYNCH_MUTEX, guard, this->load_alert_lock_); + + // TAO's PortableGroup library only uses the lower 32 bits of the + // ObjectGroupId, so this cast is safe. + ACE_UINT32 group_id = + ACE_static_cast (ACE_UINT32, + this->get_object_group_id (object_group + ACE_ENV_ARG_PARAMETER)); + ACE_CHECK; + + TAO_LB_LoadAlertMap::ENTRY * entry; + if (this->load_alert_map_.find (group_id, entry) == 0) + { + // A LoadAlert list for the given ObjectGroup exists. Find the + // LoadAlert object for the member residing at the given + // location. + + TAO_LB_LoadAlertInfoSet & alert_set = entry->int_id_; + + TAO_LB_LoadAlertInfo alert_info; + alert_info.location = the_location; + // No need to set the LoadAlert member. It isn't used in + // comparisons. + + if (alert_set.remove (alert_info) != 0) + ACE_THROW (CosLoadBalancing::LoadAlertNotFound ()); + } + else + ACE_THROW (PortableGroup::ObjectGroupNotFound ()); + } void @@ -66,7 +437,7 @@ TAO_LB_LoadManager::register_load_monitor ( ACE_GUARD (TAO_SYNCH_MUTEX, guard, - this->lock_); + this->monitor_lock_); int result = this->monitor_map_.bind (the_location, the_monitor); @@ -116,7 +487,7 @@ TAO_LB_LoadManager::get_load_monitor ( { ACE_GUARD_RETURN (TAO_SYNCH_MUTEX, guard, - this->lock_, + this->monitor_lock_, CosLoadBalancing::LoadMonitor::_nil ()); TAO_LB_MonitorMap::ENTRY * entry; @@ -139,7 +510,7 @@ TAO_LB_LoadManager::remove_load_monitor ( { ACE_GUARD (TAO_SYNCH_MUTEX, guard, - this->lock_); + this->monitor_lock_); if (this->monitor_map_.unbind (the_location) != 0) ACE_THROW (CosLoadBalancing::LocationNotFound ()); @@ -171,6 +542,10 @@ TAO_LB_LoadManager::set_default_properties ( PortableGroup::InvalidProperty, PortableGroup::UnsupportedProperty)) { + this->check_strategy_prop (props + ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + this->property_manager_.set_default_properties (props ACE_ENV_ARG_PARAMETER); } @@ -187,7 +562,7 @@ TAO_LB_LoadManager::get_default_properties ( void TAO_LB_LoadManager::remove_default_properties ( - const PortableGroup::Properties &props + const PortableGroup::Properties & props ACE_ENV_ARG_DECL) ACE_THROW_SPEC ((CORBA::SystemException, PortableGroup::InvalidProperty, @@ -200,12 +575,16 @@ TAO_LB_LoadManager::remove_default_properties ( void TAO_LB_LoadManager::set_type_properties ( const char *type_id, - const PortableGroup::Properties &overrides + const PortableGroup::Properties & overrides ACE_ENV_ARG_DECL) ACE_THROW_SPEC ((CORBA::SystemException, PortableGroup::InvalidProperty, PortableGroup::UnsupportedProperty)) { + this->check_strategy_prop (overrides + ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + this->property_manager_.set_type_properties (type_id, overrides ACE_ENV_ARG_PARAMETER); @@ -225,7 +604,7 @@ TAO_LB_LoadManager::get_type_properties ( void TAO_LB_LoadManager::remove_type_properties ( const char *type_id, - const PortableGroup::Properties &props + const PortableGroup::Properties & props ACE_ENV_ARG_DECL) ACE_THROW_SPEC ((CORBA::SystemException, PortableGroup::InvalidProperty, @@ -239,13 +618,17 @@ TAO_LB_LoadManager::remove_type_properties ( void TAO_LB_LoadManager::set_properties_dynamically ( PortableGroup::ObjectGroup_ptr object_group, - const PortableGroup::Properties &overrides + const PortableGroup::Properties & overrides ACE_ENV_ARG_DECL) ACE_THROW_SPEC ((CORBA::SystemException, PortableGroup::ObjectGroupNotFound, PortableGroup::InvalidProperty, PortableGroup::UnsupportedProperty)) { + this->check_strategy_prop (overrides + ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + this->property_manager_.set_properties_dynamically (object_group, overrides ACE_ENV_ARG_PARAMETER); @@ -266,9 +649,9 @@ TAO_LB_LoadManager::get_properties ( PortableGroup::ObjectGroup_ptr TAO_LB_LoadManager::create_member ( PortableGroup::ObjectGroup_ptr object_group, - const PortableGroup::Location &the_location, - const char *type_id, - const PortableGroup::Criteria &the_criteria + const PortableGroup::Location & the_location, + const char * type_id, + const PortableGroup::Criteria & the_criteria ACE_ENV_ARG_DECL) ACE_THROW_SPEC ((CORBA::SystemException, PortableGroup::ObjectGroupNotFound, @@ -289,7 +672,7 @@ TAO_LB_LoadManager::create_member ( PortableGroup::ObjectGroup_ptr TAO_LB_LoadManager::add_member ( PortableGroup::ObjectGroup_ptr object_group, - const PortableGroup::Location &the_location, + const PortableGroup::Location & the_location, CORBA::Object_ptr member ACE_ENV_ARG_DECL) ACE_THROW_SPEC ((CORBA::SystemException, @@ -307,7 +690,7 @@ TAO_LB_LoadManager::add_member ( PortableGroup::ObjectGroup_ptr TAO_LB_LoadManager::remove_member ( PortableGroup::ObjectGroup_ptr object_group, - const PortableGroup::Location &the_location + const PortableGroup::Location & the_location ACE_ENV_ARG_DECL) ACE_THROW_SPEC ((CORBA::SystemException, PortableGroup::ObjectGroupNotFound, @@ -358,7 +741,7 @@ TAO_LB_LoadManager::get_object_group_ref ( CORBA::Object_ptr TAO_LB_LoadManager::get_member_ref ( PortableGroup::ObjectGroup_ptr object_group, - const PortableGroup::Location &the_location + const PortableGroup::Location & the_location ACE_ENV_ARG_DECL) ACE_THROW_SPEC ((CORBA::SystemException, PortableGroup::ObjectGroupNotFound, @@ -463,8 +846,8 @@ TAO_LB_LoadManager::delete_object ( } CORBA::Object_ptr -TAO_LB_LoadManager::member (const PortableServer::ObjectId & oid - ACE_ENV_ARG_DECL) +TAO_LB_LoadManager::next_member (const PortableServer::ObjectId & oid + ACE_ENV_ARG_DECL) { // Pass the cached loads to the balancing strategy so that the // strategy may choose which member to forward requests to next. @@ -481,30 +864,38 @@ TAO_LB_LoadManager::member (const PortableServer::ObjectId & oid ACE_ENV_ARG_PARAMETER); ACE_CHECK_RETURN (CORBA::Object::_nil ()); - // @todo Cache this property name. No need to create it each time - // this method is called. - PortableGroup::Name balancing_strategy_name (1); - balancing_strategy_name.length (1); - balancing_strategy_name[0].id = - CORBA::string_dup ("org.omg.CosLoadBalancing.Strategy"); - + // Prefer custom load balancing strategies over built-in ones. PortableGroup::Value value; CosLoadBalancing::Strategy_var balancing_strategy; - if (TAO_PG::get_property_value (balancing_strategy_name, - properties.in (), - value) - && (value >>= balancing_strategy.inout ()) - && !CORBA::is_nil (balancing_strategy.in ())) + const char * built_in; // Name of built-in Strategy + if ((TAO_PG::get_property_value (this->custom_balancing_strategy_name_, + properties.in (), + value) + && (value >>= balancing_strategy.inout ()) + && !CORBA::is_nil (balancing_strategy.in ()))) { - // @todo Cache this ObjectGroupManager reference. - PortableGroup::ObjectGroupManager_var group_manager = - this->object_group_manager_._this (ACE_ENV_SINGLE_ARG_PARAMETER); - ACE_CHECK_RETURN (CORBA::Object::_nil ()); - return balancing_strategy->next_member (object_group.in (), this->lm_ref_.in () ACE_ENV_ARG_PARAMETER); } + else if (TAO_PG::get_property_value (this->built_in_balancing_strategy_name_, + properties.in (), + value) + && (value >>= built_in)) + { + balancing_strategy = this->built_in_strategy (built_in); + if (!CORBA::is_nil (balancing_strategy.in ())) + { + return balancing_strategy->next_member (object_group.in (), + this->lm_ref_.in () + ACE_ENV_ARG_PARAMETER); + } + else + { + ACE_THROW_RETURN (CORBA::INTERNAL (), + CORBA::Object::_nil ()); + } + } else { ACE_THROW_RETURN (CORBA::OBJECT_NOT_EXIST (), @@ -514,10 +905,13 @@ TAO_LB_LoadManager::member (const PortableServer::ObjectId & oid void TAO_LB_LoadManager::init ( - CORBA::ORB_ptr orb, + ACE_Reactor * reactor, PortableServer::POA_ptr root_poa ACE_ENV_ARG_DECL) { + ACE_ASSERT (reactor != 0); + ACE_ASSERT (!CORBA::is_nil (root_poa)); + ACE_GUARD (TAO_SYNCH_MUTEX, guard, this->lock_); @@ -615,7 +1009,7 @@ TAO_LB_LoadManager::init ( poa_manager->activate (ACE_ENV_SINGLE_ARG_PARAMETER); ACE_CHECK; - this->reactor_ = orb->orb_core ()->reactor (); + this->reactor_ = reactor; } if (CORBA::is_nil (this->lm_ref_.in ())) @@ -623,4 +1017,258 @@ TAO_LB_LoadManager::init ( this->lm_ref_ = this->_this (ACE_ENV_SINGLE_ARG_PARAMETER); ACE_CHECK; } + + if (CORBA::is_nil (this->load_alert_handler_.in ())) + { + TAO_LB_LoadAlert_Handler * handler; + ACE_NEW_THROW_EX (handler, + TAO_LB_LoadAlert_Handler, + CORBA::NO_MEMORY ( + CORBA::SystemException::_tao_minor_code ( + TAO_DEFAULT_MINOR_CODE, + ENOMEM), + CORBA::COMPLETED_NO)); + ACE_CHECK; + + PortableServer::ServantBase_var safe_handler = handler; + + this->load_alert_handler_ = + handler->_this (ACE_ENV_SINGLE_ARG_PARAMETER); + ACE_CHECK; + } + + this->built_in_balancing_strategy_name_.length (1); + this->built_in_balancing_strategy_name_[0].id = + CORBA::string_dup ("org.omg.CosLoadBalancing.Strategy"); + + this->custom_balancing_strategy_name_.length (1); + this->custom_balancing_strategy_name_[0].id = + CORBA::string_dup ("org.omg.CosLoadBalancing.CustomStrategy"); +} + +ACE_INLINE CosLoadBalancing::Strategy_ptr +TAO_LB_LoadManager::built_in_strategy (const char * strategy) +{ + ACE_ASSERT (strategy != 0); + + CosLoadBalancing::Strategy_ptr s; + + // @todo We should probably shove this code into a factory. + + if (ACE_OS::strcmp ("RoundRobin", strategy) == 0) + { + // Double-checked locking + if (this->round_robin_ == 0) + { + ACE_GUARD_RETURN (TAO_SYNCH_MUTEX, + guard, + this->lock_, + 0); + + if (this->round_robin_ == 0) + { + ACE_NEW_RETURN (this->round_robin_, + TAO_LB_RoundRobin, + CosLoadBalancing::Strategy::_nil ()); + } + } + + s = this->round_robin_; + } + + else if (ACE_OS::strcmp ("Random", strategy) == 0) + { + // Double-checked locking + if (this->random_ == 0) + { + ACE_GUARD_RETURN (TAO_SYNCH_MUTEX, + guard, + this->lock_, + 0); + + if (this->random_ == 0) + { + ACE_NEW_RETURN (this->random_, + TAO_LB_Random, + CosLoadBalancing::Strategy::_nil ()); + } + } + + s = this->random_; + } + + else if (ACE_OS::strcmp ("LeastLoaded", strategy) == 0) + { + // Double-checked locking + if (this->least_loaded_ == 0) + { + ACE_GUARD_RETURN (TAO_SYNCH_MUTEX, + guard, + this->lock_, + 0); + + if (this->least_loaded_ == 0) + { + // Use default "LeastLoaded" properties. + ACE_NEW_RETURN (this->least_loaded_, + TAO_LB_LeastLoaded, + CosLoadBalancing::Strategy::_nil ()); + } + } + + s = this->least_loaded_; + } + + else + { + if (TAO_debug_level > 0) + ACE_ERROR ((LM_ERROR, + "ERROR: TAO_LB_LoadManager::next_member - " + "Unknown/unexpected built-in Strategy:\n" + " \"%s\"\n", + strategy)); + + // This should never occur! + return CosLoadBalancing::Strategy::_nil (); + } + + ACE_ASSERT (!CORBA::is_nil (s)); + + return CosLoadBalancing::Strategy::_duplicate (s); +} + +void +TAO_LB_LoadManager::check_strategy_prop ( + const PortableGroup::Properties & props + ACE_ENV_ARG_DECL) +{ + const CORBA::ULong len = props.length (); + for (CORBA::ULong i; i < len; ++i) + { + const PortableGroup::Property & property = props[i]; + if (ACE_OS::strcmp (property.nam[0].id.in (), + "org.omg.CosLoadBalancing.CustomStrategy") == 0) + { + CosLoadBalancing::CustomStrategy_var strategy; + if (!(property.val >>= strategy.inout ()) + || CORBA::is_nil (strategy.in ())) + ACE_THROW (PortableGroup::InvalidProperty (property.nam, + property.val)); + } + + else if (ACE_OS::strcmp (property.nam[0].id.in (), + "org.omg.CosLoadBalancing.Strategy") == 0) + { + CosLoadBalancing::StrategyInfo * info; + if (property.val >>= info) + { + if (ACE_OS::strcmp (info->name.in (), "LeastLoaded") == 0) + { + this->init_least_loaded (info->props + ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + } + } + else + ACE_THROW (PortableGroup::InvalidProperty (property.nam, + property.val)); + } + + } +} + +void +TAO_LB_LoadManager::init_least_loaded (const PortableGroup::Properties & props + ACE_ENV_ARG_DECL) +{ + // Double-checked locking + if (this->least_loaded_ == 0) + { + ACE_GUARD (TAO_SYNCH_MUTEX, guard, this->lock_); + + if (this->least_loaded_ == 0) + { + CORBA::Float critical_threshold = + TAO_LB::LL_DEFAULT_CRITICAL_THRESHOLD; + CORBA::Float reject_threshold = TAO_LB::LL_DEFAULT_REJECT_THRESHOLD; + CORBA::Float tolerance = TAO_LB::LL_DEFAULT_TOLERANCE; + CORBA::Float dampening = TAO_LB::LL_DEFAULT_DAMPENING; + CORBA::Float per_balance_load = TAO_LB::LL_DEFAULT_PER_BALANCE_LOAD; + + const CORBA::ULong len = props.length (); + for (CORBA::ULong i; i < len; ++i) + { + const PortableGroup::Property & property = props[i]; + if (ACE_OS::strcmp (property.nam[0].id.in (), + "org.omg.CosLoadBalancing.Strategy.LeastLoaded.CriticalThreshold") == 0) + { + this->extract_float_property (property, + critical_threshold + ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + } + + else if (ACE_OS::strcmp (property.nam[0].id.in (), + "org.omg.CosLoadBalancing.Strategy.LeastLoaded.RejectThreshold") == 0) + { + this->extract_float_property (property, + reject_threshold + ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + } + + else if (ACE_OS::strcmp (property.nam[0].id.in (), + "org.omg.CosLoadBalancing.Strategy.LeastLoaded.Tolerance") == 0) + { + this->extract_float_property (property, + tolerance + ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + } + + else if (ACE_OS::strcmp (property.nam[0].id.in (), + "org.omg.CosLoadBalancing.Strategy.LeastLoaded.Dampening") == 0) + { + this->extract_float_property (property, + dampening + ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + } + + else if (ACE_OS::strcmp (property.nam[0].id.in (), + "org.omg.CosLoadBalancing.Strategy.LeastLoaded.PerBalanceLoad") == 0) + { + this->extract_float_property (property, + per_balance_load + ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + } + } + + // Use default "LeastLoaded" properties. + ACE_NEW_THROW_EX (this->least_loaded_, + TAO_LB_LeastLoaded (critical_threshold, + reject_threshold, + tolerance, + dampening, + per_balance_load), + CORBA::NO_MEMORY ( + CORBA::SystemException::_tao_minor_code ( + TAO_DEFAULT_MINOR_CODE, + ENOMEM), + CORBA::COMPLETED_NO)); + ACE_CHECK; + } + } +} + +void +TAO_LB_LoadManager::extract_float_property ( + const PortableGroup::Property & property, + CORBA::Float & value + ACE_ENV_ARG_DECL) +{ + if (!(property.val >>= value)) + ACE_THROW (PortableGroup::InvalidProperty (property.nam, + property.val)); } diff --git a/TAO/orbsvcs/orbsvcs/LoadBalancing/LB_LoadManager.h b/TAO/orbsvcs/orbsvcs/LoadBalancing/LB_LoadManager.h index fedce5dd7b8..464476de890 100644 --- a/TAO/orbsvcs/orbsvcs/LoadBalancing/LB_LoadManager.h +++ b/TAO/orbsvcs/orbsvcs/LoadBalancing/LB_LoadManager.h @@ -23,7 +23,9 @@ #endif /* ACE_LACKS_PRAGMA_ONCE */ +#include "LB_LoadAlertMap.h" #include "LB_MonitorMap.h" +#include "LB_LoadListMap.h" #include "LB_Pull_Handler.h" #include "orbsvcs/PortableGroupC.h" @@ -34,20 +36,20 @@ /// Forward declarations -class TAO_LB_Balancing_Strategy; +class TAO_LB_RoundRobin; +class TAO_LB_Random; +class TAO_LB_LeastLoaded; class TAO_LoadBalancing_Export TAO_LB_LoadManager - : public virtual POA_CosLoadBalancing::LoadManager + : public virtual POA_CosLoadBalancing::LoadManager, + public virtual PortableServer::RefCountServantBase { public: /// Constructor. TAO_LB_LoadManager (void); - /// Destructor. - ~TAO_LB_LoadManager (void); - /** * @name CosLoadBalancing::LoadManager Methods * @@ -55,12 +57,65 @@ public: */ //@{ - // For the PUSH load monitoring style. + /// For the PUSH load monitoring style. virtual void push_loads (const PortableGroup::Location & the_location, const CosLoadBalancing::LoadList & loads ACE_ENV_ARG_DECL_WITH_DEFAULTS) ACE_THROW_SPEC ((CORBA::SystemException)); + /// Return the raw loads at the given location. + virtual CosLoadBalancing::LoadList * get_loads ( + const PortableGroup::Location & the_location + ACE_ENV_ARG_DECL_WITH_DEFAULTS) + ACE_THROW_SPEC ((CORBA::SystemException, + CosLoadBalancing::LocationNotFound)); + + /// Inform member at given location of load alert condition. + virtual void enable_alert (PortableGroup::ObjectGroup_ptr object_group, + const PortableGroup::Location & the_location + ACE_ENV_ARG_DECL_WITH_DEFAULTS) + ACE_THROW_SPEC ((PortableGroup::ObjectGroupNotFound, + CosLoadBalancing::LoadAlertNotFound)); + + /// Inform member at given location that load alert condition has + /// passed. + virtual void disable_alert (PortableGroup::ObjectGroup_ptr object_group, + const PortableGroup::Location & the_location + ACE_ENV_ARG_DECL_WITH_DEFAULTS) + ACE_THROW_SPEC ((PortableGroup::ObjectGroupNotFound, + CosLoadBalancing::LoadAlertNotFound)); + + /// Register a LoadAlert object for the member at the given + /// location. + virtual void register_load_alert ( + PortableGroup::ObjectGroup_ptr object_group, + const PortableGroup::Location & the_location, + CosLoadBalancing::LoadAlert_ptr load_alert + ACE_ENV_ARG_DECL_WITH_DEFAULTS) + ACE_THROW_SPEC ((CORBA::SystemException, + PortableGroup::ObjectGroupNotFound, + CosLoadBalancing::LoadAlertAlreadyPresent, + CosLoadBalancing::LoadAlertNotAdded)); + + /// Retrieve the LoadAlert object for the member at the given + /// location. + virtual CosLoadBalancing::LoadAlert_ptr get_load_alert ( + PortableGroup::ObjectGroup_ptr object_group, + const PortableGroup::Location & the_location + ACE_ENV_ARG_DECL_WITH_DEFAULTS) + ACE_THROW_SPEC ((CORBA::SystemException, + PortableGroup::ObjectGroupNotFound, + CosLoadBalancing::LoadAlertNotFound)); + + /// Remove (de-register) the LoadAlert object for the member at the + /// given location. + virtual void remove_load_alert (PortableGroup::ObjectGroup_ptr object_group, + const PortableGroup::Location & the_location + ACE_ENV_ARG_DECL_WITH_DEFAULTS) + ACE_THROW_SPEC ((CORBA::SystemException, + PortableGroup::ObjectGroupNotFound, + CosLoadBalancing::LoadAlertNotFound)); + /// Register a load monitor with the load balancer. virtual void register_load_monitor ( CosLoadBalancing::LoadMonitor_ptr load_monitor, @@ -302,30 +357,29 @@ public: /** * Select the next member of the object group corresponding to the * given ObjectId. The object group's load balancing strategy - * will be queried that member. + * will be queried for that member. */ - CORBA::Object_ptr member (const PortableServer::ObjectId & oid - ACE_ENV_ARG_DECL); + CORBA::Object_ptr next_member (const PortableServer::ObjectId & oid + ACE_ENV_ARG_DECL); public: - /// Return a reference to the replica to which the current client - /// request will be forwarded. - /** - * The load balancer does the right thing and figures which object - * group the replica should be chosen from. - */ - CORBA::Object_ptr replica (const PortableServer::ObjectId &oid - ACE_ENV_ARG_DECL); - - /// Initialize the load balancer. This will cause a child POA to be /// created with the appropriate policies to support ServantLocators - /// (i.e. for the ReplicaLocator). - void init (CORBA::ORB_ptr orb, + /// (i.e. for the MemberLocator). + void init (ACE_Reactor * reactor, PortableServer::POA_ptr root_poa ACE_ENV_ARG_DECL); +protected: + + /// Destructor. + /** + * Destructor is protected to enforce correct memory management + * through reference counting. + */ + ~TAO_LB_LoadManager (void); + private: /// Extract the value of the InitialNumberReplicas property from @@ -347,6 +401,34 @@ private: const PortableGroup::Criteria & the_criteria, PortableGroup::FactoryInfos & factory_infos) const; + /// Return a reference to the built-in load balancing strategy named + /// "strategy." + CosLoadBalancing::Strategy_ptr built_in_strategy (const char * strategy); + + /// Check validity of Strategy or CustomStrategy property. + /** + * If a "LeastLoaded" Strategy is found in the property list, the + * LeastLoaded Strategy implementation will be initialized with the + * provided LeastLoaded-specific properties. + */ + void check_strategy_prop (const PortableGroup::Properties & props + ACE_ENV_ARG_DECL); + + /// Initialize the built-in LeastLoaded Strategy with the given + /// LeastLoaded properties. + void init_least_loaded (const PortableGroup::Properties & props + ACE_ENV_ARG_DECL); + + /// Utility method to extract a CORBA::Float value from the given + /// property. + /** + * @note This method is really only used when initializing the + * LeastLoaded built-in Strategy. + */ + void extract_float_property (const PortableGroup::Property & property, + CORBA::Float & value + ACE_ENV_ARG_DECL); + private: /// Reactor used when pulling loads from registered load monitors. @@ -355,13 +437,29 @@ private: /// The POA that dispatches requests to the ReplicaLocator. PortableServer::POA_var poa_; - /// Mutex that provides synchronization. + /// Mutex that provides synchronization for the LoadMonitor map. + TAO_SYNCH_MUTEX monitor_lock_; + + /// Mutex that provides synchronization for the LoadMap table. + TAO_SYNCH_MUTEX load_lock_; + + /// Mutex that provides synchronization for the LoadAlert table. + TAO_SYNCH_MUTEX load_alert_lock_; + + /// Mutex that provides synchronization for the LoadManager's + /// state. TAO_SYNCH_MUTEX lock_; /// Table that maps PortableGroup::Location to load monitor at that /// location. TAO_LB_MonitorMap monitor_map_; + /// Table that maps location to load list. + TAO_LB_LoadListMap load_map_; + + /// Table that maps object group and location to LoadAlert object. + TAO_LB_LoadAlertMap load_alert_map_; + /// The ObjectGroupManager that implements the functionality /// necessary for application-controlled object group membership. TAO_PG_ObjectGroupManager object_group_manager_; @@ -384,6 +482,35 @@ private: /// Cached object reference that points to this servant. CosLoadBalancing::LoadManager_var lm_ref_; + /// Cached object reference that points to the AMI handler for all + /// LoadAlert objects. + CosLoadBalancing::AMI_LoadAlertHandler_var load_alert_handler_; + + /** + * @name Built-in load balancing strategy implementations + * + * "Built-in" load balancing strategies defined by the load + * balancing specification. + */ + //@{ + /// The "RoundRobin" load balancing strategy. + TAO_LB_RoundRobin * round_robin_; + + /// The "Random" load balancing strategy. + TAO_LB_Random * random_; + + /// The "LeastLoaded" load balancing strategy. + TAO_LB_LeastLoaded * least_loaded_; + //@} + + /// Cached instance of the Property name + /// "org.omg.CosLoadBalancing.Strategy". + PortableGroup::Name built_in_balancing_strategy_name_; + + /// Cached instance of the Property name + /// "org.omg.CosLoadBalancing.CustomStrategy". + PortableGroup::Name custom_balancing_strategy_name_; + }; diff --git a/TAO/orbsvcs/orbsvcs/LoadBalancing/LB_MemberLocator.cpp b/TAO/orbsvcs/orbsvcs/LoadBalancing/LB_MemberLocator.cpp index 1c189bf7f2c..7012d1ab668 100644 --- a/TAO/orbsvcs/orbsvcs/LoadBalancing/LB_MemberLocator.cpp +++ b/TAO/orbsvcs/orbsvcs/LoadBalancing/LB_MemberLocator.cpp @@ -23,8 +23,8 @@ TAO_LB_MemberLocator::preinvoke ( PortableServer::ForwardRequest)) { CORBA::Object_var member = - this->load_manager_->member (oid - ACE_ENV_ARG_PARAMETER); + this->load_manager_->next_member (oid + ACE_ENV_ARG_PARAMETER); ACE_CHECK_RETURN (0); // ACE_DEBUG ((LM_DEBUG, diff --git a/TAO/orbsvcs/orbsvcs/LoadBalancing/LB_Random.cpp b/TAO/orbsvcs/orbsvcs/LoadBalancing/LB_Random.cpp index 38a018f12c7..0831b8ce4f4 100644 --- a/TAO/orbsvcs/orbsvcs/LoadBalancing/LB_Random.cpp +++ b/TAO/orbsvcs/orbsvcs/LoadBalancing/LB_Random.cpp @@ -16,7 +16,7 @@ char * TAO_LB_Random::name (ACE_ENV_SINGLE_ARG_DECL_NOT_USED) ACE_THROW_SPEC ((CORBA::SystemException)) { - return CORBA::string_dup ("TAO_LB_Random"); + return CORBA::string_dup ("Random"); } CosLoadBalancing::Properties * diff --git a/TAO/orbsvcs/orbsvcs/LoadBalancing/LB_Random.h b/TAO/orbsvcs/orbsvcs/LoadBalancing/LB_Random.h index 5518bdb1e76..277f8fa9103 100644 --- a/TAO/orbsvcs/orbsvcs/LoadBalancing/LB_Random.h +++ b/TAO/orbsvcs/orbsvcs/LoadBalancing/LB_Random.h @@ -20,7 +20,7 @@ # pragma once # endif /* ACE_LACKS_PRAGMA_ONCE */ -#include "orbsvcs/CosLoadBalancingS.h" +#include "orbsvcs/CosLoadBalancingC.h" /** * @class TAO_LB_Random @@ -30,8 +30,9 @@ * This load balancing strategy is designed to select an object group * member residing at a random location. */ -class TAO_LoadBalancing_Export TAO_LB_Random - : public virtual POA_CosLoadBalancing::Strategy +class TAO_LB_Random + : public virtual CosLoadBalancing::Strategy, + public virtual CORBA::LocalObject { public: diff --git a/TAO/orbsvcs/orbsvcs/LoadBalancing/LB_RoundRobin.cpp b/TAO/orbsvcs/orbsvcs/LoadBalancing/LB_RoundRobin.cpp new file mode 100644 index 00000000000..15dfeb2bdf3 --- /dev/null +++ b/TAO/orbsvcs/orbsvcs/LoadBalancing/LB_RoundRobin.cpp @@ -0,0 +1,67 @@ +// -*- C++ -*- + +#include "LB_RoundRobin.h" +#include "orbsvcs/PortableGroup/PG_conf.h" +#include "tao/debug.h" + + +ACE_RCSID (LoadBalancing, + LB_RoundRobin, + "$Id$") + + +TAO_LB_RoundRobin::TAO_LB_RoundRobin (void) + // : lock_ (), +{ +} + +TAO_LB_RoundRobin::~TAO_LB_RoundRobin (void) +{ +} + +char * +TAO_LB_RoundRobin::name (ACE_ENV_SINGLE_ARG_DECL_NOT_USED) + ACE_THROW_SPEC ((CORBA::SystemException)) +{ + return CORBA::string_dup ("RoundRobin"); +} + +CosLoadBalancing::Properties * +TAO_LB_RoundRobin::get_properties (ACE_ENV_SINGLE_ARG_DECL) + ACE_THROW_SPEC ((CORBA::SystemException)) +{ + CosLoadBalancing::Properties * props = 0; + ACE_NEW_THROW_EX (props, + CosLoadBalancing::Properties, + CORBA::NO_MEMORY ( + CORBA::SystemException::_tao_minor_code ( + TAO_DEFAULT_MINOR_CODE, + ENOMEM), + CORBA::COMPLETED_NO)); + ACE_CHECK_RETURN (props); + + return props; +} + +void +TAO_LB_RoundRobin::push_loads ( + const PortableGroup::Location & the_location, + const CosLoadBalancing::LoadList & loads + ACE_ENV_ARG_DECL) + ACE_THROW_SPEC ((CORBA::SystemException, + CosLoadBalancing::StrategyNotAdaptive)) +{ + ACE_THROW (CosLoadBalancing::StrategyNotAdaptive ()); +} + +CORBA::Object_ptr +TAO_LB_RoundRobin::next_member ( + PortableGroup::ObjectGroup_ptr object_group, + CosLoadBalancing::LoadManager_ptr load_manager + ACE_ENV_ARG_DECL) + ACE_THROW_SPEC ((CORBA::SystemException, + PortableGroup::ObjectGroupNotFound, + PortableGroup::MemberNotFound)) +{ + ACE_THROW_RETURN (CORBA::NO_IMPLEMENT (), CORBA::Object::_nil ()); +} diff --git a/TAO/orbsvcs/orbsvcs/LoadBalancing/LB_RoundRobin.h b/TAO/orbsvcs/orbsvcs/LoadBalancing/LB_RoundRobin.h new file mode 100644 index 00000000000..5cf5579fbd7 --- /dev/null +++ b/TAO/orbsvcs/orbsvcs/LoadBalancing/LB_RoundRobin.h @@ -0,0 +1,94 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file LB_RoundRobin.h + * + * $Id$ + * + * @author Ossama Othman <ossama@uci.edu> + */ +//============================================================================= + + +#ifndef LB_ROUND_ROBIN_H +#define LB_ROUND_ROBIN_H + +#include "ace/pre.h" + +#include "LB_LoadMap.h" + +# if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +# endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "orbsvcs/CosLoadBalancingC.h" + +#include "ace/Synch.h" + +/** + * @class TAO_LB_RoundRobin_Strategy + * + * @brief "Round Robin" load balancing strategy + * + * This load balancing strategy is designed to select an object group + * member residing at the next location. + */ +class TAO_LB_RoundRobin + : public virtual CosLoadBalancing::Strategy, + public virtual CORBA::LocalObject +{ +public: + + /// Constructor. + TAO_LB_RoundRobin (void); + + /// Destructor + ~TAO_LB_RoundRobin (void); + + /** + * @name CosLoadBalancing::Strategy methods + * + * Methods required by the CosLoadBalancing::Strategy interface. + */ + //@{ + virtual char * name (ACE_ENV_SINGLE_ARG_DECL_WITH_DEFAULTS) + ACE_THROW_SPEC ((CORBA::SystemException)); + + virtual CosLoadBalancing::Properties * get_properties ( + ACE_ENV_SINGLE_ARG_DECL_WITH_DEFAULTS) + ACE_THROW_SPEC ((CORBA::SystemException)); + + virtual void push_loads ( + const PortableGroup::Location & the_location, + const CosLoadBalancing::LoadList & loads + ACE_ENV_ARG_DECL_WITH_DEFAULTS) + ACE_THROW_SPEC ((CORBA::SystemException, + CosLoadBalancing::StrategyNotAdaptive)); + + virtual CORBA::Object_ptr next_member ( + PortableGroup::ObjectGroup_ptr object_group, + CosLoadBalancing::LoadManager_ptr load_manager + ACE_ENV_ARG_DECL_WITH_DEFAULTS) + ACE_THROW_SPEC ((CORBA::SystemException, + PortableGroup::ObjectGroupNotFound, + PortableGroup::MemberNotFound)); + +protected: + + /// Retrieve the least loaded location from the given list of + /// locations. +// CORBA::Boolean get_location (const PortableGroup::Locations & locations, +// PortableGroup::Location & location); + +private: + + /// Lock used to ensure atomic access to state retained by this + /// class. +// TAO_SYNCH_MUTEX lock_; + +}; + +#include "ace/post.h" + +#endif /* LB_ROUND_ROBIN_H */ |