forked from sonic-net/sonic-swss
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
The Table class wraps Redis transaction access. The Table class define conventions of "Tables" on flat key-value Redis DB. Every key belongs to a table. The key encoding is <TABLE_NAME>:<KEY_NAME> Every change in Redis DB will be recorded in three lists: KEY, VALUE and OP. The idea behind those lists is to allow consumer to get notification even when elements are rapidly added and removed from the DB. Signed-off-by: Elad Raz <[email protected]>
- Loading branch information
Showing
3 changed files
with
169 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
#include <hiredis/hiredis.h> | ||
#include <system_error> | ||
|
||
#include "common/table.h" | ||
#include "common/logger.h" | ||
#include "common/redisreply.h" | ||
|
||
using namespace std; | ||
|
||
namespace swss { | ||
|
||
Table::Table(DBConnector *db, string tableName) : | ||
m_db(db), | ||
m_tableName(tableName) | ||
{ | ||
} | ||
|
||
string Table::getKeyName(string key) | ||
{ | ||
return m_tableName + ':' + key; | ||
} | ||
|
||
string Table::getKeyQueueTableName() | ||
{ | ||
return m_tableName + "_KEY_QUEUE"; | ||
} | ||
|
||
string Table::getValueQueueTableName() | ||
{ | ||
return m_tableName + "_VALUE_QUEUE"; | ||
} | ||
|
||
string Table::getOpQueueTableName() | ||
{ | ||
return m_tableName + "_OP_QUEUE"; | ||
} | ||
|
||
string Table::getChannelTableName() | ||
{ | ||
return m_tableName + "_CHANNEL"; | ||
} | ||
|
||
void Table::multi() | ||
{ | ||
while (!m_expectedResults.empty()) | ||
m_expectedResults.pop(); | ||
RedisReply r(m_db, "MULTI", REDIS_REPLY_STATUS); | ||
r.checkStatusOK(); | ||
} | ||
|
||
redisReply *Table::queueResultsFront() | ||
{ | ||
return m_results.front()->getContext(); | ||
} | ||
|
||
void Table::queueResultsPop() | ||
{ | ||
delete m_results.front(); | ||
m_results.pop(); | ||
} | ||
|
||
void Table::exec() | ||
{ | ||
redisReply *reply = (redisReply *)redisCommand(m_db->getContext(), "EXEC"); | ||
unsigned int size = reply->elements; | ||
|
||
try | ||
{ | ||
if (reply->type != REDIS_REPLY_ARRAY) | ||
throw system_error(make_error_code(errc::io_error), | ||
"Error in transaction"); | ||
|
||
if (size != m_expectedResults.size()) | ||
throw system_error(make_error_code(errc::io_error), | ||
"Got to different nuber of answers!"); | ||
|
||
while (!m_results.empty()) | ||
queueResultsPop(); | ||
|
||
for (unsigned int i = 0; i < size; i++) | ||
{ | ||
int expectedType = m_expectedResults.front(); | ||
m_expectedResults.pop(); | ||
if (expectedType != reply->element[i]->type) | ||
{ | ||
SWSS_LOG_INFO("Except to get redis type %d got type %d\n", | ||
expectedType, reply->element[i]->type); | ||
throw system_error(make_error_code(errc::io_error), | ||
"Got unexpected result"); | ||
} | ||
} | ||
} | ||
catch (...) { | ||
freeReplyObject(reply); | ||
throw; | ||
} | ||
|
||
for (unsigned int i = 0; i < size; i++) | ||
m_results.push(new RedisReply(reply->element[i])); | ||
|
||
/* Free only the array memory */ | ||
free(reply->element); | ||
free(reply); | ||
} | ||
|
||
void Table::enqueue(std::string command, int exepectedResult, bool isFormatted) | ||
{ | ||
RedisReply r(m_db, command, REDIS_REPLY_STATUS, isFormatted); | ||
r.checkStatusQueued(); | ||
m_expectedResults.push(exepectedResult); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
#ifndef __TABLE__ | ||
#define __TABLE__ | ||
|
||
#include <string> | ||
#include <queue> | ||
#include <tuple> | ||
#include "hiredis/hiredis.h" | ||
#include "common/dbconnector.h" | ||
#include "common/redisreply.h" | ||
#include "common/scheme.h" | ||
|
||
namespace swss { | ||
|
||
typedef std::tuple<std::string, std::string> FieldValueTuple; | ||
#define fvField std::get<0> | ||
#define fvValue std::get<1> | ||
typedef std::tuple<std::string, std::string, std::vector<FieldValueTuple> > KeyOpFieldsValuesTuple; | ||
#define kfvKey std::get<0> | ||
#define kfvOp std::get<1> | ||
#define kfvFieldsValues std::get<2> | ||
|
||
class Table { | ||
protected: | ||
Table(DBConnector *db, std::string tableName); | ||
|
||
/* Return the actual key name as a comibation of tableName:key */ | ||
std::string getKeyName(std::string key); | ||
|
||
std::string getKeyQueueTableName(); | ||
std::string getValueQueueTableName(); | ||
std::string getOpQueueTableName(); | ||
std::string getChannelTableName(); | ||
|
||
/* Start a transaction */ | ||
void multi(); | ||
/* Execute a transaction and get results */ | ||
void exec(); | ||
|
||
/* Send a command within a transaction */ | ||
void enqueue(std::string command, int exepectedResult, bool isFormatted = false); | ||
redisReply* queueResultsFront(); | ||
void queueResultsPop(); | ||
|
||
DBConnector *m_db; | ||
std::string m_tableName; | ||
|
||
/* Remember the expected results for the transaction */ | ||
std::queue<int> m_expectedResults; | ||
std::queue<RedisReply * > m_results; | ||
}; | ||
|
||
} | ||
|
||
#endif |