2 //=============================================================================
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"
38 #pragma warning(disable:4503)
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 */
80 Svc_Handler::Svc_Handler (ACE_Thread_Manager
*t
)
81 : ACE_Svc_Handler
<ACE_SOCK_STREAM
, ACE_NULL_SYNCH
> (t
)
86 Svc_Handler::open (void *)
90 ACE_TEXT ("opening Svc_Handler %@ with handle %d\n"),
92 this->peer ().get_handle ()));
98 Svc_Handler::close (u_long flags
)
100 ACE_DEBUG ((LM_DEBUG
,
101 ACE_TEXT ("Closing Svc_Handler %@ with handle %d\n"),
103 this->peer ().get_handle ()));
104 return ACE_Svc_Handler
<ACE_SOCK_STREAM
, ACE_NULL_SYNCH
>::close (flags
);
107 enum Caching_Strategy_Type
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;
129 static int iterations
= 200;
130 #endif /* ACE_WIN32 */
132 //====================================================================
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.
143 ACE_TEXT ("Purging connections from Connection Cache...\n")));
145 if (-1 == connect_strategy
->purge_connections ())
146 ACE_ERROR ((LM_ERROR
,
148 ACE_TEXT ("purge_connections")));
152 ACE_ERROR ((LM_ERROR
,
154 ACE_TEXT ("in out_of_sockets_handler, ")
155 ACE_TEXT ("but out_of_handles said no")));
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 (),
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
,
173 ACE_ERROR_RETURN ((LM_ERROR
,
175 ACE_TEXT ("connection failed")),
178 // Reset Svc_Handler state.
179 svc_handler
->recycle_state (ACE_RECYCLABLE_PURGABLE_BUT_NOT_IDLE
);
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
,
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.
210 test_connection_management (CACHING_STRATEGY
&caching_strategy
)
212 // Configure the Strategy Connector with a strategy that caches
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,
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")));
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 ();
244 for (int i
= 1; i
<= iterations
; ++i
)
246 ACE_DEBUG ((LM_DEBUG
,
247 ACE_TEXT ("%T iteration %d\n"),
250 // If <listen_once> is false, one Acceptor is used for every
252 ACCEPTOR listen_multiple_times_acceptor
;
254 ACCEPTOR
&acceptor
= listen_once
?
255 listen_one_time_acceptor
:
256 listen_multiple_times_acceptor
;
260 // Bind acceptor to any port and then find out what the port
262 if (acceptor
.open (ACE_sap_any_cast (const ACE_INET_Addr
&)) == -1)
264 out_of_sockets_handler ();
268 if (acceptor
.acceptor ().get_local_addr (server_addr
) == -1)
270 ACE_ERROR ((LM_ERROR
,
272 ACE_TEXT ("get_local_addr")));
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 ();
292 test_caching_strategy_type ()
294 CACHING_STRATEGY
*caching_strategy
= 0;
296 switch (caching_strategy_type
)
299 ACE_DEBUG ((LM_DEBUG
, ACE_TEXT ("\nNull_Caching_Strategy\n\n")));
300 ACE_NEW (caching_strategy
,
301 NULL_CACHING_STRATEGY_ADAPTER
);
305 ACE_DEBUG ((LM_DEBUG
, ACE_TEXT ("\nLRU_Caching_Strategy\n\n")));
306 ACE_NEW (caching_strategy
,
307 LRU_CACHING_STRATEGY_ADAPTER
);
311 ACE_DEBUG ((LM_DEBUG
, ACE_TEXT ("\nLFU_Caching_Strategy\n\n")));
312 ACE_NEW (caching_strategy
,
313 LFU_CACHING_STRATEGY_ADAPTER
);
317 ACE_DEBUG ((LM_DEBUG
, ACE_TEXT ("\nFIFO_Caching_Strategy\n\n")));
318 ACE_NEW (caching_strategy
,
319 FIFO_CACHING_STRATEGY_ADAPTER
);
322 case ACE_ALL
: // Just to remove warnings!
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"));
338 while ((cc
= get_opt ()) != -1)
345 listen_once
= ACE_OS::atoi (get_opt
.opt_arg ());
348 iterations
= ACE_OS::atoi (get_opt
.opt_arg ());
349 user_has_specified_iterations
= 1;
352 purge_percentage
= ACE_OS::atoi (get_opt
.opt_arg ());
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
;
368 keep_handles_available
= ACE_OS::atoi (get_opt
.opt_arg ());
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")));
389 run_main (int argc
, ACE_TCHAR
*argv
[])
392 int result
= parse_args (argc
, argv
);
396 #if defined (ACE_WIN32)
397 // Somehow, on Win32, the <listen once> option allows us to create
399 if (!user_has_specified_iterations
&& listen_once
)
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
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
)
431 caching_strategy_type
= ACE_LFU
;
432 test_caching_strategy_type ();
434 caching_strategy_type
= ACE_FIFO
;
435 test_caching_strategy_type ();
439 test_caching_strategy_type ();
442 ACE_LOG_MSG
->set_flags (ACE_Log_Msg::VERBOSE_LITE
);