@@ -13,13 +13,13 @@ using namespace std;
1313namespace swss {
1414
1515ZmqServer::ZmqServer (const std::string& endpoint)
16- : ZmqServer(endpoint, " " )
16+ : ZmqServer(endpoint, " " , false )
1717{
1818}
1919
20- ZmqServer::ZmqServer (const std::string& endpoint, const std::string& vrf)
20+ ZmqServer::ZmqServer (const std::string& endpoint, const std::string& vrf, bool oneToOneSync )
2121 : m_endpoint(endpoint),
22- m_vrf (vrf)
22+ m_vrf (vrf), m_oneToOneSync(oneToOneSync), m_allowZmqPoll( true )
2323{
2424 connect ();
2525 m_buffer.resize (MQ_RESPONSE_MAX_COUNT);
@@ -31,6 +31,7 @@ ZmqServer::ZmqServer(const std::string& endpoint, const std::string& vrf)
3131
3232ZmqServer::~ZmqServer ()
3333{
34+ m_allowZmqPoll = true ;
3435 m_runThread = false ;
3536 m_mqPollThread->join ();
3637
@@ -42,11 +43,22 @@ void ZmqServer::connect()
4243{
4344 SWSS_LOG_ENTER ();
4445 m_context = zmq_ctx_new ();
45- m_socket = zmq_socket (m_context, ZMQ_PULL);
4646
47- // Increase recv buffer for use all bandwidth: http://api.zeromq.org/4-2:zmq-setsockopt
48- int high_watermark = MQ_WATERMARK;
49- zmq_setsockopt (m_socket, ZMQ_RCVHWM, &high_watermark, sizeof (high_watermark));
47+ if (m_oneToOneSync)
48+ {
49+ m_socket = zmq_socket (m_context, ZMQ_REP);
50+ }
51+ else
52+ {
53+ m_socket = zmq_socket (m_context, ZMQ_PULL);
54+ }
55+
56+ if (!m_oneToOneSync)
57+ {
58+ // Increase recv buffer for use all bandwidth: http://api.zeromq.org/4-2:zmq-setsockopt
59+ int high_watermark = MQ_WATERMARK;
60+ zmq_setsockopt (m_socket, ZMQ_RCVHWM, &high_watermark, sizeof (high_watermark));
61+ }
5062
5163 if (!m_vrf.empty ())
5264 {
@@ -129,6 +141,8 @@ void ZmqServer::mqPollThread()
129141 SWSS_LOG_NOTICE (" bind to zmq endpoint: %s" , m_endpoint.c_str ());
130142 while (m_runThread)
131143 {
144+ m_allowZmqPoll = false ;
145+
132146 // receive message
133147 auto rc = zmq_poll (&poll_item, 1 , 1000 );
134148 if (rc == 0 || !(poll_item.revents & ZMQ_POLLIN))
@@ -139,7 +153,14 @@ void ZmqServer::mqPollThread()
139153 }
140154
141155 // receive message
142- rc = zmq_recv (m_socket, m_buffer.data (), MQ_RESPONSE_MAX_COUNT, ZMQ_DONTWAIT);
156+ if (m_oneToOneSync)
157+ {
158+ rc = zmq_recv (m_socket, m_buffer.data (), MQ_RESPONSE_MAX_COUNT, 0 );
159+ }
160+ else
161+ {
162+ rc = zmq_recv (m_socket, m_buffer.data (), MQ_RESPONSE_MAX_COUNT, ZMQ_DONTWAIT);
163+ }
143164 if (rc < 0 )
144165 {
145166 int zmq_err = zmq_errno ();
@@ -166,6 +187,10 @@ void ZmqServer::mqPollThread()
166187
167188 // deserialize and write to redis:
168189 handleReceivedData (m_buffer.data (), rc);
190+ while (m_oneToOneSync && !m_allowZmqPoll)
191+ {
192+ usleep (10 );
193+ }
169194 }
170195 SWSS_LOG_NOTICE (" mqPollThread end" );
171196}
@@ -175,6 +200,75 @@ void ZmqServer::mqPollThread()
175200void ZmqServer::sendMsg (
176201 const std::string &dbName, const std::string &tableName,
177202 const std::vector<swss::KeyOpFieldsValuesTuple> &values) {
178- return ;
203+ if (!m_oneToOneSync)
204+ {
205+ return ;
206+ }
207+
208+ int serializedlen = (int )BinarySerializer::serializeBuffer (
209+ m_buffer.data (),
210+ m_buffer.size (),
211+ dbName,
212+ tableName,
213+ values);
214+
215+ SWSS_LOG_DEBUG (" sending: %d" , serializedlen);
216+ int zmq_err = 0 ;
217+ int retry_delay = 10 ;
218+ int rc = 0 ;
219+ for (int i = 0 ; i <= MQ_MAX_RETRY; ++i)
220+ {
221+ rc = zmq_send (m_socket, m_buffer.data (), serializedlen, 0 );
222+
223+ if (rc >= 0 )
224+ {
225+ m_allowZmqPoll = true ;
226+ SWSS_LOG_DEBUG (" zmq sent %d bytes" , serializedlen);
227+ return ;
228+ }
229+
230+ zmq_err = zmq_errno ();
231+ // sleep (2 ^ retry time) * 10 ms
232+ retry_delay *= 2 ;
233+ if (zmq_err == EINTR
234+ || zmq_err== EFSM)
235+ {
236+ // EINTR: interrupted by signal
237+ // EFSM: socket state not ready
238+ // For example when ZMQ socket still not receive reply message from last sended package.
239+ // There was state machine inside ZMQ socket, when the socket is not in ready to send state, this
240+ // error will happen.
241+ // for more detail, please check: http://api.zeromq.org/2-1:zmq-send
242+ SWSS_LOG_DEBUG (" zmq send retry, endpoint: %s, error: %d" , m_endpoint.c_str (), zmq_err);
243+
244+ retry_delay = 0 ;
245+ }
246+ else if (zmq_err == EAGAIN)
247+ {
248+ // EAGAIN: ZMQ is full to need try again
249+ SWSS_LOG_WARN (" zmq is full, will retry in %d ms, endpoint: %s, error: %d" , retry_delay, m_endpoint.c_str (), zmq_err);
250+ }
251+ else if (zmq_err == ETERM)
252+ {
253+ auto message = " zmq connection break, endpoint: " + m_endpoint + " , error: " + to_string (rc);
254+ SWSS_LOG_ERROR (" %s" , message.c_str ());
255+ throw system_error (make_error_code (errc::connection_reset), message);
256+ }
257+ else
258+ {
259+ // for other error, send failed immediately.
260+ auto message = " zmq send failed, endpoint: " + m_endpoint + " , error: " + to_string (rc);
261+ SWSS_LOG_ERROR (" %s" , message.c_str ());
262+ throw system_error (make_error_code (errc::io_error), message);
263+ }
264+
265+ usleep (retry_delay * 1000 );
266+ }
267+
268+ // failed after retry
269+ auto message = " zmq send failed, endpoint: " + m_endpoint + " , zmqerrno: " + to_string (zmq_err) + " :" + zmq_strerror (zmq_err) + " , msg length:" + to_string (serializedlen);
270+ SWSS_LOG_ERROR (" %s" , message.c_str ());
271+ throw system_error (make_error_code (errc::io_error), message);
179272}
273+
180274}
0 commit comments