Commit eb3e63e2 authored by Francesco Montorsi's avatar Francesco Montorsi Committed by Luca Boccassi

Hwm tests and docs (#3242)

Add new HWM tests and more detailed documentation
parent 07502111
......@@ -148,6 +148,7 @@ test_security_zap
test_socket_null
test_xpub_verbose
test_mock_pub_sub
test_proxy_hwm
unittest_ip_resolver
unittest_mtrie
unittest_poller
......
......@@ -422,6 +422,7 @@ test_apps = \
tests/test_inproc_connect \
tests/test_issue_566 \
tests/test_proxy \
tests/test_proxy_hwm \
tests/test_proxy_single_socket \
tests/test_proxy_terminate \
tests/test_getsockopt_memset \
......@@ -628,6 +629,10 @@ tests_test_issue_566_LDADD = src/libzmq.la
tests_test_proxy_SOURCES = tests/test_proxy.cpp
tests_test_proxy_LDADD = src/libzmq.la
tests_test_proxy_hwm_SOURCES = tests/test_proxy_hwm.cpp
tests_test_proxy_hwm_LDADD = src/libzmq.la ${UNITY_LIBS}
tests_test_proxy_hwm_CPPFLAGS = ${UNITY_CPPFLAGS}
tests_test_proxy_single_socket_SOURCES = tests/test_proxy_single_socket.cpp
tests_test_proxy_single_socket_LDADD = src/libzmq.la
......
......@@ -640,6 +640,10 @@ blocking or dropping sent messages. Refer to the individual socket descriptions
in linkzmq:zmq_socket[3] for details on the exact action taken for each socket
type.
NOTE: 0MQ does not guarantee that the socket will be able to queue as many as ZMQ_RCVHWM
messages, and the actual limit may be lower or higher, depending on socket transport.
A notable example is for sockets using TCP transport; see linkzmq:zmq_tcp[7].
[horizontal]
Option value type:: int
Option value unit:: messages
......@@ -858,7 +862,9 @@ type.
NOTE: 0MQ does not guarantee that the socket will accept as many as ZMQ_SNDHWM
messages, and the actual limit may be as much as 90% lower depending on the
flow of messages on the socket.
flow of messages on the socket. The socket may even be able to accept more messages
than the ZMQ_SNDHWM threshold; a notable example is for sockets using TCP transport;
see linkzmq:zmq_tcp[7].
[horizontal]
Option value type:: int
......
......@@ -69,6 +69,30 @@ A 'peer address' may be specified by either of the following:
Note: A description of the ZeroMQ Message Transport Protocol (ZMTP) which is
used by the TCP transport can be found at <http://rfc.zeromq.org/spec:15>
HWM
---
For the TCP transport, the high water mark (HWM) mechanism works in conjunction
with the TCP socket buffers handled at OS level.
Depending on the OS and several other factors the size of such TCP buffers will
be different. Moreover TCP buffers provided by the OS will accomodate a varying
number of messages depending on the size of messages (unlike ZMQ HWM settings
the TCP socket buffers are measured in bytes and not messages).
This may result in apparently inexplicable behaviors: e.g., you may expect that
setting ZMQ_SNDHWM to 100 on a socket using TCP transport will have the effect
of blocking the transmission of the 101-th message if the receiver is slow.
This is very unlikely when using TCP transport since OS TCP buffers will typically
provide enough buffering to allow you sending much more than 100 messages.
Of course if the receiver is slow, transmitting on a TCP ZMQ socket will eventually trigger
the "mute state" of the socket; simply don't rely on the exact HWM value.
Obviously the same considerations apply for the receive HWM (see ZMQ_RCVHWM).
EXAMPLES
--------
.Assigning a local address to a socket
......
......@@ -86,6 +86,7 @@ if(NOT WIN32)
test_rebind_ipc
test_reqrep_ipc
test_proxy
test_proxy_hwm
test_proxy_single_socket
test_proxy_terminate
test_getsockopt_memset
......
......@@ -30,6 +30,8 @@
#include "testutil.hpp"
#include "testutil_unity.hpp"
#define SOCKET_STRING_LEN (MAX_SOCKET_STRING * 4)
void setUp ()
{
setup_test_context ();
......@@ -40,17 +42,20 @@ void tearDown ()
teardown_test_context ();
}
// const int MAX_SENDS = 10000;
int test_defaults (int send_hwm_, int msg_cnt_)
int test_defaults (int send_hwm_, int msg_cnt_, const char *endpoint)
{
// Set up bind socket
size_t len = SOCKET_STRING_LEN;
char pub_endpoint[SOCKET_STRING_LEN];
// Set up and bind PUB socket
void *pub_socket = test_context_socket (ZMQ_PUB);
TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (pub_socket, "inproc://a"));
TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (pub_socket, endpoint));
TEST_ASSERT_SUCCESS_ERRNO (
zmq_getsockopt (pub_socket, ZMQ_LAST_ENDPOINT, pub_endpoint, &len));
// Set up connect socket
// Set up and connect SUB socket
void *sub_socket = test_context_socket (ZMQ_SUB);
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sub_socket, "inproc://a"));
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sub_socket, pub_endpoint));
//set a hwm on publisher
TEST_ASSERT_SUCCESS_ERRNO (
......@@ -58,17 +63,22 @@ int test_defaults (int send_hwm_, int msg_cnt_)
TEST_ASSERT_SUCCESS_ERRNO (
zmq_setsockopt (sub_socket, ZMQ_SUBSCRIBE, 0, 0));
// Send until we block
msleep (
SETTLE_TIME); // give some time to background threads to perform PUB-SUB connection
// Send until we reach "mute" state
int send_count = 0;
while (send_count < msg_cnt_
&& zmq_send (pub_socket, NULL, 0, ZMQ_DONTWAIT) == 0)
&& zmq_send (pub_socket, "test message", 13, ZMQ_DONTWAIT) == 13)
++send_count;
TEST_ASSERT_EQUAL_INT (send_hwm_, send_count);
msleep (SETTLE_TIME);
// Now receive all sent messages
int recv_count = 0;
while (0 == zmq_recv (sub_socket, NULL, 0, ZMQ_DONTWAIT)) {
char dummybuff[64];
while (13 == zmq_recv (sub_socket, &dummybuff, 64, ZMQ_DONTWAIT)) {
++recv_count;
}
......@@ -85,23 +95,27 @@ int receive (void *socket_)
{
int recv_count = 0;
// Now receive all sent messages
while (0 == zmq_recv (socket_, NULL, 0, ZMQ_DONTWAIT)) {
while (0 == zmq_recv (socket_, NULL, 0, 0)) {
++recv_count;
}
return recv_count;
}
int test_blocking (int send_hwm_, int msg_cnt_)
int test_blocking (int send_hwm_, int msg_cnt_, const char *endpoint)
{
size_t len = SOCKET_STRING_LEN;
char pub_endpoint[SOCKET_STRING_LEN];
// Set up bind socket
void *pub_socket = test_context_socket (ZMQ_PUB);
TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (pub_socket, "inproc://a"));
TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (pub_socket, endpoint));
TEST_ASSERT_SUCCESS_ERRNO (
zmq_getsockopt (pub_socket, ZMQ_LAST_ENDPOINT, pub_endpoint, &len));
// Set up connect socket
void *sub_socket = test_context_socket (ZMQ_SUB);
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sub_socket, "inproc://a"));
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sub_socket, pub_endpoint));
//set a hwm on publisher
TEST_ASSERT_SUCCESS_ERRNO (
......@@ -109,9 +123,14 @@ int test_blocking (int send_hwm_, int msg_cnt_)
int wait = 1;
TEST_ASSERT_SUCCESS_ERRNO (
zmq_setsockopt (pub_socket, ZMQ_XPUB_NODROP, &wait, sizeof (wait)));
int timeout_ms = 10;
TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (
sub_socket, ZMQ_RCVTIMEO, &timeout_ms, sizeof (timeout_ms)));
TEST_ASSERT_SUCCESS_ERRNO (
zmq_setsockopt (sub_socket, ZMQ_SUBSCRIBE, 0, 0));
msleep (SETTLE_TIME);
// Send until we block
int send_count = 0;
int recv_count = 0;
......@@ -120,13 +139,15 @@ int test_blocking (int send_hwm_, int msg_cnt_)
if (rc == 0) {
++send_count;
} else if (-1 == rc) {
// if the PUB socket blocks due to HWM, errno should be EAGAIN:
TEST_ASSERT_EQUAL_INT (EAGAIN, errno);
recv_count += receive (sub_socket);
TEST_ASSERT_EQUAL_INT (send_count, recv_count);
}
}
msleep (2 * SETTLE_TIME); // required for TCP transport
recv_count += receive (sub_socket);
TEST_ASSERT_EQUAL_INT (send_count, recv_count);
// Clean up
test_context_socket_close (sub_socket);
......@@ -142,7 +163,7 @@ void test_reset_hwm ()
const int first_count = 9999;
const int second_count = 1100;
int hwm = 11024;
char my_endpoint[MAX_SOCKET_STRING];
char my_endpoint[SOCKET_STRING_LEN];
// Set up bind socket
void *pub_socket = test_context_socket (ZMQ_PUB);
......@@ -199,25 +220,51 @@ void test_reset_hwm ()
test_context_socket_close (pub_socket);
}
void test_defaults_1000 ()
void test_tcp ()
{
// send 1000 msg on hwm 1000, receive 1000, on TCP transport
TEST_ASSERT_EQUAL_INT (1000,
test_defaults (1000, 1000, "tcp://127.0.0.1:*"));
// send 100 msg on hwm 100, receive 100
TEST_ASSERT_EQUAL_INT (100, test_defaults (100, 100, "tcp://127.0.0.1:*"));
// send 6000 msg on hwm 2000, drops above hwm, only receive hwm:
TEST_ASSERT_EQUAL_INT (6000,
test_blocking (2000, 6000, "tcp://127.0.0.1:*"));
}
void test_inproc ()
{
// send 1000 msg on hwm 1000, receive 1000
TEST_ASSERT_EQUAL_INT (1000, test_defaults (1000, 1000));
TEST_ASSERT_EQUAL_INT (1000, test_defaults (1000, 1000, "inproc://a"));
TEST_ASSERT_EQUAL_INT (100, test_defaults (100, 100, "inproc://b"));
TEST_ASSERT_EQUAL_INT (6000, test_blocking (2000, 6000, "inproc://c"));
}
void test_blocking_2000 ()
#ifndef ZMQ_HAVE_WINDOWS
void test_ipc ()
{
// send 6000 msg on hwm 2000, drops above hwm, only receive hwm
TEST_ASSERT_EQUAL_INT (6000, test_blocking (2000, 6000));
TEST_ASSERT_EQUAL_INT (1000, test_defaults (1000, 1000, "ipc://*"));
TEST_ASSERT_EQUAL_INT (100, test_defaults (100, 100, "ipc://*"));
TEST_ASSERT_EQUAL_INT (6000, test_blocking (2000, 6000, "ipc://*"));
}
#endif
int main ()
{
setup_test_environment ();
UNITY_BEGIN ();
RUN_TEST (test_defaults_1000);
RUN_TEST (test_blocking_2000);
// repeat the test for both TCP, INPROC and IPC transports:
RUN_TEST (test_tcp);
RUN_TEST (test_inproc);
#ifndef ZMQ_HAVE_WINDOWS
RUN_TEST (test_ipc);
#endif
RUN_TEST (test_reset_hwm);
return UNITY_END ();
}
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment