Hold GCRA out of the release (#15191)
Some checks failed
CI / test-ubuntu-latest (push) Waiting to run
CI / test-sanitizer-address (push) Waiting to run
CI / build-debian-old (push) Waiting to run
CI / build-macos-latest (push) Waiting to run
CI / build-32bit (push) Waiting to run
CI / build-libc-malloc (push) Waiting to run
CI / build-centos-jemalloc (push) Waiting to run
CI / build-old-chain-jemalloc (push) Waiting to run
Codecov / code-coverage (push) Waiting to run
External Server Tests / test-external-standalone (push) Waiting to run
External Server Tests / test-external-cluster (push) Waiting to run
External Server Tests / test-external-nodebug (push) Waiting to run
Spellcheck / Spellcheck (push) Waiting to run
Reply-schemas linter / reply-schemas-linter (push) Has been cancelled

After introducing GCRA algorithm into redis
https://github.com/redis/redis/pull/14826 and subsequent introduction of
new RATE_LIMIT object type - https://github.com/redis/redis/pull/14905.
It was internally decided not to introduce GCRA into the new release.

As still no decision is made on whether it will be kept or not in the
future, this PR only makes the code related to GCRA dead - commands are
inaccessible and AOF/RDB load+save is disabled.

---------

Co-authored-by: debing.sun <debing.sun@redis.com>
This commit is contained in:
Mincho Paskalev 2026-05-14 16:31:25 +03:00 committed by GitHub
parent c3db5254b7
commit 2e46d2e735
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
25 changed files with 117 additions and 219 deletions

View file

@ -2051,7 +2051,6 @@ latency-monitor-threshold 0
# (Note: not included in the 'A' class)
# c Type-changed events generated every time a key's type changes
# (Note: not included in the 'A' class)
# r rate limit event
# S Subkeyspace events, published with __subkeyspace@<db>__:<key> prefix.
# T Subkeyevent events, published with __subkeyevent@<db>__:<event> prefix.
# I Subkeyspaceitem events, published per subkey with
@ -2059,7 +2058,7 @@ latency-monitor-threshold 0
# V Subkeyspaceevent events, published with
# __subkeyspaceevent@<db>__:<event>|<key> prefix.
# A Alias for g$lshzxetad, so that the "AKE" string means all the events
# except key-miss, new key, overwritten, type-changed and rate-limit.
# except key-miss, new key, overwritten and type-changed.
#
# The "notify-keyspace-events" takes as argument a string that is composed
# of zero or multiple characters. The empty string means that notifications

View file

@ -71,7 +71,9 @@ struct ACLCategoryItem {
{"connection", ACL_CATEGORY_CONNECTION},
{"transaction", ACL_CATEGORY_TRANSACTION},
{"scripting", ACL_CATEGORY_SCRIPTING},
#ifdef ENABLE_GCRA
{"ratelimit", ACL_CATEGORY_RATE_LIMIT},
#endif
{NULL,0} /* Terminator. */
};

View file

@ -2467,6 +2467,7 @@ int rewriteStreamObject(rio *r, robj *key, robj *o) {
return 1;
}
#ifdef ENABLE_GCRA
int rewriteGCRAObject(rio *r, robj *key, robj *o) {
long long val;
getLongLongFromGCRAObject(o, &val);
@ -2478,6 +2479,7 @@ int rewriteGCRAObject(rio *r, robj *key, robj *o) {
if (rioWriteBulkLongLong(r,val) == 0) return 0;
return 1;
}
#endif
/* Call the module type callback in order to rewrite a data type
* that is exported by a module and is not handled by Redis itself.
@ -2644,8 +2646,10 @@ int rewriteObject(rio *r, robj *key, robj *o, int dbid, long long expiretime) {
if (rewriteHashObject(r,key,o) == 0) return C_ERR;
} else if (o->type == OBJ_STREAM) {
if (rewriteStreamObject(r,key,o) == 0) return C_ERR;
#ifdef ENABLE_GCRA
} else if (o->type == OBJ_GCRA) {
if (rewriteGCRAObject(r,key,o) == 0) return C_ERR;
#endif
} else if (o->type == OBJ_ARRAY) {
if (rewriteArrayObject(r,key,o) == 0) return C_ERR;
} else if (o->type == OBJ_MODULE) {

View file

@ -26,7 +26,9 @@ const char *COMMAND_GROUP_STR[] = {
"bitmap",
"array",
"module",
#ifdef ENABLE_GCRA
"rate_limit"
#endif
};
const char *commandGroupStr(int index) {
@ -5910,59 +5912,6 @@ struct COMMAND_ARG UNSUBSCRIBE_Args[] = {
{MAKE_ARG("channel",ARG_TYPE_STRING,-1,NULL,NULL,NULL,CMD_ARG_OPTIONAL|CMD_ARG_MULTIPLE,0,NULL)},
};
/********** GCRA ********************/
#ifndef SKIP_CMD_HISTORY_TABLE
/* GCRA history */
#define GCRA_History NULL
#endif
#ifndef SKIP_CMD_TIPS_TABLE
/* GCRA tips */
#define GCRA_Tips NULL
#endif
#ifndef SKIP_CMD_KEY_SPECS_TABLE
/* GCRA key specs */
keySpec GCRA_Keyspecs[1] = {
{NULL,CMD_KEY_RW|CMD_KEY_ACCESS|CMD_KEY_UPDATE,KSPEC_BS_INDEX,.bs.index={1},KSPEC_FK_RANGE,.fk.range={0,1,0}}
};
#endif
/* GCRA argument table */
struct COMMAND_ARG GCRA_Args[] = {
{MAKE_ARG("key",ARG_TYPE_KEY,0,NULL,NULL,NULL,CMD_ARG_NONE,0,NULL)},
{MAKE_ARG("max-burst",ARG_TYPE_INTEGER,-1,NULL,NULL,NULL,CMD_ARG_NONE,0,NULL)},
{MAKE_ARG("tokens-per-period",ARG_TYPE_INTEGER,-1,NULL,NULL,NULL,CMD_ARG_NONE,0,NULL)},
{MAKE_ARG("period",ARG_TYPE_DOUBLE,-1,NULL,NULL,NULL,CMD_ARG_NONE,0,NULL)},
{MAKE_ARG("count",ARG_TYPE_INTEGER,-1,"TOKENS",NULL,NULL,CMD_ARG_OPTIONAL,0,NULL)},
};
/********** GCRASETVALUE ********************/
#ifndef SKIP_CMD_HISTORY_TABLE
/* GCRASETVALUE history */
#define GCRASETVALUE_History NULL
#endif
#ifndef SKIP_CMD_TIPS_TABLE
/* GCRASETVALUE tips */
#define GCRASETVALUE_Tips NULL
#endif
#ifndef SKIP_CMD_KEY_SPECS_TABLE
/* GCRASETVALUE key specs */
keySpec GCRASETVALUE_Keyspecs[1] = {
{NULL,CMD_KEY_OW|CMD_KEY_UPDATE,KSPEC_BS_INDEX,.bs.index={1},KSPEC_FK_RANGE,.fk.range={0,1,0}}
};
#endif
/* GCRASETVALUE argument table */
struct COMMAND_ARG GCRASETVALUE_Args[] = {
{MAKE_ARG("key",ARG_TYPE_KEY,0,NULL,NULL,NULL,CMD_ARG_NONE,0,NULL)},
{MAKE_ARG("tat",ARG_TYPE_INTEGER,-1,NULL,NULL,NULL,CMD_ARG_NONE,0,NULL)},
};
/********** EVAL ********************/
#ifndef SKIP_CMD_HISTORY_TABLE
@ -12556,9 +12505,6 @@ struct COMMAND_STRUCT redisCommandTable[] = {
{MAKE_CMD("subscribe","Listens for messages published to channels.","O(N) where N is the number of channels to subscribe to.","2.0.0",CMD_DOC_NONE,NULL,NULL,"pubsub",COMMAND_GROUP_PUBSUB,SUBSCRIBE_History,0,SUBSCRIBE_Tips,0,subscribeCommand,-2,CMD_PUBSUB|CMD_NOSCRIPT|CMD_LOADING|CMD_STALE|CMD_SENTINEL|CMD_DENYOOM,0,SUBSCRIBE_Keyspecs,0,NULL,1),.args=SUBSCRIBE_Args},
{MAKE_CMD("sunsubscribe","Stops listening to messages posted to shard channels.","O(N) where N is the number of shard channels to unsubscribe.","7.0.0",CMD_DOC_NONE,NULL,NULL,"pubsub",COMMAND_GROUP_PUBSUB,SUNSUBSCRIBE_History,0,SUNSUBSCRIBE_Tips,0,sunsubscribeCommand,-1,CMD_PUBSUB|CMD_NOSCRIPT|CMD_LOADING|CMD_STALE,0,SUNSUBSCRIBE_Keyspecs,1,NULL,1),.args=SUNSUBSCRIBE_Args},
{MAKE_CMD("unsubscribe","Stops listening to messages posted to channels.","O(N) where N is the number of channels to unsubscribe.","2.0.0",CMD_DOC_NONE,NULL,NULL,"pubsub",COMMAND_GROUP_PUBSUB,UNSUBSCRIBE_History,0,UNSUBSCRIBE_Tips,0,unsubscribeCommand,-1,CMD_PUBSUB|CMD_NOSCRIPT|CMD_LOADING|CMD_STALE|CMD_SENTINEL,0,UNSUBSCRIBE_Keyspecs,0,NULL,1),.args=UNSUBSCRIBE_Args},
/* rate_limit */
{MAKE_CMD("gcra","Rate limit via GCRA (Generic Cell Rate Algorithm).","O(1)","8.8.0",CMD_DOC_NONE,NULL,NULL,"rate_limit",COMMAND_GROUP_RATE_LIMIT,GCRA_History,0,GCRA_Tips,0,gcraCommand,-5,CMD_WRITE|CMD_DENYOOM|CMD_FAST,ACL_CATEGORY_RATE_LIMIT,GCRA_Keyspecs,1,NULL,5),.args=GCRA_Args},
{MAKE_CMD("gcrasetvalue","An internal command for recording a GCRA TAT value during AOF rewrite and replication.","O(1)","8.8.0",CMD_DOC_NONE,NULL,NULL,"rate_limit",COMMAND_GROUP_RATE_LIMIT,GCRASETVALUE_History,0,GCRASETVALUE_Tips,0,gcraSetValueCommand,3,CMD_WRITE|CMD_DENYOOM|CMD_FAST,ACL_CATEGORY_RATE_LIMIT,GCRASETVALUE_Keyspecs,1,NULL,2),.args=GCRASETVALUE_Args},
/* scripting */
{MAKE_CMD("eval","Executes a server-side Lua script.","Depends on the script that is executed.","2.6.0",CMD_DOC_NONE,NULL,NULL,"scripting",COMMAND_GROUP_SCRIPTING,EVAL_History,0,EVAL_Tips,0,evalCommand,-3,CMD_NOSCRIPT|CMD_SKIP_MONITOR|CMD_MAY_REPLICATE|CMD_NO_MANDATORY_KEYS|CMD_STALE,ACL_CATEGORY_SCRIPTING,EVAL_Keyspecs,1,evalGetKeys,4),.args=EVAL_Args},
{MAKE_CMD("evalsha","Executes a server-side Lua script by SHA1 digest.","Depends on the script that is executed.","2.6.0",CMD_DOC_NONE,NULL,NULL,"scripting",COMMAND_GROUP_SCRIPTING,EVALSHA_History,0,EVALSHA_Tips,0,evalShaCommand,-3,CMD_NOSCRIPT|CMD_SKIP_MONITOR|CMD_MAY_REPLICATE|CMD_NO_MANDATORY_KEYS|CMD_STALE,ACL_CATEGORY_SCRIPTING,EVALSHA_Keyspecs,1,evalGetKeys,4),.args=EVALSHA_Args},

View file

@ -1,92 +0,0 @@
{
"GCRA": {
"summary": "Rate limit via GCRA (Generic Cell Rate Algorithm).",
"complexity": "O(1)",
"group": "rate_limit",
"since": "8.8.0",
"arity": -5,
"function": "gcraCommand",
"command_flags": [
"WRITE",
"DENYOOM",
"FAST"
],
"acl_categories": [
"RATE_LIMIT"
],
"key_specs": [
{
"flags": [
"RW",
"ACCESS",
"UPDATE"
],
"begin_search": {
"index": {
"pos": 1
}
},
"find_keys": {
"range": {
"lastkey": 0,
"step": 1,
"limit": 0
}
}
}
],
"reply_schema": {
"type": "array",
"minItems": 5,
"maxItems": 5,
"description": "Rate limiting result",
"items": [
{
"type": "integer",
"description": "Limited: 0 if allowed, 1 if rate limited"
},
{
"type": "integer",
"description": "Max request tokens: always equal to max_burst+1"
},
{
"type": "integer",
"description": "Number of tokens available immediately"
},
{
"type": "integer",
"description": "Retry after: seconds after which the caller should retry. Always -1 if not limited"
},
{
"type": "integer",
"description": "Full burst after: seconds after which a full burst will be allowed"
}
]
},
"arguments": [
{
"name": "key",
"type": "key",
"key_spec_index": 0
},
{
"name": "max-burst",
"type": "integer"
},
{
"name": "tokens-per-period",
"type": "integer"
},
{
"name": "period",
"type": "double"
},
{
"name": "count",
"type": "integer",
"token": "TOKENS",
"optional": true
}
]
}
}

View file

@ -1,52 +0,0 @@
{
"GCRASETVALUE": {
"summary": "An internal command for recording a GCRA TAT value during AOF rewrite and replication.",
"complexity": "O(1)",
"group": "rate_limit",
"since": "8.8.0",
"arity": 3,
"function": "gcraSetValueCommand",
"command_flags": [
"WRITE",
"DENYOOM",
"FAST"
],
"acl_categories": [
"RATE_LIMIT"
],
"key_specs": [
{
"flags": [
"OW",
"UPDATE"
],
"begin_search": {
"index": {
"pos": 1
}
},
"find_keys": {
"range": {
"lastkey": 0,
"step": 1,
"limit": 0
}
}
}
],
"reply_schema": {
"const": "OK"
},
"arguments": [
{
"name": "key",
"type": "key",
"key_spec_index": 0
},
{
"name": "tat",
"type": "integer"
}
]
}
}

View file

@ -2972,7 +2972,11 @@ static int setConfigNotifyKeyspaceEventsOption(standardConfig *config, sds *argv
}
int flags = keyspaceEventsStringToFlags(argv[0]);
if (flags == -1) {
*err = "Invalid event class character. Use 'Ag$lshzxeKEtmdnocrSTIV'.";
#ifdef ENABLE_GCRA
*err = "Invalid event class character. Use 'Ag$lshzxeKEtmdnocraSTIV'.";
#else
*err = "Invalid event class character. Use 'Ag$lshzxeKEtmdnocaSTIV'.";
#endif
return 0;
}
server.notify_keyspace_events = flags;

View file

@ -1758,8 +1758,10 @@ char *obj_type_name[OBJ_TYPE_MAX] = {
"hash",
NULL, /* module type is special */
"stream",
"gcra",
"array"
"array",
#ifdef ENABLE_GCRA
"gcra"
#endif
};
/* Helper function to get type from a string in scan commands */
@ -2434,7 +2436,9 @@ void copyCommand(client *c) {
case OBJ_ZSET: newobj = zsetDup(o); break;
case OBJ_HASH: newobj = hashTypeDup(o, &minHashExpire); break;
case OBJ_STREAM: newobj = streamDup(o); break;
#ifdef ENABLE_GCRA
case OBJ_GCRA: newobj = gcraDup(o); break;
#endif
case OBJ_MODULE:
newobj = moduleTypeDupOrReply(c, key, newkey, dst->id, o);
if (!newobj) return;

View file

@ -123,6 +123,7 @@ void mixStringObjectDigest(unsigned char *digest, robj *o) {
decrRefCount(o);
}
#ifdef ENABLE_GCRA
void mixGCRAObjectDigest(unsigned char *digest, robj *o) {
char buf[LONG_STR_SIZE];
long long val;
@ -130,6 +131,7 @@ void mixGCRAObjectDigest(unsigned char *digest, robj *o) {
int len = ll2string(buf, sizeof(buf), val);
mixDigest(digest,buf,len);
}
#endif
/* This function computes the digest of a data structure stored in the
* object 'o'. It is the core of the DEBUG DIGEST command: when taking the
@ -263,8 +265,10 @@ void xorObjectDigest(redisDb *db, robj *keyobj, unsigned char *digest, robj *o)
}
}
streamIteratorStop(&si);
#ifdef ENABLE_GCRA
} else if (o->type == OBJ_GCRA) {
mixGCRAObjectDigest(digest, o);
#endif
} else if (o->type == OBJ_MODULE) {
RedisModuleDigest md = {{0},{0},keyobj,db->id};
moduleValue *mv = o->ptr;
@ -1327,9 +1331,11 @@ void serverLogObjectDebugInfo(const robj *o) {
serverLog(LL_WARNING,"Skiplist level: %d", (int) ((const zset*)o->ptr)->zsl->level);
} else if (o->type == OBJ_STREAM) {
serverLog(LL_WARNING,"Stream size: %d", (int) streamLength(o));
#ifdef ENABLE_GCRA
} else if (o->type == OBJ_GCRA) {
#if UINTPTR_MAX == 0xffffffffffffffff
serverLog(LL_WARNING, "GCRA object: %lld", (long long)o->ptr);
#endif
#endif
}
#endif

View file

@ -1189,12 +1189,14 @@ void defragKey(defragKeysCtx *ctx, dictEntry *de, dictEntryLink link) {
}
} else if (ob->type == OBJ_STREAM) {
defragStream(ctx, ob);
#ifdef ENABLE_GCRA
} else if (ob->type == OBJ_GCRA) {
/* GCRA object is just an allocation to a long long value */
#if UINTPTR_MAX == 0xffffffff
void *newptr, *ptr = ob->ptr;
if ((newptr = activeDefragAlloc(ptr)))
ob->ptr = newptr;
#endif
#endif
} else if (ob->type == OBJ_MODULE) {
defragModule(ctx,db, ob);

View file

@ -9,6 +9,8 @@
#include "server.h"
#include <math.h>
#ifdef ENABLE_GCRA
/* GCRA algorithm for rate limiting.
* Implementation is heavily based on the implementation of (redis-cell)
* [https://github.com/brandur/redis-cell] by (brandur)[https://github.com/brandur].
@ -278,3 +280,5 @@ robj *gcraDup(robj *o) {
getLongLongFromGCRAObject(o, &val);
return createGCRAObject(val);
}
#endif /* ENABLE_GCRA */

View file

@ -4254,7 +4254,9 @@ int RM_KeyType(RedisModuleKey *key) {
case OBJ_HASH: return REDISMODULE_KEYTYPE_HASH;
case OBJ_MODULE: return REDISMODULE_KEYTYPE_MODULE;
case OBJ_STREAM: return REDISMODULE_KEYTYPE_STREAM;
#ifdef ENABLE_GCRA
case OBJ_GCRA: return REDISMODULE_KEYTYPE_GCRA;
#endif
case OBJ_ARRAY: return REDISMODULE_KEYTYPE_ARRAY;
default: return REDISMODULE_KEYTYPE_EMPTY;
}

View file

@ -41,7 +41,9 @@ int keyspaceEventsStringToFlags(char *classes) {
case 'n': flags |= NOTIFY_NEW; break;
case 'o': flags |= NOTIFY_OVERWRITTEN; break;
case 'c': flags |= NOTIFY_TYPE_CHANGED; break;
#ifdef ENABLE_GCRA
case 'r': flags |= NOTIFY_RATE_LIMIT; break;
#endif
case 'S': flags |= NOTIFY_SUBKEYSPACE; break;
case 'T': flags |= NOTIFY_SUBKEYEVENT; break;
case 'I': flags |= NOTIFY_SUBKEYSPACEITEM; break;
@ -77,7 +79,9 @@ sds keyspaceEventsFlagsToString(int flags) {
if (flags & NOTIFY_NEW) res = sdscatlen(res,"n",1);
if (flags & NOTIFY_OVERWRITTEN) res = sdscatlen(res,"o",1);
if (flags & NOTIFY_TYPE_CHANGED) res = sdscatlen(res,"c",1);
#ifdef ENABLE_GCRA
if (flags & NOTIFY_RATE_LIMIT) res = sdscatlen(res,"r",1);
#endif
}
if (flags & NOTIFY_KEYSPACE) res = sdscatlen(res,"K",1);
if (flags & NOTIFY_KEYEVENT) res = sdscatlen(res,"E",1);

View file

@ -514,6 +514,7 @@ robj *createStreamObject(void) {
return o;
}
#ifdef ENABLE_GCRA
robj *createGCRAObject(long long value) {
/* NOTE: for 32-bit systems we can't use integer encoding (as OBJ_STRING does)
* as the GCRA object is a unixtime value in microseconds, which as of the
@ -530,6 +531,7 @@ robj *createGCRAObject(long long value) {
o->encoding = OBJ_ENCODING_INT;
return o;
}
#endif
robj *createArrayObject(void) {
redisArray *ar = arNew();
@ -610,6 +612,7 @@ void freeStreamObject(robj *o) {
freeStream(o->ptr);
}
#ifdef ENABLE_GCRA
void freeGCRAObject(robj *o) {
#if UINTPTR_MAX == 0xffffffff
zfree(o->ptr);
@ -617,6 +620,7 @@ void freeGCRAObject(robj *o) {
(void)o;
#endif
}
#endif
void freeArrayObject(robj *o) {
arFree(o->ptr);
@ -673,7 +677,9 @@ void decrRefCount(robj *o) {
case OBJ_HASH: freeHashObject(o); break;
case OBJ_MODULE: freeModuleObject(o); break;
case OBJ_STREAM: freeStreamObject(o); break;
#ifdef ENABLE_GCRA
case OBJ_GCRA: freeGCRAObject(o); break;
#endif
case OBJ_ARRAY: freeArrayObject(o); break;
default: serverPanic("Unknown object type"); break;
}
@ -827,12 +833,14 @@ void dismissArrayObject(robj *o, size_t size_hint) {
arDismiss(o->ptr, size_hint);
}
#ifdef ENABLE_GCRA
void dismissGCRAObject(robj *o, size_t size_hint) {
/* GCRA is a single allocation of a long long thus way smaller than a
* page-size. The dismiss mechanism is not needed for it - hence NOOP.*/
(void)o;
(void)size_hint;
}
#endif
/* When creating a snapshot in a fork child process, the main process and child
* process share the same physical memory pages, and if / when the parent
@ -862,7 +870,9 @@ void dismissObject(robj *o, size_t size_hint) {
case OBJ_ZSET: dismissZsetObject(o, size_hint); break;
case OBJ_HASH: dismissHashObject(o, size_hint); break;
case OBJ_STREAM: dismissStreamObject(o, size_hint); break;
#ifdef ENABLE_GCRA
case OBJ_GCRA: dismissGCRAObject(o, size_hint); break;
#endif
case OBJ_ARRAY: dismissArrayObject(o, size_hint); break;
default: break;
}
@ -985,7 +995,9 @@ size_t getObjectLength(robj *o) {
case OBJ_ZSET: return zsetLength(o);
case OBJ_HASH: return hashTypeLength(o, 0);
case OBJ_STREAM: return streamLength(o);
#ifdef ENABLE_GCRA
case OBJ_GCRA: return gcraObjectLength(o);
#endif
case OBJ_ARRAY: return arCount(o->ptr);
default: return 0;
}
@ -1195,6 +1207,7 @@ int getLongLongFromObject(robj *o, long long *target) {
return C_OK;
}
#ifdef ENABLE_GCRA
int getLongLongFromGCRAObject(robj *o, long long *target) {
long long res;
serverAssertWithInfo(NULL, o, o->type == OBJ_GCRA);
@ -1210,6 +1223,7 @@ int getLongLongFromGCRAObject(robj *o, long long *target) {
*target = res;
return C_OK;
}
#endif
int getLongLongFromObjectOrReply(client *c, robj *o, long long *target, const char *msg) {
long long value;
@ -1303,7 +1317,9 @@ size_t kvobjComputeSize(robj *key, kvobj *o, size_t sample_size, int dbid) {
o->type == OBJ_ZSET ||
o->type == OBJ_HASH ||
o->type == OBJ_STREAM ||
#ifdef ENABLE_GCRA
o->type == OBJ_GCRA ||
#endif
o->type == OBJ_ARRAY)
{
return kvobjAllocSize(o);
@ -1330,8 +1346,10 @@ size_t kvobjAllocSize(kvobj *o) {
} else if (o->type == OBJ_STREAM) {
stream *s = o->ptr;
asize += s->alloc_size;
#ifdef ENABLE_GCRA
} else if (o->type == OBJ_GCRA) {
asize += gcraTypeAllocSize(o);
#endif
} else if (o->type == OBJ_ARRAY) {
redisArray *ar = o->ptr;
asize += ar->alloc_size;
@ -1341,6 +1359,7 @@ size_t kvobjAllocSize(kvobj *o) {
return asize;
}
#ifdef ENABLE_GCRA
size_t gcraTypeAllocSize(robj *o) {
(void)o;
#if UINTPTR_MAX == 0xffffffff
@ -1357,6 +1376,7 @@ size_t gcraObjectLength(robj *o) {
(void)o;
return 1;
}
#endif
/* Release data obtained with getMemoryOverheadData(). */
void freeMemoryOverheadData(struct redisMemOverhead *mh) {

View file

@ -5,7 +5,7 @@
* values of different logical types (strings, lists, sets, hashes, sorted sets,
* streams, modules, ...). It contains:
* - type: one of OBJ_STRING, OBJ_LIST, OBJ_SET, OBJ_ZSET, OBJ_HASH, OBJ_STREAM,
* OBJ_GCRA, OBJ_MODULE, ...
* OBJ_MODULE, ...
* - encoding: an implementation detail of how the value is represented in
* memory for the given type (see OBJ_ENCODING_* below). For example,
* strings may be RAW/EMBSTR/INT, sets may be INTSET or HT, etc.

View file

@ -722,8 +722,10 @@ int rdbSaveObjectType(rio *rdb, robj *o) {
serverPanic("Unknown hash encoding");
case OBJ_STREAM:
return rdbSaveType(rdb,RDB_TYPE_STREAM_LISTPACKS_5);
#ifdef ENABLE_GCRA
case OBJ_GCRA:
return rdbSaveType(rdb,RDB_TYPE_GCRA);
#endif
case OBJ_MODULE:
return rdbSaveType(rdb,RDB_TYPE_MODULE_2);
case OBJ_ARRAY:
@ -1474,11 +1476,13 @@ ssize_t rdbSaveObject(rio *rdb, robj *o, robj *key, int dbid) {
/* Save the all-time count of duplicate IIDs detected. */
if ((n = rdbSaveLen(rdb,s->iids_duplicates)) == -1) return -1;
nwritten += n;
#ifdef ENABLE_GCRA
} else if (o->type == OBJ_GCRA) {
long long t;
getLongLongFromGCRAObject(o, &t);
if ((n = rdbSaveLen(rdb,t)) == -1) return -1;
nwritten += n;
#endif
} else if (o->type == OBJ_MODULE) {
/* Save a module-specific value. */
RedisModuleIO io;
@ -3769,6 +3773,7 @@ robj *rdbLoadObject(int rdbtype, rio *rdb, sds key, int dbid, int *error)
return NULL;
}
o = createModuleObject(mt, ptr);
#ifdef ENABLE_GCRA
} else if (rdbtype == RDB_TYPE_GCRA) {
uint64_t time = rdbLoadLen(rdb, NULL);
if (time == RDB_LENERR || time > LLONG_MAX) {
@ -3776,6 +3781,7 @@ robj *rdbLoadObject(int rdbtype, rio *rdb, sds key, int dbid, int *error)
return NULL;
}
o = createGCRAObject((long long)time);
#endif
} else if (rdbtype == RDB_TYPE_ARRAY) {
/* Load array value. We only persist elements and insert_idx - no
* implementation details. Arrays use current ar_slice_size config. */

View file

@ -80,12 +80,18 @@
#define RDB_TYPE_HASH_LISTPACK_EX 25 /* Hash LP with HFEs. Attach min TTL at start */
#define RDB_TYPE_STREAM_LISTPACKS_4 26 /* Stream with IDMP support */
#define RDB_TYPE_STREAM_LISTPACKS_5 27 /* Stream with XNACK support (NACKed entries) */
#define RDB_TYPE_GCRA 28 /* GCRA object */
#define RDB_TYPE_ARRAY 29 /* Array data type */
#define RDB_TYPE_ARRAY 28 /* Array data type */
#ifdef ENABLE_GCRA
#define RDB_TYPE_GCRA 29 /* GCRA object */
#endif
/* NOTE: WHEN ADDING NEW RDB TYPE, UPDATE rdbIsObjectType(), and rdb_type_string[] */
/* Test if a type is an object type. */
#ifdef ENABLE_GCRA
#define rdbIsObjectType(t) (((t) >= 0 && (t) <= 7) || ((t) >= 9 && (t) <= 29))
#else
#define rdbIsObjectType(t) (((t) >= 0 && (t) <= 7) || ((t) >= 9 && (t) <= 28))
#endif
/* Special RDB opcodes (saved/loaded with rdbSaveType/rdbLoadType). */
#define RDB_OPCODE_KEY_META 243 /* Key metadata (module metadata classes). */

View file

@ -88,8 +88,10 @@ char *rdb_type_string[] = {
"hash-listpack-md",
"stream-v4",
"stream-v5",
"gcra",
"array",
#ifdef ENABLE_GCRA
"gcra",
#endif
};
/* Show a few stats collected into 'rdbstate' */

View file

@ -89,8 +89,7 @@ typedef long long ustime_t;
#define REDISMODULE_KEYTYPE_ZSET 5
#define REDISMODULE_KEYTYPE_MODULE 6
#define REDISMODULE_KEYTYPE_STREAM 7
#define REDISMODULE_KEYTYPE_GCRA 8
#define REDISMODULE_KEYTYPE_ARRAY 9
#define REDISMODULE_KEYTYPE_ARRAY 8
/* Reply types. */
#define REDISMODULE_REPLY_UNKNOWN -1
@ -249,18 +248,24 @@ This flag should not be used directly by the module.
#define REDISMODULE_NOTIFY_OVERWRITTEN (1<<15) /* o, key overwrite notification */
#define REDISMODULE_NOTIFY_TYPE_CHANGED (1<<16) /* c, key type changed notification */
#define REDISMODULE_NOTIFY_KEY_TRIMMED (1<<17) /* module only key space notification, indicates a key trimmed during slot migration */
#define REDISMODULE_NOTIFY_RATE_LIMIT (1<<18) /* r, rate limit event */
#define REDISMODULE_NOTIFY_SUBKEYSPACE (1<<19) /* S */
#define REDISMODULE_NOTIFY_SUBKEYEVENT (1<<20) /* T */
#define REDISMODULE_NOTIFY_SUBKEYSPACEITEM (1<<21) /* I */
#define REDISMODULE_NOTIFY_SUBKEYSPACEEVENT (1<<22) /* V */
#define REDISMODULE_NOTIFY_ARRAY (1<<23) /* a, array key space notification */
#ifdef ENABLE_GCRA
#define REDISMODULE_NOTIFY_RATE_LIMIT (1<<24) /* r, rate limit event */
#endif
/* Next notification flag, must be updated when adding new flags above!
This flag should not be used directly by the module.
* Use RedisModule_GetKeyspaceNotificationFlagsAll instead. */
#ifdef ENABLE_GCRA
#define _REDISMODULE_NOTIFY_NEXT (1<<25)
#else
#define _REDISMODULE_NOTIFY_NEXT (1<<24)
#endif
/* Delivery flags for RM_SubscribeToKeyspaceEventsWithSubkeys.
* These are passed in the 'flags' parameter, not in 'types'. */

View file

@ -288,8 +288,10 @@ extern int configOOMScoreAdjValuesDefaults[CONFIG_OOM_COUNT];
#define ACL_CATEGORY_CONNECTION (1ULL<<18)
#define ACL_CATEGORY_TRANSACTION (1ULL<<19)
#define ACL_CATEGORY_SCRIPTING (1ULL<<20)
#define ACL_CATEGORY_RATE_LIMIT (1ULL<<21)
#define ACL_CATEGORY_ARRAY (1ULL<<22)
#define ACL_CATEGORY_ARRAY (1ULL<<21)
#ifdef ENABLE_GCRA
#define ACL_CATEGORY_RATE_LIMIT (1ULL<<22)
#endif
/* Key-spec flags *
* -------------- */
@ -798,12 +800,14 @@ typedef enum {
#define NOTIFY_OVERWRITTEN (1<<15) /* o, key overwrite notification (Note: excluded from NOTIFY_ALL) */
#define NOTIFY_TYPE_CHANGED (1<<16) /* c, key type changed notification (Note: excluded from NOTIFY_ALL) */
#define NOTIFY_KEY_TRIMMED (1<<17) /* module only key space notification, indicates a key trimmed during slot migration */
#define NOTIFY_RATE_LIMIT (1<<18) /* r, notify rate limit event (Note: excluded from NOTIFY_ALL)*/
#define NOTIFY_SUBKEYSPACE (1<<19) /* S, subkey-level keyspace notification */
#define NOTIFY_SUBKEYEVENT (1<<20) /* T, subkey-level keyevent notification */
#define NOTIFY_SUBKEYSPACEITEM (1<<21) /* I, subkey-level notification per item: channel=key\nsubkey */
#define NOTIFY_SUBKEYSPACEEVENT (1<<22) /* V, subkey-level notification: channel=event|key */
#define NOTIFY_ARRAY (1<<23) /* a, array notification */
#ifdef ENABLE_GCRA
#define NOTIFY_RATE_LIMIT (1<<24) /* r, notify rate limit event (Note: excluded from NOTIFY_ALL)*/
#endif
#define NOTIFY_ALL (NOTIFY_GENERIC | NOTIFY_STRING | NOTIFY_LIST | NOTIFY_SET | NOTIFY_HASH | NOTIFY_ZSET | NOTIFY_EXPIRED | NOTIFY_EVICTED | NOTIFY_STREAM | NOTIFY_MODULE | NOTIFY_ARRAY) /* A flag */
/* Using the following macro you can run code inside serverCron() with the
@ -866,11 +870,18 @@ typedef enum {
* by a 64 bit module type ID, which has a 54 bits module-specific signature
* in order to dispatch the loading to the right module, plus a 10 bits
* encoding version. */
/* Code related to GCRA is disabled by default.
* Build with -DENABLE_GCRA to compile it back in. */
#define OBJ_MODULE 5 /* Module object. */
#define OBJ_STREAM 6 /* Stream object. */
#define OBJ_GCRA 7 /* GCRA object. */
#define OBJ_ARRAY 8 /* Array object. */
#define OBJ_ARRAY 7 /* Array object. */
#ifdef ENABLE_GCRA
#define OBJ_GCRA 8 /* GCRA object. */
#define OBJ_TYPE_MAX 9 /* Maximum number of object types */
#else
#define OBJ_TYPE_MAX 8 /* Maximum number of object types */
#endif
/* NOTE: adding a new object requires changes in the following places:
* - rdb.c - save/load (also bump RDB_VERSION if needed)
@ -2811,7 +2822,9 @@ typedef enum {
COMMAND_GROUP_BITMAP,
COMMAND_GROUP_ARRAY,
COMMAND_GROUP_MODULE,
#ifdef ENABLE_GCRA
COMMAND_GROUP_RATE_LIMIT,
#endif
} redisCommandGroup;
typedef void redisCommandProc(client *c);

Binary file not shown.

View file

@ -68,7 +68,9 @@ proc generate_types {} {
# create other non-collection types
r incr int
r set string str
if 0 {
r gcra gcra 10 5 60000
}
# create bigger objects with 10 items (more than a single ziplist / listpack)
generate_collections big 10

View file

@ -801,9 +801,12 @@ proc generate_fuzzy_traffic_on_key {key type duration} {
set set_commands {SADD SCARD SDIFF SDIFFSTORE SINTER SINTERSTORE SISMEMBER SMEMBERS SMOVE SPOP SRANDMEMBER SREM SSCAN SUNION SUNIONSTORE}
set stream_commands {XACK XADD XCLAIM XDEL XGROUP XINFO XLEN XPENDING XRANGE XREAD XREADGROUP XREVRANGE XTRIM XDELEX XACKDEL XNACK}
set vset_commands {VADD VREM}
set gcra_commands {GCRA}
set array_commands {ARSET ARGET ARDEL ARCOUNT ARMSET ARMGET ARGETRANGE ARDELRANGE ARINFO}
set commands [dict create string $string_commands hash $hash_commands zset $zset_commands list $list_commands set $set_commands stream $stream_commands vectorset $vset_commands gcra $gcra_commands array $array_commands]
set commands [dict create string $string_commands hash $hash_commands zset $zset_commands list $list_commands set $set_commands stream $stream_commands vectorset $vset_commands array $array_commands]
if 0 {
set gcra_commands {GCRA}
dict set commands gcra $gcra_commands
}
set cmds [dict get $commands $type]
set start_time [clock seconds]

View file

@ -1,4 +1,5 @@
start_server {tags {"gcra" "external:skip"}} {
if 0 {
test {GCRA - argument validation} {
# Wrong number of arguments (too few)
catch {r gcra} err
@ -236,8 +237,10 @@ start_server {tags {"gcra" "external:skip"}} {
assert {[r pttl mykey] > 0}
}
}
}
start_server {tags {"gcra" "external:skip"}} {
if 0 {
test {GCRA - RDB save and reload preserves value} {
r del mykey
r gcra mykey 5 1 60
@ -333,8 +336,10 @@ start_server {tags {"gcra" "external:skip"}} {
assert_equal $digest_before $digest_after
} {} {needs:debug}
}
}
start_server {tags {"gcra repl" "external:skip"}} {
if 0 {
set replica [srv 0 client]
set replica_host [srv 0 host]
set replica_port [srv 0 port]
@ -368,3 +373,4 @@ start_server {tags {"gcra repl" "external:skip"}} {
} {} {external:skip}
}
}
}

View file

@ -606,7 +606,9 @@ const char *COMMAND_GROUP_STR[] = {
"bitmap",
"array",
"module",
#ifdef ENABLE_GCRA
"rate_limit"
#endif
};
const char *commandGroupStr(int index) {