int Ardb::BRPopLPush(Context& ctx, RedisCommandFrame& cmd) { uint32 timeout; if (!string_touint32(cmd.GetArguments()[cmd.GetArguments().size() - 1], timeout)) { fill_error_reply(ctx.reply, "timeout is not an integer or out of range"); return 0; } RPopLPush(ctx, cmd); if (ctx.reply.type == REDIS_REPLY_NIL) { //block; AddBlockKey(ctx, cmd.GetArguments()[0]); if (NULL != ctx.client) { ctx.client->DetachFD(); if (timeout > 0) { ctx.block->blocking_timer_task_id = ctx.client->GetService().GetTimer().ScheduleHeapTask( new BlockConnectionTimeout(&ctx), timeout, -1, SECONDS); } } ctx.reply.type = 0; } return 0; }
int Ardb::Keys(Context& ctx, RedisCommandFrame& cmd) { KeysOptions opt; opt.op = OP_GET; opt.pattern = cmd.GetArguments()[0]; uint32 limit = 100000; //return max 100000 keys one time if (cmd.GetArguments().size() > 1) { for (uint32 i = 1; i < cmd.GetArguments().size(); i++) { if (!strcasecmp(cmd.GetArguments()[i].c_str(), "limit")) { if (i + 1 >= cmd.GetArguments().size() || !string_touint32(cmd.GetArguments()[i + 1], limit)) { fill_error_reply(ctx.reply, "value is not an integer or out of range"); return 0; } i++; } else { fill_error_reply(ctx.reply, "Syntax error, try KEYS "); return 0; } } } opt.limit = limit; KeysOperation(ctx, opt); return 0; }
int Ardb::BRPop(Context& ctx, RedisCommandFrame& cmd) { uint32 timeout; if (!string_touint32(cmd.GetArguments()[cmd.GetArguments().size() - 1], timeout)) { fill_error_reply(ctx.reply, "timeout is not an integer or out of range"); return 0; } for (uint32 i = 0; i < cmd.GetArguments().size() - 1; i++) { if (ListPop(ctx, cmd.GetArguments()[i], false) == 0 && ctx.reply.type == REDIS_REPLY_STRING) { RedisReply& r1 = ctx.reply.AddMember(); RedisReply& r2 = ctx.reply.AddMember(); fill_str_reply(r1, cmd.GetArguments()[i]); fill_str_reply(r2, ctx.reply.str); return 0; } } for (uint32 i = 0; i < cmd.GetArguments().size() - 1; i++) { AddBlockKey(ctx, cmd.GetArguments()[i]); } if (NULL != ctx.client) { ctx.client->DetachFD(); if (timeout > 0) { ctx.block->blocking_timer_task_id = ctx.client->GetService().GetTimer().ScheduleHeapTask( new BlockConnectionTimeout(&ctx), timeout, -1, SECONDS); } } return 0; }
void Slave::HandleRedisCommand(Channel* ch, RedisCommandFrame& cmd) { int flag = ARDB_PROCESS_REPL_WRITE; if (m_slave_state == SLAVE_STATE_SYNCED || m_slave_state == SLAVE_STATE_LOADING_DUMP_DATA) { flag |= ARDB_PROCESS_FORCE_REPLICATION; } else { flag |= ARDB_PROCESS_WITHOUT_REPLICATION; } DEBUG_LOG("Recv master cmd %s at %lld at flag:%d at state:%d", cmd.ToString().c_str(), m_backlog.GetReplEndOffset(), flag, m_slave_state); if (m_slave_state == SLAVE_STATE_WAITING_PSYNC_REPLY && m_server_type == ARDB_DB_SERVER_TYPE) { if (!strcasecmp(cmd.GetCommand().c_str(), "FULLSYNCED")) { uint64 offset, cksm; string_touint64(cmd.GetArguments()[0], offset); string_touint64(cmd.GetArguments()[1], cksm); m_backlog.SetChecksum(cksm); ASSERT(offset == m_backlog.GetReplEndOffset()); //m_backlog.SetReplOffset(offset); m_slave_state = SLAVE_STATE_SYNCED; //Disconnect all slaves when all data resynced m_serv->m_master_serv.DisconnectAllSlaves(); return; } } if (!strcasecmp(cmd.GetCommand().c_str(), "PING")) { m_ping_recved_time = time(NULL); } else if (!strcasecmp(cmd.GetCommand().c_str(), "SELECT")) { DBID id = 0; string_touint32(cmd.GetArguments()[0], id); m_backlog.SetCurrentDBID(id); } GetArdbConnContext(); m_actx->is_slave_conn = true; m_actx->conn = ch; if (strcasecmp(cmd.GetCommand().c_str(), "SELECT") && strcasecmp(cmd.GetCommand().c_str(), "__SET__") && strcasecmp(cmd.GetCommand().c_str(), "__DEL__")) { if (!m_include_dbs.empty() && m_include_dbs.count(m_actx->currentDB) == 0) { flag |= ARDB_PROCESS_FEED_REPLICATION_ONLY; } if (!m_exclude_dbs.empty() && m_exclude_dbs.count(m_actx->currentDB) > 0) { flag |= ARDB_PROCESS_FEED_REPLICATION_ONLY; } } m_serv->ProcessRedisCommand(*m_actx, cmd, flag); }
int ArdbServer::Select(ArdbConnContext& ctx, RedisCommandFrame& cmd) { if (!string_touint32(cmd.GetArguments()[0], ctx.currentDB) || ctx.currentDB > 0xFFFFFF) { fill_error_reply(ctx.reply, "value is not an integer or out of range"); return 0; } m_clients_holder.ChangeCurrentDB(ctx.conn, ctx.currentDB); fill_status_reply(ctx.reply, "OK"); return 0; }
int ArdbServer::PSetEX(ArdbConnContext& ctx, RedisCommandFrame& cmd) { uint32 mills; if (!string_touint32(cmd.GetArguments()[1], mills)) { fill_error_reply(ctx.reply, "value is not an integer or out of range"); return 0; } m_db->PSetEx(ctx.currentDB, cmd.GetArguments()[0], cmd.GetArguments()[2], mills); fill_status_reply(ctx.reply, "OK"); return 0; }
int Comms::BLPop(Context& ctx, RedisCommandFrame& cmd) { uint32 timeout; if (!string_touint32(cmd.GetArguments()[cmd.GetArguments().size() - 1], timeout)) { fill_error_reply(ctx.reply, "timeout is not an integer or out of range"); return 0; } bool lpop = cmd.GetType() == REDIS_CMD_BLPOP; for (uint32 i = 0; i < cmd.GetArguments().size() - 1; i++) { std::string v; int err = lpop ? m_kv_store->LPop(ctx.currentDB, cmd.GetArguments()[i], v) : m_kv_store->RPop(ctx.currentDB, cmd.GetArguments()[i], v); if (0 == err && !v.empty()) { RedisReply& r1 = ctx.reply.AddMember(); RedisReply& r2 = ctx.reply.AddMember(); fill_str_reply(r1, cmd.GetArguments()[i]); fill_str_reply(r2, v); FireKeyChangedEvent(ctx, ctx.currentDB, cmd.GetArguments()[i]); RedisCommandFrame list_pop(lpop ? "lpop" : "rpop"); list_pop.AddArg(cmd.GetArguments()[i]); RewriteClientCommand(ctx, list_pop); return 0; } if (err != 0 && err != mmkv::ERR_ENTRY_NOT_EXIST && err != mmkv::ERR_DB_NOT_EXIST) { FillErrorReply(ctx, err); return 0; } } if (NULL != ctx.client) { ctx.client->DetachFD(); ctx.GetBlockContext().lpop = cmd.GetType() == REDIS_CMD_BLPOP; if (timeout > 0) { ctx.block->blocking_timer_task_id = ctx.client->GetService().GetTimer().ScheduleHeapTask( new BlockListTimeout(&ctx), timeout, -1, SECONDS); } } for (uint32 i = 0; i < cmd.GetArguments().size() - 1; i++) { AddBlockKey(ctx, cmd.GetArguments()[i]); } return 0; }
void Master::AddSlave(Channel* slave, RedisCommandFrame& cmd) { DEBUG_LOG("Recv sync command:%s", cmd.ToString().c_str()); slave->Flush(); SlaveConnection* conn = NULL; NEW(conn, SlaveConnection); conn->conn = slave; if (!strcasecmp(cmd.GetCommand().c_str(), "sync")) { //Redis 2.6/2.4 send 'sync' conn->isRedisSlave = true; conn->sync_offset = -1; } else { conn->server_key = cmd.GetArguments()[0]; const std::string& offset_str = cmd.GetArguments()[1]; if (!string_toint64(offset_str, conn->sync_offset)) { ERROR_LOG("Invalid offset argument:%s", offset_str.c_str()); slave->Close(); DELETE(conn); return; } //Redis 2.8+ send psync, Ardb send psync2 if (!strcasecmp(cmd.GetCommand().c_str(), "psync")) { conn->isRedisSlave = true; } else { conn->isRedisSlave = false; if (cmd.GetArguments().size() >= 3) { std::vector<std::string> ss = split_string(cmd.GetArguments()[2], "|"); for (uint32 i = 0; i < ss.size(); i++) { DBID id; if (string_touint32(ss[i], id)) { conn->syncdbs.insert(id); } } } } } m_server->m_service->DetachChannel(slave, true); ReplicationInstruction inst(conn, REPL_INSTRUCTION_ADD_SLAVE); OfferReplInstruction(inst); }
int split_uint32_array(const std::string& str, const std::string& sep, std::vector<uint32>& array) { if (str.empty()) { return 0; } std::vector<std::string> ss = split_string(str, sep); for (uint32 i = 0; i < ss.size(); i++) { uint32 id; if (!string_touint32(ss[i], id)) { return -1; } else { array.push_back(id); } } return 0; }
void Master::WriteSlaves(const DBID& dbid, RedisCommandFrame& cmd) { //DEBUG_LOG("WriteSlaves cmd:%s %u", cmd.ToString().c_str(), cmd.GetType()); switch (cmd.GetType()) { case REDIS_CMD_SELECT: { DBID id = 0; string_touint32(cmd.GetArguments()[0], id); m_backlog.SetCurrentDBID(id); break; } case REDIS_CMD_PING: { break; } default: { if (m_backlog.GetCurrentDBID() != dbid) { if (!m_server->m_cfg.master_host.empty()) { ERROR_LOG("Can NOT happen since slave instance can NOT generate select command."); } else { RedisCommandFrame select("select %u", dbid); select.SetType(REDIS_CMD_SELECT); m_backlog.SetCurrentDBID(dbid); WriteCmdToSlaves(select); } } break; } } WriteCmdToSlaves(cmd); }
int Comms::Move(Context& ctx, RedisCommandFrame& cmd) { DBID dst = 0; if (!string_touint32(cmd.GetArguments()[1], dst)) { fill_error_reply(ctx.reply, "value is not an integer or out of range"); return 0; } int err = m_kv_store->Move(ctx.currentDB, cmd.GetArguments()[0], dst); if (err >= 0) { if (err > 0) { FireKeyChangedEvent(ctx, cmd.GetArguments()[0]); FireKeyChangedEvent(ctx, dst, cmd.GetArguments()[0]); } fill_int_reply(ctx.reply, err); } else { FillErrorReply(ctx, err); } return 0; }
int Ardb::Scan(Context& ctx, RedisCommandFrame& cmd) { StringArray keys; std::string pattern; uint32 limit = 10000; //return max 10000 keys one time if (cmd.GetArguments().size() > 1) { for (uint32 i = 1; i < cmd.GetArguments().size(); i++) { if (!strcasecmp(cmd.GetArguments()[i].c_str(), "count")) { if (i + 1 >= cmd.GetArguments().size() || !string_touint32(cmd.GetArguments()[i + 1], limit)) { fill_error_reply(ctx.reply, "value is not an integer or out of range"); return 0; } i++; } else if (!strcasecmp(cmd.GetArguments()[i].c_str(), "match")) { if (i + 1 >= cmd.GetArguments().size()) { fill_error_reply(ctx.reply, "'MATCH' need one args followed"); return 0; } pattern = cmd.GetArguments()[i + 1]; i++; } else { fill_error_reply(ctx.reply, "Syntax error, try scan 0 "); return 0; } } } RedisReply& r1 = ctx.reply.AddMember(); RedisReply& r2 = ctx.reply.AddMember(); r2.type = REDIS_REPLY_ARRAY; KeyObject from; from.db = ctx.currentDB; from.type = KEY_META; const std::string& cursor = cmd.GetArguments()[0]; std::string scan_start_cursor; if (cmd.GetArguments()[0] != "0") { if (m_cfg.scan_redis_compatible) { FindElementByRedisCursor(cursor, scan_start_cursor); } from.key = scan_start_cursor; } Iterator* iter = IteratorKeyValue(from, false); bool reachend = false; std::string tmpkey; while (NULL != iter && iter->Valid()) { KeyObject kk; if (!decode_key(iter->Key(), kk) || kk.db != ctx.currentDB || kk.type != KEY_META) { reachend = true; break; } tmpkey.clear(); tmpkey.assign(kk.key.data(), kk.key.size()); if (r2.MemberSize() >= limit) { break; } if ((pattern.empty() || stringmatchlen(pattern.c_str(), pattern.size(), tmpkey.c_str(), tmpkey.size(), 0) == 1)) { RedisReply& rr1 = r2.AddMember(); fill_str_reply(rr1, tmpkey); } iter->Next(); } if (reachend || !iter->Valid()) { fill_str_reply(r1, "0"); } else { if (m_cfg.scan_redis_compatible) { uint64 newcursor = GetNewRedisCursor(tmpkey); fill_str_reply(r1, stringfromll(newcursor)); } else { fill_str_reply(r1, tmpkey); } } DELETE(iter); return 0; }
int Ardb::Move(Context& ctx, RedisCommandFrame& cmd) { DBID dst = 0; if (!string_touint32(cmd.GetArguments()[1], dst)) { fill_error_reply(ctx.reply, "value is not an integer or out of range"); return 0; } RedisCommandFrame exists("Exists"); exists.AddArg(cmd.GetArguments()[0]); Context tmpctx; tmpctx.currentDB = dst; Exists(tmpctx, exists); if (ctx.reply.integer == 1) { fill_int_reply(ctx.reply, 0); return 0; } KeyType type = KEY_END; GetType(ctx, cmd.GetArguments()[0], type); switch (type) { case SET_META: { RenameSet(ctx, ctx.currentDB, cmd.GetArguments()[0], dst, cmd.GetArguments()[0]); break; } case LIST_META: { RenameList(ctx, ctx.currentDB, cmd.GetArguments()[0], dst, cmd.GetArguments()[0]); break; } case ZSET_META: { RenameZSet(ctx, ctx.currentDB, cmd.GetArguments()[0], dst, cmd.GetArguments()[0]); break; } case HASH_META: { RenameHash(ctx, ctx.currentDB, cmd.GetArguments()[0], dst, cmd.GetArguments()[0]); break; } case STRING_META: { RenameString(ctx, ctx.currentDB, cmd.GetArguments()[0], dst, cmd.GetArguments()[0]); break; } case BITSET_META: { RenameBitset(ctx, ctx.currentDB, cmd.GetArguments()[0], dst, cmd.GetArguments()[0]); break; } default: { fill_error_reply(ctx.reply, "Invalid type to move"); break; } } fill_int_reply(ctx.reply, 1); return 0; }
int Comms::Scan(Context& ctx, RedisCommandFrame& cmd) { StringArray keys; std::string pattern; uint32 limit = 1000; //return max 1000 keys one time int arg_start = 0; if (cmd.GetType() != REDIS_CMD_SCAN) { arg_start = 1; } if (cmd.GetArguments().size() > arg_start + 1) { for (uint32 i = arg_start + 1; i < cmd.GetArguments().size(); i++) { if (!strcasecmp(cmd.GetArguments()[i].c_str(), "count")) { if (i + 1 >= cmd.GetArguments().size() || !string_touint32(cmd.GetArguments()[i + 1], limit)) { fill_error_reply(ctx.reply, "value is not an integer or out of range"); return 0; } i++; } else if (!strcasecmp(cmd.GetArguments()[i].c_str(), "match")) { if (i + 1 >= cmd.GetArguments().size()) { fill_error_reply(ctx.reply, "'MATCH' need one args followed"); return 0; } pattern = cmd.GetArguments()[i + 1]; i++; } else { fill_error_reply(ctx.reply, "Syntax error, try scan 0 "); return 0; } } } uint32 scan_count_limit = limit * 10; uint32 scan_count = 0; uint32 scan_cursor = 0; if (!string_touint32(cmd.GetArguments()[arg_start], scan_cursor)) { fill_error_reply(ctx.reply, "value is not an integer or out of range"); return 0; } RedisReply& r1 = ctx.reply.AddMember(); RedisReply& r2 = ctx.reply.AddMember(); r2.type = REDIS_REPLY_ARRAY; mmkv::StringArrayResult results(ReplyResultStringAlloc, &r2); int new_cursor = 0; switch (cmd.GetType()) { case REDIS_CMD_SCAN: { new_cursor = m_kv_store->Scan(ctx.currentDB, scan_cursor, pattern, scan_count_limit, results); break; } case REDIS_CMD_SSCAN: { new_cursor = m_kv_store->SScan(ctx.currentDB, cmd.GetArguments()[0], scan_cursor, pattern, scan_count_limit, results); break; } case REDIS_CMD_HSCAN: { new_cursor = m_kv_store->HScan(ctx.currentDB, cmd.GetArguments()[0], scan_cursor, pattern, scan_count_limit, results); break; } case REDIS_CMD_ZSCAN: { new_cursor = m_kv_store->ZScan(ctx.currentDB, cmd.GetArguments()[0], scan_cursor, pattern, scan_count_limit, results); break; } default: { new_cursor = 0; break; } } fill_int_reply(r1, new_cursor); return 0; }
bool ArdbConfig::Parse(const Properties& props) { conf_props = props; conf_get_string(props, "home", home); if (home.empty()) { home = "../ardb"; } make_dir(home); int err = real_path(home, home); if (0 != err) { ERROR_LOG("Invalid 'home' config:%s for reason:%s", home.c_str(), strerror(err)); return false; } err = access(home.c_str(), R_OK | W_OK); if (0 != err) { err = errno; ERROR_LOG("Invalid 'home' config:%s for reason:%s", home.c_str(), strerror(err)); return false; } setenv("ARDB_HOME", home.c_str(), 1); replace_env_var(const_cast<Properties&>(props)); conf_get_string(props, "pidfile", pidfile); conf_get_int64(props, "thread-pool-size", thread_pool_size); if (thread_pool_size <= 0) { thread_pool_size = available_processors(); } conf_get_int64(props, "hz", hz); if (hz < CONFIG_MIN_HZ) hz = CONFIG_MIN_HZ; if (hz > CONFIG_MAX_HZ) hz = CONFIG_MAX_HZ; conf_get_int64(props, "tcp-keepalive", tcp_keepalive); conf_get_int64(props, "timeout", timeout); //conf_get_int64(props, "unixsocketperm", unixsocketperm); conf_get_int64(props, "slowlog-log-slower-than", slowlog_log_slower_than); conf_get_int64(props, "slowlog-max-len", slowlog_max_len); conf_get_int64(props, "maxclients", max_clients); if(max_clients <= 0) { max_clients = 10000; } for (int i = 0;; i++) { char config_key[256]; sprintf(config_key, "server[%d].listen", i); ListenPoint lp; std::string address; if (!conf_get_string(props, config_key, address)) { break; } if (address.find(":") == std::string::npos) { lp.host = address; } else { std::vector<std::string> ss = split_string(address, ":"); uint32 port; if (ss.size() < 2 || !string_touint32(ss[ss.size() - 1], port) || port > 65535) { ERROR_LOG("Invalid listen address %s", address.c_str()); return false; } lp.host = address.substr(0, address.size() - ss[ss.size() - 1].size() - 1); lp.port = port; } sprintf(config_key, "server[%d].qps-limit", i); conf_get_int64(props, config_key, lp.qps_limit); sprintf(config_key, "server[%d].unixsocketperm", i); conf_get_int64(props, config_key, lp.qps_limit); servers.push_back(lp); } if (servers.empty()) { ListenPoint lp; lp.host = "0.0.0.0"; lp.port = 16379; servers.push_back(lp); } if (strcasecmp(engine.c_str(), "rocksdb") == 0) { conf_get_string(props, "rocksdb.compaction", rocksdb_compaction); conf_get_bool(props, "rocksdb.disableWAL", rocksdb_disablewal); conf_get_bool(props, "rocksdb.scan-total-order", rocksdb_scan_total_order); } conf_get_string(props, "engine", engine); conf_get_string(props, "data-dir", data_base_path); conf_get_string(props, "backup-dir", backup_dir); conf_get_string(props, "repl-dir", repl_data_dir); make_dir(repl_data_dir); make_dir(backup_dir); err = real_path(repl_data_dir, repl_data_dir); if (0 != err) { ERROR_LOG("Invalid 'repl-dir' config:%s for reason:%s", repl_data_dir.c_str(), strerror(err)); return false; } std::string backup_file_format; conf_get_string(props, "backup-file-format", backup_file_format); if (!strcasecmp(backup_file_format.c_str(), "redis")) { backup_redis_format = true; } conf_get_string(props, "zookeeper-servers", zookeeper_servers); conf_get_string(props, "zk-clientid-file", zk_clientid_file); conf_get_string(props, "loglevel", loglevel); conf_get_string(props, "logfile", logfile); conf_get_bool(props, "daemonize", daemonize); conf_get_int64(props, "repl-backlog-size", repl_backlog_size); conf_get_int64(props, "repl-backlog-cache-size", repl_backlog_cache_size); conf_get_int64(props, "repl-ping-slave-period", repl_ping_slave_period); conf_get_int64(props, "repl-timeout", repl_timeout); conf_get_int64(props, "repl-backlog-sync-period", repl_backlog_sync_period); conf_get_int64(props, "repl-backlog-ttl", repl_backlog_time_limit); conf_get_int64(props, "min-slaves-to-write", repl_min_slaves_to_write); conf_get_int64(props, "min-slaves-max-lag", repl_min_slaves_max_lag); conf_get_bool(props, "slave-serve-stale-data", repl_serve_stale_data); conf_get_int64(props, "max-slave-worker-queue", max_slave_worker_queue); if(max_slave_worker_queue <= 0) { max_slave_worker_queue = 1024; } conf_get_bool(props, "repl-disable-tcp-nodelay", repl_disable_tcp_nodelay); conf_get_int64(props, "lua-time-limit", lua_time_limit); conf_get_int64(props, "snapshot-max-lag-offset", snapshot_max_lag_offset); conf_get_int64(props, "maxsnapshots", maxsnapshots); if(maxsnapshots == 0) { maxsnapshots = 1; } if (snapshot_max_lag_offset > repl_backlog_size / 2) { snapshot_max_lag_offset = repl_backlog_size / 2; } conf_get_int64(props, "hll-sparse-max-bytes", hll_sparse_max_bytes); conf_get_bool(props, "slave-read-only", slave_readonly); conf_get_bool(props, "slave-serve-stale-data", slave_serve_stale_data); conf_get_int64(props, "slave-priority", slave_priority); conf_get_bool(props, "slave-ignore-expire", slave_ignore_expire); conf_get_bool(props, "slave-ignore-del", slave_ignore_del); conf_get_bool(props, "slave-cleardb-before-fullresync", slave_cleardb_before_fullresync); conf_get_int64(props, "statistics-log-period", statistics_log_period); if (statistics_log_period <= 0) { statistics_log_period = DEFAULT_STAT_LOG_PERIOD_SECS; } std::string slaveof; if (conf_get_string(props, "slaveof", slaveof)) { std::vector<std::string> ss = split_string(slaveof, ":"); if (ss.size() == 2) { master_host = ss[0]; if (!string_touint32(ss[1], master_port)) { master_host = ""; WARN_LOG("Invalid 'slaveof' config."); } } else { WARN_LOG("Invalid 'slaveof' config."); } } conf_get_string(props, "masterauth", masterauth); if (data_base_path.empty()) { data_base_path = "."; } make_dir(data_base_path); err = real_path(data_base_path, data_base_path); if (0 != err) { ERROR_LOG("Invalid 'data-dir' config:%s for reason:%s", data_base_path.c_str(), strerror(err)); return false; } conf_get_string(props, "requirepass", requirepass); Properties::const_iterator fit = props.find("rename-command"); if (fit != props.end()) { rename_commands.clear(); const ConfItemsArray& cs = fit->second; ConfItemsArray::const_iterator cit = cs.begin(); while (cit != cs.end()) { if (cit->size() != 2) { ERROR_LOG("Invalid 'rename-command' config with %u args.", cit->size()); } else { rename_commands[cit->at(0)] = cit->at(1); } cit++; } } conf_get_int64(props, "reply-pool-size", reply_pool_size); conf_get_int64(props, "slave-client-output-buffer-limit", slave_client_output_buffer_limit); conf_get_int64(props, "pubsub-client-output-buffer-limit", pubsub_client_output_buffer_limit); conf_get_string(props, "redis-compatible-version", redis_compatible_version); conf_get_bool(props, "redis-compatible-mode", redis_compatible); conf_get_bool(props, "compact-after-snapshot-load", compact_after_snapshot_load); conf_get_int64(props, "qps-limit-per-host", qps_limit_per_host); conf_get_int64(props, "qps-limit-per-connection", qps_limit_per_connection); conf_get_int64(props, "range-delete-min-size", range_delete_min_size); conf_get_int64(props, "stream-lru-cache-size", stream_lru_cache_size); //trusted_ip.clear(); Properties::const_iterator ip_it = props.find("trusted-ip"); if (ip_it != props.end()) { const ConfItemsArray& cs = ip_it->second; for (uint32 i = 0; i < cs.size(); i++) { //trusted_ip.insert(cs[i][0]); } } if (!verify_config(*this)) { return false; } ArdbLogger::SetLogLevel(loglevel); return true; }
bool ArdbConfig::Parse(const Properties& props) { conf_props = props; conf_get_string(props, "home", home); if (home.empty()) { home = "../ardb"; } make_dir(home); int err = real_path(home, home); if (0 != err) { ERROR_LOG("Invalid 'home' config:%s for reason:%s", home.c_str(), strerror(err)); return false; } err = access(home.c_str(), R_OK | W_OK); if (0 != err) { err = errno; ERROR_LOG("Invalid 'home' config:%s for reason:%s", home.c_str(), strerror(err)); return false; } setenv("ARDB_HOME", home.c_str(), 1); replace_env_var(const_cast<Properties&>(props)); conf_get_string(props, "pidfile", pidfile); conf_get_int64(props, "tcp-keepalive", tcp_keepalive); conf_get_int64(props, "timeout", timeout); conf_get_int64(props, "unixsocketperm", unixsocketperm); conf_get_int64(props, "slowlog-log-slower-than", slowlog_log_slower_than); conf_get_int64(props, "slowlog-max-len", slowlog_max_len); conf_get_int64(props, "maxclients", max_clients); Properties::const_iterator listen_it = props.find("listen"); if (listen_it != props.end()) { const ConfItemsArray& cs = listen_it->second; for (uint32 i = 0; i < cs.size(); i++) { if (cs[i].size() != 1) { WARN_LOG("Invalid config 'listen'"); } else { const std::string& str = cs[i][0]; listen_addresses.push_back(str); } } } if (listen_addresses.empty()) { listen_addresses.push_back("0.0.0.0:16379"); } Properties::const_iterator tp_it = props.find("thread-pool-size"); if (tp_it != props.end()) { const ConfItemsArray& cs = tp_it->second; for (uint32 i = 0; i < cs.size(); i++) { uint32 size = 0; if (cs[i].size() != 1 || !string_touint32(cs[i][0], size)) { WARN_LOG("Invalid config 'thread-pool-size'"); } else { thread_pool_sizes.push_back((int64) size); } } } Properties::const_iterator qp_it = props.find("qps-limit"); if (qp_it != props.end()) { const ConfItemsArray& cs = qp_it->second; for (uint32 i = 0; i < cs.size(); i++) { uint32 limit = 0; if (cs[i].size() != 1 || !string_touint32(cs[i][0], limit)) { WARN_LOG("Invalid config 'qps-limit'"); } else { qps_limits.push_back((int64) limit); } } } thread_pool_sizes.resize(listen_addresses.size()); qps_limits.resize(listen_addresses.size()); conf_get_string(props, "data-dir", data_base_path); conf_get_string(props, "backup-dir", backup_dir); conf_get_string(props, "repl-dir", repl_data_dir); make_dir(repl_data_dir); make_dir(backup_dir); err = real_path(repl_data_dir, repl_data_dir); if (0 != err) { ERROR_LOG("Invalid 'repl-dir' config:%s for reason:%s", repl_data_dir.c_str(), strerror(err)); return false; } std::string backup_file_format; conf_get_string(props, "backup-file-format", backup_file_format); if (!strcasecmp(backup_file_format.c_str(), "redis")) { backup_redis_format = true; } conf_get_string(props, "zookeeper-servers", zookeeper_servers); conf_get_string(props, "loglevel", loglevel); conf_get_string(props, "logfile", logfile); conf_get_bool(props, "daemonize", daemonize); conf_get_int64(props, "repl-backlog-size", repl_backlog_size); conf_get_int64(props, "repl-ping-slave-period", repl_ping_slave_period); conf_get_int64(props, "repl-timeout", repl_timeout); conf_get_int64(props, "repl-state-persist-period", repl_state_persist_period); conf_get_int64(props, "repl-backlog-ttl", repl_backlog_time_limit); conf_get_bool(props, "repl-disable-tcp-nodelay", repl_disable_tcp_nodelay); conf_get_int64(props, "lua-time-limit", lua_time_limit); conf_get_int64(props, "hash-max-ziplist-entries", hash_max_ziplist_entries); conf_get_int64(props, "hash_max-ziplist-value", hash_max_ziplist_value); conf_get_int64(props, "set-max-ziplist-entries", set_max_ziplist_entries); conf_get_int64(props, "set-max-ziplist-value", set_max_ziplist_value); conf_get_int64(props, "list-max-ziplist-entries", list_max_ziplist_entries); conf_get_int64(props, "list-max-ziplist-value", list_max_ziplist_value); conf_get_int64(props, "zset-max-ziplist-entries", zset_max_ziplist_entries); conf_get_int64(props, "zset_max_ziplist_value", zset_max_ziplist_value); conf_get_int64(props, "L1-zset-max-cache-size", L1_zset_max_cache_size); conf_get_int64(props, "L1-set-max-cache-size", L1_set_max_cache_size); conf_get_int64(props, "L1-hash-max-cache-size", L1_hash_max_cache_size); conf_get_int64(props, "L1-list-max-cache-size", L1_list_max_cache_size); conf_get_int64(props, "L1-string-max-cache-size", L1_string_max_cache_size); conf_get_bool(props, "L1-zset-read-fill-cache", L1_zset_read_fill_cache); conf_get_bool(props, "L1-zset-seek-load-cache", L1_zset_seek_load_cache); conf_get_bool(props, "L1-set-read-fill-cache", L1_set_read_fill_cache); conf_get_bool(props, "L1-set-seek-load-cache", L1_set_seek_load_cache); conf_get_bool(props, "L1-hash-read-fill-cache", L1_hash_read_fill_cache); conf_get_bool(props, "L1-hash-seek-load-cache", L1_hash_seek_load_cache); conf_get_bool(props, "L1-list-read-fill-cache", L1_list_read_fill_cache); conf_get_bool(props, "L1-list-seek-load-cache", L1_list_seek_load_cache); conf_get_bool(props, "L1-string-read-fill-cache", L1_string_read_fill_cache); conf_get_int64(props, "hll-sparse-max-bytes", hll_sparse_max_bytes); conf_get_bool(props, "slave-read-only", slave_readonly); conf_get_bool(props, "slave-serve-stale-data", slave_serve_stale_data); conf_get_int64(props, "slave-priority", slave_priority); conf_get_bool(props, "slave-ignore-expire", slave_ignore_expire); conf_get_bool(props, "slave-ignore-del", slave_ignore_del); std::string slaveof; if (conf_get_string(props, "slaveof", slaveof)) { std::vector<std::string> ss = split_string(slaveof, ":"); if (ss.size() == 2) { master_host = ss[0]; if (!string_touint32(ss[1], master_port)) { master_host = ""; WARN_LOG("Invalid 'slaveof' config."); } } else { WARN_LOG("Invalid 'slaveof' config."); } } std::string include_dbs, exclude_dbs; repl_includes.clear(); repl_excludes.clear(); conf_get_string(props, "replicate-include-db", include_dbs); conf_get_string(props, "replicate-exclude-db", exclude_dbs); if (0 != split_uint32_array(include_dbs, "|", repl_includes)) { ERROR_LOG("Invalid 'replicate-include-db' config."); repl_includes.clear(); } if (0 != split_uint32_array(exclude_dbs, "|", repl_excludes)) { ERROR_LOG("Invalid 'replicate-exclude-db' config."); repl_excludes.clear(); } if (data_base_path.empty()) { data_base_path = "."; } make_dir(data_base_path); err = real_path(data_base_path, data_base_path); if (0 != err) { ERROR_LOG("Invalid 'data-dir' config:%s for reason:%s", data_base_path.c_str(), strerror(err)); return false; } conf_get_string(props, "additional-misc-info", additional_misc_info); conf_get_string(props, "requirepass", requirepass); Properties::const_iterator fit = props.find("rename-command"); if (fit != props.end()) { rename_commands.clear(); StringSet newcmdset; const ConfItemsArray& cs = fit->second; ConfItemsArray::const_iterator cit = cs.begin(); while (cit != cs.end()) { if (cit->size() != 2 || newcmdset.count(cit->at(1)) > 0) { ERROR_LOG("Invalid 'rename-command' config."); } else { rename_commands[cit->at(0)] = cit->at(1); newcmdset.insert(cit->at(1)); } cit++; } } conf_get_int64(props, "compact-min-interval", compact_min_interval); conf_get_int64(props, "compact-max-interval", compact_max_interval); conf_get_int64(props, "compact-after-write", compact_trigger_write_count); conf_get_bool(props, "compact-enable", compact_enable); conf_get_int64(props, "reply-pool-size", reply_pool_size); conf_get_bool(props, "replace-all-for-multi-sadd", replace_for_multi_sadd); conf_get_bool(props, "replace-all-for-hmset", replace_for_hmset); conf_get_int64(props, "slave-client-output-buffer-limit", slave_client_output_buffer_limit); conf_get_int64(props, "pubsub-client-output-buffer-limit", pubsub_client_output_buffer_limit); conf_get_bool(props, "scan-redis-compatible", scan_redis_compatible); conf_get_int64(props, "scan-cursor-expire-after", scan_cursor_expire_after); conf_get_int64(props, "max-string-bitset-value", max_string_bitset_value); conf_get_int64(props, "databases", maxdb); conf_get_bool(props, "lua-exec-atomic", lua_exec_atomic); trusted_ip.clear(); Properties::const_iterator ip_it = props.find("trusted-ip"); if (ip_it != props.end()) { const ConfItemsArray& cs = ip_it->second; for (uint32 i = 0; i < cs.size(); i++) { trusted_ip.insert(cs[i][0]); } } if (!verify_config(*this)) { return false; } ArdbLogger::SetLogLevel(loglevel); return true; }
int Ardb::HScan(Context& ctx, RedisCommandFrame& cmd) { std::string pattern; uint32 limit = 10000; //return max 10000 keys one time if (cmd.GetArguments().size() > 2) { for (uint32 i = 2; i < cmd.GetArguments().size(); i++) { if (!strcasecmp(cmd.GetArguments()[i].c_str(), "count")) { if (i + 1 >= cmd.GetArguments().size() || !string_touint32(cmd.GetArguments()[i + 1], limit)) { fill_error_reply(ctx.reply, "value is not an integer or out of range"); return 0; } i++; } else if (!strcasecmp(cmd.GetArguments()[i].c_str(), "match")) { if (i + 1 >= cmd.GetArguments().size()) { fill_error_reply(ctx.reply, "'MATCH' need one args followed"); return 0; } pattern = cmd.GetArguments()[i + 1]; i++; } else { fill_error_reply(ctx.reply, "Syntax error, try scan 0 "); return 0; } } } ValueObject meta; int err = GetMetaValue(ctx, cmd.GetArguments()[0], HASH_META, meta); CHECK_ARDB_RETURN_VALUE(ctx.reply, err); RedisReply& r1 = ctx.reply.AddMember(); RedisReply& r2 = ctx.reply.AddMember(); r2.type = REDIS_REPLY_ARRAY; if (0 != err) { fill_str_reply(r1, "0"); return 0; } const std::string& cursor = cmd.GetArguments()[1]; HashIterator iter; HashIter(ctx, meta, cursor == "0" ? "" : cursor, iter, true); while (iter.Valid()) { const Data* field = iter.Field(); std::string tmp; field->GetDecodeString(tmp); if ((pattern.empty() || fnmatch(pattern.c_str(), tmp.c_str(), 0) == 0)) { RedisReply& rr1 = r2.AddMember(); RedisReply& rr2 = r2.AddMember(); fill_str_reply(rr1, tmp); fill_value_reply(rr2, *(iter.Value())); } if (r2.MemberSize() >= (limit * 2)) { break; } iter.Next(); } if (iter.Valid()) { iter.Next(); const Data* next_field = iter.Field(); std::string tmp; fill_str_reply(r1, next_field->GetDecodeString(tmp)); } else { fill_str_reply(r1, "0"); } return 0; }