Skip to content

Commit 149f985

Browse files
jipanyangyxieca
authored andcommitted
mv WarmStart class from swss to swss-common repo (sonic-net#241)
Signed-off-by: Jipan Yang <jipan.yang@alibaba-inc.com>
1 parent 3a6a0d1 commit 149f985

File tree

5 files changed

+392
-2
lines changed

5 files changed

+392
-2
lines changed

common/Makefile.am

+2-1
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,8 @@ libswsscommon_la_SOURCES = \
5050
tokenize.cpp \
5151
exec.cpp \
5252
subscriberstatetable.cpp \
53-
timestamp.cpp
53+
timestamp.cpp \
54+
warm_restart.cpp
5455

5556
libswsscommon_la_CXXFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(LIBNL_CFLAGS)
5657
libswsscommon_la_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(LIBNL_CPPFLAGS)

common/warm_restart.cpp

+190
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
#include <string>
2+
#include <climits>
3+
#include "logger.h"
4+
#include "schema.h"
5+
#include "warm_restart.h"
6+
7+
namespace swss {
8+
9+
const WarmStart::WarmStartStateNameMap WarmStart::warmStartStateNameMap =
10+
{
11+
{INITIALIZED, "initialized"},
12+
{RESTORED, "restored"},
13+
{RECONCILED, "reconciled"}
14+
};
15+
16+
WarmStart &WarmStart::getInstance(void)
17+
{
18+
static WarmStart m_warmStart;
19+
return m_warmStart;
20+
}
21+
22+
/*
23+
* WarmStart's initialization method -- to be invoked once per application.
24+
*/
25+
void WarmStart::initialize(const std::string &app_name,
26+
const std::string &docker_name,
27+
unsigned int db_timeout,
28+
const std::string &db_hostname,
29+
int db_port)
30+
{
31+
auto& warmStart = getInstance();
32+
33+
if (warmStart.m_initialized)
34+
{
35+
return;
36+
}
37+
38+
/* Use unix socket for db connection by default */
39+
if(db_hostname.empty())
40+
{
41+
warmStart.m_stateDb =
42+
std::make_shared<swss::DBConnector>(STATE_DB, swss::DBConnector::DEFAULT_UNIXSOCKET, db_timeout);
43+
warmStart.m_cfgDb =
44+
std::make_shared<swss::DBConnector>(CONFIG_DB, swss::DBConnector::DEFAULT_UNIXSOCKET, db_timeout);
45+
}
46+
else
47+
{
48+
warmStart.m_stateDb =
49+
std::make_shared<swss::DBConnector>(STATE_DB, db_hostname, db_port, db_timeout);
50+
warmStart.m_cfgDb =
51+
std::make_shared<swss::DBConnector>(CONFIG_DB, db_hostname, db_port, db_timeout);
52+
}
53+
54+
warmStart.m_stateWarmRestartTable =
55+
std::unique_ptr<Table>(new Table(warmStart.m_stateDb.get(), STATE_WARM_RESTART_TABLE_NAME));
56+
warmStart.m_cfgWarmRestartTable =
57+
std::unique_ptr<Table>(new Table(warmStart.m_cfgDb.get(), CFG_WARM_RESTART_TABLE_NAME));
58+
59+
warmStart.m_initialized = true;
60+
}
61+
62+
/*
63+
* <1> Upon system reboot, the system enable knob will be checked.
64+
* If enabled, database data will be preserved, if not, database will be flushed.
65+
* No need to check docker level knobs in this case since the whole system is being rebooted .
66+
67+
* <2> Upon docker service start, first to check system knob.
68+
* if enabled, docker warm-start should be performed, otherwise system warm-reboot will be ruined.
69+
* If system knob disabled, while docker knob enabled, this is likely an individual docker
70+
* warm-restart request.
71+
72+
* Within each application which should take care warm start case,
73+
* when the system knob or docker knob enabled, we do further check on the
74+
* actual warm-start state ( restore_count), if no warm-start state data available,
75+
* the database has been flushed, do cold start. Otherwise warm-start.
76+
*/
77+
78+
/*
79+
* Method to verify/obtain the state of Warm-Restart feature for any warm-reboot
80+
* capable component. Typically, this function will be called during initialization of
81+
* SONiC modules; however, method could be invoked at any given point to verify the
82+
* latest state of Warm-Restart functionality and to update the restore_count value.
83+
*/
84+
bool WarmStart::checkWarmStart(const std::string &app_name,
85+
const std::string &docker_name)
86+
{
87+
std::string value;
88+
89+
auto& warmStart = getInstance();
90+
91+
// Check system level warm-restart config first
92+
warmStart.m_cfgWarmRestartTable->hget("system", "enable", value);
93+
if (value == "true")
94+
{
95+
warmStart.m_enabled = true;
96+
}
97+
98+
// Check docker level warm-restart configuration
99+
warmStart.m_cfgWarmRestartTable->hget(docker_name, "enable", value);
100+
if (value == "true")
101+
{
102+
warmStart.m_enabled = true;
103+
}
104+
105+
// For cold start, the whole state db will be flushed including warm start table.
106+
// Create the entry for this app here.
107+
if (!warmStart.m_enabled)
108+
{
109+
warmStart.m_stateWarmRestartTable->hset(app_name, "restore_count", "0");
110+
return false;
111+
}
112+
113+
uint32_t restore_count = 0;
114+
warmStart.m_stateWarmRestartTable->hget(app_name, "restore_count", value);
115+
if (value == "")
116+
{
117+
SWSS_LOG_WARN("%s doing warm start, but restore_count not found in stateDB %s table, fall back to cold start",
118+
app_name.c_str(), STATE_WARM_RESTART_TABLE_NAME);
119+
warmStart.m_enabled = false;
120+
warmStart.m_stateWarmRestartTable->hset(app_name, "restore_count", "0");
121+
return false;
122+
}
123+
else
124+
{
125+
restore_count = (uint32_t)stoul(value);
126+
}
127+
128+
restore_count++;
129+
warmStart.m_stateWarmRestartTable->hset(app_name, "restore_count",
130+
std::to_string(restore_count));
131+
132+
SWSS_LOG_NOTICE("%s doing warm start, restore count %d", app_name.c_str(),
133+
restore_count);
134+
135+
return true;
136+
}
137+
138+
/*
139+
* Obtain the time-interval defined by a warm-restart-capable application
140+
* corresponding to the amount of time required to complete a full-restart cycle.
141+
* This time-duration (warmStartTimer) will be taken into account by the
142+
* warm-restart logic to kick-off the reconciliation process of this application.
143+
* A returned value of '0' implies that no valid interval was found.
144+
*/
145+
uint32_t WarmStart::getWarmStartTimer(const std::string &app_name,
146+
const std::string &docker_name)
147+
{
148+
auto& warmStart = getInstance();
149+
std::string timer_name = app_name + "_timer";
150+
std::string timer_value_str;
151+
152+
warmStart.m_cfgWarmRestartTable->hget(docker_name, timer_name, timer_value_str);
153+
154+
unsigned long int temp_value = strtoul(timer_value_str.c_str(), NULL, 0);
155+
156+
if (temp_value != 0 && temp_value != ULONG_MAX &&
157+
temp_value <= MAXIMUM_WARMRESTART_TIMER_VALUE)
158+
{
159+
SWSS_LOG_NOTICE("Getting warmStartTimer for docker: %s, app: %s, value: %lu",
160+
docker_name.c_str(), app_name.c_str(), temp_value);
161+
return (uint32_t)temp_value;
162+
}
163+
164+
SWSS_LOG_NOTICE("warmStartTimer is not configured or invalid for docker: %s, app: %s",
165+
docker_name.c_str(), app_name.c_str());
166+
return 0;
167+
}
168+
169+
bool WarmStart::isWarmStart(void)
170+
{
171+
auto& warmStart = getInstance();
172+
173+
return warmStart.m_enabled;
174+
}
175+
176+
// Set the WarmStart FSM state for a particular application.
177+
void WarmStart::setWarmStartState(const std::string &app_name, WarmStartState state)
178+
{
179+
auto& warmStart = getInstance();
180+
181+
warmStart.m_stateWarmRestartTable->hset(app_name,
182+
"state",
183+
warmStartStateNameMap.at(state).c_str());
184+
185+
SWSS_LOG_NOTICE("%s warm start state changed to %s",
186+
app_name.c_str(),
187+
warmStartStateNameMap.at(state).c_str());
188+
}
189+
190+
}

common/warm_restart.h

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
#ifndef SWSS_WARM_RESTART_H
2+
#define SWSS_WARM_RESTART_H
3+
4+
#include <string>
5+
#include "dbconnector.h"
6+
#include "table.h"
7+
8+
#define MAXIMUM_WARMRESTART_TIMER_VALUE 9999
9+
10+
namespace swss {
11+
12+
class WarmStart
13+
{
14+
public:
15+
enum WarmStartState
16+
{
17+
INITIALIZED,
18+
RESTORED,
19+
RECONCILED,
20+
};
21+
22+
typedef std::map<WarmStartState, std::string> WarmStartStateNameMap;
23+
static const WarmStartStateNameMap warmStartStateNameMap;
24+
25+
static WarmStart &getInstance(void);
26+
27+
static void initialize(const std::string &app_name,
28+
const std::string &docker_name = "swss",
29+
unsigned int db_timeout = 0,
30+
const std::string &db_hostname = "",
31+
int db_port = 6379);
32+
33+
static bool checkWarmStart(const std::string &app_name,
34+
const std::string &docker_name = "swss");
35+
36+
static bool isWarmStart(void);
37+
38+
static void setWarmStartState(const std::string &app_name,
39+
WarmStartState state);
40+
41+
static uint32_t getWarmStartTimer(const std::string &app_name,
42+
const std::string &docker_name ="swss");
43+
44+
private:
45+
std::shared_ptr<swss::DBConnector> m_stateDb;
46+
std::shared_ptr<swss::DBConnector> m_cfgDb;
47+
std::unique_ptr<Table> m_stateWarmRestartTable;
48+
std::unique_ptr<Table> m_cfgWarmRestartTable;
49+
bool m_initialized;
50+
bool m_enabled;
51+
};
52+
53+
}
54+
55+
#endif

tests/Makefile.am

+2-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ tests_SOURCES = redis_ut.cpp \
2525
converter_ut.cpp \
2626
exec_ut.cpp \
2727
redis_subscriber_state_ut.cpp \
28-
selectable_priority.cpp
28+
selectable_priority.cpp \
29+
warm_restart_ut.cpp
2930

3031
tests_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_GTEST) $(LIBNL_CFLAGS)
3132
tests_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_GTEST) $(LIBNL_CFLAGS)

0 commit comments

Comments
 (0)