Skip to content

Commit 9c01751

Browse files
committed
New p4orch development for performance.
Change-Id: I867ce9d1d4a641b35493fb81d60813083d4404f9
1 parent 054ed34 commit 9c01751

16 files changed

Lines changed: 186 additions & 896 deletions

cfgmgr/Makefile.am

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ CFLAGS_SAI = -I /usr/include/sai
33
LIBNL_CFLAGS = -I/usr/include/libnl3
44
LIBNL_LIBS = -lnl-genl-3 -lnl-route-3 -lnl-3
55
SAIMETA_LIBS = -lsaimeta -lsaimetadata -lzmq
6-
COMMON_LIBS = -lswsscommon
6+
COMMON_LIBS = -lswsscommon -lpthread
77

88
bin_PROGRAMS = vlanmgrd teammgrd portmgrd intfmgrd buffermgrd vrfmgrd nbrmgrd vxlanmgrd sflowmgrd natmgrd coppmgrd tunnelmgrd macsecmgrd fabricmgrd
99

orchagent/orch.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,7 @@ class Orch
271271
void addExecutor(Executor* executor);
272272
Executor *getExecutor(std::string executorName);
273273

274-
ResponsePublisher m_publisher;
274+
ResponsePublisher m_publisher{"APPL_STATE_DB"};
275275
private:
276276
void addConsumer(swss::DBConnector *db, std::string tableName, int pri = default_orch_pri);
277277
};

orchagent/p4orch/p4orch.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,8 @@ void P4Orch::doTask(Consumer &consumer)
154154
{
155155
manager->drain();
156156
}
157+
158+
m_publisher.flush();
157159
}
158160

159161
void P4Orch::doTask(swss::SelectableTimer &timer)

orchagent/p4orch/p4orch.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,5 +83,8 @@ class P4Orch : public Orch
8383
// Notification consumer for port state change
8484
swss::NotificationConsumer *m_portStatusNotificationConsumer;
8585

86+
// Sepcial publisher that writes to APPL DB instead of APPL STATE DB.
87+
ResponsePublisher m_publisher{"APPL_DB", /*bool buffered=*/true, /*db_write_thread=*/true};
88+
8689
friend class p4orch::test::WcmpManagerTest;
8790
};

orchagent/p4orch/tests/return_code_test.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ TEST(ReturnCodeTest, SaiCodeToReturnCodeMapping)
119119
{SAI_STATUS_TABLE_FULL, StatusCode::SWSS_RC_FULL},
120120
{SAI_STATUS_NOT_IMPLEMENTED, StatusCode::SWSS_RC_UNIMPLEMENTED},
121121
{SAI_STATUS_OBJECT_IN_USE, StatusCode::SWSS_RC_IN_USE},
122+
{SAI_STATUS_NOT_EXECUTED, StatusCode::SWSS_RC_NOT_EXECUTED},
122123
{SAI_STATUS_FAILURE, StatusCode::SWSS_RC_UNKNOWN},
123124
{SAI_STATUS_INVALID_ATTRIBUTE_0, StatusCode::SWSS_RC_INVALID_PARAM},
124125
{SAI_STATUS_INVALID_ATTRIBUTE_10, StatusCode::SWSS_RC_INVALID_PARAM},

orchagent/response_publisher.cpp

Lines changed: 124 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -64,26 +64,52 @@ void RecordResponse(const std::string &response_channel, const std::string &key,
6464

6565
} // namespace
6666

67-
ResponsePublisher::ResponsePublisher(bool buffered)
68-
: m_db(std::make_unique<swss::DBConnector>("APPL_STATE_DB", 0)),
69-
m_pipe(std::make_unique<swss::RedisPipeline>(m_db.get())), m_buffered(buffered)
67+
ResponsePublisher::ResponsePublisher(const std::string &dbName, bool buffered, bool db_write_thread)
68+
: m_db(std::make_unique<swss::DBConnector>(dbName, 0)), m_buffered(buffered)
7069
{
70+
if (m_buffered)
71+
{
72+
m_ntf_pipe = std::make_unique<swss::RedisPipeline>(m_db.get());
73+
m_pipe = std::make_unique<swss::RedisPipeline>(m_db.get());
74+
}
75+
else
76+
{
77+
m_ntf_pipe = std::make_unique<swss::RedisPipeline>(m_db.get(), 1);
78+
m_pipe = std::make_unique<swss::RedisPipeline>(m_db.get(), 1);
79+
}
80+
if (db_write_thread)
81+
{
82+
m_update_thread = std::unique_ptr<std::thread>(new std::thread(&ResponsePublisher::dbUpdateThread, this));
83+
}
7184
}
7285

73-
void ResponsePublisher::publish(const std::string &table, const std::string &key,
74-
const std::vector<swss::FieldValueTuple> &intent_attrs, const ReturnCode &status,
75-
const std::vector<swss::FieldValueTuple> &state_attrs, bool replace)
86+
ResponsePublisher::~ResponsePublisher()
7687
{
77-
// Write to the DB only if:
78-
// 1) A write operation is being performed and state attributes are specified.
79-
// 2) A successful delete operation.
80-
if ((intent_attrs.size() && state_attrs.size()) || (status.ok() && !intent_attrs.size()))
88+
if (m_update_thread != nullptr)
8189
{
82-
writeToDB(table, key, state_attrs, intent_attrs.size() ? SET_COMMAND : DEL_COMMAND, replace);
90+
{
91+
std::lock_guard<std::mutex> lock(m_lock);
92+
m_queue.push(entry{
93+
.table = "",
94+
.key = "",
95+
.values = std::vector<swss::FieldValueTuple>{},
96+
.op = "",
97+
.replace = false,
98+
.flush = false,
99+
.shutdown = true,
100+
});
101+
}
102+
m_signal.notify_one();
103+
m_update_thread->join();
83104
}
105+
}
84106

107+
void ResponsePublisher::publish(const std::string &table, const std::string &key,
108+
const std::vector<swss::FieldValueTuple> &intent_attrs, const ReturnCode &status,
109+
const std::vector<swss::FieldValueTuple> &state_attrs, bool replace)
110+
{
85111
std::string response_channel = "APPL_DB_" + table + "_RESPONSE_CHANNEL";
86-
swss::NotificationProducer notificationProducer{m_pipe.get(), response_channel, m_buffered};
112+
swss::NotificationProducer notificationProducer{m_ntf_pipe.get(), response_channel, m_buffered};
87113

88114
auto intent_attrs_copy = intent_attrs;
89115
// Add error message as the first field-value-pair.
@@ -92,6 +118,14 @@ void ResponsePublisher::publish(const std::string &table, const std::string &key
92118
// Sends the response to the notification channel.
93119
notificationProducer.send(status.codeStr(), key, intent_attrs_copy);
94120
RecordResponse(response_channel, key, intent_attrs_copy, status.codeStr());
121+
122+
// Write to the DB only if:
123+
// 1) A write operation is being performed and state attributes are specified.
124+
// 2) A successful delete operation.
125+
if ((intent_attrs.size() && state_attrs.size()) || (status.ok() && !intent_attrs.size()))
126+
{
127+
writeToDB(table, key, state_attrs, intent_attrs.size() ? SET_COMMAND : DEL_COMMAND, replace);
128+
}
95129
}
96130

97131
void ResponsePublisher::publish(const std::string &table, const std::string &key,
@@ -112,6 +146,33 @@ void ResponsePublisher::publish(const std::string &table, const std::string &key
112146

113147
void ResponsePublisher::writeToDB(const std::string &table, const std::string &key,
114148
const std::vector<swss::FieldValueTuple> &values, const std::string &op, bool replace)
149+
{
150+
if (m_update_thread != nullptr)
151+
{
152+
{
153+
std::lock_guard<std::mutex> lock(m_lock);
154+
m_queue.push(entry{
155+
.table = table,
156+
.key = key,
157+
.values = values,
158+
.op = op,
159+
.replace = replace,
160+
.flush = false,
161+
.shutdown = false,
162+
});
163+
}
164+
m_signal.notify_one();
165+
}
166+
else
167+
{
168+
writeToDBInternal(table, key, values, op, replace);
169+
}
170+
RecordDBWrite(table, key, values, op);
171+
}
172+
173+
void ResponsePublisher::writeToDBInternal(const std::string &table, const std::string &key,
174+
const std::vector<swss::FieldValueTuple> &values, const std::string &op,
175+
bool replace)
115176
{
116177
swss::Table applStateTable{m_pipe.get(), table, m_buffered};
117178

@@ -133,7 +194,6 @@ void ResponsePublisher::writeToDB(const std::string &table, const std::string &k
133194
if (!applStateTable.get(key, fv))
134195
{
135196
applStateTable.set(key, attrs);
136-
RecordDBWrite(table, key, attrs, op);
137197
return;
138198
}
139199
for (auto it = attrs.cbegin(); it != attrs.cend();)
@@ -150,22 +210,70 @@ void ResponsePublisher::writeToDB(const std::string &table, const std::string &k
150210
if (attrs.size())
151211
{
152212
applStateTable.set(key, attrs);
153-
RecordDBWrite(table, key, attrs, op);
154213
}
155214
}
156215
else if (op == DEL_COMMAND)
157216
{
158217
applStateTable.del(key);
159-
RecordDBWrite(table, key, {}, op);
160218
}
161219
}
162220

163221
void ResponsePublisher::flush()
164222
{
165-
m_pipe->flush();
223+
m_ntf_pipe->flush();
224+
if (m_update_thread != nullptr)
225+
{
226+
{
227+
std::lock_guard<std::mutex> lock(m_lock);
228+
m_queue.push(entry{
229+
.table = "",
230+
.key = "",
231+
.values = std::vector<swss::FieldValueTuple>{},
232+
.op = "",
233+
.replace = false,
234+
.flush = true,
235+
.shutdown = false,
236+
});
237+
}
238+
m_signal.notify_one();
239+
}
240+
else
241+
{
242+
m_pipe->flush();
243+
}
166244
}
167245

168246
void ResponsePublisher::setBuffered(bool buffered)
169247
{
170248
m_buffered = buffered;
171249
}
250+
251+
void ResponsePublisher::dbUpdateThread()
252+
{
253+
while (true)
254+
{
255+
entry e;
256+
{
257+
std::unique_lock<std::mutex> lock(m_lock);
258+
while (m_queue.empty())
259+
{
260+
m_signal.wait(lock);
261+
}
262+
263+
e = m_queue.front();
264+
m_queue.pop();
265+
}
266+
if (e.shutdown)
267+
{
268+
break;
269+
}
270+
if (e.flush)
271+
{
272+
m_pipe->flush();
273+
}
274+
else
275+
{
276+
writeToDBInternal(e.table, e.key, e.values, e.op, e.replace);
277+
}
278+
}
279+
}

orchagent/response_publisher.h

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
#pragma once
22

3+
#include <condition_variable>
34
#include <memory>
5+
#include <mutex>
6+
#include <queue>
47
#include <string>
8+
#include <thread>
59
#include <unordered_map>
610
#include <vector>
711

@@ -17,9 +21,9 @@
1721
class ResponsePublisher : public ResponsePublisherInterface
1822
{
1923
public:
20-
explicit ResponsePublisher(bool buffered = false);
24+
explicit ResponsePublisher(const std::string &dbName, bool buffered = false, bool db_write_thread = false);
2125

22-
virtual ~ResponsePublisher() = default;
26+
virtual ~ResponsePublisher();
2327

2428
// Intent attributes are the attributes sent in the notification into the
2529
// redis channel.
@@ -57,8 +61,29 @@ class ResponsePublisher : public ResponsePublisherInterface
5761
void setBuffered(bool buffered);
5862

5963
private:
64+
struct entry
65+
{
66+
std::string table;
67+
std::string key;
68+
std::vector<swss::FieldValueTuple> values;
69+
std::string op;
70+
bool replace;
71+
bool flush;
72+
bool shutdown;
73+
};
74+
75+
void dbUpdateThread();
76+
void writeToDBInternal(const std::string &table, const std::string &key,
77+
const std::vector<swss::FieldValueTuple> &values, const std::string &op, bool replace);
78+
6079
std::unique_ptr<swss::DBConnector> m_db;
80+
std::unique_ptr<swss::RedisPipeline> m_ntf_pipe;
6181
std::unique_ptr<swss::RedisPipeline> m_pipe;
6282

6383
bool m_buffered{false};
84+
// Thread to write to DB.
85+
std::unique_ptr<std::thread> m_update_thread;
86+
std::queue<entry> m_queue;
87+
mutable std::mutex m_lock;
88+
std::condition_variable m_signal;
6489
};

orchagent/return_code.h

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,24 @@ class ReturnCode
177177
ReturnCode(const sai_status_t &status, const std::string &message = "")
178178
: stream_(std::ios_base::out | std::ios_base::ate), is_sai_(true)
179179
{
180-
if (m_saiStatusCodeLookup.find(status) == m_saiStatusCodeLookup.end())
180+
// Non-ranged SAI codes that are not included in this lookup map will map to
181+
// SWSS_RC_UNKNOWN. This includes the general SAI failure:
182+
// SAI_STATUS_FAILURE.
183+
static const auto *const saiStatusCodeLookup = new std::unordered_map<sai_status_t, StatusCode>({
184+
{SAI_STATUS_SUCCESS, StatusCode::SWSS_RC_SUCCESS},
185+
{SAI_STATUS_NOT_SUPPORTED, StatusCode::SWSS_RC_UNIMPLEMENTED},
186+
{SAI_STATUS_NO_MEMORY, StatusCode::SWSS_RC_NO_MEMORY},
187+
{SAI_STATUS_INSUFFICIENT_RESOURCES, StatusCode::SWSS_RC_FULL},
188+
{SAI_STATUS_INVALID_PARAMETER, StatusCode::SWSS_RC_INVALID_PARAM},
189+
{SAI_STATUS_ITEM_ALREADY_EXISTS, StatusCode::SWSS_RC_EXISTS},
190+
{SAI_STATUS_ITEM_NOT_FOUND, StatusCode::SWSS_RC_NOT_FOUND},
191+
{SAI_STATUS_TABLE_FULL, StatusCode::SWSS_RC_FULL},
192+
{SAI_STATUS_NOT_IMPLEMENTED, StatusCode::SWSS_RC_UNIMPLEMENTED},
193+
{SAI_STATUS_OBJECT_IN_USE, StatusCode::SWSS_RC_IN_USE},
194+
{SAI_STATUS_NOT_EXECUTED, StatusCode::SWSS_RC_NOT_EXECUTED},
195+
});
196+
197+
if (saiStatusCodeLookup->find(status) == saiStatusCodeLookup->end())
181198
{
182199
// Check for ranged SAI codes.
183200
if (SAI_RANGED_STATUS_IS_INVALID_ATTRIBUTE(status))
@@ -207,7 +224,7 @@ class ReturnCode
207224
}
208225
else
209226
{
210-
status_ = m_saiStatusCodeLookup[status];
227+
status_ = saiStatusCodeLookup->at(status);
211228
}
212229
stream_ << message;
213230
}
@@ -298,21 +315,6 @@ class ReturnCode
298315
}
299316

300317
private:
301-
// Non-ranged SAI codes that are not included in this lookup map will map to
302-
// SWSS_RC_UNKNOWN. This includes the general SAI failure: SAI_STATUS_FAILURE.
303-
std::unordered_map<sai_status_t, StatusCode> m_saiStatusCodeLookup = {
304-
{SAI_STATUS_SUCCESS, StatusCode::SWSS_RC_SUCCESS},
305-
{SAI_STATUS_NOT_SUPPORTED, StatusCode::SWSS_RC_UNIMPLEMENTED},
306-
{SAI_STATUS_NO_MEMORY, StatusCode::SWSS_RC_NO_MEMORY},
307-
{SAI_STATUS_INSUFFICIENT_RESOURCES, StatusCode::SWSS_RC_FULL},
308-
{SAI_STATUS_INVALID_PARAMETER, StatusCode::SWSS_RC_INVALID_PARAM},
309-
{SAI_STATUS_ITEM_ALREADY_EXISTS, StatusCode::SWSS_RC_EXISTS},
310-
{SAI_STATUS_ITEM_NOT_FOUND, StatusCode::SWSS_RC_NOT_FOUND},
311-
{SAI_STATUS_TABLE_FULL, StatusCode::SWSS_RC_FULL},
312-
{SAI_STATUS_NOT_IMPLEMENTED, StatusCode::SWSS_RC_UNIMPLEMENTED},
313-
{SAI_STATUS_OBJECT_IN_USE, StatusCode::SWSS_RC_IN_USE},
314-
};
315-
316318
StatusCode status_;
317319
std::stringstream stream_;
318320
// Whether the ReturnCode is generated from a SAI status code or not.

tests/mock_tests/fake_response_publisher.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,10 @@
88
* when needed to test code that uses response publisher. */
99
std::unique_ptr<MockResponsePublisher> gMockResponsePublisher;
1010

11-
ResponsePublisher::ResponsePublisher(bool buffered) : m_db(std::make_unique<swss::DBConnector>("APPL_STATE_DB", 0)), m_buffered(buffered) {}
11+
ResponsePublisher::ResponsePublisher(const std::string& dbName, bool buffered, bool db_write_thread) :
12+
m_db(std::make_unique<swss::DBConnector>(dbName, 0)), m_buffered(buffered) {}
13+
14+
ResponsePublisher::~ResponsePublisher() {}
1215

1316
void ResponsePublisher::publish(
1417
const std::string& table, const std::string& key,

tests/mock_tests/response_publisher/response_publisher_ut.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ TEST(ResponsePublisher, TestPublish)
99
DBConnector conn{"APPL_STATE_DB", 0};
1010
Table stateTable{&conn, "SOME_TABLE"};
1111
std::string value;
12-
ResponsePublisher publisher{};
12+
ResponsePublisher publisher{"APPL_STATE_DB"};
1313

1414
publisher.publish("SOME_TABLE", "SOME_KEY", {{"field", "value"}}, ReturnCode(SAI_STATUS_SUCCESS));
1515
ASSERT_TRUE(stateTable.hget("SOME_KEY", "field", value));
@@ -21,7 +21,7 @@ TEST(ResponsePublisher, TestPublishBuffered)
2121
DBConnector conn{"APPL_STATE_DB", 0};
2222
Table stateTable{&conn, "SOME_TABLE"};
2323
std::string value;
24-
ResponsePublisher publisher{};
24+
ResponsePublisher publisher{"APPL_STATE_DB"};
2525

2626
publisher.setBuffered(true);
2727

0 commit comments

Comments
 (0)