1 //=============================================================================
3 * @file Load_Balancer_i.cpp
5 * @author Marina Spivak <marina@cs.wustl.edu>
7 //=============================================================================
10 #include "Load_Balancer_i.h"
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 ()
23 Object_Group_Factory_i::remove_group (const ACE_CString
&id
,
26 // Remove the entry from the appropriate map of groups.
28 random_groups_
.unbind (id
);
30 rr_groups_
.unbind (id
);
33 Load_Balancer::Object_Group_ptr
34 Object_Group_Factory_i::make_round_robin (const char * id
)
40 Load_Balancer::Object_Group_ptr
41 Object_Group_Factory_i::make_random (const char * id
)
47 Load_Balancer::Object_Group_ptr
48 Object_Group_Factory_i::make_group (int random
,
51 ACE_CString
group_id (id
);
53 // Check to make sure we don't already have a group with the same
55 if (rr_groups_
.find (group_id
) == 0
56 || random_groups_
.find (group_id
) == 0)
57 throw Load_Balancer::duplicate_group ();
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
;
66 ACE_NEW_THROW_EX (group_servant
,
67 Random_Object_Group (id
, this),
70 ACE_NEW_THROW_EX (group_servant
,
71 RR_Object_Group (id
, this),
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 ();
83 // Make an entry in appropriate map of groups.
86 if (random_groups_
.bind (group_id
, group
) == -1)
87 throw CORBA::INTERNAL ();
90 "Load_Balancer: Created new Random Group"
91 " with id <%C>\n", id
));
95 if (rr_groups_
.bind (group_id
, group
) == -1)
96 throw CORBA::INTERNAL ();
98 "Load_Balancer: Created new Round Robin Group"
99 " with id <%C>\n", id
));
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 ();
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.
127 len
= random_groups_
.current_size ();
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 ());
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_
);
142 group_iter
= &random_iter
;
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 ();
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
)
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
182 Object_Group_i::ITERATOR
iter (member_id_list_
);
186 delete (iter
.next ());
187 } while (iter
.advance ());
191 Object_Group_i::id ()
193 return CORBA::string_dup (id_
.c_str ());
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
);
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_>.
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
221 ACE_DEBUG ((LM_DEBUG
,
222 "Load_Balancer: Added member <%C> to <%C> Group\n",
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 ()))
246 delete (iter
.next ());
249 ACE_DEBUG ((LM_DEBUG
,
250 "Load_Balancer: Removed member with id <%C>"
251 "from <%C> object group\n", id
, id_
.c_str ()));
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 ();
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 ());
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 ();
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 ()
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 ();
333 Random_Object_Group::resolve ()
335 CORBA::Object_var obj
;
337 size_t group_size
= members_
.current_size ();
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.
346 member_id_list_
.get (id
, member
);
348 ACE_DEBUG ((LM_DEBUG
, "Load_Balancer: In <%C> Group resolved to <%C>\n",
352 // Return the object reference corresponding to the found id to the client.
353 members_
.find (*id
, obj
);
357 RR_Object_Group::RR_Object_Group (const char *id
,
358 Object_Group_Factory_i
*my_factory
)
359 : Object_Group_i (id
, my_factory
),
364 RR_Object_Group::~RR_Object_Group ()
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 ();
379 RR_Object_Group::resolve ()
381 CORBA::Object_var obj
;
383 size_t group_size
= members_
.current_size ();
385 throw Load_Balancer::no_such_member ();
387 // Get the id of the member to return to the client.
389 member_id_list_
.get (id
, next_
);
391 ACE_DEBUG ((LM_DEBUG
, "Load_Balancer: In <%C> Group resolved to <%C>\n",
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 ();
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.
420 Object_Group_i::ITERATOR
iter (member_id_list_
);
421 while (member_id
!= *(iter
.next ()))
426 delete (iter
.next ());
429 // Update <next_> if necessary to reflect the deletion.
430 if (position
< 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 ()));