Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages  

TAO_Leader_Follower Class Reference

#include <Leader_Follower.h>

Collaboration diagram for TAO_Leader_Follower:

Collaboration graph
[legend]
List of all members.

Public Methods

 TAO_Leader_Follower (TAO_ORB_Core *orb_core, TAO_New_Leader_Generator *new_leader_generator=0)
 Constructor. More...

 ~TAO_Leader_Follower (void)
 Destructor. More...

int set_event_loop_thread (ACE_Time_Value *max_wait_time)
 The current thread has become a server thread (i.e. called ORB::run), update any flags and counters. More...

void reset_event_loop_thread (void)
 The current thread is not a server thread anymore, reset any flags and counters. More...

void set_upcall_thread (void)
 This thread is going to perform an upcall, it will no longer be an event loop thread. More...

int leader_available (void) const
 Is there any thread running as a leader? More...

void set_client_thread (void)
 A server thread is making a request. More...

void reset_client_thread (void)
 A server thread has finished is making a request. More...

int wait_for_event (TAO_LF_Event *event, TAO_Transport *transport, ACE_Time_Value *max_wait_time)
 Wait on the Leader/Followers loop until one event happens. More...

void set_client_leader_thread (void)
 The current thread has become the leader thread in the client side leader-follower set. More...

void reset_client_leader_thread (void)
 The current thread is no longer the leader thread in the client side leader-follower set. More...

void set_client_leader_thread (ACE_thread_t thread_ID)
 sets the thread ID of the leader thread in the leader-follower model. More...

int is_client_leader_thread (void) const
 checks if we are a leader thread. More...

int elect_new_leader (void)
TAO_SYNCH_MUTEX & lock (void)
 Get a reference to the underlying mutex. More...

ACE_Reverse_Lock< TAO_SYNCH_MUTEX > & reverse_lock (void)
 Provide a pre-initialized reverse lock for the Leader/Followers set. More...

int has_clients (void) const
 Check if there are any client threads running. More...

ACE_Reactorreactor (void)
 Accesor to the reactor. More...

void no_leaders_available (void)
 Called when we are out of leaders. More...

Follower creation/destructions
The Leader/Followers set acts as a factory for the Follower objects. Followers are used to represent a thread blocked waiting in the Follower set.

The Leader/Followers abstraction keeps a list of the waiting followers, so it can wake up one when the leader thread stops handling events.

For performance reasons the Leader/Followers set uses a pool (or free-list) to keep Follower objects unattached to any thread. It could be tempting to use TSS to keep such followers, after all a thread can only need one such Follower object, however, that does not work with multiple Leader/Followers sets, consult this bug report for more details:

http://ace.cs.wustl.edu/bugzilla/show_bug.cgi?id=296

TAO_LF_Followerallocate_follower (void)
 Allocate a new follower to the caller. More...

void release_follower (TAO_LF_Follower *)
 The caller has finished using a follower. More...

Follower Set Operations
void add_follower (TAO_LF_Follower *follower)
 Add a new follower to the set. More...

void remove_follower (TAO_LF_Follower *follower)
 Removes a follower from the leader-follower set. More...

int follower_available (void) const
 Checks if there are any followers available. More...


Private Types

typedef ACE_Intrusive_List<
TAO_LF_Follower
Follower_Set
 Implement the Leader/Followers set using an intrusive list. More...


Private Methods

TAO_ORB_Core_TSS_Resourcesget_tss_resources (void) const
 Shortcut to obtain the TSS resources of the orb core. More...

int wait_for_client_leader_to_complete (ACE_Time_Value *max_wait_time)
 Wait for the client leader to complete. More...

void reset_event_loop_thread_i (TAO_ORB_Core_TSS_Resources *tss)
Follower Set Operations
int elect_new_leader_i (void)
 Remote a follower from the Followers set and promote it to the leader role. More...


Private Attributes

TAO_ORB_Coreorb_core_
 The orb core. More...

TAO_SYNCH_MUTEX lock_
 To synchronize access to the members. More...

ACE_Reverse_Lock< TAO_SYNCH_MUTEX > reverse_lock_
 do protect the access to the following three members. More...

Follower_Set follower_set_
Follower_Set follower_free_list_
 Use a free list to allocate and release Follower objects. More...

int leaders_
int clients_
 Count the number of active clients, this is useful to know when to deactivate the reactor. More...

ACE_Reactorreactor_
 The reactor. More...

int client_thread_is_leader_
 Is a client thread the current leader? More...

int event_loop_threads_waiting_
 Are server threads waiting for the client leader to complete? More...

TAO_SYNCH_CONDITION event_loop_threads_condition_
 Condition variable for server threads waiting for the client leader to complete. More...

TAO_New_Leader_Generatornew_leader_generator_
 Leader/Follower class uses this method to notify the system that we are out of leaders. More...


Member Typedef Documentation

typedef ACE_Intrusive_List<TAO_LF_Follower> TAO_Leader_Follower::Follower_Set [private]
 

Implement the Leader/Followers set using an intrusive list.

Definition at line 208 of file Leader_Follower.h.


Constructor & Destructor Documentation

ACE_INLINE TAO_Leader_Follower::TAO_Leader_Follower TAO_ORB_Core   orb_core,
TAO_New_Leader_Generator   new_leader_generator = 0
 

Constructor.

Definition at line 7 of file Leader_Follower.i.

00009   : orb_core_ (orb_core),
00010     reverse_lock_ (lock_),
00011     leaders_ (0),
00012     clients_ (0),
00013     reactor_ (0),
00014     client_thread_is_leader_ (0),
00015     event_loop_threads_waiting_ (0),
00016     event_loop_threads_condition_ (lock_),
00017     new_leader_generator_ (new_leader_generator)
00018 {
00019 }

TAO_Leader_Follower::~TAO_Leader_Follower void   
 

Destructor.

Definition at line 22 of file Leader_Follower.cpp.

References ACE_Intrusive_List< TAO_LF_Follower >::empty, follower_free_list_, orb_core_, ACE_Intrusive_List< TAO_LF_Follower >::pop_front, reactor_, TAO_Resource_Factory::reclaim_reactor, and TAO_ORB_Core::resource_factory.

00023 {
00024   while (!this->follower_free_list_.empty ())
00025     {
00026       TAO_LF_Follower *follower =
00027         this->follower_free_list_.pop_front ();
00028       delete follower;
00029     }
00030   // Hand the reactor back to the resource factory.
00031   this->orb_core_->resource_factory ()->reclaim_reactor (this->reactor_);
00032   this->reactor_ = 0;
00033 }


Member Function Documentation

ACE_INLINE void TAO_Leader_Follower::add_follower TAO_LF_Follower   follower
 

Add a new follower to the set.

Definition at line 170 of file Leader_Follower.i.

References follower_set_, and ACE_Intrusive_List< TAO_LF_Follower >::push_back.

Referenced by TAO_LF_Follower_Auto_Adder::TAO_LF_Follower_Auto_Adder.

00171 {
00172   this->follower_set_.push_back (follower);
00173 }

TAO_LF_Follower * TAO_Leader_Follower::allocate_follower void   
 

Allocate a new follower to the caller.

Definition at line 36 of file Leader_Follower.cpp.

References ACE_Intrusive_List< TAO_LF_Follower >::empty, follower_free_list_, and ACE_Intrusive_List< TAO_LF_Follower >::pop_front.

00037 {
00038   if (!this->follower_free_list_.empty ())
00039     return this->follower_free_list_.pop_front ();
00040 
00041   return new TAO_LF_Follower (*this);
00042 }

ACE_INLINE int TAO_Leader_Follower::elect_new_leader void   
 

A leader thread is relinquishing its role, unless there are more leader threads running pick up a follower (if there is any) to play the leader role.

Definition at line 41 of file Leader_Follower.i.

References elect_new_leader_i, event_loop_threads_condition_, event_loop_threads_waiting_, follower_available, leaders_, and no_leaders_available.

Referenced by TAO_LF_Strategy_Complete::reset_event_loop_thread, set_upcall_thread, and wait_for_event.

00042 {
00043   if (this->leaders_ == 0)
00044     {
00045       if (this->event_loop_threads_waiting_)
00046         {
00047           return this->event_loop_threads_condition_.broadcast ();
00048         }
00049       else if (this->follower_available ())
00050         {
00051           return this->elect_new_leader_i ();
00052         }
00053       else
00054         {
00055           this->no_leaders_available ();
00056         }
00057     }
00058   return 0;
00059 }

int TAO_Leader_Follower::elect_new_leader_i void    [private]
 

Remote a follower from the Followers set and promote it to the leader role.

This is a helper routine for elect_new_leader(), after verifying that all the pre-conditions are satisfied the Follower set is changed and the promoted Follower is signaled.

Definition at line 51 of file Leader_Follower.cpp.

References ACE_DEBUG, follower_set_, ACE_Intrusive_List< TAO_LF_Follower >::head, LM_DEBUG, and TAO_LF_Follower::signal.

Referenced by elect_new_leader.

00052 {
00053   TAO_LF_Follower* follower =
00054     this->follower_set_.head ();
00055 
00056 #if defined (TAO_DEBUG_LEADER_FOLLOWER)
00057   ACE_DEBUG ((LM_DEBUG,
00058               "TAO (%P|%t) LF::elect_new_leader_i - "
00059               "follower is %x\n",
00060               follower));
00061 #endif /* TAO_DEBUG_LEADER_FOLLOWER */
00062 
00063   return follower->signal ();
00064 }

ACE_INLINE int TAO_Leader_Follower::follower_available void    const
 

Checks if there are any followers available.

Returns:
1 if there follower set is not empty

Definition at line 28 of file Leader_Follower.i.

References ACE_Intrusive_List< TAO_LF_Follower >::empty, and follower_set_.

Referenced by elect_new_leader.

00029 {
00030   return !this->follower_set_.empty ();
00031 }

ACE_INLINE TAO_ORB_Core_TSS_Resources * TAO_Leader_Follower::get_tss_resources void    const [private]
 

Shortcut to obtain the TSS resources of the orb core.

Definition at line 22 of file Leader_Follower.i.

References TAO_ORB_Core::get_tss_resources, and orb_core_.

Referenced by is_client_leader_thread, reset_client_leader_thread, reset_client_thread, reset_event_loop_thread, set_client_leader_thread, set_client_thread, set_event_loop_thread, and set_upcall_thread.

00023 {
00024   return this->orb_core_->get_tss_resources ();
00025 }

ACE_INLINE int TAO_Leader_Follower::has_clients void    const
 

Check if there are any client threads running.

Definition at line 188 of file Leader_Follower.i.

References clients_.

Referenced by TAO_Thread_Lane_Resources::shutdown_reactor.

00189 {
00190   return this->clients_;
00191 }

ACE_INLINE int TAO_Leader_Follower::is_client_leader_thread void    const
 

checks if we are a leader thread.

Definition at line 163 of file Leader_Follower.i.

References TAO_ORB_Core_TSS_Resources::client_leader_thread_, and get_tss_resources.

00164 {
00165   TAO_ORB_Core_TSS_Resources *tss = this->get_tss_resources ();
00166   return tss->client_leader_thread_ != 0;
00167 }

ACE_INLINE int TAO_Leader_Follower::leader_available void    const
 

Is there any thread running as a leader?

Definition at line 139 of file Leader_Follower.i.

References leaders_.

Referenced by wait_for_event.

00140 {
00141   return this->leaders_ != 0;
00142 }

ACE_INLINE TAO_SYNCH_MUTEX & TAO_Leader_Follower::lock void   
 

Get a reference to the underlying mutex.

Definition at line 119 of file Leader_Follower.i.

References lock_.

Referenced by TAO_LF_Strategy_Complete::reset_event_loop_thread, TAO_LF_Strategy_Complete::set_event_loop_thread, TAO_Thread_Lane_Resources::shutdown_reactor, and TAO_LF_Event::state_changed.

00120 {
00121   return this->lock_;
00122 }

ACE_INLINE void TAO_Leader_Follower::no_leaders_available void   
 

Called when we are out of leaders.

Definition at line 34 of file Leader_Follower.i.

References new_leader_generator_, and TAO_New_Leader_Generator::no_leaders_available.

Referenced by elect_new_leader.

00035 {
00036   if (this->new_leader_generator_)
00037     this->new_leader_generator_->no_leaders_available ();
00038 }

ACE_Reactor * TAO_Leader_Follower::reactor void   
 

Accesor to the reactor.

Definition at line 113 of file Leader_Follower.cpp.

References ACE_GUARD_RETURN, TAO_Resource_Factory::get_reactor, orb_core_, reactor_, TAO_ORB_Core::resource_factory, and TAO_SYNCH_MUTEX.

Referenced by TAO_Thread_Lane_Resources::finalize, TAO_ORB_Core::reactor, TAO_Thread_Lane_Resources::shutdown_reactor, and wait_for_event.

00114 {
00115   if (this->reactor_ == 0)
00116     {
00117       ACE_GUARD_RETURN (TAO_SYNCH_MUTEX, ace_mon, this->lock (), 0);
00118       if (this->reactor_ == 0)
00119         {
00120           this->reactor_ =
00121             this->orb_core_->resource_factory ()->get_reactor ();
00122         }
00123     }
00124   return this->reactor_;
00125 }

void TAO_Leader_Follower::release_follower TAO_LF_Follower  
 

The caller has finished using a follower.

Definition at line 45 of file Leader_Follower.cpp.

References follower_free_list_, and ACE_Intrusive_List< TAO_LF_Follower >::push_front.

Referenced by TAO_LF_Follower_Auto_Ptr::~TAO_LF_Follower_Auto_Ptr.

00046 {
00047   this->follower_free_list_.push_front (follower);
00048 }

ACE_INLINE void TAO_Leader_Follower::remove_follower TAO_LF_Follower   follower
 

Removes a follower from the leader-follower set.

Definition at line 176 of file Leader_Follower.i.

References follower_set_, and ACE_Intrusive_List< TAO_LF_Follower >::remove.

Referenced by TAO_LF_Follower::signal, and TAO_LF_Follower_Auto_Adder::~TAO_LF_Follower_Auto_Adder.

00177 {
00178   this->follower_set_.remove (follower);
00179 }

ACE_INLINE void TAO_Leader_Follower::reset_client_leader_thread void   
 

The current thread is no longer the leader thread in the client side leader-follower set.

Definition at line 154 of file Leader_Follower.i.

References TAO_ORB_Core_TSS_Resources::client_leader_thread_, client_thread_is_leader_, get_tss_resources, and leaders_.

Referenced by TAO_LF_Client_Leader_Thread_Helper::~TAO_LF_Client_Leader_Thread_Helper.

00155 {
00156   TAO_ORB_Core_TSS_Resources *tss = this->get_tss_resources ();
00157   --tss->client_leader_thread_;
00158   --this->leaders_;
00159   --this->client_thread_is_leader_;
00160 }

void TAO_Leader_Follower::reset_client_thread void   
 

A server thread has finished is making a request.

Definition at line 151 of file Leader_Follower.cpp.

References TAO_ORB_Core_TSS_Resources::client_leader_thread_, clients_, ACE_Reactor::end_reactor_event_loop, TAO_ORB_Core_TSS_Resources::event_loop_thread_, get_tss_resources, TAO_ORB_Core::has_shutdown, leaders_, orb_core_, and TAO_ORB_Core::reactor.

Referenced by TAO_LF_Client_Thread_Helper::~TAO_LF_Client_Thread_Helper.

00152 {
00153   // If we were a leader thread or an event loop thread, take back
00154   // leadership.
00155   TAO_ORB_Core_TSS_Resources *tss = this->get_tss_resources ();
00156   if (tss->event_loop_thread_ ||
00157       tss->client_leader_thread_)
00158     {
00159       ++this->leaders_;
00160     }
00161 
00162   this->clients_--;
00163   if (this->clients_ == 0 && this->orb_core_->has_shutdown ())
00164     {
00165       // The ORB has shutdown and we are the last client thread, we
00166       // must stop the reactor to ensure that any server threads go
00167       // away.
00168       this->orb_core_->reactor ()->end_reactor_event_loop ();
00169     }
00170 }

ACE_INLINE void TAO_Leader_Follower::reset_event_loop_thread void   
 

The current thread is not a server thread anymore, reset any flags and counters.

Definition at line 111 of file Leader_Follower.i.

References TAO_ORB_Core_TSS_Resources::event_loop_thread_, get_tss_resources, and reset_event_loop_thread_i.

Referenced by TAO_LF_Strategy_Complete::reset_event_loop_thread.

00112 {
00113   TAO_ORB_Core_TSS_Resources *tss = this->get_tss_resources ();
00114   if (tss->event_loop_thread_ > 0)
00115     this->reset_event_loop_thread_i (tss);
00116 }

ACE_INLINE void TAO_Leader_Follower::reset_event_loop_thread_i TAO_ORB_Core_TSS_Resources   tss [private]
 

Implement the reset_event_loop_thread() method, once the TSS resources have been acquired. Also used in the set_upcall_thread.

Definition at line 95 of file Leader_Follower.i.

References TAO_ORB_Core_TSS_Resources::client_leader_thread_, TAO_ORB_Core_TSS_Resources::event_loop_thread_, and leaders_.

Referenced by reset_event_loop_thread, and set_upcall_thread.

00096 {
00097   // Always decrement <event_loop_thread_>. If <event_loop_thread_>
00098   // reaches 0 and we are not a client leader, we are done with our
00099   // duties of running the event loop. Therefore, decrement the
00100   // leaders.  Otherwise, we just got done with a nested call to the
00101   // event loop or a call to the event loop when we were the client
00102   // leader.
00103   --tss->event_loop_thread_;
00104 
00105   if (tss->event_loop_thread_ == 0 &&
00106       tss->client_leader_thread_ == 0)
00107     --this->leaders_;
00108 }

ACE_INLINE ACE_Reverse_Lock< TAO_SYNCH_MUTEX > & TAO_Leader_Follower::reverse_lock void   
 

Provide a pre-initialized reverse lock for the Leader/Followers set.

The Leader/Followers set mutex must be release during some long running operations. This helper class simplifies the process of releasing and reacquiring said mutex.

Definition at line 182 of file Leader_Follower.i.

References reverse_lock_.

00183 {
00184   return this->reverse_lock_;
00185 }

void TAO_Leader_Follower::set_client_leader_thread ACE_thread_t    thread_ID
 

sets the thread ID of the leader thread in the leader-follower model.

ACE_INLINE void TAO_Leader_Follower::set_client_leader_thread void   
 

The current thread has become the leader thread in the client side leader-follower set.

Definition at line 145 of file Leader_Follower.i.

References TAO_ORB_Core_TSS_Resources::client_leader_thread_, client_thread_is_leader_, get_tss_resources, and leaders_.

Referenced by TAO_LF_Client_Leader_Thread_Helper::TAO_LF_Client_Leader_Thread_Helper.

00146 {
00147   TAO_ORB_Core_TSS_Resources *tss = this->get_tss_resources ();
00148   ++this->leaders_;
00149   ++this->client_thread_is_leader_;
00150   ++tss->client_leader_thread_;
00151 }

void TAO_Leader_Follower::set_client_thread void   
 

A server thread is making a request.

Definition at line 128 of file Leader_Follower.cpp.

References TAO_ORB_Core_TSS_Resources::client_leader_thread_, clients_, TAO_ORB_Core_TSS_Resources::event_loop_thread_, get_tss_resources, TAO_ORB_Core::has_shutdown, leaders_, orb_core_, TAO_ORB_Core::reactor, and ACE_Reactor::reset_reactor_event_loop.

Referenced by TAO_LF_Client_Thread_Helper::TAO_LF_Client_Thread_Helper.

00129 {
00130   // If we were a leader thread or an event loop thread, give up
00131   // leadership.
00132   TAO_ORB_Core_TSS_Resources *tss = this->get_tss_resources ();
00133   if (tss->event_loop_thread_ ||
00134       tss->client_leader_thread_)
00135     {
00136       --this->leaders_;
00137     }
00138 
00139   if (this->clients_ == 0 &&
00140       this->orb_core_->has_shutdown ())
00141     {
00142       // The ORB has shutdown and we are the first client after
00143       // that. This means that the reactor is disabled, we must
00144       // re-enable it if we want to receive any replys...
00145       this->orb_core_->reactor ()->reset_reactor_event_loop ();
00146     }
00147   this->clients_++;
00148 }

ACE_INLINE int TAO_Leader_Follower::set_event_loop_thread ACE_Time_Value   max_wait_time
 

The current thread has become a server thread (i.e. called ORB::run), update any flags and counters.

Definition at line 62 of file Leader_Follower.i.

References TAO_ORB_Core_TSS_Resources::client_leader_thread_, client_thread_is_leader_, TAO_ORB_Core_TSS_Resources::event_loop_thread_, get_tss_resources, leaders_, and wait_for_client_leader_to_complete.

Referenced by TAO_LF_Strategy_Complete::set_event_loop_thread.

00063 {
00064   TAO_ORB_Core_TSS_Resources *tss = this->get_tss_resources ();
00065 
00066   // Make sure that there is no other client thread run the show.  If
00067   // we are the client thread running the show, then it is ok.
00068   if (this->client_thread_is_leader_ &&
00069       tss->client_leader_thread_ == 0)
00070     {
00071       int result =
00072         this->wait_for_client_leader_to_complete (max_wait_time);
00073 
00074       if (result != 0)
00075         return result;
00076     }
00077 
00078   // If <event_loop_thread_> == 0 and <client_leader_thread_> == 0, we
00079   // are running the event loop for the first time.  Therefore,
00080   // increment the leaders.  Otherwise, simply increment
00081   // <event_loop_thread_> since either (a) if <event_loop_thread_> !=
00082   // 0 this is a nested call to the event loop, or (b)
00083   // <client_leader_thread_> != 0 this is a call to the event loop
00084   // while we are a client leader.
00085   if (tss->event_loop_thread_ == 0 &&
00086       tss->client_leader_thread_ == 0)
00087     ++this->leaders_;
00088 
00089   ++tss->event_loop_thread_;
00090 
00091   return 0;
00092 }

ACE_INLINE void TAO_Leader_Follower::set_upcall_thread void   
 

This thread is going to perform an upcall, it will no longer be an event loop thread.

Definition at line 125 of file Leader_Follower.i.

References ACE_GUARD, elect_new_leader, TAO_ORB_Core_TSS_Resources::event_loop_thread_, get_tss_resources, reset_event_loop_thread_i, and TAO_SYNCH_MUTEX.

Referenced by TAO_LF_Strategy_Complete::set_upcall_thread.

00126 {
00127   TAO_ORB_Core_TSS_Resources *tss = this->get_tss_resources ();
00128 
00129   if (tss->event_loop_thread_ > 0)
00130     {
00131       ACE_GUARD (TAO_SYNCH_MUTEX, ace_mon, this->lock ());
00132       this->reset_event_loop_thread_i (tss);
00133 
00134       this->elect_new_leader ();
00135     }
00136 }

int TAO_Leader_Follower::wait_for_client_leader_to_complete ACE_Time_Value   max_wait_time [private]
 

Wait for the client leader to complete.

Definition at line 67 of file Leader_Follower.cpp.

References ACE_ERROR, ACE_TEXT, client_thread_is_leader_, ETIME, event_loop_threads_condition_, event_loop_threads_waiting_, ACE_OS::gettimeofday, LM_ERROR, and ACE_Countdown_Time::update.

Referenced by set_event_loop_thread.

00068 {
00069   int result = 0;
00070   ACE_Countdown_Time countdown (max_wait_time);
00071 
00072   // Note that we are waiting.
00073   ++this->event_loop_threads_waiting_;
00074 
00075   while (this->client_thread_is_leader_ &&
00076          result != -1)
00077     {
00078       if (max_wait_time == 0)
00079         {
00080           if (this->event_loop_threads_condition_.wait () == -1)
00081             {
00082               ACE_ERROR ((LM_ERROR,
00083                           ACE_TEXT ("TAO (%P|%t): TAO_Leader_Follower::wait_for_client_leader_to_complete - ")
00084                           ACE_TEXT ("Condition variable wait failed\n")));
00085 
00086               result = -1;
00087             }
00088         }
00089       else
00090         {
00091           countdown.update ();
00092           ACE_Time_Value tv = ACE_OS::gettimeofday ();
00093           tv += *max_wait_time;
00094           if (this->event_loop_threads_condition_.wait (&tv) == -1)
00095             {
00096               if (errno != ETIME)
00097                 ACE_ERROR ((LM_ERROR,
00098                             ACE_TEXT ("TAO (%P|%t): TAO_Leader_Follower::wait_for_client_leader_to_complete - ")
00099                             ACE_TEXT ("Condition variable wait failed\n")));
00100 
00101               result = -1;
00102             }
00103         }
00104     }
00105 
00106   // Reset waiting state.
00107   --this->event_loop_threads_waiting_;
00108 
00109   return result;
00110 }

int TAO_Leader_Follower::wait_for_event TAO_LF_Event   event,
TAO_Transport   transport,
ACE_Time_Value   max_wait_time
 

Wait on the Leader/Followers loop until one event happens.

Parameters:
event  The event we wait for, the loop iterates until the event is sucessful, or it fails due to timeout, and error or a connection closed.
transport  The transport attached to the event
max_wait_time  Limit the time spent on the loop
Todo:
Document this better, split the Follower code to the TAO_LF_Follower class, we probably don't need the transport object.

Definition at line 173 of file Leader_Follower.cpp.

References ACE_DEBUG, ACE_ERROR, ACE_ERROR_RETURN, ACE_GUARD_RETURN, elect_new_leader, TAO_LF_Event::error_detected, ETIME, TAO_LF_Follower_Auto_Ptr::get, ACE_OS::gettimeofday, ACE_Reactor::handle_events, TAO_Transport::id, TAO_LF_Event::keep_waiting, leader_available, TAO_LF_Event::LFS_TIMEOUT, LM_DEBUG, LM_ERROR, ACE_Reactor::owner, reactor, reactor_, ACE_Thread::self, TAO_LF_Event::set_state, TAO_LF_Event::successful, TAO_SYNCH_MUTEX, ACE_Countdown_Time::update, and ACE_Time_Value::zero.

Referenced by TAO_Transport::close_connection_shared, TAO_Leader_Follower_Flushing_Strategy::flush_message, TAO_Wait_On_Leader_Follower::wait, and TAO_LF_Connect_Strategy::wait.

00176 {
00177   // Obtain the lock.
00178   ACE_GUARD_RETURN (TAO_SYNCH_MUTEX, ace_mon, this->lock (), -1);
00179 
00180   ACE_Countdown_Time countdown (max_wait_time);
00181 
00182   // Optmize the first iteration [no access to errno]
00183   int result = 1;
00184 
00185   // For some cases the transport may dissappear like when waiting for
00186   // connection to be initiated or closed. So cache the id.
00187   // @@ NOTE: This is not completely safe either. We will be fine for
00188   // cases that dont access the id ie. when debug level is off but
00189   // with debugging level on we are on a sticky wicket. Hopefully none
00190   // of our users should run TAO with debugging enabled like they did
00191   // in PathFinder
00192   size_t t_id = 0;
00193 
00194   if (TAO_debug_level)
00195     t_id = transport->id ();
00196 
00197   {
00198     // Calls this->set_client_thread () on construction and
00199     // this->reset_client_thread () on destruction.
00200     TAO_LF_Client_Thread_Helper client_thread_helper (*this);
00201     ACE_UNUSED_ARG (client_thread_helper);
00202 
00203     // Check if there is a leader.  Note that it cannot be us since we
00204     // gave up our leadership when we became a client.
00205     if (this->leader_available ())
00206       {
00207         // = Wait as a follower.
00208 
00209         // Grab a follower:
00210         TAO_LF_Follower_Auto_Ptr follower (*this);
00211         if (follower.get () == 0)
00212           return -1;
00213 
00214         if (TAO_debug_level >= 5)
00215           ACE_DEBUG ((LM_DEBUG,
00216                       "TAO (%P|%t) - Leader_Follower[%d]::wait_for_event,"
00217                       " (follower), cond <%x>\n",
00218                       t_id, follower.get ()));
00219 
00220         // Bound the follower and the LF_Event, this is important to
00221         // get a signal when the event terminates
00222         TAO_LF_Event_Binder event_binder (event, follower.get ());
00223 
00224         while (event->keep_waiting () &&
00225                this->leader_available ())
00226           {
00227             // Add ourselves to the list, do it everytime we wake up
00228             // from the CV loop. Because:
00229             //
00230             // - The leader thread could have elected us as the new
00231             // leader.
00232             // - Before we can assume the role another thread becomes
00233             // the leader
00234             // - But our condition variable could have been removed
00235             // already, if we don't add it again we will never wake
00236             // up.
00237             //
00238             // Notice that we can have spurious wake ups, in that case
00239             // adding the leader results in an error, that must be
00240             // ignored.
00241             // You may be thinking of not removing the condition
00242             // variable in the code that sends the signal, but
00243             // removing it here, that does not work either, in that
00244             // case the condition variable may be used twice:
00245             //
00246             //  - Wake up because its reply arrived
00247             //  - Wake up because it must become the leader
00248             //
00249             // but only the first one has any effect, so the leader is
00250             // lost.
00251             //
00252 
00253             TAO_LF_Follower_Auto_Adder auto_adder (*this, follower);
00254 
00255             if (max_wait_time == 0)
00256               {
00257                 if (follower->wait (max_wait_time) == -1)
00258                   {
00259                     if (TAO_debug_level >= 5)
00260                       ACE_DEBUG ((LM_DEBUG,
00261                                   "TAO (%P|%t) - Leader_Follower[%d]::wait_for_event, "
00262                                   " (follower) [no timer, cond failed]\n",
00263                                   t_id));
00264 
00265                     // @@ Michael: What is our error handling in this case?
00266                     //             We could be elected as leader and
00267                     //             no leader would come in?
00268                     return -1;
00269                   }
00270               }
00271             else
00272               {
00273                 countdown.update ();
00274                 ACE_Time_Value tv = ACE_OS::gettimeofday ();
00275                 tv += *max_wait_time;
00276                 if (follower->wait (&tv) == -1)
00277                   {
00278                     if (TAO_debug_level >= 5)
00279                       ACE_DEBUG ((LM_DEBUG,
00280                                   "TAO (%P|%t) - Leader_Follower[%d]::wait, "
00281                                   "(follower) [has timer, follower failed]\n",
00282                                   t_id ));
00283 
00284                     // If we have timedout set the state in the
00285                     // LF_Event. We call the non-locking,
00286                     // no-signalling method on LF_Event.
00287                     if (errno == ETIME)
00288                         // We have timedout
00289                         event->set_state (TAO_LF_Event::LFS_TIMEOUT);
00290 
00291                     if (!event->successful ())
00292                       {
00293                         // Remove follower can fail because either
00294                         // 1) the condition was satisfied (i.e. reply
00295                         //    received or queue drained), or
00296                         // 2) somebody elected us as leader, or
00297                         // 3) the connection got closed.
00298                         //
00299                         // Therefore:
00300                         // If remove_follower fails and the condition
00301                         // was not satisfied, we know that we got
00302                         // elected as a leader.
00303                         // But we got a timeout, so we cannot become
00304                         // the leader, therefore, we have to select a
00305                         // new leader.
00306                         //
00307 
00308                         if (this->elect_new_leader () == -1
00309                             && TAO_debug_level > 0)
00310                           {
00311                             ACE_ERROR ((LM_ERROR,
00312                                         "TAO (%P|%t) - Leader_Follower[%d]::wait_for_event, "
00313                                         "elect_new_leader failed\n",
00314                                         t_id ));
00315                           }
00316                       }
00317 
00318 
00319                     return -1;
00320                   }
00321               }
00322           }
00323 
00324         countdown.update ();
00325 
00326         // @@ Michael: This is an old comment why we do not want to
00327         //             remove the follower here.
00328         // We should not remove the follower here, we *must* remove it when
00329         // we signal it so the same condition is not signalled for
00330         // both wake up as a follower and as the next leader.
00331 
00332         if (TAO_debug_level >= 5)
00333           ACE_DEBUG ((LM_DEBUG,
00334                       "TAO (%P|%t) - Leader_Follower[%d]::wait_for_event,"
00335                       " done (follower), successful %d\n",
00336                       t_id,
00337                       event->successful ()));
00338 
00339         // Now somebody woke us up to become a leader or to handle our
00340         // input. We are already removed from the follower queue.
00341 
00342         if (event->successful ())
00343           return 0;
00344 
00345         if (event->error_detected ())
00346           return -1;
00347 
00348         // FALLTHROUGH
00349         // We only get here if we woke up but the reply is not
00350         // complete yet, time to assume the leader role....
00351         // i.e. ACE_ASSERT (event->successful () == 0);
00352       }
00353 
00354     // = Leader Code.
00355 
00356     // The only way to reach this point is if we must become the
00357     // leader, because there is no leader or we have to update to a
00358     // leader or we are doing nested upcalls in this case we do
00359     // increase the refcount on the leader in TAO_ORB_Core.
00360 
00361     // Calls this->set_client_leader_thread () on
00362     // construction and this->reset_client_leader_thread ()
00363     // on destruction.  Note that this may increase the refcount of
00364     // the leader.
00365     TAO_LF_Client_Leader_Thread_Helper client_leader_thread_helper (*this);
00366     ACE_UNUSED_ARG (client_leader_thread_helper);
00367 
00368     {
00369       ACE_GUARD_RETURN (ACE_Reverse_Lock<TAO_SYNCH_MUTEX>, rev_mon,
00370                         this->reverse_lock (), -1);
00371 
00372       // Become owner of the reactor.
00373       ACE_Reactor *reactor = this->reactor_;
00374       reactor->owner (ACE_Thread::self ());
00375 
00376       // Run the reactor event loop.
00377 
00378       if (TAO_debug_level >= 5)
00379         ACE_DEBUG ((LM_DEBUG,
00380                     "TAO (%P|%t) - Leader_Follower[%d]::wait_for_event,"
00381                     " (leader) enter reactor event loop\n",
00382                     t_id));
00383 
00384       // If we got our event, no need to run the event loop any
00385       // further.
00386       while (event->keep_waiting ())
00387         {
00388           // Run the event loop.
00389           result = reactor->handle_events (max_wait_time);
00390 
00391           // Did we timeout? If so, stop running the loop.
00392           if (result == 0 &&
00393               max_wait_time != 0 &&
00394               *max_wait_time == ACE_Time_Value::zero)
00395             break;
00396 
00397           // Other errors? If so, stop running the loop.
00398           if (result == -1)
00399             break;
00400 
00401           // Otherwise, keep going...
00402         }
00403 
00404       if (TAO_debug_level >= 5)
00405         ACE_DEBUG ((LM_DEBUG,
00406                     "TAO (%P|%t) - Leader_Follower[%d]::wait_for_event,"
00407                     " (leader) exit reactor event loop\n",
00408                     t_id));
00409     }
00410   }
00411   //
00412   // End artificial scope for auto_ptr like helpers calling:
00413   // this->reset_client_thread () and (maybe)
00414   // this->reset_client_leader_thread ().
00415   //
00416 
00417   // Wake up the next leader, we cannot do that in handle_input,
00418   // because the woken up thread would try to get into handle_events,
00419   // which is at the time in handle_input still occupied. But do it
00420   // before checking the error in <result>, even if there is an error
00421   // in our input we should continue running the loop in another
00422   // thread.
00423 
00424   if (this->elect_new_leader () == -1)
00425     ACE_ERROR_RETURN ((LM_ERROR,
00426                        "TAO (%P|%t) - Leader_Follower[%d]::wait_for_event,"
00427                        " failed to elect new leader\n",
00428                        t_id),
00429                       -1);
00430 
00431   if (result == -1)
00432     ACE_ERROR_RETURN ((LM_ERROR,
00433                        "TAO (%P|%t) - Leader_Follower[%d]::wait_for_event,"
00434                        " handle_events failed\n",
00435                        t_id),
00436                       -1);
00437 
00438   // Return an error if there was a problem receiving the reply...
00439   if (max_wait_time != 0)
00440     {
00441       if (!event->successful ()
00442           && *max_wait_time == ACE_Time_Value::zero)
00443         {
00444           result = -1;
00445           errno = ETIME;
00446         }
00447       else if (event->error_detected ())
00448         {
00449           // If the time did not expire yet, but we get a failure,
00450           // e.g. the connections closed, we should still return an error.
00451           result = -1;
00452         }
00453     }
00454   else
00455     {
00456       result = 0;
00457       if (event->error_detected ())
00458         {
00459           result = -1;
00460         }
00461     }
00462   return result;
00463 }


Member Data Documentation

int TAO_Leader_Follower::client_thread_is_leader_ [private]
 

Is a client thread the current leader?

Definition at line 230 of file Leader_Follower.h.

Referenced by reset_client_leader_thread, set_client_leader_thread, set_event_loop_thread, and wait_for_client_leader_to_complete.

int TAO_Leader_Follower::clients_ [private]
 

Count the number of active clients, this is useful to know when to deactivate the reactor.

Definition at line 224 of file Leader_Follower.h.

Referenced by has_clients, reset_client_thread, and set_client_thread.

TAO_SYNCH_CONDITION TAO_Leader_Follower::event_loop_threads_condition_ [private]
 

Condition variable for server threads waiting for the client leader to complete.

Definition at line 237 of file Leader_Follower.h.

Referenced by elect_new_leader, and wait_for_client_leader_to_complete.

int TAO_Leader_Follower::event_loop_threads_waiting_ [private]
 

Are server threads waiting for the client leader to complete?

Definition at line 233 of file Leader_Follower.h.

Referenced by elect_new_leader, and wait_for_client_leader_to_complete.

Follower_Set TAO_Leader_Follower::follower_free_list_ [private]
 

Use a free list to allocate and release Follower objects.

Definition at line 212 of file Leader_Follower.h.

Referenced by allocate_follower, release_follower, and ~TAO_Leader_Follower.

Follower_Set TAO_Leader_Follower::follower_set_ [private]
 

Definition at line 209 of file Leader_Follower.h.

Referenced by add_follower, elect_new_leader_i, follower_available, and remove_follower.

int TAO_Leader_Follower::leaders_ [private]
 

Count the number of active leaders. There could be many leaders in the thread pool (i.e. calling ORB::run), and the same leader could show up multiple times as it receives nested upcalls and sends more requests.

Definition at line 220 of file Leader_Follower.h.

Referenced by elect_new_leader, leader_available, reset_client_leader_thread, reset_client_thread, reset_event_loop_thread_i, set_client_leader_thread, set_client_thread, and set_event_loop_thread.

TAO_SYNCH_MUTEX TAO_Leader_Follower::lock_ [private]
 

To synchronize access to the members.

Definition at line 202 of file Leader_Follower.h.

Referenced by lock.

TAO_New_Leader_Generator* TAO_Leader_Follower::new_leader_generator_ [private]
 

Leader/Follower class uses this method to notify the system that we are out of leaders.

Definition at line 241 of file Leader_Follower.h.

Referenced by no_leaders_available.

TAO_ORB_Core* TAO_Leader_Follower::orb_core_ [private]
 

The orb core.

Definition at line 199 of file Leader_Follower.h.

Referenced by get_tss_resources, reactor, reset_client_thread, set_client_thread, and ~TAO_Leader_Follower.

ACE_Reactor* TAO_Leader_Follower::reactor_ [private]
 

The reactor.

Definition at line 227 of file Leader_Follower.h.

Referenced by reactor, wait_for_event, and ~TAO_Leader_Follower.

ACE_Reverse_Lock<TAO_SYNCH_MUTEX> TAO_Leader_Follower::reverse_lock_ [private]
 

do protect the access to the following three members.

Definition at line 205 of file Leader_Follower.h.

Referenced by reverse_lock.


The documentation for this class was generated from the following files:
Generated on Mon Jun 16 15:22:48 2003 for TAO by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002