Skip to content

Module set/get config API#14051

Merged
minchopaskal merged 10 commits intoredis:unstablefrom
minchopaskal:module-config-cmd-api
Jul 3, 2025
Merged

Module set/get config API#14051
minchopaskal merged 10 commits intoredis:unstablefrom
minchopaskal:module-config-cmd-api

Conversation

@minchopaskal
Copy link
Collaborator

@minchopaskal minchopaskal commented May 16, 2025

Problem

Some redis modules need to call CONFIG GET/SET commands. Server may be ran with rename-command CONFIG ""(or something similar) which leads to the module being unable to access the config.

Solution

Added new API functions for use by modules

RedisModuleConfigIterator* RedisModule_GetConfigIterator(RedisModuleCtx *ctx, const char *pattern);
void RedisModule_ReleaseConfigIterator(RedisModuleCtx *ctx, RedisModuleConfigIterator *iter);
const char *RedisModule_ConfigIteratorNext(RedisModuleConfigIterator *iter);
int RedisModule_GetConfigType(const char *name, RedisModuleConfigType *res);
int RedisModule_GetBoolConfig(RedisModuleCtx *ctx, const char *name, int *res);
int RedisModule_GetConfig(RedisModuleCtx *ctx, const char *name, RedisModuleString **res);
int RedisModule_GetEnumConfig(RedisModuleCtx *ctx, const char *name, RedisModuleString **res);
int RedisModule_GetNumericConfig(RedisModuleCtx *ctx, const char *name, long long *res);
int RedisModule_SetBoolConfig(RedisModuleCtx *ctx, const char *name, int value, RedisModuleString **err);
int RedisModule_SetConfig(RedisModuleCtx *ctx, const char *name, RedisModuleString *value, RedisModuleString **err);
int RedisModule_SetEnumConfig(RedisModuleCtx *ctx, const char *name, RedisModuleString *value, RedisModuleString **err);
int RedisModule_SetNumericConfig(RedisModuleCtx *ctx, const char *name, long long value, RedisModuleString **err);

Implementation

The work is mostly done inside config.c as I didn't want to expose the config dict outside of it. That means each of these module functions has a corresponding method in config.c that actually does the job. F.e RedisModule_SetEnumConfig calls moduleSetEnumConfig which is implemented in config.c

Notes

Also, refactored configSetCommand and restoreBackupConfig functions for the following reasons:

  • code and logic is now way more clear in configSetCommand. Only caveat here is removal of an optimization that skipped running apply functions that already have ran in favour of code clarity.
  • Both functions needlessly separated logic for module configs and normal configs whereas no such separation is needed. This also had the side effect of removing some allocations.
  • restoreBackupConfig now has clearer interface and can be reused with ease. One of the places I reused it is for the individual moduleSet*Config functions, each of which needs the restoration functionality but for a single config only.

Future

Additionally, a couple considerations were made for potentially extending the API in the future

  • if need be an API for atomically setting multiple config values can be added - RedisModule_SetConfigsTranscationStart/End or similar that can be put around RedisModule_Set*Config calls.
  • if performance is an issue an API RedisModule_GetConfigIteratorNextWithTypehint or similar may be added in order not to incur the additional cost of calling RedisModule_GetConfigType.

@snyk-io
Copy link

snyk-io bot commented May 16, 2025

🎉 Snyk checks have passed. No issues have been found so far.

security/snyk check is complete. No issues have been found. (View Details)

license/snyk check is complete. No issues have been found. (View Details)

@minchopaskal minchopaskal requested a review from oranagra May 16, 2025 13:35
@sundb sundb added release-notes indication that this issue needs to be mentioned in the release notes state:needs-doc-pr requires a PR to redis-doc repository labels May 17, 2025
@sundb sundb requested a review from Copilot May 17, 2025 03:34

This comment was marked as outdated.

@sundb sundb removed the state:needs-doc-pr requires a PR to redis-doc repository label May 17, 2025
Copy link
Contributor

@raz-mon raz-mon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM (module's POV)
See some small comments

src/config.c Outdated
Comment on lines +2102 to +2101
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this considered a breaking change?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sundb @oshadmi I don't think so, as negative values were previously only handled in numericParseString - i.e if the config is not percent config and the value is negative it directly returned error.

Since now I needed to use the numericBoundaryCheck directly I needed to add that check which wouldn't break existing code.

Setting a numeric config through a module though would fail if one passes a negative value and the config is not a PERCENT_CONFIG as it should.

That said, I'm still worried if passing a negative value for percenta configs is confusing:

/* Set the value of a numeric config.
 * If the value passed is meant to be a percentage, it should be passed as a
 * negative value.
 *
 * See RedisModule_SetStringConfig for return value. */
int RM_SetNumericConfig(RedisModuleCtx *ctx, const char *name, long long value, RedisModuleString **err);

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sundb can u comment?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can consider it as a bug instead of a break change.
when ll is negative, we will convert it to unsigned, which might cause us to load an invalid negative config.
Although after checking the code, it seems this case wouldn’t actually happen.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i just stumbled across this.
i think it's a breaking change.
if someone would have set an insane maxmemory, it the past it would have worked (memory being practically unlimited), and now it'll error.
i.e. the value is negative when we get to this function, but the caller intended to pass a positive value and it'll just be casted to this function as negative.

that is, unless the RESP or config parser would have blocked such a huge number (since they think they're parsing signed values)?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i didn't carefully read the discussion.
@minchopaskal so you're saying that before this PR there was no way for this function to get a negative value for ULONGLONG config? not from config file and not from config command?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, yes - for the maxmemory example numericParseString->memtoull would have prevented it. But now with the new module API what you described can happen so needs a fix.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR made here #14286

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in the PR you're saying it was a breaking change. but if it didn't break config file parsing and the CONFIG SET command, what did it break? the module APIs didn't yet exist so it can't break them.
am i missing something?

Copy link
Collaborator Author

@minchopaskal minchopaskal Aug 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are not, it's my bad.

EDIT: It indeed was a breaking change.. I wasn't thinking of such cases (thanks @sundb to pointing this out)

Output from unstable

$ ./src/redis-server --maxmemory 9999999999999999999999999

*** FATAL CONFIG FILE ERROR (Redis 255.255.255) ***
Reading the configuration file, at line 2
>>> 'maxmemory "9999999999999999999999999"'
argument must be greater or equal to 0

Copy link
Member

@oranagra oranagra left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i only reviewed the API and their docs, not the code.

please consider adding more details in the PR description about the considerations we took, limitations and plans.
e.g. did we have any plans to later add some API to allow atomically set several configs at one (or apply them together)

@minchopaskal minchopaskal added the action:run-benchmark Triggers the benchmark suite for this Pull Request label Jun 16, 2025
@fcostaoliveira
Copy link
Collaborator

fcostaoliveira commented Jun 16, 2025

CE Performance Automation : step 1 of 2 (build) DONE.

This comment was automatically generated given a benchmark was triggered.
Started building at 2025-06-17 11:18:11.735568 and took 66 seconds.
You can check each build/benchmark progress in grafana:

  • git hash: 40bdd7889d3a428cd039027004b80ed653c054c4
  • git branch: minchopaskal:module-config-cmd-api
  • commit date and time: n/a
  • commit summary: n/a
  • test filters:
    • command priority lower limit: 0
    • command priority upper limit: 10000
    • test name regex: .*
    • command group regex: .*

You can check a comparison in detail via the grafana link

@fcostaoliveira
Copy link
Collaborator

fcostaoliveira commented Jun 16, 2025

CE Performance Automation : step 2 of 2 (benchmark) FINISHED.

This comment was automatically generated given a benchmark was triggered.

Started benchmark suite at 2025-06-24 14:21:18.487824 and took 12565.242281 seconds to finish.
Status: [################################################################################] 100.0% completed.

In total will run 176 benchmarks.
- 0 pending.
- 176 completed:
- 0 successful.
- 176 failed.
You can check a the status in detail via the grafana link

@fcostaoliveira
Copy link
Collaborator

fcostaoliveira commented Jun 16, 2025

Automated performance analysis summary

This comment was automatically generated given there is performance data available.

Using platform named: intel64-ubuntu22.04-redis-gnr1 to do the comparison.

In summary:

  • Detected a total of 15 stable tests between versions.
  • Detected a total of 1 improvements above the improvement water line.
  • Detected a total of 1 regressions bellow the regression water line 10.0.
    • Median/Common-Case regression was -12.8% and ranged from [-12.8%,-12.8%].

You can check a comparison in detail via the grafana link

Comparison between unstable and minchopaskal:module-config-cmd-api.

Time Period from 5 months ago. (environment used: oss-standalone)

By GROUP change csv:

command_group,min_change,max_change

By COMMAND change csv:

command,min_change,max_change

#### Regressions Table
Test Case Baseline redis/redis unstable (median obs. +- std.dev) Comparison redis/redis minchopaskal:module-config-cmd-api (median obs. +- std.dev) % change (higher-better) Note
memtier_benchmark-1key-zrank-10M-elements-pipeline-1 3151 2747 -12.8% REGRESSION

Regressions test regexp names: memtier_benchmark-1key-zrank-10M-elements-pipeline-1

Improvements Table

Test Case Baseline redis/redis unstable (median obs. +- std.dev) Comparison redis/redis minchopaskal:module-config-cmd-api (median obs. +- std.dev) % change (higher-better) Note
memtier_benchmark-1Mkeys-load-zset-listpack-with-100-elements-double-score 2743 4210 53.5% IMPROVEMENT

Improvements test regexp names: memtier_benchmark-1Mkeys-load-zset-listpack-with-100-elements-double-score

Full Results table:
Test Case Baseline redis/redis unstable (median obs. +- std.dev) Comparison redis/redis minchopaskal:module-config-cmd-api (median obs. +- std.dev) % change (higher-better) Note
memtier_benchmark-10Mkeys-load-hash-5-fields-with-100B-values 138173 137591 -0.4% No Change
memtier_benchmark-1Mkeys-generic-expire-pipeline-10 1140211 1181963 3.7% potential IMPROVEMENT
memtier_benchmark-1Mkeys-generic-touch-pipeline-10 1180435 1227843 4.0% potential IMPROVEMENT
memtier_benchmark-1Mkeys-load-hash-hmset-5-fields-with-1000B-values 108326 109736 1.3% No Change
memtier_benchmark-1Mkeys-load-zset-listpack-with-100-elements-double-score 2743 4210 53.5% IMPROVEMENT
memtier_benchmark-1Mkeys-string-get-10B 186322 191674 2.9% No Change
memtier_benchmark-1Mkeys-string-get-10B-pipeline-100 2598206 2595170 -0.1% No Change
memtier_benchmark-1Mkeys-string-get-10B-pipeline-50 2404659 2423383 0.8% No Change
memtier_benchmark-1Mkeys-string-incrbyfloat-pipeline-10 789713 804992 1.9% No Change
memtier_benchmark-1Mkeys-string-setrange-100B 220728 224103 1.5% No Change
memtier_benchmark-1key-100M-bits-bitmap-bitcount 19143 19313 0.9% No Change
memtier_benchmark-1key-list-100-elements-lrange-all-elements-pipeline-10 264694 259904 -1.8% No Change
memtier_benchmark-1key-zrank-10M-elements-pipeline-1 3151 2747 -12.8% REGRESSION
memtier_benchmark-1key-zrevrangebyscore-256K-elements-pipeline-10 201978 207922 2.9% No Change
memtier_benchmark-1key-zset-1M-elements-zrevrange-5-elements 221714 225225 1.6% No Change
memtier_benchmark-2keys-zset-300-elements-skiplist-encoded-zunion 5178 5244 1.3% No Change
memtier_benchmark-2keys-zset-300-elements-skiplist-encoded-zunionstore 5935 5970 0.6% No Change

WARNING: There were 333 benchmarks with NO datapoints for both baseline and comparison.

NO DATAPOINTS test regexp names: latency-rate-limited-10000_qps-memtier_benchmark-100Kkeys-hash-hgetall-50-fields-100B-values|latency-rate-limited-10000_qps-memtier_benchmark-100Kkeys-load-hash-50-fields-with-1000B-values|latency-rate-limited-10000_qps-memtier_benchmark-100Kkeys-load-hash-50-fields-with-100B-values|latency-rate-limited-10000_qps-memtier_benchmark-100Kkeys-load-hash-50-fields-with-10B-values|latency-rate-limited-10000_qps-memtier_benchmark-10Mkeys-load-hash-5-fields-with-100B-values|latency-rate-limited-10000_qps-memtier_benchmark-10Mkeys-load-hash-5-fields-with-100B-values-pipeline-10|latency-rate-limited-10000_qps-memtier_benchmark-10Mkeys-load-hash-5-fields-with-10B-values|latency-rate-limited-10000_qps-memtier_benchmark-10Mkeys-load-hash-5-fields-with-10B-values-pipeline-10|latency-rate-limited-10000_qps-memtier_benchmark-1Mkeys-100B-expire-use-case|latency-rate-limited-10000_qps-memtier_benchmark-1Mkeys-10B-expire-use-case|latency-rate-limited-10000_qps-memtier_benchmark-1Mkeys-1KiB-expire-use-case|latency-rate-limited-10000_qps-memtier_benchmark-1Mkeys-4KiB-expire-use-case|latency-rate-limited-10000_qps-memtier_benchmark-1Mkeys-bitmap-getbit-pipeline-10|latency-rate-limited-10000_qps-memtier_benchmark-1Mkeys-generic-exists-pipeline-10|latency-rate-limited-10000_qps-memtier_benchmark-1Mkeys-generic-expire-pipeline-10|latency-rate-limited-10000_qps-memtier_benchmark-1Mkeys-generic-expireat-pipeline-10|latency-rate-limited-10000_qps-memtier_benchmark-1Mkeys-generic-pexpire-pipeline-10|latency-rate-limited-10000_qps-memtier_benchmark-1Mkeys-generic-scan-pipeline-10|latency-rate-limited-10000_qps-memtier_benchmark-1Mkeys-generic-touch-pipeline-10|latency-rate-limited-10000_qps-memtier_benchmark-1Mkeys-generic-ttl-pipeline-10|latency-rate-limited-10000_qps-memtier_benchmark-1Mkeys-hash-hexists|latency-rate-limited-10000_qps-memtier_benchmark-1Mkeys-hash-hget-hgetall-hkeys-hvals-with-100B-values|latency-rate-limited-10000_qps-memtier_benchmark-1Mkeys-hash-hgetall-50-fields-10B-values|latency-rate-limited-10000_qps-memtier_benchmark-1Mkeys-hash-hincrby|latency-rate-limited-10000_qps-memtier_benchmark-1Mkeys-hash-hmget-5-fields-with-100B-values-pipeline-10|latency-rate-limited-10000_qps-memtier_benchmark-1Mkeys-hash-transactions-multi-exec-pipeline-20|latency-rate-limited-10000_qps-memtier_benchmark-1Mkeys-list-lpop-rpop-with-100B-values|latency-rate-limited-10000_qps-memtier_benchmark-1Mkeys-list-lpop-rpop-with-10B-values|latency-rate-limited-10000_qps-memtier_benchmark-1Mkeys-list-lpop-rpop-with-1KiB-values|latency-rate-limited-10000_qps-memtier_benchmark-1Mkeys-load-hash-5-fields-with-1000B-values|latency-rate-limited-10000_qps-memtier_benchmark-1Mkeys-load-hash-5-fields-with-1000B-values-pipeline-10|latency-rate-limited-10000_qps-memtier_benchmark-1Mkeys-load-hash-hmset-5-fields-with-1000B-values|latency-rate-limited-10000_qps-memtier_benchmark-1Mkeys-load-list-with-100B-values|latency-rate-limited-10000_qps-memtier_benchmark-1Mkeys-load-list-with-10B-values|latency-rate-limited-10000_qps-memtier_benchmark-1Mkeys-load-list-with-1KiB-values|latency-rate-limited-10000_qps-memtier_benchmark-1Mkeys-load-set-intset-with-100-elements|latency-rate-limited-10000_qps-memtier_benchmark-1Mkeys-load-set-intset-with-100-elements-pipeline-10|latency-rate-limited-10000_qps-memtier_benchmark-1Mkeys-load-stream-1-fields-with-100B-values|latency-rate-limited-10000_qps-memtier_benchmark-1Mkeys-load-stream-1-fields-with-100B-values-pipeline-10|latency-rate-limited-10000_qps-memtier_benchmark-1Mkeys-load-stream-5-fields-with-100B-values|latency-rate-limited-10000_qps-memtier_benchmark-1Mkeys-load-stream-5-fields-with-100B-values-pipeline-10|latency-rate-limited-10000_qps-memtier_benchmark-1Mkeys-load-string-with-100B-values|latency-rate-limited-10000_qps-memtier_benchmark-1Mkeys-load-string-with-100B-values-pipeline-10|latency-rate-limited-10000_qps-memtier_benchmark-1Mkeys-load-string-with-10B-values|latency-rate-limited-10000_qps-memtier_benchmark-1Mkeys-load-string-with-10B-values-pipeline-10|latency-rate-limited-10000_qps-memtier_benchmark-1Mkeys-load-string-with-1KiB-values|latency-rate-limited-10000_qps-memtier_benchmark-1Mkeys-load-string-with-20KiB-values|latency-rate-limited-10000_qps-memtier_benchmark-1Mkeys-load-zset-with-10-elements-double-score|latency-rate-limited-10000_qps-memtier_benchmark-1Mkeys-load-zset-with-10-elements-int-score|latency-rate-limited-10000_qps-memtier_benchmark-1Mkeys-string-append-1-100B|latency-rate-limited-10000_qps-memtier_benchmark-1Mkeys-string-append-1-100B-pipeline-10|latency-rate-limited-10000_qps-memtier_benchmark-1Mkeys-string-decr|latency-rate-limited-10000_qps-memtier_benchmark-1Mkeys-string-get-100B|latency-rate-limited-10000_qps-memtier_benchmark-1Mkeys-string-get-100B-pipeline-10|latency-rate-limited-10000_qps-memtier_benchmark-1Mkeys-string-get-10B|latency-rate-limited-10000_qps-memtier_benchmark-1Mkeys-string-get-10B-pipeline-10|latency-rate-limited-10000_qps-memtier_benchmark-1Mkeys-string-get-1KiB|latency-rate-limited-10000_qps-memtier_benchmark-1Mkeys-string-get-1KiB-pipeline-10|latency-rate-limited-10000_qps-memtier_benchmark-1Mkeys-string-get-20KiB|latency-rate-limited-10000_qps-memtier_benchmark-1Mkeys-string-incrby|latency-rate-limited-10000_qps-memtier_benchmark-1Mkeys-string-incrby-pipeline-10|latency-rate-limited-10000_qps-memtier_benchmark-1Mkeys-string-incrbyfloat|latency-rate-limited-10000_qps-memtier_benchmark-1Mkeys-string-incrbyfloat-pipeline-10|latency-rate-limited-10000_qps-memtier_benchmark-1Mkeys-string-mget-1KiB|latency-rate-limited-10000_qps-memtier_benchmark-1Mkeys-string-setex-100B-pipeline-10|latency-rate-limited-10000_qps-memtier_benchmark-1Mkeys-string-setrange-100B|latency-rate-limited-10000_qps-memtier_benchmark-1Mkeys-string-setrange-100B-pipeline-10|latency-rate-limited-10000_qps-memtier_benchmark-1key-geo-2-elements-geopos|latency-rate-limited-10000_qps-memtier_benchmark-1key-geo-2-elements-geosearch-fromlonlat-withcoord|latency-rate-limited-10000_qps-memtier_benchmark-1key-geo-60M-elements-geodist|latency-rate-limited-10000_qps-memtier_benchmark-1key-geo-60M-elements-geodist-pipeline-10|latency-rate-limited-10000_qps-memtier_benchmark-1key-geo-60M-elements-geohash|latency-rate-limited-10000_qps-memtier_benchmark-1key-geo-60M-elements-geohash-pipeline-10|latency-rate-limited-10000_qps-memtier_benchmark-1key-geo-60M-elements-geopos|latency-rate-limited-10000_qps-memtier_benchmark-1key-geo-60M-elements-geopos-pipeline-10|latency-rate-limited-10000_qps-memtier_benchmark-1key-geo-60M-elements-geosearch-fromlonlat|latency-rate-limited-10000_qps-memtier_benchmark-1key-geo-60M-elements-geosearch-fromlonlat-bybox|latency-rate-limited-10000_qps-memtier_benchmark-1key-geo-60M-elements-geosearch-fromlonlat-pipeline-10|latency-rate-limited-10000_qps-memtier_benchmark-1key-hash-hscan-50-fields-10B-values|latency-rate-limited-10000_qps-memtier_benchmark-1key-list-10-elements-lrange-all-elements|latency-rate-limited-10000_qps-memtier_benchmark-1key-list-10-elements-lrange-all-elements-pipeline-10|latency-rate-limited-10000_qps-memtier_benchmark-1key-list-100-elements-lrange-all-elements|latency-rate-limited-10000_qps-memtier_benchmark-1key-list-100-elements-lrange-all-elements-pipeline-10|latency-rate-limited-10000_qps-memtier_benchmark-1key-list-10K-elements-lindex-integer|latency-rate-limited-10000_qps-memtier_benchmark-1key-list-10K-elements-lindex-string|latency-rate-limited-10000_qps-memtier_benchmark-1key-list-1K-elements-lrange-all-elements|latency-rate-limited-10000_qps-memtier_benchmark-1key-list-1K-elements-lrange-all-elements-pipeline-10|latency-rate-limited-10000_qps-memtier_benchmark-1key-pfadd-4KB-values-pipeline-10|latency-rate-limited-10000_qps-memtier_benchmark-1key-set-10-elements-smembers|latency-rate-limited-10000_qps-memtier_benchmark-1key-set-10-elements-smembers-pipeline-10|latency-rate-limited-10000_qps-memtier_benchmark-1key-set-10-elements-smismember|latency-rate-limited-10000_qps-memtier_benchmark-1key-set-100-elements-sismember-is-a-member|latency-rate-limited-10000_qps-memtier_benchmark-1key-set-100-elements-sismember-not-a-member|latency-rate-limited-10000_qps-memtier_benchmark-1key-set-100-elements-smembers|latency-rate-limited-10000_qps-memtier_benchmark-1key-set-100-elements-smismember|latency-rate-limited-10000_qps-memtier_benchmark-1key-set-100-elements-sscan|latency-rate-limited-10000_qps-memtier_benchmark-1key-set-10M-elements-sismember-50pct-chance|latency-rate-limited-10000_qps-memtier_benchmark-1key-set-1K-elements-smembers|latency-rate-limited-10000_qps-memtier_benchmark-1key-set-1M-elements-sismember-50pct-chance|latency-rate-limited-10000_qps-memtier_benchmark-1key-set-200K-elements-sadd-constant|latency-rate-limited-10000_qps-memtier_benchmark-1key-set-2M-elements-sadd-increasing|latency-rate-limited-10000_qps-memtier_benchmark-1key-zincrby-1M-elements-pipeline-1|latency-rate-limited-10000_qps-memtier_benchmark-1key-zrank-1M-elements-pipeline-1|latency-rate-limited-10000_qps-memtier_benchmark-1key-zrem-5M-elements-pipeline-1|latency-rate-limited-10000_qps-memtier_benchmark-1key-zrevrangebyscore-256K-elements-pipeline-1|latency-rate-limited-10000_qps-memtier_benchmark-1key-zrevrank-1M-elements-pipeline-1|latency-rate-limited-10000_qps-memtier_benchmark-1key-zset-10-elements-zrange-all-elements|latency-rate-limited-10000_qps-memtier_benchmark-1key-zset-10-elements-zrange-all-elements-long-scores|latency-rate-limited-10000_qps-memtier_benchmark-1key-zset-100-elements-zrange-all-elements|latency-rate-limited-10000_qps-memtier_benchmark-1key-zset-100-elements-zrangebyscore-all-elements|latency-rate-limited-10000_qps-memtier_benchmark-1key-zset-100-elements-zrangebyscore-all-elements-long-scores|latency-rate-limited-10000_qps-memtier_benchmark-1key-zset-100-elements-zscan|latency-rate-limited-10000_qps-memtier_benchmark-1key-zset-1M-elements-zcard-pipeline-10|latency-rate-limited-10000_qps-memtier_benchmark-1key-zset-1M-elements-zrevrange-5-elements|latency-rate-limited-10000_qps-memtier_benchmark-1key-zset-1M-elements-zscore-pipeline-10|latency-rate-limited-10000_qps-memtier_benchmark-2keys-lua-eval-hset-expire|latency-rate-limited-10000_qps-memtier_benchmark-2keys-lua-evalsha-hset-expire|latency-rate-limited-10000_qps-memtier_benchmark-2keys-set-10-100-elements-sdiff|latency-rate-limited-10000_qps-memtier_benchmark-2keys-set-10-100-elements-sinter|latency-rate-limited-10000_qps-memtier_benchmark-2keys-set-10-100-elements-sunion|latency-rate-limited-10000_qps-memtier_benchmark-2keys-stream-5-entries-xread-all-entries|latency-rate-limited-10000_qps-memtier_benchmark-2keys-stream-5-entries-xread-all-entries-pipeline-10|latency-rate-limited-10000_qps-memtier_benchmark-3Mkeys-load-string-with-512B-values|latency-rate-limited-10000_qps-memtier_benchmark-connection-hello|latency-rate-limited-1000_qps-memtier_benchmark-10Kkeys-load-hash-50-fields-with-10000B-values|latency-rate-limited-1000_qps-memtier_benchmark-1Mkeys-load-zset-listpack-with-100-elements-double-score|latency-rate-limited-1000_qps-memtier_benchmark-1key-100M-bits-bitmap-bitcount|latency-rate-limited-1000_qps-memtier_benchmark-1key-list-10K-elements-linsert-lrem-integer|latency-rate-limited-1000_qps-memtier_benchmark-1key-list-10K-elements-linsert-lrem-string|latency-rate-limited-1000_qps-memtier_benchmark-1key-list-10K-elements-lpos-integer|latency-rate-limited-1000_qps-memtier_benchmark-1key-list-10K-elements-lpos-string|latency-rate-limited-1000_qps-memtier_benchmark-1key-list-2K-elements-quicklist-lrange-all-elements-longs|latency-rate-limited-1000_qps-memtier_benchmark-1key-zset-1K-elements-zrange-all-elements|latency-rate-limited-1000_qps-memtier_benchmark-2keys-zset-300-elements-skiplist-encoded-zunion|latency-rate-limited-1000_qps-memtier_benchmark-2keys-zset-300-elements-skiplist-encoded-zunionstore|latency-rate-limited-100_qps-memtier_benchmark-1key-1Billion-bits-bitmap-bitcount|memtier_benchmark-100Kkeys-hash-hgetall-50-fields-100B-values|memtier_benchmark-100Kkeys-load-hash-20-fields-with-1B-values-pipeline-30|memtier_benchmark-100Kkeys-load-hash-50-fields-with-1000B-values|memtier_benchmark-100Kkeys-load-hash-50-fields-with-100B-values|memtier_benchmark-100Kkeys-load-hash-50-fields-with-10B-values|memtier_benchmark-10Kkeys-load-hash-50-fields-with-10000B-values|memtier_benchmark-10Kkeys-load-list-with-10B-values-pipeline-50|memtier_benchmark-10Mkeys-load-hash-5-fields-with-1000B-values|memtier_benchmark-10Mkeys-load-hash-5-fields-with-1000B-values-pipeline-10|memtier_benchmark-10Mkeys-load-hash-5-fields-with-100B-values-pipeline-10|memtier_benchmark-10Mkeys-load-hash-5-fields-with-10B-values|memtier_benchmark-10Mkeys-load-hash-5-fields-with-10B-values-pipeline-10|memtier_benchmark-10Mkeys-string-get-10B-pipeline-100-nokeyprefix|memtier_benchmark-1Mkeys-100B-expire-use-case|memtier_benchmark-1Mkeys-10B-expire-use-case|memtier_benchmark-1Mkeys-10B-psetex-expire-use-case|memtier_benchmark-1Mkeys-10B-setex-expire-use-case|memtier_benchmark-1Mkeys-1KiB-expire-use-case|memtier_benchmark-1Mkeys-4KiB-expire-use-case|memtier_benchmark-1Mkeys-bitmap-getbit-pipeline-10|memtier_benchmark-1Mkeys-generic-exists-pipeline-10|memtier_benchmark-1Mkeys-generic-expireat-pipeline-10|memtier_benchmark-1Mkeys-generic-pexpire-pipeline-10|memtier_benchmark-1Mkeys-generic-scan-count-500-pipeline-10|memtier_benchmark-1Mkeys-generic-scan-cursor-count-500-pipeline-10|memtier_benchmark-1Mkeys-generic-scan-cursor-count-5000-pipeline-10|memtier_benchmark-1Mkeys-generic-scan-cursor-pipeline-10|memtier_benchmark-1Mkeys-generic-scan-pipeline-10|memtier_benchmark-1Mkeys-generic-scan-type-pipeline-10|memtier_benchmark-1Mkeys-generic-ttl-pipeline-10|memtier_benchmark-1Mkeys-hash-hexists|memtier_benchmark-1Mkeys-hash-hget-hgetall-hkeys-hvals-with-100B-values|memtier_benchmark-1Mkeys-hash-hgetall-50-fields-10B-values|memtier_benchmark-1Mkeys-hash-hincrby|memtier_benchmark-1Mkeys-hash-hincrbyfloat|memtier_benchmark-1Mkeys-hash-hmget-5-fields-with-100B-values-pipeline-10|memtier_benchmark-1Mkeys-hash-transactions-multi-exec-pipeline-20|memtier_benchmark-1Mkeys-lhash-hexists|memtier_benchmark-1Mkeys-lhash-hincbry|memtier_benchmark-1Mkeys-list-lpop-rpop-with-100B-values|memtier_benchmark-1Mkeys-list-lpop-rpop-with-10B-values|memtier_benchmark-1Mkeys-list-lpop-rpop-with-1KiB-values|memtier_benchmark-1Mkeys-list-rpoplpush-with-10B-values|memtier_benchmark-1Mkeys-load-hash-5-fields-with-1000B-values|memtier_benchmark-1Mkeys-load-hash-5-fields-with-1000B-values-pipeline-10|memtier_benchmark-1Mkeys-load-list-rpush-with-10B-values|memtier_benchmark-1Mkeys-load-list-with-100B-values|memtier_benchmark-1Mkeys-load-list-with-10B-values|memtier_benchmark-1Mkeys-load-list-with-10B-values-pipeline-10|memtier_benchmark-1Mkeys-load-list-with-1KiB-values|memtier_benchmark-1Mkeys-load-set-intset-with-100-elements|memtier_benchmark-1Mkeys-load-set-intset-with-100-elements-pipeline-10|memtier_benchmark-1Mkeys-load-stream-1-fields-with-100B-values|memtier_benchmark-1Mkeys-load-stream-1-fields-with-100B-values-pipeline-10|memtier_benchmark-1Mkeys-load-stream-5-fields-with-100B-values|memtier_benchmark-1Mkeys-load-stream-5-fields-with-100B-values-pipeline-10|memtier_benchmark-1Mkeys-load-string-with-100B-values|memtier_benchmark-1Mkeys-load-string-with-100B-values-pipeline-10|memtier_benchmark-1Mkeys-load-string-with-10B-values|memtier_benchmark-1Mkeys-load-string-with-10B-values-pipeline-10|memtier_benchmark-1Mkeys-load-string-with-10B-values-pipeline-100|memtier_benchmark-1Mkeys-load-string-with-10B-values-pipeline-100-nokeyprefix|memtier_benchmark-1Mkeys-load-string-with-10B-values-pipeline-50|memtier_benchmark-1Mkeys-load-string-with-10B-values-pipeline-500|memtier_benchmark-1Mkeys-load-string-with-1KiB-values|memtier_benchmark-1Mkeys-load-string-with-200KiB-values|memtier_benchmark-1Mkeys-load-string-with-20KiB-values|memtier_benchmark-1Mkeys-load-string-with-2MB-values|memtier_benchmark-1Mkeys-load-zset-with-10-elements-double-score|memtier_benchmark-1Mkeys-load-zset-with-10-elements-int-score|memtier_benchmark-1Mkeys-string-append-1-100B|memtier_benchmark-1Mkeys-string-append-1-100B-pipeline-10|memtier_benchmark-1Mkeys-string-decr|memtier_benchmark-1Mkeys-string-get-100B|memtier_benchmark-1Mkeys-string-get-100B-pipeline-10|memtier_benchmark-1Mkeys-string-get-10B-pipeline-10|memtier_benchmark-1Mkeys-string-get-10B-pipeline-100-nokeyprefix|memtier_benchmark-1Mkeys-string-get-10B-pipeline-500|memtier_benchmark-1Mkeys-string-get-1KiB|memtier_benchmark-1Mkeys-string-get-1KiB-pipeline-10|memtier_benchmark-1Mkeys-string-get-200KiB|memtier_benchmark-1Mkeys-string-get-20KiB|memtier_benchmark-1Mkeys-string-get-2MB|memtier_benchmark-1Mkeys-string-get-32B|memtier_benchmark-1Mkeys-string-get-32B-pipeline-10|memtier_benchmark-1Mkeys-string-incr-pipeline-10|memtier_benchmark-1Mkeys-string-incrby|memtier_benchmark-1Mkeys-string-incrby-pipeline-10|memtier_benchmark-1Mkeys-string-incrbyfloat|memtier_benchmark-1Mkeys-string-int-encoding-strlen-pipeline-10|memtier_benchmark-1Mkeys-string-mget-1KiB|memtier_benchmark-1Mkeys-string-mixed-50-50-set-get-100B|memtier_benchmark-1Mkeys-string-mixed-50-50-set-get-100B-pipeline-10|memtier_benchmark-1Mkeys-string-mixed-50-50-set-get-1KB|memtier_benchmark-1Mkeys-string-mixed-50-50-set-get-1KB-pipeline-10|memtier_benchmark-1Mkeys-string-mixed-50-50-set-get-32B|memtier_benchmark-1Mkeys-string-mixed-50-50-set-get-32B-pipeline-10|memtier_benchmark-1Mkeys-string-mixed-50-50-set-get-512B|memtier_benchmark-1Mkeys-string-mixed-50-50-set-get-512B-pipeline-10|memtier_benchmark-1Mkeys-string-mixed-50-50-set-get-with-expiration-240B-400_conns|memtier_benchmark-1Mkeys-string-set-with-ex-100B-pipeline-10|memtier_benchmark-1Mkeys-string-setex-100B-pipeline-10|memtier_benchmark-1Mkeys-string-setrange-100B-pipeline-10|memtier_benchmark-1key-1Billion-bits-bitmap-bitcount|memtier_benchmark-1key-geo-2-elements-geopos|memtier_benchmark-1key-geo-2-elements-geosearch-fromlonlat-withcoord|memtier_benchmark-1key-geo-60M-elements-geodist|memtier_benchmark-1key-geo-60M-elements-geodist-pipeline-10|memtier_benchmark-1key-geo-60M-elements-geohash|memtier_benchmark-1key-geo-60M-elements-geohash-pipeline-10|memtier_benchmark-1key-geo-60M-elements-geopos|memtier_benchmark-1key-geo-60M-elements-geopos-pipeline-10|memtier_benchmark-1key-geo-60M-elements-geosearch-fromlonlat|memtier_benchmark-1key-geo-60M-elements-geosearch-fromlonlat-bybox|memtier_benchmark-1key-geo-60M-elements-geosearch-fromlonlat-pipeline-10|memtier_benchmark-1key-hash-1K-fields-hgetall|memtier_benchmark-1key-hash-1K-fields-hgetall-pipeline-10|memtier_benchmark-1key-hash-hscan-50-fields-10B-values|memtier_benchmark-1key-list-10-elements-lrange-all-elements|memtier_benchmark-1key-list-10-elements-lrange-all-elements-pipeline-10|memtier_benchmark-1key-list-100-elements-int-7bit-uint-lrange-all-elements-pipeline-10|memtier_benchmark-1key-list-100-elements-int-lrange-all-elements-pipeline-10|memtier_benchmark-1key-list-100-elements-llen-pipeline-10|memtier_benchmark-1key-list-100-elements-lrange-all-elements|memtier_benchmark-1key-list-10K-elements-lindex-integer|memtier_benchmark-1key-list-10K-elements-lindex-string|memtier_benchmark-1key-list-10K-elements-lindex-string-pipeline-10|memtier_benchmark-1key-list-10K-elements-linsert-lrem-integer|memtier_benchmark-1key-list-10K-elements-linsert-lrem-string|memtier_benchmark-1key-list-10K-elements-lpos-integer|memtier_benchmark-1key-list-10K-elements-lpos-string|memtier_benchmark-1key-list-1K-elements-lrange-all-elements|memtier_benchmark-1key-list-1K-elements-lrange-all-elements-pipeline-10|memtier_benchmark-1key-list-2K-elements-quicklist-lrange-all-elements-longs|memtier_benchmark-1key-load-hash-1K-fields-with-5B-values|memtier_benchmark-1key-load-zset-with-5-elements-parsing-float-score|memtier_benchmark-1key-load-zset-with-5-elements-parsing-hexa-score|memtier_benchmark-1key-pfadd-4KB-values-pipeline-10|memtier_benchmark-1key-set-10-elements-smembers|memtier_benchmark-1key-set-10-elements-smembers-pipeline-10|memtier_benchmark-1key-set-10-elements-smismember|memtier_benchmark-1key-set-100-elements-sismember-is-a-member|memtier_benchmark-1key-set-100-elements-sismember-not-a-member|memtier_benchmark-1key-set-100-elements-smembers|memtier_benchmark-1key-set-100-elements-smismember|memtier_benchmark-1key-set-100-elements-sscan|memtier_benchmark-1key-set-10M-elements-sismember-50pct-chance|memtier_benchmark-1key-set-10M-elements-srem-50pct-chance|memtier_benchmark-1key-set-1K-elements-smembers|memtier_benchmark-1key-set-1M-elements-sismember-50pct-chance|memtier_benchmark-1key-set-200K-elements-sadd-constant|memtier_benchmark-1key-set-2M-elements-sadd-increasing|memtier_benchmark-1key-zincrby-1M-elements-pipeline-1|memtier_benchmark-1key-zrank-100K-elements-pipeline-1|memtier_benchmark-1key-zrank-1M-elements-pipeline-1|memtier_benchmark-1key-zrem-5M-elements-pipeline-1|memtier_benchmark-1key-zrevrangebyscore-256K-elements-pipeline-1|memtier_benchmark-1key-zrevrank-1M-elements-pipeline-1|memtier_benchmark-1key-zset-10-elements-zrange-all-elements|memtier_benchmark-1key-zset-10-elements-zrange-all-elements-long-scores|memtier_benchmark-1key-zset-100-elements-zrange-all-elements|memtier_benchmark-1key-zset-100-elements-zrangebyscore-all-elements|memtier_benchmark-1key-zset-100-elements-zrangebyscore-all-elements-long-scores|memtier_benchmark-1key-zset-100-elements-zscan|memtier_benchmark-1key-zset-1K-elements-zrange-all-elements|memtier_benchmark-1key-zset-1M-elements-zcard-pipeline-10|memtier_benchmark-1key-zset-1M-elements-zremrangebyscore-pipeline-10|memtier_benchmark-1key-zset-1M-elements-zrevrange-withscores-5-elements-pipeline-10|memtier_benchmark-1key-zset-1M-elements-zscore-pipeline-10|memtier_benchmark-1key-zset-600K-elements-zrangestore-1K-elements|memtier_benchmark-1key-zset-600K-elements-zrangestore-300K-elements|memtier_benchmark-1key-zset-listpack-zrank-100-elements-pipeline-1|memtier_benchmark-2keys-lua-eval-hset-expire|memtier_benchmark-2keys-lua-evalsha-hset-expire|memtier_benchmark-2keys-set-10-100-elements-sdiff|memtier_benchmark-2keys-set-10-100-elements-sinter|memtier_benchmark-2keys-set-10-100-elements-sunion|memtier_benchmark-2keys-stream-5-entries-xread-all-entries|memtier_benchmark-2keys-stream-5-entries-xread-all-entries-pipeline-10|memtier_benchmark-3Mkeys-load-string-with-512B-values|memtier_benchmark-3Mkeys-load-string-with-512B-values-pipeline-10|memtier_benchmark-3Mkeys-string-get-with-1KiB-values-pipeline-10-2000_conns|memtier_benchmark-3Mkeys-string-get-with-1KiB-values-pipeline-10-400_conns|memtier_benchmark-3Mkeys-string-get-with-1KiB-values-pipeline-10-40_conns|memtier_benchmark-3Mkeys-string-mixed-20-80-with-512B-values-pipeline-10-2000_conns|memtier_benchmark-3Mkeys-string-mixed-20-80-with-512B-values-pipeline-10-400_conns|memtier_benchmark-3Mkeys-string-mixed-20-80-with-512B-values-pipeline-10-5200_conns|memtier_benchmark-connection-hello|memtier_benchmark-connection-hello-pipeline-10|memtier_benchmark-nokeys-connection-ping-pipeline-10|memtier_benchmark-nokeys-pubsub-publish-1K-channels-10B-no-subscribers|memtier_benchmark-nokeys-server-time-pipeline-10|redis-benchmark-full-suite-1Mkeys-100B|redis-benchmark-full-suite-1Mkeys-100B-pipeline-10|redis-benchmark-full-suite-1Mkeys-1KiB|redis-benchmark-full-suite-1Mkeys-1KiB-pipeline-10|vector_db_benchmark_test

Copy link
Member

@oranagra oranagra left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

interface changes LGTM.
one thought i had is that maybe the APIs should have a uniform prefix rather than a uniform suffix.
i.e. all start with RM_Config. WDYT?

@minchopaskal minchopaskal force-pushed the module-config-cmd-api branch from 32b66e1 to 40bdd78 Compare June 17, 2025 11:18
@minchopaskal minchopaskal removed the action:run-benchmark Triggers the benchmark suite for this Pull Request label Jun 17, 2025
@sundb sundb requested a review from Copilot June 24, 2025 06:19
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR introduces a set/get configuration API for modules, allowing modules to access and modify various Redis configurations even when native commands are renamed or restricted. Key changes include:

  • New RedisModule API functions for config iteration, type retrieval, and get/set operations.
  • Refactoring of the internal configuration apply and backup restoration logic.
  • Updates to tests and module build files to cover the new APIs.

Reviewed Changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
tests/unit/moduleapi/configaccess.tcl Added tests for getting and setting various config types using the new module API.
tests/modules/configaccess.c Introduced new test commands implementing the module config API functions.
tests/modules/Makefile Updated to build the new configaccess module.
src/server.h Added declarations for new API functions used by modules to access config values.
src/redismodule.h Added new API function pointers and extended enum for config types.
src/module.c Extended auto-memory handling and introduced REDISMODULE_AM_CONFIG for config iterators.
src/config.c Refactored backup restoration and apply logic for both module and standard configs.
runtest-moduleapi Included the new configaccess unit tests in the test runner.
Comments suppressed due to low confidence (1)

src/config.c:3607

  • [nitpick] Passing the address of a single config and a single sds value to a function that expects arrays can be confusing; consider adding a dedicated helper for restoring a single config to enhance clarity.
        restoreBackupConfig(&config, &old_value, 1);

@minchopaskal minchopaskal force-pushed the module-config-cmd-api branch from 40bdd78 to 7fef8c0 Compare June 24, 2025 07:25
@sundb sundb added the state:needs-doc-pr requires a PR to redis-doc repository label Jun 24, 2025
# Run a dummy server on used_port so we know we can't configure redis to
# use it. It's ok for this to fail because that means used_port is invalid
# anyway
catch {set sockfd [socket -server dummy_accept -myaddr 127.0.0.1 $used_port]} e
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

forget to close it?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah yes, tnx

Copy link
Collaborator

@sundb sundb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@minchopaskal minchopaskal merged commit 15706f2 into redis:unstable Jul 3, 2025
18 checks passed
minchopaskal added a commit that referenced this pull request Jul 4, 2025
…14171)

Recent [PR](#14051) causes MSan to
fail during daily CI with uninitialized value warning.
It is not a bug per se as the uninitialized member is dependent on
another member not being NULL.
With this PR now MSan does not complain.
fcostaoliveira pushed a commit to filipecosta90/redis that referenced this pull request Jul 4, 2025
# Problem

Some redis modules need to call `CONFIG GET/SET` commands. Server may be
ran with `rename-command CONFIG ""`(or something similar) which leads to
the module being unable to access the config.

# Solution

Added new API functions for use by modules
```
RedisModuleConfigIterator* RedisModule_GetConfigIterator(RedisModuleCtx *ctx, const char *pattern);
void RedisModule_ReleaseConfigIterator(RedisModuleCtx *ctx, RedisModuleConfigIterator *iter);
const char *RedisModule_ConfigIteratorNext(RedisModuleConfigIterator *iter);
int RedisModule_GetConfigType(const char *name, RedisModuleConfigType *res);
int RedisModule_GetBoolConfig(RedisModuleCtx *ctx, const char *name, int *res);
int RedisModule_GetConfig(RedisModuleCtx *ctx, const char *name, RedisModuleString **res);
int RedisModule_GetEnumConfig(RedisModuleCtx *ctx, const char *name, RedisModuleString **res);
int RedisModule_GetNumericConfig(RedisModuleCtx *ctx, const char *name, long long *res);
int RedisModule_SetBoolConfig(RedisModuleCtx *ctx, const char *name, int value, RedisModuleString **err);
int RedisModule_SetConfig(RedisModuleCtx *ctx, const char *name, RedisModuleString *value, RedisModuleString **err);
int RedisModule_SetEnumConfig(RedisModuleCtx *ctx, const char *name, RedisModuleString *value, RedisModuleString **err);
int RedisModule_SetNumericConfig(RedisModuleCtx *ctx, const char *name, long long value, RedisModuleString **err);
```

## Implementation

The work is mostly done inside `config.c` as I didn't want to expose the
config dict outside of it. That means each of these module functions has
a corresponding method in `config.c` that actually does the job. F.e
`RedisModule_SetEnumConfig` calls `moduleSetEnumConfig` which is
implemented in `config.c`

## Notes

Also, refactored `configSetCommand` and `restoreBackupConfig` functions
for the following reasons:
- code and logic is now way more clear in `configSetCommand`. Only
caveat here is removal of an optimization that skipped running apply
functions that already have ran in favour of code clarity.
- Both functions needlessly separated logic for module configs and
normal configs whereas no such separation is needed. This also had the
side effect of removing some allocations.
- `restoreBackupConfig` now has clearer interface and can be reused with
ease. One of the places I reused it is for the individual
`moduleSet*Config` functions, each of which needs the restoration
functionality but for a single config only.

## Future

Additionally, a couple considerations were made for potentially
extending the API in the future
- if need be an API for atomically setting multiple config values can be
added - `RedisModule_SetConfigsTranscationStart/End` or similar that can
be put around `RedisModule_Set*Config` calls.
- if performance is an issue an API
`RedisModule_GetConfigIteratorNextWithTypehint` or similar may be added
in order not to incur the additional cost of calling
`RedisModule_GetConfigType`.

---------

Co-authored-by: Oran Agra <[email protected]>
@sundb sundb mentioned this pull request Aug 4, 2025
sundb added a commit that referenced this pull request Aug 4, 2025
This is the General Availability release of Redis Open Source 8.2.

### Major changes compared to 8.0

- Streams - new commands: `XDELEX` and `XACKDEL`; extension to `XADD`
and `XTRIM`
- Bitmap - `BITOP`: new operators: `DIFF`, `DIFF1`, `ANDOR`, and `ONE`
- Query Engine - new SVS-VAMANA vector index type which supports vector
compression
- More than 15 performance and resource utilization improvements
- New metrics: per-slot usage metrics, key size distributions for basic
data types, and more

### Binary distributions

- Alpine and Debian Docker images - https://hub.docker.com/_/redis
- Install using snap - see https://github.com/redis/redis-snap
- Install using brew - see https://github.com/redis/homebrew-redis
- Install using RPM - see https://github.com/redis/redis-rpm
- Install using Debian APT - see https://github.com/redis/redis-debian


### Operating systems we test Redis 8.2 on

- Ubuntu 22.04 (Jammy Jellyfish), 24.04 (Noble Numbat)
- Rocky Linux 8.10, 9.5
- AlmaLinux 8.10, 9.5
- Debian 12 (Bookworm)
- macOS 13 (Ventura), 14 (Sonoma), 15 (Sequoia)

### Security fixes (compared to 8.2-RC1)

- (CVE-2025-32023) Fix out-of-bounds write in `HyperLogLog` commands
- (CVE-2025-48367) Retry accepting other connections even if the
accepted connection reports an error

### New Features (compared to 8.2-RC1)

- #14141 Keyspace notifications - new event types:
  - `OVERWRITTEN` - the value of a key is completely overwritten
  - `TYPE_CHANGED` - key type change

### Bug fixes (compared to 8.2-RC1)

- #14162 Crash when using evport with I/O threads
- #14163 `EVAL` crash when error table is empty
- #14144 Vector sets - RDB format is not compatible with big endian
machines
- #14165 Endless client blocking for blocking commands
- #14164 Prevent `CLIENT UNBLOCK` from unblocking `CLIENT PAUSE`
- #14216 TTL was not removed by the `SET` command
- #14224 `HINCRBYFLOAT` removes field expiration on replica

### Performance and resource utilization improvements (compared to
8.2-RC1)

- #14200 Store iterators on stack instead of on heap
- #14144 Vector set - improve RDB loading / RESTORE speed by storing the
worst link info
- #Q6430 More compression variants for the SVS-VAMANA vector index
- #Q6535 `SHARD_K_RATIO` parameter - favor network latency over accuracy
for KNN vector query in a Redis cluster (unstable feature) (MOD-10359)

### Modules API

- #14051 `RedisModule_Get*`, `RedisModule_Set*` - allow modules to
access Redis configurations
- #14114 `RM_UnsubscribeFromKeyspaceEvents` - unregister a module from
specific keyspace notifications
minchopaskal added a commit that referenced this pull request Oct 28, 2025
Revert a breaking change introduced in #14051 described in this comment
#14051 (comment)

The non-negative check inside `checkNumericBoundaries` was ignoring that
passing a big unsigned long long value (> 2^63-1) will be passed as
negative value and will never reach the lower/upper boundary check.

The check is removed, reverting the breaking change.

This allows for RedisModule_ConfigSetNumeric to pass big unsigned number, albeit via `long long` parameter. Added comments about this behaviour.

Added tests for #14051 (comment)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

release-notes indication that this issue needs to be mentioned in the release notes state:needs-doc-pr requires a PR to redis-doc repository

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants