Doxygen changes
[ACE_TAO.git] / ACE / tests / Cached_Conn_Test.cpp
blobf197be790afd5c4ecd21d8321a3f797ab8bddfa3
2 //=============================================================================
3 /**
4 * @file Cached_Conn_Test.cpp
6 * The test illustrates how the <ACE_Strategy_Connector> works by
7 * showing how you can cache connections on the client using
8 * different caching strategies. Also how connections can be purged
9 * explicitly and implicitly if needed from the connection cache
10 * maintained by the connector.
12 * @author Kirthika Parameswaran <kirthika@cs.wustl.edu>
14 //=============================================================================
17 #ifndef CACHED_CONNECT_TEST
18 #define CACHED_CONNECT_TEST
20 #include "test_config.h"
22 #include "Cached_Conn_Test.h"
24 #include "ace/OS_NS_string.h"
25 #include "ace/INET_Addr.h"
26 #include "ace/SOCK_Connector.h"
27 #include "ace/SOCK_Acceptor.h"
28 #include "ace/Svc_Handler.h"
29 #include "ace/SOCK_Stream.h"
30 #include "ace/Acceptor.h"
31 #include "ace/Connector.h"
32 #include "ace/Get_Opt.h"
33 #include "ace/Caching_Utility_T.h"
34 #include "ace/Cached_Connect_Strategy_T.h"
35 #include "ace/Handle_Gobbler.h"
37 #if defined(_MSC_VER)
38 #pragma warning(disable:4503)
39 #endif /* _MSC_VER */
43 typedef size_t ATTRIBUTES;
44 typedef std::pair<Svc_Handler *, ATTRIBUTES>
45 CACHED_HANDLER;
46 typedef ACE_Refcounted_Hash_Recyclable<ACE_INET_Addr>
47 ACE_ADDR;
48 typedef ACE_Hash<ACE_ADDR> H_KEY;
49 typedef ACE_Equal_To<ACE_ADDR> C_KEYS;
51 typedef ACE_Hash_Map_Manager_Ex<ACE_ADDR, CACHED_HANDLER, H_KEY, C_KEYS, ACE_Null_Mutex>
52 HASH_MAP;
53 typedef ACE_Hash_Map_Iterator_Ex<ACE_ADDR, CACHED_HANDLER, H_KEY, C_KEYS, ACE_Null_Mutex>
54 HASH_MAP_ITERATOR;
55 typedef ACE_Hash_Map_Reverse_Iterator_Ex<ACE_ADDR, CACHED_HANDLER, H_KEY, C_KEYS, ACE_Null_Mutex>
56 HASH_MAP_REVERSE_ITERATOR;
58 typedef ACE_Recyclable_Handler_Cleanup_Strategy<ACE_ADDR, CACHED_HANDLER, HASH_MAP>
59 CLEANUP_STRATEGY;
60 typedef ACE_Recyclable_Handler_Caching_Utility<ACE_ADDR, CACHED_HANDLER, HASH_MAP, HASH_MAP_ITERATOR, ATTRIBUTES>
61 CACHING_UTILITY;
63 typedef ACE_LRU_Caching_Strategy<ATTRIBUTES, CACHING_UTILITY>
64 LRU_CACHING_STRATEGY;
66 typedef ACE_LFU_Caching_Strategy<ATTRIBUTES, CACHING_UTILITY>
67 LFU_CACHING_STRATEGY;
68 typedef ACE_FIFO_Caching_Strategy<ATTRIBUTES, CACHING_UTILITY>
69 FIFO_CACHING_STRATEGY;
70 typedef ACE_Null_Caching_Strategy<ATTRIBUTES, CACHING_UTILITY>
71 NULL_CACHING_STRATEGY;
72 typedef ACE_Caching_Strategy_Adapter<ATTRIBUTES, CACHING_UTILITY, LRU_CACHING_STRATEGY>
73 LRU_CACHING_STRATEGY_ADAPTER;
74 typedef ACE_Caching_Strategy_Adapter<ATTRIBUTES, CACHING_UTILITY, LFU_CACHING_STRATEGY>
75 LFU_CACHING_STRATEGY_ADAPTER;
76 typedef ACE_Caching_Strategy_Adapter<ATTRIBUTES, CACHING_UTILITY, FIFO_CACHING_STRATEGY>
77 FIFO_CACHING_STRATEGY_ADAPTER;
78 typedef ACE_Caching_Strategy_Adapter<ATTRIBUTES, CACHING_UTILITY, NULL_CACHING_STRATEGY>
79 NULL_CACHING_STRATEGY_ADAPTER;
80 typedef ACE_Caching_Strategy<ATTRIBUTES, CACHING_UTILITY>
81 CACHING_STRATEGY;
83 typedef ACE_Oneshot_Acceptor<Svc_Handler, ACE_SOCK_ACCEPTOR>
84 ACCEPTOR;
86 typedef ACE_Strategy_Connector<Svc_Handler, ACE_SOCK_CONNECTOR>
87 STRATEGY_CONNECTOR;
89 typedef ACE_NOOP_Creation_Strategy<Svc_Handler>
90 NULL_CREATION_STRATEGY;
92 typedef ACE_NOOP_Concurrency_Strategy<Svc_Handler>
93 NULL_ACTIVATION_STRATEGY;
95 typedef ACE_Cached_Connect_Strategy_Ex<Svc_Handler, ACE_SOCK_CONNECTOR, CACHING_STRATEGY, ATTRIBUTES, ACE_SYNCH_NULL_MUTEX>
96 CACHED_CONNECT_STRATEGY;
98 #endif /* CACHED_CONNECT_TEST */
100 static int debug = 0;
102 Svc_Handler::Svc_Handler (ACE_Thread_Manager *t)
103 : ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH> (t)
108 Svc_Handler::open (void *)
110 if (debug)
111 ACE_DEBUG ((LM_DEBUG,
112 ACE_TEXT ("opening Svc_Handler %@ with handle %d\n"),
113 this,
114 this->peer ().get_handle ()));
116 return 0;
120 Svc_Handler::close (u_long flags)
122 ACE_DEBUG ((LM_DEBUG,
123 ACE_TEXT ("Closing Svc_Handler %@ with handle %d\n"),
124 this,
125 this->peer ().get_handle ()));
126 return ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH>::close (flags);
129 enum Caching_Strategy_Type
131 ACE_LFU,
132 ACE_FIFO,
133 ACE_LRU,
134 ACE_NULL,
135 ACE_ALL
138 // Default number of clients/servers.
139 static int listen_once = 1;
140 static int user_has_specified_iterations = 0;
141 static size_t keep_handles_available = 100;
142 static double purge_percentage = 20;
143 static Caching_Strategy_Type caching_strategy_type = ACE_ALL;
144 static CACHED_CONNECT_STRATEGY *connect_strategy = 0;
146 // On Win32, the handle gobbling doesn't work. Therefore, we need
147 // more iterations to get to the handle limit.
148 #if defined (ACE_WIN32)
149 static int iterations = 2000;
150 #else
151 static int iterations = 200;
152 #endif /* ACE_WIN32 */
154 //====================================================================
156 static void
157 out_of_sockets_handler (void)
159 if (ACE::out_of_handles (errno))
161 // Close connections which are cached by explicitly purging the
162 // connection cache maintained by the connector.
163 ACE_DEBUG
164 ((LM_DEBUG,
165 ACE_TEXT ("Purging connections from Connection Cache...\n")));
167 if (-1 == connect_strategy->purge_connections ())
168 ACE_ERROR ((LM_ERROR,
169 ACE_TEXT ("%p\n"),
170 ACE_TEXT ("purge_connections")));
172 else
174 ACE_ERROR ((LM_ERROR,
175 ACE_TEXT ("%p\n"),
176 ACE_TEXT ("in out_of_sockets_handler, ")
177 ACE_TEXT ("but out_of_handles said no")));
181 static int
182 cached_connect (STRATEGY_CONNECTOR &con,
183 const ACE_INET_Addr &server_addr)
185 // This will make sure we get the host information correct.
186 ACE_INET_Addr remote_addr (server_addr.get_port_number (),
187 ACE_LOCALHOST);
189 // Perform a blocking connect to the server using the Strategy
190 // Connector with a connection caching strategy.
191 Svc_Handler *svc_handler = 0;
192 int result = con.connect (svc_handler,
193 remote_addr);
194 if (result == -1)
195 ACE_ERROR_RETURN ((LM_ERROR,
196 ACE_TEXT ("%p\n"),
197 ACE_TEXT ("connection failed")),
198 -1);
200 // Reset Svc_Handler state.
201 svc_handler->recycle_state (ACE_RECYCLABLE_PURGABLE_BUT_NOT_IDLE);
203 return 0;
206 static int
207 server (ACCEPTOR *acceptor)
209 ACE_INET_Addr cli_addr;
211 // Create a new <Svc_Handler> to consume the data.
212 Svc_Handler svc_handler;
214 int result = acceptor->accept (&svc_handler,
215 &cli_addr);
216 if (result == -1)
217 return -1;
219 if (debug)
220 ACE_DEBUG ((LM_DEBUG,
221 ACE_TEXT ("client %s connected from %d\n"),
222 cli_addr.get_host_name (),
223 cli_addr.get_port_number ()));
226 // Svc_Handler dies here, closing the server side socket.
228 return 0;
231 static void
232 test_connection_management (CACHING_STRATEGY &caching_strategy)
234 // Configure the Strategy Connector with a strategy that caches
235 // connection.
236 CACHED_CONNECT_STRATEGY caching_connect_strategy (caching_strategy);
238 // This is required by the <out_of_sockets_handler>.
239 connect_strategy = &caching_connect_strategy;
241 NULL_CREATION_STRATEGY creation_strategy;
242 NULL_ACTIVATION_STRATEGY activation_strategy;
244 STRATEGY_CONNECTOR strategy_connector (0,
245 &creation_strategy,
246 &caching_connect_strategy,
247 &activation_strategy);
249 // If <listen_once> is true, only one Acceptor is used for the test.
250 ACCEPTOR listen_one_time_acceptor;
251 ACE_INET_Addr server_addr;
253 if (0 != listen_one_time_acceptor.open (ACE_sap_any_cast (const ACE_INET_Addr &)))
255 ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("acceptor open")));
256 return;
259 if (0 != listen_one_time_acceptor.acceptor ().get_local_addr (server_addr))
261 ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("acceptor getaddr")));
262 listen_one_time_acceptor.close ();
263 return;
266 for (int i = 1; i <= iterations; ++i)
268 ACE_DEBUG ((LM_DEBUG,
269 ACE_TEXT ("%T iteration %d\n"),
270 i));
272 // If <listen_once> is false, one Acceptor is used for every
273 // iteration.
274 ACCEPTOR listen_multiple_times_acceptor;
276 ACCEPTOR &acceptor = listen_once ?
277 listen_one_time_acceptor :
278 listen_multiple_times_acceptor;
280 if (!listen_once)
282 // Bind acceptor to any port and then find out what the port
283 // was.
284 if (acceptor.open (ACE_sap_any_cast (const ACE_INET_Addr &)) == -1)
286 out_of_sockets_handler ();
287 continue;
290 if (acceptor.acceptor ().get_local_addr (server_addr) == -1)
292 ACE_ERROR ((LM_ERROR,
293 ACE_TEXT ("%p\n"),
294 ACE_TEXT ("get_local_addr")));
295 break;
298 if (debug)
299 ACE_DEBUG ((LM_DEBUG,
300 ACE_TEXT ("starting server at port %d\n"),
301 server_addr.get_port_number ()));
304 // Run the cached blocking test.
305 if (-1 == cached_connect (strategy_connector, server_addr))
306 ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("cached_connect")));
308 if (-1 == server (&acceptor))
309 out_of_sockets_handler ();
313 void
314 test_caching_strategy_type (void)
316 CACHING_STRATEGY *caching_strategy = 0;
318 switch (caching_strategy_type)
320 case ACE_NULL:
321 ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\nNull_Caching_Strategy\n\n")));
322 ACE_NEW (caching_strategy,
323 NULL_CACHING_STRATEGY_ADAPTER);
324 break;
326 case ACE_LRU:
327 ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\nLRU_Caching_Strategy\n\n")));
328 ACE_NEW (caching_strategy,
329 LRU_CACHING_STRATEGY_ADAPTER);
330 break;
332 case ACE_LFU:
333 ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\nLFU_Caching_Strategy\n\n")));
334 ACE_NEW (caching_strategy,
335 LFU_CACHING_STRATEGY_ADAPTER);
336 break;
338 case ACE_FIFO:
339 ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\nFIFO_Caching_Strategy\n\n")));
340 ACE_NEW (caching_strategy,
341 FIFO_CACHING_STRATEGY_ADAPTER);
342 break;
344 case ACE_ALL: // Just to remove warnings!
345 break;
348 caching_strategy->purge_percent (purge_percentage);
349 test_connection_management (*caching_strategy);
350 delete caching_strategy;
354 parse_args (int argc, ACE_TCHAR *argv[])
356 ACE_Get_Opt get_opt (argc, argv, ACE_TEXT ("l:i:p:c:a:d"));
358 int cc;
360 while ((cc = get_opt ()) != -1)
361 switch (cc)
363 case 'd':
364 debug = 1;
365 break;
366 case 'l':
367 listen_once = ACE_OS::atoi (get_opt.opt_arg ());
368 break;
369 case 'i':
370 iterations = ACE_OS::atoi (get_opt.opt_arg ());
371 user_has_specified_iterations = 1;
372 break;
373 case 'p':
374 purge_percentage = ACE_OS::atoi (get_opt.opt_arg ());
375 break;
376 case 'c':
377 // Note that if null caching strategy is used then this test
378 // will fail if the number of servers exceed number of open
379 // files allowed for the process.
380 if (ACE_OS::strcmp (get_opt.opt_arg (), ACE_TEXT ("null")) == 0)
381 caching_strategy_type = ACE_NULL;
382 if (ACE_OS::strcmp (get_opt.opt_arg (), ACE_TEXT ("lru")) == 0)
383 caching_strategy_type = ACE_LRU;
384 if (ACE_OS::strcmp (get_opt.opt_arg (), ACE_TEXT ("lfu")) == 0)
385 caching_strategy_type = ACE_LFU;
386 if (ACE_OS::strcmp (get_opt.opt_arg (), ACE_TEXT ("fifo")) == 0)
387 caching_strategy_type = ACE_FIFO;
388 break;
389 case 'a':
390 keep_handles_available = ACE_OS::atoi (get_opt.opt_arg ());
391 break;
392 case '?':
393 case 'h':
394 default:
395 ACE_ERROR ((LM_ERROR,
396 ACE_TEXT ("usage: %s ")
397 ACE_TEXT ("[-c (caching strategy: lru / lfu / fifo / null [default = all])] ")
398 ACE_TEXT ("[-i (iterations)] ")
399 ACE_TEXT ("[-l (listen once)] ")
400 ACE_TEXT ("[-d (addition debugging output)] ")
401 ACE_TEXT ("[-p (purge percent)] ")
402 ACE_TEXT ("[-a (keep handles available)] "),
403 ACE_TEXT ("Cached_Conn_Test")));
404 return -1;
407 return 0;
411 run_main (int argc, ACE_TCHAR *argv[])
413 // Validate options.
414 int result = parse_args (argc, argv);
415 if (result != 0)
416 return result;
418 #if defined (ACE_WIN32)
419 // Somehow, on Win32, the <listen once> option allows us to create
420 // more handles.
421 if (!user_has_specified_iterations && listen_once)
422 iterations *= 2;
423 #endif /* ACE_WIN32 */
425 // Start the test only if options are valid.
426 ACE_START_TEST (ACE_TEXT ("Cached_Conn_Test"));
428 // Remove the extra debugging attributes from Log_Msg output.
429 ACE_LOG_MSG->clr_flags (ACE_Log_Msg::VERBOSE_LITE);
431 // The reactor's constructor changes the handle limit for the
432 // process.
433 ACE_Reactor::instance ();
435 // Consume all handles in the process, leaving us
436 // <keep_handles_available> to play with.
437 ACE_Handle_Gobbler handle_gobbler;
438 if (0 != handle_gobbler.consume_handles (keep_handles_available))
439 ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("handle_gobbler")));
441 // Do we need to test all the strategies. Note, that the less
442 // useful null strategy is ignored in this case.
443 if (caching_strategy_type == ACE_ALL)
445 caching_strategy_type = ACE_LRU;
446 test_caching_strategy_type ();
448 // Default iterations are too many; if the user hasn't specified
449 // otherwise, we'll shrink the iterations for LFU and FIFO.
450 if (!user_has_specified_iterations)
451 iterations /= 100;
453 caching_strategy_type = ACE_LFU;
454 test_caching_strategy_type ();
456 caching_strategy_type = ACE_FIFO;
457 test_caching_strategy_type ();
459 else
461 test_caching_strategy_type ();
464 ACE_LOG_MSG->set_flags (ACE_Log_Msg::VERBOSE_LITE);
466 ACE_END_TEST;
467 return 0;