Skip to content

Commit

Permalink
DBRedis: add HMGET
Browse files Browse the repository at this point in the history
Redis HMGET command allows to query multiple fields in the same request.
Limit to a maximum of DB_REDIS_HMGET_NUMKEYS fields per HMGET request.
  • Loading branch information
Nestorfish authored and sfan5 committed Oct 21, 2016
1 parent 53706e8 commit fabde97
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 0 deletions.
58 changes: 58 additions & 0 deletions db-redis.cpp
Expand Up @@ -5,6 +5,8 @@
#include "types.h"
#include "util.h"

#define DB_REDIS_HMGET_NUMFIELDS 30

static inline int64_t stoi64(const std::string &s)
{
std::stringstream tmp(s);
Expand Down Expand Up @@ -109,6 +111,62 @@ void DBRedis::loadPosCache()
}


void DBRedis::HMGET(const std::vector<BlockPos> &positions, std::vector<ustring> *result)
{
const char *argv[DB_REDIS_HMGET_NUMFIELDS + 2];
argv[0] = "HMGET";
argv[1] = hash.c_str();

std::vector<BlockPos>::const_iterator position = positions.begin();
std::size_t remaining = positions.size();
while (remaining > 0) {
const std::size_t batch_size =
(remaining > DB_REDIS_HMGET_NUMFIELDS) ? DB_REDIS_HMGET_NUMFIELDS : remaining;
redisReply *reply;
{
// storage to preserve std::string::c_str() validity
std::vector<std::string> keys;
keys.reserve(batch_size);
for (std::size_t i = 0; i < batch_size; ++i) {
keys.push_back(i64tos(encodeBlockPos(*position++)));
argv[i+2] = keys.back().c_str();
}
reply = (redisReply*) redisCommandArgv(ctx, batch_size + 2, argv, NULL);
}
if(!reply) {
throw std::runtime_error("HMGET failed");
}
if (reply->type != REDIS_REPLY_ARRAY) {
freeReplyObject(reply);
throw std::runtime_error(std::string("HMGET unexpected reply type ")
+ replyTypeStr(reply->type));
}
if (reply->elements != batch_size) {
freeReplyObject(reply);
throw std::runtime_error("HMGET wrong number of elements");
}
for (std::size_t i = 0; i < batch_size; ++i) {
redisReply *subreply = reply->element[i];
if(!subreply) {
throw std::runtime_error("HMGET failed");
}
if (subreply->type != REDIS_REPLY_STRING) {
freeReplyObject(reply);
throw std::runtime_error(std::string("HMGET wrong subreply type ")
+ replyTypeStr(subreply->type));
}
if (subreply->len == 0) {
freeReplyObject(reply);
throw std::runtime_error("HMGET empty string");
}
result->push_back(ustring((const unsigned char *) subreply->str, subreply->len));
}
freeReplyObject(reply);
remaining -= batch_size;
}
}


void DBRedis::getBlocksOnZ(std::map<int16_t, BlockList> &blocks, int16_t zPos)
{
redisReply *reply;
Expand Down
1 change: 1 addition & 0 deletions db-redis.h
Expand Up @@ -14,6 +14,7 @@ class DBRedis : public DB {
static std::string replyTypeStr(int type);

void loadPosCache();
void HMGET(const std::vector<BlockPos> &positions, std::vector<ustring> *result);

std::vector<BlockPos> posCache;

Expand Down

0 comments on commit fabde97

Please sign in to comment.