/* * GEOADD key MERCATOR|WGS84 x y value [x y value....] */ int Ardb::GeoAdd(Context& ctx, RedisCommandFrame& cmd) { GeoAddOptions options; std::string err; if (0 != options.Parse(cmd.GetArguments(), err, 1)) { fill_error_reply(ctx.reply, "%s", err.c_str()); return 0; } GeoHashRange lat_range, lon_range; GeoHashHelper::GetCoordRange(options.coord_type, lat_range, lon_range); KeyLockerGuard keylock(m_key_lock, ctx.currentDB, cmd.GetArguments()[0]); ValueObject meta; int ret = GetMetaValue(ctx, cmd.GetArguments()[0], ZSET_META, meta); CHECK_ARDB_RETURN_VALUE(ctx.reply, ret); RedisCommandFrame zadd("zadd"); zadd.AddArg(cmd.GetArguments()[0]); BatchWriteGuard guard(GetKeyValueEngine()); GeoPointArray::iterator git = options.points.begin(); uint32 count = 0; while (git != options.points.end()) { GeoPoint& point = *git; if (point.x < lon_range.min || point.x > lon_range.max || point.y < lat_range.min || point.y > lat_range.max) { guard.MarkFailed(); break; } GeoHashBits hash; geohash_encode(&lat_range, &lon_range, point.y, point.x, 30, &hash); GeoHashFix60Bits score = hash.bits; Data score_value; score_value.SetInt64((int64) score); Data element; element.SetString(point.value, true); count += ZSetAdd(ctx, meta, element, score_value, NULL); std::string tmp; score_value.GetDecodeString(tmp); zadd.AddArg(tmp); element.GetDecodeString(tmp); zadd.AddArg(tmp); git++; } if (guard.Success()) { SetKeyValue(ctx, meta); RewriteClientCommand(ctx, zadd); fill_int_reply(ctx.reply, count); } else { fill_error_reply(ctx.reply, "Invalid arguments"); } return 0; }
int Ardb::HDel(Context& ctx, RedisCommandFrame& cmd) { ValueObject meta; int err = GetMetaValue(ctx, cmd.GetArguments()[0], HASH_META, meta); CHECK_ARDB_RETURN_VALUE(ctx.reply, err); int count = 0; if (err == 0) { BatchWriteGuard guard(GetKeyValueEngine()); for (uint32 i = 1; i < cmd.GetArguments().size(); i++) { Data field(cmd.GetArguments()[i]); Data value; err = HashGet(ctx, meta, field, value); if (err == 0) { if (meta.meta.encoding != COLLECTION_ECODING_ZIPMAP) { KeyObject k; k.db = ctx.currentDB; k.key = cmd.GetArguments()[0]; k.type = HASH_FIELD; k.element = field; DelKeyValue(ctx, k); if (meta.meta.len > 0) { meta.meta.len--; } } else { meta.meta.zipmap.erase(field); } count++; } } if (count > 0) { if (meta.meta.Length() != 0) { SetKeyValue(ctx, meta); } else { DelKeyValue(ctx, meta.key); } } } fill_int_reply(ctx.reply, count); return 0; }
int Ardb::LPush(Context& ctx, RedisCommandFrame& cmd) { ValueObject meta; int err = GetMetaValue(ctx, cmd.GetArguments()[0], LIST_META, meta); CHECK_ARDB_RETURN_VALUE(ctx.reply, err); KeyLockerGuard lock(m_key_lock, ctx.currentDB, cmd.GetArguments()[0]); BatchWriteGuard guard(GetKeyValueEngine(), cmd.GetArguments().size() > 2); for (uint32 i = 1; i < cmd.GetArguments().size(); i++) { ListInsert(ctx, meta, NULL, cmd.GetArguments()[i], true, false); } SetKeyValue(ctx, meta); return 0; }
int Ardb::Del(Context& ctx, RedisCommandFrame& cmd) { if (ctx.IsSlave() && m_cfg.slave_ignore_del) { return 0; } BatchWriteGuard guard(GetKeyValueEngine()); int count = 0; for (uint32 i = 0; i < cmd.GetArguments().size(); i++) { count += DeleteKey(ctx, cmd.GetArguments()[i]); } fill_int_reply(ctx.reply, count); return 0; }
int Ardb::HClear(Context& ctx, ValueObject& meta) { BatchWriteGuard guard(GetKeyValueEngine(), meta.meta.encoding != COLLECTION_ECODING_ZIPMAP); if (meta.meta.encoding != COLLECTION_ECODING_ZIPMAP) { HashIterator iter; HashIter(ctx, meta, "", iter, false); while (iter.Valid()) { DelRaw(ctx, iter.CurrentRawKey()); iter.Next(); } } DelKeyValue(ctx, meta.key); return 0; }
int Ardb::ListInsert(Context& ctx, const std::string& key, const std::string* match, const std::string& value, bool head, bool abort_nonexist) { ValueObject meta; int err = GetMetaValue(ctx, key, LIST_META, meta); CHECK_ARDB_RETURN_VALUE(ctx.reply, err); BatchWriteGuard guard(GetKeyValueEngine(), meta.meta.Encoding() != COLLECTION_ENCODING_ZIPLIST); if (0 != err && abort_nonexist) { fill_int_reply(ctx.reply, 0); return 0; } ListInsert(ctx, meta, match, value, head, abort_nonexist); SetKeyValue(ctx, meta); return 0; }
int Ardb::RenameList(Context& ctx, DBID srcdb, const std::string& srckey, DBID dstdb, const std::string& dstkey) { Context tmpctx; tmpctx.currentDB = srcdb; ValueObject v; int err = GetMetaValue(tmpctx, srckey, LIST_META, v); CHECK_ARDB_RETURN_VALUE(ctx.reply, err); if (0 != err) { fill_error_reply(ctx.reply, "no such key or some error"); return 0; } if (v.meta.Encoding() == COLLECTION_ENCODING_ZIPLIST) { DelKeyValue(tmpctx, v.key); v.key.encode_buf.Clear(); v.key.db = dstdb; v.key.key = dstkey; v.meta.expireat = 0; SetKeyValue(ctx, v); } else { ListIterator iter; ListIter(ctx, v, iter, false); tmpctx.currentDB = dstdb; ValueObject dstmeta; dstmeta.key.type = KEY_META; dstmeta.key.key = dstkey; dstmeta.type = LIST_META; dstmeta.meta.SetFlag(COLLECTION_FLAG_SEQLIST); dstmeta.meta.SetEncoding(COLLECTION_ENCODING_ZIPLIST); BatchWriteGuard guard(GetKeyValueEngine()); while (iter.Valid()) { std::string tmpstr; ListInsert(tmpctx, dstmeta, NULL, iter.Element()->GetDecodeString(tmpstr), false, false); iter.Next(); } SetKeyValue(tmpctx, dstmeta); tmpctx.currentDB = srcdb; DeleteKey(tmpctx, srckey); } ctx.data_change = true; return 0; }
int Ardb::GenericExpire(Context& ctx, const Slice& key, uint64 ms) { if (ms > 0 && get_current_epoch_millis() >= ms) { return 0; } if (m_cfg.slave_ignore_expire && ctx.IsSlave()) { /* * ignore expire setting, but issue data change event for replication */ ctx.data_change = true; return 0; } ValueObject meta; int err = GetMetaValue(ctx, key, KEY_END, meta); if (0 != err) { return err; } BatchWriteGuard guard(GetKeyValueEngine()); if (meta.meta.expireat != ms && meta.meta.expireat > 0) { KeyObject expire; expire.key = key; expire.type = KEY_EXPIRATION_ELEMENT; expire.db = ctx.currentDB; expire.score.SetInt64(meta.meta.expireat); DelKeyValue(ctx, expire); } meta.meta.expireat = ms; SetKeyValue(ctx, meta); if (meta.meta.expireat > 0) { ValueObject vv(KEY_EXPIRATION_ELEMENT); vv.key.key = key; vv.key.type = KEY_EXPIRATION_ELEMENT; vv.key.db = ctx.currentDB; vv.key.score.SetInt64(meta.meta.expireat); SetKeyValue(ctx, vv); } return 0; }
int Ardb::RenameHash(Context& ctx, DBID srcdb, const std::string& srckey, DBID dstdb, const std::string& dstkey) { Context tmpctx; tmpctx.currentDB = srcdb; ValueObject v; int err = GetMetaValue(tmpctx, srckey, HASH_META, v); CHECK_ARDB_RETURN_VALUE(ctx.reply, err); if (0 != err) { fill_error_reply(ctx.reply, "no such key or some error"); return 0; } if (v.meta.encoding == COLLECTION_ECODING_ZIPMAP) { DelKeyValue(tmpctx, v.key); v.key.encode_buf.Clear(); v.key.db = dstdb; v.key.key = dstkey; v.meta.expireat = 0; SetKeyValue(ctx, v); } else { HashIterator iter; HashIter(ctx, v, "", iter, false); tmpctx.currentDB = dstdb; ValueObject dstmeta; dstmeta.key.type = KEY_META; dstmeta.key.key = dstkey; dstmeta.type = HASH_META; dstmeta.meta.encoding = COLLECTION_ECODING_ZIPMAP; BatchWriteGuard guard(GetKeyValueEngine()); while (iter.Valid()) { HashSet(tmpctx, dstmeta, *(iter.Field()), *(iter.Value())); iter.Next(); } SetKeyValue(tmpctx, dstmeta); tmpctx.currentDB = srcdb; DeleteKey(tmpctx, srckey); } ctx.data_change = true; return 0; }
int Ardb::LClear(Context& ctx, ValueObject& meta) { BatchWriteGuard guard(GetKeyValueEngine(), meta.meta.Encoding() != COLLECTION_ENCODING_ZIPLIST); if (meta.meta.Encoding() != COLLECTION_ENCODING_ZIPLIST) { ListIterator iter; meta.meta.len = 0; ListIter(ctx, meta, iter, false); while (iter.Valid()) { KeyObject fk; fk.db = ctx.currentDB; fk.key = meta.key.key; fk.type = LIST_ELEMENT; fk.score = *(iter.Score()); DelKeyValue(ctx, fk); iter.Next(); } } DelKeyValue((ctx), meta.key); return 0; }
OP_NAMESPACE_BEGIN int Ardb::HashMultiSet(Context& ctx, ValueObject& meta, DataMap& fs) { if (meta.meta.encoding != COLLECTION_ECODING_ZIPMAP) { bool multi_write = fs.size() > 1; bool set_meta = meta.meta.len != -1; if (meta.meta.Length() > 0) { multi_write = true; } BatchWriteGuard guard(GetKeyValueEngine(), multi_write); DataMap::iterator it = fs.begin(); while (it != fs.end()) { ValueObject v(HASH_FIELD); v.element = it->second; v.key.type = HASH_FIELD; v.key.db = meta.key.db; v.key.key = meta.key.key; v.key.element = it->first; SetKeyValue(ctx, v); it++; } if (set_meta) { meta.meta.len = -1; SetKeyValue(ctx, meta); } fill_int_reply(ctx.reply, fs.size()); } else { int64 oldlen = meta.meta.Length(); DataMap::iterator it = fs.begin(); bool zipsave = true; while (it != fs.end()) { const Data& field = it->first; Data& value = it->second; meta.meta.zipmap[field] = value; it++; if (!meta.attach.force_zipsave && (field.StringLength() > m_cfg.hash_max_ziplist_value || value.StringLength() > m_cfg.hash_max_ziplist_value)) { zipsave = false; } } if (meta.meta.zipmap.size() > m_cfg.hash_max_ziplist_entries) { zipsave = false; } BatchWriteGuard guard(GetKeyValueEngine(), !zipsave); if (!zipsave) { /* * convert to non zipmap encoding */ DataMap::iterator fit = meta.meta.zipmap.begin(); while (fit != meta.meta.zipmap.end()) { ValueObject v(HASH_FIELD); v.element = fit->second; v.key.type = HASH_FIELD; v.key.db = meta.key.db; v.key.key = meta.key.key; v.key.element = fit->first; SetKeyValue(ctx, v); fit++; } meta.meta.len = meta.meta.zipmap.size(); meta.meta.zipmap.clear(); meta.meta.encoding = COLLECTION_ECODING_RAW; } SetKeyValue(ctx, meta); fill_int_reply(ctx.reply, meta.meta.Length() - oldlen); } return 0; }
int Ardb::LTrim(Context& ctx, RedisCommandFrame& cmd) { int64 start, end; if (!GetInt64Value(ctx, cmd.GetArguments()[1], start) || !GetInt64Value(ctx, cmd.GetArguments()[2], end)) { return 0; } ValueObject meta; int err = GetMetaValue(ctx, cmd.GetArguments()[0], LIST_META, meta); CHECK_ARDB_RETURN_VALUE(ctx.reply, err); if (0 != err) { fill_status_reply(ctx.reply, "OK"); return 0; } /* convert negative indexes */ if (start < 0) start = meta.meta.Length() + start; if (end < 0) end = meta.meta.Length() + end; if (start < 0) start = 0; if (end >= meta.meta.Length()) end = meta.meta.Length() - 1; /* Invariant: start >= 0, so this test will be true when end < 0. * The range is empty when start > end or start >= length. */ if (start > end || start >= meta.meta.Length()) { /* Out of range start or start > end result in empty list */ DeleteKey(ctx, cmd.GetArguments()[0]); return 0; } if (meta.meta.Encoding() == COLLECTION_ENCODING_ZIPLIST) { DataArray newzip; for (int64 i = start; i <= end; i++) { newzip.push_back(meta.meta.ziplist[i]); } meta.meta.ziplist = newzip; SetKeyValue(ctx, meta); } else { BatchWriteGuard guard(GetKeyValueEngine()); if (meta.meta.IsSequentialList()) { int64 listlen = meta.meta.Length(); for (int64 s = 0; s < listlen; s++) { if (s == start) { s = end; continue; } KeyObject lk; lk.db = meta.key.db; lk.key = meta.key.key; lk.type = LIST_ELEMENT; lk.score = meta.meta.min_index.IncrBy(s); meta.meta.len--; DelKeyValue(ctx, lk); } meta.meta.max_index = meta.meta.min_index; meta.meta.min_index.IncrBy(start); meta.meta.max_index.IncrBy(end); } else { ListIterator iter; ListIter(ctx, meta, iter, false); int64 cursor = 0; while (iter.Valid()) { if (cursor < start || cursor > end) { DelRaw(ctx, iter.CurrentRawKey()); meta.meta.len--; } if (cursor == start) { meta.meta.min_index = *(iter.Element()); } else if (cursor == end) { meta.meta.max_index = *(iter.Element()); } cursor++; iter.Next(); } } SetKeyValue(ctx, meta); } return 0; }
int Ardb::LRem(Context& ctx, RedisCommandFrame& cmd) { int64 count; if (!GetInt64Value(ctx, cmd.GetArguments()[1], count)) { return 0; } int64 toremove = std::abs(count); ValueObject meta; int err = GetMetaValue(ctx, cmd.GetArguments()[0], LIST_META, meta); CHECK_ARDB_RETURN_VALUE(ctx.reply, err); if (0 != err) { fill_int_reply(ctx.reply, 0); return 0; } Data element; element.SetString(cmd.GetArguments()[2], true); KeyLockerGuard lock(m_key_lock, ctx.currentDB, cmd.GetArguments()[0]); if (meta.meta.Encoding() == COLLECTION_ENCODING_ZIPLIST) { uint32 oldlen = meta.meta.ziplist.size(); int64 removed = 0; DataArray newzip; if (count >= 0) { for (uint32 i = 0; i < oldlen; i++) { if (meta.meta.ziplist[i] == element) { if (toremove == 0 || removed < toremove) { removed++; continue; } } newzip.push_back(meta.meta.ziplist[i]); } } else { for (uint32 i = 0; i < oldlen; i++) { if (meta.meta.ziplist[oldlen - 1 - i] == element) { if (toremove == 0 || removed < toremove) { removed++; continue; } } newzip.push_front(meta.meta.ziplist[i]); } } if (removed > 0) { meta.meta.ziplist = newzip; SetKeyValue(ctx, meta); } fill_int_reply(ctx.reply, removed); return 0; } BatchWriteGuard guard(GetKeyValueEngine()); ListIterator iter; ListIter(ctx, meta, iter, count < 0); int64 remove = 0; while (iter.Valid()) { if (iter.Element()->Compare(element) == 0) { meta.meta.len--; meta.meta.SetFlag(COLLECTION_FLAG_NORMAL); DelRaw(ctx, iter.CurrentRawKey()); //DelKeyValue(ctx, k); remove++; if (remove == toremove) { break; } } if (count < 0) { iter.Prev(); } else { iter.Next(); } } if (remove > 0) { SetKeyValue(ctx, meta); } fill_int_reply(ctx.reply, remove); return 0; }
int Ardb::ListPop(Context& ctx, const std::string& key, bool lpop) { ValueObject meta; KeyLockerGuard keylock(m_key_lock, ctx.currentDB, key); int err = GetMetaValue(ctx, key, LIST_META, meta); CHECK_ARDB_RETURN_VALUE(ctx.reply, err); if (0 != err) { ctx.reply.type = REDIS_REPLY_NIL; return 0; } BatchWriteGuard guard(GetKeyValueEngine(), meta.meta.Encoding() != COLLECTION_ENCODING_ZIPLIST); if (meta.meta.Encoding() == COLLECTION_ENCODING_ZIPLIST) { if (!meta.meta.ziplist.empty()) { if (lpop) { Data& data = meta.meta.ziplist.front(); fill_value_reply(ctx.reply, data); meta.meta.ziplist.pop_front(); } else { Data& data = meta.meta.ziplist.back(); fill_value_reply(ctx.reply, data); meta.meta.ziplist.pop_back(); } if (meta.meta.ziplist.empty()) { DelKeyValue(ctx, meta.key); } else { SetKeyValue(ctx, meta); } } else { ctx.reply.type = REDIS_REPLY_NIL; } return 0; } else { bool poped = false; if (meta.meta.IsSequentialList()) { if (meta.meta.Length() > 0) { ValueObject lkv; lkv.key.type = LIST_ELEMENT; lkv.key.key = meta.key.key; lkv.key.db = ctx.currentDB; lkv.key.score = lpop ? meta.meta.min_index : meta.meta.max_index; if (0 == GetKeyValue(ctx, lkv.key, &lkv)) { DelKeyValue(ctx, lkv.key); if (lpop) { meta.meta.min_index.IncrBy(1); } else { meta.meta.max_index.IncrBy(-1); } meta.meta.len--; poped = true; fill_value_reply(ctx.reply, lkv.element); } } } else { ListIterator iter; err = ListIter(ctx, meta, iter, !lpop); while (iter.Valid()) { if (!poped) { fill_value_reply(ctx.reply, *(iter.Element())); poped = true; meta.meta.len--; KeyObject k; k.type = LIST_ELEMENT; k.key = meta.key.key; k.db = ctx.currentDB; k.score = *(iter.Score()); DelKeyValue(ctx, k); } else { if (lpop) { meta.meta.min_index = *(iter.Score()); } else { meta.meta.max_index = *(iter.Score()); } break; } if (lpop) { iter.Next(); } else { iter.Prev(); } } } if (poped) { if (meta.meta.Length() > 0) { SetKeyValue(ctx, meta); } else { DelKeyValue(ctx, meta.key); } } else { ctx.reply.type = REDIS_REPLY_NIL; } return 0; } }
int Ardb::SortCommand(Context& ctx, const Slice& key, SortOptions& options, DataArray& values) { values.clear(); KeyType keytype = KEY_END; GetType(ctx, key, keytype); switch (keytype) { case LIST_META: { ListRange(ctx, key, 0, -1); break; } case SET_META: { SetMembers(ctx, key); break; } case ZSET_META: { ZSetRange(ctx, key, 0, -1, false, false, OP_GET); if (NULL == options.by) { options.nosort = true; } break; } default: { return ERR_INVALID_TYPE; } } DataArray sortvals; if (ctx.reply.MemberSize() > 0) { for (uint32 i = 0; i < ctx.reply.MemberSize(); i++) { Data v; v.SetString(ctx.reply.MemberAt(i).str, true); sortvals.push_back(v); } } if (sortvals.empty()) { return 0; } if (options.with_limit) { if (options.limit_offset < 0) { options.limit_offset = 0; } if ((uint32) options.limit_offset > sortvals.size()) { values.clear(); return 0; } if (options.limit_count < 0) { options.limit_count = sortvals.size(); } } std::vector<SortValue> sortvec; if (!options.nosort) { if (NULL != options.by) { sortvec.reserve(sortvals.size()); } for (uint32 i = 0; i < sortvals.size(); i++) { if (NULL != options.by) { sortvec.push_back(SortValue(&sortvals[i])); if (GetValueByPattern(ctx, options.by, sortvals[i], sortvec[i].cmp) < 0) { DEBUG_LOG("Failed to get value by pattern:%s", options.by); sortvec[i].cmp.Clear(); continue; } } if (options.with_alpha) { if (NULL != options.by) { sortvec[i].cmp.ToString(); } else { sortvals[i].ToString(); } } } if (NULL != options.by) { if (!options.is_desc) { std::sort(sortvec.begin(), sortvec.end(), less_value<SortValue>); } else { std::sort(sortvec.begin(), sortvec.end(), greater_value<SortValue>); } } else { if (!options.is_desc) { std::sort(sortvals.begin(), sortvals.end(), less_value<Data>); } else { std::sort(sortvals.begin(), sortvals.end(), greater_value<Data>); } } } if (!options.with_limit) { options.limit_offset = 0; options.limit_count = sortvals.size(); } uint32 count = 0; for (uint32 i = options.limit_offset; i < sortvals.size() && count < (uint32) options.limit_count; i++, count++) { Data* patternObj = NULL; if (NULL != options.by) { patternObj = sortvec[i].value; } else { patternObj = &(sortvals[i]); } if (options.get_patterns.empty()) { values.push_back(*patternObj); } else { for (uint32 j = 0; j < options.get_patterns.size(); j++) { Data vo; if (GetValueByPattern(ctx, options.get_patterns[j], *patternObj, vo) < 0) { DEBUG_LOG("Failed to get value by pattern for:%s", options.get_patterns[j]); vo.Clear(); } values.push_back(vo); } } } uint32 step = options.get_patterns.empty() ? 1 : options.get_patterns.size(); switch (options.aggregate) { case AGGREGATE_SUM: case AGGREGATE_AVG: { DataArray result; result.resize(step); for (uint32 i = 0; i < result.size(); i++) { for (uint32 j = i; j < values.size(); j += step) { result[i].IncrBy(values[j]); } } if (options.aggregate == AGGREGATE_AVG) { size_t count = values.size() / step; for (uint32 i = 0; i < result.size(); i++) { result[i].SetDouble(result[i].NumberValue() / count); } } values.assign(result.begin(), result.end()); break; } case AGGREGATE_MAX: case AGGREGATE_MIN: { DataArray result; result.resize(step); for (uint32 i = 0; i < result.size(); i++) { for (uint32 j = i; j < values.size(); j += step) { if (result[i].IsNil()) { result[i] = values[j]; } else { if (options.aggregate == AGGREGATE_MIN) { if (values[j] < result[i]) { result[i] = values[j]; } } else { if (values[j] > result[i]) { result[i] = values[j]; } } } } } values.assign(result.begin(), result.end()); break; } case AGGREGATE_COUNT: { size_t size = values.size() / step; values.clear(); Data v; v.SetInt64(size); values.push_back(v); break; } default: { break; } } if (options.store_dst != NULL && !values.empty()) { DeleteKey(ctx, options.store_dst); ValueObject list_meta; list_meta.key.key = options.store_dst; list_meta.key.type = KEY_META; list_meta.key.db = ctx.currentDB; list_meta.type = LIST_META; list_meta.meta.SetEncoding(COLLECTION_ECODING_ZIPLIST); BatchWriteGuard guard(GetKeyValueEngine()); DataArray::iterator it = values.begin(); while (it != values.end()) { if (!it->IsNil()) { std::string tmp; it->GetDecodeString(tmp); ListInsert(ctx, list_meta, NULL, tmp, false, false); } it++; } SetKeyValue(ctx, list_meta); } return 0; }