=default for generated implementation copy ctor
[ACE_TAO.git] / TAO / examples / Load_Balancing / Load_Balancer_i.cpp
blob0aad497d12f77e382df57dcee490b0ae237e2dcb
1 //=============================================================================
2 /**
3 * @file Load_Balancer_i.cpp
5 * @author Marina Spivak <marina@cs.wustl.edu>
6 */
7 //=============================================================================
10 #include "Load_Balancer_i.h"
11 #include <memory>
12 #include "ace/OS_NS_time.h"
14 Object_Group_Factory_i::Object_Group_Factory_i ()
18 Object_Group_Factory_i::~Object_Group_Factory_i ()
22 void
23 Object_Group_Factory_i::remove_group (const ACE_CString &id,
24 int random)
26 // Remove the entry from the appropriate map of groups.
27 if (random)
28 random_groups_.unbind (id);
29 else
30 rr_groups_.unbind (id);
33 Load_Balancer::Object_Group_ptr
34 Object_Group_Factory_i::make_round_robin (const char * id)
36 return make_group (0,
37 id);
40 Load_Balancer::Object_Group_ptr
41 Object_Group_Factory_i::make_random (const char * id)
43 return make_group (1,
44 id);
47 Load_Balancer::Object_Group_ptr
48 Object_Group_Factory_i::make_group (int random,
49 const char * id)
51 ACE_CString group_id (id);
53 // Check to make sure we don't already have a group with the same
54 // <id>.
55 if (rr_groups_.find (group_id) == 0
56 || random_groups_.find (group_id) == 0)
57 throw Load_Balancer::duplicate_group ();
58 else
60 // Store our result here for return.
61 Load_Balancer::Object_Group_var group;
63 // Create an appropriate servant.
64 Object_Group_i * group_servant;
65 if (random)
66 ACE_NEW_THROW_EX (group_servant,
67 Random_Object_Group (id, this),
68 CORBA::NO_MEMORY ());
69 else
70 ACE_NEW_THROW_EX (group_servant,
71 RR_Object_Group (id, this),
72 CORBA::NO_MEMORY ());
74 // Temporarily put the servant into the auto_ptr.
75 std::unique_ptr<Object_Group_i> temp (group_servant);
77 // Register with the poa, begin using ref. counting.
78 group = group_servant->_this ();
80 group_servant->_remove_ref ();
81 temp.release ();
83 // Make an entry in appropriate map of groups.
84 if (random)
86 if (random_groups_.bind (group_id, group) == -1)
87 throw CORBA::INTERNAL ();
89 ACE_DEBUG ((LM_DEBUG,
90 "Load_Balancer: Created new Random Group"
91 " with id <%C>\n", id));
93 else
95 if (rr_groups_.bind (group_id, group) == -1)
96 throw CORBA::INTERNAL ();
97 ACE_DEBUG ((LM_DEBUG,
98 "Load_Balancer: Created new Round Robin Group"
99 " with id <%C>\n", id));
101 // Return.
102 return group._retn ();
106 Load_Balancer::Object_Group_ptr
107 Object_Group_Factory_i::resolve (const char * id)
109 ACE_CString group_id (id);
110 Load_Balancer::Object_Group_var group;
112 if (rr_groups_.find (group_id, group) == -1
113 && random_groups_.find (group_id, group) == -1)
114 throw Load_Balancer::no_such_group ();
115 else
116 return group._retn ();
119 Load_Balancer::Group_List *
120 Object_Group_Factory_i::list_groups (int random)
122 Load_Balancer::Group_List * list;
124 // Figure out the length of the list.
125 CORBA::ULong len;
126 if (random)
127 len = random_groups_.current_size ();
128 else
129 len = rr_groups_.current_size ();
131 // Allocate the list of <len> length.
132 ACE_NEW_THROW_EX (list,
133 Load_Balancer::Group_List (len),
134 CORBA::NO_MEMORY ());
135 list->length (len);
137 // Create an iterator for group structure to populate the list.
138 Object_Group_Factory_i::HASH_MAP::ITERATOR *group_iter;
139 Object_Group_Factory_i::HASH_MAP::ITERATOR random_iter (random_groups_);
140 Object_Group_Factory_i::HASH_MAP::ITERATOR rr_iter (rr_groups_);
141 if (random)
142 group_iter = &random_iter;
143 else
144 group_iter = &rr_iter;
146 // Iterate over groups and populate the list.
147 Object_Group_Factory_i::HASH_MAP::ENTRY *hash_entry = 0;
148 for (CORBA::ULong i = 0; i < len; i++)
150 group_iter->next (hash_entry);
151 group_iter->advance ();
153 (*list)[i] = hash_entry->ext_id_.c_str ();
156 return list;
159 Load_Balancer::Group_List *
160 Object_Group_Factory_i::round_robin_groups ()
162 return list_groups (0);
165 Load_Balancer::Group_List *
166 Object_Group_Factory_i::random_groups ()
168 return list_groups (1);
171 Object_Group_i::Object_Group_i (const char * id,
172 Object_Group_Factory_i *my_factory)
173 : id_ (id),
174 my_factory_ (my_factory)
178 Object_Group_i::~Object_Group_i ()
180 // Need to delete all the items from the member_id_list, to avoid
181 // memory leaks.
182 Object_Group_i::ITERATOR iter (member_id_list_);
186 delete (iter.next ());
187 } while (iter.advance ());
190 char *
191 Object_Group_i::id ()
193 return CORBA::string_dup (id_.c_str ());
196 void
197 Object_Group_i::bind (const Load_Balancer::Member & member)
199 ACE_CString member_id (member.id);
200 CORBA::Object_var obj = CORBA::Object::_duplicate (member.obj.in ());
202 // Insert new member into <members_> and check for duplicates/failures.
203 int result = members_.trybind (member_id, obj);
204 if (result == 1)
205 throw Load_Balancer::duplicate_member ();
206 else if (result == -1)
207 throw CORBA::INTERNAL ();
209 // Insert new member's id into <member_id_list_>.
210 ACE_CString *new_id;
211 ACE_NEW_THROW_EX (new_id,
212 ACE_CString (member.id),
213 CORBA::NO_MEMORY ());
214 if (member_id_list_.insert_tail (new_id) == 0)
215 throw CORBA::NO_MEMORY ();
217 // Theoretically, we should deal with memory failures more
218 // thoroughly. But, practically, the whole system is going to be
219 // hosed anyways ...
221 ACE_DEBUG ((LM_DEBUG,
222 "Load_Balancer: Added member <%C> to <%C> Group\n",
223 member_id.c_str (),
224 id_.c_str ()));
227 void
228 Object_Group_i::unbind (const char * id)
230 ACE_CString member_id (id);
232 // Code below works if list and hash map states are consistent,
233 // which is the case unless the system experienced major problems,
234 // e.g., ran out of memory ...
236 // Check to make sure we have it.
237 if (members_.find (member_id) == -1)
238 throw Load_Balancer::no_such_member ();
240 // Remove all entries for this member.
241 members_.unbind (member_id);
243 Object_Group_i::ITERATOR iter (member_id_list_);
244 while (member_id != *(iter.next ()))
245 iter.advance ();
246 delete (iter.next ());
247 iter.remove ();
249 ACE_DEBUG ((LM_DEBUG,
250 "Load_Balancer: Removed member with id <%C>"
251 "from <%C> object group\n", id, id_.c_str ()));
254 CORBA::Object_ptr
255 Object_Group_i::resolve_with_id (const char * id)
257 CORBA::Object_var obj;
258 ACE_CString member_id (id);
260 if (members_.find (member_id, obj) == -1)
261 throw Load_Balancer::no_such_member ();
263 return obj._retn ();
266 Load_Balancer::Member_ID_List *
267 Object_Group_i::members ()
269 Load_Balancer::Member_ID_List * list;
271 // Figure out the length of the list.
272 CORBA::ULong len = members_.current_size ();
274 // Allocate the list of <len> length.
275 ACE_NEW_THROW_EX (list,
276 Load_Balancer::Member_ID_List (len),
277 CORBA::NO_MEMORY ());
278 list->length (len);
280 // Create an iterator for <member_id_list_> to populate the list.
281 Object_Group_i::ITERATOR id_iter (member_id_list_);
283 // Iterate over groups and populate the list.
284 for (CORBA::ULong i = 0; i < len; i++)
286 (*list)[i] = id_iter.next ()->c_str ();
287 id_iter.advance ();
290 return list;
293 void
294 Object_Group_i::destroy ()
296 // Deregister with POA.
297 PortableServer::POA_var poa =
298 this->_default_POA ();
300 PortableServer::ObjectId_var id =
301 poa->servant_to_id (this);
303 poa->deactivate_object (id.in ());
305 ACE_DEBUG ((LM_DEBUG,
306 "Load_Balancer: Destroyed object group"
307 "with id <%C>\n", id_.c_str ()));
310 Random_Object_Group::Random_Object_Group (const char *id,
311 Object_Group_Factory_i *my_factory)
312 : Object_Group_i (id, my_factory)
314 // Seed the random number generator.
315 ACE_OS::srand (static_cast<u_int> (ACE_OS::time ()));
318 Random_Object_Group::~Random_Object_Group ()
322 void
323 Random_Object_Group::destroy ()
325 //Deregisters this <Object_Group> with its
326 // <Object_Group_Factory>.
327 my_factory_->remove_group (id_, 1);
329 Object_Group_i::destroy ();
332 CORBA::Object_ptr
333 Random_Object_Group::resolve ()
335 CORBA::Object_var obj;
337 size_t group_size = members_.current_size ();
338 if (group_size == 0)
339 throw Load_Balancer::no_such_member ();
341 // Generate random number in the range [0, group_size - 1]
342 size_t member = ACE_OS::rand() % group_size;
344 // Get the id of the member to return to the client.
345 ACE_CString *id = 0;
346 member_id_list_.get (id, member);
348 ACE_DEBUG ((LM_DEBUG, "Load_Balancer: In <%C> Group resolved to <%C>\n",
349 id_.c_str (),
350 id->c_str()));
352 // Return the object reference corresponding to the found id to the client.
353 members_.find (*id, obj);
354 return obj._retn ();
357 RR_Object_Group::RR_Object_Group (const char *id,
358 Object_Group_Factory_i *my_factory)
359 : Object_Group_i (id, my_factory),
360 next_ (0)
364 RR_Object_Group::~RR_Object_Group ()
368 void
369 RR_Object_Group::destroy ()
371 //Deregisters this <Object_Group> with its
372 // <Object_Group_Factory>.
373 my_factory_->remove_group (id_, 0);
375 Object_Group_i::destroy ();
378 CORBA::Object_ptr
379 RR_Object_Group::resolve ()
381 CORBA::Object_var obj;
383 size_t group_size = members_.current_size ();
384 if (group_size == 0)
385 throw Load_Balancer::no_such_member ();
387 // Get the id of the member to return to the client.
388 ACE_CString *id = 0;
389 member_id_list_.get (id, next_);
391 ACE_DEBUG ((LM_DEBUG, "Load_Balancer: In <%C> Group resolved to <%C>\n",
392 id_.c_str (),
393 id->c_str ()));
395 // Adjust <next_> for the next invocation.
396 next_ = (next_ + 1) % group_size;
398 // Return the object reference corresponding to the found id to the client.
399 if (members_.find (*id, obj) == -1)
400 throw CORBA::INTERNAL ();
402 return obj._retn ();
405 void
406 RR_Object_Group::unbind (const char *id)
408 ACE_CString member_id (id);
410 // Check to make sure we have it.
411 if (members_.find (member_id) == -1)
412 throw Load_Balancer::no_such_member ();
414 // Remove all entries for this member.
415 members_.unbind (member_id);
417 // As we remove the id from the <member_id_list>, we note the
418 // position of the id in the list.
419 size_t position = 0;
420 Object_Group_i::ITERATOR iter (member_id_list_);
421 while (member_id != *(iter.next ()))
423 iter.advance ();
424 position++;
426 delete (iter.next ());
427 iter.remove ();
429 // Update <next_> if necessary to reflect the deletion.
430 if (position < next_)
431 next_--;
433 else if (position == next_)
434 next_ = next_ % (members_.current_size ());
436 ACE_DEBUG ((LM_DEBUG,
437 "Load_Balancer: Removed member with id <%C>"
438 "from <%C> object group\n", id, id_.c_str ()));