Skip to content

Commit

Permalink
Added support for setting TTL on a Table managed entry. (#526)
Browse files Browse the repository at this point in the history
[table.h/rediscommand.h] 
* Updated table.h with a new set() routine capable of also setting TTL on an entry.
* Updated rediscommand.h with the EXPIRE command
  • Loading branch information
Cosmin-Jinga-MS authored Sep 19, 2021
1 parent 7d27b52 commit 81182ec
Show file tree
Hide file tree
Showing 5 changed files with 112 additions and 2 deletions.
12 changes: 12 additions & 0 deletions common/rediscommand.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,18 @@ void RedisCommand::formatHDEL(const std::string& key, const std::vector<std::str
formatArgv(static_cast<int>(args.size()), args.data(), NULL);
}

/* Format EXPIRE key field command */
void RedisCommand::formatEXPIRE(const std::string& key, const int64_t& ttl)
{
return format("EXPIRE %s %lld", key.c_str(), ttl);
}

/* Format TTL key command */
void RedisCommand::formatTTL(const std::string& key)
{
return format("TTL %s", key.c_str());
}

const char *RedisCommand::c_str() const
{
return temp;
Expand Down
6 changes: 6 additions & 0 deletions common/rediscommand.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,12 @@ class RedisCommand {
/* Format HDEL key multiple fields command */
void formatHDEL(const std::string& key, const std::vector<std::string>& fields);

/* Format EXPIRE key ttl command */
void formatEXPIRE(const std::string& key, const int64_t& ttl);

/* Format TTL key command */
void formatTTL(const std::string& key);

const char *c_str() const;

size_t length() const;
Expand Down
39 changes: 37 additions & 2 deletions common/table.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -123,21 +123,56 @@ void Table::hset(const string &key, const std::string &field, const std::string
}

void Table::set(const string &key, const vector<FieldValueTuple> &values,
const string& /*op*/, const string& /*prefix*/)
const string &op, const string &prefix)
{
set(key, values, op, prefix, DEFAULT_DB_TTL);
}

// TODO: Implement this without overloading(add an additional ttl param
// to existing set() command once sonic-swss's mock_table.cpp and other
// dependencies can be updated to use the extended new default set())
void Table::set(const string &key, const vector<FieldValueTuple> &values,
const string &op, const string &prefix, const int64_t &ttl)
{
if (values.size() == 0)
return;

RedisCommand cmd;

cmd.formatHMSET(getKeyName(key), values.begin(), values.end());

m_pipe->push(cmd, REDIS_REPLY_STATUS);

if (ttl != DEFAULT_DB_TTL)
{
// Configure the expire time for the entry that was just added
cmd.formatEXPIRE(getKeyName(key), ttl);
m_pipe->push(cmd, REDIS_REPLY_INTEGER);
}

if (!m_buffered)
{
m_pipe->flush();
}
}

bool Table::ttl(const string &key, int64_t &reply_value)
{
RedisCommand cmd_ttl;
cmd_ttl.formatTTL(getKeyName(key));
RedisReply r = m_pipe->push(cmd_ttl);
redisReply *reply = r.getContext();

if (reply != NULL)
{
reply_value = reply->integer;
return true;
}
else
{
return false;
}
}

void Table::del(const string &key, const string& /* op */, const string& /*prefix*/)
{
RedisCommand del_key;
Expand Down
13 changes: 13 additions & 0 deletions common/table.h
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,9 @@ class TableEntryEnumerable {
void getContent(std::vector<KeyOpFieldsValuesTuple> &tuples);
};

/* The default time to live for a DB entry is infinite */
static constexpr int64_t DEFAULT_DB_TTL = -1;

class Table : public TableBase, public TableEntryEnumerable {
public:
Table(const DBConnector *db, const std::string &tableName);
Expand All @@ -175,10 +178,20 @@ class Table : public TableBase, public TableEntryEnumerable {
const std::vector<FieldValueTuple> &values,
const std::string &op = "",
const std::string &prefix = EMPTY_PREFIX);

/* Set an entry in the DB directly and configure ttl for it (op not in use) */
virtual void set(const std::string &key,
const std::vector<FieldValueTuple> &values,
const std::string &op,
const std::string &prefix,
const int64_t &ttl);

/* Delete an entry in the table */
virtual void del(const std::string &key,
const std::string &op = "",
const std::string &prefix = EMPTY_PREFIX);
/* Get the configured ttl value for key */
bool ttl(const std::string &key, int64_t &reply_value);

#ifdef SWIG
// SWIG interface file (.i) globally rename map C++ `del` to python `delete`,
Expand Down
44 changes: 44 additions & 0 deletions tests/redis_ut.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -709,6 +709,50 @@ TEST(Table, table_separator_test)
TableBasicTest("TABLE_UT_TEST", false);
}

TEST(Table, ttl_test)
{
string tableName = "TABLE_UT_TEST";
DBConnector db("TEST_DB", 0, true);
RedisPipeline pipeline(&db);
Table t(&pipeline, tableName, true);

clearDB();
cout << "Starting table manipulations" << endl;

string key_1 = "a";
string key_2 = "b";
vector<FieldValueTuple> values;

for (int i = 1; i < 4; i++)
{
string field = "field_" + to_string(i);
string value = to_string(i);
values.push_back(make_pair(field, value));
}

int64_t initial_a_ttl = -1, initial_b_ttl = 200;
cout << "- Step 1. SET with custom ttl" << endl;
cout << "Set key [a] field_1:1 field_2:2 field_3:3 infinite ttl" << endl;
cout << "Set key [b] field_1:1 field_2:2 field_3:3 200 seconds ttl" << endl;

t.set(key_1, values, "", "", initial_a_ttl);
t.set(key_2, values, "", "", initial_b_ttl);
t.flush();

cout << "- Step 2. GET_TTL_VALUES" << endl;

int64_t a_ttl = 0, b_ttl = 0;
// Expect that we find the two entries confgured in the DB
EXPECT_EQ(true, t.ttl(key_1, a_ttl));
EXPECT_EQ(true, t.ttl(key_2, b_ttl));

// Expect that TTL values are the ones configured earlier
EXPECT_EQ(a_ttl, initial_a_ttl);
EXPECT_EQ(b_ttl, initial_b_ttl);

cout << "Done." << endl;
}

TEST(ProducerConsumer, Prefix)
{
std::string tableName = "tableName";
Expand Down

0 comments on commit 81182ec

Please sign in to comment.