Skip to content

Commit da71bdb

Browse files
authored
Move ntf_queue to proper NotificationQueue class (sonic-net#539)
* Move ntf_queue to proper NotificationQueue class * add extra aspell exception * Address comments
1 parent 2081aca commit da71bdb

File tree

6 files changed

+148
-89
lines changed

6 files changed

+148
-89
lines changed

syncd/Makefile.am

+4-2
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ syncd_SOURCES = \
2222
syncd_notifications.cpp \
2323
syncd_applyview.cpp \
2424
syncd_flex_counter.cpp \
25-
TimerWatchdog.cpp
25+
TimerWatchdog.cpp \
26+
NotificationQueue.cpp
2627

2728
syncd_CPPFLAGS = $(DBGFLAGS) $(AM_CPPFLAGS) $(CFLAGS_COMMON) $(SAIFLAGS)
2829
syncd_LDADD = -lhiredis -lswsscommon $(SAILIB) -lpthread -L$(top_srcdir)/meta/.libs -lsaimetadata -lsaimeta -ldl
@@ -48,7 +49,8 @@ tests_SOURCES = \
4849
syncd_notifications.cpp \
4950
syncd_applyview.cpp \
5051
syncd_flex_counter.cpp \
51-
TimerWatchdog.cpp
52+
TimerWatchdog.cpp \
53+
NotificationQueue.cpp
5254

5355
tests_CPPFLAGS = $(DBGFLAGS) $(AM_CPPFLAGS) $(CFLAGS_COMMON)
5456
tests_LDADD = -lhiredis -lswsscommon -lpthread -L$(top_srcdir)/lib/src/.libs -lsairedis -L$(top_srcdir)/meta/.libs -lsaimetadata -lsaimeta

syncd/NotificationQueue.cpp

+83
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
#include "NotificationQueue.h"
2+
3+
#define NOTIFICATION_QUEUE_DROP_COUNT_INDICATOR (1000)
4+
5+
NotificationQueue::NotificationQueue(
6+
_In_ size_t queueLimit):
7+
m_queueSizeLimit(queueLimit),
8+
m_dropCount(0)
9+
{
10+
SWSS_LOG_ENTER();
11+
12+
// empty;
13+
}
14+
15+
NotificationQueue::~NotificationQueue()
16+
{
17+
SWSS_LOG_ENTER();
18+
19+
// empty
20+
}
21+
22+
bool NotificationQueue::enqueue(
23+
_In_ const swss::KeyOpFieldsValuesTuple& item)
24+
{
25+
SWSS_LOG_ENTER();
26+
27+
/*
28+
* If the queue exceeds the limit, then drop all further FDB events This is
29+
* a temporary solution to handle high memory usage by syncd and the
30+
* notification queue keeps growing. The permanent solution would be to
31+
* make this stateful so that only the *latest* event is published.
32+
*/
33+
34+
if (getQueueSize() < m_queueSizeLimit || kfvOp(item) != "fdb_event") // TODO use enum instead of strings
35+
{
36+
std::lock_guard<std::mutex> lock(m_mutex);
37+
38+
m_queue.push(item);
39+
40+
return true;
41+
}
42+
43+
m_dropCount++;
44+
45+
if (!(m_dropCount % NOTIFICATION_QUEUE_DROP_COUNT_INDICATOR))
46+
{
47+
SWSS_LOG_NOTICE(
48+
"Too many messages in queue (%zu), dropped %zu FDB events!",
49+
getQueueSize(),
50+
m_dropCount);
51+
}
52+
53+
return false;
54+
}
55+
56+
bool NotificationQueue::tryDequeue(
57+
_Out_ swss::KeyOpFieldsValuesTuple& item)
58+
{
59+
SWSS_LOG_ENTER();
60+
61+
std::lock_guard<std::mutex> lock(m_mutex);
62+
63+
if (m_queue.empty())
64+
{
65+
return false;
66+
}
67+
68+
item = m_queue.front();
69+
70+
m_queue.pop();
71+
72+
return true;
73+
}
74+
75+
size_t NotificationQueue::getQueueSize()
76+
{
77+
SWSS_LOG_ENTER();
78+
79+
std::lock_guard<std::mutex> lock(m_mutex);
80+
81+
return m_queue.size();
82+
}
83+

syncd/NotificationQueue.h

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
#pragma once
2+
3+
extern "C" {
4+
#include <sai.h>
5+
}
6+
7+
#include "swss/table.h"
8+
9+
#include <queue>
10+
#include <mutex>
11+
12+
/**
13+
* @brief Default notification queue size limit.
14+
*
15+
* Value based on typical L2 deployment with 256k MAC entries and
16+
* some extra buffer for other events like port-state, q-deadlock etc
17+
*
18+
* TODO: move to config, also this limit only applies to fdb notifications
19+
*/
20+
#define DEFAULT_NOTIFICATION_QUEUE_SIZE_LIMIT (300000)
21+
22+
class NotificationQueue
23+
{
24+
public:
25+
26+
NotificationQueue(
27+
_In_ size_t limit = DEFAULT_NOTIFICATION_QUEUE_SIZE_LIMIT);
28+
29+
virtual ~NotificationQueue();
30+
31+
public:
32+
33+
bool enqueue(
34+
_In_ const swss::KeyOpFieldsValuesTuple& msg);
35+
36+
bool tryDequeue(
37+
_Out_ swss::KeyOpFieldsValuesTuple& msg);
38+
39+
size_t getQueueSize();
40+
41+
private:
42+
43+
std::mutex m_mutex;
44+
45+
std::queue<swss::KeyOpFieldsValuesTuple> m_queue;
46+
47+
size_t m_queueSizeLimit;
48+
49+
size_t m_dropCount;
50+
};
51+

syncd/syncd_notifications.cpp

+6-85
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
#include <memory>
77
#include <condition_variable>
88

9+
#include "NotificationQueue.h"
10+
911
void send_notification(
1012
_In_ std::string op,
1113
_In_ std::string data,
@@ -602,95 +604,14 @@ void processNotification(
602604

603605
std::condition_variable cv;
604606

605-
class ntf_queue_t
606-
{
607-
public:
608-
ntf_queue_t() { }
609-
bool enqueue(swss::KeyOpFieldsValuesTuple msg);
610-
bool tryDequeue(swss::KeyOpFieldsValuesTuple& msg);
611-
size_t queueStats()
612-
{
613-
SWSS_LOG_ENTER();
614-
615-
std::lock_guard<std::mutex> lock(queue_mutex);
616-
617-
return ntf_queue.size();
618-
}
619-
620-
private:
621-
std::mutex queue_mutex;
622-
std::queue<swss::KeyOpFieldsValuesTuple> ntf_queue;
623-
624-
/*
625-
* Value based on typical L2 deployment with 256k MAC entries and
626-
* some extra buffer for other events like port-state, q-deadlock etc
627-
*/
628-
const size_t limit = 300000;
629-
};
630-
631-
632607
/*
633608
* Make sure that notification queue pointer is populated before we start
634609
* thread, and before we create_switch, since at switch_create we can start
635610
* receiving fdb_notifications which will arrive on different thread and
636-
* will call queueStats() when queue pointer could be null (this=0x0).
611+
* will call getQueueSize() when queue pointer could be null (this=0x0).
637612
*/
638613

639-
static std::unique_ptr<ntf_queue_t> ntf_queue_hdlr = std::unique_ptr<ntf_queue_t>(new ntf_queue_t);
640-
641-
bool ntf_queue_t::tryDequeue(
642-
_Out_ swss::KeyOpFieldsValuesTuple &item)
643-
{
644-
std::lock_guard<std::mutex> lock(queue_mutex);
645-
646-
SWSS_LOG_ENTER();
647-
648-
if (ntf_queue.empty())
649-
{
650-
return false;
651-
}
652-
653-
item = ntf_queue.front();
654-
655-
ntf_queue.pop();
656-
657-
return true;
658-
}
659-
660-
bool ntf_queue_t::enqueue(
661-
_In_ swss::KeyOpFieldsValuesTuple item)
662-
{
663-
SWSS_LOG_ENTER();
664-
665-
std::string notification = kfvKey(item);
666-
667-
/*
668-
* If the queue exceeds the limit, then drop all further FDB events This is
669-
* a temporary solution to handle high memory usage by syncd and the
670-
* notification queue keeps growing. The permanent solution would be to
671-
* make this stateful so that only the *latest* event is published.
672-
*/
673-
674-
if (queueStats() < limit || notification != "fdb_event")
675-
{
676-
std::lock_guard<std::mutex> lock(queue_mutex);
677-
678-
ntf_queue.push(item);
679-
return true;
680-
}
681-
682-
static uint32_t log_count = 0;
683-
684-
if (!(log_count % 1000))
685-
{
686-
SWSS_LOG_NOTICE("Too many messages in queue (%zu), dropped %u FDB events!",
687-
queueStats(), (log_count+1));
688-
}
689-
690-
++log_count;
691-
692-
return false;
693-
}
614+
static auto g_notificationQueue = std::make_shared<NotificationQueue>();
694615

695616
void enqueue_notification(
696617
_In_ std::string op,
@@ -703,7 +624,7 @@ void enqueue_notification(
703624

704625
swss::KeyOpFieldsValuesTuple item(op, data, entry);
705626

706-
if(ntf_queue_hdlr->enqueue(item))
627+
if (g_notificationQueue->enqueue(item))
707628
{
708629
cv.notify_all();
709630
}
@@ -808,7 +729,7 @@ void ntf_process_function()
808729

809730
swss::KeyOpFieldsValuesTuple item;
810731

811-
while (ntf_queue_hdlr->tryDequeue(item))
732+
while (g_notificationQueue->tryDequeue(item))
812733
{
813734
processNotification(item);
814735
}

tests/Makefile.am

+2-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ vssyncd_SOURCES = \
1818
../syncd/syncd_notifications.cpp \
1919
../syncd/syncd_applyview.cpp \
2020
../syncd/syncd_flex_counter.cpp \
21-
../syncd/TimerWatchdog.cpp
21+
../syncd/TimerWatchdog.cpp \
22+
../syncd/NotificationQueue.cpp
2223

2324
vssyncd_CPPFLAGS = $(DBGFLAGS) $(AM_CPPFLAGS) $(CFLAGS_COMMON) $(SAIFLAGS)
2425
vssyncd_LDADD = -lhiredis -lswsscommon $(SAILIB) -lpthread -L$(top_srcdir)/meta/.libs -lsaimetadata -lsaimeta -ldl

tests/aspell.en.pws

+2-1
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ FIXME
7171
FlexCounter
7272
genetlink
7373
getInstance
74+
getQueueSize
7475
getSwitchId
7576
getVid
7677
github
@@ -91,8 +92,8 @@ INSEG
9192
ip
9293
IP
9394
IPG
94-
IPGs
9595
ipgs
96+
IPGs
9697
ipmc
9798
IPv
9899
isobjectid

0 commit comments

Comments
 (0)