summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjai <jai@ae88bc3d-4319-0410-8dbf-d08b4c9d3795>2004-01-30 23:07:42 +0000
committerjai <jai@ae88bc3d-4319-0410-8dbf-d08b4c9d3795>2004-01-30 23:07:42 +0000
commit74fec246bba6803e0295f48e2a70d4d7e255adfb (patch)
tree3e9c1ceeb1f7b9e11ed587a300be3b70c76e1ade
parentcdd0661aaa60b46ee748fe9b68ac3d632bb86d00 (diff)
downloadATCD-74fec246bba6803e0295f48e2a70d4d7e255adfb.tar.gz
Fri Jan 30 16:43:43 2004 Jaiganesh B <jai@dre.vanderbilt.edu>
-rw-r--r--TAO/ChangeLog20
-rw-r--r--TAO/orbsvcs/orbsvcs/LoadBalancing/LB_LoadAverage.cpp434
-rw-r--r--TAO/orbsvcs/orbsvcs/LoadBalancing/LB_LoadAverage.h187
-rw-r--r--TAO/orbsvcs/orbsvcs/LoadBalancing/LB_LoadAverage.inl23
-rw-r--r--TAO/orbsvcs/orbsvcs/LoadBalancing/LB_LoadMinimum.cpp620
-rw-r--r--TAO/orbsvcs/orbsvcs/LoadBalancing/LB_LoadMinimum.h204
-rw-r--r--TAO/orbsvcs/orbsvcs/LoadBalancing/LB_LoadMinimum.inl22
7 files changed, 1507 insertions, 3 deletions
diff --git a/TAO/ChangeLog b/TAO/ChangeLog
index f6c94079ca6..958b281a294 100644
--- a/TAO/ChangeLog
+++ b/TAO/ChangeLog
@@ -1,7 +1,21 @@
+Fri Jan 30 16:43:43 2004 Jaiganesh B <jai@dre.vanderbilt.edu>
+
+ * orbsvcs/orbsvcs/LoadBalancing/LB_LoadAverage.h:
+ * orbsvcs/orbsvcs/LoadBalancing/LB_LoadAverage.cpp:
+ * orbsvcs/orbsvcs/LoadBalancing/LB_LoadAverage.inl:
+ * orbsvcs/orbsvcs/LoadBalancing/LB_LoadMinimum.h:
+ * orbsvcs/orbsvcs/LoadBalancing/LB_LoadMinimum.cpp:
+ * orbsvcs/orbsvcs/LoadBalancing/LB_LoadMinimum.inl:
+ * orbsvcs/orbsvcs/Makefile.CosLoadBalancing:
+
+ Integrated two new adaptive load balancing strategies
+ with the TAO Load Balancing Service - Cygnus.
+
+
Thu Jan 29 18:14:20 2004 Jeff Parsons <j.parsons@vanderbilt.edu>
* TAO_IDL/util/utl_global.cpp:
-
+
When executing validate_included_idl_files() on a non-windows
platform, the system function realpath() is called. Denny
Kolb <kolb@g2ss.com> has submitted a version for use on LynxOS,
@@ -10,7 +24,7 @@ Thu Jan 29 18:14:20 2004 Jeff Parsons <j.parsons@vanderbilt.edu>
Thu Jan 29 15:33:16 2004 Jeff Parsons <j.parsons@vanderbilt.edu>
* tao/TypeCodeFactory/TypeCodeFactory_i.cpp:
-
+
Added missing parenthesis is a block of code compiled only
when ACE_SWAP_ON_WRITE is defined. This closes [BUGID:1732].
Thanks to Mouna Seri <seri@crhc.uiuc.edu> for making the
@@ -75,7 +89,7 @@ Thu Jan 29 14:10:27 2004 Balachandran Natarajan <bala@dre.vanderbilt.edu>
Thanks to Duane Binder<duane.binder@veritas.com> for providing
patches to fix some of the messages printed out using
- ACE_Log_Msg.
+ ACE_Log_Msg.
Thu Jan 29 14:03:42 2004 Chad Elliott <elliott_c@ociweb.com>
diff --git a/TAO/orbsvcs/orbsvcs/LoadBalancing/LB_LoadAverage.cpp b/TAO/orbsvcs/orbsvcs/LoadBalancing/LB_LoadAverage.cpp
new file mode 100644
index 00000000000..9cdd42917f6
--- /dev/null
+++ b/TAO/orbsvcs/orbsvcs/LoadBalancing/LB_LoadAverage.cpp
@@ -0,0 +1,434 @@
+#include "LB_LoadAverage.h"
+#include "LB_LoadMap.h"
+#include "LB_Random.h"
+
+#include "orbsvcs/PortableGroup/PG_conf.h"
+
+#include "tao/debug.h"
+#include "tao/ORB_Constants.h"
+#include "ace/Null_Mutex.h"
+
+ACE_RCSID (LoadBalancing,
+ LB_LoadAverage,
+ "$Id$")
+
+#if !defined (__ACE_INLINE__)
+#include "LB_LoadAverage.inl"
+#endif /* defined INLINE */
+
+
+TAO_LB_LoadAverage::TAO_LB_LoadAverage (PortableServer::POA_ptr poa)
+ : poa_ (PortableServer::POA::_duplicate (poa)),
+ load_map_ (0),
+ lock_ (0),
+ properties_ (),
+ tolerance_ (TAO_LB::LA_DEFAULT_TOLERANCE),
+ dampening_ (TAO_LB::LA_DEFAULT_DAMPENING),
+ per_balance_load_ (TAO_LB::LA_DEFAULT_DAMPENING)
+{
+ // A load map that retains previous load values at a given location
+ // and lock are only needed if dampening is enabled, i.e. non-zero.
+ if (this->dampening_ != 0)
+ {
+ ACE_NEW (this->load_map_, TAO_LB_LoadMap (TAO_PG_MAX_LOCATIONS));
+
+ ACE_NEW (this->lock_, TAO_SYNCH_MUTEX);
+ }
+
+ // Initialize the random load balancing strategy.
+ TAO_LB_Random::init ();
+}
+
+TAO_LB_LoadAverage::~TAO_LB_LoadAverage (void)
+{
+ delete this->load_map_;
+ delete this->lock_;
+}
+
+char *
+TAO_LB_LoadAverage::name (ACE_ENV_SINGLE_ARG_DECL_NOT_USED)
+ ACE_THROW_SPEC ((CORBA::SystemException))
+{
+ return CORBA::string_dup ("LoadAverage");
+}
+
+CosLoadBalancing::Properties *
+TAO_LB_LoadAverage::get_properties (ACE_ENV_SINGLE_ARG_DECL)
+ ACE_THROW_SPEC ((CORBA::SystemException))
+{
+ CosLoadBalancing::Properties * props = 0;
+ ACE_NEW_THROW_EX (props,
+ CosLoadBalancing::Properties (this->properties_),
+ CORBA::NO_MEMORY (
+ CORBA::SystemException::_tao_minor_code (
+ TAO_DEFAULT_MINOR_CODE,
+ ENOMEM),
+ CORBA::COMPLETED_NO));
+ ACE_CHECK_RETURN (0);
+
+ return props;
+}
+
+void
+TAO_LB_LoadAverage::push_loads (
+ const PortableGroup::Location & the_location,
+ const CosLoadBalancing::LoadList & loads
+ ACE_ENV_ARG_DECL)
+ ACE_THROW_SPEC ((CORBA::SystemException))
+{
+ // Only the first load is used by this load balancing strategy.
+ 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_LoadAverage::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)
+ {
+ 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 = entry->int_id_;
+
+ if (previous_load.id != new_load.id)
+ ACE_THROW (CORBA::BAD_PARAM ()); // Somebody switched
+ // LoadIds on us!
+
+ 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)
+ };
+
+ if (this->load_map_->bind (the_location, eff_load) != 0)
+ {
+ if (TAO_debug_level > 0)
+ ACE_ERROR ((LM_ERROR,
+ "ERROR: TAO_LB_LoadAverage - "
+ "Unable to push loads\n"));
+
+ ACE_THROW (CORBA::INTERNAL ());
+ }
+
+ load = eff_load;
+ }
+ }
+ else
+ {
+ load.id = new_load.id;
+ load.value = this->effective_load (0, new_load.value);
+ }
+}
+
+CosLoadBalancing::LoadList *
+TAO_LB_LoadAverage::get_loads (CosLoadBalancing::LoadManager_ptr load_manager,
+ const PortableGroup::Location & the_location
+ ACE_ENV_ARG_DECL)
+ ACE_THROW_SPEC ((CORBA::SystemException,
+ CosLoadBalancing::LocationNotFound))
+{
+ if (CORBA::is_nil (load_manager))
+ ACE_THROW_RETURN (CORBA::BAD_PARAM (), 0);
+
+ CosLoadBalancing::LoadList_var loads =
+ load_manager->get_loads (the_location
+ ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK_RETURN (0);
+
+ this->push_loads (the_location,
+ loads.in (),
+ loads[0]
+ ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK_RETURN (0);
+
+ return loads._retn ();
+}
+
+
+CORBA::Object_ptr
+TAO_LB_LoadAverage::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))
+{
+ if (CORBA::is_nil (load_manager))
+ ACE_THROW_RETURN (CORBA::BAD_PARAM (),
+ CORBA::Object::_nil ());
+
+ PortableGroup::Locations_var locations =
+ load_manager->locations_of_members (object_group
+ ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK_RETURN (CORBA::Object::_nil ());
+
+ if (locations->length () == 0)
+ ACE_THROW_RETURN (CORBA::TRANSIENT (),
+ CORBA::Object::_nil ());
+
+ // @note The Random load balancing strategy is used since it is
+ // very lightweight and stateless.
+
+ return TAO_LB_Random::_tao_next_member (object_group,
+ load_manager,
+ locations.in ()
+ ACE_ENV_ARG_PARAMETER);
+}
+
+void
+TAO_LB_LoadAverage::analyze_loads (
+ PortableGroup::ObjectGroup_ptr object_group,
+ CosLoadBalancing::LoadManager_ptr load_manager
+ ACE_ENV_ARG_DECL)
+ ACE_THROW_SPEC ((CORBA::SystemException))
+{
+ if (CORBA::is_nil (load_manager))
+ ACE_THROW (CORBA::BAD_PARAM ());
+
+ PortableGroup::Locations_var locations =
+ load_manager->locations_of_members (object_group
+ ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+
+ if (locations->length () == 0)
+ ACE_THROW (CORBA::TRANSIENT ());
+
+ const CORBA::ULong len = locations->length ();
+
+ CosLoadBalancing::Load total_load;
+ CosLoadBalancing::Load avg_load;
+
+ CosLoadBalancing::LoadList tmp (len);
+ tmp.length (1);
+
+ // Iterate through the entire location list to determine
+ // the average load of all the locations
+ for (CORBA::ULong i = 0; i < len; ++i)
+ {
+ ACE_TRY
+ {
+ 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;
+
+ total_load.value = total_load.value + load.value;
+
+ tmp[i] = load;
+
+ /*
+ ACE_DEBUG ((LM_DEBUG,
+ "TOTAL == %f\n",
+ total_load.value));
+ */
+
+ }
+ ACE_CATCH (CosLoadBalancing::LocationNotFound, ex)
+ {
+ // no location found
+ //
+ }
+ ACE_ENDTRY;
+ ACE_CHECK;
+ }
+
+ avg_load.value = total_load.value / len;
+
+ // Iterate through the entire location list to determine
+ // the location where the load has to be shed.
+ for (CORBA::ULong i = 0; i < len; ++i)
+ {
+ ACE_TRY
+ {
+ 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 present_load;
+ this->push_loads (loc,
+ current_loads.in (),
+ present_load
+ ACE_ENV_ARG_PARAMETER);
+ ACE_TRY_CHECK;
+ */
+
+ /*
+ ACE_DEBUG ((LM_DEBUG,
+ "EFFECTIVE_LOAD == %f\n"
+ "AVERAGE == %f\n",
+ tmp[i].value,
+ avg_load.value));
+ */
+
+ if (tmp[i].value <= avg_load.value)
+ {
+ load_manager->disable_alert (loc
+ ACE_ENV_ARG_PARAMETER);
+ ACE_TRY_CHECK;
+ }
+ else
+ {
+ /*
+ ACE_DEBUG ((LM_DEBUG,
+ "%P --- ALERTING LOCATION %u\n",
+ i));
+ */
+ load_manager->enable_alert (loc
+ ACE_ENV_ARG_PARAMETER);
+ ACE_TRY_CHECK;
+ }
+ }
+ ACE_CATCH (CosLoadBalancing::LocationNotFound, ex)
+ {
+ // no location found
+ //
+ }
+ ACE_ENDTRY;
+ ACE_CHECK;
+ }
+
+}
+
+PortableServer::POA_ptr
+TAO_LB_LoadAverage::_default_POA (ACE_ENV_SINGLE_ARG_DECL_NOT_USED)
+{
+ return PortableServer::POA::_duplicate (this->poa_.in ());
+}
+
+CORBA::Boolean
+TAO_LB_LoadAverage::get_location (
+ CosLoadBalancing::LoadManager_ptr load_manager /* the manager */,
+ const PortableGroup::Locations & locations /* locations */,
+ PortableGroup::Location & location /* the location */
+ ACE_ENV_ARG_DECL_NOT_USED)
+{
+ CORBA::Boolean found_location = 0;
+ return found_location;
+}
+
+void
+TAO_LB_LoadAverage::init (const PortableGroup::Properties & props
+ ACE_ENV_ARG_DECL)
+{
+ CORBA::Float tolerance = TAO_LB::LA_DEFAULT_TOLERANCE;
+ CORBA::Float dampening = TAO_LB::LA_DEFAULT_DAMPENING;
+ CORBA::Float per_balance_load = TAO_LB::LA_DEFAULT_PER_BALANCE_LOAD;
+
+ const CORBA::ULong len = props.length ();
+ for (CORBA::ULong i = 0; i < len; ++i)
+ {
+ const PortableGroup::Property & property = props[i];
+ if (ACE_OS::strcmp (property.nam[0].id.in (),
+ "org.omg.CosLoadBalancing.Strategy.LoadAverage.Tolerance") == 0)
+ {
+ this->extract_float_property (property,
+ tolerance
+ ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+
+ // Valid tolerance values are greater than or equal to one.
+ if (tolerance < 1)
+ ACE_THROW (PortableGroup::InvalidProperty (property.nam,
+ property.val));
+ }
+
+ else if (ACE_OS::strcmp (property.nam[0].id.in (),
+ "org.omg.CosLoadBalancing.Strategy.LoadAverage.Dampening") == 0)
+ {
+ this->extract_float_property (property,
+ dampening
+ ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+
+ // Dampening range is [0,1).
+ if (dampening < 0 || dampening >= 1)
+ ACE_THROW (PortableGroup::InvalidProperty (property.nam,
+ property.val));
+ }
+
+ else if (ACE_OS::strcmp (property.nam[0].id.in (),
+ "org.omg.CosLoadBalancing.Strategy.LoadAverage.PerBalanceLoad") == 0)
+ {
+ this->extract_float_property (property,
+ per_balance_load
+ ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+ }
+ }
+
+ this->properties_ = props;
+
+ this->tolerance_ = tolerance;
+ this->dampening_ = dampening;
+ this->per_balance_load_ = per_balance_load;
+
+ /*
+ ACE_DEBUG ((LM_DEBUG,
+ "--------------------------------\n"
+ "tolerance = %f\n"
+ "dampening = %f\n"
+ "per_balance_load = %f\n"
+ "--------------------------------\n",
+ tolerance,
+ dampening,
+ per_balance_load));
+ */
+}
+
+void
+TAO_LB_LoadAverage::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_LoadAverage.h b/TAO/orbsvcs/orbsvcs/LoadBalancing/LB_LoadAverage.h
new file mode 100644
index 00000000000..2fc3410e981
--- /dev/null
+++ b/TAO/orbsvcs/orbsvcs/LoadBalancing/LB_LoadAverage.h
@@ -0,0 +1,187 @@
+// -*- C++ -*-
+
+//=============================================================================
+/**
+ * @file LB_LoadAverage.h
+ *
+ * $Id$
+ *
+ * @author Jaiganesh Balasubramanian <jai@dre.vanderbilt.edu>
+ * @author Ossama Othman <jai@dre.vanderbilt.edu>
+ */
+//=============================================================================
+
+
+#ifndef LB_LOAD_AVERAGE_H
+#define LB_LOAD_AVERAGE_H
+
+#include /**/ "ace/pre.h"
+
+#include "LB_LoadMap.h"
+
+# if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+# endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "orbsvcs/CosLoadBalancingS.h"
+
+#include "ace/Synch_Traits.h"
+#include "ace/Thread_Mutex.h"
+
+namespace TAO_LB
+{
+ /**
+ * @name Default LoadAverage strategy parameters.
+ *
+ * Defaults defined by the Load Balancing specification.
+ */
+ //@{
+ const CORBA::Float LA_DEFAULT_TOLERANCE = 1;
+ const CORBA::Float LA_DEFAULT_DAMPENING = 0;
+ const CORBA::Float LA_DEFAULT_PER_BALANCE_LOAD = 0;
+ //@}
+
+}
+
+/**
+ * @class TAO_LB_LoadAverage
+ *
+ * @brief "Least loaded" load balancing strategy
+ *
+ * This load balancing strategy is designed to select an object group
+ * member residing at a location with the smallest load.
+ */
+class TAO_LB_LoadAverage
+ : public virtual POA_CosLoadBalancing::Strategy,
+ public virtual PortableServer::RefCountServantBase
+{
+public:
+
+ /// Constructor.
+ TAO_LB_LoadAverage (PortableServer::POA_ptr poa);
+
+ /**
+ * @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));
+
+ virtual CosLoadBalancing::LoadList * get_loads (
+ CosLoadBalancing::LoadManager_ptr load_manager,
+ const PortableGroup::Location & the_location
+ ACE_ENV_ARG_DECL_WITH_DEFAULTS)
+ ACE_THROW_SPEC ((CORBA::SystemException,
+ CosLoadBalancing::LocationNotFound));
+
+ 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));
+
+ 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));
+ //@}
+
+ /// Returns the default POA for this servant.
+ virtual PortableServer::POA_ptr _default_POA (
+ ACE_ENV_SINGLE_ARG_DECL_WITH_DEFAULTS
+ );
+
+ /// Initialize the LoadAverage instance with the given properties.
+ void init (const PortableGroup::Properties & props
+ ACE_ENV_ARG_DECL);
+
+protected:
+
+ /// Destructor.
+ ~TAO_LB_LoadAverage (void);
+
+ /// Retrieve the least loaded location from the given list of
+ /// locations.
+ CORBA::Boolean get_location (CosLoadBalancing::LoadManager_ptr load_manager,
+ const PortableGroup::Locations & locations,
+ PortableGroup::Location & location
+ ACE_ENV_ARG_DECL);
+
+ /// Return the effective load.
+ CORBA::Float effective_load (CORBA::Float previous_load,
+ CORBA::Float new_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::LoadList & loads,
+ CosLoadBalancing::Load & effective_load
+ ACE_ENV_ARG_DECL);
+
+ /// Utility method to extract a CORBA::Float value from the given
+ /// property.
+ void extract_float_property (const PortableGroup::Property & property,
+ CORBA::Float & value
+ ACE_ENV_ARG_DECL);
+
+private:
+
+ /// This servant's default POA.
+ PortableServer::POA_var poa_;
+
+ /// 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_;
+
+ /// Cached set of properties used when initializing this strategy.
+ CosLoadBalancing::Properties properties_;
+
+ /**
+ * @name LoadAverage Property Values
+ *
+ * Cached LoadAverage load balancing strategy property values.
+ */
+ //@{
+
+ ///
+ CORBA::Float tolerance_;
+
+ ///
+ CORBA::Float dampening_;
+
+ ///
+ CORBA::Float per_balance_load_;
+
+ //@}
+
+ CosLoadBalancing::LoadList current_loads_;
+
+};
+
+
+#if defined (__ACE_INLINE__)
+#include "LB_LoadAverage.inl"
+#endif /* defined INLINE */
+
+#include /**/ "ace/post.h"
+
+#endif /* LB_LOAD_AVERAGE_H */
diff --git a/TAO/orbsvcs/orbsvcs/LoadBalancing/LB_LoadAverage.inl b/TAO/orbsvcs/orbsvcs/LoadBalancing/LB_LoadAverage.inl
new file mode 100644
index 00000000000..807367ef5c1
--- /dev/null
+++ b/TAO/orbsvcs/orbsvcs/LoadBalancing/LB_LoadAverage.inl
@@ -0,0 +1,23 @@
+// -*- C++ -*-
+//
+// $Id$
+
+
+ACE_INLINE CORBA::Float
+TAO_LB_LoadAverage::effective_load (CORBA::Float previous_load,
+ CORBA::Float new_load)
+{
+ // Apply per-balance load. (Recompute raw load)
+ previous_load += this->per_balance_load_;
+
+ // Apply dampening. (Recompute new raw load)
+ CORBA::Float result =
+ this->dampening_ * previous_load + (1 - this->dampening_) * new_load;
+
+ ACE_ASSERT (this->tolerance_ != 0);
+
+ // Compute the effective load.
+ result /= this->tolerance_;
+
+ return result;
+}
diff --git a/TAO/orbsvcs/orbsvcs/LoadBalancing/LB_LoadMinimum.cpp b/TAO/orbsvcs/orbsvcs/LoadBalancing/LB_LoadMinimum.cpp
new file mode 100644
index 00000000000..b03702b45e3
--- /dev/null
+++ b/TAO/orbsvcs/orbsvcs/LoadBalancing/LB_LoadMinimum.cpp
@@ -0,0 +1,620 @@
+#include "LB_LoadMinimum.h"
+#include "ace/OS_NS_sys_time.h"
+#include "LB_LoadMap.h"
+#include "LB_Random.h"
+
+#include "orbsvcs/PortableGroup/PG_conf.h"
+
+#include "tao/debug.h"
+#include "tao/ORB_Constants.h"
+#include "ace/Null_Mutex.h"
+
+ACE_RCSID (LoadBalancing,
+ LB_LoadMinimum,
+ "$Id$")
+
+#if !defined (__ACE_INLINE__)
+#include "LB_LoadMinimum.inl"
+#endif /* defined INLINE */
+
+
+TAO_LB_LoadMinimum::TAO_LB_LoadMinimum (PortableServer::POA_ptr poa)
+ : poa_ (PortableServer::POA::_duplicate (poa)),
+ load_map_ (0),
+ lock_ (0),
+ properties_ (),
+ tolerance_ (TAO_LB::LM_DEFAULT_TOLERANCE),
+ dampening_ (TAO_LB::LM_DEFAULT_DAMPENING),
+ per_balance_load_ (TAO_LB::LM_DEFAULT_DAMPENING)
+{
+ // A load map that retains previous load values at a given location
+ // and lock are only needed if dampening is enabled, i.e. non-zero.
+ if (this->dampening_ != 0)
+ {
+ ACE_NEW (this->load_map_, TAO_LB_LoadMap (TAO_PG_MAX_LOCATIONS));
+
+ ACE_NEW (this->lock_, TAO_SYNCH_MUTEX);
+ }
+
+ // Initialize the random load balancing strategy.
+ TAO_LB_Random::init ();
+}
+
+TAO_LB_LoadMinimum::~TAO_LB_LoadMinimum (void)
+{
+ delete this->load_map_;
+ delete this->lock_;
+}
+
+char *
+TAO_LB_LoadMinimum::name (ACE_ENV_SINGLE_ARG_DECL_NOT_USED)
+ ACE_THROW_SPEC ((CORBA::SystemException))
+{
+ return CORBA::string_dup ("LoadMinimum");
+}
+
+CosLoadBalancing::Properties *
+TAO_LB_LoadMinimum::get_properties (ACE_ENV_SINGLE_ARG_DECL)
+ ACE_THROW_SPEC ((CORBA::SystemException))
+{
+ CosLoadBalancing::Properties * props = 0;
+ ACE_NEW_THROW_EX (props,
+ CosLoadBalancing::Properties (this->properties_),
+ CORBA::NO_MEMORY (
+ CORBA::SystemException::_tao_minor_code (
+ TAO_DEFAULT_MINOR_CODE,
+ ENOMEM),
+ CORBA::COMPLETED_NO));
+ ACE_CHECK_RETURN (0);
+
+ return props;
+}
+
+void
+TAO_LB_LoadMinimum::push_loads (
+ const PortableGroup::Location & the_location,
+ const CosLoadBalancing::LoadList & loads
+ ACE_ENV_ARG_DECL)
+ ACE_THROW_SPEC ((CORBA::SystemException))
+{
+ // Only the first load is used by this load balancing strategy.
+ 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_LoadMinimum::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)
+ {
+ 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 = entry->int_id_;
+
+ if (previous_load.id != new_load.id)
+ ACE_THROW (CORBA::BAD_PARAM ()); // Somebody switched
+ // LoadIds on us!
+
+ 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)
+ };
+
+ if (this->load_map_->bind (the_location, eff_load) != 0)
+ {
+ if (TAO_debug_level > 0)
+ ACE_ERROR ((LM_ERROR,
+ "ERROR: TAO_LB_LoadMinimum - "
+ "Unable to push loads\n"));
+
+ ACE_THROW (CORBA::INTERNAL ());
+ }
+
+ load = eff_load;
+ }
+ }
+ else
+ {
+ load.id = new_load.id;
+ load.value = this->effective_load (0, new_load.value);
+ }
+}
+
+CosLoadBalancing::LoadList *
+TAO_LB_LoadMinimum::get_loads (CosLoadBalancing::LoadManager_ptr load_manager,
+ const PortableGroup::Location & the_location
+ ACE_ENV_ARG_DECL)
+ ACE_THROW_SPEC ((CORBA::SystemException,
+ CosLoadBalancing::LocationNotFound))
+{
+ if (CORBA::is_nil (load_manager))
+ ACE_THROW_RETURN (CORBA::BAD_PARAM (), 0);
+
+ CosLoadBalancing::LoadList_var loads =
+ load_manager->get_loads (the_location
+ ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK_RETURN (0);
+
+ this->push_loads (the_location,
+ loads.in (),
+ loads[0]
+ ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK_RETURN (0);
+
+ return loads._retn ();
+}
+
+
+CORBA::Object_ptr
+TAO_LB_LoadMinimum::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))
+{
+ if (CORBA::is_nil (load_manager))
+ ACE_THROW_RETURN (CORBA::BAD_PARAM (),
+ CORBA::Object::_nil ());
+
+ PortableGroup::Locations_var locations =
+ load_manager->locations_of_members (object_group
+ ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK_RETURN (CORBA::Object::_nil ());
+
+ if (locations->length () == 0)
+ ACE_THROW_RETURN (CORBA::TRANSIENT (),
+ CORBA::Object::_nil ());
+
+ // @@ RACE CONDITION. OBJECT GROUP MEMBERSHIP MAY CHANGE AFTER
+ // RETRIEVING LOCATIONS! HOW DO WE HANDLE THAT?
+
+ PortableGroup::Location location;
+ CORBA::Boolean found_location =
+ this->get_location (load_manager,
+ locations.in (),
+ location
+ ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK_RETURN (CORBA::Object::_nil ());
+
+ if (found_location)
+ {
+// ACE_DEBUG ((LM_DEBUG,
+// "RETURNING REFERENCE FOR LOCATION \"%s\"\n",
+// location[0].id.in ()));
+
+ return load_manager->get_member_ref (object_group,
+ location
+ ACE_ENV_ARG_PARAMETER);
+ }
+ else
+ {
+ // No loads have been reported for any of the locations the
+ // object group members reside at. If no loads have been
+ // reported to the LoadManager, adaptive load balancing
+ // decisions cannot be made. Fall back on a non-adaptive
+ // strategy, such as the Random load balancing strategy,
+ // instead.
+ //
+ // @note The Random load balancing strategy is used since it is
+ // very lightweight and stateless.
+
+ return TAO_LB_Random::_tao_next_member (object_group,
+ load_manager,
+ locations.in ()
+ ACE_ENV_ARG_PARAMETER);
+ }
+}
+
+void
+TAO_LB_LoadMinimum::analyze_loads (
+ PortableGroup::ObjectGroup_ptr object_group,
+ CosLoadBalancing::LoadManager_ptr load_manager
+ ACE_ENV_ARG_DECL)
+ ACE_THROW_SPEC ((CORBA::SystemException))
+{
+ if (CORBA::is_nil (load_manager))
+ ACE_THROW (CORBA::BAD_PARAM ());
+
+ PortableGroup::Locations_var locations =
+ load_manager->locations_of_members (object_group
+ ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+
+ if (locations->length () == 0)
+ ACE_THROW (CORBA::TRANSIENT ());
+
+ const CORBA::ULong len = locations->length ();
+
+ CosLoadBalancing::Load total_load;
+ CosLoadBalancing::Load avg_load;
+
+ CosLoadBalancing::LoadList tmp (len);
+ tmp.length (1);
+
+ // Iterate through the entire location list to determine
+ // the average load of all the locations
+ for (CORBA::ULong i = 0; i < len; ++i)
+ {
+ ACE_TRY
+ {
+ 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;
+
+ total_load.value = total_load.value + load.value;
+ tmp[i] = load;
+
+ /*
+ ACE_DEBUG ((LM_DEBUG,
+ "TOTAL == %f\n",
+ total_load.value));
+ */
+
+ }
+ ACE_CATCH (CosLoadBalancing::LocationNotFound, ex)
+ {
+ // no location found
+ //
+ }
+ ACE_ENDTRY;
+ ACE_CHECK;
+ }
+
+ avg_load.value = total_load.value / len;
+
+ // Iterate through the entire location list to determine
+ // the location where the load has to be shed.
+ for (CORBA::ULong i = 0; i < len; ++i)
+ {
+ ACE_TRY
+ {
+ 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 present_load;
+ this->push_loads (loc,
+ current_loads.in (),
+ present_load
+ ACE_ENV_ARG_PARAMETER);
+ ACE_TRY_CHECK;
+ */
+
+ /*
+ ACE_DEBUG ((LM_DEBUG,
+ "EFFECTIVE_LOAD == %f\n"
+ "AVERAGE == %f\n",
+ tmp[i].value,
+ avg_load.value));
+ */
+
+ if (tmp[i].value <= avg_load.value)
+ {
+ load_manager->disable_alert (loc
+ ACE_ENV_ARG_PARAMETER);
+ ACE_TRY_CHECK;
+ }
+ else
+ {
+
+ /*
+ ACE_DEBUG ((LM_DEBUG,
+ "%P --- ALERTING LOCATION %u\n",
+ i));
+ */
+ load_manager->enable_alert (loc
+ ACE_ENV_ARG_PARAMETER);
+ ACE_TRY_CHECK;
+ }
+ }
+ ACE_CATCH (CosLoadBalancing::LocationNotFound, ex)
+ {
+ // no location found
+ //
+ }
+ ACE_ENDTRY;
+ ACE_CHECK;
+ }
+
+}
+
+PortableServer::POA_ptr
+TAO_LB_LoadMinimum::_default_POA (ACE_ENV_SINGLE_ARG_DECL_NOT_USED)
+{
+ return PortableServer::POA::_duplicate (this->poa_.in ());
+}
+
+CORBA::Boolean
+TAO_LB_LoadMinimum::get_location (
+ CosLoadBalancing::LoadManager_ptr load_manager,
+ const PortableGroup::Locations & locations,
+ PortableGroup::Location & location
+ ACE_ENV_ARG_DECL)
+{
+ CORBA::Float min_load = FLT_MAX; // Start out with the largest
+ // positive value.
+
+ CORBA::ULong location_index = 0;
+ CORBA::Boolean found_location = 0;
+ CORBA::Boolean found_load = 0;
+
+ const CORBA::ULong len = locations.length ();
+
+ // Iterate through the entire location list to find the least loaded
+ // of them.
+ for (CORBA::ULong i = 0; i < len; ++i)
+ {
+ ACE_TRY
+ {
+ 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;
+
+ found_load = 1;
+
+ CosLoadBalancing::Load load;
+ this->push_loads (loc,
+ current_loads.in (),
+ load
+ ACE_ENV_ARG_PARAMETER);
+ ACE_TRY_CHECK;
+
+ if (load.value < min_load)
+ {
+// ACE_DEBUG ((LM_DEBUG,
+// "**** LOAD == %f\n",
+// load.value));
+
+ if (i > 0 && load.value != 0)
+ {
+ /*
+ percent difference =
+ (min_load - load.value) / load.value
+ == (min_load / load.value) - 1
+
+ The latter form is used to avoid a potential
+ arithmetic overflow problem, such as when
+ (min_load - load.value) > FLT_MAX, assuming that
+ either load.value is negative and min_load is
+ positive, or vice versa.
+ */
+ const CORBA::Float percent_diff =
+ (min_load / load.value) - 1;
+
+ /*
+ A "thundering herd" phenomenon may occur when
+ location loads are basically the same (e.g. only
+ differ by a very small amount), where one object
+ group member ends up receiving the majority of
+ requests from different clients. In order to
+ prevent a single object group member from
+ receiving such request bursts, one of two equally
+ loaded locations is chosen at random. Thanks to
+ Carlos, Marina and Jody at ATD for coming up with
+ this solution to this form of the thundering herd
+ problem.
+
+ See the documentation for
+ TAO_LB::LL_DEFAULT_LOAD_PERCENT_DIFF_CUTOFF in
+ LB_LoadMinimum.h for additional information.
+ */
+ if (percent_diff <= TAO_LB::LM_DEFAULT_LOAD_PERCENT_DIFF_CUTOFF)
+ {
+ // Prevent integer arithmetic overflow.
+ const CORBA::Float NUM_MEMBERS = 2;
+
+ // n == 0: Use previously selected location.
+ // n == 1: Use current location.
+ const CORBA::ULong n =
+ ACE_static_cast (CORBA::ULong,
+ NUM_MEMBERS * ACE_OS::rand ()
+ / (RAND_MAX + 1.0));
+
+ ACE_ASSERT (n == 0 || n == 1);
+
+ if (n == 1)
+ {
+ min_load = load.value;
+ location_index = i;
+ found_location = 1;
+
+// ACE_DEBUG ((LM_DEBUG,
+// "** NEW MIN_LOAD == %f\n",
+// min_load));
+ }
+
+// if (n == 0)
+// ACE_DEBUG ((LM_DEBUG, "^^^^^ PREVIOUS LOCATION\n"));
+// else
+// ACE_DEBUG ((LM_DEBUG, "^^^^^ CURRENT LOCATION\n"));
+
+ }
+ else
+ {
+ min_load = load.value;
+ location_index = i;
+ found_location = 1;
+
+// ACE_DEBUG ((LM_DEBUG,
+// "***** NEW MIN_LOAD == %f\n",
+// min_load));
+ }
+ }
+ else
+ {
+ min_load = load.value;
+ location_index = i;
+ found_location = 1;
+
+// ACE_DEBUG ((LM_DEBUG,
+// "NEW MIN_LOAD == %f\n",
+// min_load));
+ }
+ }
+
+ // ACE_DEBUG ((LM_DEBUG, "NEW MIN_LOAD == %f\n", min_load));
+ }
+ ACE_CATCH (CosLoadBalancing::LocationNotFound, ex)
+ {
+ // No load available for the requested location. Try the
+ // next location.
+ }
+ ACE_ENDTRY;
+ ACE_CHECK_RETURN (0);
+ }
+
+// ACE_DEBUG ((LM_DEBUG,
+// "FOUND_LOAD == %u\n"
+// "FOUND_LOCATION == %u\n",
+// found_load,
+// found_location));
+
+ // If no loads were found, return without an exception to allow this
+ // strategy to select a member using an alternative method
+ // (e.g. random selection).
+ if (found_load)
+ {
+ if (found_location)
+ location = locations[location_index];
+// ACE_DEBUG ((LM_DEBUG, "LOCATION ID == %s\n", location[0].id.in ()));
+ }
+
+ //ACE_DEBUG ((LM_DEBUG, "LOCATED = %u\n", location_index));
+
+ return found_location;
+}
+
+void
+TAO_LB_LoadMinimum::init (const PortableGroup::Properties & props
+ ACE_ENV_ARG_DECL)
+{
+ CORBA::Float tolerance = TAO_LB::LM_DEFAULT_TOLERANCE;
+ CORBA::Float dampening = TAO_LB::LM_DEFAULT_DAMPENING;
+ CORBA::Float per_balance_load = TAO_LB::LM_DEFAULT_PER_BALANCE_LOAD;
+
+ const CORBA::ULong len = props.length ();
+ for (CORBA::ULong i = 0; i < len; ++i)
+ {
+ const PortableGroup::Property & property = props[i];
+ if (ACE_OS::strcmp (property.nam[0].id.in (),
+ "org.omg.CosLoadBalancing.Strategy.LoadMinimum.Tolerance") == 0)
+ {
+ this->extract_float_property (property,
+ tolerance
+ ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+
+ // Valid tolerance values are greater than or equal to one.
+ if (tolerance < 1)
+ ACE_THROW (PortableGroup::InvalidProperty (property.nam,
+ property.val));
+ }
+
+ else if (ACE_OS::strcmp (property.nam[0].id.in (),
+ "org.omg.CosLoadBalancing.Strategy.LoadMinimum.Dampening") == 0)
+ {
+ this->extract_float_property (property,
+ dampening
+ ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+
+ // Dampening range is [0,1).
+ if (dampening < 0 || dampening >= 1)
+ ACE_THROW (PortableGroup::InvalidProperty (property.nam,
+ property.val));
+ }
+
+ else if (ACE_OS::strcmp (property.nam[0].id.in (),
+ "org.omg.CosLoadBalancing.Strategy.LoadMinimum.PerBalanceLoad") == 0)
+ {
+ this->extract_float_property (property,
+ per_balance_load
+ ACE_ENV_ARG_PARAMETER);
+ ACE_CHECK;
+ }
+ }
+
+ this->properties_ = props;
+
+ this->tolerance_ = tolerance;
+ this->dampening_ = dampening;
+ this->per_balance_load_ = per_balance_load;
+
+ /*
+ ACE_DEBUG ((LM_DEBUG,
+ "--------------------------------\n"
+ "tolerance = %f\n"
+ "dampening = %f\n"
+ "per_balance_load = %f\n"
+ "--------------------------------\n",
+ tolerance,
+ dampening,
+ per_balance_load));
+ */
+}
+
+void
+TAO_LB_LoadMinimum::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_LoadMinimum.h b/TAO/orbsvcs/orbsvcs/LoadBalancing/LB_LoadMinimum.h
new file mode 100644
index 00000000000..bf96ad0e870
--- /dev/null
+++ b/TAO/orbsvcs/orbsvcs/LoadBalancing/LB_LoadMinimum.h
@@ -0,0 +1,204 @@
+// -*- C++ -*-
+
+//=============================================================================
+/**
+ * @file LB_LoadMinimum.h
+ *
+ * $Id$
+ *
+ * @author Jaiganesh Balasubramanian <jai@dre.vanderbilt.edu>
+ * Ossama Othman <ossama@uci.edu>
+ */
+//=============================================================================
+
+
+#ifndef LB_LOAD_MINIMUM_H
+#define LB_LOAD_MINIMUM_H
+
+#include /**/ "ace/pre.h"
+
+#include "LB_LoadMap.h"
+
+# if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+# endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "orbsvcs/CosLoadBalancingS.h"
+
+#include "ace/Synch_Traits.h"
+#include "ace/Thread_Mutex.h"
+
+namespace TAO_LB
+{
+ /**
+ * @name Default LoadMinimum strategy parameters.
+ *
+ * Defaults defined by the Load Balancing specification.
+ */
+ //@{
+ const CORBA::Float LM_DEFAULT_TOLERANCE = 1;
+ const CORBA::Float LM_DEFAULT_DAMPENING = 0;
+ const CORBA::Float LM_DEFAULT_PER_BALANCE_LOAD = 0;
+ //@}
+
+ /**
+ * @name TAO-specific LoadMinimum strategy parameters.
+ *
+ * Parameters internal to TAO's LoadMinimum strategy
+ * implementation.
+ */
+ //@{
+ /// Percentage difference between two load values that determines
+ /// whether the loads are considered equivalent.
+ /**
+ * If the percent difference between two loads, i.e.:
+ * (Old Load - New Load) / New Load
+ * is less than or equal to this value, the two loads will be
+ * considered equivalent. In such a case, an object group member
+ * residing at the location corresponding to one of the two loads
+ * will be selected at random.
+ */
+ const CORBA::Float LM_DEFAULT_LOAD_PERCENT_DIFF_CUTOFF = 0.01f; // 1%
+ //@}
+}
+
+/**
+ * @class TAO_LB_LoadMinimum
+ *
+ * @brief "Least loaded" load balancing strategy
+ *
+ * This load balancing strategy is designed to select an object group
+ * member residing at a location with the smallest load.
+ */
+class TAO_LB_LoadMinimum
+ : public virtual POA_CosLoadBalancing::Strategy,
+ public virtual PortableServer::RefCountServantBase
+{
+public:
+
+ /// Constructor.
+ TAO_LB_LoadMinimum (PortableServer::POA_ptr poa);
+
+ /**
+ * @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));
+
+ virtual CosLoadBalancing::LoadList * get_loads (
+ CosLoadBalancing::LoadManager_ptr load_manager,
+ const PortableGroup::Location & the_location
+ ACE_ENV_ARG_DECL_WITH_DEFAULTS)
+ ACE_THROW_SPEC ((CORBA::SystemException,
+ CosLoadBalancing::LocationNotFound));
+
+ 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));
+
+ 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));
+ //@}
+
+ /// Returns the default POA for this servant.
+ virtual PortableServer::POA_ptr _default_POA (
+ ACE_ENV_SINGLE_ARG_DECL_WITH_DEFAULTS
+ );
+
+ /// Initialize the LoadMinimum instance with the given properties.
+ void init (const PortableGroup::Properties & props
+ ACE_ENV_ARG_DECL);
+
+protected:
+
+ /// Destructor.
+ ~TAO_LB_LoadMinimum (void);
+
+ /// Retrieve the least loaded location from the given list of
+ /// locations.
+ CORBA::Boolean get_location (CosLoadBalancing::LoadManager_ptr load_manager,
+ const PortableGroup::Locations & locations,
+ PortableGroup::Location & location
+ ACE_ENV_ARG_DECL);
+
+ /// Return the effective load.
+ CORBA::Float effective_load (CORBA::Float previous_load,
+ CORBA::Float new_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::LoadList & loads,
+ CosLoadBalancing::Load & effective_load
+ ACE_ENV_ARG_DECL);
+
+ /// Utility method to extract a CORBA::Float value from the given
+ /// property.
+ void extract_float_property (const PortableGroup::Property & property,
+ CORBA::Float & value
+ ACE_ENV_ARG_DECL);
+
+private:
+
+ /// This servant's default POA.
+ PortableServer::POA_var poa_;
+
+ /// 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_;
+
+ /// Cached set of properties used when initializing this strategy.
+ CosLoadBalancing::Properties properties_;
+
+ /**
+ * @name LoadMinimum Property Values
+ *
+ * Cached LoadMinimum load balancing strategy property values.
+ */
+ //@{
+
+ ///
+ CORBA::Float tolerance_;
+
+ ///
+ CORBA::Float dampening_;
+
+ ///
+ CORBA::Float per_balance_load_;
+
+ //@}
+
+};
+
+
+#if defined (__ACE_INLINE__)
+#include "LB_LoadMinimum.inl"
+#endif /* defined INLINE */
+
+#include /**/ "ace/post.h"
+
+#endif /* LB_LOAD_MINIMUM_H */
diff --git a/TAO/orbsvcs/orbsvcs/LoadBalancing/LB_LoadMinimum.inl b/TAO/orbsvcs/orbsvcs/LoadBalancing/LB_LoadMinimum.inl
new file mode 100644
index 00000000000..4f096fa4040
--- /dev/null
+++ b/TAO/orbsvcs/orbsvcs/LoadBalancing/LB_LoadMinimum.inl
@@ -0,0 +1,22 @@
+// -*- C++ -*-
+//
+// $Id$
+
+ACE_INLINE CORBA::Float
+TAO_LB_LoadMinimum::effective_load (CORBA::Float previous_load,
+ CORBA::Float new_load)
+{
+ // Apply per-balance load. (Recompute raw load)
+ previous_load += this->per_balance_load_;
+
+ // Apply dampening. (Recompute new raw load)
+ CORBA::Float result =
+ this->dampening_ * previous_load + (1 - this->dampening_) * new_load;
+
+ ACE_ASSERT (this->tolerance_ != 0);
+
+ // Compute the effective load.
+ result /= this->tolerance_;
+
+ return result;
+}