Skip to content

Commit

Permalink
Re-write sonic-db-cli with c++ for sonic startup performance issue (#607
Browse files Browse the repository at this point in the history
) (#636)

Fix sonic-db-cli high CPU usage on SONiC startup issue: sonic-net/sonic-buildimage#10218
    ETA of this issue will be 2022/05/31

    Re-write sonic-cli with c++.

    Add c++ unit test to cover all code.
    Pass all E2E test scenario.

<!--
- Note we only backport fixes to a release branch, *not* features!
- Please also provide a reason for the backporting below.
- e.g.
- [x] 202006
-->

- [ ] 201811
- [ ] 201911
- [ ] 202006
- [ ] 202012
- [ ] 202106
- [ ] 202111

    Re-write sonic-cli with c++ for sonic startup performance issue
  • Loading branch information
liuh-80 committed Jun 23, 2022
1 parent ac042b3 commit ace3a42
Show file tree
Hide file tree
Showing 17 changed files with 807 additions and 3 deletions.
2 changes: 1 addition & 1 deletion Makefile.am
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
SUBDIRS = common pyext tests
SUBDIRS = common pyext sonic-db-cli tests

ACLOCAL_AMFLAGS = -I m4
10 changes: 10 additions & 0 deletions common/rediscommand.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,16 @@ void RedisCommand::formatArgv(int argc, const char **argv, const size_t *argvlen
}
}

void RedisCommand::format(const vector<string> &commands)
{
vector<const char*> args;
for (auto& command : commands)
{
args.push_back(command.c_str());
}
formatArgv(static_cast<int>(args.size()), args.data(), NULL);
}

/* Format HMSET key multiple field value command */
void RedisCommand::formatHMSET(const std::string &key,
const std::vector<FieldValueTuple> &values)
Expand Down
1 change: 1 addition & 0 deletions common/rediscommand.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ class RedisCommand {

void format(const char *fmt, ...);
void formatArgv(int argc, const char **argv, const size_t *argvlen);
void format(const std::vector<std::string> &commands);

/* Format HMSET key multiple field value command */
#ifndef SWIG
Expand Down
43 changes: 42 additions & 1 deletion common/redisreply.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include <stdint.h>
#include <vector>
#include <iostream>
#include <sstream>
#include <system_error>
#include <functional>

Expand Down Expand Up @@ -158,7 +159,7 @@ void RedisReply::checkReplyType(int expectedType)
const char *err = (m_reply->type == REDIS_REPLY_STRING || m_reply->type == REDIS_REPLY_ERROR) ?
m_reply->str : "NON-STRING-REPLY";

string errmsg = "Expected to get redis type " + to_string(expectedType) + " got type " + to_string(m_reply->type) + ", err: " + err;
string errmsg = "Expected to get redis type " + std::to_string(expectedType) + " got type " + std::to_string(m_reply->type) + ", err: " + err;
SWSS_LOG_ERROR("%s", errmsg.c_str());
throw system_error(make_error_code(errc::io_error), errmsg);
}
Expand Down Expand Up @@ -225,4 +226,44 @@ template<> RedisMessage RedisReply::getReply<RedisMessage>()
return ret;
}


string RedisReply::to_string()
{
return to_string(getContext());
}

string RedisReply::to_string(redisReply *reply)
{
switch(reply->type)
{
case REDIS_REPLY_INTEGER:
return std::to_string(reply->integer);

case REDIS_REPLY_STRING:
case REDIS_REPLY_ERROR:
case REDIS_REPLY_STATUS:
case REDIS_REPLY_NIL:
return string(reply->str, reply->len);

case REDIS_REPLY_ARRAY:
{
stringstream result;
for (size_t i = 0; i < reply->elements; i++)
{
result << to_string(reply->element[i]);

if (i < reply->elements - 1)
{
result << endl;
}
}
return result.str();
}

default:
SWSS_LOG_ERROR("invalid type %d for message", reply->type);
return string();
}
}

}
4 changes: 4 additions & 0 deletions common/redisreply.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,10 @@ class RedisReply
/* Check that the status is QUEUED, throw exception otherwise */
void checkStatusQueued();

std::string to_string();

static std::string to_string(redisReply *reply);

private:
void checkStatus(const char *status);
void checkReply();
Expand Down
1 change: 1 addition & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ AC_CONFIG_FILES([
pyext/Makefile
pyext/py2/Makefile
pyext/py3/Makefile
sonic-db-cli/Makefile
tests/Makefile
])

Expand Down
6 changes: 6 additions & 0 deletions debian/control
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,9 @@ Architecture: any
Depends: ${shlibs:Depends}, ${misc:Pre-Depends}
Section: libs
Description: This package contains Switch State Service common Python3 library.

Package: sonic-db-cli
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Pre-Depends}
Section: libs
Description: This package contains SONiC DB cli.
1 change: 1 addition & 0 deletions debian/sonic-db-cli.dirs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
usr/bin
1 change: 1 addition & 0 deletions debian/sonic-db-cli.install
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
usr/bin/sonic-db-cli
19 changes: 19 additions & 0 deletions sonic-db-cli/Makefile.am
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
INCLUDES = -I $(top_srcdir)

if DEBUG
DBGFLAGS = -ggdb -DDEBUG
else
DBGFLAGS = -g -DNDEBUG
endif

lib_LTLIBRARIES = libsonicdbcli.la
libsonicdbcli_la_SOURCES = sonic-db-cli.cpp
libsonicdbcli_la_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON)
libsonicdbcli_la_CPPFLAGS = $(DBGFLAGS) $(AM_CPPFLAGS) $(CFLAGS_COMMON)
libsonicdbcli_la_LDFLAGS = -L$(top_srcdir)/common -lswsscommon -lpthread

bin_PROGRAMS = sonic-db-cli
sonic_db_cli_SOURCES = sonic-db-cli.cpp main.cpp
sonic_db_cli_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON)
sonic_db_cli_CPPFLAGS = $(DBGFLAGS) $(AM_CPPFLAGS) $(CFLAGS_COMMON)
sonic_db_cli_LDFLAGS = -L$(top_srcdir)/common -lswsscommon -lpthread
24 changes: 24 additions & 0 deletions sonic-db-cli/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#include "sonic-db-cli.h"
#include "common/dbconnector.h"

using namespace swss;
using namespace std;

int main(int argc, char** argv)
{
auto initializeGlobalConfig = []()
{
SonicDBConfig::initializeGlobalConfig(SonicDBConfig::DEFAULT_SONIC_DB_GLOBAL_CONFIG_FILE);
};

auto initializeConfig = []()
{
SonicDBConfig::initialize(SonicDBConfig::DEFAULT_SONIC_DB_CONFIG_FILE);
};

return sonic_db_cli(
argc,
argv,
initializeGlobalConfig,
initializeConfig);
}
Loading

0 comments on commit ace3a42

Please sign in to comment.