Skip to content

Commit

Permalink
Throw proper exceptions when talking with Redis (#384)
Browse files Browse the repository at this point in the history
* Add new exception RedisResponseError
* Rename to RedisError
* Throw bad_alloc when ouf of memory
* Handle and throw exception in RedisPipeline
  • Loading branch information
qiluo-msft authored Sep 18, 2020
1 parent 2b9a00f commit 5776ef5
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 6 deletions.
14 changes: 12 additions & 2 deletions common/redispipeline.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,13 @@ class RedisPipeline {
case REDIS_REPLY_STATUS:
case REDIS_REPLY_INTEGER:
{
redisAppendFormattedCommand(m_db->getContext(), command.c_str(), command.length());
int rc = redisAppendFormattedCommand(m_db->getContext(), command.c_str(), command.length());
if (rc != REDIS_OK)
{
// The only reason of error is REDIS_ERR_OOM (Out of memory)
// ref: https://github.com/redis/hiredis/blob/master/hiredis.c
throw std::bad_alloc();
}
m_expectedTypes.push(expectedType);
m_remaining++;
mayflush();
Expand Down Expand Up @@ -71,7 +77,11 @@ class RedisPipeline {
if (m_remaining == 0) return NULL;

redisReply *reply;
redisGetReply(m_db->getContext(), (void**)&reply);
int rc = redisGetReply(m_db->getContext(), (void**)&reply);
if (rc != REDIS_OK)
{
throw RedisError("Failed to redisGetReply in RedisPipeline::pop", m_db->getContext());
}
RedisReply r(reply);
m_remaining--;

Expand Down
30 changes: 26 additions & 4 deletions common/redisreply.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,37 @@ inline void guard(FUNC func, const char* command)

RedisReply::RedisReply(DBConnector *db, const RedisCommand& command)
{
redisAppendFormattedCommand(db->getContext(), command.c_str(), command.length());
redisGetReply(db->getContext(), (void**)&m_reply);
int rc = redisAppendFormattedCommand(db->getContext(), command.c_str(), command.length());
if (rc != REDIS_OK)
{
// The only reason of error is REDIS_ERR_OOM (Out of memory)
// ref: https://github.com/redis/hiredis/blob/master/hiredis.c
throw bad_alloc();
}

rc = redisGetReply(db->getContext(), (void**)&m_reply);
if (rc != REDIS_OK)
{
throw RedisError("Failed to redisGetReply with " + string(command.c_str()), db->getContext());
}
guard([&]{checkReply();}, command.c_str());
}

RedisReply::RedisReply(DBConnector *db, const string &command)
{
redisAppendCommand(db->getContext(), command.c_str());
redisGetReply(db->getContext(), (void**)&m_reply);
int rc = redisAppendCommand(db->getContext(), command.c_str());
if (rc != REDIS_OK)
{
// The only reason of error is REDIS_ERR_OOM (Out of memory)
// ref: https://github.com/redis/hiredis/blob/master/hiredis.c
throw bad_alloc();
}

rc = redisGetReply(db->getContext(), (void**)&m_reply);
if (rc != REDIS_OK)
{
throw RedisError("Failed to redisGetReply with " + command, db->getContext());
}
guard([&]{checkReply();}, command.c_str());
}

Expand Down
24 changes: 24 additions & 0 deletions common/redisreply.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,37 @@
#define __REDISREPLY__

#include <hiredis/hiredis.h>
#include <string>
#include <stdexcept>
#include "rediscommand.h"

namespace swss {

class DBConnector;

class RedisError : public std::runtime_error
{
int m_err;
std::string m_errstr;
mutable std::string m_message;
public:
RedisError(const std::string& arg, redisContext *ctx)
: std::runtime_error(arg)
, m_err(ctx->err)
, m_errstr(ctx->errstr)
{
}

const char *what() const noexcept override
{
if (m_message.empty())
{
m_message = std::string("RedisResponseError: ") + std::runtime_error::what() + ", err=" + std::to_string(m_err) + ": errstr=" + m_errstr;
}
return m_message.c_str();
}
};

class RedisReply
{
public:
Expand Down

0 comments on commit 5776ef5

Please sign in to comment.