Compare commits

...
Author SHA1 Message Date
Malavan Sotheeswaran 5d46171ff7 add config to disable storage key cache 2023-04-24 17:58:19 -07:00
Malavan Sotheeswaran a8c0f9b1c4 limit number of random elements returned based on config, exit loop early if client is being closed 2023-04-18 17:08:27 -07:00
Malavan Sotheeswaran 36d515ef39 ptrFromObj to szFromObj 2023-04-18 17:08:27 -07:00
Malavan Sotheeswaran 525c97d6cd ->ptr to ptrFromObj 2023-04-18 17:08:27 -07:00
4c200e0985 fix hincrbyfloat not to create a key if the new value is invalid (#11149)
Check the validity of the value before performing the create operation,
prevents new data from being generated even if the request fails to execute.

Co-authored-by: Oran Agra <oran@redislabs.com>
Co-authored-by: chendianqiang <chendianqiang@meituan.com>
Co-authored-by: Binbin <binloveplay1314@qq.com>
2023-04-18 17:08:27 -07:00
Oran Agra d4c0a970e7 Integer Overflow in RAND commands can lead to assertion (CVE-2023-25155) (#11857)
Issue happens when passing a negative long value that greater than
the max positive value that the long can store.
2023-04-18 17:08:27 -07:00
Malavan Sotheeswaran 1735e73a35 don't count base repl buffer size as overhead (#629) 2023-04-12 16:01:22 -04:00
Heng Kuang f9ccf90566 fix the swapdb issue (#620) 2023-04-12 15:08:09 -04:00
Malavan Sotheeswaran f54e3ea367 restore fork impl of save to replica sockets (#622)
* restore fork impl of save to slave sockets

* default to fork bgsave
2023-04-06 22:13:12 -04:00
Ubuntu 77bc0afad4 add key eviction number for storage 2023-04-06 15:09:10 -04:00
Malavan Sotheeswaran 858db2645d add g_expirelock to previously async accesses to expireset (#618)
* add expire_lock to previously async access to expireset

* add flash option to create-cluster
2023-03-30 23:23:56 -04:00
Malavan Sotheeswaran 06380e5fe1 Add KeyDB global variable to lua api (#606) 2023-03-14 13:45:29 -07:00
Malavan Sotheeswaran deaaa992bd don't do if statement on every key for flash load, use stack object for module notify (#604) 2023-03-13 18:16:17 -04:00
Malavan Sotheeswaran 715f832b00 make connectWithMaster error message less confusing (#592) 2023-03-08 16:00:53 -05:00
Malavan Sotheeswaran c8dd6744da Add config for AWS s3 rdb save/load. (#591)
* add s3 config

* missing include

* ignore s3 config in config test

* Update introspection.tcl

* Update config.cpp
2023-03-08 16:00:44 -05:00
Malavan Sotheeswaran b398021b2c update slotToKey during fast load (#589) 2023-03-08 15:54:50 -05:00
Malavan Sotheeswaran c2077a2fbd Fix rdb fd leak (#579)
* close tempfile when done bgsave

* declare getTempFileName

* open close child pipes in correct place

* assert no existing child pipe when opening new child pipe
2023-03-02 13:51:47 -05:00
Malavan Sotheeswaran a9995d2e54 Upgrade rocksdb to v7.9.2 (#555)
* upgrade to rocksdb v7.9.2

* need c++17 for rocksdb

* don't prefix jemalloc

* different exception specifier
2023-03-02 13:51:21 -05:00
31 changed files with 303 additions and 113 deletions

No files matched your search

+1 -1
View File
@@ -95,7 +95,7 @@ JEMALLOC_LDFLAGS= $(LDFLAGS)
jemalloc: .make-prerequisites
@printf '%b %b\n' $(MAKECOLOR)MAKE$(ENDCOLOR) $(BINCOLOR)$@$(ENDCOLOR)
cd jemalloc && ./configure --with-version=5.2.1-0-g0 --with-lg-quantum=3 --with-jemalloc-prefix=je_ --disable-cxx CFLAGS="$(JEMALLOC_CFLAGS)" LDFLAGS="$(JEMALLOC_LDFLAGS)"
cd jemalloc && ./configure --with-version=5.2.1-0-g0 --with-lg-quantum=3 --disable-cxx CFLAGS="$(JEMALLOC_CFLAGS)" LDFLAGS="$(JEMALLOC_LDFLAGS)"
cd jemalloc && $(MAKE) CFLAGS="$(JEMALLOC_CFLAGS)" LDFLAGS="$(JEMALLOC_LDFLAGS)" lib/libjemalloc.a
.PHONY: jemalloc
+1 -1
+1 -1
View File
@@ -25,7 +25,7 @@ NODEPS:=clean distclean
# Default settings
STD=-pedantic -DREDIS_STATIC=''
CXX_STD=-std=c++14 -pedantic -fno-rtti -D__STDC_FORMAT_MACROS
CXX_STD=-std=c++17 -pedantic -fno-rtti -D__STDC_FORMAT_MACROS
ifneq (,$(findstring clang,$(CC)))
STD+=-Wno-c11-extensions
else
+1 -1
View File
@@ -140,7 +140,7 @@ void SnapshotPayloadParseState::flushQueuedKeys() {
auto &insertsInFlightTmp = insertsInFlight; // C++ GRRRRRRRRRRRRRRRR, we don't want to capute "this" because that's dangerous
if (current_database < cserver.dbnum) {
g_pserver->asyncworkqueue->AddWorkFunction([idb, vecqueuedKeys = std::move(this->vecqueuedKeys), vecqueuedKeysCb = std::move(this->vecqueuedKeysCb), vecqueuedVals = std::move(this->vecqueuedVals), vecqueuedValsCb = std::move(this->vecqueuedValsCb), &insertsInFlightTmp, pallocator = m_spallocator.release()]() mutable {
g_pserver->db[idb]->bulkStorageInsert(vecqueuedKeys.data(), vecqueuedKeysCb.data(), vecqueuedVals.data(), vecqueuedValsCb.data(), vecqueuedKeys.size());
g_pserver->db[idb]->bulkDirectStorageInsert(vecqueuedKeys.data(), vecqueuedKeysCb.data(), vecqueuedVals.data(), vecqueuedValsCb.data(), vecqueuedKeys.size());
--insertsInFlightTmp;
delete pallocator;
});
+1 -1
View File
@@ -21,7 +21,7 @@ dictType dbStorageCacheType = {
StorageCache::StorageCache(IStorage *storage, bool fCache)
: m_spstorage(storage)
{
if (fCache)
if (!g_pserver->flash_disable_key_cache && fCache)
m_pdict = dictCreate(&dbStorageCacheType, nullptr);
}
+1
View File
@@ -42,6 +42,7 @@ typedef struct {
* RDB / AOF saving process from the child to the parent (for instance
* the amount of copy on write memory used) */
void openChildInfoPipe(void) {
serverAssert(g_pserver->child_info_pipe[0] == -1);
if (pipe(g_pserver->child_info_pipe) == -1) {
/* On error our two file descriptors should be still set to -1,
* but we call anyway closeChildInfoPipe() since can't hurt. */
+31 -1
View File
@@ -35,6 +35,7 @@
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/wait.h>
#ifdef __linux__
#include <sys/sysinfo.h>
#endif
@@ -2456,6 +2457,32 @@ static int isValidAOFfilename(char *val, const char **err) {
return 1;
}
static int isValidS3Bucket(char *s3bucket, const char **err) {
int status = EXIT_FAILURE;
pid_t pid = fork();
if (pid < 0)
{
*err = "couldn't fork to call aws cli";
return 0;
}
if (pid == 0)
{
execlp("aws", "aws", "s3", "ls", s3bucket);
exit(EXIT_FAILURE);
}
else
{
waitpid(pid, &status, 0);
}
if (status != EXIT_SUCCESS) {
*err = "could not access s3 bucket";
return 0;
}
return 1;
}
/* Validate specified string is a valid proc-title-template */
static int isValidProcTitleTemplate(char *val, const char **err) {
if (!validateProcTitleTemplate(val)) {
@@ -2779,7 +2806,7 @@ standardConfig configs[] = {
createBoolConfig("appendonly", NULL, MODIFIABLE_CONFIG, g_pserver->aof_enabled, 0, NULL, updateAppendonly),
createBoolConfig("cluster-allow-reads-when-down", NULL, MODIFIABLE_CONFIG, g_pserver->cluster_allow_reads_when_down, 0, NULL, NULL),
createBoolConfig("delete-on-evict", NULL, MODIFIABLE_CONFIG, cserver.delete_on_evict, 0, NULL, NULL),
createBoolConfig("use-fork", NULL, IMMUTABLE_CONFIG, cserver.fForkBgSave, 0, NULL, NULL),
createBoolConfig("use-fork", NULL, IMMUTABLE_CONFIG, cserver.fForkBgSave, 1, NULL, NULL),
createBoolConfig("io-threads-do-reads", NULL, IMMUTABLE_CONFIG, fDummy, 0, NULL, NULL),
createBoolConfig("time-thread-priority", NULL, IMMUTABLE_CONFIG, cserver.time_thread_priority, 0, NULL, NULL),
createBoolConfig("prefetch-enabled", NULL, MODIFIABLE_CONFIG, g_pserver->prefetch_enabled, 1, NULL, NULL),
@@ -2803,6 +2830,7 @@ standardConfig configs[] = {
createStringConfig("cluster-announce-ip", NULL, MODIFIABLE_CONFIG, EMPTY_STRING_IS_NULL, g_pserver->cluster_announce_ip, NULL, NULL, NULL),
createStringConfig("syslog-ident", NULL, IMMUTABLE_CONFIG, ALLOW_EMPTY_STRING, g_pserver->syslog_ident, "redis", NULL, NULL),
createStringConfig("dbfilename", NULL, MODIFIABLE_CONFIG, ALLOW_EMPTY_STRING, g_pserver->rdb_filename, CONFIG_DEFAULT_RDB_FILENAME, isValidDBfilename, NULL),
createStringConfig("db-s3-object", NULL, MODIFIABLE_CONFIG, EMPTY_STRING_IS_NULL, g_pserver->rdb_s3bucketpath, NULL, isValidS3Bucket, NULL),
createStringConfig("appendfilename", NULL, IMMUTABLE_CONFIG, ALLOW_EMPTY_STRING, g_pserver->aof_filename, "appendonly.aof", isValidAOFfilename, NULL),
createStringConfig("server_cpulist", NULL, IMMUTABLE_CONFIG, EMPTY_STRING_IS_NULL, g_pserver->server_cpulist, NULL, NULL, NULL),
createStringConfig("bio_cpulist", NULL, IMMUTABLE_CONFIG, EMPTY_STRING_IS_NULL, g_pserver->bio_cpulist, NULL, NULL, NULL),
@@ -2884,6 +2912,7 @@ standardConfig configs[] = {
createLongLongConfig("repl-backlog-size", NULL, MODIFIABLE_CONFIG, 1, LLONG_MAX, g_pserver->repl_backlog_size, 1024*1024, MEMORY_CONFIG, NULL, updateReplBacklogSize), /* Default: 1mb */
createLongLongConfig("repl-backlog-disk-reserve", NULL, IMMUTABLE_CONFIG, 0, LLONG_MAX, cserver.repl_backlog_disk_size, 0, MEMORY_CONFIG, NULL, NULL),
createLongLongConfig("max-snapshot-slip", NULL, MODIFIABLE_CONFIG, 0, 5000, g_pserver->snapshot_slip, 400, 0, NULL, NULL),
createLongLongConfig("max-rand-count", NULL, MODIFIABLE_CONFIG, 0, LONG_MAX/2, g_pserver->rand_total_threshold, LONG_MAX/2, 0, NULL, NULL),
/* Unsigned Long Long configs */
createULongLongConfig("maxmemory", NULL, MODIFIABLE_CONFIG, 0, LLONG_MAX, g_pserver->maxmemory, 0, MEMORY_CONFIG, NULL, updateMaxmemory),
@@ -2911,6 +2940,7 @@ standardConfig configs[] = {
createBoolConfig("allow-write-during-load", NULL, MODIFIABLE_CONFIG, g_pserver->fWriteDuringActiveLoad, 0, NULL, NULL),
createBoolConfig("force-backlog-disk-reserve", NULL, MODIFIABLE_CONFIG, cserver.force_backlog_disk, 0, NULL, NULL),
createBoolConfig("soft-shutdown", NULL, MODIFIABLE_CONFIG, g_pserver->config_soft_shutdown, 0, NULL, NULL),
createBoolConfig("flash-disable-key-cache", NULL, MODIFIABLE_CONFIG, g_pserver->flash_disable_key_cache, 0, NULL, NULL),
createSizeTConfig("semi-ordered-set-bucket-size", NULL, MODIFIABLE_CONFIG, 0, 1024, g_semiOrderedSetTargetBucketSize, 0, INTEGER_CONFIG, NULL, NULL),
#ifdef USE_OPENSSL
+39 -10
View File
@@ -1737,6 +1737,9 @@ int dbSwapDatabases(int id1, int id2) {
id2 < 0 || id2 >= cserver.dbnum) return C_ERR;
if (id1 == id2) return C_OK;
std::swap(g_pserver->db[id1], g_pserver->db[id2]);
//swap db's id too, otherwise db does not match its id
std::swap(g_pserver->db[id1]->id, g_pserver->db[id2]->id);
/* Note that we don't swap blocking_keys,
* ready_keys and watched_keys, since we want clients to
@@ -1766,7 +1769,7 @@ int dbSwapDatabases(int id1, int id2) {
/* SWAPDB db1 db2 */
void swapdbCommand(client *c) {
int id1, id2;
int id1, id2, oriId;
/* Not allowed in cluster mode: we have just DB 0 there. */
if (g_pserver->cluster_enabled) {
@@ -1783,6 +1786,9 @@ void swapdbCommand(client *c) {
"invalid second DB index") != C_OK)
return;
//get client's original db's id
oriId=c->db->id;
/* Swap... */
if (dbSwapDatabases(id1,id2) == C_ERR) {
addReplyError(c,"DB index is out of range");
@@ -1791,6 +1797,10 @@ void swapdbCommand(client *c) {
RedisModuleSwapDbInfo si = {REDISMODULE_SWAPDBINFO_VERSION,(int32_t)id1,(int32_t)id2};
moduleFireServerEvent(REDISMODULE_EVENT_SWAPDB,0,&si);
g_pserver->dirty++;
//set client's db to original db
c->db=g_pserver->db[oriId];
addReply(c,shared.ok);
}
}
@@ -1931,6 +1941,7 @@ void setExpire(client *c, redisDb *db, robj *key, expireEntry &&e)
* is associated with this key (i.e. the key is non volatile) */
expireEntry *redisDbPersistentDataSnapshot::getExpire(const char *key) {
/* No expire? return ASAP */
std::unique_lock<fastlock> ul(g_expireLock);
if (expireSize() == 0)
return nullptr;
@@ -2607,12 +2618,15 @@ void clusterStorageLoadCallback(const char *rgchkey, size_t cch, void *)
slotToKeyUpdateKeyCore(rgchkey, cch, true /*add*/);
}
void moduleLoadCallback(const char * rgchKey, size_t cchKey, void *data) {
if (g_pserver->cluster_enabled) {
clusterStorageLoadCallback(rgchKey, cchKey, data);
}
robj *keyobj = createEmbeddedStringObject(rgchKey, cchKey);
moduleNotifyKeyspaceEvent(NOTIFY_LOADED, "loaded", keyobj, *(int *)data);
void moduleLoadCallback(const char * rgchKey, size_t, void *data) {
redisObjectStack keyobj;
initStaticStringObject(keyobj, const_cast<char *>(rgchKey));
moduleNotifyKeyspaceEvent(NOTIFY_LOADED, "loaded", &keyobj, *(int *)data);
}
void moduleClusterLoadCallback(const char * rgchKey, size_t cchKey, void *data) {
clusterStorageLoadCallback(rgchKey, cchKey, data);
moduleLoadCallback(rgchKey, cchKey, data);
}
void redisDb::initialize(int id)
@@ -2633,7 +2647,7 @@ void redisDb::storageProviderInitialize()
{
if (g_pserver->m_pstorageFactory != nullptr)
{
IStorageFactory::key_load_iterator itr = moduleLoadCallback;
IStorageFactory::key_load_iterator itr = g_pserver->cluster_enabled ? moduleClusterLoadCallback : moduleLoadCallback;
this->setStorageProvider(StorageCache::create(g_pserver->m_pstorageFactory, id, itr, &id));
}
}
@@ -2724,8 +2738,11 @@ void redisDbPersistentData::clear(void(callback)(void*))
m_cnewKeysPending = 0;
m_fAllChanged++;
}
{
std::unique_lock<fastlock> ul(g_expireLock);
delete m_setexpire;
m_setexpire = new (MALLOC_LOCAL) expireset();
}
if (m_spstorage != nullptr)
m_spstorage->clear(callback);
dictEmpty(m_pdictTombstone,callback);
@@ -2858,7 +2875,8 @@ LNotFound:
{
dictAdd(m_pdict, sdsNewKey, o);
o->SetFExpires(spexpire != nullptr);
std::unique_lock<fastlock> ul(g_expireLock);
if (spexpire != nullptr)
{
auto itr = m_setexpire->find(sdsKey);
@@ -2881,6 +2899,7 @@ LNotFound:
if (*pde != nullptr && dictGetVal(*pde) != nullptr)
{
robj *o = (robj*)dictGetVal(*pde);
std::unique_lock<fastlock> ul(g_expireLock);
serverAssert(o->FExpires() == (m_setexpire->find(sdsKey) != m_setexpire->end()));
}
}
@@ -3002,8 +3021,16 @@ void redisDbPersistentData::processChangesAsync(std::atomic<int> &pendingJobs)
});
}
void redisDbPersistentData::bulkStorageInsert(char **rgKeys, size_t *rgcbKeys, char **rgVals, size_t *rgcbVals, size_t celem)
/* This function is to bulk insert directly to storage provider bypassing in memory, assumes rgKeys and rgVals are not sds strings */
void redisDbPersistentData::bulkDirectStorageInsert(char **rgKeys, size_t *rgcbKeys, char **rgVals, size_t *rgcbVals, size_t celem)
{
if (g_pserver->cluster_enabled) {
aeAcquireLock();
for (size_t i = 0; i < celem; i++) {
slotToKeyUpdateKeyCore(rgKeys[i], rgcbKeys[i], 1);
}
aeReleaseLock();
}
m_spstorage->bulkInsert(rgKeys, rgcbKeys, rgVals, rgcbVals, celem);
}
@@ -3245,6 +3272,7 @@ std::unique_ptr<expireEntry> deserializeExpire(sds key, const char *str, size_t
sds serializeStoredObjectAndExpire(redisDbPersistentData *db, const char *key, robj_roptr o)
{
std::unique_lock<fastlock> ul(g_expireLock);
auto itrExpire = db->setexpire()->find(key);
const expireEntry *pexpire = nullptr;
if (itrExpire != db->setexpire()->end())
@@ -3369,6 +3397,7 @@ void redisDbPersistentData::prefetchKeysAsync(client *c, parsed_command &command
dictAdd(m_pdict, sharedKey, o);
o->SetFExpires(spexpire != nullptr);
std::unique_lock<fastlock> ul(g_expireLock);
if (spexpire != nullptr)
{
auto itr = m_setexpire->find(sharedKey);
+4 -4
View File
@@ -341,10 +341,10 @@ void mallctl_int(client *c, robj **argv, int argc) {
}
size_t sz = sizeof(old);
while (sz > 0) {
if ((ret=je_mallctl(szFromObj(argv[0]), &old, &sz, argc > 1? &val: NULL, argc > 1?sz: 0))) {
if ((ret=mallctl(szFromObj(argv[0]), &old, &sz, argc > 1? &val: NULL, argc > 1?sz: 0))) {
if (ret == EPERM && argc > 1) {
/* if this option is write only, try just writing to it. */
if (!(ret=je_mallctl(szFromObj(argv[0]), NULL, 0, &val, sz))) {
if (!(ret=mallctl(szFromObj(argv[0]), NULL, 0, &val, sz))) {
addReply(c, shared.ok);
return;
}
@@ -375,7 +375,7 @@ void mallctl_string(client *c, robj **argv, int argc) {
char *old;
size_t sz = sizeof(old);
/* for strings, it seems we need to first get the old value, before overriding it. */
if ((rret=je_mallctl(szFromObj(argv[0]), &old, &sz, NULL, 0))) {
if ((rret=mallctl(szFromObj(argv[0]), &old, &sz, NULL, 0))) {
/* return error unless this option is write only. */
if (!(rret == EPERM && argc > 1)) {
addReplyErrorFormat(c,"%s", strerror(rret));
@@ -387,7 +387,7 @@ void mallctl_string(client *c, robj **argv, int argc) {
char **valref = &val;
if ((!strcmp(val,"VOID")))
valref = NULL, sz = 0;
wret = je_mallctl(szFromObj(argv[0]), NULL, 0, valref, sz);
wret = mallctl(szFromObj(argv[0]), NULL, 0, valref, sz);
}
if (!rret)
addReplyBulkCString(c, old);
+2 -1
View File
@@ -380,7 +380,7 @@ size_t freeMemoryGetNotCountedMemory(void) {
/* also don't count the replication backlog memory
* that's where the replication clients get their memory from */
overhead += g_pserver->repl_backlog_size;
overhead += g_pserver->repl_backlog_size - g_pserver->repl_backlog_config_size;
if (g_pserver->aof_state != AOF_OFF) {
overhead += sdsalloc(g_pserver->aof_buf)+aofRewriteBufferSize();
@@ -771,6 +771,7 @@ int performEvictions(bool fPreSnapshot) {
if (db->removeCachedValue(bestkey, &deT)) {
mem_freed += splazy->addEntry(db->dictUnsafeKeyOnly(), deT);
ckeysFailed = 0;
g_pserver->stat_evictedkeys++;
}
else {
delta = 0;
+1
View File
@@ -481,6 +481,7 @@ void expireSlaveKeys(void) {
if (slaveKeysWithExpire == NULL ||
dictSize(slaveKeysWithExpire) == 0) return;
std::unique_lock<fastlock> ul(g_expireLock);
int cycles = 0, noexpire = 0;
mstime_t start = mstime();
while(1) {
-7
View File
@@ -41,10 +41,3 @@ void operator delete(void *p, std::size_t) noexcept
}
#endif
#if defined(USE_JEMALLOC)
extern "C" size_t malloc_usable_size(void *ptr)
{
return zmalloc_usable_size(ptr);
}
#endif
+2 -1
View File
@@ -1541,7 +1541,7 @@ void memoryCommand(client *c) {
} else if (!strcasecmp(szFromObj(c->argv[1]),"malloc-stats") && c->argc == 2) {
#if defined(USE_JEMALLOC)
sds info = sdsempty();
je_malloc_stats_print(inputCatSds, &info, NULL);
malloc_stats_print(inputCatSds, &info, NULL);
addReplyVerbatim(c,info,sdslen(info),"txt");
sdsfree(info);
#else
@@ -1668,6 +1668,7 @@ robj *deserializeStoredObjectCore(const void *data, size_t cb)
robj *deserializeStoredObject(const redisDbPersistentData *db, const char *key, const void *data, size_t cb)
{
robj *o = deserializeStoredObjectCore(data, cb);
std::unique_lock<fastlock> ul(g_expireLock);
o->SetFExpires(db->setexpire()->exists(key));
return o;
}
+123 -50
View File
@@ -1334,7 +1334,7 @@ int rdbSaveRio(rio *rdb, const redisDbPersistentDataSnapshot **rgpdb, int *error
if (rdbSaveModulesAux(rdb, REDISMODULE_AUX_BEFORE_RDB) == -1) goto werr;
for (j = 0; j < cserver.dbnum; j++) {
const redisDbPersistentDataSnapshot *db = rgpdb[j];
const redisDbPersistentDataSnapshot *db = rgpdb != nullptr ? rgpdb[j] : g_pserver->db[j];
if (db->size() == 0) continue;
/* Write the SELECT DB opcode */
@@ -1490,7 +1490,7 @@ int rdbSaveFile(char *filename, const redisDbPersistentDataSnapshot **rgpdb, rdb
rio rdb;
int error = 0;
snprintf(tmpfile,sizeof(tmpfile),"temp-%d-%d.rdb", getpid(), g_pserver->rdbThreadVars.tmpfileNum);
getTempFileName(tmpfile, g_pserver->rdbThreadVars.tmpfileNum);
fp = fopen(tmpfile,"w");
if (!fp) {
char *cwdp = getcwd(cwd,MAXPATHLEN);
@@ -1660,12 +1660,14 @@ int launchRdbSaveThread(pthread_t &child, rdbSaveInfo *rsi)
pthread_attr_t tattr;
pthread_attr_init(&tattr);
pthread_attr_setstacksize(&tattr, 1 << 23); // 8 MB
openChildInfoPipe();
if (pthread_create(&child, &tattr, rdbSaveThread, args)) {
pthread_attr_destroy(&tattr);
for (int idb = 0; idb < cserver.dbnum; ++idb)
g_pserver->db[idb]->endSnapshot(args->rgpdb[idb]);
args->~rdbSaveThreadArgs();
zfree(args);
closeChildInfoPipe();
return C_ERR;
}
pthread_attr_destroy(&tattr);
@@ -1683,13 +1685,11 @@ int rdbSaveBackground(rdbSaveInfo *rsi) {
g_pserver->dirty_before_bgsave = g_pserver->dirty;
g_pserver->lastbgsave_try = time(NULL);
openChildInfoPipe();
start = ustime();
latencyStartMonitor(g_pserver->rdb_save_latency);
if (launchRdbSaveThread(child, rsi) != C_OK) {
closeChildInfoPipe();
g_pserver->lastbgsave_status = C_ERR;
serverLog(LL_WARNING,"Can't save in background: fork: %s",
strerror(errno));
@@ -1715,7 +1715,7 @@ void getTempFileName(char tmpfile[], int tmpfileNum) {
char tmpfileNumString[214];
/* Generate temp rdb file name using aync-signal safe functions. */
int pid_len = ll2string(pid, sizeof(pid), getpid());
int pid_len = ll2string(pid, sizeof(pid), g_pserver->in_fork_child ? getppid() : getpid());
int tmpfileNum_len = ll2string(tmpfileNumString, sizeof(tmpfileNumString), tmpfileNum);
strcpy(tmpfile, "temp-");
strncpy(tmpfile+5, pid, pid_len);
@@ -3832,57 +3832,130 @@ int rdbSaveToSlavesSockets(rdbSaveInfo *rsi) {
}
/* Create the child process. */
openChildInfoPipe();
if (cserver.fForkBgSave) {
pid_t childpid;
if ((childpid = redisFork(CHILD_TYPE_RDB)) == 0) {
/* Child */
int retval, dummy;
rio rdb;
for (int idb = 0; idb < cserver.dbnum; ++idb)
args->rgpdb[idb] = g_pserver->db[idb]->createSnapshot(getMvccTstamp(), false /*fOptional*/);
rioInitWithFd(&rdb,args->rdb_pipe_write);
g_pserver->rdbThreadVars.tmpfileNum++;
g_pserver->rdbThreadVars.fRdbThreadCancel = false;
pthread_attr_t tattr;
pthread_attr_init(&tattr);
pthread_attr_setstacksize(&tattr, 1 << 23); // 8 MB
if (pthread_create(&child, &tattr, rdbSaveToSlavesSocketsThread, args)) {
pthread_attr_destroy(&tattr);
serverLog(LL_WARNING,"Can't save in background: fork: %s",
strerror(errno));
redisSetProcTitle("keydb-rdb-to-slaves");
redisSetCpuAffinity(g_pserver->bgsave_cpulist);
/* Undo the state change. The caller will perform cleanup on
* all the slaves in BGSAVE_START state, but an early call to
* replicationSetupSlaveForFullResync() turned it into BGSAVE_END */
listRewind(g_pserver->slaves,&li);
while((ln = listNext(&li))) {
client *replica = (client*)ln->value;
if (replica->replstate == SLAVE_STATE_WAIT_BGSAVE_END) {
replica->replstate = SLAVE_STATE_WAIT_BGSAVE_START;
retval = rdbSaveRioWithEOFMark(&rdb,nullptr,nullptr,rsi);
if (retval == C_OK && rioFlush(&rdb) == 0)
retval = C_ERR;
if (retval == C_OK) {
sendChildCowInfo(CHILD_INFO_TYPE_RDB_COW_SIZE, "RDB");
}
}
close(args->rdb_pipe_write);
close(g_pserver->rdb_pipe_read);
zfree(g_pserver->rdb_pipe_conns);
close(args->safe_to_exit_pipe);
g_pserver->rdb_pipe_conns = NULL;
g_pserver->rdb_pipe_numconns = 0;
g_pserver->rdb_pipe_numconns_writing = 0;
args->rsi.~rdbSaveInfo();
zfree(args);
closeChildInfoPipe();
return C_ERR;
}
pthread_attr_destroy(&tattr);
g_pserver->child_type = CHILD_TYPE_RDB;
serverLog(LL_NOTICE,"Background RDB transfer started");
g_pserver->rdb_save_time_start = time(NULL);
serverAssert(!g_pserver->rdbThreadVars.fRdbThreadActive);
g_pserver->rdbThreadVars.rdb_child_thread = child;
g_pserver->rdbThreadVars.fRdbThreadActive = true;
g_pserver->rdb_child_type = RDB_CHILD_TYPE_SOCKET;
aePostFunction(g_pserver->rgthreadvar[IDX_EVENT_LOOP_MAIN].el, []{
if (aeCreateFileEvent(serverTL->el, g_pserver->rdb_pipe_read, AE_READABLE, rdbPipeReadHandler,NULL) == AE_ERR) {
serverPanic("Unrecoverable error creating server.rdb_pipe_read file event.");
rioFreeFd(&rdb);
/* wake up the reader, tell it we're done. */
close(args->rdb_pipe_write);
close(g_pserver->rdb_child_exit_pipe); /* close write end so that we can detect the close on the parent. */
/* hold exit until the parent tells us it's safe. we're not expecting
* to read anything, just get the error when the pipe is closed. */
dummy = read(args->safe_to_exit_pipe, pipefds, 1);
UNUSED(dummy);
exitFromChild((retval == C_OK) ? 0 : 1);
} else {
/* Parent */
close(args->safe_to_exit_pipe);
if (childpid == -1) {
serverLog(LL_WARNING,"Can't save in background: fork: %s",
strerror(errno));
/* Undo the state change. The caller will perform cleanup on
* all the slaves in BGSAVE_START state, but an early call to
* replicationSetupSlaveForFullResync() turned it into BGSAVE_END */
listRewind(g_pserver->slaves,&li);
while((ln = listNext(&li))) {
client *replica = (client*)ln->value;
if (replica->replstate == SLAVE_STATE_WAIT_BGSAVE_END) {
replica->replstate = SLAVE_STATE_WAIT_BGSAVE_START;
}
}
close(args->rdb_pipe_write);
close(g_pserver->rdb_pipe_read);
zfree(g_pserver->rdb_pipe_conns);
g_pserver->rdb_pipe_conns = NULL;
g_pserver->rdb_pipe_numconns = 0;
g_pserver->rdb_pipe_numconns_writing = 0;
args->rsi.~rdbSaveInfo();
zfree(args);
} else {
serverLog(LL_NOTICE,"Background RDB transfer started by pid %ld",
(long)childpid);
g_pserver->rdb_save_time_start = time(NULL);
g_pserver->rdb_child_type = RDB_CHILD_TYPE_SOCKET;
g_pserver->rdbThreadVars.fRdbThreadActive = true;
updateDictResizePolicy();
close(args->rdb_pipe_write); /* close write in parent so that it can detect the close on the child. */
aePostFunction(g_pserver->rgthreadvar[IDX_EVENT_LOOP_MAIN].el, []{
if (aeCreateFileEvent(serverTL->el, g_pserver->rdb_pipe_read, AE_READABLE, rdbPipeReadHandler, nullptr) == AE_ERR) {
serverPanic("Unrecoverable error creating g_pserver->rdb_pipe_read file event.");
}
});
}
return (childpid == -1) ? C_ERR : C_OK;
}
});
}
else {
openChildInfoPipe();
for (int idb = 0; idb < cserver.dbnum; ++idb)
args->rgpdb[idb] = g_pserver->db[idb]->createSnapshot(getMvccTstamp(), false /*fOptional*/);
g_pserver->rdbThreadVars.tmpfileNum++;
g_pserver->rdbThreadVars.fRdbThreadCancel = false;
pthread_attr_t tattr;
pthread_attr_init(&tattr);
pthread_attr_setstacksize(&tattr, 1 << 23); // 8 MB
if (pthread_create(&child, &tattr, rdbSaveToSlavesSocketsThread, args)) {
pthread_attr_destroy(&tattr);
serverLog(LL_WARNING,"Can't save in background: fork: %s",
strerror(errno));
/* Undo the state change. The caller will perform cleanup on
* all the slaves in BGSAVE_START state, but an early call to
* replicationSetupSlaveForFullResync() turned it into BGSAVE_END */
listRewind(g_pserver->slaves,&li);
while((ln = listNext(&li))) {
client *replica = (client*)ln->value;
if (replica->replstate == SLAVE_STATE_WAIT_BGSAVE_END) {
replica->replstate = SLAVE_STATE_WAIT_BGSAVE_START;
}
}
close(args->rdb_pipe_write);
close(g_pserver->rdb_pipe_read);
zfree(g_pserver->rdb_pipe_conns);
close(args->safe_to_exit_pipe);
g_pserver->rdb_pipe_conns = NULL;
g_pserver->rdb_pipe_numconns = 0;
g_pserver->rdb_pipe_numconns_writing = 0;
args->rsi.~rdbSaveInfo();
zfree(args);
closeChildInfoPipe();
return C_ERR;
}
pthread_attr_destroy(&tattr);
g_pserver->child_type = CHILD_TYPE_RDB;
serverLog(LL_NOTICE,"Background RDB transfer started");
g_pserver->rdb_save_time_start = time(NULL);
serverAssert(!g_pserver->rdbThreadVars.fRdbThreadActive);
g_pserver->rdbThreadVars.rdb_child_thread = child;
g_pserver->rdbThreadVars.fRdbThreadActive = true;
g_pserver->rdb_child_type = RDB_CHILD_TYPE_SOCKET;
aePostFunction(g_pserver->rgthreadvar[IDX_EVENT_LOOP_MAIN].el, []{
if (aeCreateFileEvent(serverTL->el, g_pserver->rdb_pipe_read, AE_READABLE, rdbPipeReadHandler, nullptr) == AE_ERR) {
serverPanic("Unrecoverable error creating server.rdb_pipe_read file event.");
}
});
}
return C_OK; /* Unreached. */
}
+1
View File
@@ -151,6 +151,7 @@ int rdbLoad(rdbSaveInfo *rsi, int rdbflags);
int rdbLoadFile(const char *filename, rdbSaveInfo *rsi, int rdbflags);
int rdbSaveBackground(rdbSaveInfo *rsi);
int rdbSaveToSlavesSockets(rdbSaveInfo *rsi);
void getTempFileName(char tmpfile[], int tmpfileNum);
void rdbRemoveTempFile(pid_t childpid, int from_signal);
int rdbSave(const redisDbPersistentDataSnapshot **rgpdb, rdbSaveInfo *rsi);
int rdbSaveFile(char *filename, const redisDbPersistentDataSnapshot **rgpdb, rdbSaveInfo *rsi);
+5 -3
View File
@@ -3797,9 +3797,11 @@ int connectWithMaster(redisMaster *mi) {
connSetPrivateData(mi->repl_transfer_s, mi);
if (connConnect(mi->repl_transfer_s, mi->masterhost, mi->masterport,
NET_FIRST_BIND_ADDR, syncWithMaster) == C_ERR) {
int sev = g_pserver->enable_multimaster ? LL_NOTICE : LL_WARNING; // with multimaster its not unheard of to intentiallionall have downed masters
serverLog(sev,"Unable to connect to MASTER: %s",
connGetLastError(mi->repl_transfer_s));
const char *err = "Unknown Error";
if (mi->repl_transfer_s->last_errno != 0)
err = connGetLastError(mi->repl_transfer_s);
int sev = g_pserver->enable_multimaster ? LL_NOTICE : LL_WARNING; // with multimaster its not unheard of to intentionally have downed masters
serverLog(sev, "Unable to connect to MASTER: %s", err);
connClose(mi->repl_transfer_s);
mi->repl_transfer_s = NULL;
return C_ERR;
+3
View File
@@ -1264,6 +1264,9 @@ void scriptingInit(int setup) {
/* Finally set the table as 'redis' global var. */
lua_setglobal(lua,"redis");
/* Set table as 'keydb' global var as well */
lua_getglobal(lua,"redis");
lua_setglobal(lua,"keydb");
/* Replace math.random and math.randomseed with our implementations. */
lua_getglobal(lua,"math");
+1 -1
View File
@@ -5172,7 +5172,7 @@ int prepareForShutdown(int flags) {
* to unlink file actully) in background thread.
* The temp rdb file fd may won't be closed when redis exits quickly,
* but OS will close this fd when process exits. */
rdbRemoveTempFile(g_pserver->child_pid, 0);
rdbRemoveTempFile(g_pserver->rdbThreadVars.tmpfileNum, 0);
}
/* Kill module child if there is one. */
+10 -6
View File
@@ -1209,7 +1209,7 @@ public:
bool FSnapshot() const { return m_spdbSnapshotHOLDER != nullptr; }
std::unique_ptr<const StorageCache> CloneStorageCache() { return std::unique_ptr<const StorageCache>(m_spstorage->clone()); }
void bulkStorageInsert(char **rgKeys, size_t *rgcbKeys, char **rgVals, size_t *rgcbVals, size_t celem);
void bulkDirectStorageInsert(char **rgKeys, size_t *rgcbKeys, char **rgVals, size_t *rgcbVals, size_t celem);
dict_iter find_cached_threadsafe(const char *key) const;
@@ -1370,7 +1370,7 @@ struct redisDb : public redisDbPersistentDataSnapshot
using redisDbPersistentData::FRehashing;
using redisDbPersistentData::FTrackingChanges;
using redisDbPersistentData::CloneStorageCache;
using redisDbPersistentData::bulkStorageInsert;
using redisDbPersistentData::bulkDirectStorageInsert;
public:
const redisDbPersistentDataSnapshot *createSnapshot(uint64_t mvccCheckpoint, bool fOptional) {
@@ -2729,9 +2729,13 @@ struct redisServer {
long long repl_batch_offStart = -1;
long long repl_batch_idxStart = -1;
long long rand_total_threshold;
int config_soft_shutdown = false;
bool soft_shutdown = false;
int flash_disable_key_cache = false;
/* Lock Contention Ring Buffer */
static const size_t s_lockContentionSamples = 64;
uint16_t rglockSamples[s_lockContentionSamples];
@@ -3894,13 +3898,13 @@ void incrementMvccTstamp();
#if __GNUC__ >= 7 && !defined(NO_DEPRECATE_FREE)
[[deprecated]]
void *calloc(size_t count, size_t size);
void *calloc(size_t count, size_t size) noexcept;
[[deprecated]]
void free(void *ptr);
void free(void *ptr) noexcept;
[[deprecated]]
void *malloc(size_t size);
void *malloc(size_t size) noexcept;
[[deprecated]]
void *realloc(void *ptr, size_t size);
void *realloc(void *ptr, size_t size) noexcept;
#endif
/* Debugging stuff */
+10 -2
View File
@@ -729,6 +729,10 @@ void hincrbyfloatCommand(client *c) {
unsigned int vlen;
if (getLongDoubleFromObjectOrReply(c,c->argv[3],&incr,NULL) != C_OK) return;
if (isnan(incr) || isinf(incr)) {
addReplyError(c,"value is NaN or Infinity");
return;
}
if ((o = hashTypeLookupWriteOrCreate(c,c->argv[1])) == NULL) return;
if (hashTypeGetValue(o,szFromObj(c->argv[2]),&vstr,&vlen,&ll) == C_OK) {
if (vstr) {
@@ -1062,6 +1066,8 @@ void hrandfieldWithCountCommand(client *c, long l, int withvalues) {
addReplyBulkCBuffer(c, key, sdslen(key));
if (withvalues)
addReplyBulkCBuffer(c, value, sdslen(value));
if (c->flags & CLIENT_CLOSE_ASAP)
break;
}
} else if (hash->encoding == OBJ_ENCODING_ZIPLIST) {
ziplistEntry *keys, *vals = NULL;
@@ -1075,6 +1081,8 @@ void hrandfieldWithCountCommand(client *c, long l, int withvalues) {
count -= sample_count;
ziplistRandomPairs((unsigned char*)ptrFromObj(hash), sample_count, keys, vals);
harndfieldReplyWithZiplist(c, sample_count, keys, vals);
if (c->flags & CLIENT_CLOSE_ASAP)
break;
}
zfree(keys);
zfree(vals);
@@ -1221,13 +1229,13 @@ void hrandfieldCommand(client *c) {
ziplistEntry ele;
if (c->argc >= 3) {
if (getLongFromObjectOrReply(c,c->argv[2],&l,NULL) != C_OK) return;
if (getRangeLongFromObjectOrReply(c,c->argv[2],-LONG_MAX,LONG_MAX,&l,NULL) != C_OK) return;
if (c->argc > 4 || (c->argc == 4 && strcasecmp(szFromObj(c->argv[3]),"withvalues"))) {
addReplyErrorObject(c,shared.syntaxerr);
return;
} else if (c->argc == 4) {
withvalues = 1;
if (l < LONG_MIN/2 || l > LONG_MAX/2) {
if (l < -g_pserver->rand_total_threshold || l > g_pserver->rand_total_threshold) {
addReplyError(c,"value is out of range");
return;
}
+7 -1
View File
@@ -672,7 +672,11 @@ void srandmemberWithCountCommand(client *c) {
dict *d;
if (getLongFromObjectOrReply(c,c->argv[2],&l,NULL) != C_OK) return;
if (getRangeLongFromObjectOrReply(c,c->argv[2],-LONG_MAX,LONG_MAX,&l,NULL) != C_OK) return;
if (l < -g_pserver->rand_total_threshold || l > g_pserver->rand_total_threshold) {
addReplyError(c,"value is out of range");
return;
}
if (l >= 0) {
count = (unsigned long) l;
} else {
@@ -706,6 +710,8 @@ void srandmemberWithCountCommand(client *c) {
} else {
addReplyBulkCBuffer(c,ele,sdslen(ele));
}
if (c->flags & CLIENT_CLOSE_ASAP)
break;
}
return;
}
+6 -2
View File
@@ -4054,6 +4054,8 @@ void zrandmemberWithCountCommand(client *c, long l, int withscores) {
addReplyBulkCBuffer(c, key, sdslen(key));
if (withscores)
addReplyDouble(c, *(double*)dictGetVal(de));
if (c->flags & CLIENT_CLOSE_ASAP)
break;
}
} else if (zsetobj->encoding == OBJ_ENCODING_ZIPLIST) {
ziplistEntry *keys, *vals = NULL;
@@ -4067,6 +4069,8 @@ void zrandmemberWithCountCommand(client *c, long l, int withscores) {
count -= sample_count;
ziplistRandomPairs((unsigned char*)ptrFromObj(zsetobj), sample_count, keys, vals);
zarndmemberReplyWithZiplist(c, sample_count, keys, vals);
if (c->flags & CLIENT_CLOSE_ASAP)
break;
}
zfree(keys);
zfree(vals);
@@ -4210,13 +4214,13 @@ void zrandmemberCommand(client *c) {
ziplistEntry ele;
if (c->argc >= 3) {
if (getLongFromObjectOrReply(c,c->argv[2],&l,NULL) != C_OK) return;
if (getRangeLongFromObjectOrReply(c,c->argv[2],-LONG_MAX,LONG_MAX,&l,NULL) != C_OK) return;
if (c->argc > 4 || (c->argc == 4 && strcasecmp(szFromObj(c->argv[3]),"withscores"))) {
addReplyErrorObject(c,shared.syntaxerr);
return;
} else if (c->argc == 4) {
withscores = 1;
if (l < LONG_MIN/2 || l > LONG_MAX/2) {
if (l < -g_pserver->rand_total_threshold || l > g_pserver->rand_total_threshold) {
addReplyError(c,"value is out of range");
return;
}
+13 -13
View File
@@ -80,12 +80,12 @@ static_assert((PREFIX_SIZE % 16) == 0, "Our prefix must be modulo 16-bytes or ou
#define realloc(ptr,size, type) tc_realloc(ptr,size)
#define free(ptr) tc_free(ptr)
#elif defined(USE_JEMALLOC)
#define malloc(size, type) je_malloc(size)
#define calloc(count,size,type) je_calloc(count,size)
#define realloc(ptr,size,type) je_realloc(ptr,size)
#define free(ptr) je_free(ptr)
#define mallocx(size,flags) je_mallocx(size,flags)
#define dallocx(ptr,flags) je_dallocx(ptr,flags)
#define malloc(size, type) malloc(size)
#define calloc(count,size,type) calloc(count,size)
#define realloc(ptr,size,type) realloc(ptr,size)
#define free(ptr) free(ptr)
#define mallocx(size,flags) mallocx(size,flags)
#define dallocx(ptr,flags) dallocx(ptr,flags)
#else
#define malloc(size, type) malloc(size)
#define calloc(count,size,type) calloc(count,size)
@@ -494,17 +494,17 @@ int zmalloc_get_allocator_info(size_t *allocated,
*allocated = *resident = *active = 0;
/* Update the statistics cached by mallctl. */
sz = sizeof(epoch);
je_mallctl("epoch", &epoch, &sz, &epoch, sz);
mallctl("epoch", &epoch, &sz, &epoch, sz);
sz = sizeof(size_t);
/* Unlike RSS, this does not include RSS from shared libraries and other non
* heap mappings. */
je_mallctl("stats.resident", resident, &sz, NULL, 0);
mallctl("stats.resident", resident, &sz, NULL, 0);
/* Unlike resident, this doesn't not include the pages jemalloc reserves
* for re-use (purge will clean that). */
je_mallctl("stats.active", active, &sz, NULL, 0);
mallctl("stats.active", active, &sz, NULL, 0);
/* Unlike zmalloc_used_memory, this matches the stats.resident by taking
* into account all allocations done by this process (not only zmalloc). */
je_mallctl("stats.allocated", allocated, &sz, NULL, 0);
mallctl("stats.allocated", allocated, &sz, NULL, 0);
return 1;
}
@@ -512,7 +512,7 @@ void set_jemalloc_bg_thread(int enable) {
/* let jemalloc do purging asynchronously, required when there's no traffic
* after flushdb */
char val = !!enable;
je_mallctl("background_thread", NULL, 0, &val, 1);
mallctl("background_thread", NULL, 0, &val, 1);
}
int jemalloc_purge() {
@@ -520,9 +520,9 @@ int jemalloc_purge() {
char tmp[32];
unsigned narenas = 0;
size_t sz = sizeof(unsigned);
if (!je_mallctl("arenas.narenas", &narenas, &sz, NULL, 0)) {
if (!mallctl("arenas.narenas", &narenas, &sz, NULL, 0)) {
snprintf(tmp, sizeof(tmp), "arena.%d.purge", narenas);
if (!je_mallctl(tmp, NULL, 0, NULL, 0))
if (!mallctl(tmp, NULL, 0, NULL, 0))
return 0;
}
return -1;
+1 -1
View File
@@ -55,7 +55,7 @@
#include <jemalloc/jemalloc.h>
#if (JEMALLOC_VERSION_MAJOR == 2 && JEMALLOC_VERSION_MINOR >= 1) || (JEMALLOC_VERSION_MAJOR > 2)
#define HAVE_MALLOC_SIZE 1
#define zmalloc_size(p) je_malloc_usable_size(p)
#define zmalloc_size(p) malloc_usable_size(p)
#else
#error "Newer version of jemalloc required"
#endif
+4 -3
View File
@@ -162,15 +162,16 @@ start_server {tags {"introspection"}} {
aof_rewrite_cpulist
time-thread-priority
bgsave_cpulist
storage-cache-mode
storage-provider-options
use-fork
storage-cache-mode
storage-provider-options
use-fork
multi-master
active-replica
bind
set-proc-title
repl-backlog-disk-reserve
tls-allowlist
db-s3-object
}
if {!$::tls} {
+8
View File
@@ -182,4 +182,12 @@ start_server {tags {"obuf-limits"} overrides { server-threads 1 }} {
assert_equal "v2" [r get k2]
assert_equal "v3" [r get k3]
}
test "Obuf limit, HRANDFIELD with huge count stopped mid-run" {
r config set client-output-buffer-limit {normal 1000000 0 0}
r hset myhash a b
catch {r hrandfield myhash -999999999} e
assert_match "*I/O error*" $e
reconnect
}
}
+6 -1
View File
@@ -43,10 +43,15 @@ start_server {tags {"scripting"}} {
r eval {return redis.call('get',KEYS[1])} 1 mykey
} {myval}
test { EVAL - keys command works? } {
test {EVAL - keys command works? } {
r eval {return redis.call('keys', 'test')} 0
}
test {EVAL - KeyDB global works } {
r eval {return keydb.call('get', KEYS[1])} 1 mykey
assert_equal [r eval {return redis.call('get',KEYS[1])} 1 mykey] [r eval {return keydb.call('get', KEYS[1])} 1 mykey]
}
test {EVALSHA - Can we call a SHA1 if already defined?} {
r evalsha fd758d1589d044dd850a6f05d52f2eefd27f033f 1 mykey
} {myval}
+6
View File
@@ -71,6 +71,8 @@ start_server {tags {"hash"}} {
test "HRANDFIELD count overflow" {
r hmset myhash a 1
assert_error {*value is out of range*} {r hrandfield myhash -9223372036854770000 withvalues}
assert_error {*value is out of range*} {r hrandfield myhash -9223372036854775808 withvalues}
assert_error {*value is out of range*} {r hrandfield myhash -9223372036854775808}
} {}
test "HRANDFIELD with <count> against non existing key" {
@@ -831,4 +833,8 @@ start_server {tags {"hash"}} {
set _ $k
} {ZIP_INT_8B 127 ZIP_INT_16B 32767 ZIP_INT_32B 2147483647 ZIP_INT_64B 9223372036854775808 ZIP_INT_IMM_MIN 0 ZIP_INT_IMM_MAX 12}
test {HINCRBYFLOAT does not allow NaN or Infinity} {
assert_error "*value is NaN or Infinity*" {r hincrbyfloat hfoo field +inf}
assert_equal 0 [r exists hfoo]
}
}
+5
View File
@@ -588,6 +588,11 @@ start_server {
r srandmember nonexisting_key 100
} {}
test "SRANDMEMBER count overflow" {
r sadd myset a
assert_error {*value is out of range*} {r srandmember myset -9223372036854775808}
} {}
# Make sure we can distinguish between an empty array and a null response
r readraw 1
+2
View File
@@ -1717,6 +1717,8 @@ start_server {tags {"zset"}} {
test "ZRANDMEMBER count overflow" {
r zadd myzset 0 a
assert_error {*value is out of range*} {r zrandmember myzset -9223372036854770000 withscores}
assert_error {*value is out of range*} {r zrandmember myzset -9223372036854775808 withscores}
assert_error {*value is out of range*} {r zrandmember myzset -9223372036854775808}
} {}
# Make sure we can distinguish between an empty array and a null response
+7 -1
View File
@@ -26,7 +26,11 @@ then
while [ $((PORT < ENDPORT)) != "0" ]; do
PORT=$((PORT+1))
echo "Starting $PORT"
$BIN_PATH/keydb-server --port $PORT --protected-mode $PROTECTED_MODE --cluster-enabled yes --cluster-config-file nodes-${PORT}.conf --cluster-node-timeout $TIMEOUT --appendonly yes --appendfilename appendonly-${PORT}.aof --dbfilename dump-${PORT}.rdb --logfile ${PORT}.log --daemonize yes ${ADDITIONAL_OPTIONS}
if [ "$2" == "flash" ]
then
ADDITIONAL_OPTIONS="--save \"\" \"\" \"\" --semi-ordered-set-bucket-size 8 --client-output-buffer-limit replica 1 1 0 --maxmemory 100000000 --storage-provider flash ./$PORT.flash"
fi
$BIN_PATH/keydb-server --server-threads 4 --port $PORT --protected-mode $PROTECTED_MODE --cluster-enabled yes --cluster-config-file nodes-${PORT}.conf --cluster-node-timeout $TIMEOUT --dbfilename dump-${PORT}.rdb --logfile ${PORT}.log --daemonize yes ${ADDITIONAL_OPTIONS}
done
exit 0
fi
@@ -97,6 +101,8 @@ then
rm -rf appendonly*.aof
rm -rf dump*.rdb
rm -rf nodes*.conf
rm -rf *.flash
rm -rf temp*.rdb
exit 0
fi