common/redis_table_waiter.cpp (130 lines of code) (raw):
#include "redis_table_waiter.h"
#include "select.h"
#include "subscriberstatetable.h"
using namespace swss;
bool RedisTableWaiter::waitUntil(
DBConnector &db,
const std::string &tableName,
unsigned int maxWaitSec,
CheckFunc &checkFunc)
{
if (maxWaitSec == 0)
{
SWSS_LOG_ERROR("Error: invalid maxWaitSec value 0, must be larger than 0");
return false;
}
SubscriberStateTable table(&db, tableName);
Select s;
s.addSelectable(&table);
int maxWaitMs = static_cast<int>(maxWaitSec) * 1000;
int selectTimeout = maxWaitMs;
auto start = std::chrono::steady_clock::now();
while(1)
{
Selectable *sel = NULL;
int ret = s.select(&sel, selectTimeout, true);
if (ret == Select::OBJECT)
{
KeyOpFieldsValuesTuple kco;
table.pop(kco);
if (checkFunc(kco))
{
return true;
}
}
else if (ret == Select::ERROR)
{
SWSS_LOG_NOTICE("Error: wait redis table got error - %s!", strerror(errno));
}
else if (ret == Select::TIMEOUT)
{
SWSS_LOG_INFO("Timeout: wait redis table got select timeout");
}
else if (ret == Select::SIGNALINT)
{
return false;
}
auto end = std::chrono::steady_clock::now();
int delay = static_cast<int>(
std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count());
if (delay >= maxWaitMs)
{
return false;
}
selectTimeout = maxWaitMs - delay;
}
return false;
}
bool RedisTableWaiter::waitUntilFieldSet(
DBConnector &db,
const std::string &tableName,
const std::string &key,
const std::string &fieldName,
unsigned int maxWaitSec,
ConditionFunc &cond)
{
auto sep = SonicDBConfig::getSeparator(&db);
auto value = db.hget(tableName + sep + key, fieldName);
if (value && cond(*value.get()))
{
return true;
}
CheckFunc checkFunc = [&](const KeyOpFieldsValuesTuple &kco) -> bool {
if (SET_COMMAND == kfvOp(kco))
{
if (key == kfvKey(kco))
{
auto& values = kfvFieldsValues(kco);
for (auto& fvt: values)
{
if (fieldName == fvField(fvt))
{
return cond(fvValue(fvt));
}
}
}
}
return false;
};
return waitUntil(db, tableName, maxWaitSec, checkFunc);
}
bool RedisTableWaiter::waitUntilKeySet(
DBConnector &db,
const std::string &tableName,
const std::string &key,
unsigned int maxWaitSec)
{
auto sep = SonicDBConfig::getSeparator(&db);
if (db.exists(tableName + sep + key))
{
return true;
}
CheckFunc checkFunc = [&](const KeyOpFieldsValuesTuple &kco) -> bool {
if (SET_COMMAND == kfvOp(kco))
{
return key == kfvKey(kco);
}
return false;
};
return waitUntil(db, tableName, maxWaitSec, checkFunc);
}
bool RedisTableWaiter::waitUntilKeyDel(
DBConnector &db,
const std::string &tableName,
const std::string &key,
unsigned int maxWaitSec)
{
auto sep = SonicDBConfig::getSeparator(&db);
if (!db.exists(tableName + sep + key))
{
return true;
}
CheckFunc checkFunc = [&](const KeyOpFieldsValuesTuple &kco) -> bool {
if (DEL_COMMAND == kfvOp(kco))
{
return key == kfvKey(kco);
}
return false;
};
return waitUntil(db, tableName, maxWaitSec, checkFunc);
}