I want to put a std::map<std::string, std::string>
into redis server with hiredis. Since the API only allows formatted strings to be passed to redisCommand
, I'm unable to store the map via a single command. I've tried using pipelines, but that is slower than HMSET
and is therefore not applicable to performance restrains I'm in.
Anyone knows of any direct or indirect methods to pass a variant sized map via hiredis?
You are supposed to use the "Argv" flavors of redisCommand:
int redisAppendCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen);
void *redisCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen);
You need to build two arrays (pointers and sizes) before they can be called.
Something like this should work (untested):
void hmset( redisContext *c, const string &key, const map<string,string> &m )
{
vector<const char *> argv;
vector<size_t> argvlen;
static char cmd[] = "HMSET";
argv.push_back( cmd );
argvlen.push_back( sizeof(cmd)-1 );
argv.push_back( key.c_str() );
argvlen.push_back( key.size() );
map<string,string>::const_iterator i;
for ( i=m.begin(); i!=m.end(); ++i )
{
argv.push_back( i->first.c_str() );
argvlen.push_back( i->first.size() );
argv.push_back( i->second.c_str() );
argvlen.push_back( i->second.size() );
}
void *r = redisCommandArgv(c, argv.size(), &(argv[0]), &(argvlen[0]) );
if ( !r )
throw runtime_error( "Redis error" );
freeReplyObject( r );
}
Note that if your map contains a lot of items, it is a wrong idea to push it to Redis in one single command. Past N=100-1000 items, variadic commands should be split (in batches of N items) and pipelined. Keep in mind that Redis is single-threaded. When a huge command is executed, nothing else is executed. Plus, you can hit the limit of the communication buffer.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With