Merge pull request #2301 from sonndinh/remove-dup-reactor-functions
[ACE_TAO.git] / ACE / tests / Cached_Conn_Test.cpp
blob1b98d391959d586d3e8387921e179f6615cb01a7
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 */
42 using ATTRIBUTES = size_t;
43 using CACHED_HANDLER = std::pair<Svc_Handler *, ATTRIBUTES>;
44 using ACE_ADDR = ARHR<ACE_INET_Addr>;
45 using H_KEY = ACE_Hash<ACE_ADDR>;
46 using C_KEYS = ACE_Equal_To<ACE_ADDR>;
48 using HASH_MAP = ACE_Hash_Map_Manager_Ex<ACE_ADDR, CACHED_HANDLER, H_KEY, C_KEYS, ACE_Null_Mutex>;
49 using HASH_MAP_ITERATOR = ACE_Hash_Map_Iterator_Ex<ACE_ADDR, CACHED_HANDLER, H_KEY, C_KEYS, ACE_Null_Mutex>;
50 using HASH_MAP_REVERSE_ITERATOR = ACE_Hash_Map_Reverse_Iterator_Ex<ACE_ADDR, CACHED_HANDLER, H_KEY, C_KEYS, ACE_Null_Mutex>;
52 using CLEANUP_STRATEGY = ARHCLE<ACE_ADDR, CACHED_HANDLER, HASH_MAP>;
53 using CACHING_UTILITY = ACE_Recyclable_Handler_Caching_Utility<ACE_ADDR, CACHED_HANDLER, HASH_MAP, HASH_MAP_ITERATOR, ATTRIBUTES>;
55 using LRU_CACHING_STRATEGY = ALRU<ATTRIBUTES, CACHING_UTILITY>;
57 using LFU_CACHING_STRATEGY = ALFU<ATTRIBUTES, CACHING_UTILITY>;
58 using FIFO_CACHING_STRATEGY = AFIFO<ATTRIBUTES, CACHING_UTILITY>;
59 using NULL_CACHING_STRATEGY = ANULL<ATTRIBUTES, CACHING_UTILITY>;
60 using LRU_CACHING_STRATEGY_ADAPTER = ACSA<ATTRIBUTES, CACHING_UTILITY, LRU_CACHING_STRATEGY>;
61 using LFU_CACHING_STRATEGY_ADAPTER = ACSA<ATTRIBUTES, CACHING_UTILITY, LFU_CACHING_STRATEGY>;
62 using FIFO_CACHING_STRATEGY_ADAPTER = ACSA<ATTRIBUTES, CACHING_UTILITY, FIFO_CACHING_STRATEGY>;
63 using NULL_CACHING_STRATEGY_ADAPTER = ACSA<ATTRIBUTES, CACHING_UTILITY, NULL_CACHING_STRATEGY>;
64 using CACHING_STRATEGY = ACS<ATTRIBUTES, CACHING_UTILITY>;
66 using ACCEPTOR = ACE_Oneshot_Acceptor<Svc_Handler, ACE_SOCK_Acceptor>;
68 using STRATEGY_CONNECTOR = ACE_Strategy_Connector<Svc_Handler, ACE_SOCK_Connector>;
70 using NULL_CREATION_STRATEGY = ACE_NOOP_Creation_Strategy<Svc_Handler>;
72 using NULL_ACTIVATION_STRATEGY = ACE_NOOP_Concurrency_Strategy<Svc_Handler>;
74 using CACHED_CONNECT_STRATEGY = ACCSE<Svc_Handler, ACE_SOCK_Connector, CACHING_STRATEGY, ATTRIBUTES, ACE_MT_SYNCH::NULL_MUTEX>;
76 #endif /* CACHED_CONNECT_TEST */
78 static int debug = 0;
80 Svc_Handler::Svc_Handler (ACE_Thread_Manager *t)
81 : ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH> (t)
85 int
86 Svc_Handler::open (void *)
88 if (debug)
89 ACE_DEBUG ((LM_DEBUG,
90 ACE_TEXT ("opening Svc_Handler %@ with handle %d\n"),
91 this,
92 this->peer ().get_handle ()));
94 return 0;
97 int
98 Svc_Handler::close (u_long flags)
100 ACE_DEBUG ((LM_DEBUG,
101 ACE_TEXT ("Closing Svc_Handler %@ with handle %d\n"),
102 this,
103 this->peer ().get_handle ()));
104 return ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH>::close (flags);
107 enum Caching_Strategy_Type
109 ACE_LFU,
110 ACE_FIFO,
111 ACE_LRU,
112 ACE_NULL,
113 ACE_ALL
116 // Default number of clients/servers.
117 static int listen_once = 1;
118 static int user_has_specified_iterations = 0;
119 static size_t keep_handles_available = 100;
120 static double purge_percentage = 20;
121 static Caching_Strategy_Type caching_strategy_type = ACE_ALL;
122 static CACHED_CONNECT_STRATEGY *connect_strategy = 0;
124 // On Win32, the handle gobbling doesn't work. Therefore, we need
125 // more iterations to get to the handle limit.
126 #if defined (ACE_WIN32)
127 static int iterations = 2000;
128 #else
129 static int iterations = 200;
130 #endif /* ACE_WIN32 */
132 //====================================================================
134 static void
135 out_of_sockets_handler ()
137 if (ACE::out_of_handles (errno))
139 // Close connections which are cached by explicitly purging the
140 // connection cache maintained by the connector.
141 ACE_DEBUG
142 ((LM_DEBUG,
143 ACE_TEXT ("Purging connections from Connection Cache...\n")));
145 if (-1 == connect_strategy->purge_connections ())
146 ACE_ERROR ((LM_ERROR,
147 ACE_TEXT ("%p\n"),
148 ACE_TEXT ("purge_connections")));
150 else
152 ACE_ERROR ((LM_ERROR,
153 ACE_TEXT ("%p\n"),
154 ACE_TEXT ("in out_of_sockets_handler, ")
155 ACE_TEXT ("but out_of_handles said no")));
159 static int
160 cached_connect (STRATEGY_CONNECTOR &con,
161 const ACE_INET_Addr &server_addr)
163 // This will make sure we get the host information correct.
164 ACE_INET_Addr remote_addr (server_addr.get_port_number (),
165 ACE_LOCALHOST);
167 // Perform a blocking connect to the server using the Strategy
168 // Connector with a connection caching strategy.
169 Svc_Handler *svc_handler = 0;
170 int result = con.connect (svc_handler,
171 remote_addr);
172 if (result == -1)
173 ACE_ERROR_RETURN ((LM_ERROR,
174 ACE_TEXT ("%p\n"),
175 ACE_TEXT ("connection failed")),
176 -1);
178 // Reset Svc_Handler state.
179 svc_handler->recycle_state (ACE_RECYCLABLE_PURGABLE_BUT_NOT_IDLE);
181 return 0;
184 static int
185 server (ACCEPTOR *acceptor)
187 ACE_INET_Addr cli_addr;
189 // Create a new <Svc_Handler> to consume the data.
190 Svc_Handler svc_handler;
192 int result = acceptor->accept (&svc_handler,
193 &cli_addr);
194 if (result == -1)
195 return -1;
197 if (debug)
198 ACE_DEBUG ((LM_DEBUG,
199 ACE_TEXT ("client %s connected from %d\n"),
200 cli_addr.get_host_name (),
201 cli_addr.get_port_number ()));
204 // Svc_Handler dies here, closing the server side socket.
206 return 0;
209 static void
210 test_connection_management (CACHING_STRATEGY &caching_strategy)
212 // Configure the Strategy Connector with a strategy that caches
213 // connection.
214 CACHED_CONNECT_STRATEGY caching_connect_strategy (caching_strategy);
216 // This is required by the <out_of_sockets_handler>.
217 connect_strategy = &caching_connect_strategy;
219 NULL_CREATION_STRATEGY creation_strategy;
220 NULL_ACTIVATION_STRATEGY activation_strategy;
222 STRATEGY_CONNECTOR strategy_connector (0,
223 &creation_strategy,
224 &caching_connect_strategy,
225 &activation_strategy);
227 // If <listen_once> is true, only one Acceptor is used for the test.
228 ACCEPTOR listen_one_time_acceptor;
229 ACE_INET_Addr server_addr;
231 if (0 != listen_one_time_acceptor.open (ACE_sap_any_cast (const ACE_INET_Addr &)))
233 ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("acceptor open")));
234 return;
237 if (0 != listen_one_time_acceptor.acceptor ().get_local_addr (server_addr))
239 ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("acceptor getaddr")));
240 listen_one_time_acceptor.close ();
241 return;
244 for (int i = 1; i <= iterations; ++i)
246 ACE_DEBUG ((LM_DEBUG,
247 ACE_TEXT ("%T iteration %d\n"),
248 i));
250 // If <listen_once> is false, one Acceptor is used for every
251 // iteration.
252 ACCEPTOR listen_multiple_times_acceptor;
254 ACCEPTOR &acceptor = listen_once ?
255 listen_one_time_acceptor :
256 listen_multiple_times_acceptor;
258 if (!listen_once)
260 // Bind acceptor to any port and then find out what the port
261 // was.
262 if (acceptor.open (ACE_sap_any_cast (const ACE_INET_Addr &)) == -1)
264 out_of_sockets_handler ();
265 continue;
268 if (acceptor.acceptor ().get_local_addr (server_addr) == -1)
270 ACE_ERROR ((LM_ERROR,
271 ACE_TEXT ("%p\n"),
272 ACE_TEXT ("get_local_addr")));
273 break;
276 if (debug)
277 ACE_DEBUG ((LM_DEBUG,
278 ACE_TEXT ("starting server at port %d\n"),
279 server_addr.get_port_number ()));
282 // Run the cached blocking test.
283 if (-1 == cached_connect (strategy_connector, server_addr))
284 ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("cached_connect")));
286 if (-1 == server (&acceptor))
287 out_of_sockets_handler ();
291 void
292 test_caching_strategy_type ()
294 CACHING_STRATEGY *caching_strategy = 0;
296 switch (caching_strategy_type)
298 case ACE_NULL:
299 ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\nNull_Caching_Strategy\n\n")));
300 ACE_NEW (caching_strategy,
301 NULL_CACHING_STRATEGY_ADAPTER);
302 break;
304 case ACE_LRU:
305 ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\nLRU_Caching_Strategy\n\n")));
306 ACE_NEW (caching_strategy,
307 LRU_CACHING_STRATEGY_ADAPTER);
308 break;
310 case ACE_LFU:
311 ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\nLFU_Caching_Strategy\n\n")));
312 ACE_NEW (caching_strategy,
313 LFU_CACHING_STRATEGY_ADAPTER);
314 break;
316 case ACE_FIFO:
317 ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\nFIFO_Caching_Strategy\n\n")));
318 ACE_NEW (caching_strategy,
319 FIFO_CACHING_STRATEGY_ADAPTER);
320 break;
322 case ACE_ALL: // Just to remove warnings!
323 break;
326 caching_strategy->purge_percent (purge_percentage);
327 test_connection_management (*caching_strategy);
328 delete caching_strategy;
332 parse_args (int argc, ACE_TCHAR *argv[])
334 ACE_Get_Opt get_opt (argc, argv, ACE_TEXT ("l:i:p:c:a:d"));
336 int cc;
338 while ((cc = get_opt ()) != -1)
339 switch (cc)
341 case 'd':
342 debug = 1;
343 break;
344 case 'l':
345 listen_once = ACE_OS::atoi (get_opt.opt_arg ());
346 break;
347 case 'i':
348 iterations = ACE_OS::atoi (get_opt.opt_arg ());
349 user_has_specified_iterations = 1;
350 break;
351 case 'p':
352 purge_percentage = ACE_OS::atoi (get_opt.opt_arg ());
353 break;
354 case 'c':
355 // Note that if null caching strategy is used then this test
356 // will fail if the number of servers exceed number of open
357 // files allowed for the process.
358 if (ACE_OS::strcmp (get_opt.opt_arg (), ACE_TEXT ("null")) == 0)
359 caching_strategy_type = ACE_NULL;
360 if (ACE_OS::strcmp (get_opt.opt_arg (), ACE_TEXT ("lru")) == 0)
361 caching_strategy_type = ACE_LRU;
362 if (ACE_OS::strcmp (get_opt.opt_arg (), ACE_TEXT ("lfu")) == 0)
363 caching_strategy_type = ACE_LFU;
364 if (ACE_OS::strcmp (get_opt.opt_arg (), ACE_TEXT ("fifo")) == 0)
365 caching_strategy_type = ACE_FIFO;
366 break;
367 case 'a':
368 keep_handles_available = ACE_OS::atoi (get_opt.opt_arg ());
369 break;
370 case '?':
371 case 'h':
372 default:
373 ACE_ERROR ((LM_ERROR,
374 ACE_TEXT ("usage: %s ")
375 ACE_TEXT ("[-c (caching strategy: lru / lfu / fifo / null [default = all])] ")
376 ACE_TEXT ("[-i (iterations)] ")
377 ACE_TEXT ("[-l (listen once)] ")
378 ACE_TEXT ("[-d (addition debugging output)] ")
379 ACE_TEXT ("[-p (purge percent)] ")
380 ACE_TEXT ("[-a (keep handles available)] "),
381 ACE_TEXT ("Cached_Conn_Test")));
382 return -1;
385 return 0;
389 run_main (int argc, ACE_TCHAR *argv[])
391 // Validate options.
392 int result = parse_args (argc, argv);
393 if (result != 0)
394 return result;
396 #if defined (ACE_WIN32)
397 // Somehow, on Win32, the <listen once> option allows us to create
398 // more handles.
399 if (!user_has_specified_iterations && listen_once)
400 iterations *= 2;
401 #endif /* ACE_WIN32 */
403 // Start the test only if options are valid.
404 ACE_START_TEST (ACE_TEXT ("Cached_Conn_Test"));
406 // Remove the extra debugging attributes from Log_Msg output.
407 ACE_LOG_MSG->clr_flags (ACE_Log_Msg::VERBOSE_LITE);
409 // The reactor's constructor changes the handle limit for the
410 // process.
411 ACE_Reactor::instance ();
413 // Consume all handles in the process, leaving us
414 // <keep_handles_available> to play with.
415 ACE_Handle_Gobbler handle_gobbler;
416 if (0 != handle_gobbler.consume_handles (keep_handles_available))
417 ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("handle_gobbler")));
419 // Do we need to test all the strategies. Note, that the less
420 // useful null strategy is ignored in this case.
421 if (caching_strategy_type == ACE_ALL)
423 caching_strategy_type = ACE_LRU;
424 test_caching_strategy_type ();
426 // Default iterations are too many; if the user hasn't specified
427 // otherwise, we'll shrink the iterations for LFU and FIFO.
428 if (!user_has_specified_iterations)
429 iterations /= 100;
431 caching_strategy_type = ACE_LFU;
432 test_caching_strategy_type ();
434 caching_strategy_type = ACE_FIFO;
435 test_caching_strategy_type ();
437 else
439 test_caching_strategy_type ();
442 ACE_LOG_MSG->set_flags (ACE_Log_Msg::VERBOSE_LITE);
444 ACE_END_TEST;
445 return 0;