"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "src/module.c" between
redis-6.2-rc3.tar.gz and redis-6.2.0.tar.gz

About: redis is an advanced key-value store. It is often referred to as a data structure server since keys can contain strings, hashes, lists, sets and sorted sets.

module.c  (redis-6.2-rc3):module.c  (redis-6.2.0)
skipping to change at line 2611 skipping to change at line 2611
* setting it to 1 or 0 depending on the outcome of the operation. * setting it to 1 or 0 depending on the outcome of the operation.
* The 'deleted' argument can be NULL if the caller is not interested * The 'deleted' argument can be NULL if the caller is not interested
* to know if the element was really removed. * to know if the element was really removed.
* *
* Empty keys will be handled correctly by doing nothing. */ * Empty keys will be handled correctly by doing nothing. */
int RM_ZsetRem(RedisModuleKey *key, RedisModuleString *ele, int *deleted) { int RM_ZsetRem(RedisModuleKey *key, RedisModuleString *ele, int *deleted) {
if (!(key->mode & REDISMODULE_WRITE)) return REDISMODULE_ERR; if (!(key->mode & REDISMODULE_WRITE)) return REDISMODULE_ERR;
if (key->value && key->value->type != OBJ_ZSET) return REDISMODULE_ERR; if (key->value && key->value->type != OBJ_ZSET) return REDISMODULE_ERR;
if (key->value != NULL && zsetDel(key->value,ele->ptr)) { if (key->value != NULL && zsetDel(key->value,ele->ptr)) {
if (deleted) *deleted = 1; if (deleted) *deleted = 1;
moduleDelKeyIfEmpty(key);
} else { } else {
if (deleted) *deleted = 0; if (deleted) *deleted = 0;
} }
return REDISMODULE_OK; return REDISMODULE_OK;
} }
/* On success retrieve the double score associated at the sorted set element /* On success retrieve the double score associated at the sorted set element
* 'ele' and returns REDISMODULE_OK. Otherwise REDISMODULE_ERR is returned * 'ele' and returns REDISMODULE_OK. Otherwise REDISMODULE_ERR is returned
* to signal one of the following conditions: * to signal one of the following conditions:
* *
skipping to change at line 2656 skipping to change at line 2657
if (key->u.zset.type == REDISMODULE_ZSET_RANGE_LEX) if (key->u.zset.type == REDISMODULE_ZSET_RANGE_LEX)
zslFreeLexRange(&key->u.zset.lrs); zslFreeLexRange(&key->u.zset.lrs);
/* Setup sensible values so that misused iteration API calls when an /* Setup sensible values so that misused iteration API calls when an
* iterator is not active will result into something more sensible * iterator is not active will result into something more sensible
* than crashing. */ * than crashing. */
zsetKeyReset(key); zsetKeyReset(key);
} }
/* Return the "End of range" flag value to signal the end of the iteration. */ /* Return the "End of range" flag value to signal the end of the iteration. */
int RM_ZsetRangeEndReached(RedisModuleKey *key) { int RM_ZsetRangeEndReached(RedisModuleKey *key) {
if (!key->value || key->value->type != OBJ_ZSET) return 1;
return key->u.zset.er; return key->u.zset.er;
} }
/* Helper function for RM_ZsetFirstInScoreRange() and RM_ZsetLastInScoreRange(). /* Helper function for RM_ZsetFirstInScoreRange() and RM_ZsetLastInScoreRange().
* Setup the sorted set iteration according to the specified score range * Setup the sorted set iteration according to the specified score range
* (see the functions calling it for more info). If 'first' is true the * (see the functions calling it for more info). If 'first' is true the
* first element in the range is used as a starting point for the iterator * first element in the range is used as a starting point for the iterator
* otherwise the last. Return REDISMODULE_OK on success otherwise * otherwise the last. Return REDISMODULE_OK on success otherwise
* REDISMODULE_ERR. */ * REDISMODULE_ERR. */
int zsetInitScoreRange(RedisModuleKey *key, double min, double max, int minex, i nt maxex, int first) { int zsetInitScoreRange(RedisModuleKey *key, double min, double max, int minex, i nt maxex, int first) {
skipping to change at line 2973 skipping to change at line 2975
* set to REDISMODULE_HASH_NONE if no special behavior is needed. * set to REDISMODULE_HASH_NONE if no special behavior is needed.
* *
* REDISMODULE_HASH_NX: The operation is performed only if the field was not * REDISMODULE_HASH_NX: The operation is performed only if the field was not
* already existing in the hash. * already existing in the hash.
* REDISMODULE_HASH_XX: The operation is performed only if the field was * REDISMODULE_HASH_XX: The operation is performed only if the field was
* already existing, so that a new value could be * already existing, so that a new value could be
* associated to an existing filed, but no new fields * associated to an existing filed, but no new fields
* are created. * are created.
* REDISMODULE_HASH_CFIELDS: The field names passed are null terminated C * REDISMODULE_HASH_CFIELDS: The field names passed are null terminated C
* strings instead of RedisModuleString objects. * strings instead of RedisModuleString objects.
* REDISMODULE_HASH_COUNT_ALL: Include the number of inserted fields in the
* returned number, in addition to the number of
* updated and deleted fields. (Added in Redis
* 6.2.)
* *
* Unless NX is specified, the command overwrites the old field value with * Unless NX is specified, the command overwrites the old field value with
* the new one. * the new one.
* *
* When using REDISMODULE_HASH_CFIELDS, field names are reported using * When using REDISMODULE_HASH_CFIELDS, field names are reported using
* normal C strings, so for example to delete the field "foo" the following * normal C strings, so for example to delete the field "foo" the following
* code can be used: * code can be used:
* *
* RedisModule_HashSet(key,REDISMODULE_HASH_CFIELDS,"foo", * RedisModule_HashSet(key,REDISMODULE_HASH_CFIELDS,"foo",
* REDISMODULE_HASH_DELETE,NULL); * REDISMODULE_HASH_DELETE,NULL);
* *
* Return value: * Return value:
* *
* The number of fields updated (that may be less than the number of fields * The number of fields existing in the hash prior to the call, which have been
* specified because of the XX or NX options). * updated (its old value has been replaced by a new value) or deleted. If the
* * flag REDISMODULE_HASH_COUNT_ALL is set, insterted fields not previously
* In the following case the return value is always zero: * existing in the hash are also counted.
* *
* * The key was not open for writing. * If the return value is zero, `errno` is set (since Redis 6.2) as follows:
* * The key was associated with a non Hash value. *
* - EINVAL if any unknown flags are set or if key is NULL.
* - ENOTSUP if the key is associated with a non Hash value.
* - EBADF if the key was not opened for writing.
* - ENOENT if no fields were counted as described under Return value above.
* This is not actually an error. The return value can be zero if all fields
* were just created and the COUNT_ALL flag was unset, or if changes were held
* back due to the NX and XX flags.
*
* NOTICE: The return value semantics of this function are very different
* between Redis 6.2 and older versions. Modules that use it should determine
* the Redis version and handle it accordingly.
*/ */
int RM_HashSet(RedisModuleKey *key, int flags, ...) { int RM_HashSet(RedisModuleKey *key, int flags, ...) {
va_list ap; va_list ap;
if (!(key->mode & REDISMODULE_WRITE)) return 0; if (!key || (flags & ~(REDISMODULE_HASH_NX |
if (key->value && key->value->type != OBJ_HASH) return 0; REDISMODULE_HASH_XX |
REDISMODULE_HASH_CFIELDS |
REDISMODULE_HASH_COUNT_ALL))) {
errno = EINVAL;
return 0;
} else if (key->value && key->value->type != OBJ_HASH) {
errno = ENOTSUP;
return 0;
} else if (!(key->mode & REDISMODULE_WRITE)) {
errno = EBADF;
return 0;
}
if (key->value == NULL) moduleCreateEmptyKey(key,REDISMODULE_KEYTYPE_HASH); if (key->value == NULL) moduleCreateEmptyKey(key,REDISMODULE_KEYTYPE_HASH);
int updated = 0; int count = 0;
va_start(ap, flags); va_start(ap, flags);
while(1) { while(1) {
RedisModuleString *field, *value; RedisModuleString *field, *value;
/* Get the field and value objects. */ /* Get the field and value objects. */
if (flags & REDISMODULE_HASH_CFIELDS) { if (flags & REDISMODULE_HASH_CFIELDS) {
char *cfield = va_arg(ap,char*); char *cfield = va_arg(ap,char*);
if (cfield == NULL) break; if (cfield == NULL) break;
field = createRawStringObject(cfield,strlen(cfield)); field = createRawStringObject(cfield,strlen(cfield));
} else { } else {
field = va_arg(ap,RedisModuleString*); field = va_arg(ap,RedisModuleString*);
skipping to change at line 3028 skipping to change at line 3056
if (((flags & REDISMODULE_HASH_XX) && !exists) || if (((flags & REDISMODULE_HASH_XX) && !exists) ||
((flags & REDISMODULE_HASH_NX) && exists)) ((flags & REDISMODULE_HASH_NX) && exists))
{ {
if (flags & REDISMODULE_HASH_CFIELDS) decrRefCount(field); if (flags & REDISMODULE_HASH_CFIELDS) decrRefCount(field);
continue; continue;
} }
} }
/* Handle deletion if value is REDISMODULE_HASH_DELETE. */ /* Handle deletion if value is REDISMODULE_HASH_DELETE. */
if (value == REDISMODULE_HASH_DELETE) { if (value == REDISMODULE_HASH_DELETE) {
updated += hashTypeDelete(key->value, field->ptr); count += hashTypeDelete(key->value, field->ptr);
if (flags & REDISMODULE_HASH_CFIELDS) decrRefCount(field); if (flags & REDISMODULE_HASH_CFIELDS) decrRefCount(field);
continue; continue;
} }
int low_flags = HASH_SET_COPY; int low_flags = HASH_SET_COPY;
/* If CFIELDS is active, we can pass the ownership of the /* If CFIELDS is active, we can pass the ownership of the
* SDS object to the low level function that sets the field * SDS object to the low level function that sets the field
* to avoid a useless copy. */ * to avoid a useless copy. */
if (flags & REDISMODULE_HASH_CFIELDS) if (flags & REDISMODULE_HASH_CFIELDS)
low_flags |= HASH_SET_TAKE_FIELD; low_flags |= HASH_SET_TAKE_FIELD;
robj *argv[2] = {field,value}; robj *argv[2] = {field,value};
hashTypeTryConversion(key->value,argv,0,1); hashTypeTryConversion(key->value,argv,0,1);
updated += hashTypeSet(key->value, field->ptr, value->ptr, low_flags); int updated = hashTypeSet(key->value, field->ptr, value->ptr, low_flags)
;
count += (flags & REDISMODULE_HASH_COUNT_ALL) ? 1 : updated;
/* If CFIELDS is active, SDS string ownership is now of hashTypeSet(), /* If CFIELDS is active, SDS string ownership is now of hashTypeSet(),
* however we still have to release the 'field' object shell. */ * however we still have to release the 'field' object shell. */
if (flags & REDISMODULE_HASH_CFIELDS) { if (flags & REDISMODULE_HASH_CFIELDS) {
field->ptr = NULL; /* Prevent the SDS string from being freed. */ field->ptr = NULL; /* Prevent the SDS string from being freed. */
decrRefCount(field); decrRefCount(field);
} }
} }
va_end(ap); va_end(ap);
moduleDelKeyIfEmpty(key); moduleDelKeyIfEmpty(key);
return updated; if (count == 0) errno = ENOENT;
return count;
} }
/* Get fields from an hash value. This function is called using a variable /* Get fields from an hash value. This function is called using a variable
* number of arguments, alternating a field name (as a RedisModuleString * number of arguments, alternating a field name (as a RedisModuleString
* pointer) with a pointer to a RedisModuleString pointer, that is set to the * pointer) with a pointer to a RedisModuleString pointer, that is set to the
* value of the field if the field exists, or NULL if the field does not exist. * value of the field if the field exists, or NULL if the field does not exist.
* At the end of the field/value-ptr pairs, NULL must be specified as last * At the end of the field/value-ptr pairs, NULL must be specified as last
* argument to signal the end of the arguments in the variadic function. * argument to signal the end of the arguments in the variadic function.
* *
* This is an example usage: * This is an example usage:
skipping to change at line 5119 skipping to change at line 5149
bc->reply_callback = reply_callback; bc->reply_callback = reply_callback;
bc->timeout_callback = timeout_callback; bc->timeout_callback = timeout_callback;
bc->disconnect_callback = NULL; /* Set by RM_SetDisconnectCallback() */ bc->disconnect_callback = NULL; /* Set by RM_SetDisconnectCallback() */
bc->free_privdata = free_privdata; bc->free_privdata = free_privdata;
bc->privdata = privdata; bc->privdata = privdata;
bc->reply_client = createClient(NULL); bc->reply_client = createClient(NULL);
bc->reply_client->flags |= CLIENT_MODULE; bc->reply_client->flags |= CLIENT_MODULE;
bc->dbid = c->db->id; bc->dbid = c->db->id;
bc->blocked_on_keys = keys != NULL; bc->blocked_on_keys = keys != NULL;
bc->unblocked = 0; bc->unblocked = 0;
bc->background_timer = 0;
bc->background_duration = 0; bc->background_duration = 0;
c->bpop.timeout = timeout; c->bpop.timeout = timeout;
if (islua || ismulti) { if (islua || ismulti) {
c->bpop.module_blocked_handle = NULL; c->bpop.module_blocked_handle = NULL;
addReplyError(c, islua ? addReplyError(c, islua ?
"Blocking module command called from Lua script" : "Blocking module command called from Lua script" :
"Blocking module command called from transaction"); "Blocking module command called from transaction");
} else { } else {
if (keys) { if (keys) {
skipping to change at line 6722 skipping to change at line 6753
/* Starts a dict field, similar to the ones in INFO KEYSPACE. Use normal /* Starts a dict field, similar to the ones in INFO KEYSPACE. Use normal
* RedisModule_InfoAddField* functions to add the items to this field, and * RedisModule_InfoAddField* functions to add the items to this field, and
* terminate with RedisModule_InfoEndDictField. */ * terminate with RedisModule_InfoEndDictField. */
int RM_InfoBeginDictField(RedisModuleInfoCtx *ctx, char *name) { int RM_InfoBeginDictField(RedisModuleInfoCtx *ctx, char *name) {
if (!ctx->in_section) if (!ctx->in_section)
return REDISMODULE_ERR; return REDISMODULE_ERR;
/* Implicitly end dicts, instead of returning an error which is likely un ch ecked. */ /* Implicitly end dicts, instead of returning an error which is likely un ch ecked. */
if (ctx->in_dict_field) if (ctx->in_dict_field)
RM_InfoEndDictField(ctx); RM_InfoEndDictField(ctx);
char *tmpmodname, *tmpname;
ctx->info = sdscatfmt(ctx->info, ctx->info = sdscatfmt(ctx->info,
"%s_%s:", "%s_%s:",
ctx->module->name, getSafeInfoString(ctx->module->name, strlen(ctx->module->name), &tmpmodn
name); ame),
getSafeInfoString(name, strlen(name), &tmpname));
if (tmpmodname != NULL) zfree(tmpmodname);
if (tmpname != NULL) zfree(tmpname);
ctx->in_dict_field = 1; ctx->in_dict_field = 1;
return REDISMODULE_OK; return REDISMODULE_OK;
} }
/* Ends a dict field, see RedisModule_InfoBeginDictField */ /* Ends a dict field, see RedisModule_InfoBeginDictField */
int RM_InfoEndDictField(RedisModuleInfoCtx *ctx) { int RM_InfoEndDictField(RedisModuleInfoCtx *ctx) {
if (!ctx->in_dict_field) if (!ctx->in_dict_field)
return REDISMODULE_ERR; return REDISMODULE_ERR;
/* trim the last ',' if found. */ /* trim the last ',' if found. */
if (ctx->info[sdslen(ctx->info)-1]==',') if (ctx->info[sdslen(ctx->info)-1]==',')
skipping to change at line 7655 skipping to change at line 7689
} else { } else {
/* Parent */ /* Parent */
moduleForkInfo.done_handler = cb; moduleForkInfo.done_handler = cb;
moduleForkInfo.done_handler_user_data = user_data; moduleForkInfo.done_handler_user_data = user_data;
serverLog(LL_VERBOSE, "Module fork started pid: %ld ", (long) childpid); serverLog(LL_VERBOSE, "Module fork started pid: %ld ", (long) childpid);
} }
return childpid; return childpid;
} }
/* The module is advised to call this function from the fork child once in a whi le, /* The module is advised to call this function from the fork child once in a whi le,
* so that it can report COW memory to the parent which will be reported in INFO * so that it can report progress and COW memory to the parent which will be
*/ * reported in INFO.
void RM_SendChildCOWInfo(void) { * The `progress` argument should between 0 and 1, or -1 when not available. */
sendChildCOWInfo(CHILD_TYPE_MODULE, 0, "Module fork"); void RM_SendChildHeartbeat(double progress) {
sendChildInfoGeneric(CHILD_INFO_TYPE_CURRENT_INFO, 0, progress, "Module fork
");
} }
/* Call from the child process when you want to terminate it. /* Call from the child process when you want to terminate it.
* retcode will be provided to the done handler executed on the parent process. * retcode will be provided to the done handler executed on the parent process.
*/ */
int RM_ExitFromChild(int retcode) { int RM_ExitFromChild(int retcode) {
sendChildCOWInfo(CHILD_TYPE_MODULE, 1, "Module fork"); sendChildCowInfo(CHILD_INFO_TYPE_MODULE_COW_SIZE, "Module fork");
exitFromChild(retcode); exitFromChild(retcode);
return REDISMODULE_OK; return REDISMODULE_OK;
} }
/* Kill the active module forked child, if there is one active and the /* Kill the active module forked child, if there is one active and the
* pid matches, and returns C_OK. Otherwise if there is no active module * pid matches, and returns C_OK. Otherwise if there is no active module
* child or the pid does not match, return C_ERR without doing anything. */ * child or the pid does not match, return C_ERR without doing anything. */
int TerminateModuleForkChild(int child_pid, int wait) { int TerminateModuleForkChild(int child_pid, int wait) {
/* Module child should be active and pid should match. */ /* Module child should be active and pid should match. */
if (server.child_type != CHILD_TYPE_MODULE || if (server.child_type != CHILD_TYPE_MODULE ||
skipping to change at line 9195 skipping to change at line 9231
REGISTER_API(ExportSharedAPI); REGISTER_API(ExportSharedAPI);
REGISTER_API(GetSharedAPI); REGISTER_API(GetSharedAPI);
REGISTER_API(RegisterCommandFilter); REGISTER_API(RegisterCommandFilter);
REGISTER_API(UnregisterCommandFilter); REGISTER_API(UnregisterCommandFilter);
REGISTER_API(CommandFilterArgsCount); REGISTER_API(CommandFilterArgsCount);
REGISTER_API(CommandFilterArgGet); REGISTER_API(CommandFilterArgGet);
REGISTER_API(CommandFilterArgInsert); REGISTER_API(CommandFilterArgInsert);
REGISTER_API(CommandFilterArgReplace); REGISTER_API(CommandFilterArgReplace);
REGISTER_API(CommandFilterArgDelete); REGISTER_API(CommandFilterArgDelete);
REGISTER_API(Fork); REGISTER_API(Fork);
REGISTER_API(SendChildCOWInfo); REGISTER_API(SendChildHeartbeat);
REGISTER_API(ExitFromChild); REGISTER_API(ExitFromChild);
REGISTER_API(KillForkChild); REGISTER_API(KillForkChild);
REGISTER_API(RegisterInfoFunc); REGISTER_API(RegisterInfoFunc);
REGISTER_API(InfoAddSection); REGISTER_API(InfoAddSection);
REGISTER_API(InfoBeginDictField); REGISTER_API(InfoBeginDictField);
REGISTER_API(InfoEndDictField); REGISTER_API(InfoEndDictField);
REGISTER_API(InfoAddFieldString); REGISTER_API(InfoAddFieldString);
REGISTER_API(InfoAddFieldCString); REGISTER_API(InfoAddFieldCString);
REGISTER_API(InfoAddFieldDouble); REGISTER_API(InfoAddFieldDouble);
REGISTER_API(InfoAddFieldLongLong); REGISTER_API(InfoAddFieldLongLong);
 End of changes. 15 change blocks. 
21 lines changed or deleted 59 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)