Compare commits

...
150 Commits
Author SHA1 Message Date
Jacob MurphyandGitHub cd7ca4c9c0 Release notes for 7.2.9 (#1996)
Signed-off-by: Jacob Murphy <jkmurphy@google.com>
2025-04-23 13:01:14 -07:00
uriyageandGitHub 6513ac47b3 Add output buffer limiting for unauthenticated clients (#1992)
This commit introduces a mechanism to track client authentication state
with a new `ever_authenticated` flag.
It refactors client authentication handling by adding a `clientSetUser`
function that properly sets both the authenticated and
`ever_authenticated` flags.

The implementation limits output buffer size for clients that have never
been authenticated.

Added tests to verify the output buffer limiting behavior for
unauthenticated clients.

---------

Signed-off-by: Uri Yagelnik <uriy@amazon.com>
Signed-off-by: Viktor Söderqvist <viktor.soderqvist@est.tech>
2025-04-23 20:26:34 +02:00
Harkrishn PatroandViktor Söderqvist b67292acbf Update upload artifacts to v4 (#1539)
Fixes #1538

Signed-off-by: Harkrishn Patro <harkrisp@amazon.com>
Signed-off-by: Jacob Murphy <jkmurphy@google.com>
2025-04-23 19:03:29 +02:00
Vitah LinandViktor Söderqvist e6ed6f91b1 Fix CI latest fedora: install awk and tcl8, build tcltls from source (#1965)
Fix two problems in fedora CI jobs:

1. Install awk where missing. It's required for building jemalloc.
2. Fix problems with TCL, required for running the tests. Fedora comes
   with TCL 9 by default, but the TLS package 'tcltls' isn't built for TCL 9.
   Install 'tcl8' and build 'tcltls' from source.

---------

Signed-off-by: vitah <vitahlin@gmail.com>
Signed-off-by: Viktor Söderqvist <viktor.soderqvist@est.tech>
Co-authored-by: Viktor Söderqvist <viktor.soderqvist@est.tech>
Signed-off-by: Jacob Murphy <jkmurphy@google.com>
2025-04-23 19:03:29 +02:00
Jacob MurphyandViktor Söderqvist f99cb12b9c Fix flaky shutdown tests caused by timing issue (#1960)
This started failing after
https://github.com/valkey-io/valkey/commit/57cd9a51d9c7d8cf9c4551bd1f2af79a0f279eeb,
since processing of SHUTDOWN might happen after the CLIENT INFO is
retrieved. Now we use wait_for_condition to make sure CLIENT INFO is
retried in the case that SHUTDOWN is not processed yet.

Signed-off-by: Jacob Murphy <jkmurphy@google.com>
2025-04-23 19:03:29 +02:00
nesty92andViktor Söderqvist 977d162690 Fix incorrect lag reported in XINFO GROUPS (#1952)
When a tombstone is created after the last_id of a consumer group.

The consumer group lag is reported in the reply of `XINFO GROUPS mystream`.

Close: #1951

Signed-off-by: Ernesto Alejandro Santana Hidalgo <ernesto.alejandrosantana@gmail.com>
Signed-off-by: Jacob Murphy <jkmurphy@google.com>
2025-04-23 19:03:29 +02:00
Jacob MurphyandViktor Söderqvist 9abcee6214 Fix panic in primary when blocking shutdown after previous block with timeout (#1948)
When previous timeout isn't zeroed out, shutdown will use the previously
executed blocking commands timeout. Since shutdown is not expected to
have timeouts, this causes a serverPanic.

Without this fix, this scenario leads to a server panic:

1. Call any command that uses blockClient with a timeout (this could be
BLPOP or something that blocks implicitly like CLUSTER SETSLOT)
2. On the same client, call SHUTDOWN with some pending replication data,
which will trigger shutdown to be blocked while we try to catch the
replica up

Signed-off-by: Jacob Murphy <jkmurphy@google.com>
2025-04-23 19:03:29 +02:00
Arthur LeeandViktor Söderqvist aacf75f2fb fix: add samples to stream object consumer trees (#1825)
Use sampling when calculating the memory usage of consumers as part of
streams in MEMORY USAGE and MEMORY STATS.

Without this fix, all consumers are traversed, which is slow if there
are very many consumers.

Fixes #1824

Signed-off-by: arthur.lee <liziang.arthur@bytedance.com>
Signed-off-by: Jacob Murphy <jkmurphy@google.com>
2025-04-23 19:03:29 +02:00
7176676a34 Fix RANDOMKEY infinite loop during CLIENT PAUSE (#1850)
When the `client pause write` is set and all the keys in the server
are expired keys, executing the `randomkey` command will lead to an
infinite loop.

The reason is that expired keys are not deleted in this case. Limit
the number of tries and return an expired key after the max number
tries in this case.

Closes #1848.

---------

Signed-off-by: li-benson <1260437731@qq.com>
Signed-off-by: youngmore <youngmore1024@outlook.com>
Signed-off-by: Viktor Söderqvist <viktor.soderqvist@est.tech>
Co-authored-by: youngmore <youngmore1024@outlook.com>
Co-authored-by: Viktor Söderqvist <viktor.soderqvist@est.tech>
Signed-off-by: Jacob Murphy <jkmurphy@google.com>
2025-04-23 19:03:29 +02:00
c41fd60d8d Fix error "SSL routines::bad length" when connTLSWrite is called second time with smaller buffer (#1737)
Issue described in #1135

When call to `connTLSWrite` fails on next attempt `connTLSWritev` should
provide buffer with at least same amount of bytes,
but if first call was with buffer smaller than
`NET_MAX_WRITES_PER_EVENT` then buffer gets larger and exceed
`NET_MAX_WRITES_PER_EVENT`, `connTLSWritev` will not combine `iov` into
one buffer resulting into chance that first element of `iov` is smaller
than last failed call to `connTLSWrite` and causing `SSL routines::bad
length`.

This change force combining `iov`s into one buffer if first element of
`iov` is smaller than last failed write by `connTLSWrite`

---------

Signed-off-by: Marek Zoremba <marek@janeasystems.com>
Signed-off-by: Madelyn Olson <madelyneolson@gmail.com>
Signed-off-by: ranshid <ranshid@amazon.com>
Co-authored-by: Madelyn Olson <madelyneolson@gmail.com>
Co-authored-by: ranshid <ranshid@amazon.com>
Signed-off-by: Jacob Murphy <jkmurphy@google.com>
2025-04-23 19:03:29 +02:00
45172387f5 Fix raxRemove crash at memcpy() due to key size exceeds max Rax size (#1722)
Fix raxRemove crash at memcpy() (line 1181) due to key size exceeds
`RAX_NODE_MAX_SIZE`. Note that this could happen when key size was more
than 512MB if we allow it by increasing the default
`proto-max-bulk-len`. The crash could happen when we recompress the rax
after removing a key due to expiry or DEL while memcpy() merge the key
that exceed 512MB limit. While the counting phase has the size check,
the actual compress logic is missing it which lead to this crash.

---------

Signed-off-by: Ram Prasad Voleti <ramvolet@amazon.com>
Co-authored-by: Ram Prasad Voleti <ramvolet@amazon.com>
Signed-off-by: Jacob Murphy <jkmurphy@google.com>
2025-04-23 19:03:29 +02:00
BinbinandViktor Söderqvist 95dc162858 Fix module LatencyAddSample still work when latency-monitor-threshold is 0 (#1541)
When latency-monitor-threshold is set to 0, it means the latency monitor
is disabled, and in VM_LatencyAddSample, we wrote the condition
incorrectly, causing us to record latency when latency was turned off.

This bug was introduced in the very first day, see 144277c, it was merged
in 2019.

Signed-off-by: Binbin <binloveplay1314@qq.com>
Signed-off-by: Jacob Murphy <jkmurphy@google.com>
2025-04-23 19:03:29 +02:00
Yury-FridlyandandViktor Söderqvist cfe8b9637b Fix CI concurrency (#849)
Few CI improvements witch will reduce occupation CI queue and eliminate
stale runs.

1. Kill CI jobs on PRs once PR branch gets a new push. This will prevent
situation happened today - a huge job triggered twice in less than an
hour and occupied all **org** (for all repositories) runners queue for
the rest of the day (see pic). This completely blocked valkey-glide
team.
2. Distribute nightly croned jobs on time to prevent them running
together. Keep in mind, cron's TZ is UTC, so midnight tasks incur
developers located in other timezones.

This must be backported to all release branches (`valkey-x.y` and `x.y`)

![image](https://github.com/user-attachments/assets/923d8237-3cb7-42f5-80c8-5322b3f5187d)

---------

Signed-off-by: Yury-Fridlyand <yury.fridlyand@improving.com>
Signed-off-by: Jacob Murphy <jkmurphy@google.com>
2025-04-23 19:03:29 +02:00
2c9255310a [Backport 7.2] Moved build-release automation to valkey-release-automation (#1987)
All the Valkey Release automation has been moved and setup here:
https://github.com/valkey-io/valkey-release-automation

The release automation will now be triggered from the
[trigger-build-release.yml](https://github.com/valkey-io/valkey/blob/unstable/.github/workflows/trigger-build-release.yml)
workflow.

Need to remove these files to stop duplicating push to the s3 bucket.

---------

Signed-off-by: Roshan Khatri <rvkhatri@amazon.com>
Signed-off-by: Nikhil Manglore <nmanglor@amazon.com>
Co-authored-by: Roshan Khatri <117414976+roshkhatri@users.noreply.github.com>
2025-04-22 17:40:03 -07:00
PierreandGitHub ec67e6f9ed Backport "Fix memory leak in forgotten node ping ext code path" to 7.2 (#1576)
When processing a cluster bus PING extension, there is a memory leak
when adding a new key to the `nodes_black_list` dict. We now make sure
to free the key `sds` if the dict did not take ownership of it.

Backport of #1574 from unstable.

Signed-off-by: Pierre Turin <pieturin@amazon.com>
2025-04-15 20:23:15 +02:00
Roshan KhatriandViktor Söderqvist 3827624e3c Migrate binaries build to ARM github runners
Signed-off-by: Roshan Khatri <rvkhatri@amazon.com>
2025-04-15 09:40:42 +02:00
Nikhil MangloreandViktor Söderqvist 05428aed4b Update correct repository name for automation trigger workflow (#1855)
Update automation repository name to `valkey-release-automation`

Signed-off-by: Nikhil Manglore <nmanglor@amazon.com>
2025-04-15 09:40:42 +02:00
6ecea600f0 Trigger post-release tasks in Valkey for a new release (#1830)
This trigger-build-release.yml file will be used to automate the release
process as described in #1397. It will trigger the post release task after a new release

---------

Signed-off-by: Nikhil Manglore <nmanglor@amazon.com>
Signed-off-by: Nikhil Manglore <nikhilmanglore9@gmail.com>
Co-authored-by: Roshan Khatri <117414976+roshkhatri@users.noreply.github.com>
2025-04-15 09:40:42 +02:00
BinbinandGitHub 5571f95373 Fix defrag crash when using FLUSHDB ASYNC in cluster mode (#1873)
There is a crash report in #1872:
```
=== REDIS BUG REPORT START: Cut & paste starting from here ===
69308:M 22 Mar 2025 08:35:10.242 # valkey 7.2.8 crashed by signal: 11, si_code: 1
69308:M 22 Mar 2025 08:35:10.245 # Accessing address: 0x50
69308:M 22 Mar 2025 08:35:10.246 # Crashed running the instruction at: 0x109e82510

------ STACK TRACE ------
EIP:
0   valkey-server                       0x0000000109e82510 dbDictAfterReplaceEntry + 576

Backtrace:
0   libsystem_platform.dylib            0x00007ff801d12e1d _sigtramp + 29
1   ???                                 0x0000000000000000 0x0 + 0
2   valkey-server                       0x0000000109e81782 dictDefragBucket + 354
3   valkey-server                       0x0000000109e813ec dictScanDefrag + 732
4   valkey-server                       0x0000000109faa520 activeDefragCycle + 592
5   valkey-server                       0x0000000109e86b8e serverCron + 4974
6   valkey-server                       0x0000000109e7e466 aeProcessEvents + 1094
7   valkey-server                       0x0000000109ea29ad main + 24781
8   dyld                                0x00007ff80194d2cd start + 1805
```

The reason is that when doing FLUSHDB async, in emptyDbAsync, after we create
the new dict, we did not call slotToKeyInit to init the clusterDictMetadata.
And then in slotToKeyReplaceEntry we will get a wrong pointer and crash.

This issue only occurs under 7.2 since the code structure changed in unstable
branch. Fixes #1872.

Signed-off-by: Binbin <binloveplay1314@qq.com>
2025-04-10 10:57:24 +08:00
Roshan KhatriandGitHub 5937a59be0 Backport - Fix Valkey binary build workflow, version support changes. (#1429) (#1716)
Backport - Fix Valkey binary build workflow, version support changes.
(#1429)
This change makes the binary build on the target ubuntu version.

This PR also deprecated ubuntu18 and valkey will not support.

- X86:
  - Ubuntu 20
  - Ubuntu 22
  - Ubuntu 24
 - ARM:
   - Ubuntu 20
   - Ubuntu 22

Removed ARM ubuntu 24 as the action we are using for ARM builds does not
support Ubuntu 24.

---------

Signed-off-by: Roshan Khatri <rvkhatri@amazon.com>
2025-02-12 10:31:26 -08:00
a4cd0526d3 Update 00-RELEASENOTES
Co-authored-by: Viktor Söderqvist <viktor.soderqvist@est.tech>
Signed-off-by: Harkrishn Patro <bunty.hari@gmail.com>
2025-01-08 11:35:54 -08:00
Harkrishn PatroandHarkrishn Patro 8cd5faa63d Update release valkey version 2025-01-08 11:35:54 -08:00
Harkrishn PatroandHarkrishn Patro ede3eb14bb Fix build failure for macos 2025-01-08 11:35:54 -08:00
ranshidandHarkrishn Patro e1344755f6 change the container image to ubuntu:plucky (#1359)
Our fortify workflow is running on ubuntu lunar container that is EOL
since [January 25, 2024(January 25,
2024](https://lists.ubuntu.com/archives/ubuntu-announce/2024-January/000298.html).
This case cause the workflow to fail during update actions like:
```
apt-get update && apt-get install -y make gcc-13
  update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-1[3](https://github.com/valkey-io/valkey/actions/runs/12021130026/job/33547460209#step:5:3) 100
  make all-with-unit-tests CC=gcc OPT=-O3 SERVER_CFLAGS='-Werror -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=3'
  shell: sh -e {0}
Ign:1 http://security.ubuntu.com/ubuntu lunar-security InRelease
Err:2 http://security.ubuntu.com/ubuntu lunar-security Release
  [4](https://github.com/valkey-io/valkey/actions/runs/12021130026/job/33547460209#step:5:4)04  Not Found [IP: 91.189.91.82 80]
Ign:3 http://archive.ubuntu.com/ubuntu lunar InRelease
Ign:4 http://archive.ubuntu.com/ubuntu lunar-updates InRelease
Ign:[5](https://github.com/valkey-io/valkey/actions/runs/12021130026/job/33547460209#step:5:5) http://archive.ubuntu.com/ubuntu lunar-backports InRelease
Err:[6](https://github.com/valkey-io/valkey/actions/runs/12021130026/job/33547460209#step:5:7) http://archive.ubuntu.com/ubuntu lunar Release
  404  Not Found [IP: 185.125.190.81 80]
Err:7 http://archive.ubuntu.com/ubuntu lunar-updates Release
  404  Not Found [IP: 185.125.190.81 80]
Err:8 http://archive.ubuntu.com/ubuntu lunar-backports Release
  404  Not Found [IP: 185.125.190.81 80]
Reading package lists...
E: The repository 'http://security.ubuntu.com/ubuntu lunar-security Release' does not have a Release file.
E: The repository 'http://archive.ubuntu.com/ubuntu lunar Release' does not have a Release file.
E: The repository 'http://archive.ubuntu.com/ubuntu lunar-updates Release' does not have a Release file.
E: The repository 'http://archive.ubuntu.com/ubuntu lunar-backports Release' does not have a Release file.
update-alternatives: error: alternative path /usr/bin/gcc-[13](https://github.com/valkey-io/valkey/actions/runs/12021130026/job/33547460209#step:5:14) doesn't exist
Error: Process completed with exit code 2.
```

example:
https://github.com/valkey-io/valkey/actions/runs/12021130026/job/33547460209

This pr uses the latest stable ubuntu image release
[plucky](https://hub.docker.com/layers/library/ubuntu/plucky/images/sha256-dc4565c7636f006c26d54c988faae576465e825ea349fef6fd3af6bf5100e8b6?context=explore)

Signed-off-by: Ran Shidlansik <ranshid@amazon.com>
2025-01-08 11:35:54 -08:00
Roshan KhatriandHarkrishn Patro 2fdf7bda64 Workflow changes to fix old release binaries (#1461)
- Moves `build-config.json` to workflow dir to build old versions with
new configs.
- Enables contributors to test release Wf on private repo by adding
`github.event_name == 'workflow_dispatch' ||`

---------

Signed-off-by: Roshan Khatri <rvkhatri@amazon.com>
2025-01-08 11:35:54 -08:00
BinbinandHarkrishn Patro c8c1942f07 Fix wrong file name in build-release-packages.yml (#1437)
Introduced in #1363, the file name does not match.

Signed-off-by: Binbin <binloveplay1314@qq.com>
2025-01-08 11:35:54 -08:00
Roshan KhatriandHarkrishn Patro 0d64300faa Fix the secrete for test bucket. (#1447)
We have set the secret as `AWS_S3_TEST_BUCKET` for test bucket and I
missed it in the initial review.

Signed-off-by: Roshan Khatri <rvkhatri@amazon.com>
2025-01-08 11:35:54 -08:00
Vu DiepandHarkrishn Patro 3bf3c737c4 Use configure-aws-credentials workflow instead of passing secret_access_key (#1363)
This PR fixes #1346 where we can get rid of the long term credentials by
using OpenID Connect. OpenID Connect (OIDC) allows your GitHub Actions
workflows to access resources in Amazon Web Services (AWS), without
needing to store the AWS credentials as long-lived GitHub secrets.

---------

Signed-off-by: vudiep411 <vdiep@amazon.com>
2025-01-08 11:35:54 -08:00
BinbinandHarkrishn Patro f51d7599c9 Skip build-release-packages CI job in forks (#1438)
The CI job was introduced in #1363, we should skip it in forks.

Signed-off-by: Binbin <binloveplay1314@qq.com>
2025-01-08 11:35:54 -08:00
BinbinandHarkrishn Patro 7a0f6bef40 Skip IPv6 tests when TCLSH version is < 8.6 (#910)
In #786, we did skip it in the daily, but not for the others.
When running ./runtest on MacOS, we will get the failure.
```
couldn't open socket: host is unreachable (nodename nor servname provided, or not known)
```

The reason is that TCL 8.5 doesn't support ipv6, so we skip tests
tagged with ipv6. This also revert #786.

Signed-off-by: Binbin <binloveplay1314@qq.com>
2025-01-08 11:35:54 -08:00
Yury-FridlyandandHarkrishn Patro af077cb972 Fix CI concurrency (#849)
Few CI improvements witch will reduce occupation CI queue and eliminate
stale runs.

1. Kill CI jobs on PRs once PR branch gets a new push. This will prevent
situation happened today - a huge job triggered twice in less than an
hour and occupied all **org** (for all repositories) runners queue for
the rest of the day (see pic). This completely blocked valkey-glide
team.
2. Distribute nightly croned jobs on time to prevent them running
together. Keep in mind, cron's TZ is UTC, so midnight tasks incur
developers located in other timezones.

This must be backported to all release branches (`valkey-x.y` and `x.y`)

![image](https://github.com/user-attachments/assets/923d8237-3cb7-42f5-80c8-5322b3f5187d)

---------

Signed-off-by: Yury-Fridlyand <yury.fridlyand@improving.com>
2025-01-08 11:35:54 -08:00
Viktor SöderqvistandHarkrishn Patro e957ae0444 Skip IPv6 tests on MacOS (daily) (#786)
Signed-off-by: Viktor Söderqvist <viktor.soderqvist@est.tech>
2025-01-08 11:35:54 -08:00
0d4eb06171 Replace centos 7 with alternative versions (#543)
replace centos 7 with almalinux 8, add almalinux 9, centos stream 9, fedora stable, rawhide

Fixes #527

---------

Signed-off-by: Jonathan Wright <jonathan@almalinux.org>
Signed-off-by: Madelyn Olson <madelyneolson@gmail.com>
Co-authored-by: Madelyn Olson <madelyneolson@gmail.com>
2025-01-08 11:35:54 -08:00
eaed026574 Deprecate MacOS 11 build target (#524)
Deprecate MacOS 11 build target. End of life June 2024.  Fixes #523

---------

Signed-off-by: Siddhartha Mondal <siddharthmondal@gmail.com>
Co-authored-by: Madelyn Olson <madelyneolson@gmail.com>
Co-authored-by: Roshan Khatri <117414976+roshkhatri@users.noreply.github.com>
2025-01-08 11:35:54 -08:00
Madelyn OlsonandHarkrishn Patro b02b49b9ba Automatically notify the slack channel when tests fail (#509)
Adds a job that will automatically run at the end of the daily, which
will collect all the failed tests and send them to the developer slack.
It will include a link to the job as well.

Example job that ran on my private repo:
https://github.com/madolson/valkey/actions/runs/9123245899/job/25085418567

Example notification:
<img width="662" alt="image"
src="https://github.com/valkey-io/valkey/assets/34459052/69127db4-e416-4321-bc06-eefcecab1130">
(Note: I removed the sassy text at the bottom from the PR)

Signed-off-by: Madelyn Olson <madelyneolson@gmail.com>
2025-01-08 11:35:54 -08:00
Björn SvenssonandHarkrishn Patro 8207559757 Pin versions of Github Actions in CI (#221)
Pin the Github Action dependencies to the hash according to secure
software development best practices
recommended by the Open Source Security Foundation (OpenSSF).

When developing a CI workflow, it's common to version-pin dependencies
(i.e. actions/checkout@v4). However, version tags are mutable, so a
malicious attacker could overwrite a version tag to point to a malicious
or vulnerable commit instead.
Pinning workflow dependencies by hash ensures the dependency is
immutable and its behavior is guaranteed.
See
https://github.com/ossf/scorecard/blob/main/docs/checks.md#pinned-dependencies

The `dependabot` supports updating a hash and the version comment so its
update will continue to work as before.

Links to used actions and theit tag/hash for review/validation:
https://github.com/actions/checkout/tags    (v4.1.2 was rolled back)
https://github.com/github/codeql-action/tags
https://github.com/maxim-lobanov/setup-xcode/tags
https://github.com/cross-platform-actions/action/releases/tag/v0.22.0
https://github.com/py-actions/py-dependency-install/tags
https://github.com/actions/upload-artifact/tags
https://github.com/actions/setup-node/tags
https://github.com/taiki-e/install-action/releases/tag/v2.32.2

This PR is part of #211.

Signed-off-by: Björn Svensson <bjorn.a.svensson@est.tech>
2025-01-08 11:35:54 -08:00
21caff001d Add Codecov for Automated Code Coverage (#316)
This PR introduces Codecov to automate code coverage tracking for our
project's tests.

For more information about the Codecov platform, please refer to
https://docs.codecov.com/docs/quick-start

---------

Signed-off-by: Vitah Lin <vitahlin@gmail.com>
Co-authored-by: Madelyn Olson <madelyneolson@gmail.com>
2025-01-08 11:35:54 -08:00
Björn SvenssonandHarkrishn Patro 86d20aa745 Set permissions for Github Actions in CI (#312)
This sets the default permission for current CI workflows to only be
able to read from the repository (scope: "contents").
When a used Github Action require additional permissions (like CodeQL)
we grant that permission on job-level instead.

This means that a compromised action will not be able to modify the repo
or even steal secrets since all other permission-scopes are implicit set
to "none", i.e. not permitted. This is recommended by
[OpenSSF](https://github.com/ossf/scorecard/blob/main/docs/checks.md#token-permissions).

This PR includes a small fix for the possibility of missing server logs
artifacts, found while verifying the permission.
The `upload-artifact@v3` action will replace artifacts which already
exists. Since both CI-jobs `test-external-standalone` and
`test-external-nodebug` uses the same artifact name, when both jobs
fail, we only get logs from the last finished job. This can be avoided
by using unique artifact names.

This PR is part of #211

More about permissions and scope can be found here:

https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#permissions

---------

Signed-off-by: Björn Svensson <bjorn.a.svensson@est.tech>
2025-01-08 11:35:54 -08:00
Harkrishn PatroandHarkrishn Patro 5d2aff4677 Add release notes for 7.2.8 2025-01-08 11:35:54 -08:00
8f897ce91f Fix LUA garbage collector (CVE-2024-46981) (#1513)
Reset GC state before closing the lua VM to prevent user data to be
wrongly freed while still might be used on destructor callbacks.

Created and publish by Redis in their OSS branch.

Signed-off-by: Madelyn Olson <madelyneolson@gmail.com>
Co-authored-by: YaacovHazan <yaacov.hazan@redis.com>
2025-01-08 11:35:54 -08:00
b4543045dc Fix Read/Write key pattern selector (CVE-2024-51741) (#1514)
The explanation on the original commit was wrong. Key based access must
have a `~` in order to correctly configure whey key prefixes to apply
the selector to. If this is missing, a server assert will be triggered
later.

Signed-off-by: Madelyn Olson <madelyneolson@gmail.com>
Co-authored-by: YaacovHazan <yaacov.hazan@redis.com>
2025-01-08 11:35:54 -08:00
a379db854f Use the correct command proc for the LOOKUP_NOTOUCH exception in lookupKey (#1499)
When looking up a key in no-touch mode, `LOOKUP_NOTOUCH` is set to avoid
updating the last access time in `lookupKey`. An exception must be made
for the `TOUCH` command which must always update the key.

When called from a script, `server.executing_client` will point to the
`TOUCH` command, while `server.current_client` will point to e.g. an
`EVAL` command. So, we must use the former to find out the currently
executing command if defined.

This fix addresses the issue where TOUCH wasn't updating key access
times when called from scripts like EVAL.

Fixes #1498

Signed-off-by: Simon Baatz <gmbnomis@gmail.com>
Co-authored-by: Binbin <binloveplay1314@qq.com>
2025-01-08 11:35:54 -08:00
muelstefamznandHarkrishn Patro 08f508d668 Trim free space from inline command argument strings to avoid excess memory usage (#1213)
The command argument strings created while parsing inline commands (see
`processInlineBuffer()`) can contain free capacity. Since some commands
,such as `SET`, store these strings in the database, that free capacity
increases the memory usage. In the worst case, it could double the
memory usage.

This only occurs if the inline command format is used. The argument
strings are built by appending character by character in
`sdssplitargs()`. Regular RESP commands are not affected.

This change trims the strings within `processInlineBuffer()`.

this?

When the command argument string is packed into an object,
`trimStringObjectIfNeeded()` is called.

This does only trim the string if it is larger than
`PROTO_MBULK_BIG_ARG` (32kB), as only strings larger than this would
ever need trimming if the command it sent using the bulk string format.

We could modify this condition, but that would potentially have a
performance impact on commands using the bulk format. Since those make
up for the vast majority of executed commands, limiting this change to
inline commands seems prudent.

* 1 million `SET [key] [value]` commands
* Random keys (16 bytes)
* 600 bytes values

Memory usage without this change:

```
used_memory:1089327888
used_memory_human:1.01G
used_memory_rss:1131696128
used_memory_rss_human:1.05G
used_memory_peak:1089348264
used_memory_peak_human:1.01G
used_memory_peak_perc:100.00%
used_memory_overhead:49302800
used_memory_startup:911808
used_memory_dataset:1040025088
used_memory_dataset_perc:95.55%
```

Memory usage with this change:
```
used_memory:705327888
used_memory_human:672.65M
used_memory_rss:718802944
used_memory_rss_human:685.50M
used_memory_peak:705348256
used_memory_peak_human:672.67M
used_memory_peak_perc:100.00%
used_memory_overhead:49302800
used_memory_startup:911808
used_memory_dataset:656025088
used_memory_dataset_perc:93.13%
```

If the same experiment is repeated using the normal RESP array of bulk
string format (`*3\r\n$3\r\nSET\r\n...`) then the memory usage is 672MB
with and without of this change.

If a replica is attached, its memory usage is 672MB with and without
this change, since the replication link never uses inline commands.

Signed-off-by: Stefan Mueller <muelstef@amazon.com>
2025-01-08 11:35:54 -08:00
BinbinandHarkrishn Patro d90d042c70 Fix FUNCTION KILL error message being displayed as SCRIPT KILL (#1171)
The client that was killed by FUNCTION KILL received a reply of
SCRIPT KILL and the server log also showed SCRIPT KILL.

Signed-off-by: Binbin <binloveplay1314@qq.com>
2025-01-08 11:35:54 -08:00
Madelyn OlsonandGitHub 984c0a2c79 Apply security fixes for CVEs (#1113)
Apply the security fixes for the release.

(CVE-2024-31449) Lua library commands may lead to stack overflow and
potential RCE.
(CVE-2024-31227) Potential Denial-of-service due to malformed ACL
selectors.
(CVE-2024-31228) Potential Denial-of-service due to unbounded pattern
matching.

---------

Signed-off-by: Madelyn Olson <madelyneolson@gmail.com>
2024-10-02 13:11:08 -07:00
Melroy van den BergandViktor Söderqvist 6d9b16fb9f Build binary releases with systemd support (#1107)
- Add systemd support to the build artifact tarballs, so people can use
it under systemd compatible distros. As discussed here:
https://github.com/orgs/valkey-io/discussions/1103#discussioncomment-10815549.
Adding `libsystemd-dev` to install and add `USE_SYSTEMD=yes` to the
build.
- Cleanup & bring the arm & x86 workflow files in-sync. It was a bit of
a mess ;) (removing `jq wget awscli` from the 'Tarball' step)

Signed-off-by: Melroy van den Berg <melroy@melroy.org>
2024-10-02 20:11:12 +02:00
Melroy van den BergandViktor Söderqvist 85abdd5e97 Avoid .c, .d and .o files from being copied to the binary tar.gz releases (#1106)
As discussed here:
https://github.com/orgs/valkey-io/discussions/1103#discussioncomment-10814006

`cp` can't be used anymore, `rsync` is more powerful and allow to
exclude files.

Alternatively:

1. Remove the c, d and o files. Which isn't ideal either.
2. Improve the build. Eg. by building inside a `build` directory instead
of in the src folder.

Ps. I know these workflows aren't trigger in this PR. Only via "Build
Release Packages" workflow action:
https://github.com/valkey-io/valkey/actions/workflows/build-release-packages.yml..
So I can't fully test in this PR. But it should work ^^

Ps. ps. I did test `rsync -av --exclude='*.c' --exclude='*.d'
--exclude='*.o' src/valkey-*` command in isolation and that works as
expected!

---------

Signed-off-by: Melroy van den Berg <melroy@melroy.org>
2024-10-02 20:11:12 +02:00
Madelyn Olson 99572fc2b0 Prepare for 7.2.7 release without security fixes
Signed-off-by: Madelyn Olson <madelyneolson@gmail.com>
2024-09-30 15:25:39 -07:00
BinbinandMadelyn Olson 16abb019a7 Fix module RdbLoad wrongly disable the AOF (#1001)
In RdbLoad, we disable AOF before emptyData and rdbLoad to prevent copy-on-write issues. After rdbLoad completes, AOF should be re-enabled, but the code incorrectly checks server.aof_state, which has been reset to AOF_OFF in stopAppendOnly. This leads to AOF not being re-enabled after being disabled.
---------

Signed-off-by: Binbin <binloveplay1314@qq.com>
2024-09-30 15:17:13 -07:00
BinbinandMadelyn Olson 1ff79d5ed8 Fix missing replication link re-connection when primary's IP/port is updated in clusterProcessGossipSection (#965)
`clusterProcessGossipSection` currently doesn't trigger a check and call `replicationSetPrimary` when `myself`'s primary node’s IP/port is updated. This fix ensures that after every node address update, `replicationSetPrimary` is called if the updated node is `myself`'s primary. This prevents missed updates and ensures that replicas reconnect properly to maintain their replication link with the primary.

Signed-off-by: Madelyn Olson <madelyneolson@gmail.com>
2024-09-30 15:07:33 -07:00
Ted LyngmoandMadelyn Olson 248c2792ca Log the real reason for why posix_fadvise failed (#430)
`reclaimFilePageCache` did not set `errno` but `rdbSaveInternal` which
is logging the error assumed it did. This makes sure `errno` is set.

Signed-off-by: Ted Lyngmo <ted@lyncon.se>
2024-09-30 14:58:31 -07:00
Roshan KhatriandGitHub c8feb6a5d1 [Cherry-Pick]Adds workflows to build release binaries and push to S3 (#315) (#857)
[related to](https://github.com/valkey-io/valkey/issues/230)

Adds workflows to build Valkey binaries and push to S3 to make it
available to download from the website

The Workflows can be triggered by pushing a release to the repo and the
other option is manually by one of the Maintainers.

Once the workflow triggers, it will generate a matrix of Jobs for the
platforms we need to build from `utils/releasetools/build-config.json`
and then the respective Jobs are triggered. These jobs make Valkey with
respect to the platform binaries we want to release and would push to a
private S3 bucket.

---------

Signed-off-by: Roshan Khatri <rvkhatri@amazon.com>
2024-09-30 14:21:33 -07:00
PierreandGitHub df9f982ec9 Fix crash in active defrag (#883)
This crash would happen if we disable active defrag while it is running,
then re-enable active defrag. In this case the `expires_cursor` variable
in `activeDefragCycle()` would not be reset to 0 when disabling active
defrag, so when re-enabling it, this variable can still be non-zero,
which causes the `db` and other variables to not be initialized before
starting the defrag process.

Signed-off-by: Pierre Turin <pieturin@amazon.com>
2024-08-12 13:38:20 -07:00
23828d6b34 Valkey 7.2.6 Patch Release (#842)
Signed-off-by: Ping Xie <pingxie@google.com>
Signed-off-by: Ping Xie <pingxie@outlook.com>
Co-authored-by: Madelyn Olson <madelyneolson@gmail.com>
2024-07-30 16:40:02 -07:00
Harkrishn PatroandPing Xie 7b171abce7 Generate correct slot information in cluster shards command on primary failure (#790)
Fix #784

Prior to the change, `CLUSTER SHARDS` command processing might pick a
failed primary node which won't have the slot coverage information and
the slots `output` in turn would be empty. This change finds an
appropriate node which has the slot coverage information served by a
given shard and correctly displays it as part of `CLUSTER SHARDS`
output.

 Before:

 ```
 1) 1) "slots"
   2)  (empty array)
   3) "nodes"
   4) 1)  1) "id"
          2) "2936f22a490095a0a851b7956b0a88f2b67a5d44"
          ...
          9) "role"
         10) "master"
         ...
         13) "health"
         14) "fail"
 ```

 After:

 ```
 1) 1) "slots"
   2) 1) 0
       2) 5461
   3) "nodes"
   4) 1)  1) "id"
          2) "2936f22a490095a0a851b7956b0a88f2b67a5d44"
          ...
          9) "role"
         10) "master"
         ...
         13) "health"
         14) "fail"
 ```

---------

Signed-off-by: Harkrishn Patro <harkrisp@amazon.com>
2024-07-22 23:48:00 -07:00
Yossi GottliebandPing Xie 461c529ea6 Reduce FreeBSD daily scope. (#12758)
The full test is very flaky running on a VM inside GitHub worker, so we
have to settle for only building and running a small smoke test.

Signed-off-by: Ping Xie <pingxie@google.com>
2024-07-15 14:29:28 -07:00
18a88dcae5 Replace centos 7 with alternative versions (#543)
replace centos 7 with almalinux 8, add almalinux 9, centos stream 9, fedora stable, rawhide

Fixes #527

---------

Signed-off-by: Jonathan Wright <jonathan@almalinux.org>
Signed-off-by: Madelyn Olson <madelyneolson@gmail.com>
Co-authored-by: Madelyn Olson <madelyneolson@gmail.com>
Signed-off-by: Ping Xie <pingxie@google.com>
2024-07-12 15:01:57 -07:00
Madelyn OlsonandPing Xie ce7b03a297 Skip tls for xgroup read regression since it doesn't matter
Signed-off-by: Madelyn Olson <madelyneolson@gmail.com>
2024-07-11 20:02:30 -07:00
Ping XieandPing Xie 0221ecc5ec Add missing test helper function
Signed-off-by: Ping Xie <pingxie@google.com>
2024-07-09 19:39:40 -07:00
BinbinandPing Xie f630e56e10 Make valkey compatible with redis-sentinel to start sentinel (#731)
We already have similar changes to check-rdb / check-aof, apply
this change to sentinel.

Fixes #719.

Signed-off-by: Binbin <binloveplay1314@qq.com>
Signed-off-by: Ping Xie <pingxie@google.com>
2024-07-09 19:39:40 -07:00
KarthikSubbaraoandPing Xie a129ac30c4 Allow Module authentication to succeed when cluster is down (#693)
Module Authentication using a blocking implementation currently gets
rejected when the "cluster is down" from the client timeout cron job
(`clientsCronHandleTimeout`).

This PR exempts clients blocked on Module Authentication from being
rejected here.

---------

Signed-off-by: KarthikSubbarao <karthikrs2021@gmail.com>
Signed-off-by: Ping Xie <pingxie@google.com>
2024-07-09 19:39:40 -07:00
BinbinandPing Xie 1b36f39759 Only primary with slots has the right to mark a node as failed (#634)
In markNodeAsFailingIfNeeded we will count needed_quorum and failures,
needed_quorum is the half the cluster->size and plus one, and
cluster-size
is the size of primary node which contain slots, but when counting
failures, we dit not check if primary has slots.

Only the primary has slots that has the rights to vote, adding a new
clusterNodeIsVotingPrimary to formalize this concept.

Release notes:

bugfix where nodes not in the quorum group might spuriously mark nodes
as failed

---------

Signed-off-by: Binbin <binloveplay1314@qq.com>
Co-authored-by: Ping Xie <pingxie@outlook.com>
Signed-off-by: Ping Xie <pingxie@google.com>
2024-07-09 19:39:40 -07:00
SankarandPing Xie edc059db65 Make cluster meet reliable under link failures (#461)
When there is a link failure while an ongoing MEET request is sent the
sending node stops sending anymore MEET and starts sending PINGs. Since
every node responds to PINGs from unknown nodes with a PONG, the
receiving node never adds the sending node. But the sending node adds
the receiving node when it sees a PONG. This can lead to asymmetry in
cluster membership. This changes makes the sender keep sending MEET
until it sees a PONG, avoiding the asymmetry.

---------

Signed-off-by: Sankar <1890648+srgsanky@users.noreply.github.com>
Signed-off-by: Ping Xie <pingxie@google.com>
2024-07-09 19:39:40 -07:00
d272828706 Fix crash where command duration is not reset when client is blocked … (#526)
In #11012, we changed the way command durations were computed to handle
the same command being executed multiple times. In #11970, we added an
assert if the duration is not properly reset, potentially indicating
that a call to report statistics was missed.

I found an edge case where this happens - easily reproduced by blocking
a client on `XGROUPREAD` and migrating the stream's slot. This causes
the engine to process the `XGROUPREAD` command twice:

1. First time, we are blocked on the stream, so we wait for unblock to
come back to it a second time. In most cases, when we come back to
process the command second time after unblock, we process the command
normally, which includes recording the duration and then resetting it.
2. After unblocking we come back to process the command, and this is
where we hit the edge case - at this point, we had already migrated the
slot to another node, so we return a `MOVED` response. But when we do
that, we don’t reset the duration field.

Fix: also reset the duration when returning a `MOVED` response. I think
this is right, because the client should redirect the command to the
right node, which in turn will calculate the execution duration.

Also wrote a test which reproduces this, it fails without the fix and
passes with it.

---------

Signed-off-by: Nitai Caro <caronita@amazon.com>
Co-authored-by: Nitai Caro <caronita@amazon.com>
Signed-off-by: Ping Xie <pingxie@google.com>
2024-07-09 19:39:40 -07:00
Viktor SöderqvistandPing Xie 4d7dcf2103 Don't let install flags affect build (#382)
Don't let the Make valiable `USE_REDIS_SYMLINKS` affect the build.
If it does, it causes the second line in the example below (`make
install`) to recompile what was already compiled on the line above, and
this time it's built without BUILD_TLS=yes USE_SYSTEMD=yes.

    make BUILD_TLS=yes USE_SYSTEMD=yes
    make PREFIX=custom/usr USE_REDIS_SYMLINKS=no install

Fixes #377

Signed-off-by: Viktor Söderqvist <viktor.soderqvist@est.tech>
Signed-off-by: Ping Xie <pingxie@google.com>
2024-07-09 19:39:40 -07:00
Yanqi LvandPing Xie 0e5e12e353 fix wrong data type conversion in zrangeResultBeginStore (#13148)
In `beginResultEmission`, -1 means the result length is not known in
advance. But after #12185, if we pass -1 to `zrangeResultBeginStore`, it
will convert to SIZE_MAX in `zsetTypeCreate` and try to `dictExpand`.
Although `dictExpand` won't succeed because the size overflows, I think
we'd better to avoid this wrong conversion.

This bug can be triggered when the source of `zrangestore` doesn't exist
or we use `zrangestore` command with `byscore` or `bylex`.
The impact is that dst keys will be converted to use skiplist instead of
listpack.

Signed-off-by: Ping Xie <pingxie@google.com>
2024-07-02 00:24:19 -07:00
BinbinandPing Xie 0b32fa00e7 Fix redis-check-aof incorrectly considering data in manifest format as MP-AOF (#12958)
The check in fileIsManifest misjudged the manifest file. For example,
if resp aof contains "file", it will be considered a manifest file and
the check will fail:
```
*3
$3
set
$4
file
$4
file
```

In #12951, if the preamble aof also contains it, it will also fail.
Fixes #12951.

the bug was happening if the the word "file" is mentioned
in the first 1024 lines of the AOF. and now as soon as it finds
a non-comment line it'll break (if it contains "file" or doesn't)

Signed-off-by: Ping Xie <pingxie@google.com>
2024-07-02 00:24:19 -07:00
192086838d Fix conversion of numbers in lua args to redis args (#13115)
Since lua_Number is not explicitly an integer or a double, we need to
make an effort
to convert it as an integer when that's possible, since the string could
later be used
in a context that doesn't support scientific notation (e.g. 1e9 instead
of 100000000).

Since fpconv_dtoa converts numbers with the equivalent of `%f` or `%e`,
which ever is shorter,
this would break if we try to pass a long integer number to a command
that takes integer.
we'll get an implicit conversion to string in Lua, and then the parsing
in getLongLongFromObjectOrReply will fail.

```
> eval "redis.call('hincrby', 'key', 'field', '1000000000')" 0
(nil)
> eval "redis.call('hincrby', 'key', 'field', tonumber('1000000000'))" 0
(error) ERR value is not an integer or out of range script: ac99c32e4daf7e300d593085b611de261954a946, on @user_script:1.
```

Switch to using ll2string if the number can be safely represented as a
long long.

The problem was introduced in #10587 (Redis 7.2).
closes #13113.

---------

Co-authored-by: Binbin <binloveplay1314@qq.com>
Co-authored-by: debing.sun <debing.sun@redis.com>
Co-authored-by: Oran Agra <oran@redislabs.com>
Signed-off-by: Ping Xie <pingxie@google.com>
2024-07-02 00:24:19 -07:00
LiiNenandPing Xie 08e94adea9 Fix redis-cli --count (for --scan, --bigkeys, etc) was ignored unless --pattern was also used (#13092)
The --count option for redis-cli has been released in redis 7.2.
https://github.com/redis/redis/pull/12042
But I have found in code, that some logic was missing for using this
'count' option.

```
static redisReply *sendScan(unsigned long long *it) {
    redisReply *reply;

    if (config.pattern)
        reply = redisCommand(context, "SCAN %llu MATCH %b COUNT %d",
            *it, config.pattern, sdslen(config.pattern), config.count);
    else
        reply = redisCommand(context,"SCAN %llu",*it);
```

The intention was being able to using scan count.
But in this case, the --count will be only applied when 'pattern' is
declared.
So, I had fix it simply, to be worked properly - even if --pattern
option is not being used.

I tested it simply with time() command several times, and I could see it
works as intended with this commit.
The examples of test results are below:
```
# unstable build

time(./redis-cli -a $AUTH -p $PORT -h $HOST --scan >/dev/null 2>/dev/null)

real    0m1.287s
user    0m0.011s
sys     0m0.022s

# count is not applied
time(./redis-cli -a $AUTH -p $PORT -h $HOST --scan --count 1000 >/dev/null 2>/dev/null)

real    0m1.117s
user    0m0.011s
sys     0m0.020s

# count is applied with --pattern

time(./redis-cli -a $AUTH -p $PORT -h $HOST --scan --count 1000 --pattern "hash:*" >/dev/null 2>/dev/null)

real    0m0.045s
user    0m0.002s
sys     0m0.002s
```

```
# fix-redis-cli-scan-count build
time(./redis-cli -a $AUTH -p $PORT -h $HOST --scan >/dev/null 2>/dev/null)

real    0m1.084s
user    0m0.008s
sys     0m0.024s

# count is applied even if --pattern is not declared
time(./redis-cli -a $AUTH -p $PORT -h $HOST --scan --count 1000 >/dev/null 2>/dev/null)

real    0m0.043s
user    0m0.000s
sys     0m0.004s

# of course this also applied
time(./redis-cli -a $AUTH -p $PORT -h $HOST --scan --count 1000 --pattern "hash:*" >/dev/null 2>/dev/null)

real    0m0.031s
user    0m0.002s
sys     0m0.002s
```

Thanks a lot.

Signed-off-by: Ping Xie <pingxie@google.com>
2024-07-02 00:24:19 -07:00
BinbinandPing Xie 96a63b3fac Increase tolerance range to block reprocess tests to avoid timing issues (#13053)
These tests have all failed in daily CI:
```
*** [err]: Blocking XREADGROUP for stream key that has clients blocked on stream - reprocessing command in tests/unit/type/stream-cgroups.tcl
Expected '1101' to be between to '1000' and '1100' (context: type eval line 23 cmd {assert_range [expr $end-$start] 1000 1100} proc ::test)

*** [err]: BLPOP unblock but the key is expired and then block again - reprocessing command in tests/unit/type/list.tcl
Expected '1101' to be between to '1000' and '1100' (context: type eval line 23 cmd {assert_range [expr $end-$start] 1000 1100} proc ::test)

*** [err]: BZPOPMIN unblock but the key is expired and then block again - reprocessing command in tests/unit/type/zset.tcl
Expected '1103' to be between to '1000' and '1100' (context: type eval line 23 cmd {assert_range [expr $end-$start] 1000 1100} proc ::test)
```

Increase the range to avoid failures, and improve the comment to be
clearer.
tests was introduced in #13004.

Signed-off-by: Ping Xie <pingxie@google.com>
2024-07-02 00:24:19 -07:00
debing.sunandPing Xie e2867a879f Fix crash due to merge of quicklist node introduced by #12955 (#13040)
Fix two crash introducted by #12955

When a quicklist node can't be inserted and split, we eventually merge
the current node with its neighboring
nodes after inserting, and compress the current node and its siblings.

1. When the current node is merged with another node, the current node
may become invalid and can no longer be used.

   Solution: let `_quicklistMergeNodes()` return the merged nodes.

3. If the current node is a LZF quicklist node, its recompress will be
1. If the split node can be merged with a sibling node to become head or
tail, recompress may cause the head and tail to be compressed, which is
not allowed.

    Solution: always recompress to 0 after merging.

Signed-off-by: Ping Xie <pingxie@google.com>
2024-07-02 00:24:19 -07:00
debing.sunandPing Xie 8d6fbe827f Prevent LSET command from causing quicklist plain node size to exceed 4GB (#12955)
Fix #12864

The main reason for this crash is that when replacing a element of a
quicklist packed node with lpReplace() method,
if the final size is larger than 4GB, lpReplace() will fail and returns
NULL, causing `node->entry` to be incorrectly set to NULL.

Since the inserted data is not a large element, we can't just replace it
like a large element, first quicklistInsertAfter()
and then quicklistDelIndex(), because the current node may be merged and
invalidated in quicklistInsertAfter().

The solution of this PR:
When replacing a node fails (listpack exceeds 4GB), split the current
node, create a new node to put in the middle, and try to merge them.
This is the same as inserting a large element.
In the worst case, its size will not exceed 4GB.

Signed-off-by: Ping Xie <pingxie@google.com>
2024-07-02 00:24:19 -07:00
Oran AgraandPing Xie 0f184975e4 update redis-check-rdb types (#12969)
seems that we forgot to update the array in redis-check rdb.

Signed-off-by: Ping Xie <pingxie@google.com>
2024-07-02 00:24:19 -07:00
BinbinandPing Xie bcea2da0e4 Fix timeout not being set in module blockClient case (#13011)
This was introduced in #13004, missing this assignment.
It causes timeout to be a random value (may be less than now),
and then in `Unblock by timer` test, the client is unblocked
and then it call timeout_callback, since the callback is NULL,
the server will crash.

The crash stack is:
```
beforesleep
handleBlockedClientsTimeout
checkBlockedClientTimeout
unblockClientOnTimeout
replyToBlockedClientTimedOut
moduleBlockedClientTimedOut
-- the timeout_callback is NULL, invalidFunctionWasCalled
bc->timeout_callback(&ctx,(void**)c->argv,c->argc);
```

Signed-off-by: Ping Xie <pingxie@google.com>
2024-07-02 00:24:19 -07:00
BinbinandPing Xie f983fc31a2 Fix blocking commands timeout is reset due to re-processing command (#13004)
In #11012, we will reprocess command when client is unblocked on keys,
in some blocking commands, for example, in the XREADGROUP BLOCK
scenario,
because of the re-processing command, we will recalculate the block
timeout,
causing the blocking time to be reset.

This commit add a new CLIENT_REPROCESSING_COMMAND clent flag, explicitly
let the command know that it is being re-processed, later in
blockForKeys
we will not reset the timeout.

Affected BLOCK cases:
- list / zset / stream, added test cases for each.

Unaffected cases:
- module (never re-process the commands).
- WAIT / WAITAOF (never re-process the commands).

Fixes #12998.

Signed-off-by: Ping Xie <pingxie@google.com>
2024-07-02 00:24:19 -07:00
bentottenandPing Xie 85e25ebc9b When one shard, sole primary node marks potentially failed replica as FAIL instead of PFAIL (#12824)
Fixes issue where a single primary cannot mark a replica as failed in a
single-shard cluster.

Signed-off-by: Ping Xie <pingxie@google.com>
2024-07-02 00:24:19 -07:00
BinbinandPing Xie 7bb645ef14 Add announced-endpoints test to all_tests and fix tls related tests (#12927)
The test was introduced in #10745, but we forgot to add it to the
test_helper.tcl, so our CI did not actually run it. This PR adds it
and ensures it passes CI tests.

Signed-off-by: Ping Xie <pingxie@google.com>
2024-07-02 00:24:19 -07:00
Mikhail KoviazinandGitHub d48f885bf9 module: fix typo in REGISTER_API (#608)
`REGISTER_API` is supposed to register two functions: one starts with
`ValkeyModule_` and the other one with `RedisModule_`. It does so in
`unstable` branch. However there was a copy-paste mistake during
backporting it to 7.2. This caused modules built with `valkeymodule-rs`
to fail since they called `RedisModule_SetModuleAttribs` which caused
valkey to segfault.

This commit fixes the typo.

Signed-off-by: Mikhail Koviazin <mikhail.koviazin@aiven.io>
2024-06-07 00:24:41 -07:00
Madelyn OlsonandGitHub ffcb4e222b Release notes for 7.2.5 (#322)
Add GA release notes for 7.2.5. 

Signed-off-by: Madelyn Olson <madelyneolson@gmail.com>
2024-04-15 21:18:47 -07:00
Ping XieandMadelyn Olson 6a5f8eaf1b Fixed url links in valkey.conf (#320)
Signed-off-by: Ping Xie <pingxie@google.com>
Signed-off-by: Madelyn Olson <madelyneolson@gmail.com>
Co-authored-by: Madelyn Olson <madelyneolson@gmail.com>
2024-04-15 12:50:27 -07:00
Madelyn OlsonandGitHub 75c2746c95 Bumped version to 7.2.5 for valkey and wrote release notes (#305)
Release notes for RC2 (really 7.2.5-rc1). Based on conversation, decided
to have first release on 7.2.5 to make it clear this was a patch release
over Redis. This could be considered a minor release, but we wanted to
clearly signal compatibility with Redis OSS.

---------

Signed-off-by: Madelyn Olson <madelyneolson@gmail.com>
2024-04-12 12:06:53 -07:00
Madelyn OlsonandMadelyn Olson 25486f1647 Add links for security issues (#299)
Add an initial security release page. In the fullness of time I would
like to also include our version support here, but until that has been
decided I would like to keep this simple and just include links.

---------

Signed-off-by: Madelyn Olson <madelyneolson@gmail.com>
2024-04-11 15:58:12 -07:00
ParthandMadelyn Olson 573579acfa Fixing a lua debugger bug that prevented use of 'server' for server.call invocations. (#303)
* Tested it on local instance. This was originally part of
https://github.com/valkey-io/valkey/pull/288 but I am pushing this
separately, so that we can easily merge it into the upcoming release.

```
lua debugger> server ping
<redis> ping
<reply> "+PONG"
lua debugger> redis ping
<redis> ping
<reply> "+PONG"
```

* I also searched for lua debugger related unit tests to add coverage
for this but did not find any relevant test to modify. Leaving it at
that for now.

---------

Signed-off-by: Parth Patel <661497+parthpatel@users.noreply.github.com>
2024-04-11 15:55:32 -07:00
Madelyn Olson 78a168a538 Overwrite 7.2 README file with unstable's version
Signed-off-by: Madelyn Olson <madelyneolson@gmail.com>
2024-04-11 13:17:06 -07:00
Roshan KhatriandMadelyn Olson 8c7484d9bf Revert update of RedisModuleEvent_MasterLinkChange (#289)
ValkeyModuleEvent_MasterLinkChange was updated to use more inclusive
language, but it was done in the compatibility layer as well
(RedisModuleEvent_).

---------

Signed-off-by: Roshan Khatri <rvkhatri@amazon.com>
2024-04-10 17:35:38 -07:00
Björn SvenssonandGitHub b61785fc37 Correcting the installed redis symlinks in 7.2.4-rc1 (#282)
This is a PR directly to the 7.2 branch.

The make variable `ENGINE_NAME` (from
7d5fe95851) was lost during branching of
`7.2` and tag `7.2.4-rc1`
resulting in the creation of faulty symlinks:
```
      INSTALL SYMLINK valkey-serverredis -> valkey-server
      INSTALL SYMLINK valkey-cliredis -> valkey-cli
      INSTALL SYMLINK valkey-benchmarkredis -> valkey-benchmark
      INSTALL SYMLINK valkey-check-rdbredis -> valkey-check-rdb
      INSTALL SYMLINK valkey-check-aofredis -> valkey-check-aof
      INSTALL SYMLINK valkey-sentinelredis -> valkey-sentinel
```

By just adding the variable we get a minimal diff compared to unstable.

Signed-off-by: Björn Svensson <bjorn.a.svensson@est.tech>
2024-04-10 16:55:27 -07:00
ShivshankarandViktor Söderqvist babf19e1f1 Rename redis in valkey-cli file comments and prints (#222)
Updated to Valkey in valkey-cli.c file's comments and prints.

* The output of valkey-cli --help
* The output of the cli built-in HELP command
* The prompt in interactive valkey-cli -s unixsocket
* The history file and the default rc file (changed filename)

---------

Signed-off-by: Shivshankar-Reddy <shiva.sheri.github@gmail.com>
2024-04-10 11:03:38 +02:00
Madelyn OlsonandMadelyn Olson 4fcde04dcc Revert the default PID file back to the real default (#275)
The default pid file is created at /var/run/redis.pid based on the code
at
https://github.com/valkey-io/valkey/blob/c65a6fecba8e6bb09b9f349f96b63f7b693ae252/src/server.h#L132.
Until we update it, we should reflect that in the conf file.

Signed-off-by: Madelyn Olson <madelyneolson@gmail.com>
2024-04-09 08:22:18 -07:00
Madelyn OlsonandGitHub 94fcf4318e Initial draft for 7.2.4.Rc1 release notes (#247)
Add release nodes for 7.2.4-rc1. 

---------

Signed-off-by: Madelyn Olson <madelyneolson@gmail.com>
2024-04-09 08:13:22 -07:00
Lipeng ZhuandViktor Söderqvist fb75e2f9df Changes references to redis binaries in output of "--help", "--version" (#113)
Rename output from redis-* to valkey-* for binaries:

1. `valkey-benchmark`
2. `valkey-cli`
3. `valkey-server`
4. `valkey-sentinel`
5. `valkey-check-rdb`
6. `valkey-check-aof`

"--help" "--version" option.

Signed-off-by: Lipeng Zhu <lipeng.zhu@intel.com>
2024-04-09 09:49:33 +02:00
Vitah LinandMadelyn Olson d27f439e67 Fix rename redis to valkey to pass reply-schemas-validator job (#133)
Signed-off-by: Vitah Lin <vitahlin@gmail.com>
2024-04-08 17:11:02 -07:00
Madelyn OlsonandMadelyn Olson 885f969d50 Update crash wording to include our repo (#263)
Update the wording in the crash log to point to Valkey repo instead of Redis repo.

Signed-off-by: Madelyn Olson <madelyneolson@gmail.com>
2024-04-08 10:09:57 -07:00
Harkrishn PatroandMadelyn Olson 13332e28c3 Pass extensions to node if extension processing is handled by it (#52)
Ref: https://github.com/redis/redis/pull/12760

enabled by default) with older Redis cluster (< 7.0 - extensions not
handled) .

With some of the extensions enabled by default in 7.2 version, new nodes
running 7.2 and above start sending out larger clusterbus message
payload including the ping extensions. This caused an incompatibility
with node running engine versions < 7.0. Old nodes (< 7.0) would receive
the payload from new nodes (> 7.2) would observe a payload length
(totlen) > (estlen) and would perform an early exit and won't process
the message.

This fix introduces a flag `extensions_supported` on the clusterMsg
indicating the sender node can handle extensions parsing. Once, a
receiver nodes receives a message with this flag set to 1, it would
update clusterNode new field extensions_supported and start sending out
extensions if it has any.

This PR also introduces a DEBUG sub command to enable/disable cluster
message extensions `process-clustermsg-extensions` feature.

Note: A successful `PING`/`PONG` is required as a sender for a given
node to be marked as `extensions_supported` and then extensions message
will be sent to it. This could cause a slight delay in receiving the
extensions message(s).

TCL test verifying the cluster state is healthy irrespective of
enabling/disabling cluster message extensions feature.

---------

Signed-off-by: Harkrishn Patro <harkrisp@amazon.com>
2024-04-08 09:26:13 -07:00
BanyandMadelyn Olson b3d4653ccb Update ValkeyModuleEvent_MasterLinkChange to ValkeyModuleEvent_PrimaryLinkChange (#262)
Update ValkeyModuleEvent_MasterLinkChange to ValkeyModuleEvent_PrimaryLinkChange

Signed-off-by: 0del <bany.y0599@gmail.com>
2024-04-08 09:16:45 -07:00
Viktor SöderqvistandMadelyn Olson af5784c031 Log branding (#252)
Small changes to the log messages printed during startup and shutdown,
for Valkey branding.

SERVER_NAME is replaced by verbatim "Valkey" in one place, because
SERVER_NAME expands to "valkey" in lowercase. (Should we introduce
another macro that expands to "Valkey"?)

Signed-off-by: Viktor Söderqvist <viktor.soderqvist@est.tech>
2024-04-07 17:32:22 -07:00
Madelyn OlsonandMadelyn Olson f5d8b9f536 Madelyn's attempt as a logo (#251)
Apply new logo at startup.

It is one character wider and 2 characters taller than the original
Redis logo.

---------

Signed-off-by: Madelyn Olson <madelyneolson@gmail.com>
2024-04-07 17:32:10 -07:00
Madelyn OlsonandMadelyn Olson 3cfeaea24c Fix two typos that were flagged in the 7.2 build (#248)
These were flagged on the 7.2 build system, which is using the old spell
check. I think we should consider re-adding it as it missed some typos.

Relevant: https://github.com/valkey-io/valkey/pull/72

Signed-off-by: Madelyn Olson <madelyneolson@gmail.com>
2024-04-07 00:08:13 -07:00
f598645e7e The usage (--help) message now refers to valkey (#189)
Fixing redis -> valkey in the output of valkey-server --help.

Signed-off-by: Daniel House <daniel.house@huawei.com>
Co-authored-by: Daniel House <daniel.house@huawei.com>
2024-04-06 23:51:02 -07:00
Madelyn Olson b2ff9407e2 Apply missing 7.2 changes
Signed-off-by: Madelyn Olson <madelyneolson@gmail.com>
2024-04-06 23:50:57 -07:00
Wen HuiandMadelyn Olson 2872565dd1 Update Valkey keyword in sentinel.conf (#171)
Mostly comments, but one pre-filled config in this template config file
is changed:

    pidfile /var/run/valkey-sentinel.pid

---------

Signed-off-by: hwware <wen.hui.ware@gmail.com>
2024-04-06 22:50:16 -07:00
Harkrishn PatroandMadelyn Olson 1ba9929633 Remove trademarked wording on configuration file and individual configs (#29)
Remove trademarked wording on configuration layer.

Following changes for release notes:

1. Rename redis.conf to valkey.conf
2. Pre-filled config in the template config file: Changing pidfile to `/var/run/valkey_6379.pid`

Signed-off-by: Harkrishn Patro <harkrisp@amazon.com>
2024-04-06 22:49:27 -07:00
d3972ad5a8 Add redis symlinks at the same place as the installed binaries (#193)
Adds a new make variable called `USE_REDIS_SYMLINKS`, with default value
`yes`. If yes, then `make install` creates additional symlinks to the
installed binaries:

* `valkey-server`
* `valkey-cli`
* `valkey-benchmark`
* `valkey-check-rdb`
* `valkey-check-aof`
* `valkey-sentinel`

The names of the symlinks are the legacy redis binary names
(`redis-server`, etc.). The purpose is to provide backward compatibility
for scripts expecting the these filenames. The symlinks are installed in
the same directory as the binaries (typically `/usr/local/bin/` or
similar).

Similarly, `make uninstall` removes these symlinks if
`USE_REDIS_SYMLINKS` is `yes`.

This is described in a note in README.md.

Fixes #147

---------

Signed-off-by: Vitah Lin <vitahlin@gmail.com>
Co-authored-by: Madelyn Olson <34459052+madolson@users.noreply.github.com>
2024-04-06 22:44:42 -07:00
bacdcbe18b Rename ValkeyModule_DefragModuleString to ValkeyModule_DefragValkeyModuleString (#243)
fixes: #242

---------

Signed-off-by: 0del <bany.y0599@gmail.com>
Co-authored-by: Viktor Söderqvist <viktor.soderqvist@est.tech>
2024-04-06 22:41:55 -07:00
Madelyn Olson 8da5b6333f Fix merge conflicts
Signed-off-by: Madelyn Olson <madelyneolson@gmail.com>
2024-04-06 22:41:50 -07:00
debing.sunandMadelyn Olson ef746b0dff Check user's oom_score_adj write permission for oom-score-adj test (#13111)
`CONFIG SET oom-score-adj handles configuration failures` test failed in
some CI jobs today.
Failed CI: https://github.com/redis/redis/actions/runs/8152519326

Not sure why the github action's docker image perssions have changed,
but the issue is similar to #12887,
where we can't assume the range of oom_score_adj that a user can change.

## Solution:
Modify the way of determining whether the current user has no privileges
or not,
instead of relying on whether the user id is 0 or not.
2024-04-06 22:24:22 -07:00
04c2d0dfe9 Fix oom-score-adj test due to no permission (#12887)
Fix #12792

On ubuntu 23(lunar), non-root users will not be allowed to change the
oom_score_adj of a process to a value that is too low.
Since terminal's default oom_score_adj is 200, if we run the test on
terminal, we won't be able to set the oom_score_adj of the redis process
to 9 or 22, which is too low.

Reproduction on ubuntu 23(lunar) terminal:
```sh
$ cat /proc/`pgrep redis-server`/oom_score_adj
200
$ echo 100 > /proc/`pgrep redis-server`/oom_score_adj
# success without error
$ echo 99 > /proc/`pgrep redis-server`/oom_score_adj
echo: write error: Permission denied
```

As from the output above, we can only set the minimum oom score of redis
processes to 100.
By modifying the test, make oom_score_adj only increase upwards and not
decrease.

---------

Co-authored-by: debing.sun <debing.sun@redis.com>
2024-04-06 22:08:51 -07:00
Ping XieandMadelyn Olson c79091d72e Remove REDISMODULE_ prefixes and introduce compatibility header (#194)
Fix #146

Removed REDISMODULE_ prefixes from the core source code to align with
the new SERVERMODULE_ naming convention. Added a new 'redismodule.h'
header file to ensure full backward compatibility with existing modules.
This compatibility layer maps all legacy REDISMODULE_ prefixed
identifiers to their new SERVERMODULE_ equivalents, allowing existing
Redis modules to function without modification.

---------

Signed-off-by: Ping Xie <pingxie@google.com>
2024-04-06 21:59:15 -07:00
ParthandMadelyn Olson f30986f299 Adding server.call/pcall option to LUA scripting. (#136) (#213)
This commit does not remove redis.call/pcall just yet. It also does not
rename Redis in error messages such as "Please specify at least one
argument for this redis lib call". This allows users to maintain full
backwards compatibility while introducing an option to use server.call
for new code.

I verified that the unit tests pass. Also manually verified that the
redis-server responds to server.call invocations within lua scripting.
Also verified that function registration works as expected.

```
[ok]: EVAL - is Lua able to call Redis API? (0 ms)
[ok]: EVAL - is Lua able to call Server API? (1 ms)
[ok]: EVAL - No arguments to redis.call/pcall is considered an error (0 ms)
[ok]: EVAL - No arguments to server.call/pcall is considered an error (1 ms)
```

---------

Signed-off-by: Parth Patel <661497+parthpatel@users.noreply.github.com>
Signed-off-by: Madelyn Olson <madelyneolson@gmail.com>
Co-authored-by: Madelyn Olson <madelyneolson@gmail.com>
2024-04-06 20:43:56 -07:00
Roshan KhatriandMadelyn Olson 1abedeeb7e For additional compatibility this adds REDIS_CFLAGS and REDIS_LDFLAGS support to MAKEFILE (#66)
This resolves (1.viii) from
https://github.com/valkey-io/valkey/issues/43
> REDIS_FLAGS will be updated to SERVER_FLAGS. Maybe we should also
allow REDIS_FLAGS -> SERVER_FLAGS as well, for an extra layer of
compatibility.

---------

Signed-off-by: Roshan Khatri <rvkhatri@amazon.com>
2024-04-06 20:43:52 -07:00
Madelyn OlsonandMadelyn Olson 9c4237c17e Update Server version to valkey version (#232)
This commit updates the following fields:
1. server_version -> valkey_version in server info. Since we would like
to advertise specific compatibility, we are making the version specific
to valkey. servername will remain as an optional indicator, and other
valkey compatible stores might choose to advertise something else.
1. We dropped redis-ver from the API. This isn't related to API
compatibility, but we didn't want to "fake" that valkey was creating an
rdb from a Redis version.
1. Renamed server-ver -> valkey_version in rdb info. Same as point one,
we want to explicitly indicate this was created by a valkey server.

---------

Signed-off-by: Madelyn Olson <madelyneolson@gmail.com>
2024-04-06 20:43:42 -07:00
Madelyn OlsonandMadelyn Olson 3a9009d3bd Update versioning fields for compatibility (#47)
New info information to be used to determine the valkey versioning info.

Internally, introduce new define values for "SERVER_VERSION" which is
different from the Redis compatibility version, "REDIS_VERSION".

Add two new info fields:
`server_version`: The Valkey server version
`server_name`: Indicates that the server is valkey.

Add one new RDB field: `server_ver`, which indicates the valkey version
that produced the server.

Add 3 new LUA globals: `SERVER_VERSION_NUM`, `SERVER_VERSION`, and
`SERVER_NAME`. Which reflect the valkey version instead of the Redis
compatibility version.

Also clean up various places where Redis and configuration was being
used that is no longer necessary.

---------

Signed-off-by: Madelyn Olson <madelyneolson@gmail.com>
2024-04-06 20:36:05 -07:00
Madelyn Olson 20339015f0 Squash changes for creating valkey-server
Signed-off-by: Madelyn Olson <madelyneolson@gmail.com>
2024-04-06 20:33:09 -07:00
Oran Agra 2c9af0f00d Redis 7.2.4 2024-01-09 13:51:49 +02:00
BinbinandOran Agra 122e375eeb Fix CLUSTER SHARDS crash in 7.0/7.2 mixed clusters where shard ids are not sync (#12832)
Crash reported in #12695. In the process of upgrading the cluster from
7.0 to 7.2, because the 7.0 nodes will not gossip shard id, in 7.2 we
will rely on shard id to build the server.cluster->shards dict.

In some cases, for example, the 7.0 master node and the 7.2 replica node.
From the view of 7.2 replica node, the cluster->shards dictionary does not
have its master node. In this case calling CLUSTER SHARDS on the 7.2 replica
node may crash.

We should fix the underlying assumption of updateShardId, which is that the
shard dict should be always in sync with the node's shard_id. The fix was
suggested by PingXie, see more details in #12695.

(cherry picked from commit 77f48cd894)
2024-01-09 13:51:49 +02:00
BinbinandOran Agra d70a9d1653 Use shard-id of the master if the replica does not support shard-id (#12805)
If there are nodes in the cluster that do not support shard-id, they
will gossip shard-id. From the perspective of nodes that support shard-id,
their shard-id is meaningless (since shard-id is randomly generated when
we create a node.)

Nodes that support shard-id will save the shard-id information in nodes.conf.
If the node is restarted according to nodes.conf, the server will report a
corrupted cluster config file error. Because auxShardIdSetter will reject
configurations with inconsistent master-replica shard-ids.

A cluster-wide consensus for the node's shard_id is not necessary. The key
is maintaining consistency of the shard_id on each individual 7.2 node.
As the cluster progressively upgrades to version 7.2, we can expect the
shard_ids across all nodes to naturally converge and align.

In this PR, when processing the gossip, if sender is a replica and does not
support shard-id, set the shard_id to the shard_id of its master.

(cherry picked from commit e4811e61d6)
2024-01-09 13:51:49 +02:00
BinbinandOran Agra e52f3bfdd1 Un-register notification and server event when RedisModule_OnLoad fails (#12809)
When we register notification or server event in RedisModule_OnLoad, but
RedisModule_OnLoad eventually fails, triggering notification or server
event
will cause the server to crash.

If the loading fails on a later stage of moduleLoad, we do call
moduleUnload
which handles all un-registration, but when it fails on the
RedisModule_OnLoad
call, we only un-register several specific things and these were
missing:

- moduleUnsubscribeNotifications
- moduleUnregisterFilters
- moduleUnsubscribeAllServerEvents

Refactored the code to reuse the code from moduleUnload.

Fixes #12808.

(cherry picked from commit 4b0f42817a)
2024-01-09 13:51:49 +02:00
Meir Shpilraien (Spielrein)andOran Agra 94b5ec459a Before evicted and before expired server events are not executed inside an execution unit. (#12733)
Redis 7.2 (#9406) introduced a new modules event, `RedisModuleEvent_Key`.
This new event allows the module to read the key data just before it is removed
from the database (either deleted, expired, evicted, or overwritten).

When the key is removed from the database, either by active expire or eviction.
The new event was not called as part of an execution unit. This can cause an
issue if the module registers a post notification job inside the event. This job will
not be executed atomically with the expiration/eviction operation and will not
replicated inside a Multi/Exec. Moreover, the post notification job will be executed
right after the event where it is still not safe to perform any write operation, this will
violate the promise that post notification job will be called atomically with the
operation that triggered it and **only when it is safe to write**.

This PR fixes the issue by wrapping each expiration/eviction of a key with an execution
unit. This makes sure the entire operation will run atomically and all the post notification
jobs will be executed at the end where it is safe to write.

Tests were modified to verify the fix.

(cherry picked from commit fad56faead)
2024-01-09 13:51:49 +02:00
SankarandOran Agra 802a70e3ad Clear owner_not_claiming_slot bit for the slot in clusterDelSlot (#12564)
Clear owner_not_claiming_slot bit for the slot in clusterDelSlot to keep it
consistent with slot ownership information.

(cherry picked from commit 11ded735b3)
2024-01-09 13:51:49 +02:00
BinbinandOran Agra 22c9e05439 Use CLZ in _dictNextExp to get the next power of two (#12815)
In the past, we did not call _dictNextExp frequently. It was only
called when the dictionary was expanded.

Later, dictTypeExpandAllowed was introduced in #7954, which is 6.2.
For the data dict and the expire dict, we can check maxmemory before
actually expanding the dict. This is a good optimization to avoid
maxmemory being exceeded due to the dict expansion.

And in #11692, we moved the dictTypeExpandAllowed check before the
threshold check, this caused a bit of performance degradation, every
time a key is added to the dict, dictTypeExpandAllowed is called to
check.

The main reason for degradation is that in a large dict, we need to
call _dictNextExp frequently, that is, every time we add a key, we
need to call _dictNextExp once. Then the threshold is checked to see
if the dict needs to be expanded. We can see that the order of checks
here can be optimized.

So we moved the dictTypeExpandAllowed check back to after the threshold
check in #12789. In this way, before the dict is actually expanded (that
is, before the threshold is reached), we will not do anything extra
compared to before, that is, we will not call _dictNextExp frequently.

But note we'll still hit the degradation when we over the thresholds.
When the threshold is reached, because #7954, we may delay the dict
expansion due to maxmemory limitations. In this case, we will call
_dictNextExp every time we add a key during this period.

This PR use CLZ in _dictNextExp to get the next power of two. CLZ (count
leading zeros) can easily give you the next power of two. It should be
noted that we have actually introduced the use of __builtin_clzl in
#8687,
which is 7.0. So i suppose all the platforms we use have it (even if the
CPU doesn't have an instruction).

We build 67108864 (2**26) keys through DEBUG POPULTE, which will use
approximately 5.49G memory (used_memory:5898522936). If expansion is
triggered, the additional hash table will consume approximately 1G
memory (2 ** 27 * 8). So we set maxmemory to 6871947673 (that is, 6.4G),
which will be less than 5.49G + 1G, so we will delay the dict rehash
while addint the keys.

After that, each time an element is added to the dict, an allow check
will be performed, that is, we can frequently call _dictNextExp to test
the comparison before and after the optimization. Using DEBUG HTSTATS 0
to
check and make sure that our dict expansion is dealyed.

Using `./src/redis-server redis.conf --save "" --maxmemory 6871947673`.
Using `./src/redis-benchmark -P 100 -r 1000000000 -t set -n 5000000`.
After ten rounds of testing:
```
unstable:           this PR:
769585.94           816860.00
771724.00           818196.69
775674.81           822368.44
781983.12           822503.69
783576.25           828088.75
784190.75           828637.75
791389.69           829875.50
794659.94           835660.69
798212.00           830013.25
801153.62           833934.56
```

We can see there is about 4-5% performance improvement in this case.

(cherry picked from commit a0059b3607)
2024-01-09 13:51:49 +02:00
BinbinandOran Agra 44eff3aad4 Optimize dict expand check, move allow check after the thresholds check (#12789)
dictExpandAllowed (for the main db dict and the expire dict) seems to
involve a few function calls and memory accesses, and we can do it only
after the thresholds checks and can get some performance improvements.

A simple benchmark test: there are 11032768 fixed keys in the database,
start a redis-server with `--maxmemory big_number --save ""`,
start a redis-benchmark with `-P 100 -r 1000000000 -t set -n 5000000`,
collect `throughput summary: n requests per second` result.

After five rounds of testing:
```
unstable     this PR
848032.56    897988.56
854408.69    913408.88
858663.94    914076.81
871839.56    916758.31
882612.56    920640.75
```

We can see a 5% performance improvement in general condition.
But note we'll still hit the degradation when we over the thresholds.

(cherry picked from commit f3720f74bd)
2024-01-09 13:51:49 +02:00
Oran Agra 8e5683fb1c Fix possible corruption in sdsResize (CVE-2023-41056)
#11766 introduced a bug in sdsResize where it could forget to update
the sds type in the sds header and then cause an overflow in sdsalloc.
it looks like the only implication of that is a possible assertion in HLL,
but it's hard to rule out possible heap corruption issues with clientsCronResizeQueryBuffer
2024-01-09 13:51:49 +02:00
Oran Agra bb9130d9c6 Redis 7.2.3 2023-11-01 14:38:13 +02:00
Viktor SöderqvistandOran Agra 9d1150494b Don't crash when adding a forgotten node to blacklist twice (#12702)
Add a defensive checks to prevent double freeing a node from the cluster blacklist.

(cherry picked from commit 4453eabb8e)
2023-11-01 14:38:13 +02:00
Oran Agra 19d6702358 Fix fd leak causing deleted files to remain open and eat disk space (#12693)
This was introduced in v7.2 by #11248

(cherry picked from commit 4d2ac760c3)
2023-11-01 14:38:13 +02:00
Oran Agra 629b757cc4 Redis 7.2.2 2023-10-18 10:44:10 +03:00
BinbinandOran Agra 708a7e9ea1 Fix crash when running rebalance command in a mixed cluster of 7.0 and 7.2 (#12604)
In #10536, we introduced the assert, some older versions of servers
(like 7.0) doesn't gossip shard_id, so we will not add the node to
cluster->shards, and node->shard_id is filled in randomly and may not
be found here.

It causes that if we add a 7.2 node to a 7.0 cluster and allocate slots
to the 7.2 node, the 7.2 node will crash when it hits this assert. Somehow
like #12538.

In this PR, we remove the assert and replace it with an unconditional removal.

(cherry picked from commit 195e6a362d)
2023-10-18 10:44:10 +03:00
BinbinandOran Agra 67bb61fa5c Fix redis-cli pubsub_mode and connect minor prompt / crash issue (#12571)
When entering pubsub mode and using the redis-cli only
connect command, we need to reset pubsub_mode because
we switch to a different connection.

This will affect the prompt when the connection is successful,
and redis-cli will crash when the connect fails:
```
127.0.0.1:6379> subscribe ch
1) "subscribe"
2) "ch"
3) (integer) 1
127.0.0.1:6379(subscribed mode)> connect 127.0.0.1 6380
127.0.0.1:6380(subscribed mode)> ping
PONG
127.0.0.1:6380(subscribed mode)> connect a b
Could not connect to Redis at a:0: Name or service not known
Segmentation fault
```

(cherry picked from commit 91925792d6)
2023-10-18 10:44:10 +03:00
guybe7andOran Agra 93fee40390 WAITAOF: Update fsynced_reploff_pending just before starting the initial AOFRW fork (#12620)
If we set `fsynced_reploff_pending` in `startAppendOnly`, and the fork doesn't start
immediately (e.g. there's another fork active at the time), any subsequent commands
will increment `server.master_repl_offset`, but will not cause a fsync (given they were
executed before the fork started, they just ended up in the RDB part of it)
Therefore, any WAITAOF will wait on the new master_repl_offset, but it will time out
because no fsync will be executed.

Release notes:
```
WAITAOF could timeout in the absence of write traffic in case a new AOF is created and
an AOFRW can't immediately start.
This can happen by the appendonly config is changed at runtime, but also after FLUSHALL,
and replica full sync.
```

(cherry picked from commit d967ed0e08)
2023-10-18 10:44:10 +03:00
Nir RattnerandOran Agra 64aa4537ba Fix overflow calculation for next timer event (#12474)
The `retval` variable is defined as an `int`, so with 4 bytes, it cannot properly represent
microsecond values greater than the equivalent of about 35 minutes.

This bug shouldn't impact standard Redis behavior because Redis doesn't have timer
events that are scheduled as far as 35 minutes out, but it may affect custom Redis modules
which interact with the event timers via the RM_CreateTimer API.

The impact is that `usUntilEarliestTimer` may return 0 for as long as `retval` is scaled to
an overflowing value. While `usUntilEarliestTimer` continues to return `0`, `aeApiPoll`
will have a zero timeout, and so Redis will use significantly more CPU iterating through
its event loop without pause. For timers scheduled far enough into the future, Redis will
cycle between ~35 minute periods of high CPU usage and ~35 minute periods of standard
CPU usage.

(cherry picked from commit d16dd42764)
2023-10-18 10:44:10 +03:00
Chen TianjieandOran Agra 5bcce7a39d Use server.current_client to decide whether cluster commands should return TLS info. (#12569)
Starting a change in #12233 (released in 7.2), CLUSTER commands use client's
connection to decide whether to return TLS port or non-TLS port, but commands
called by Lua script and module's RM_Call don't have a real client with connection,
and would currently be regarded as non-TLS connections.

We can use server.current_client instead when it is available. When it is not (module calls
commands without a real client), we may see this as an undefined behavior, and return null
or default port (currently in this PR it returns default port, judged by server.tls_cluster).

(cherry picked from commit 115ed5e156)
2023-10-18 10:44:10 +03:00
BinbinandOran Agra 20b20d404c Fix that slot return in CLUSTER SHARDS should be integer (#12561)
An unintentional change was introduced in #10536, we used
to use addReplyLongLong and now it is addReplyBulkLonglong,
revert it back the previous behavior.

(cherry picked from commit 2a958dc37b)
2023-10-18 10:44:10 +03:00
JachinandOran Agra 139d93266d Fix compile on macOS 13 (#12611)
Use the __MAC_OS_X_VERSION_MIN_REQUIRED macro to detect the
macOS system version instead of using MAC_OS_X_VERSION_10_6.

From MacOSX14.0.sdk, the default definitions of MAC_OS_X_VERSION_xxx have
been removed in usr/include/AvailabilityMacros.h. It includes AvailabilityVersions.h,
where the following condition must be met:
`#if (!defined(_POSIX_C_SOURCE) && !defined(_XOPEN_SOURCE)) || defined(_DARWIN_C_SOURCE)`
Only then will MAC_OS_X_VERSION_xxx be defined.
However, in the project, _DARWIN_C_SOURCE is not defined, which leads to the
loss of the definition for MAC_OS_X_VERSION_10_6.

(cherry picked from commit 0267fbb0a3)
2023-10-18 10:44:10 +03:00
BinbinandOran Agra 4d78a6061f Support NO ONE block in REPLICAOF command json (#12633)
The current commands.json doesn't mention the special NO ONE arguments.
This change is also applied to SLAVEOF

(cherry picked from commit f6d839fde2)
2023-10-18 10:44:10 +03:00
Yossi GottliebandOran Agra c2ebbd0668 Fix issue of listen before chmod on Unix sockets (CVE-2023-45145)
Before this commit, Unix socket setup performed chmod(2) on the socket
file after calling listen(2). Depending on what umask is used, this
could leave the file with the wrong permissions for a short period of
time. As a result, another process could exploit this race condition and
establish a connection that would otherwise not be possible.

We now make sure the socket permissions are set up prior to calling
listen(2).
2023-10-18 10:44:10 +03:00
Oran Agra 68d6dffe50 Redis 7.2.1 2023-09-06 20:56:15 +03:00
nihohitandOran Agra 22087fc2b4 Update command tips on more admin / configuration commands (#12545)
Updated the command tips for ACL SAVE / SETUSER / DELUSER, CLIENT SETNAME / SETINFO, and LATENCY RESET.
The tips now match CONFIG SET, since there's a similar behavior for all of these commands - the
user expects to update the various configurations & states on all nodes, not only on a single, random node.
For LATENCY RESET the response tip is now agg_sum.

Co-authored-by: Shachar Langbeheim <shachlan@amazon.com>
(cherry picked from commit 1c2c30ef03)
2023-09-06 20:56:15 +03:00
secwallandOran Agra b3d6f4bbf2 Check shard_id pointer validity in updateShardId (#12538)
When connecting between a 7.0 and 7.2 cluster, the 7.0 cluster will not populate the shard_id field, which is expect on the 7.2 cluster. This is not intended behavior, as the 7.2 cluster is supposed to use a temporary shard_id while the node is in the upgrading state, but it wasn't being correctly set in this case.

(cherry picked from commit 0a680287a6)
2023-09-06 20:56:15 +03:00
BinbinandOran Agra d5f5378d47 Update sort_ro reply_schema to mention the null reply (#12534)
Also added a test to cover this case, so this can
cover the reply schemas check.

(cherry picked from commit 2550dcf968)
2023-09-06 20:56:15 +03:00
bodong.ybdandOran Agra 93784e2ee3 Fix sort_ro get-keys function return wrong key number (#12522)
Before:
```
127.0.0.1:6379> command getkeys sort_ro key
(empty array)
127.0.0.1:6379>
```
After:
```
127.0.0.1:6379> command getkeys sort_ro key
1) "key"
127.0.0.1:6379>
```

(cherry picked from commit 7d43d7604e)
2023-09-06 20:56:15 +03:00
nihohitandOran Agra 41275dd3d3 Align CONFIG RESETSTAT/REWRITE tips with SET. (#12530)
Since the three commands have similar behavior (change config, return
OK), the tips that govern how they should behave should be similar.

Co-authored-by: Shachar Langbeheim <shachlan@amazon.com>
(cherry picked from commit 056498406c)
2023-09-06 20:56:15 +03:00
Oran AgraandGitHub 42d7d976ed Release Redis 7.2.0 GA 2023-08-15 12:38:36 +03:00
Oran Agra 606f3502c9 Redis 7.2.0 2023-08-15 10:04:17 +03:00
Oran Agra 146644355e Merge branch 'unstable' into 7.2 to prepare for 7.2.0 GA 2023-08-15 09:43:09 +03:00
Oran AgraandGitHub ff1c49d07b Release Redis 7.2 RC3 2023-07-10 14:55:20 +03:00
Oran Agra cd05870817 Redis 7.2 RC3 2023-07-10 11:52:53 +03:00
Oran Agra 1bc735bf30 Merge remote-tracking branch 'origin/unstable' into 7.2 2023-07-10 10:26:53 +03:00
Oran AgraandGitHub b1fe900842 Release Redis 7.2 RC2 2023-05-15 13:08:15 +03:00
Oran Agra df68e754a7 Redis 7.2 RC2 2023-05-15 09:53:36 +03:00
Oran Agra f4ba22d9b6 Merge remote-tracking branch 'origin/unstable' into 7.2 2023-05-15 09:50:01 +03:00
Oran Agra 45f46a1a5a Redis 7.2 RC1 2023-03-22 15:58:15 +02:00
160 changed files with 9375 additions and 6624 deletions
+2 -1
View File
@@ -18,4 +18,5 @@ statics
filetest
ro
exat
clen
clen
parth
@@ -0,0 +1,31 @@
name: 'Install TCL8'
description: 'Installs tcl8 and tcltls from source on Fedora-based or uses the system package on others.'
inputs:
matrix_name:
description: 'The name of the matrix to check for fedora'
required: true
runs:
using: "composite"
steps:
# Fedora 42 comes with Tcl 9 by default, but tcltls is currently incompatible with Tcl 9.
# As a workaround, we install Tcl 8 and manually build tcltls 1.7.22 from source.
# Once tcltls adds support for Tcl 9, this logic can be removed and system packages used instead.
- run: |
if [[ "${{ inputs.matrix_name }}" =~ "fedora" ]]; then
dnf -y install tcl8 tcl8-devel gcc make awk openssl openssl-devel
ln -s /usr/bin/tclsh8.6 /usr/bin/tclsh
curl -LO https://core.tcl-lang.org/tcltls/uv/tcltls-1.7.22.tar.gz
tar -xzf tcltls-1.7.22.tar.gz
pushd tcltls-1.7.22
./configure --with-tcl=/usr/lib64/tcl8.6
make
mkdir -p /usr/lib64/tcl8.6/tls1.7.22
cp tcltls.so pkgIndex.tcl /usr/lib64/tcl8.6/tls1.7.22/
popd
else
dnf -y install tcl tcltls
fi
./utils/gen-test-certs.sh
shell: bash
+25 -17
View File
@@ -2,16 +2,23 @@ name: CI
on: [push, pull_request]
concurrency:
group: ci-${{ github.head_ref || github.ref }}
cancel-in-progress: true
permissions:
contents: read
jobs:
test-ubuntu-latest:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- name: make
# Fail build if there are warnings
# build with TLS just for compilation coverage
run: make REDIS_CFLAGS='-Werror' BUILD_TLS=yes
run: make SERVER_CFLAGS='-Werror' BUILD_TLS=yes
- name: test
run: |
sudo apt-get install tcl8.6 tclx
@@ -28,10 +35,10 @@ jobs:
test-sanitizer-address:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- name: make
# build with TLS module just for compilation coverage
run: make SANITIZER=address REDIS_CFLAGS='-Werror' BUILD_TLS=module
run: make SANITIZER=address SERVER_CFLAGS='-Werror' BUILD_TLS=module
- name: testprep
run: sudo apt-get install tcl8.6 tclx -y
- name: test
@@ -43,42 +50,43 @@ jobs:
runs-on: ubuntu-latest
container: debian:buster
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- name: make
run: |
apt-get update && apt-get install -y build-essential
make REDIS_CFLAGS='-Werror'
make SERVER_CFLAGS='-Werror'
build-macos-latest:
runs-on: macos-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- name: make
run: make REDIS_CFLAGS='-Werror'
run: make SERVER_CFLAGS='-Werror'
build-32bit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- name: make
run: |
sudo apt-get update && sudo apt-get install libc6-dev-i386
make REDIS_CFLAGS='-Werror' 32bit
make SERVER_CFLAGS='-Werror' 32bit
build-libc-malloc:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- name: make
run: make REDIS_CFLAGS='-Werror' MALLOC=libc
run: make SERVER_CFLAGS='-Werror' MALLOC=libc
build-centos7-jemalloc:
build-almalinux8-jemalloc:
runs-on: ubuntu-latest
container: centos:7
container: almalinux:8
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- name: make
run: |
yum -y install gcc make
make REDIS_CFLAGS='-Werror'
dnf -y install epel-release gcc make procps-ng which
make -j SERVER_CFLAGS='-Werror'
+28
View File
@@ -0,0 +1,28 @@
name: "Codecov"
# Enabling on each push is to display the coverage changes in every PR,
# where each PR needs to be compared against the coverage of the head commit
on: [push, pull_request]
concurrency:
group: codecov-${{ github.head_ref || github.ref }}
cancel-in-progress: true
jobs:
code-coverage:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Install lcov and run test
run: |
sudo apt-get install lcov
make lcov
- name: Upload code coverage
uses: codecov/codecov-action@v4
with:
token: ${{ secrets.CODECOV_TOKEN }}
file: ./src/valkey.info
+15 -6
View File
@@ -4,13 +4,22 @@ on:
pull_request:
schedule:
# run weekly new vulnerability was added to the database
- cron: '0 0 * * 0'
- cron: '0 3 * * 0'
concurrency:
group: codeql-${{ github.head_ref || github.ref }}
cancel-in-progress: true
permissions:
contents: read
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
if: github.event_name != 'schedule' || github.repository == 'redis/redis'
if: github.event_name != 'schedule' || github.repository == 'valkey-io/valkey'
permissions:
security-events: write
strategy:
fail-fast: false
@@ -19,15 +28,15 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v3
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
uses: github/codeql-action/init@1b1aada464948af03b950897e5eb522f92603cc2 # v3.24.9
with:
languages: ${{ matrix.language }}
- name: Autobuild
uses: github/codeql-action/autobuild@v2
uses: github/codeql-action/autobuild@1b1aada464948af03b950897e5eb522f92603cc2 # v3.24.9
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
uses: github/codeql-action/analyze@1b1aada464948af03b950897e5eb522f92603cc2 # v3.24.9
+39
View File
@@ -0,0 +1,39 @@
# Creates and uploads a Coverity build on a schedule
name: Coverity Scan
on:
schedule:
# Run once daily, since below 500k LOC can have 21 builds per week, per https://scan.coverity.com/faq#frequency
- cron: '0 1 * * *'
# Support manual execution
workflow_dispatch:
concurrency:
group: coverity-${{ github.head_ref || github.ref }}
cancel-in-progress: true
permissions:
contents: read
jobs:
coverity:
if: github.repository == 'valkey-io/valkey'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- name: Download and extract the Coverity Build Tool
run: |
wget -q https://scan.coverity.com/download/cxx/linux64 --post-data "token=${{ secrets.COVERITY_SCAN_TOKEN }}&project=valkey-io%2Fvalkey" -O cov-analysis-linux64.tar.gz
mkdir cov-analysis-linux64
tar xzf cov-analysis-linux64.tar.gz --strip 1 -C cov-analysis-linux64
- name: Install Valkey dependencies
run: sudo apt install -y gcc procps libssl-dev
- name: Build with cov-build
run: cov-analysis-linux64/bin/cov-build --dir cov-int make
- name: Upload the result
run: |
tar czvf cov-int.tgz cov-int
curl \
--form email=${{ secrets.COVERITY_SCAN_EMAIL }} \
--form token=${{ secrets.COVERITY_SCAN_TOKEN }} \
--form file=@cov-int.tgz \
https://scan.coverity.com/builds?project=valkey-io%2Fvalkey
File diff suppressed because it is too large Load Diff
+41 -31
View File
@@ -1,82 +1,92 @@
name: External Server Tests
on:
pull_request:
push:
schedule:
- cron: '0 0 * * *'
pull_request:
push:
schedule:
- cron: '0 2 * * *'
concurrency:
group: external-${{ github.head_ref || github.ref }}
cancel-in-progress: true
permissions:
contents: read
jobs:
test-external-standalone:
runs-on: ubuntu-latest
if: github.event_name != 'schedule' || github.repository == 'redis/redis'
if: github.event_name != 'schedule' || github.repository == 'valkey-io/valkey'
timeout-minutes: 14400
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- name: Build
run: make REDIS_CFLAGS=-Werror
- name: Start redis-server
run: make SERVER_CFLAGS=-Werror
- name: Start valkey-server
run: |
./src/redis-server --daemonize yes --save "" --logfile external-redis.log \
./src/valkey-server --daemonize yes --save "" --logfile external-server.log \
--enable-protected-configs yes --enable-debug-command yes --enable-module-command yes
- name: Run external test
run: |
./runtest \
--host 127.0.0.1 --port 6379 \
--verbose \
--tags -slow
- name: Archive redis log
- name: Archive server log
if: ${{ failure() }}
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4.5.0
with:
name: test-external-redis-log
path: external-redis.log
name: test-external-standalone-log
path: external-server.log
test-external-cluster:
runs-on: ubuntu-latest
if: github.event_name != 'schedule' || github.repository == 'redis/redis'
if: github.event_name != 'schedule' || github.repository == 'valkey-io/valkey'
timeout-minutes: 14400
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- name: Build
run: make REDIS_CFLAGS=-Werror
- name: Start redis-server
run: make SERVER_CFLAGS=-Werror
- name: Start valkey-server
run: |
./src/redis-server --cluster-enabled yes --daemonize yes --save "" --logfile external-redis.log \
./src/valkey-server --cluster-enabled yes --daemonize yes --save "" --logfile external-server.log \
--enable-protected-configs yes --enable-debug-command yes --enable-module-command yes
- name: Create a single node cluster
run: ./src/redis-cli cluster addslots $(for slot in {0..16383}; do echo $slot; done); sleep 5
run: ./src/valkey-cli cluster addslots $(for slot in {0..16383}; do echo $slot; done); sleep 5
- name: Run external test
run: |
./runtest \
--host 127.0.0.1 --port 6379 \
--verbose \
--cluster-mode \
--tags -slow
- name: Archive redis log
- name: Archive server log
if: ${{ failure() }}
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4.5.0
with:
name: test-external-cluster-log
path: external-redis.log
path: external-server.log
test-external-nodebug:
runs-on: ubuntu-latest
if: github.event_name != 'schedule' || github.repository == 'redis/redis'
if: github.event_name != 'schedule' || github.repository == 'valkey-io/valkey'
timeout-minutes: 14400
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- name: Build
run: make REDIS_CFLAGS=-Werror
- name: Start redis-server
run: make SERVER_CFLAGS=-Werror
- name: Start valkey-server
run: |
./src/redis-server --daemonize yes --save "" --logfile external-redis.log
./src/valkey-server --daemonize yes --save "" --logfile external-server.log
- name: Run external test
run: |
./runtest \
--host 127.0.0.1 --port 6379 \
--verbose \
--tags "-slow -needs:debug"
- name: Archive redis log
- name: Archive server log
if: ${{ failure() }}
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4.5.0
with:
name: test-external-redis-log
path: external-redis.log
name: test-external-nodebug-log
path: external-server.log
+9 -2
View File
@@ -8,13 +8,20 @@ on:
paths:
- 'src/commands/*.json'
concurrency:
group: reply-schemas-linter-${{ github.head_ref || github.ref }}
cancel-in-progress: true
permissions:
contents: read
jobs:
reply-schemas-linter:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- name: Setup nodejs
uses: actions/setup-node@v3
uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
- name: Install packages
run: npm install ajv
- name: linter
+10 -3
View File
@@ -9,6 +9,13 @@ on:
push:
pull_request:
concurrency:
group: spellcheck-${{ github.head_ref || github.ref }}
cancel-in-progress: true
permissions:
contents: read
jobs:
build:
name: Spellcheck
@@ -16,10 +23,10 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v3
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- name: pip cache
uses: actions/cache@v3
- name: Install typos
uses: taiki-e/install-action@cd5df4de2e75f3b819ba55f780f7bb8cd4a05a41 # v2.32.2
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
@@ -0,0 +1,50 @@
name: Trigger Build Release
on:
release:
types: [published]
workflow_dispatch:
inputs:
version:
description: Version of Valkey to build
required: true
environment:
description: Environment to build
required: true
type: choice
options:
- dev
- prod
jobs:
trigger:
runs-on: ubuntu-latest
steps:
- name: Determine version and environment
id: determine-vars
run: |
if [[ "${{ github.event_name }}" == "release" ]]; then
echo "Triggered by a release event."
VERSION=${{ github.event.release.tag_name }}
ENVIRONMENT="prod"
else
echo "Triggered manually (workflow_dispatch)."
VERSION=${{ inputs.version }}
ENVIRONMENT=${{ inputs.environment }}
fi
# Set the outputs for version and environment
echo "version=$VERSION" >> $GITHUB_OUTPUT
echo "environment=$ENVIRONMENT" >> $GITHUB_OUTPUT
- name: Trigger build
uses: peter-evans/repository-dispatch@ff45666b9427631e3450c54a1bcbee4d9ff4d7c0 # Version 3
with:
token: ${{ secrets.AUTOMATION_PAT }}
repository: ${{ github.repository_owner }}/valkey-release-automation
event-type: build-release
client-payload: >
{
"version": "${{ steps.determine-vars.outputs.version }}",
"environment": "${{ steps.determine-vars.outputs.environment }}"
}
+15 -9
View File
@@ -1,17 +1,19 @@
.*.swp
*.o
*.a
*.xo
*.so
*.d
*.log
dump.rdb
redis-benchmark
redis-check-aof
redis-check-rdb
redis-check-dump
redis-cli
redis-sentinel
redis-server
*-benchmark
*-check-aof
*-check-rdb
*-check-dump
*-cli
*-sentinel
*-server
*-unit-tests
doc-tools
release
misc/*
@@ -23,8 +25,7 @@ release.h
src/transfer.sh
src/configs
redis.ds
src/redis.conf
src/nodes.conf
src/*.conf
deps/lua/src/lua
deps/lua/src/luac
deps/lua/src/liblua.a
@@ -41,3 +42,8 @@ Makefile.dep
.ccls-cache/*
compile_commands.json
redis.code-workspace
.cache
.cscope*
.swp
nodes.conf
tests/cluster/tmp/*
+214 -11
View File
@@ -1,16 +1,219 @@
Hello! This file is just a placeholder, since this is the "unstable" branch
of Redis, the place where all the development happens.
Valkey 7.2 release notes
========================
There is no release notes for this branch, it gets forked into another branch
every time there is a partial feature freeze in order to eventually create
a new stable release.
--------------------------------------------------------------------------------
Upgrade urgency levels:
Usually "unstable" is stable enough for you to use it in development environments
however you should never use it in production environments. It is possible
to download the latest stable release here:
LOW: No need to upgrade unless there are new features you want to use.
MODERATE: Program an upgrade of the server, but it's not urgent.
HIGH: There is a critical bug that may affect a subset of users. Upgrade!
CRITICAL: There is a critical bug affecting MOST USERS. Upgrade ASAP.
SECURITY: There are security fixes in the release.
--------------------------------------------------------------------------------
https://download.redis.io/redis-stable.tar.gz
================================================================================
Valkey 7.2.9 - Released Wed 23 Apr 2025
================================================================================
More information is available at https://redis.io
Upgrade urgency SECURITY: This release includes security fixes we recommend you
apply as soon as possible.
Happy hacking!
Bug fixes
=========
* Fix defrag crash when using FLUSHDB ASYNC in cluster mode (#1873)
* Fix memory leak in forgotten node ping ext code path (#1576)
* Fix module LatencyAddSample still work when latency-monitor-threshold is 0 (#1541)
* Fix potential crash in radix tree recompression of huge keys (#1722)
* Fix error "SSL routines::bad length" when connTLSWrite is called second time with smaller buffer (#1737)
* Fix RANDOMKEY infinite loop during CLIENT PAUSE (#1850)
* fix: add samples to stream object consumer trees (#1825)
* Fix panic in primary when blocking shutdown after previous block with timeout (#1948)
* Fix incorrect lag reported in XINFO GROUPS (#1952)
Security fixes
==============
* CVE-2025-21605 Limit output buffer for unauthenticated clients (#1992)
================================================================================
Valkey 7.2.8 - Released Mon 07 Jan 2025
================================================================================
Upgrade urgency SECURITY: This release includes security fixes we recommend you
apply as soon as possible.
Bug fixes
=========
* Fix a bug where extra memory would be used when storing strings in the
inline protocol. (#1213)
* Send the correct error message when `FUNCTION KILL` is used to kill an
ongoing script. (#1171)
* Make sure the last accessed time is correctly updated when using the `TOUCH`
command with the `CLIENT NO-TOUCH` option. (#1499)
Security fixes
==============
* (CVE-2024-46981) Lua script commands may lead to remote code execution. (#1513)
* (CVE-2024-51741) Denial-of-service due to malformed ACL selectors. (#1514)
================================================================================
Valkey 7.2.7 - Released Tue 01 Oct 2024
================================================================================
Upgrade urgency SECURITY: This release includes security fixes we recommend you
apply as soon as possible.
Bug fixes
=========
* Prevented AOF from being incorrectly disabled after loading RDB data, ensuring
proper re-enabling of AOF. (#1001)
* Resolved issues in replicationSetPrimary where the primary node's IP/port
updates were not correctly handled in the cluster gossip section. (#965)
Security fixes
==============
* (CVE-2024-31449) Lua library commands may lead to stack overflow and potential RCE.
* (CVE-2024-31227) Potential Denial-of-service due to malformed ACL selectors.
* (CVE-2024-31228) Potential Denial-of-service due to unbounded pattern matching.
================================================================================
Valkey 7.2.6 GA - Released Tue 30 July 2024
================================================================================
Upgrade urgency MODERATE: This release fixes an incompatibility issue with modules
compiled for Redis. For other users, it primarily fixes uncommon bugs.
Bug fixes - Core
================
* Fix typo in REGISTER_API macro to prevent segfaults when loading Redis
modules (#608)
* Fix the command duration reset issue when clients are blocked and commands
are reprocessed (#526)
* Fix the data type conversion error in zrangeResultBeginStore (Redis#13148)
* Fix a crash caused by quicklist node merges (Redis#13040)
* Fix crashes in module blocking client timeout cases (Redis#13011)
* Fix conversion of numbers in Lua args to Redis args
(Redis#13115, Fixes Redis#13113)
* Fix crash in LSET command when replacing small list items with larger ones,
creating listpacks larger than 4GB (Redis#12955, Fixes Redis#12864)
* Fix blocking command timeout reset issue during reprocessing (Redis#13004)
Bug fixes - Cluster
===================
* Fix the CLUSTER SHARDS command to display accurate slot information even
if a primary node fails (#790, Fixes #784)
* Fix an issue where module authentication failed when the cluster was down
(#693, Fixes #619)
* Ensure only primary nodes with slots can mark another node as failed (#634)
* Improve MEET command reliability under link failures to maintain cluster
membership symmetry (#461)
* Allow single primary node to mark potentially failed replica as FAIL in
single-shard cluster (Redis#12824)
Bug fixes - Sentinel
====================
* Accept redis-sentinel to start Valkey in sentinel mode (#731, Fixes #719)
Bug fixes - CLI
===============
* Ensure the `--count` option in redis-cli works correctly even without
`--pattern` (Redis#13092)
* Fix redis-check-aof misidentifying data in manifest format as MP-AOF
(Redis#12951)
* Update redis-check-rdb types to replace stream-v2 with stream-v3
(Redis#12969)
================================================================================
Valkey 7.2.5 GA - Released Tue 16 Apr 2024
================================================================================
Upgrade urgency LOW: This is the first stable release of Valkey 7.2.5.
Changes to support Valkey branding
=========
* Update template config files to remove references of redis.io and replace them
with valkey.io. (#320)
================================================================================
Valkey 7.2.5 RC1 - Released Fri 12 Apr 2024
================================================================================
Upgrade urgency LOW: Second release candidate for Valkey with API compatibility
for OSS Redis 7.2.4. Moving to a release candidate on 7.2.5, to make it clearer
this is a patch iteration as opposed to an exact copy of OSS Redis. Also includes
fixes to minor bugs present in 7.2.4 RC1 and more compatibility changes.
Changes to support Valkey branding
=========
* Update README to remove Redis references.
* Update valkey-server and valkey-cli help info to show only Valkey (#222)
* Add compatibility for lua debugger to use 'server' instead of redis. (#303)
Bug fixes
=========
* Fix module event name to maintain Redis compatibility. (#289)
* Fix issue where Redis symlinks were created with the wrong name. (#282)
================================================================================
Valkey 7.2.4 RC1 - Released Tue 09 Apr 2024
================================================================================
Upgrade urgency LOW: Initial release of Valkey with API compatibility for OSS
Redis 7.2.4. This release is based off of OSS Redis 7.2.4, with additional
functionality to better brand the server as Valkey instead of Redis. All APIs
are fully backwards compatible and care was taken to minimize the number of
log lines that were changed to best support existing tooling around log parsing.
Changes to support Valkey branding
=========
* Rename the 6 Redis binaries to ones with `valkey` prefixes: `valkey-server`,
`valkey-cli`, `valkey-benchmark`, `valkey-check-aof`, `valkey-check-rdb` and
`valkey-sentinel`. (#62)
* During install, create symlinks mapping the corresponding Redis binary names
to the new Valkey binaries. (#193)
* INFO fields: Introduce `valkey_version` and `server_name` fields. The
`redis_version` will continue to be present and will indicate the Redis OSS
version that the server is compatible with. (#47, #232)
* RDB file format: Introduce a `valkey-ver` RDB field to indicate an RDB file
was produced by a Valkey server. This field is ignored when the file is
loaded by Redis OSS. (#47)
* Module API changes: Introduce Valkey Module API in a new file, valkeymodule.h,
with functions and types prefixed by ValkeyModule. Valkey is still fully ABI
compatible with the Redis Module API, meaning Valkey supports running modules
compiled with either the Redis or Valkey Module APIs. For full source
compatibility, the Redis Module API (redismodule.h) is also kept with the
RedisModule prefixed functions and types. (#194, #243, #262)
* Scripting: Introduce a new top level `server` object for functions and scripts
that can be instead of the existing `redis` object. This allows users to
replace calls like `redis.call(...)` with `server.call(...)`. (#213)
* Makefile: Introduce `SERVER_CFLAGS` and `SERVER_LDFLAGS` as an alternative to
`REDIS_CFLAGS` and `REDIS_LDFLAGS`. (#46)
* Update template config files to replace references to Redis with Valkey. The
file valkey.conf replaces redis.conf. (#29, #171)
* Logging: Update startup, shutdown, and help logs to reference Valkey instead of
Redis. Valkey server will also show the Valkey logo at startup and show the
Valkey repositories when crashing. (#251, #252, #263, #113)
Bug fixes
=========
* Cluster: Fix an issue where cluster nodes running on Redis versions earlier
than 7.0 would be unable to communicate with nodes running on Valkey 7.2. This
change also introduces a slight delay when hostnames are not displayed when a
node is first added to the cluster. (#52)
A special thank you for the amount of work put into this release by:
- Viktor Söderqvist
- Madelyn Olson
- Wen Hui
- Ping Xie
- Parth Patel
- Roshan Katri
- Zhu Binbin
- Zhao Zhao
- Bany
- Harkrishn Patro
- Vitah Lin
- Ziyang Zeng (For creating the logo!)
- The many other community members who provided their support!
+61 -350
View File
@@ -1,34 +1,25 @@
This README is just a fast *quick start* document. You can find more detailed documentation at [redis.io](https://redis.io).
[![codecov](https://codecov.io/gh/valkey-io/valkey/graph/badge.svg?token=KYYSJAYC5F)](https://codecov.io/gh/valkey-io/valkey)
What is Redis?
This README is under construction as we work to build a new community driven high performance key-value store.
This project was forked from the open source Redis project right before the transition to their new source available licenses.
This README is just a fast *quick start* document. We are currently working on a more permanent documentation page.
What is Valkey?
--------------
Valkey is a high-performance data structure server that primarily serves key/value workloads.
It supports a wide range of native structures and an extensible plugin system for adding new data structures and access patterns.
Building Valkey
--------------
Redis is often referred to as a *data structures* server. What this means is that Redis provides access to mutable data structures via a set of commands, which are sent using a *server-client* model with TCP sockets and a simple protocol. So different processes can query and modify the same data structures in a shared way.
Data structures implemented into Redis have a few special properties:
* Redis cares to store them on disk, even if they are always served and modified into the server memory. This means that Redis is fast, but that it is also non-volatile.
* The implementation of data structures emphasizes memory efficiency, so data structures inside Redis will likely use less memory compared to the same data structure modelled using a high-level programming language.
* Redis offers a number of features that are natural to find in a database, like replication, tunable levels of durability, clustering, and high availability.
Another good example is to think of Redis as a more complex version of memcached, where the operations are not just SETs and GETs, but operations that work with complex data types like Lists, Sets, ordered data structures, and so forth.
If you want to know more, this is a list of selected starting points:
* Introduction to Redis data types. https://redis.io/topics/data-types-intro
* Try Redis directly inside your browser. https://try.redis.io
* The full list of Redis commands. https://redis.io/commands
* There is much more inside the official Redis documentation. https://redis.io/documentation
Building Redis
--------------
Redis can be compiled and used on Linux, OSX, OpenBSD, NetBSD, FreeBSD.
Valkey can be compiled and used on Linux, OSX, OpenBSD, NetBSD, FreeBSD.
We support big endian and little endian architectures, and both 32 bit
and 64 bit systems.
It may compile on Solaris derived systems (for instance SmartOS) but our
support for this platform is *best effort* and Redis is not guaranteed to
support for this platform is *best effort* and Valkey is not guaranteed to
work as well as in Linux, OSX, and \*BSD.
It is as simple as:
@@ -45,15 +36,15 @@ as libsystemd-dev on Debian/Ubuntu or systemd-devel on CentOS) and run:
% make USE_SYSTEMD=yes
To append a suffix to Redis program names, use:
To append a suffix to Valkey program names, use:
% make PROG_SUFFIX="-alt"
You can build a 32 bit Redis binary using:
You can build a 32 bit Valkey binary using:
% make 32bit
After building Redis, it is a good idea to test it using:
After building Valkey, it is a good idea to test it using:
% make test
@@ -67,7 +58,7 @@ installed):
Fixing build problems with dependencies or cached build options
---------
Redis has some dependencies which are included in the `deps` directory.
Valkey has some dependencies which are included in the `deps` directory.
`make` does not automatically rebuild dependencies even if something in
the source code of dependencies changes.
@@ -87,11 +78,11 @@ command.
Fixing problems building 32 bit binaries
---------
If after building Redis with a 32 bit target you need to rebuild it
If after building Valkey with a 32 bit target you need to rebuild it
with a 64 bit target, or the other way around, you need to perform a
`make distclean` in the root directory of the Redis distribution.
`make distclean` in the root directory of the Valkey distribution.
In case of build errors when trying to build a 32 bit binary of Redis, try
In case of build errors when trying to build a 32 bit binary of Valkey, try
the following steps:
* Install the package libc6-dev-i386 (also try g++-multilib).
@@ -101,8 +92,8 @@ the following steps:
Allocator
---------
Selecting a non-default memory allocator when building Redis is done by setting
the `MALLOC` environment variable. Redis is compiled and linked against libc
Selecting a non-default memory allocator when building Valkey is done by setting
the `MALLOC` environment variable. Valkey is compiled and linked against libc
malloc by default, with the exception of jemalloc being the default on Linux
systems. This default was picked because jemalloc has proven to have fewer
fragmentation problems than libc malloc.
@@ -118,7 +109,7 @@ To compile against jemalloc on Mac OS X systems, use:
Monotonic clock
---------------
By default, Redis will build using the POSIX clock_gettime function as the
By default, Valkey will build using the POSIX clock_gettime function as the
monotonic clock source. On most modern systems, the internal processor clock
can be used to improve performance. Cautions can be found here:
http://oliveryang.net/2015/09/pitfalls-of-TSC-usage/
@@ -130,75 +121,78 @@ To build with support for the processor's internal instruction clock, use:
Verbose build
-------------
Redis will build with a user-friendly colorized output by default.
Valkey will build with a user-friendly colorized output by default.
If you want to see a more verbose output, use the following:
% make V=1
Running Redis
Running Valkey
-------------
To run Redis with the default configuration, just type:
To run Valkey with the default configuration, just type:
% cd src
% ./redis-server
% ./valkey-server
If you want to provide your redis.conf, you have to run it using an additional
If you want to provide your valkey.conf, you have to run it using an additional
parameter (the path of the configuration file):
% cd src
% ./redis-server /path/to/redis.conf
% ./valkey-server /path/to/valkey.conf
It is possible to alter the Redis configuration by passing parameters directly
It is possible to alter the Valkey configuration by passing parameters directly
as options using the command line. Examples:
% ./redis-server --port 9999 --replicaof 127.0.0.1 6379
% ./redis-server /etc/redis/6379.conf --loglevel debug
% ./valkey-server --port 9999 --replicaof 127.0.0.1 6379
% ./valkey-server /etc/valkey/6379.conf --loglevel debug
All the options in redis.conf are also supported as options using the command
All the options in valkey.conf are also supported as options using the command
line, with exactly the same name.
Running Redis with TLS:
Running Valkey with TLS:
------------------
Please consult the [TLS.md](TLS.md) file for more information on
how to use Redis with TLS.
how to use Valkey with TLS.
Playing with Redis
Playing with Valkey
------------------
You can use redis-cli to play with Redis. Start a redis-server instance,
You can use valkey-cli to play with Valkey. Start a valkey-server instance,
then in another terminal try the following:
% cd src
% ./redis-cli
redis> ping
% ./valkey-cli
valkey> ping
PONG
redis> set foo bar
valkey> set foo bar
OK
redis> get foo
valkey> get foo
"bar"
redis> incr mycounter
valkey> incr mycounter
(integer) 1
redis> incr mycounter
valkey> incr mycounter
(integer) 2
redis>
valkey>
You can find the list of all the available commands at https://redis.io/commands.
Installing Redis
Installing Valkey
-----------------
In order to install Redis binaries into /usr/local/bin, just use:
In order to install Valkey binaries into /usr/local/bin, just use:
% make install
You can use `make PREFIX=/some/other/directory install` if you wish to use a
different destination.
_Note_: For compatibility with Redis, we create symlinks from the Redis names (`redis-server`, `redis-cli`, etc.) to the Valkey binaries installed by `make install`.
The symlinks are created in same directory as the Valkey binaries.
The symlinks are removed when using `make uninstall`.
The creation of the symlinks can be skipped by setting the makefile variable `USE_REDIS_SYMLINKS=no`.
`make install` will just install binaries in your system, but will not configure
init scripts and configuration files in the appropriate place. This is not
needed if you just want to play a bit with Redis, but if you are installing
needed if you just want to play a bit with Valkey, but if you are installing
it the proper way for a production system, we have a script that does this
for Ubuntu and Debian systems:
@@ -208,299 +202,16 @@ for Ubuntu and Debian systems:
_Note_: `install_server.sh` will not work on Mac OSX; it is built for Linux only.
The script will ask you a few questions and will setup everything you need
to run Redis properly as a background daemon that will start again on
to run Valkey properly as a background daemon that will start again on
system reboots.
You'll be able to stop and start Redis using the script named
`/etc/init.d/redis_<portnumber>`, for instance `/etc/init.d/redis_6379`.
You'll be able to stop and start Valkey using the script named
`/etc/init.d/valkey_<portnumber>`, for instance `/etc/init.d/valkey_6379`.
Code contributions
-----------------
Please see the [CONTRIBUTING.md][2]. For security bugs and vulnerabilities, please see [SECURITY.md][3].
Note: By contributing code to the Redis project in any form, including sending
a pull request via Github, a code fragment or patch via private email or
public discussion groups, you agree to release your code under the terms
of the BSD license that you can find in the [COPYING][1] file included in the Redis
source distribution.
Please see the [CONTRIBUTING.md][2] file in this source distribution for more
information. For security bugs and vulnerabilities, please see [SECURITY.md][3].
[1]: https://github.com/redis/redis/blob/unstable/COPYING
[2]: https://github.com/redis/redis/blob/unstable/CONTRIBUTING.md
[3]: https://github.com/redis/redis/blob/unstable/SECURITY.md
Redis internals
===
If you are reading this README you are likely in front of a Github page
or you just untarred the Redis distribution tar ball. In both the cases
you are basically one step away from the source code, so here we explain
the Redis source code layout, what is in each file as a general idea, the
most important functions and structures inside the Redis server and so forth.
We keep all the discussion at a high level without digging into the details
since this document would be huge otherwise and our code base changes
continuously, but a general idea should be a good starting point to
understand more. Moreover most of the code is heavily commented and easy
to follow.
Source code layout
---
The Redis root directory just contains this README, the Makefile which
calls the real Makefile inside the `src` directory and an example
configuration for Redis and Sentinel. You can find a few shell
scripts that are used in order to execute the Redis, Redis Cluster and
Redis Sentinel unit tests, which are implemented inside the `tests`
directory.
Inside the root are the following important directories:
* `src`: contains the Redis implementation, written in C.
* `tests`: contains the unit tests, implemented in Tcl.
* `deps`: contains libraries Redis uses. Everything needed to compile Redis is inside this directory; your system just needs to provide `libc`, a POSIX compatible interface and a C compiler. Notably `deps` contains a copy of `jemalloc`, which is the default allocator of Redis under Linux. Note that under `deps` there are also things which started with the Redis project, but for which the main repository is not `redis/redis`.
There are a few more directories but they are not very important for our goals
here. We'll focus mostly on `src`, where the Redis implementation is contained,
exploring what there is inside each file. The order in which files are
exposed is the logical one to follow in order to disclose different layers
of complexity incrementally.
Note: lately Redis was refactored quite a bit. Function names and file
names have been changed, so you may find that this documentation reflects the
`unstable` branch more closely. For instance, in Redis 3.0 the `server.c`
and `server.h` files were named `redis.c` and `redis.h`. However the overall
structure is the same. Keep in mind that all the new developments and pull
requests should be performed against the `unstable` branch.
server.h
---
The simplest way to understand how a program works is to understand the
data structures it uses. So we'll start from the main header file of
Redis, which is `server.h`.
All the server configuration and in general all the shared state is
defined in a global structure called `server`, of type `struct redisServer`.
A few important fields in this structure are:
* `server.db` is an array of Redis databases, where data is stored.
* `server.commands` is the command table.
* `server.clients` is a linked list of clients connected to the server.
* `server.master` is a special client, the master, if the instance is a replica.
There are tons of other fields. Most fields are commented directly inside
the structure definition.
Another important Redis data structure is the one defining a client.
In the past it was called `redisClient`, now just `client`. The structure
has many fields, here we'll just show the main ones:
```c
struct client {
int fd;
sds querybuf;
int argc;
robj **argv;
redisDb *db;
int flags;
list *reply;
// ... many other fields ...
char buf[PROTO_REPLY_CHUNK_BYTES];
}
```
The client structure defines a *connected client*:
* The `fd` field is the client socket file descriptor.
* `argc` and `argv` are populated with the command the client is executing, so that functions implementing a given Redis command can read the arguments.
* `querybuf` accumulates the requests from the client, which are parsed by the Redis server according to the Redis protocol and executed by calling the implementations of the commands the client is executing.
* `reply` and `buf` are dynamic and static buffers that accumulate the replies the server sends to the client. These buffers are incrementally written to the socket as soon as the file descriptor is writable.
As you can see in the client structure above, arguments in a command
are described as `robj` structures. The following is the full `robj`
structure, which defines a *Redis object*:
```c
struct redisObject {
unsigned type:4;
unsigned encoding:4;
unsigned lru:LRU_BITS; /* LRU time (relative to global lru_clock) or
* LFU data (least significant 8 bits frequency
* and most significant 16 bits access time). */
int refcount;
void *ptr;
};
```
Basically this structure can represent all the basic Redis data types like
strings, lists, sets, sorted sets and so forth. The interesting thing is that
it has a `type` field, so that it is possible to know what type a given
object has, and a `refcount`, so that the same object can be referenced
in multiple places without allocating it multiple times. Finally the `ptr`
field points to the actual representation of the object, which might vary
even for the same type, depending on the `encoding` used.
Redis objects are used extensively in the Redis internals, however in order
to avoid the overhead of indirect accesses, recently in many places
we just use plain dynamic strings not wrapped inside a Redis object.
server.c
---
This is the entry point of the Redis server, where the `main()` function
is defined. The following are the most important steps in order to startup
the Redis server.
* `initServerConfig()` sets up the default values of the `server` structure.
* `initServer()` allocates the data structures needed to operate, setup the listening socket, and so forth.
* `aeMain()` starts the event loop which listens for new connections.
There are two special functions called periodically by the event loop:
1. `serverCron()` is called periodically (according to `server.hz` frequency), and performs tasks that must be performed from time to time, like checking for timed out clients.
2. `beforeSleep()` is called every time the event loop fired, Redis served a few requests, and is returning back into the event loop.
Inside server.c you can find code that handles other vital things of the Redis server:
* `call()` is used in order to call a given command in the context of a given client.
* `activeExpireCycle()` handles eviction of keys with a time to live set via the `EXPIRE` command.
* `performEvictions()` is called when a new write command should be performed but Redis is out of memory according to the `maxmemory` directive.
* The global variable `redisCommandTable` defines all the Redis commands, specifying the name of the command, the function implementing the command, the number of arguments required, and other properties of each command.
commands.c
---
This file is auto generated by utils/generate-command-code.py, the content is based on the JSON files in the src/commands folder.
These are meant to be the single source of truth about the Redis commands, and all the metadata about them.
These JSON files are not meant to be used by anyone directly, instead that metadata can be obtained via the `COMMAND` command.
networking.c
---
This file defines all the I/O functions with clients, masters and replicas
(which in Redis are just special clients):
* `createClient()` allocates and initializes a new client.
* The `addReply*()` family of functions are used by command implementations in order to append data to the client structure, that will be transmitted to the client as a reply for a given command executed.
* `writeToClient()` transmits the data pending in the output buffers to the client and is called by the *writable event handler* `sendReplyToClient()`.
* `readQueryFromClient()` is the *readable event handler* and accumulates data read from the client into the query buffer.
* `processInputBuffer()` is the entry point in order to parse the client query buffer according to the Redis protocol. Once commands are ready to be processed, it calls `processCommand()` which is defined inside `server.c` in order to actually execute the command.
* `freeClient()` deallocates, disconnects and removes a client.
aof.c and rdb.c
---
As you can guess from the names, these files implement the RDB and AOF
persistence for Redis. Redis uses a persistence model based on the `fork()`
system call in order to create a process with the same (shared) memory
content of the main Redis process. This secondary process dumps the content
of the memory on disk. This is used by `rdb.c` to create the snapshots
on disk and by `aof.c` in order to perform the AOF rewrite when the
append only file gets too big.
The implementation inside `aof.c` has additional functions in order to
implement an API that allows commands to append new commands into the AOF
file as clients execute them.
The `call()` function defined inside `server.c` is responsible for calling
the functions that in turn will write the commands into the AOF.
db.c
---
Certain Redis commands operate on specific data types; others are general.
Examples of generic commands are `DEL` and `EXPIRE`. They operate on keys
and not on their values specifically. All those generic commands are
defined inside `db.c`.
Moreover `db.c` implements an API in order to perform certain operations
on the Redis dataset without directly accessing the internal data structures.
The most important functions inside `db.c` which are used in many command
implementations are the following:
* `lookupKeyRead()` and `lookupKeyWrite()` are used in order to get a pointer to the value associated to a given key, or `NULL` if the key does not exist.
* `dbAdd()` and its higher level counterpart `setKey()` create a new key in a Redis database.
* `dbDelete()` removes a key and its associated value.
* `emptyDb()` removes an entire single database or all the databases defined.
The rest of the file implements the generic commands exposed to the client.
object.c
---
The `robj` structure defining Redis objects was already described. Inside
`object.c` there are all the functions that operate with Redis objects at
a basic level, like functions to allocate new objects, handle the reference
counting and so forth. Notable functions inside this file:
* `incrRefCount()` and `decrRefCount()` are used in order to increment or decrement an object reference count. When it drops to 0 the object is finally freed.
* `createObject()` allocates a new object. There are also specialized functions to allocate string objects having a specific content, like `createStringObjectFromLongLong()` and similar functions.
This file also implements the `OBJECT` command.
replication.c
---
This is one of the most complex files inside Redis, it is recommended to
approach it only after getting a bit familiar with the rest of the code base.
In this file there is the implementation of both the master and replica role
of Redis.
One of the most important functions inside this file is `replicationFeedSlaves()` that writes commands to the clients representing replica instances connected
to our master, so that the replicas can get the writes performed by the clients:
this way their data set will remain synchronized with the one in the master.
This file also implements both the `SYNC` and `PSYNC` commands that are
used in order to perform the first synchronization between masters and
replicas, or to continue the replication after a disconnection.
Script
---
The script unit is composed of 3 units:
* `script.c` - integration of scripts with Redis (commands execution, set replication/resp, ...)
* `script_lua.c` - responsible to execute Lua code, uses script.c to interact with Redis from within the Lua code.
* `function_lua.c` - contains the Lua engine implementation, uses script_lua.c to execute the Lua code.
* `functions.c` - contains Redis Functions implementation (FUNCTION command), uses functions_lua.c if the function it wants to invoke needs the Lua engine.
* `eval.c` - contains the `eval` implementation using `script_lua.c` to invoke the Lua code.
Other C files
---
* `t_hash.c`, `t_list.c`, `t_set.c`, `t_string.c`, `t_zset.c` and `t_stream.c` contains the implementation of the Redis data types. They implement both an API to access a given data type, and the client command implementations for these data types.
* `ae.c` implements the Redis event loop, it's a self contained library which is simple to read and understand.
* `sds.c` is the Redis string library, check https://github.com/antirez/sds for more information.
* `anet.c` is a library to use POSIX networking in a simpler way compared to the raw interface exposed by the kernel.
* `dict.c` is an implementation of a non-blocking hash table which rehashes incrementally.
* `cluster.c` implements the Redis Cluster. Probably a good read only after being very familiar with the rest of the Redis code base. If you want to read `cluster.c` make sure to read the [Redis Cluster specification][4].
[4]: https://redis.io/topics/cluster-spec
Anatomy of a Redis command
---
All the Redis commands are defined in the following way:
```c
void foobarCommand(client *c) {
printf("%s",c->argv[1]->ptr); /* Do something with the argument. */
addReply(c,shared.ok); /* Reply something to the client. */
}
```
The command function is referenced by a JSON file, together with its metadata, see `commands.c` described above for details.
The command flags are documented in the comment above the `struct redisCommand` in `server.h`.
For other details, please refer to the `COMMAND` command. https://redis.io/commands/command/
After the command operates in some way, it returns a reply to the client,
usually using `addReply()` or a similar function defined inside `networking.c`.
There are tons of command implementations inside the Redis source code
that can serve as examples of actual commands implementations (e.g. pingCommand). Writing
a few toy commands can be a good exercise to get familiar with the code base.
There are also many other files not described here, but it is useless to
cover everything. We just want to help you with the first steps.
Eventually you'll find your way inside the Redis code base :-)
Enjoy!
[1]: https://github.com/valkey-io/valkey/blob/unstable/COPYING
[2]: https://github.com/valkey-io/valkey/blob/unstable/CONTRIBUTING.md
[3]: https://github.com/valkey-io/valkey/blob/unstable/SECURITY.md
+4 -41
View File
@@ -1,43 +1,6 @@
# Security Policy
## Supported Versions
Redis is generally backwards compatible with very few exceptions, so we
recommend users to always use the latest version to experience stability,
performance and security.
We generally backport security issues to a single previous major version,
unless this is not possible or feasible with a reasonable effort.
| Version | Supported |
| ------- | ------------------ |
| 7.0.x | :white_check_mark: |
| 6.2.x | :white_check_mark: |
| 6.0.x | :white_check_mark: |
| < 6.0 | :x: |
## Reporting a Vulnerability
If you believe youve discovered a serious vulnerability, please contact the
Redis core team at redis@redis.io. We will evaluate your report and if
necessary issue a fix and an advisory. If the issue was previously undisclosed,
well also mention your name in the credits.
## Responsible Disclosure
In some cases, we may apply a responsible disclosure process to reported or
otherwise discovered vulnerabilities. We will usually do that for a critical
vulnerability, and only if we have a good reason to believe information about
it is not yet public.
This process involves providing an early notification about the vulnerability,
its impact and mitigations to a short list of vendors under a time-limited
embargo on public disclosure.
Vendors on the list are individuals or organizations that maintain Redis
distributions or provide Redis as a service, who have third party users who
will benefit from the vendors ability to prepare for a new version or deploy a
fix early.
If you believe you should be on the list, please contact us and we will
consider your request based on the above criteria.
If you believe you've discovered a security vulnerability, please contact the Valkey team at security@lists.valkey.io.
Please *DO NOT* create an issue.
We follow a responsible disclore procedure, so depending on the severity of the issue we may notify Valkey vendors about the issue before releasing it publicly.
If you would like to be added to our list of vendors, please reach out to the Valkey team at maintainers@lists.valkey.io.
+19
View File
@@ -0,0 +1,19 @@
coverage:
status:
patch:
default:
informational: true
project:
default:
informational: true
comment:
require_changes: false
require_head: false
require_base: false
layout: "condensed_header, diff, files"
hide_project_coverage: false
behavior: default
github_checks:
annotations: false
+1
View File
@@ -132,6 +132,7 @@ static int bit_tohex(lua_State *L)
const char *hexdigits = "0123456789abcdef";
char buf[8];
int i;
if (n == INT32_MIN) n = INT32_MIN+1;
if (n < 0) { n = -n; hexdigits = "0123456789ABCDEF"; }
if (n > 8) n = 8;
for (i = (int)n; --i >= 0; ) { buf[i] = hexdigits[b & 15]; b >>= 4; }
+27 -30
View File
@@ -9,15 +9,15 @@ protected-mode no
# The port that this sentinel instance will run on
port 26379
# By default Redis Sentinel does not run as a daemon. Use 'yes' if you need it.
# Note that Redis will write a pid file in /var/run/redis-sentinel.pid when
# By default Valkey Sentinel does not run as a daemon. Use 'yes' if you need it.
# Note that Valkey will write a pid file in /var/run/valkey-sentinel.pid when
# daemonized.
daemonize no
# When running daemonized, Redis Sentinel writes a pid file in
# /var/run/redis-sentinel.pid by default. You can specify a custom pid file
# When running daemonized, Valkey Sentinel writes a pid file in
# /var/run/valkey-sentinel.pid by default. You can specify a custom pid file
# location here.
pidfile /var/run/redis-sentinel.pid
pidfile /var/run/valkey-sentinel.pid
# Specify the server verbosity level.
# This can be one of:
@@ -67,12 +67,12 @@ logfile ""
# dir <working-directory>
# Every long running process should have a well-defined working directory.
# For Redis Sentinel to chdir to /tmp at startup is the simplest thing
# For Valkey Sentinel to chdir to /tmp at startup is the simplest thing
# for the process to don't interfere with administrative tasks such as
# unmounting filesystems.
dir /tmp
# sentinel monitor <master-name> <ip> <redis-port> <quorum>
# sentinel monitor <master-name> <ip> <valkey-port> <quorum>
#
# Tells Sentinel to monitor this master, and to consider it in O_DOWN
# (Objectively Down) state only if at least <quorum> sentinels agree.
@@ -94,16 +94,16 @@ sentinel monitor mymaster 127.0.0.1 6379 2
# sentinel auth-pass <master-name> <password>
#
# Set the password to use to authenticate with the master and replicas.
# Useful if there is a password set in the Redis instances to monitor.
# Useful if there is a password set in the Valkey instances to monitor.
#
# Note that the master password is also used for replicas, so it is not
# possible to set a different password in masters and replicas instances
# if you want to be able to monitor these instances with Sentinel.
#
# However you can have Redis instances without the authentication enabled
# mixed with Redis instances requiring the authentication (as long as the
# However you can have Valkey instances without the authentication enabled
# mixed with Valkey instances requiring the authentication (as long as the
# password set is the same for all the instances requiring the password) as
# the AUTH command will have no effect in Redis instances with authentication
# the AUTH command will have no effect in Valkey instances with authentication
# switched off.
#
# Example:
@@ -113,10 +113,10 @@ sentinel monitor mymaster 127.0.0.1 6379 2
# sentinel auth-user <master-name> <username>
#
# This is useful in order to authenticate to instances having ACL capabilities,
# that is, running Redis 6.0 or greater. When just auth-pass is provided the
# Sentinel instance will authenticate to Redis using the old "AUTH <pass>"
# that is, running Valkey. When just auth-pass is provided the
# Sentinel instance will authenticate to Valkey using the old "AUTH <pass>"
# method. When also an username is provided, it will use "AUTH <user> <pass>".
# In the Redis servers side, the ACL to provide just minimal access to
# In the Valkey servers side, the ACL to provide just minimal access to
# Sentinel instances, should be configured along the following lines:
#
# user sentinel-user >somepassword +client +subscribe +publish \
@@ -132,9 +132,6 @@ sentinel monitor mymaster 127.0.0.1 6379 2
# Default is 30 seconds.
sentinel down-after-milliseconds mymaster 30000
# IMPORTANT NOTE: starting with Redis 6.2 ACL capability is supported for
# Sentinel mode, please refer to the Redis website https://redis.io/topics/acl
# for more details.
# Sentinel's ACL users are defined in the following format:
#
@@ -145,8 +142,8 @@ sentinel down-after-milliseconds mymaster 30000
# user worker +@admin +@connection ~* on >ffa9203c493aa99
#
# For more information about ACL configuration please refer to the Redis
# website at https://redis.io/topics/acl and redis server configuration
# template redis.conf.
# website at https://valkey.io/topics/acl and valkey server configuration
# template valkey.conf.
# ACL LOG
#
@@ -164,9 +161,9 @@ acllog-max-len 128
# ACL file, the server will refuse to start.
#
# The format of the external ACL user file is exactly the same as the
# format that is used inside redis.conf to describe users.
# format that is used inside valkey.conf to describe users.
#
# aclfile /etc/redis/sentinel-users.acl
# aclfile /etc/valkey/sentinel-users.acl
# requirepass <password>
#
@@ -174,9 +171,9 @@ acllog-max-len 128
# so Sentinel will try to authenticate with the same password to all the
# other Sentinels. So you need to configure all your Sentinels in a given
# group with the same "requirepass" password. Check the following documentation
# for more info: https://redis.io/topics/sentinel
# for more info: https://valkey.io/topics/sentinel
#
# IMPORTANT NOTE: starting with Redis 6.2 "requirepass" is a compatibility
# IMPORTANT NOTE: "requirepass" is a compatibility
# layer on top of the ACL system. The option effect will be just setting
# the password for the default user. Clients will still authenticate using
# AUTH <password> as usually, or more explicitly with AUTH default <password>
@@ -259,7 +256,7 @@ sentinel failover-timeout mymaster 180000
# generated in the WARNING level (for instance -sdown, -odown, and so forth).
# This script should notify the system administrator via email, SMS, or any
# other messaging system, that there is something wrong with the monitored
# Redis systems.
# Valkey systems.
#
# The script is called with just two arguments: the first is the event type
# and the second the event description.
@@ -269,7 +266,7 @@ sentinel failover-timeout mymaster 180000
#
# Example:
#
# sentinel notification-script mymaster /var/redis/notify.sh
# sentinel notification-script mymaster /var/valkey/notify.sh
# CLIENTS RECONFIGURATION SCRIPT
#
@@ -294,7 +291,7 @@ sentinel failover-timeout mymaster 180000
#
# Example:
#
# sentinel client-reconfig-script mymaster /var/redis/reconfig.sh
# sentinel client-reconfig-script mymaster /var/valkey/reconfig.sh
# SECURITY
#
@@ -305,13 +302,13 @@ sentinel failover-timeout mymaster 180000
sentinel deny-scripts-reconfig yes
# REDIS COMMANDS RENAMING (DEPRECATED)
# VALKEY COMMANDS RENAMING (DEPRECATED)
#
# WARNING: avoid using this option if possible, instead use ACLs.
#
# Sometimes the Redis server has certain commands, that are needed for Sentinel
# Sometimes the Valkey server has certain commands, that are needed for Sentinel
# to work correctly, renamed to unguessable strings. This is often the case
# of CONFIG and SLAVEOF in the context of providers that provide Redis as
# of CONFIG and SLAVEOF in the context of providers that provide Valkey as
# a service, and don't want the customers to reconfigure the instances outside
# of the administration console.
#
@@ -335,7 +332,7 @@ sentinel deny-scripts-reconfig yes
# HOSTNAMES SUPPORT
#
# Normally Sentinel uses only IP addresses and requires SENTINEL MONITOR
# to specify an IP address. Also, it requires the Redis replica-announce-ip
# to specify an IP address. Also, it requires the Valkey replica-announce-ip
# keyword to specify only IP addresses.
#
# You may enable hostnames support by enabling resolve-hostnames. Note
+78 -34
View File
@@ -1,13 +1,13 @@
# Redis Makefile
# Valkey Makefile
# Copyright (C) 2009 Salvatore Sanfilippo <antirez at gmail dot com>
# This file is released under the BSD license, see the COPYING file
#
# The Makefile composes the final FINAL_CFLAGS and FINAL_LDFLAGS using
# what is needed for Redis plus the standard CFLAGS and LDFLAGS passed.
# what is needed for Valkey plus the standard CFLAGS and LDFLAGS passed.
# However when building the dependencies (Jemalloc, Lua, Hiredis, ...)
# CFLAGS and LDFLAGS are propagated to the dependencies, so to pass
# flags only to be used when compiling / linking Redis itself REDIS_CFLAGS
# and REDIS_LDFLAGS are used instead (this is the case of 'make gcov').
# flags only to be used when compiling / linking Valkey itself SERVER_CFLAGS
# and SERVER_LDFLAGS are used instead (this is the case of 'make gcov').
#
# Dependencies are stored in the Makefile.dep file. To rebuild this file
# Just use 'make dep', but this is only needed by developers.
@@ -19,11 +19,11 @@ CLANG := $(findstring clang,$(shell sh -c '$(CC) --version | head -1'))
OPTIMIZATION?=-O3
ifeq ($(OPTIMIZATION),-O3)
ifeq (clang,$(CLANG))
REDIS_CFLAGS+=-flto
SERVER_CFLAGS+=-flto
else
REDIS_CFLAGS+=-flto=auto
SERVER_CFLAGS+=-flto=auto
endif
REDIS_LDFLAGS+=-O3 -flto
SERVER_LDFLAGS+=-O3 -flto
endif
DEPENDENCY_TARGETS=hiredis linenoise lua hdr_histogram fpconv
NODEPS:=clean distclean
@@ -70,7 +70,7 @@ ifeq ($(uname_S),Linux)
MALLOC=jemalloc
endif
# To get ARM stack traces if Redis crashes we need a special C flag.
# To get ARM stack traces if Valkey crashes we need a special C flag.
ifneq (,$(filter aarch64 armv%,$(uname_M)))
CFLAGS+=-funwind-tables
endif
@@ -116,8 +116,16 @@ endif
# Override default settings if possible
-include .make-settings
FINAL_CFLAGS=$(STD) $(WARN) $(OPT) $(DEBUG) $(CFLAGS) $(REDIS_CFLAGS)
FINAL_LDFLAGS=$(LDFLAGS) $(REDIS_LDFLAGS) $(DEBUG)
# For added compatibility REDIS_CFLAGS and REDIS_LDFLAGS are also supported.
ifdef REDIS_CFLAGS
SERVER_CFLAGS := $(REDIS_CFLAGS)
endif
ifdef REDIS_LDFLAGS
SERVER_LDFLAGS := $(REDIS_LDFLAGS)
endif
FINAL_CFLAGS=$(STD) $(WARN) $(OPT) $(DEBUG) $(CFLAGS) $(SERVER_CFLAGS)
FINAL_LDFLAGS=$(LDFLAGS) $(SERVER_LDFLAGS) $(DEBUG)
FINAL_LIBS=-lm
DEBUG=-g -ggdb
@@ -297,7 +305,7 @@ ifeq ($(BUILD_TLS),yes)
endif
TLS_MODULE=
TLS_MODULE_NAME:=redis-tls$(PROG_SUFFIX).so
TLS_MODULE_NAME:=valkey-tls$(PROG_SUFFIX).so
TLS_MODULE_CFLAGS:=$(FINAL_CFLAGS)
ifeq ($(BUILD_TLS),module)
FINAL_CFLAGS+=-DUSE_OPENSSL=$(BUILD_MODULE) $(OPENSSL_CFLAGS)
@@ -311,10 +319,32 @@ ifndef V
@printf ' %b %b\n' $(LINKCOLOR)INSTALL$(ENDCOLOR) $(BINCOLOR)$(1)$(ENDCOLOR) 1>&2
@$(INSTALL) $(1) $(2)
endef
define INSTALL_REDIS_SYMLINK
@printf ' %b %b %b %b %b %b %b\n' \
$(LINKCOLOR)INSTALL SYMLINK$(ENDCOLOR) \
$(BINCOLOR)$(subst $(ENGINE_NAME),redis,$(1))$(ENDCOLOR) -\> $(BINCOLOR)$(1)$(ENDCOLOR) 1>&2
@ln -sf $(1) $(2)/$(subst $(ENGINE_NAME),redis,$(1))
endef
else
define MAKE_INSTALL
$(INSTALL) $(1) $(2)
endef
define INSTALL_REDIS_SYMLINK
ln -sf $(1) $(2)/$(subst $(ENGINE_NAME),redis,$(1))
endef
endif
# Determine install/uninstall Redis symlinks for compatibility when
# installing/uninstalling Valkey binaries (defaulting to `yes`)
USE_REDIS_SYMLINKS?=yes
ifeq ($(USE_REDIS_SYMLINKS),yes)
MAYBE_INSTALL_REDIS_SYMLINK=$(INSTALL_REDIS_SYMLINK)
MAYBE_UNINSTALL_REDIS_SYMLINK=@rm -f $(1)/$(subst $(ENGINE_NAME),redis,$(2))
else
MAYBE_INSTALL_REDIS_SYMLINK=
MAYBE_UNINSTALL_REDIS_SYMLINK=
endif
REDIS_CC=$(QUIET_CC)$(CC) $(FINAL_CFLAGS)
@@ -335,7 +365,7 @@ QUIET_LINK = @printf ' %b %b\n' $(LINKCOLOR)LINK$(ENDCOLOR) $(BINCOLOR)$@$(EN
QUIET_INSTALL = @printf ' %b %b\n' $(LINKCOLOR)INSTALL$(ENDCOLOR) $(BINCOLOR)$@$(ENDCOLOR) 1>&2;
endif
ifneq (, $(findstring LOG_REQ_RES, $(REDIS_CFLAGS)))
ifneq (, $(findstring LOG_REQ_RES, $(SERVER_CFLAGS)))
COMMANDS_DEF_FILENAME=commands_with_reply_schema
GEN_COMMANDS_FLAGS=--with-reply-schema
else
@@ -343,15 +373,16 @@ else
GEN_COMMANDS_FLAGS=
endif
REDIS_SERVER_NAME=redis-server$(PROG_SUFFIX)
REDIS_SENTINEL_NAME=redis-sentinel$(PROG_SUFFIX)
REDIS_SERVER_OBJ=adlist.o quicklist.o ae.o anet.o dict.o server.o sds.o zmalloc.o lzf_c.o lzf_d.o pqsort.o zipmap.o sha1.o ziplist.o release.o networking.o util.o object.o db.o replication.o rdb.o t_string.o t_list.o t_set.o t_zset.o t_hash.o config.o aof.o pubsub.o multi.o debug.o sort.o intset.o syncio.o cluster.o crc16.o endianconv.o slowlog.o eval.o bio.o rio.o rand.o memtest.o syscheck.o crcspeed.o crc64.o bitops.o sentinel.o notify.o setproctitle.o blocked.o hyperloglog.o latency.o sparkline.o redis-check-rdb.o redis-check-aof.o geo.o lazyfree.o module.o evict.o expire.o geohash.o geohash_helper.o childinfo.o defrag.o siphash.o rax.o t_stream.o listpack.o localtime.o lolwut.o lolwut5.o lolwut6.o acl.o tracking.o socket.o tls.o sha256.o timeout.o setcpuaffinity.o monotonic.o mt19937-64.o resp_parser.o call_reply.o script_lua.o script.o functions.o function_lua.o commands.o strl.o connection.o unix.o logreqres.o
REDIS_CLI_NAME=redis-cli$(PROG_SUFFIX)
REDIS_CLI_OBJ=anet.o adlist.o dict.o redis-cli.o zmalloc.o release.o ae.o redisassert.o crcspeed.o crc64.o siphash.o crc16.o monotonic.o cli_common.o mt19937-64.o strl.o cli_commands.o
REDIS_BENCHMARK_NAME=redis-benchmark$(PROG_SUFFIX)
REDIS_BENCHMARK_OBJ=ae.o anet.o redis-benchmark.o adlist.o dict.o zmalloc.o redisassert.o release.o crcspeed.o crc64.o siphash.o crc16.o monotonic.o cli_common.o mt19937-64.o strl.o
REDIS_CHECK_RDB_NAME=redis-check-rdb$(PROG_SUFFIX)
REDIS_CHECK_AOF_NAME=redis-check-aof$(PROG_SUFFIX)
ENGINE_NAME=valkey
REDIS_SERVER_NAME=valkey-server$(PROG_SUFFIX)
REDIS_SENTINEL_NAME=valkey-sentinel$(PROG_SUFFIX)
REDIS_SERVER_OBJ=adlist.o quicklist.o ae.o anet.o dict.o server.o sds.o zmalloc.o lzf_c.o lzf_d.o pqsort.o zipmap.o sha1.o ziplist.o release.o networking.o util.o object.o db.o replication.o rdb.o t_string.o t_list.o t_set.o t_zset.o t_hash.o config.o aof.o pubsub.o multi.o debug.o sort.o intset.o syncio.o cluster.o crc16.o endianconv.o slowlog.o eval.o bio.o rio.o rand.o memtest.o syscheck.o crcspeed.o crc64.o bitops.o sentinel.o notify.o setproctitle.o blocked.o hyperloglog.o latency.o sparkline.o valkey-check-rdb.o valkey-check-aof.o geo.o lazyfree.o module.o evict.o expire.o geohash.o geohash_helper.o childinfo.o defrag.o siphash.o rax.o t_stream.o listpack.o localtime.o lolwut.o lolwut5.o lolwut6.o acl.o tracking.o socket.o tls.o sha256.o timeout.o setcpuaffinity.o monotonic.o mt19937-64.o resp_parser.o call_reply.o script_lua.o script.o functions.o function_lua.o commands.o strl.o connection.o unix.o logreqres.o
REDIS_CLI_NAME=valkey-cli$(PROG_SUFFIX)
REDIS_CLI_OBJ=anet.o adlist.o dict.o valkey-cli.o zmalloc.o release.o ae.o redisassert.o crcspeed.o crc64.o siphash.o crc16.o monotonic.o cli_common.o mt19937-64.o strl.o cli_commands.o
REDIS_BENCHMARK_NAME=valkey-benchmark$(PROG_SUFFIX)
REDIS_BENCHMARK_OBJ=ae.o anet.o valkey-benchmark.o adlist.o dict.o zmalloc.o redisassert.o release.o crcspeed.o crc64.o siphash.o crc16.o monotonic.o cli_common.o mt19937-64.o strl.o
REDIS_CHECK_RDB_NAME=valkey-check-rdb$(PROG_SUFFIX)
REDIS_CHECK_AOF_NAME=valkey-check-aof$(PROG_SUFFIX)
ALL_SOURCES=$(sort $(patsubst %.o,%.c,$(REDIS_SERVER_OBJ) $(REDIS_CLI_OBJ) $(REDIS_BENCHMARK_OBJ)))
all: $(REDIS_SERVER_NAME) $(REDIS_SENTINEL_NAME) $(REDIS_CLI_NAME) $(REDIS_BENCHMARK_NAME) $(REDIS_CHECK_RDB_NAME) $(REDIS_CHECK_AOF_NAME) $(TLS_MODULE)
@@ -377,8 +408,8 @@ persist-settings: distclean
echo USE_SYSTEMD=$(USE_SYSTEMD) >> .make-settings
echo CFLAGS=$(CFLAGS) >> .make-settings
echo LDFLAGS=$(LDFLAGS) >> .make-settings
echo REDIS_CFLAGS=$(REDIS_CFLAGS) >> .make-settings
echo REDIS_LDFLAGS=$(REDIS_LDFLAGS) >> .make-settings
echo SERVER_CFLAGS=$(SERVER_CFLAGS) >> .make-settings
echo SERVER_LDFLAGS=$(SERVER_LDFLAGS) >> .make-settings
echo PREV_FINAL_CFLAGS=$(FINAL_CFLAGS) >> .make-settings
echo PREV_FINAL_LDFLAGS=$(FINAL_LDFLAGS) >> .make-settings
-(cd ../deps && $(MAKE) $(DEPENDENCY_TARGETS))
@@ -398,31 +429,31 @@ ifneq ($(strip $(PREV_FINAL_LDFLAGS)), $(strip $(FINAL_LDFLAGS)))
.make-prerequisites: persist-settings
endif
# redis-server
# valkey-server
$(REDIS_SERVER_NAME): $(REDIS_SERVER_OBJ)
$(REDIS_LD) -o $@ $^ ../deps/hiredis/libhiredis.a ../deps/lua/src/liblua.a ../deps/hdr_histogram/libhdrhistogram.a ../deps/fpconv/libfpconv.a $(FINAL_LIBS)
# redis-sentinel
# valkey-sentinel
$(REDIS_SENTINEL_NAME): $(REDIS_SERVER_NAME)
$(REDIS_INSTALL) $(REDIS_SERVER_NAME) $(REDIS_SENTINEL_NAME)
# redis-check-rdb
# valkey-check-rdb
$(REDIS_CHECK_RDB_NAME): $(REDIS_SERVER_NAME)
$(REDIS_INSTALL) $(REDIS_SERVER_NAME) $(REDIS_CHECK_RDB_NAME)
# redis-check-aof
# valkey-check-aof
$(REDIS_CHECK_AOF_NAME): $(REDIS_SERVER_NAME)
$(REDIS_INSTALL) $(REDIS_SERVER_NAME) $(REDIS_CHECK_AOF_NAME)
# redis-tls.so
# valkey-tls.so
$(TLS_MODULE_NAME): $(REDIS_SERVER_NAME)
$(QUIET_CC)$(CC) -o $@ tls.c -shared -fPIC $(TLS_MODULE_CFLAGS) $(TLS_CLIENT_LIBS)
# redis-cli
# valkey-cli
$(REDIS_CLI_NAME): $(REDIS_CLI_OBJ)
$(REDIS_LD) -o $@ $^ ../deps/hiredis/libhiredis.a ../deps/linenoise/linenoise.o $(FINAL_LIBS) $(TLS_CLIENT_LIBS)
# redis-benchmark
# valkey-benchmark
$(REDIS_BENCHMARK_NAME): $(REDIS_BENCHMARK_OBJ)
$(REDIS_LD) -o $@ $^ ../deps/hiredis/libhiredis.a ../deps/hdr_histogram/libhdrhistogram.a $(FINAL_LIBS) $(TLS_CLIENT_LIBS)
@@ -473,8 +504,9 @@ test-cluster: $(REDIS_SERVER_NAME) $(REDIS_CLI_NAME)
check: test
lcov:
@lcov --version
$(MAKE) gcov
@(set -e; cd ..; ./runtest --clients 1)
@(set -e; cd ..; ./runtest)
@geninfo -o redis.info .
@genhtml --legend -o lcov-html redis.info
@@ -490,7 +522,7 @@ bench: $(REDIS_BENCHMARK_NAME)
$(MAKE) CFLAGS="-m32" LDFLAGS="-m32"
gcov:
$(MAKE) REDIS_CFLAGS="-fprofile-arcs -ftest-coverage -DCOVERAGE_TEST" REDIS_LDFLAGS="-fprofile-arcs -ftest-coverage"
$(MAKE) SERVER_CFLAGS="-fprofile-arcs -ftest-coverage -DCOVERAGE_TEST" SERVER_LDFLAGS="-fprofile-arcs -ftest-coverage"
noopt:
$(MAKE) OPTIMIZATION="-O0"
@@ -499,7 +531,7 @@ valgrind:
$(MAKE) OPTIMIZATION="-O0" MALLOC="libc"
helgrind:
$(MAKE) OPTIMIZATION="-O0" MALLOC="libc" CFLAGS="-D__ATOMIC_VAR_FORCE_SYNC_MACROS" REDIS_CFLAGS="-I/usr/local/include" REDIS_LDFLAGS="-L/usr/local/lib"
$(MAKE) OPTIMIZATION="-O0" MALLOC="libc" CFLAGS="-D__ATOMIC_VAR_FORCE_SYNC_MACROS" SERVER_CFLAGS="-I/usr/local/include" SERVER_LDFLAGS="-L/usr/local/lib"
install: all
@mkdir -p $(INSTALL_BIN)
@@ -509,6 +541,18 @@ install: all
@ln -sf $(REDIS_SERVER_NAME) $(INSTALL_BIN)/$(REDIS_CHECK_RDB_NAME)
@ln -sf $(REDIS_SERVER_NAME) $(INSTALL_BIN)/$(REDIS_CHECK_AOF_NAME)
@ln -sf $(REDIS_SERVER_NAME) $(INSTALL_BIN)/$(REDIS_SENTINEL_NAME)
$(call MAYBE_INSTALL_REDIS_SYMLINK,$(REDIS_SERVER_NAME),$(INSTALL_BIN))
$(call MAYBE_INSTALL_REDIS_SYMLINK,$(REDIS_CLI_NAME),$(INSTALL_BIN))
$(call MAYBE_INSTALL_REDIS_SYMLINK,$(REDIS_BENCHMARK_NAME),$(INSTALL_BIN))
$(call MAYBE_INSTALL_REDIS_SYMLINK,$(REDIS_CHECK_RDB_NAME),$(INSTALL_BIN))
$(call MAYBE_INSTALL_REDIS_SYMLINK,$(REDIS_CHECK_AOF_NAME),$(INSTALL_BIN))
$(call MAYBE_INSTALL_REDIS_SYMLINK,$(REDIS_SENTINEL_NAME),$(INSTALL_BIN))
uninstall:
rm -f $(INSTALL_BIN)/{$(REDIS_SERVER_NAME),$(REDIS_BENCHMARK_NAME),$(REDIS_CLI_NAME),$(REDIS_CHECK_RDB_NAME),$(REDIS_CHECK_AOF_NAME),$(REDIS_SENTINEL_NAME)}
@rm -f $(INSTALL_BIN)/{$(SERVER_NAME),$(ENGINE_BENCHMARK_NAME),$(ENGINE_CLI_NAME),$(ENGINE_CHECK_RDB_NAME),$(ENGINE_CHECK_AOF_NAME),$(ENGINE_SENTINEL_NAME)}
$(call MAYBE_UNINSTALL_REDIS_SYMLINK,$(INSTALL_BIN),$(SERVER_NAME))
$(call MAYBE_UNINSTALL_REDIS_SYMLINK,$(INSTALL_BIN),$(ENGINE_CLI_NAME))
$(call MAYBE_UNINSTALL_REDIS_SYMLINK,$(INSTALL_BIN),$(ENGINE_BENCHMARK_NAME))
$(call MAYBE_UNINSTALL_REDIS_SYMLINK,$(INSTALL_BIN),$(ENGINE_CHECK_RDB_NAME))
$(call MAYBE_UNINSTALL_REDIS_SYMLINK,$(INSTALL_BIN),$(ENGINE_CHECK_AOF_NAME))
$(call MAYBE_UNINSTALL_REDIS_SYMLINK,$(INSTALL_BIN),$(ENGINE_SENTINEL_NAME))
+15 -11
View File
@@ -62,7 +62,7 @@ static unsigned long nextid = 0; /* Next command id that has not been assigned *
struct ACLCategoryItem {
const char *name;
uint64_t flag;
} ACLCommandCategories[] = { /* See redis.conf for details on each category. */
} ACLCommandCategories[] = { /* See valkey.conf for details on each category. */
{"keyspace", ACL_CATEGORY_KEYSPACE},
{"read", ACL_CATEGORY_READ},
{"write", ACL_CATEGORY_WRITE},
@@ -456,8 +456,7 @@ void ACLFreeUserAndKillClients(user *u) {
* this may result in some security hole: it's much
* more defensive to set the default user and put
* it in non authenticated mode. */
c->user = DefaultUser;
c->authenticated = 0;
clientSetUser(c, DefaultUser, 0);
/* We will write replies to this client later, so we can't
* close it directly even if async. */
if (c == server.current_client) {
@@ -1046,6 +1045,7 @@ int ACLSetSelector(aclSelector *selector, const char* op, size_t oplen) {
int flags = 0;
size_t offset = 1;
if (op[0] == '%') {
int perm_ok = 1;
for (; offset < oplen; offset++) {
if (toupper(op[offset]) == 'R' && !(flags & ACL_READ_PERMISSION)) {
flags |= ACL_READ_PERMISSION;
@@ -1055,10 +1055,14 @@ int ACLSetSelector(aclSelector *selector, const char* op, size_t oplen) {
offset++;
break;
} else {
errno = EINVAL;
return C_ERR;
perm_ok = 0;
break;
}
}
if (!flags || !perm_ok) {
errno = EINVAL;
return C_ERR;
}
} else {
flags = ACL_ALL_PERMISSION;
}
@@ -1461,10 +1465,10 @@ void addAuthErrReply(client *c, robj *err) {
* connection user reference is populated.
*
* The return value is AUTH_OK on success (valid username / password pair) & AUTH_ERR otherwise. */
int checkPasswordBasedAuth(client *c, robj *username, robj *password) {
if (ACLCheckUserCredentials(username,password) == C_OK) {
c->authenticated = 1;
c->user = ACLGetUserByName(username->ptr,sdslen(username->ptr));
static int checkPasswordBasedAuth(client *c, robj *username, robj *password) {
if (ACLCheckUserCredentials(username, password) == C_OK) {
user *user = ACLGetUserByName(username->ptr, sdslen(username->ptr));
clientSetUser(c, user, 1);
moduleNotifyUserChanged(c);
return AUTH_OK;
} else {
@@ -2207,7 +2211,7 @@ int ACLLoadConfiguredUsers(void) {
/* This function loads the ACL from the specified filename: every line
* is validated and should be either empty or in the format used to specify
* users in the redis.conf configuration or in the ACL file, that is:
* users in the valkey.conf or in the ACL file, that is:
*
* user <username> ... rules ...
*
@@ -2469,7 +2473,7 @@ cleanup:
/* This function is called once the server is already running, modules are
* loaded, and we are ready to start, in order to load the ACLs either from
* the pending list of users defined in redis.conf, or from the ACL file.
* the pending list of users defined in valkey.conf, or from the ACL file.
* The function will just exit with an error if the user is trying to mix
* both the loading methods. */
void ACLLoadUsersAtStartup(void) {
+1 -1
View File
@@ -333,7 +333,7 @@ static int processTimeEvents(aeEventLoop *eventLoop) {
processed++;
now = getMonotonicUs();
if (retval != AE_NOMORE) {
te->when = now + retval * 1000;
te->when = now + (monotime)retval * 1000;
} else {
te->id = AE_DELETED_EVENT_ID;
}
+6 -5
View File
@@ -417,13 +417,16 @@ int anetUnixGenericConnect(char *err, const char *path, int flags)
return s;
}
static int anetListen(char *err, int s, struct sockaddr *sa, socklen_t len, int backlog) {
static int anetListen(char *err, int s, struct sockaddr *sa, socklen_t len, int backlog, mode_t perm) {
if (bind(s,sa,len) == -1) {
anetSetError(err, "bind: %s", strerror(errno));
close(s);
return ANET_ERR;
}
if (sa->sa_family == AF_LOCAL && perm)
chmod(((struct sockaddr_un *) sa)->sun_path, perm);
if (listen(s, backlog) == -1) {
anetSetError(err, "listen: %s", strerror(errno));
close(s);
@@ -467,7 +470,7 @@ static int _anetTcpServer(char *err, int port, char *bindaddr, int af, int backl
if (af == AF_INET6 && anetV6Only(err,s) == ANET_ERR) goto error;
if (anetSetReuseAddr(err,s) == ANET_ERR) goto error;
if (anetListen(err,s,p->ai_addr,p->ai_addrlen,backlog) == ANET_ERR) s = ANET_ERR;
if (anetListen(err,s,p->ai_addr,p->ai_addrlen,backlog,0) == ANET_ERR) s = ANET_ERR;
goto end;
}
if (p == NULL) {
@@ -508,10 +511,8 @@ int anetUnixServer(char *err, char *path, mode_t perm, int backlog)
memset(&sa,0,sizeof(sa));
sa.sun_family = AF_LOCAL;
redis_strlcpy(sa.sun_path,path,sizeof(sa.sun_path));
if (anetListen(err,s,(struct sockaddr*)&sa,sizeof(sa),backlog) == ANET_ERR)
if (anetListen(err,s,(struct sockaddr*)&sa,sizeof(sa),backlog,perm) == ANET_ERR)
return ANET_ERR;
if (perm)
chmod(sa.sun_path, perm);
return s;
}
+23 -17
View File
@@ -117,7 +117,9 @@ aofInfo *aofInfoDup(aofInfo *orig) {
return ai;
}
/* Format aofInfo as a string and it will be a line in the manifest. */
/* Format aofInfo as a string and it will be a line in the manifest.
*
* When update this format, make sure to update valkey-check-aof as well. */
sds aofInfoFormat(sds buf, aofInfo *ai) {
sds filename_repr = NULL;
@@ -251,7 +253,7 @@ void aofLoadManifestFromDisk(void) {
sdsfree(am_filepath);
}
/* Generic manifest loading function, used in `aofLoadManifestFromDisk` and redis-check-aof tool. */
/* Generic manifest loading function, used in `aofLoadManifestFromDisk` and valkey-check-aof tool. */
#define MANIFEST_MAX_LINE 1024
aofManifest *aofLoadManifestFromFile(sds am_filepath) {
const char *err = NULL;
@@ -976,18 +978,6 @@ void stopAppendOnly(void) {
int startAppendOnly(void) {
serverAssert(server.aof_state == AOF_OFF);
/* Wait for all bio jobs related to AOF to drain. This prevents a race
* between updates to `fsynced_reploff_pending` of the worker thread, belonging
* to the previous AOF, and the new one. This concern is specific for a full
* sync scenario where we don't wanna risk the ACKed replication offset
* jumping backwards or forward when switching to a different master. */
bioDrainWorker(BIO_AOF_FSYNC);
/* Set the initial repl_offset, which will be applied to fsynced_reploff
* when AOFRW finishes (after possibly being updated by a bio thread) */
atomicSet(server.fsynced_reploff_pending, server.master_repl_offset);
server.fsynced_reploff = 0;
server.aof_state = AOF_WAIT_REWRITE;
if (hasActiveChildProcess() && server.child_type != CHILD_TYPE_AOF) {
server.aof_rewrite_scheduled = 1;
@@ -1637,14 +1627,14 @@ uxeof: /* Unexpected AOF end of file. */
}
}
serverLog(LL_WARNING, "Unexpected end of file reading the append only file %s. You can: "
"1) Make a backup of your AOF file, then use ./redis-check-aof --fix <filename.manifest>. "
"1) Make a backup of your AOF file, then use ./valkey-check-aof --fix <filename.manifest>. "
"2) Alternatively you can set the 'aof-load-truncated' configuration option to yes and restart the server.", filename);
ret = AOF_FAILED;
goto cleanup;
fmterr: /* Format error. */
serverLog(LL_WARNING, "Bad file format reading the append only file %s: "
"make a backup of your AOF file, then use ./redis-check-aof --fix <filename.manifest>", filename);
"make a backup of your AOF file, then use ./valkey-check-aof --fix <filename.manifest>", filename);
ret = AOF_FAILED;
/* fall through to cleanup. */
@@ -2213,7 +2203,7 @@ int rewriteStreamObject(rio *r, robj *key, robj *o) {
* that is exported by a module and is not handled by Redis itself.
* The function returns 0 on error, 1 on success. */
int rewriteModuleObject(rio *r, robj *key, robj *o, int dbid) {
RedisModuleIO io;
ValkeyModuleIO io;
moduleValue *mv = o->ptr;
moduleType *mt = mv->type;
moduleInitIOContext(io,mt,r,key,dbid);
@@ -2454,7 +2444,23 @@ int rewriteAppendOnlyFileBackground(void) {
server.aof_lastbgrewrite_status = C_ERR;
return C_ERR;
}
if (server.aof_state == AOF_WAIT_REWRITE) {
/* Wait for all bio jobs related to AOF to drain. This prevents a race
* between updates to `fsynced_reploff_pending` of the worker thread, belonging
* to the previous AOF, and the new one. This concern is specific for a full
* sync scenario where we don't wanna risk the ACKed replication offset
* jumping backwards or forward when switching to a different master. */
bioDrainWorker(BIO_AOF_FSYNC);
/* Set the initial repl_offset, which will be applied to fsynced_reploff
* when AOFRW finishes (after possibly being updated by a bio thread) */
atomicSet(server.fsynced_reploff_pending, server.master_repl_offset);
server.fsynced_reploff = 0;
}
server.stat_aof_rewrites++;
if ((childpid = redisFork(CHILD_TYPE_AOF)) == 0) {
char tmpfile[256];
+19 -17
View File
@@ -28,20 +28,22 @@
*/
const char *ascii_logo =
" _._ \n"
" _.-``__ ''-._ \n"
" _.-`` `. `_. ''-._ Redis %s (%s/%d) %s bit\n"
" .-`` .-```. ```\\/ _.,_ ''-._ \n"
" ( ' , .-` | `, ) Running in %s mode\n"
" |`-._`-...-` __...-.``-._|'` _.-'| Port: %d\n"
" | `-._ `._ / _.-' | PID: %ld\n"
" `-._ `-._ `-./ _.-' _.-' \n"
" |`-._`-._ `-.__.-' _.-'_.-'| \n"
" | `-._`-._ _.-'_.-' | https://redis.io \n"
" `-._ `-._`-.__.-'_.-' _.-' \n"
" |`-._`-._ `-.__.-' _.-'_.-'| \n"
" | `-._`-._ _.-'_.-' | \n"
" `-._ `-._`-.__.-'_.-' _.-' \n"
" `-._ `-.__.-' _.-' \n"
" `-._ _.-' \n"
" `-.__.-' \n\n";
" .+^+. \n"
" .+#########+. \n"
" .+########+########+. Valkey %s (%s/%d) %s bit\n"
" .+########+' '+########+. \n"
" .########+' .+. '+########. Running in %s mode\n"
" |####+' .+#######+. '+####| Port: %d\n"
" |###| .+###############+. |###| PID: %ld \n"
" |###| |#####*'' ''*#####| |###| \n"
" |###| |####' .-. '####| |###| \n"
" |###| |###( (@@@) )###| |###| https://valkey.io \n"
" |###| |####. '-' .####| |###| \n"
" |###| |#####*. .*#####| |###| \n"
" |###| '+#####| |#####+' |###| \n"
" |####+. +##| |#+' .+####| \n"
" '#######+ |##| .+########' \n"
" '+###| |##| .+########+' \n"
" '| |####+########+' \n"
" +#########+' \n"
" '+v+' \n\n";
+7 -2
View File
@@ -370,7 +370,12 @@ void blockForKeys(client *c, int btype, robj **keys, int numkeys, mstime_t timeo
list *l;
int j;
c->bstate.timeout = timeout;
if (!(c->flags & CLIENT_REPROCESSING_COMMAND)) {
/* If the client is re-processing the command, we do not set the timeout
* because we need to retain the client's original timeout. */
c->bstate.timeout = timeout;
}
for (j = 0; j < numkeys; j++) {
/* If the key already exists in the dictionary ignore it. */
if (!(client_blocked_entry = dictAddRaw(c->bstate.keys,keys[j],NULL))) {
@@ -392,7 +397,6 @@ void blockForKeys(client *c, int btype, robj **keys, int numkeys, mstime_t timeo
listAddNodeTail(l,c);
dictSetVal(c->bstate.keys,client_blocked_entry,listLast(l));
/* We need to add the key to blocking_keys_unblock_on_nokey, if the client
* wants to be awakened if key is deleted (like XREADGROUP) */
if (unblock_on_nokey) {
@@ -626,6 +630,7 @@ void blockPostponeClient(client *c) {
/* Block client due to shutdown command */
void blockClientShutdown(client *c) {
c->bstate.timeout = 0;
blockClient(c, BLOCKED_SHUTDOWN);
}
+56 -56
View File
@@ -73,55 +73,55 @@ static void callReplySetSharedData(CallReply *rep, int type, const char *proto,
static void callReplyNull(void *ctx, const char *proto, size_t proto_len) {
CallReply *rep = ctx;
callReplySetSharedData(rep, REDISMODULE_REPLY_NULL, proto, proto_len, REPLY_FLAG_RESP3);
callReplySetSharedData(rep, VALKEYMODULE_REPLY_NULL, proto, proto_len, REPLY_FLAG_RESP3);
}
static void callReplyNullBulkString(void *ctx, const char *proto, size_t proto_len) {
CallReply *rep = ctx;
callReplySetSharedData(rep, REDISMODULE_REPLY_NULL, proto, proto_len, 0);
callReplySetSharedData(rep, VALKEYMODULE_REPLY_NULL, proto, proto_len, 0);
}
static void callReplyNullArray(void *ctx, const char *proto, size_t proto_len) {
CallReply *rep = ctx;
callReplySetSharedData(rep, REDISMODULE_REPLY_NULL, proto, proto_len, 0);
callReplySetSharedData(rep, VALKEYMODULE_REPLY_NULL, proto, proto_len, 0);
}
static void callReplyBulkString(void *ctx, const char *str, size_t len, const char *proto, size_t proto_len) {
CallReply *rep = ctx;
callReplySetSharedData(rep, REDISMODULE_REPLY_STRING, proto, proto_len, 0);
callReplySetSharedData(rep, VALKEYMODULE_REPLY_STRING, proto, proto_len, 0);
rep->len = len;
rep->val.str = str;
}
static void callReplyError(void *ctx, const char *str, size_t len, const char *proto, size_t proto_len) {
CallReply *rep = ctx;
callReplySetSharedData(rep, REDISMODULE_REPLY_ERROR, proto, proto_len, 0);
callReplySetSharedData(rep, VALKEYMODULE_REPLY_ERROR, proto, proto_len, 0);
rep->len = len;
rep->val.str = str;
}
static void callReplySimpleStr(void *ctx, const char *str, size_t len, const char *proto, size_t proto_len) {
CallReply *rep = ctx;
callReplySetSharedData(rep, REDISMODULE_REPLY_STRING, proto, proto_len, 0);
callReplySetSharedData(rep, VALKEYMODULE_REPLY_STRING, proto, proto_len, 0);
rep->len = len;
rep->val.str = str;
}
static void callReplyLong(void *ctx, long long val, const char *proto, size_t proto_len) {
CallReply *rep = ctx;
callReplySetSharedData(rep, REDISMODULE_REPLY_INTEGER, proto, proto_len, 0);
callReplySetSharedData(rep, VALKEYMODULE_REPLY_INTEGER, proto, proto_len, 0);
rep->val.ll = val;
}
static void callReplyDouble(void *ctx, double val, const char *proto, size_t proto_len) {
CallReply *rep = ctx;
callReplySetSharedData(rep, REDISMODULE_REPLY_DOUBLE, proto, proto_len, REPLY_FLAG_RESP3);
callReplySetSharedData(rep, VALKEYMODULE_REPLY_DOUBLE, proto, proto_len, REPLY_FLAG_RESP3);
rep->val.d = val;
}
static void callReplyVerbatimString(void *ctx, const char *format, const char *str, size_t len, const char *proto, size_t proto_len) {
CallReply *rep = ctx;
callReplySetSharedData(rep, REDISMODULE_REPLY_VERBATIM_STRING, proto, proto_len, REPLY_FLAG_RESP3);
callReplySetSharedData(rep, VALKEYMODULE_REPLY_VERBATIM_STRING, proto, proto_len, REPLY_FLAG_RESP3);
rep->len = len;
rep->val.verbatim_str.str = str;
rep->val.verbatim_str.format = format;
@@ -129,14 +129,14 @@ static void callReplyVerbatimString(void *ctx, const char *format, const char *s
static void callReplyBigNumber(void *ctx, const char *str, size_t len, const char *proto, size_t proto_len) {
CallReply *rep = ctx;
callReplySetSharedData(rep, REDISMODULE_REPLY_BIG_NUMBER, proto, proto_len, REPLY_FLAG_RESP3);
callReplySetSharedData(rep, VALKEYMODULE_REPLY_BIG_NUMBER, proto, proto_len, REPLY_FLAG_RESP3);
rep->len = len;
rep->val.str = str;
}
static void callReplyBool(void *ctx, int val, const char *proto, size_t proto_len) {
CallReply *rep = ctx;
callReplySetSharedData(rep, REDISMODULE_REPLY_BOOL, proto, proto_len, REPLY_FLAG_RESP3);
callReplySetSharedData(rep, VALKEYMODULE_REPLY_BOOL, proto, proto_len, REPLY_FLAG_RESP3);
rep->val.ll = val;
}
@@ -164,7 +164,7 @@ static void callReplyAttribute(ReplyParser *parser, void *ctx, size_t len, const
/* Continue parsing the attribute reply */
rep->attribute->len = len;
rep->attribute->type = REDISMODULE_REPLY_ATTRIBUTE;
rep->attribute->type = VALKEYMODULE_REPLY_ATTRIBUTE;
callReplyParseCollection(parser, rep->attribute, len, proto, 2);
rep->attribute->flags |= REPLY_FLAG_PARSED | REPLY_FLAG_RESP3;
rep->attribute->private_data = rep->private_data;
@@ -180,39 +180,39 @@ static void callReplyAttribute(ReplyParser *parser, void *ctx, size_t len, const
static void callReplyArray(ReplyParser *parser, void *ctx, size_t len, const char *proto) {
CallReply *rep = ctx;
rep->type = REDISMODULE_REPLY_ARRAY;
rep->type = VALKEYMODULE_REPLY_ARRAY;
callReplyParseCollection(parser, rep, len, proto, 1);
}
static void callReplySet(ReplyParser *parser, void *ctx, size_t len, const char *proto) {
CallReply *rep = ctx;
rep->type = REDISMODULE_REPLY_SET;
rep->type = VALKEYMODULE_REPLY_SET;
callReplyParseCollection(parser, rep, len, proto, 1);
rep->flags |= REPLY_FLAG_RESP3;
}
static void callReplyMap(ReplyParser *parser, void *ctx, size_t len, const char *proto) {
CallReply *rep = ctx;
rep->type = REDISMODULE_REPLY_MAP;
rep->type = VALKEYMODULE_REPLY_MAP;
callReplyParseCollection(parser, rep, len, proto, 2);
rep->flags |= REPLY_FLAG_RESP3;
}
static void callReplyParseError(void *ctx) {
CallReply *rep = ctx;
rep->type = REDISMODULE_REPLY_UNKNOWN;
rep->type = VALKEYMODULE_REPLY_UNKNOWN;
}
/* Recursively free the current call reply and its sub-replies. */
static void freeCallReplyInternal(CallReply *rep) {
if (rep->type == REDISMODULE_REPLY_ARRAY || rep->type == REDISMODULE_REPLY_SET) {
if (rep->type == VALKEYMODULE_REPLY_ARRAY || rep->type == VALKEYMODULE_REPLY_SET) {
for (size_t i = 0 ; i < rep->len ; ++i) {
freeCallReplyInternal(rep->val.array + i);
}
zfree(rep->val.array);
}
if (rep->type == REDISMODULE_REPLY_MAP || rep->type == REDISMODULE_REPLY_ATTRIBUTE) {
if (rep->type == VALKEYMODULE_REPLY_MAP || rep->type == VALKEYMODULE_REPLY_ATTRIBUTE) {
for (size_t i = 0 ; i < rep->len ; ++i) {
freeCallReplyInternal(rep->val.array + i * 2);
freeCallReplyInternal(rep->val.array + i * 2 + 1);
@@ -234,7 +234,7 @@ void freeCallReply(CallReply *rep) {
return;
}
if (rep->flags & REPLY_FLAG_PARSED) {
if (rep->type == REDISMODULE_REPLY_PROMISE) {
if (rep->type == VALKEYMODULE_REPLY_PROMISE) {
zfree(rep);
return;
}
@@ -248,7 +248,7 @@ void freeCallReply(CallReply *rep) {
CallReply *callReplyCreatePromise(void *private_data) {
CallReply *res = zmalloc(sizeof(*res));
res->type = REDISMODULE_REPLY_PROMISE;
res->type = VALKEYMODULE_REPLY_PROMISE;
/* Mark the reply as parsed so there will be not attempt to parse
* it when calling reply API such as freeCallReply.
* Also mark the reply as root so freeCallReply will not ignore it. */
@@ -289,16 +289,16 @@ static void callReplyParse(CallReply *rep) {
rep->flags |= REPLY_FLAG_PARSED;
}
/* Return the call reply type (REDISMODULE_REPLY_...). */
/* Return the call reply type (VALKEYMODULE_REPLY_...). */
int callReplyType(CallReply *rep) {
if (!rep) return REDISMODULE_REPLY_UNKNOWN;
if (!rep) return VALKEYMODULE_REPLY_UNKNOWN;
callReplyParse(rep);
return rep->type;
}
/* Return reply string as buffer and len. Applicable to:
* - REDISMODULE_REPLY_STRING
* - REDISMODULE_REPLY_ERROR
* - VALKEYMODULE_REPLY_STRING
* - VALKEYMODULE_REPLY_ERROR
*
* The return value is borrowed from CallReply, so it must not be freed
* explicitly or used after CallReply itself is freed.
@@ -308,56 +308,56 @@ int callReplyType(CallReply *rep) {
*/
const char *callReplyGetString(CallReply *rep, size_t *len) {
callReplyParse(rep);
if (rep->type != REDISMODULE_REPLY_STRING &&
rep->type != REDISMODULE_REPLY_ERROR) return NULL;
if (rep->type != VALKEYMODULE_REPLY_STRING &&
rep->type != VALKEYMODULE_REPLY_ERROR) return NULL;
if (len) *len = rep->len;
return rep->val.str;
}
/* Return a long long reply value. Applicable to:
* - REDISMODULE_REPLY_INTEGER
* - VALKEYMODULE_REPLY_INTEGER
*/
long long callReplyGetLongLong(CallReply *rep) {
callReplyParse(rep);
if (rep->type != REDISMODULE_REPLY_INTEGER) return LLONG_MIN;
if (rep->type != VALKEYMODULE_REPLY_INTEGER) return LLONG_MIN;
return rep->val.ll;
}
/* Return a double reply value. Applicable to:
* - REDISMODULE_REPLY_DOUBLE
* - VALKEYMODULE_REPLY_DOUBLE
*/
double callReplyGetDouble(CallReply *rep) {
callReplyParse(rep);
if (rep->type != REDISMODULE_REPLY_DOUBLE) return LLONG_MIN;
if (rep->type != VALKEYMODULE_REPLY_DOUBLE) return LLONG_MIN;
return rep->val.d;
}
/* Return a reply Boolean value. Applicable to:
* - REDISMODULE_REPLY_BOOL
* - VALKEYMODULE_REPLY_BOOL
*/
int callReplyGetBool(CallReply *rep) {
callReplyParse(rep);
if (rep->type != REDISMODULE_REPLY_BOOL) return INT_MIN;
if (rep->type != VALKEYMODULE_REPLY_BOOL) return INT_MIN;
return rep->val.ll;
}
/* Return reply length. Applicable to:
* - REDISMODULE_REPLY_STRING
* - REDISMODULE_REPLY_ERROR
* - REDISMODULE_REPLY_ARRAY
* - REDISMODULE_REPLY_SET
* - REDISMODULE_REPLY_MAP
* - REDISMODULE_REPLY_ATTRIBUTE
* - VALKEYMODULE_REPLY_STRING
* - VALKEYMODULE_REPLY_ERROR
* - VALKEYMODULE_REPLY_ARRAY
* - VALKEYMODULE_REPLY_SET
* - VALKEYMODULE_REPLY_MAP
* - VALKEYMODULE_REPLY_ATTRIBUTE
*/
size_t callReplyGetLen(CallReply *rep) {
callReplyParse(rep);
switch(rep->type) {
case REDISMODULE_REPLY_STRING:
case REDISMODULE_REPLY_ERROR:
case REDISMODULE_REPLY_ARRAY:
case REDISMODULE_REPLY_SET:
case REDISMODULE_REPLY_MAP:
case REDISMODULE_REPLY_ATTRIBUTE:
case VALKEYMODULE_REPLY_STRING:
case VALKEYMODULE_REPLY_ERROR:
case VALKEYMODULE_REPLY_ARRAY:
case VALKEYMODULE_REPLY_SET:
case VALKEYMODULE_REPLY_MAP:
case VALKEYMODULE_REPLY_ATTRIBUTE:
return rep->len;
default:
return 0;
@@ -370,26 +370,26 @@ static CallReply *callReplyGetCollectionElement(CallReply *rep, size_t idx, int
}
/* Return a reply array element at a given index. Applicable to:
* - REDISMODULE_REPLY_ARRAY
* - VALKEYMODULE_REPLY_ARRAY
*
* The return value is borrowed from CallReply, so it must not be freed
* explicitly or used after CallReply itself is freed.
*/
CallReply *callReplyGetArrayElement(CallReply *rep, size_t idx) {
callReplyParse(rep);
if (rep->type != REDISMODULE_REPLY_ARRAY) return NULL;
if (rep->type != VALKEYMODULE_REPLY_ARRAY) return NULL;
return callReplyGetCollectionElement(rep, idx, 1);
}
/* Return a reply set element at a given index. Applicable to:
* - REDISMODULE_REPLY_SET
* - VALKEYMODULE_REPLY_SET
*
* The return value is borrowed from CallReply, so it must not be freed
* explicitly or used after CallReply itself is freed.
*/
CallReply *callReplyGetSetElement(CallReply *rep, size_t idx) {
callReplyParse(rep);
if (rep->type != REDISMODULE_REPLY_SET) return NULL;
if (rep->type != VALKEYMODULE_REPLY_SET) return NULL;
return callReplyGetCollectionElement(rep, idx, 1);
}
@@ -403,7 +403,7 @@ static int callReplyGetMapElementInternal(CallReply *rep, size_t idx, CallReply
}
/* Retrieve a map reply key and value at a given index. Applicable to:
* - REDISMODULE_REPLY_MAP
* - VALKEYMODULE_REPLY_MAP
*
* The key and value are returned by reference through key and val,
* which may also be NULL if not needed.
@@ -415,7 +415,7 @@ static int callReplyGetMapElementInternal(CallReply *rep, size_t idx, CallReply
* explicitly or used after CallReply itself is freed.
*/
int callReplyGetMapElement(CallReply *rep, size_t idx, CallReply **key, CallReply **val) {
return callReplyGetMapElementInternal(rep, idx, key, val, REDISMODULE_REPLY_MAP);
return callReplyGetMapElementInternal(rep, idx, key, val, VALKEYMODULE_REPLY_MAP);
}
/* Return reply attribute, or NULL if it does not exist. Applicable to all replies.
@@ -428,7 +428,7 @@ CallReply *callReplyGetAttribute(CallReply *rep) {
}
/* Retrieve attribute reply key and value at a given index. Applicable to:
* - REDISMODULE_REPLY_ATTRIBUTE
* - VALKEYMODULE_REPLY_ATTRIBUTE
*
* The key and value are returned by reference through key and val,
* which may also be NULL if not needed.
@@ -440,11 +440,11 @@ CallReply *callReplyGetAttribute(CallReply *rep) {
* explicitly or used after CallReply itself is freed.
*/
int callReplyGetAttributeElement(CallReply *rep, size_t idx, CallReply **key, CallReply **val) {
return callReplyGetMapElementInternal(rep, idx, key, val, REDISMODULE_REPLY_MAP);
return callReplyGetMapElementInternal(rep, idx, key, val, VALKEYMODULE_REPLY_MAP);
}
/* Return a big number reply value. Applicable to:
* - REDISMODULE_REPLY_BIG_NUMBER
* - VALKEYMODULE_REPLY_BIG_NUMBER
*
* The returned values are borrowed from CallReply, so they must not be freed
* explicitly or used after CallReply itself is freed.
@@ -457,13 +457,13 @@ int callReplyGetAttributeElement(CallReply *rep, size_t idx, CallReply **key, Ca
*/
const char *callReplyGetBigNumber(CallReply *rep, size_t *len) {
callReplyParse(rep);
if (rep->type != REDISMODULE_REPLY_BIG_NUMBER) return NULL;
if (rep->type != VALKEYMODULE_REPLY_BIG_NUMBER) return NULL;
*len = rep->len;
return rep->val.str;
}
/* Return a verbatim string reply value. Applicable to:
* - REDISMODULE_REPLY_VERBATIM_STRING
* - VALKEYMODULE_REPLY_VERBATIM_STRING
*
* If format is non-NULL, the verbatim reply format is also returned by value.
*
@@ -478,7 +478,7 @@ const char *callReplyGetBigNumber(CallReply *rep, size_t *len) {
*/
const char *callReplyGetVerbatim(CallReply *rep, size_t *len, const char **format){
callReplyParse(rep);
if (rep->type != REDISMODULE_REPLY_VERBATIM_STRING) return NULL;
if (rep->type != VALKEYMODULE_REPLY_VERBATIM_STRING) return NULL;
*len = rep->len;
if (format) *format = rep->val.verbatim_str.format;
return rep->val.verbatim_str.str;
+1 -1
View File
@@ -33,7 +33,7 @@
#include "resp_parser.h"
typedef struct CallReply CallReply;
typedef void (*RedisModuleOnUnblocked)(void *ctx, CallReply *reply, void *private_data);
typedef void (*ValkeyModuleOnUnblocked)(void *ctx, CallReply *reply, void *private_data);
CallReply *callReplyCreate(sds reply, list *deferred_error_list, void *private_data);
CallReply *callReplyCreateError(sds reply, void *private_data);
+176 -78
View File
@@ -43,6 +43,12 @@
#include <math.h>
#include <ctype.h>
/* Only primaries that own slots have voting rights.
* Returns 1 if the node has voting rights, otherwise returns 0. */
static inline int clusterNodeIsVotingPrimary(clusterNode *n) {
return (n->flags & CLUSTER_NODE_MASTER) && n->numslots;
}
/* A global reference to myself is handy to make code more clear.
* Myself always points to server.cluster->myself, that is, the clusterNode
* that represents this node. */
@@ -119,6 +125,20 @@ static inline int defaultClientPort(void) {
return server.tls_cluster ? server.tls_port : server.port;
}
/* When a cluster command is called, we need to decide whether to return TLS info or
* non-TLS info by the client's connection type. However if the command is called by
* a Lua script or RM_call, there is no connection in the fake client, so we use
* server.current_client here to get the real client if available. And if it is not
* available (modules may call commands without a real client), we return the default
* info, which is determined by server.tls_cluster. */
static int shouldReturnTlsInfo(void) {
if (server.current_client && server.current_client->conn) {
return connIsTLS(server.current_client->conn);
} else {
return server.tls_cluster;
}
}
/* Links to the next and previous entries for keys in the same slot are stored
* in the dict entry metadata. See Slot to Key API below. */
#define dictEntryNextInSlot(de) \
@@ -938,13 +958,13 @@ static void updateAnnouncedHumanNodename(clusterNode *node, char *new) {
static void updateShardId(clusterNode *node, const char *shard_id) {
if (memcmp(node->shard_id, shard_id, CLUSTER_NAMELEN) != 0) {
if (shard_id && memcmp(node->shard_id, shard_id, CLUSTER_NAMELEN) != 0) {
clusterRemoveNodeFromShard(node);
memcpy(node->shard_id, shard_id, CLUSTER_NAMELEN);
clusterAddNodeToShard(shard_id, node);
clusterDoBeforeSleep(CLUSTER_TODO_SAVE_CONFIG);
}
if (myself != node && myself->slaveof == node) {
if (shard_id && myself != node && myself->slaveof == node) {
if (memcmp(myself->shard_id, shard_id, CLUSTER_NAMELEN) != 0) {
/* shard-id can diverge right after a rolling upgrade
* from pre-7.2 releases */
@@ -974,7 +994,7 @@ void clusterInit(void) {
server.cluster->myself = NULL;
server.cluster->currentEpoch = 0;
server.cluster->state = CLUSTER_FAIL;
server.cluster->size = 1;
server.cluster->size = 0;
server.cluster->todo_before_sleep = 0;
server.cluster->nodes = dictCreate(&clusterNodesDictType);
server.cluster->shards = dictCreate(&clusterSdsToListType);
@@ -1120,6 +1140,9 @@ void clusterReset(int hard) {
}
dictReleaseIterator(di);
/* Empty the nodes blacklist. */
dictEmpty(server.cluster->nodes_black_list, NULL);
/* Hard reset only: set epochs to 0, change node ID. */
if (hard) {
sds oldname;
@@ -1670,6 +1693,7 @@ void clusterRenameNode(clusterNode *node, char *newname) {
serverAssert(retval == DICT_OK);
memcpy(node->name, newname, CLUSTER_NAMELEN);
clusterAddNode(node);
clusterAddNodeToShard(node->shard_id, node);
}
void clusterAddNodeToShard(const char *shard_id, clusterNode *node) {
@@ -1943,8 +1967,8 @@ void markNodeAsFailingIfNeeded(clusterNode *node) {
if (nodeFailed(node)) return; /* Already FAILing. */
failures = clusterNodeFailureReportsCount(node);
/* Also count myself as a voter if I'm a master. */
if (nodeIsMaster(myself)) failures++;
/* Also count myself as a voter if I'm a voting primary. */
if (clusterNodeIsVotingPrimary(myself)) failures++;
if (failures < needed_quorum) return; /* No weak agreement from masters. */
serverLog(LL_NOTICE,
@@ -1987,7 +2011,7 @@ void clearNodeFailureIfNeeded(clusterNode *node) {
* 1) The FAIL state is old enough.
* 2) It is yet serving slots from our point of view (not failed over).
* Apparently no one is going to fix these slots, clear the FAIL flag. */
if (nodeIsMaster(node) && node->numslots > 0 &&
if (clusterNodeIsVotingPrimary(node) &&
(now - node->fail_time) >
(server.cluster_node_timeout * CLUSTER_FAIL_UNDO_TIME_MULT))
{
@@ -2136,8 +2160,8 @@ void clusterProcessGossipSection(clusterMsg *hdr, clusterLink *link) {
node = clusterLookupNode(g->nodename, CLUSTER_NAMELEN);
if (node) {
/* We already know this node.
Handle failure reports, only when the sender is a master. */
if (sender && nodeIsMaster(sender) && node != myself) {
Handle failure reports, only when the sender is a voting primary. */
if (sender && clusterNodeIsVotingPrimary(sender) && node != myself) {
if (flags & (CLUSTER_NODE_FAIL|CLUSTER_NODE_PFAIL)) {
if (clusterNodeAddFailureReport(node,sender)) {
serverLog(LL_VERBOSE,
@@ -2195,6 +2219,23 @@ void clusterProcessGossipSection(clusterMsg *hdr, clusterLink *link) {
node->tls_port = msg_tls_port;
node->cport = ntohs(g->cport);
node->flags &= ~CLUSTER_NODE_NOADDR;
serverLog(LL_NOTICE,"Address updated for node %.40s (%s), now %s:%d",
node->name, node->human_nodename, node->ip, getNodeDefaultClientPort(node));
/* Check if this is our primary and we have to change the
* replication target as well.
*
* This is needed in case the check in nodeUpdateAddressIfNeeded
* failed due to a race condition. For example, if the replica just
* received a packet from another node that contains new address
* about the primary, we will update primary node address in here,
* when the replica receive the packet from the primary, the check
* in nodeUpdateAddressIfNeeded will fail since the address has been
* updated correctly, and we will not have the opportunity to call
* replicationSetPrimary and update the primary host. */
if (nodeIsSlave(myself) && myself->slaveof == node)
replicationSetMaster(node->ip, getNodeDefaultReplicationPort(node));
}
} else {
/* If it's not in NOADDR state and we don't have it, we
@@ -2217,6 +2258,7 @@ void clusterProcessGossipSection(clusterMsg *hdr, clusterLink *link) {
node->tls_port = msg_tls_port;
node->cport = ntohs(g->cport);
clusterAddNode(node);
clusterAddNodeToShard(node->shard_id, node);
}
}
@@ -2394,7 +2436,6 @@ void clusterUpdateSlotsConfigWith(clusterNode *sender, uint64_t senderConfigEpoc
}
clusterDelSlot(j);
clusterAddSlot(sender,j);
bitmapClearBit(server.cluster->owner_not_claiming_slot, j);
clusterDoBeforeSleep(CLUSTER_TODO_SAVE_CONFIG|
CLUSTER_TODO_UPDATE_STATE|
CLUSTER_TODO_FSYNC_CONFIG);
@@ -2567,7 +2608,7 @@ uint32_t writePingExt(clusterMsg *hdr, int gossipcount) {
clusterMsgPingExtHumanNodename *ext = preparePingExt(cursor, CLUSTERMSG_EXT_TYPE_HUMAN_NODENAME, getHumanNodenamePingExtSize());
memcpy(ext->human_nodename, myself->human_nodename, sdslen(myself->human_nodename));
/* Move the write cursor */
/* Move the write cursor */
cursor = nextPingExt(cursor);
}
@@ -2609,9 +2650,7 @@ uint32_t writePingExt(clusterMsg *hdr, int gossipcount) {
extensions++;
if (hdr != NULL) {
if (extensions != 0) {
hdr->mflags[0] |= CLUSTERMSG_FLAG0_EXT_DATA;
}
hdr->mflags[0] |= CLUSTERMSG_FLAG0_EXT_DATA;
hdr->extensions = htons(extensions);
}
@@ -2633,7 +2672,7 @@ void clusterProcessPingExtensions(clusterMsg *hdr, clusterLink *link) {
if (type == CLUSTERMSG_EXT_TYPE_HOSTNAME) {
clusterMsgPingExtHostname *hostname_ext = (clusterMsgPingExtHostname *) &(ext->ext[0].hostname);
ext_hostname = hostname_ext->hostname;
} else if (type == CLUSTERMSG_EXT_TYPE_HUMAN_NODENAME) {
} else if (type == CLUSTERMSG_EXT_TYPE_HUMAN_NODENAME) {
clusterMsgPingExtHumanNodename *humannodename_ext = (clusterMsgPingExtHumanNodename *) &(ext->ext[0].human_nodename);
ext_humannodename = humannodename_ext->human_nodename;
} else if (type == CLUSTERMSG_EXT_TYPE_FORGOTTEN_NODE) {
@@ -2641,8 +2680,11 @@ void clusterProcessPingExtensions(clusterMsg *hdr, clusterLink *link) {
clusterNode *n = clusterLookupNode(forgotten_node_ext->name, CLUSTER_NAMELEN);
if (n && n != myself && !(nodeIsSlave(myself) && myself->slaveof == n)) {
sds id = sdsnewlen(forgotten_node_ext->name, CLUSTER_NAMELEN);
dictEntry *de = dictAddRaw(server.cluster->nodes_black_list, id, NULL);
serverAssert(de != NULL);
dictEntry *de = dictAddOrFind(server.cluster->nodes_black_list, id);
if (dictGetKey(de) != id) {
/* The dict did not take ownership of the id string, so we need to free it. */
sdsfree(id);
}
uint64_t expire = server.unixtime + ntohu64(forgotten_node_ext->ttl);
dictSetUnsignedIntegerVal(de, expire);
clusterDelNode(n);
@@ -2660,11 +2702,24 @@ void clusterProcessPingExtensions(clusterMsg *hdr, clusterLink *link) {
/* We know this will be valid since we validated it ahead of time */
ext = getNextPingExt(ext);
}
/* If the node did not send us a hostname extension, assume
* they don't have an announced hostname. Otherwise, we'll
* set it now. */
updateAnnouncedHostname(sender, ext_hostname);
updateAnnouncedHumanNodename(sender, ext_humannodename);
/* If the node did not send us a shard-id extension, it means the sender
* does not support it (old version), node->shard_id is randomly generated.
* A cluster-wide consensus for the node's shard_id is not necessary.
* The key is maintaining consistency of the shard_id on each individual 7.2 node.
* As the cluster progressively upgrades to version 7.2, we can expect the shard_ids
* across all nodes to naturally converge and align.
*
* If sender is a replica, set the shard_id to the shard_id of its master.
* Otherwise, we'll set it now. */
if (ext_shardid == NULL) ext_shardid = clusterNodeGetMaster(sender)->shard_id;
updateShardId(sender, ext_shardid);
}
@@ -2719,6 +2774,11 @@ int clusterProcessPacket(clusterLink *link) {
if (type == server.cluster_drop_packet_filter) {
serverLog(LL_WARNING, "Dropping packet that matches debug drop filter");
if (server.debug_cluster_close_link_on_packet_drop) {
freeClusterLink(link);
serverLog(LL_WARNING, "Closing link for matching packet type %hu", type);
return 0;
}
return 1;
}
@@ -2791,6 +2851,10 @@ int clusterProcessPacket(clusterLink *link) {
sender = getNodeFromLinkAndMsg(link, hdr);
if (sender && (hdr->mflags[0] & CLUSTERMSG_FLAG0_EXT_DATA)) {
sender->flags |= CLUSTER_NODE_EXTENSIONS_SUPPORTED;
}
/* Update the last time we saw any data from this node. We
* use this in order to avoid detecting a timeout from a node that
* is just sending a lot of data in the cluster bus, for instance
@@ -2889,6 +2953,14 @@ int clusterProcessPacket(clusterLink *link) {
serverLog(LL_DEBUG,"%s packet received: %.40s",
clusterGetMessageTypeString(type),
link->node ? link->node->name : "NULL");
if (sender && (sender->flags & CLUSTER_NODE_MEET)) {
/* Once we get a response for MEET from the sender, we can stop sending more MEET. */
sender->flags &= ~CLUSTER_NODE_MEET;
serverLog(LL_NOTICE, "Successfully completed handshake with %.40s (%s)", sender->name,
sender->human_nodename);
}
if (!link->inbound) {
if (nodeInHandshake(link->node)) {
/* If we already have this node, try to change the
@@ -3008,6 +3080,10 @@ int clusterProcessPacket(clusterLink *link) {
clusterNodeAddSlave(master,sender);
sender->slaveof = master;
/* Update the shard_id when a replica is connected to its
* primary in the very first time. */
updateShardId(sender, master->shard_id);
/* Update config. */
clusterDoBeforeSleep(CLUSTER_TODO_SAVE_CONFIG);
}
@@ -3149,10 +3225,10 @@ int clusterProcessPacket(clusterLink *link) {
clusterSendFailoverAuthIfNeeded(sender,hdr);
} else if (type == CLUSTERMSG_TYPE_FAILOVER_AUTH_ACK) {
if (!sender) return 1; /* We don't know that node. */
/* We consider this vote only if the sender is a master serving
/* We consider this vote only if the sender is a primary serving
* a non zero number of slots, and its currentEpoch is greater or
* equal to epoch where this node started the election. */
if (nodeIsMaster(sender) && sender->numslots > 0 &&
if (clusterNodeIsVotingPrimary(sender) &&
senderCurrentEpoch >= server.cluster->failover_auth_epoch)
{
server.cluster->failover_auth_count++;
@@ -3303,12 +3379,18 @@ void clusterLinkConnectHandler(connection *conn) {
* replaced by the clusterSendPing() call. */
node->ping_sent = old_ping_sent;
}
/* We can clear the flag after the first packet is sent.
* If we'll never receive a PONG, we'll never send new packets
* to this node. Instead after the PONG is received and we
* are no longer in meet/handshake status, we want to send
* normal PING packets. */
node->flags &= ~CLUSTER_NODE_MEET;
/* NOTE: Assume the current node is A and is asked to MEET another node B.
* Once A sends MEET to B, it cannot clear the MEET flag for B until it
* gets a response from B. If the MEET packet is not accepted by B due to
* link failure, A must continue sending MEET. If A doesn't continue sending
* MEET, A will know about B, but B will never add A. Every node always
* responds to PINGs from unknown nodes with a PONG, so A will know about B
* and continue sending PINGs. But B won't add A until it sees a MEET (or it
* gets to know about A from a trusted third node C). In this case, clearing
* the MEET flag here leads to asymmetry in the cluster membership. So, we
* clear the MEET flag in clusterProcessPacket.
*/
serverLog(LL_DEBUG,"Connecting with Node %.40s at %s:%d",
node->name, node->ip, node->cport);
@@ -3587,7 +3669,9 @@ void clusterSendPing(clusterLink *link, int type) {
* to put inside the packet. */
estlen = sizeof(clusterMsg) - sizeof(union clusterMsgData);
estlen += (sizeof(clusterMsgDataGossip)*(wanted + pfail_wanted));
estlen += writePingExt(NULL, 0);
if (link->node && nodeSupportsExtensions(link->node)) {
estlen += writePingExt(NULL, 0);
}
/* Note: clusterBuildMessageHdr() expects the buffer to be always at least
* sizeof(clusterMsg) or more. */
if (estlen < (int)sizeof(clusterMsg)) estlen = sizeof(clusterMsg);
@@ -3655,7 +3739,13 @@ void clusterSendPing(clusterLink *link, int type) {
/* Compute the actual total length and send! */
uint32_t totlen = 0;
totlen += writePingExt(hdr, gossipcount);
if (link->node && nodeSupportsExtensions(link->node)) {
totlen += writePingExt(hdr, gossipcount);
} else {
serverLog(LL_DEBUG, "Unable to send extensions data, however setting ext data flag to true");
hdr->mflags[0] |= CLUSTERMSG_FLAG0_EXT_DATA;
}
totlen += sizeof(clusterMsg)-sizeof(union clusterMsgData);
totlen += (sizeof(clusterMsgDataGossip)*gossipcount);
serverAssert(gossipcount < USHRT_MAX);
@@ -4234,7 +4324,7 @@ void clusterHandleSlaveFailover(void) {
if (server.cluster->mf_end) {
server.cluster->failover_auth_time = mstime();
server.cluster->failover_auth_rank = 0;
clusterDoBeforeSleep(CLUSTER_TODO_HANDLE_FAILOVER);
clusterDoBeforeSleep(CLUSTER_TODO_HANDLE_FAILOVER);
}
serverLog(LL_NOTICE,
"Start of election delayed for %lld milliseconds "
@@ -4737,11 +4827,14 @@ void clusterCron(void) {
/* Timeout reached. Set the node as possibly failing if it is
* not already in this state. */
if (!(node->flags & (CLUSTER_NODE_PFAIL|CLUSTER_NODE_FAIL))) {
serverLog(LL_DEBUG,"*** NODE %.40s possibly failing",
node->name);
node->flags |= CLUSTER_NODE_PFAIL;
update_state = 1;
}
if (clusterNodeIsVotingPrimary(myself) && server.cluster->size == 1) {
markNodeAsFailingIfNeeded(node);
} else {
serverLog(LL_DEBUG,"*** NODE %.40s possibly failing", node->name);
}
}
}
dictReleaseIterator(di);
@@ -4770,7 +4863,7 @@ void clusterCron(void) {
* a migration if there is no master with at least *two* working
* slaves. */
if (orphaned_masters && max_slaves >= 2 && this_slaves == max_slaves &&
server.cluster_allow_replica_migration)
server.cluster_allow_replica_migration)
clusterHandleSlaveMigration(max_slaves);
}
@@ -4922,14 +5015,12 @@ int clusterDelSlot(int slot) {
if (!n) return C_ERR;
/* Cleanup the channels in master/replica as part of slot deletion. */
list *nodes_for_slot = clusterGetNodesInMyShard(n);
serverAssert(nodes_for_slot != NULL);
listNode *ln = listSearchKey(nodes_for_slot, myself);
if (ln != NULL) {
removeChannelsInSlot(slot);
}
removeChannelsInSlot(slot);
/* Clear the slot bit. */
serverAssert(clusterNodeClearSlotBit(n,slot) == 1);
server.cluster->slots[slot] = NULL;
/* Make owner_not_claiming_slot flag consistent with slot ownership information. */
bitmapClearBit(server.cluster->owner_not_claiming_slot, slot);
return C_OK;
}
@@ -5017,7 +5108,7 @@ void clusterUpdateState(void) {
while((de = dictNext(di)) != NULL) {
clusterNode *node = dictGetVal(de);
if (nodeIsMaster(node) && node->numslots) {
if (clusterNodeIsVotingPrimary(node)) {
server.cluster->size++;
if ((node->flags & (CLUSTER_NODE_FAIL|CLUSTER_NODE_PFAIL)) == 0)
reachable_masters++;
@@ -5570,7 +5661,7 @@ void addNodeToNodeReply(client *c, clusterNode *node) {
}
/* Report TLS ports to TLS client, and report non-TLS port to non-TLS client. */
addReplyLongLong(c, getNodeClientPort(node, connIsTLS(c->conn)));
addReplyLongLong(c, getNodeClientPort(node, shouldReturnTlsInfo()));
addReplyBulkCBuffer(c, node->name, CLUSTER_NAMELEN);
/* Add the additional endpoint information, this is all the known networking information
@@ -5689,37 +5780,6 @@ void addNodeDetailsToShardReply(client *c, clusterNode *node) {
setDeferredMapLen(c, node_replylen, reply_count);
}
/* Add the shard reply of a single shard based off the given primary node. */
void addShardReplyForClusterShards(client *c, list *nodes) {
serverAssert(listLength(nodes) > 0);
clusterNode *n = listNodeValue(listFirst(nodes));
addReplyMapLen(c, 2);
addReplyBulkCString(c, "slots");
/* Use slot_info_pairs from the primary only */
while (n->slaveof != NULL) n = n->slaveof;
if (n->slot_info_pairs != NULL) {
serverAssert((n->slot_info_pairs_count % 2) == 0);
addReplyArrayLen(c, n->slot_info_pairs_count);
for (int i = 0; i < n->slot_info_pairs_count; i++)
addReplyBulkLongLong(c, (unsigned long)n->slot_info_pairs[i]);
} else {
/* If no slot info pair is provided, the node owns no slots */
addReplyArrayLen(c, 0);
}
addReplyBulkCString(c, "nodes");
addReplyArrayLen(c, listLength(nodes));
listIter li;
listRewind(nodes, &li);
for (listNode *ln = listNext(&li); ln != NULL; ln = listNext(&li)) {
clusterNode *n = listNodeValue(ln);
addNodeDetailsToShardReply(c, n);
clusterFreeNodesSlotsInfo(n);
}
}
/* Add to the output buffer of the given client, an array of slot (start, end)
* pair owned by the shard, also the primary and set of replica(s) along with
* information about each node. */
@@ -5729,7 +5789,41 @@ void clusterReplyShards(client *c) {
clusterGenNodesSlotsInfo(0);
dictIterator *di = dictGetSafeIterator(server.cluster->shards);
for(dictEntry *de = dictNext(di); de != NULL; de = dictNext(di)) {
addShardReplyForClusterShards(c, dictGetVal(de));
list *nodes = dictGetVal(de);
serverAssert(listLength(nodes) > 0);
addReplyMapLen(c, 2);
addReplyBulkCString(c, "slots");
/* Find a node which has the slot information served by this shard. */
clusterNode *n = NULL;
listIter li;
listRewind(nodes, &li);
for (listNode *ln = listNext(&li); ln != NULL; ln = listNext(&li)) {
n = listNodeValue(ln);
if (n->slot_info_pairs) {
break;
}
}
if (n && n->slot_info_pairs != NULL) {
serverAssert((n->slot_info_pairs_count % 2) == 0);
addReplyArrayLen(c, n->slot_info_pairs_count);
for (int i = 0; i < n->slot_info_pairs_count; i++) {
addReplyLongLong(c, (unsigned long)n->slot_info_pairs[i]);
}
} else {
/* If no slot info pair is provided, the node owns no slots */
addReplyArrayLen(c, 0);
}
addReplyBulkCString(c, "nodes");
addReplyArrayLen(c, listLength(nodes));
listRewind(nodes, &li);
for (listNode *ln = listNext(&li); ln != NULL; ln = listNext(&li)) {
clusterNode *n = listNodeValue(ln);
addNodeDetailsToShardReply(c, n);
clusterFreeNodesSlotsInfo(n);
}
}
dictReleaseIterator(di);
}
@@ -5946,7 +6040,7 @@ NULL
} else if (!strcasecmp(c->argv[1]->ptr,"nodes") && c->argc == 2) {
/* CLUSTER NODES */
/* Report TLS ports to TLS client, and report non-TLS port to non-TLS client. */
sds nodes = clusterGenNodesDescription(c, 0, connIsTLS(c->conn));
sds nodes = clusterGenNodesDescription(c, 0, shouldReturnTlsInfo());
addReplyVerbatim(c,nodes,sdslen(nodes),"txt");
sdsfree(nodes);
} else if (!strcasecmp(c->argv[1]->ptr,"myid") && c->argc == 2) {
@@ -6312,7 +6406,7 @@ NULL
/* Report TLS ports to TLS client, and report non-TLS port to non-TLS client. */
addReplyArrayLen(c,n->numslaves);
for (j = 0; j < n->numslaves; j++) {
sds ni = clusterGenNodeDescription(c, n->slaves[j], connIsTLS(c->conn));
sds ni = clusterGenNodeDescription(c, n->slaves[j], shouldReturnTlsInfo());
addReplyBulkCString(c,ni);
sdsfree(ni);
}
@@ -7438,7 +7532,7 @@ void clusterRedirectClient(client *c, clusterNode *n, int hashslot, int error_co
error_code == CLUSTER_REDIR_ASK)
{
/* Report TLS ports to TLS client, and report non-TLS port to non-TLS client. */
int port = getNodeClientPort(n, connIsTLS(c->conn));
int port = getNodeClientPort(n, shouldReturnTlsInfo());
addReplyErrorSds(c,sdscatprintf(sdsempty(),
"-%s %d %s:%d",
(error_code == CLUSTER_REDIR_ASK) ? "ASK" : "MOVED",
@@ -7469,6 +7563,10 @@ int clusterRedirectBlockedClientIfNeeded(client *c) {
dictEntry *de;
dictIterator *di;
/* If the client is blocked on module, but not on a specific key,
* don't unblock it. */
if (c->bstate.btype == BLOCKED_MODULE && !moduleClientIsBlockedOnKeys(c)) return 0;
/* If the cluster is down, unblock the client with the right error.
* If the cluster is configured to allow reads on cluster down, we
* still want to emit this error since a write will be required
@@ -7478,11 +7576,6 @@ int clusterRedirectBlockedClientIfNeeded(client *c) {
return 1;
}
/* If the client is blocked on module, but not on a specific key,
* don't unblock it (except for the CLUSTER_FAIL case above). */
if (c->bstate.btype == BLOCKED_MODULE && !moduleClientIsBlockedOnKeys(c))
return 0;
/* All keys must belong to the same slot, so check first key only. */
di = dictGetIterator(c->bstate.keys);
if ((de = dictNext(di)) != NULL) {
@@ -7631,6 +7724,11 @@ unsigned int countKeysInSlot(unsigned int hashslot) {
return (*server.db->slots_to_keys).by_slot[hashslot].count;
}
clusterNode *clusterNodeGetMaster(clusterNode *node) {
while (node->slaveof != NULL) node = node->slaveof;
return node;
}
/* -----------------------------------------------------------------------------
* Operation(s) on channel rax tree.
* -------------------------------------------------------------------------- */
+3
View File
@@ -56,6 +56,7 @@ typedef struct clusterLink {
#define CLUSTER_NODE_MEET 128 /* Send a MEET message to this node */
#define CLUSTER_NODE_MIGRATE_TO 256 /* Master eligible for replica migration. */
#define CLUSTER_NODE_NOFAILOVER 512 /* Slave will not try to failover. */
#define CLUSTER_NODE_EXTENSIONS_SUPPORTED 1024 /* This node supports extensions. */
#define CLUSTER_NODE_NULL_NAME "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
#define nodeIsMaster(n) ((n)->flags & CLUSTER_NODE_MASTER)
@@ -66,6 +67,7 @@ typedef struct clusterLink {
#define nodeTimedOut(n) ((n)->flags & CLUSTER_NODE_PFAIL)
#define nodeFailed(n) ((n)->flags & CLUSTER_NODE_FAIL)
#define nodeCantFailover(n) ((n)->flags & CLUSTER_NODE_NOFAILOVER)
#define nodeSupportsExtensions(n) ((n)->flags & CLUSTER_NODE_EXTENSIONS_SUPPORTED)
/* Reasons why a slave is not able to failover. */
#define CLUSTER_CANT_FAILOVER_NONE 0
@@ -413,6 +415,7 @@ void clusterInit(void);
void clusterInitListeners(void);
void clusterCron(void);
void clusterBeforeSleep(void);
clusterNode *clusterNodeGetMaster(clusterNode *node);
clusterNode *getNodeByQuery(client *c, struct redisCommand *cmd, robj **argv, int argc, int *hashslot, int *ask);
int verifyClusterNodeId(const char *name, int length);
clusterNode *clusterLookupNode(const char *name, int length);
+76 -21
View File
@@ -1391,7 +1391,10 @@ struct COMMAND_ARG CLIENT_REPLY_Args[] = {
#ifndef SKIP_CMD_TIPS_TABLE
/* CLIENT SETINFO tips */
#define CLIENT_SETINFO_Tips NULL
const char *CLIENT_SETINFO_Tips[] = {
"request_policy:all_nodes",
"response_policy:all_succeeded",
};
#endif
#ifndef SKIP_CMD_KEY_SPECS_TABLE
@@ -1419,7 +1422,10 @@ struct COMMAND_ARG CLIENT_SETINFO_Args[] = {
#ifndef SKIP_CMD_TIPS_TABLE
/* CLIENT SETNAME tips */
#define CLIENT_SETNAME_Tips NULL
const char *CLIENT_SETNAME_Tips[] = {
"request_policy:all_nodes",
"response_policy:all_succeeded",
};
#endif
#ifndef SKIP_CMD_KEY_SPECS_TABLE
@@ -1543,8 +1549,8 @@ struct COMMAND_STRUCT CLIENT_Subcommands[] = {
{MAKE_CMD("no-touch","Controls whether commands sent by the client affect the LRU/LFU of accessed keys.","O(1)","7.2.0",CMD_DOC_NONE,NULL,NULL,"connection",COMMAND_GROUP_CONNECTION,CLIENT_NO_TOUCH_History,0,CLIENT_NO_TOUCH_Tips,0,clientCommand,3,CMD_NOSCRIPT|CMD_LOADING|CMD_STALE,ACL_CATEGORY_CONNECTION,CLIENT_NO_TOUCH_Keyspecs,0,NULL,1),.args=CLIENT_NO_TOUCH_Args},
{MAKE_CMD("pause","Suspends commands processing.","O(1)","3.0.0",CMD_DOC_NONE,NULL,NULL,"connection",COMMAND_GROUP_CONNECTION,CLIENT_PAUSE_History,1,CLIENT_PAUSE_Tips,0,clientCommand,-3,CMD_ADMIN|CMD_NOSCRIPT|CMD_LOADING|CMD_STALE|CMD_SENTINEL,ACL_CATEGORY_CONNECTION,CLIENT_PAUSE_Keyspecs,0,NULL,2),.args=CLIENT_PAUSE_Args},
{MAKE_CMD("reply","Instructs the server whether to reply to commands.","O(1)","3.2.0",CMD_DOC_NONE,NULL,NULL,"connection",COMMAND_GROUP_CONNECTION,CLIENT_REPLY_History,0,CLIENT_REPLY_Tips,0,clientCommand,3,CMD_NOSCRIPT|CMD_LOADING|CMD_STALE|CMD_SENTINEL,ACL_CATEGORY_CONNECTION,CLIENT_REPLY_Keyspecs,0,NULL,1),.args=CLIENT_REPLY_Args},
{MAKE_CMD("setinfo","Sets information specific to the client or connection.","O(1)","7.2.0",CMD_DOC_NONE,NULL,NULL,"connection",COMMAND_GROUP_CONNECTION,CLIENT_SETINFO_History,0,CLIENT_SETINFO_Tips,0,clientSetinfoCommand,4,CMD_NOSCRIPT|CMD_LOADING|CMD_STALE|CMD_SENTINEL,ACL_CATEGORY_CONNECTION,CLIENT_SETINFO_Keyspecs,0,NULL,1),.args=CLIENT_SETINFO_Args},
{MAKE_CMD("setname","Sets the connection name.","O(1)","2.6.9",CMD_DOC_NONE,NULL,NULL,"connection",COMMAND_GROUP_CONNECTION,CLIENT_SETNAME_History,0,CLIENT_SETNAME_Tips,0,clientCommand,3,CMD_NOSCRIPT|CMD_LOADING|CMD_STALE|CMD_SENTINEL,ACL_CATEGORY_CONNECTION,CLIENT_SETNAME_Keyspecs,0,NULL,1),.args=CLIENT_SETNAME_Args},
{MAKE_CMD("setinfo","Sets information specific to the client or connection.","O(1)","7.2.0",CMD_DOC_NONE,NULL,NULL,"connection",COMMAND_GROUP_CONNECTION,CLIENT_SETINFO_History,0,CLIENT_SETINFO_Tips,2,clientSetinfoCommand,4,CMD_NOSCRIPT|CMD_LOADING|CMD_STALE|CMD_SENTINEL,ACL_CATEGORY_CONNECTION,CLIENT_SETINFO_Keyspecs,0,NULL,1),.args=CLIENT_SETINFO_Args},
{MAKE_CMD("setname","Sets the connection name.","O(1)","2.6.9",CMD_DOC_NONE,NULL,NULL,"connection",COMMAND_GROUP_CONNECTION,CLIENT_SETNAME_History,0,CLIENT_SETNAME_Tips,2,clientCommand,3,CMD_NOSCRIPT|CMD_LOADING|CMD_STALE|CMD_SENTINEL,ACL_CATEGORY_CONNECTION,CLIENT_SETNAME_Keyspecs,0,NULL,1),.args=CLIENT_SETNAME_Args},
{MAKE_CMD("tracking","Controls server-assisted client-side caching for the connection.","O(1). Some options may introduce additional complexity.","6.0.0",CMD_DOC_NONE,NULL,NULL,"connection",COMMAND_GROUP_CONNECTION,CLIENT_TRACKING_History,0,CLIENT_TRACKING_Tips,0,clientCommand,-3,CMD_NOSCRIPT|CMD_LOADING|CMD_STALE|CMD_SENTINEL,ACL_CATEGORY_CONNECTION,CLIENT_TRACKING_Keyspecs,0,NULL,7),.args=CLIENT_TRACKING_Args},
{MAKE_CMD("trackinginfo","Returns information about server-assisted client-side caching for the connection.","O(1)","6.2.0",CMD_DOC_NONE,NULL,NULL,"connection",COMMAND_GROUP_CONNECTION,CLIENT_TRACKINGINFO_History,0,CLIENT_TRACKINGINFO_Tips,0,clientCommand,2,CMD_NOSCRIPT|CMD_LOADING|CMD_STALE|CMD_SENTINEL,ACL_CATEGORY_CONNECTION,CLIENT_TRACKINGINFO_Keyspecs,0,NULL,0)},
{MAKE_CMD("unblock","Unblocks a client blocked by a blocking command from a different connection.","O(log N) where N is the number of client connections","5.0.0",CMD_DOC_NONE,NULL,NULL,"connection",COMMAND_GROUP_CONNECTION,CLIENT_UNBLOCK_History,0,CLIENT_UNBLOCK_Tips,0,clientCommand,-3,CMD_ADMIN|CMD_NOSCRIPT|CMD_LOADING|CMD_STALE|CMD_SENTINEL,ACL_CATEGORY_CONNECTION,CLIENT_UNBLOCK_Keyspecs,0,NULL,2),.args=CLIENT_UNBLOCK_Args},
@@ -5886,7 +5892,10 @@ struct COMMAND_ARG ACL_CAT_Args[] = {
#ifndef SKIP_CMD_TIPS_TABLE
/* ACL DELUSER tips */
#define ACL_DELUSER_Tips NULL
const char *ACL_DELUSER_Tips[] = {
"request_policy:all_nodes",
"response_policy:all_succeeded",
};
#endif
#ifndef SKIP_CMD_KEY_SPECS_TABLE
@@ -6060,7 +6069,10 @@ struct COMMAND_ARG ACL_LOG_Args[] = {
#ifndef SKIP_CMD_TIPS_TABLE
/* ACL SAVE tips */
#define ACL_SAVE_Tips NULL
const char *ACL_SAVE_Tips[] = {
"request_policy:all_nodes",
"response_policy:all_succeeded",
};
#endif
#ifndef SKIP_CMD_KEY_SPECS_TABLE
@@ -6080,7 +6092,10 @@ commandHistory ACL_SETUSER_History[] = {
#ifndef SKIP_CMD_TIPS_TABLE
/* ACL SETUSER tips */
#define ACL_SETUSER_Tips NULL
const char *ACL_SETUSER_Tips[] = {
"request_policy:all_nodes",
"response_policy:all_succeeded",
};
#endif
#ifndef SKIP_CMD_KEY_SPECS_TABLE
@@ -6131,7 +6146,7 @@ struct COMMAND_ARG ACL_SETUSER_Args[] = {
/* ACL command table */
struct COMMAND_STRUCT ACL_Subcommands[] = {
{MAKE_CMD("cat","Lists the ACL categories, or the commands inside a category.","O(1) since the categories and commands are a fixed set.","6.0.0",CMD_DOC_NONE,NULL,NULL,"server",COMMAND_GROUP_SERVER,ACL_CAT_History,0,ACL_CAT_Tips,0,aclCommand,-2,CMD_NOSCRIPT|CMD_LOADING|CMD_STALE|CMD_SENTINEL,0,ACL_CAT_Keyspecs,0,NULL,1),.args=ACL_CAT_Args},
{MAKE_CMD("deluser","Deletes ACL users, and terminates their connections.","O(1) amortized time considering the typical user.","6.0.0",CMD_DOC_NONE,NULL,NULL,"server",COMMAND_GROUP_SERVER,ACL_DELUSER_History,0,ACL_DELUSER_Tips,0,aclCommand,-3,CMD_ADMIN|CMD_NOSCRIPT|CMD_LOADING|CMD_STALE|CMD_SENTINEL,0,ACL_DELUSER_Keyspecs,0,NULL,1),.args=ACL_DELUSER_Args},
{MAKE_CMD("deluser","Deletes ACL users, and terminates their connections.","O(1) amortized time considering the typical user.","6.0.0",CMD_DOC_NONE,NULL,NULL,"server",COMMAND_GROUP_SERVER,ACL_DELUSER_History,0,ACL_DELUSER_Tips,2,aclCommand,-3,CMD_ADMIN|CMD_NOSCRIPT|CMD_LOADING|CMD_STALE|CMD_SENTINEL,0,ACL_DELUSER_Keyspecs,0,NULL,1),.args=ACL_DELUSER_Args},
{MAKE_CMD("dryrun","Simulates the execution of a command by a user, without executing the command.","O(1).","7.0.0",CMD_DOC_NONE,NULL,NULL,"server",COMMAND_GROUP_SERVER,ACL_DRYRUN_History,0,ACL_DRYRUN_Tips,0,aclCommand,-4,CMD_ADMIN|CMD_NOSCRIPT|CMD_LOADING|CMD_STALE|CMD_SENTINEL,0,ACL_DRYRUN_Keyspecs,0,NULL,3),.args=ACL_DRYRUN_Args},
{MAKE_CMD("genpass","Generates a pseudorandom, secure password that can be used to identify ACL users.","O(1)","6.0.0",CMD_DOC_NONE,NULL,NULL,"server",COMMAND_GROUP_SERVER,ACL_GENPASS_History,0,ACL_GENPASS_Tips,0,aclCommand,-2,CMD_NOSCRIPT|CMD_LOADING|CMD_STALE|CMD_SENTINEL,0,ACL_GENPASS_Keyspecs,0,NULL,1),.args=ACL_GENPASS_Args},
{MAKE_CMD("getuser","Lists the ACL rules of a user.","O(N). Where N is the number of password, command and pattern rules that the user has.","6.0.0",CMD_DOC_NONE,NULL,NULL,"server",COMMAND_GROUP_SERVER,ACL_GETUSER_History,2,ACL_GETUSER_Tips,0,aclCommand,3,CMD_ADMIN|CMD_NOSCRIPT|CMD_LOADING|CMD_STALE|CMD_SENTINEL,0,ACL_GETUSER_Keyspecs,0,NULL,1),.args=ACL_GETUSER_Args},
@@ -6139,8 +6154,8 @@ struct COMMAND_STRUCT ACL_Subcommands[] = {
{MAKE_CMD("list","Dumps the effective rules in ACL file format.","O(N). Where N is the number of configured users.","6.0.0",CMD_DOC_NONE,NULL,NULL,"server",COMMAND_GROUP_SERVER,ACL_LIST_History,0,ACL_LIST_Tips,0,aclCommand,2,CMD_ADMIN|CMD_NOSCRIPT|CMD_LOADING|CMD_STALE|CMD_SENTINEL,0,ACL_LIST_Keyspecs,0,NULL,0)},
{MAKE_CMD("load","Reloads the rules from the configured ACL file.","O(N). Where N is the number of configured users.","6.0.0",CMD_DOC_NONE,NULL,NULL,"server",COMMAND_GROUP_SERVER,ACL_LOAD_History,0,ACL_LOAD_Tips,0,aclCommand,2,CMD_ADMIN|CMD_NOSCRIPT|CMD_LOADING|CMD_STALE|CMD_SENTINEL,0,ACL_LOAD_Keyspecs,0,NULL,0)},
{MAKE_CMD("log","Lists recent security events generated due to ACL rules.","O(N) with N being the number of entries shown.","6.0.0",CMD_DOC_NONE,NULL,NULL,"server",COMMAND_GROUP_SERVER,ACL_LOG_History,1,ACL_LOG_Tips,0,aclCommand,-2,CMD_ADMIN|CMD_NOSCRIPT|CMD_LOADING|CMD_STALE|CMD_SENTINEL,0,ACL_LOG_Keyspecs,0,NULL,1),.args=ACL_LOG_Args},
{MAKE_CMD("save","Saves the effective ACL rules in the configured ACL file.","O(N). Where N is the number of configured users.","6.0.0",CMD_DOC_NONE,NULL,NULL,"server",COMMAND_GROUP_SERVER,ACL_SAVE_History,0,ACL_SAVE_Tips,0,aclCommand,2,CMD_ADMIN|CMD_NOSCRIPT|CMD_LOADING|CMD_STALE|CMD_SENTINEL,0,ACL_SAVE_Keyspecs,0,NULL,0)},
{MAKE_CMD("setuser","Creates and modifies an ACL user and its rules.","O(N). Where N is the number of rules provided.","6.0.0",CMD_DOC_NONE,NULL,NULL,"server",COMMAND_GROUP_SERVER,ACL_SETUSER_History,2,ACL_SETUSER_Tips,0,aclCommand,-3,CMD_ADMIN|CMD_NOSCRIPT|CMD_LOADING|CMD_STALE|CMD_SENTINEL,0,ACL_SETUSER_Keyspecs,0,NULL,2),.args=ACL_SETUSER_Args},
{MAKE_CMD("save","Saves the effective ACL rules in the configured ACL file.","O(N). Where N is the number of configured users.","6.0.0",CMD_DOC_NONE,NULL,NULL,"server",COMMAND_GROUP_SERVER,ACL_SAVE_History,0,ACL_SAVE_Tips,2,aclCommand,2,CMD_ADMIN|CMD_NOSCRIPT|CMD_LOADING|CMD_STALE|CMD_SENTINEL,0,ACL_SAVE_Keyspecs,0,NULL,0)},
{MAKE_CMD("setuser","Creates and modifies an ACL user and its rules.","O(N). Where N is the number of rules provided.","6.0.0",CMD_DOC_NONE,NULL,NULL,"server",COMMAND_GROUP_SERVER,ACL_SETUSER_History,2,ACL_SETUSER_Tips,2,aclCommand,-3,CMD_ADMIN|CMD_NOSCRIPT|CMD_LOADING|CMD_STALE|CMD_SENTINEL,0,ACL_SETUSER_Keyspecs,0,NULL,2),.args=ACL_SETUSER_Args},
{MAKE_CMD("users","Lists all ACL users.","O(N). Where N is the number of configured users.","6.0.0",CMD_DOC_NONE,NULL,NULL,"server",COMMAND_GROUP_SERVER,ACL_USERS_History,0,ACL_USERS_Tips,0,aclCommand,2,CMD_ADMIN|CMD_NOSCRIPT|CMD_LOADING|CMD_STALE|CMD_SENTINEL,0,ACL_USERS_Keyspecs,0,NULL,0)},
{MAKE_CMD("whoami","Returns the authenticated username of the current connection.","O(1)","6.0.0",CMD_DOC_NONE,NULL,NULL,"server",COMMAND_GROUP_SERVER,ACL_WHOAMI_History,0,ACL_WHOAMI_Tips,0,aclCommand,2,CMD_NOSCRIPT|CMD_LOADING|CMD_STALE|CMD_SENTINEL,0,ACL_WHOAMI_Keyspecs,0,NULL,0)},
{0}
@@ -6446,7 +6461,10 @@ struct COMMAND_ARG CONFIG_GET_Args[] = {
#ifndef SKIP_CMD_TIPS_TABLE
/* CONFIG RESETSTAT tips */
#define CONFIG_RESETSTAT_Tips NULL
const char *CONFIG_RESETSTAT_Tips[] = {
"request_policy:all_nodes",
"response_policy:all_succeeded",
};
#endif
#ifndef SKIP_CMD_KEY_SPECS_TABLE
@@ -6463,7 +6481,10 @@ struct COMMAND_ARG CONFIG_GET_Args[] = {
#ifndef SKIP_CMD_TIPS_TABLE
/* CONFIG REWRITE tips */
#define CONFIG_REWRITE_Tips NULL
const char *CONFIG_REWRITE_Tips[] = {
"request_policy:all_nodes",
"response_policy:all_succeeded",
};
#endif
#ifndef SKIP_CMD_KEY_SPECS_TABLE
@@ -6508,8 +6529,8 @@ struct COMMAND_ARG CONFIG_SET_Args[] = {
struct COMMAND_STRUCT CONFIG_Subcommands[] = {
{MAKE_CMD("get","Returns the effective values of configuration parameters.","O(N) when N is the number of configuration parameters provided","2.0.0",CMD_DOC_NONE,NULL,NULL,"server",COMMAND_GROUP_SERVER,CONFIG_GET_History,1,CONFIG_GET_Tips,0,configGetCommand,-3,CMD_ADMIN|CMD_NOSCRIPT|CMD_LOADING|CMD_STALE,0,CONFIG_GET_Keyspecs,0,NULL,1),.args=CONFIG_GET_Args},
{MAKE_CMD("help","Returns helpful text about the different subcommands.","O(1)","5.0.0",CMD_DOC_NONE,NULL,NULL,"server",COMMAND_GROUP_SERVER,CONFIG_HELP_History,0,CONFIG_HELP_Tips,0,configHelpCommand,2,CMD_LOADING|CMD_STALE,0,CONFIG_HELP_Keyspecs,0,NULL,0)},
{MAKE_CMD("resetstat","Resets the server's statistics.","O(1)","2.0.0",CMD_DOC_NONE,NULL,NULL,"server",COMMAND_GROUP_SERVER,CONFIG_RESETSTAT_History,0,CONFIG_RESETSTAT_Tips,0,configResetStatCommand,2,CMD_ADMIN|CMD_NOSCRIPT|CMD_LOADING|CMD_STALE,0,CONFIG_RESETSTAT_Keyspecs,0,NULL,0)},
{MAKE_CMD("rewrite","Persists the effective configuration to file.","O(1)","2.8.0",CMD_DOC_NONE,NULL,NULL,"server",COMMAND_GROUP_SERVER,CONFIG_REWRITE_History,0,CONFIG_REWRITE_Tips,0,configRewriteCommand,2,CMD_ADMIN|CMD_NOSCRIPT|CMD_LOADING|CMD_STALE,0,CONFIG_REWRITE_Keyspecs,0,NULL,0)},
{MAKE_CMD("resetstat","Resets the server's statistics.","O(1)","2.0.0",CMD_DOC_NONE,NULL,NULL,"server",COMMAND_GROUP_SERVER,CONFIG_RESETSTAT_History,0,CONFIG_RESETSTAT_Tips,2,configResetStatCommand,2,CMD_ADMIN|CMD_NOSCRIPT|CMD_LOADING|CMD_STALE,0,CONFIG_RESETSTAT_Keyspecs,0,NULL,0)},
{MAKE_CMD("rewrite","Persists the effective configuration to file.","O(1)","2.8.0",CMD_DOC_NONE,NULL,NULL,"server",COMMAND_GROUP_SERVER,CONFIG_REWRITE_History,0,CONFIG_REWRITE_Tips,2,configRewriteCommand,2,CMD_ADMIN|CMD_NOSCRIPT|CMD_LOADING|CMD_STALE,0,CONFIG_REWRITE_Keyspecs,0,NULL,0)},
{MAKE_CMD("set","Sets configuration parameters in-flight.","O(N) when N is the number of configuration parameters provided","2.0.0",CMD_DOC_NONE,NULL,NULL,"server",COMMAND_GROUP_SERVER,CONFIG_SET_History,1,CONFIG_SET_Tips,2,configSetCommand,-4,CMD_ADMIN|CMD_NOSCRIPT|CMD_LOADING|CMD_STALE,0,CONFIG_SET_Keyspecs,0,NULL,1),.args=CONFIG_SET_Args},
{0}
};
@@ -6862,7 +6883,7 @@ const char *LATENCY_LATEST_Tips[] = {
/* LATENCY RESET tips */
const char *LATENCY_RESET_Tips[] = {
"request_policy:all_nodes",
"response_policy:all_succeeded",
"response_policy:agg_sum",
};
#endif
@@ -7292,12 +7313,29 @@ struct COMMAND_ARG PSYNC_Args[] = {
#define REPLICAOF_Keyspecs NULL
#endif
/* REPLICAOF argument table */
struct COMMAND_ARG REPLICAOF_Args[] = {
/* REPLICAOF args host_port argument table */
struct COMMAND_ARG REPLICAOF_args_host_port_Subargs[] = {
{MAKE_ARG("host",ARG_TYPE_STRING,-1,NULL,NULL,NULL,CMD_ARG_NONE,0,NULL)},
{MAKE_ARG("port",ARG_TYPE_INTEGER,-1,NULL,NULL,NULL,CMD_ARG_NONE,0,NULL)},
};
/* REPLICAOF args no_one argument table */
struct COMMAND_ARG REPLICAOF_args_no_one_Subargs[] = {
{MAKE_ARG("no",ARG_TYPE_PURE_TOKEN,-1,"NO",NULL,NULL,CMD_ARG_NONE,0,NULL)},
{MAKE_ARG("one",ARG_TYPE_PURE_TOKEN,-1,"ONE",NULL,NULL,CMD_ARG_NONE,0,NULL)},
};
/* REPLICAOF args argument table */
struct COMMAND_ARG REPLICAOF_args_Subargs[] = {
{MAKE_ARG("host-port",ARG_TYPE_BLOCK,-1,NULL,NULL,NULL,CMD_ARG_NONE,2,NULL),.subargs=REPLICAOF_args_host_port_Subargs},
{MAKE_ARG("no-one",ARG_TYPE_BLOCK,-1,NULL,NULL,NULL,CMD_ARG_NONE,2,NULL),.subargs=REPLICAOF_args_no_one_Subargs},
};
/* REPLICAOF argument table */
struct COMMAND_ARG REPLICAOF_Args[] = {
{MAKE_ARG("args",ARG_TYPE_ONEOF,-1,NULL,NULL,NULL,CMD_ARG_NONE,2,NULL),.subargs=REPLICAOF_args_Subargs},
};
/********** RESTORE_ASKING ********************/
#ifndef SKIP_CMD_HISTORY_TABLE
@@ -7416,12 +7454,29 @@ struct COMMAND_ARG SHUTDOWN_Args[] = {
#define SLAVEOF_Keyspecs NULL
#endif
/* SLAVEOF argument table */
struct COMMAND_ARG SLAVEOF_Args[] = {
/* SLAVEOF args host_port argument table */
struct COMMAND_ARG SLAVEOF_args_host_port_Subargs[] = {
{MAKE_ARG("host",ARG_TYPE_STRING,-1,NULL,NULL,NULL,CMD_ARG_NONE,0,NULL)},
{MAKE_ARG("port",ARG_TYPE_INTEGER,-1,NULL,NULL,NULL,CMD_ARG_NONE,0,NULL)},
};
/* SLAVEOF args no_one argument table */
struct COMMAND_ARG SLAVEOF_args_no_one_Subargs[] = {
{MAKE_ARG("no",ARG_TYPE_PURE_TOKEN,-1,"NO",NULL,NULL,CMD_ARG_NONE,0,NULL)},
{MAKE_ARG("one",ARG_TYPE_PURE_TOKEN,-1,"ONE",NULL,NULL,CMD_ARG_NONE,0,NULL)},
};
/* SLAVEOF args argument table */
struct COMMAND_ARG SLAVEOF_args_Subargs[] = {
{MAKE_ARG("host-port",ARG_TYPE_BLOCK,-1,NULL,NULL,NULL,CMD_ARG_NONE,2,NULL),.subargs=SLAVEOF_args_host_port_Subargs},
{MAKE_ARG("no-one",ARG_TYPE_BLOCK,-1,NULL,NULL,NULL,CMD_ARG_NONE,2,NULL),.subargs=SLAVEOF_args_no_one_Subargs},
};
/* SLAVEOF argument table */
struct COMMAND_ARG SLAVEOF_Args[] = {
{MAKE_ARG("args",ARG_TYPE_ONEOF,-1,NULL,NULL,NULL,CMD_ARG_NONE,2,NULL),.subargs=SLAVEOF_args_Subargs},
};
/********** SLOWLOG GET ********************/
#ifndef SKIP_CMD_HISTORY_TABLE
@@ -10731,12 +10786,12 @@ struct COMMAND_STRUCT redisCommandTable[] = {
{MAKE_CMD("monitor","Listens for all requests received by the server in real-time.",NULL,"1.0.0",CMD_DOC_NONE,NULL,NULL,"server",COMMAND_GROUP_SERVER,MONITOR_History,0,MONITOR_Tips,0,monitorCommand,1,CMD_ADMIN|CMD_NOSCRIPT|CMD_LOADING|CMD_STALE,0,MONITOR_Keyspecs,0,NULL,0)},
{MAKE_CMD("psync","An internal command used in replication.",NULL,"2.8.0",CMD_DOC_NONE,NULL,NULL,"server",COMMAND_GROUP_SERVER,PSYNC_History,0,PSYNC_Tips,0,syncCommand,-3,CMD_NO_ASYNC_LOADING|CMD_ADMIN|CMD_NO_MULTI|CMD_NOSCRIPT,0,PSYNC_Keyspecs,0,NULL,2),.args=PSYNC_Args},
{MAKE_CMD("replconf","An internal command for configuring the replication stream.","O(1)","3.0.0",CMD_DOC_SYSCMD,NULL,NULL,"server",COMMAND_GROUP_SERVER,REPLCONF_History,0,REPLCONF_Tips,0,replconfCommand,-1,CMD_ADMIN|CMD_NOSCRIPT|CMD_LOADING|CMD_STALE|CMD_ALLOW_BUSY,0,REPLCONF_Keyspecs,0,NULL,0)},
{MAKE_CMD("replicaof","Configures a server as replica of another, or promotes it to a master.","O(1)","5.0.0",CMD_DOC_NONE,NULL,NULL,"server",COMMAND_GROUP_SERVER,REPLICAOF_History,0,REPLICAOF_Tips,0,replicaofCommand,3,CMD_NO_ASYNC_LOADING|CMD_ADMIN|CMD_NOSCRIPT|CMD_STALE,0,REPLICAOF_Keyspecs,0,NULL,2),.args=REPLICAOF_Args},
{MAKE_CMD("replicaof","Configures a server as replica of another, or promotes it to a master.","O(1)","5.0.0",CMD_DOC_NONE,NULL,NULL,"server",COMMAND_GROUP_SERVER,REPLICAOF_History,0,REPLICAOF_Tips,0,replicaofCommand,3,CMD_NO_ASYNC_LOADING|CMD_ADMIN|CMD_NOSCRIPT|CMD_STALE,0,REPLICAOF_Keyspecs,0,NULL,1),.args=REPLICAOF_Args},
{MAKE_CMD("restore-asking","An internal command for migrating keys in a cluster.","O(1) to create the new key and additional O(N*M) to reconstruct the serialized value, where N is the number of Redis objects composing the value and M their average size. For small string values the time complexity is thus O(1)+O(1*M) where M is small, so simply O(1). However for sorted set values the complexity is O(N*M*log(N)) because inserting values into sorted sets is O(log(N)).","3.0.0",CMD_DOC_SYSCMD,NULL,NULL,"server",COMMAND_GROUP_SERVER,RESTORE_ASKING_History,3,RESTORE_ASKING_Tips,0,restoreCommand,-4,CMD_WRITE|CMD_DENYOOM|CMD_ASKING,ACL_CATEGORY_KEYSPACE|ACL_CATEGORY_DANGEROUS,RESTORE_ASKING_Keyspecs,1,NULL,7),.args=RESTORE_ASKING_Args},
{MAKE_CMD("role","Returns the replication role.","O(1)","2.8.12",CMD_DOC_NONE,NULL,NULL,"server",COMMAND_GROUP_SERVER,ROLE_History,0,ROLE_Tips,0,roleCommand,1,CMD_NOSCRIPT|CMD_LOADING|CMD_STALE|CMD_FAST|CMD_SENTINEL,ACL_CATEGORY_ADMIN|ACL_CATEGORY_DANGEROUS,ROLE_Keyspecs,0,NULL,0)},
{MAKE_CMD("save","Synchronously saves the database(s) to disk.","O(N) where N is the total number of keys in all databases","1.0.0",CMD_DOC_NONE,NULL,NULL,"server",COMMAND_GROUP_SERVER,SAVE_History,0,SAVE_Tips,0,saveCommand,1,CMD_NO_ASYNC_LOADING|CMD_ADMIN|CMD_NOSCRIPT|CMD_NO_MULTI,0,SAVE_Keyspecs,0,NULL,0)},
{MAKE_CMD("shutdown","Synchronously saves the database(s) to disk and shuts down the Redis server.","O(N) when saving, where N is the total number of keys in all databases when saving data, otherwise O(1)","1.0.0",CMD_DOC_NONE,NULL,NULL,"server",COMMAND_GROUP_SERVER,SHUTDOWN_History,1,SHUTDOWN_Tips,0,shutdownCommand,-1,CMD_ADMIN|CMD_NOSCRIPT|CMD_LOADING|CMD_STALE|CMD_NO_MULTI|CMD_SENTINEL|CMD_ALLOW_BUSY,0,SHUTDOWN_Keyspecs,0,NULL,4),.args=SHUTDOWN_Args},
{MAKE_CMD("slaveof","Sets a Redis server as a replica of another, or promotes it to being a master.","O(1)","1.0.0",CMD_DOC_DEPRECATED,"`REPLICAOF`","5.0.0","server",COMMAND_GROUP_SERVER,SLAVEOF_History,0,SLAVEOF_Tips,0,replicaofCommand,3,CMD_NO_ASYNC_LOADING|CMD_ADMIN|CMD_NOSCRIPT|CMD_STALE,0,SLAVEOF_Keyspecs,0,NULL,2),.args=SLAVEOF_Args},
{MAKE_CMD("slaveof","Sets a Redis server as a replica of another, or promotes it to being a master.","O(1)","1.0.0",CMD_DOC_DEPRECATED,"`REPLICAOF`","5.0.0","server",COMMAND_GROUP_SERVER,SLAVEOF_History,0,SLAVEOF_Tips,0,replicaofCommand,3,CMD_NO_ASYNC_LOADING|CMD_ADMIN|CMD_NOSCRIPT|CMD_STALE,0,SLAVEOF_Keyspecs,0,NULL,1),.args=SLAVEOF_Args},
{MAKE_CMD("slowlog","A container for slow log commands.","Depends on subcommand.","2.2.12",CMD_DOC_NONE,NULL,NULL,"server",COMMAND_GROUP_SERVER,SLOWLOG_History,0,SLOWLOG_Tips,0,NULL,-2,0,0,SLOWLOG_Keyspecs,0,NULL,0),.subcommands=SLOWLOG_Subcommands},
{MAKE_CMD("swapdb","Swaps two Redis databases.","O(N) where N is the count of clients watching or blocking on keys from both databases.","4.0.0",CMD_DOC_NONE,NULL,NULL,"server",COMMAND_GROUP_SERVER,SWAPDB_History,0,SWAPDB_Tips,0,swapdbCommand,3,CMD_WRITE|CMD_FAST,ACL_CATEGORY_KEYSPACE|ACL_CATEGORY_DANGEROUS,SWAPDB_Keyspecs,0,NULL,2),.args=SWAPDB_Args},
{MAKE_CMD("sync","An internal command used in replication.",NULL,"1.0.0",CMD_DOC_NONE,NULL,NULL,"server",COMMAND_GROUP_SERVER,SYNC_History,0,SYNC_Tips,0,syncCommand,1,CMD_NO_ASYNC_LOADING|CMD_ADMIN|CMD_NO_MULTI|CMD_NOSCRIPT,0,SYNC_Keyspecs,0,NULL,0)},
+4
View File
@@ -14,6 +14,10 @@
"STALE",
"SENTINEL"
],
"command_tips": [
"REQUEST_POLICY:ALL_NODES",
"RESPONSE_POLICY:ALL_SUCCEEDED"
],
"reply_schema": {
"type": "integer",
"description": "The number of users that were deleted"
+4
View File
@@ -14,6 +14,10 @@
"STALE",
"SENTINEL"
],
"command_tips": [
"REQUEST_POLICY:ALL_NODES",
"RESPONSE_POLICY:ALL_SUCCEEDED"
],
"reply_schema": {
"const": "OK"
}
+4
View File
@@ -24,6 +24,10 @@
"STALE",
"SENTINEL"
],
"command_tips": [
"REQUEST_POLICY:ALL_NODES",
"RESPONSE_POLICY:ALL_SUCCEEDED"
],
"reply_schema": {
"const": "OK"
},
+4
View File
@@ -13,6 +13,10 @@
"STALE",
"SENTINEL"
],
"command_tips": [
"REQUEST_POLICY:ALL_NODES",
"RESPONSE_POLICY:ALL_SUCCEEDED"
],
"acl_categories": [
"CONNECTION"
],
+4
View File
@@ -13,6 +13,10 @@
"STALE",
"SENTINEL"
],
"command_tips": [
"REQUEST_POLICY:ALL_NODES",
"RESPONSE_POLICY:ALL_SUCCEEDED"
],
"acl_categories": [
"CONNECTION"
],
+1 -1
View File
@@ -26,7 +26,7 @@
"description": "an even number element array specifying the start and end slot numbers for slot ranges owned by this shard",
"type": "array",
"items": {
"type": "string"
"type": "integer"
}
},
"nodes": {
+4
View File
@@ -13,6 +13,10 @@
"LOADING",
"STALE"
],
"command_tips": [
"REQUEST_POLICY:ALL_NODES",
"RESPONSE_POLICY:ALL_SUCCEEDED"
],
"reply_schema": {
"const": "OK"
}
+4
View File
@@ -13,6 +13,10 @@
"LOADING",
"STALE"
],
"command_tips": [
"REQUEST_POLICY:ALL_NODES",
"RESPONSE_POLICY:ALL_SUCCEEDED"
],
"reply_schema": {
"const": "OK"
}
+1 -1
View File
@@ -15,7 +15,7 @@
],
"command_tips": [
"REQUEST_POLICY:ALL_NODES",
"RESPONSE_POLICY:ALL_SUCCEEDED"
"RESPONSE_POLICY:AGG_SUM"
],
"reply_schema": {
"type": "integer",
+34 -6
View File
@@ -14,12 +14,40 @@
],
"arguments": [
{
"name": "host",
"type": "string"
},
{
"name": "port",
"type": "integer"
"name": "args",
"type": "oneof",
"arguments": [
{
"name": "host-port",
"type": "block",
"arguments": [
{
"name": "host",
"type": "string"
},
{
"name": "port",
"type": "integer"
}
]
},
{
"name": "no-one",
"type": "block",
"arguments": [
{
"name": "no",
"type": "pure-token",
"token": "NO"
},
{
"name": "one",
"type": "pure-token",
"token": "ONE"
}
]
}
]
}
],
"reply_schema": {
+34 -6
View File
@@ -19,12 +19,40 @@
],
"arguments": [
{
"name": "host",
"type": "string"
},
{
"name": "port",
"type": "integer"
"name": "args",
"type": "oneof",
"arguments": [
{
"name": "host-port",
"type": "block",
"arguments": [
{
"name": "host",
"type": "string"
},
{
"name": "port",
"type": "integer"
}
]
},
{
"name": "no-one",
"type": "block",
"arguments": [
{
"name": "no",
"type": "pure-token",
"token": "NO"
},
{
"name": "one",
"type": "pure-token",
"token": "ONE"
}
]
}
]
}
],
"reply_schema": {
+1 -1
View File
@@ -150,7 +150,7 @@
"type": "string"
},
{
"description": "GET option is specified, but no object was found ",
"description": "GET option is specified, but no object was found",
"type": "null"
}
]
+9 -1
View File
@@ -117,7 +117,15 @@
"description": "a list of sorted elements",
"type": "array",
"items": {
"type": "string"
"oneOf": [
{
"type": "string"
},
{
"description": "GET option is specified, but no object was found",
"type": "null"
}
]
}
}
}
+6 -7
View File
@@ -634,8 +634,7 @@ void loadServerConfigFromString(char *config) {
loaderr:
if (argv) sdsfreesplitres(argv,argc);
fprintf(stderr, "\n*** FATAL CONFIG FILE ERROR (Redis %s) ***\n",
REDIS_VERSION);
fprintf(stderr, "\n*** FATAL CONFIG FILE ERROR (Version %s) ***\n", VALKEY_VERSION);
if (i < totlines) {
fprintf(stderr, "Reading the configuration file, at line %d\n", linenum);
fprintf(stderr, ">>> '%s'\n", lines[i]);
@@ -935,8 +934,8 @@ void configSetCommand(client *c) {
goto err;
}
RedisModuleConfigChangeV1 cc = {.num_changes = config_count, .config_names = config_names};
moduleFireServerEvent(REDISMODULE_EVENT_CONFIG, REDISMODULE_SUBEVENT_CONFIG_CHANGE, &cc);
ValkeyModuleConfigChangeV1 cc = {.num_changes = config_count, .config_names = config_names};
moduleFireServerEvent(VALKEYMODULE_EVENT_CONFIG, VALKEYMODULE_SUBEVENT_CONFIG_CHANGE, &cc);
addReply(c,shared.ok);
goto end;
@@ -1265,7 +1264,7 @@ int rewriteConfigRewriteLine(struct rewriteConfigState *state, const char *optio
}
/* Write the long long 'bytes' value as a string in a way that is parsable
* inside redis.conf. If possible uses the GB, MB, KB notation. */
* inside valkey.conf. If possible uses the GB, MB, KB notation. */
int rewriteConfigFormatMemory(char *buf, size_t len, long long bytes) {
int gb = 1024*1024*1024;
int mb = 1024*1024;
@@ -1463,7 +1462,7 @@ void rewriteConfigReplicaOfOption(standardConfig *config, const char *name, stru
/* If this is a master, we want all the slaveof config options
* in the file to be removed. Note that if this is a cluster instance
* we don't want a slaveof directive inside redis.conf. */
* we don't want a slaveof directive inside valkey.conf. */
if (server.cluster_enabled || server.masterhost == NULL) {
rewriteConfigMarkAsProcessed(state, name);
return;
@@ -1579,7 +1578,7 @@ void rewriteConfigLoadmoduleOption(struct rewriteConfigState *state) {
dictIterator *di = dictGetIterator(modules);
dictEntry *de;
while ((de = dictNext(di)) != NULL) {
struct RedisModule *module = dictGetVal(de);
struct ValkeyModule *module = dictGetVal(de);
line = sdsnew("loadmodule ");
line = sdscatsds(line, module->loadmod->path);
for (int i = 0; i < module->loadmod->argc; i++) {
+7 -3
View File
@@ -40,8 +40,12 @@
#include <fcntl.h>
#endif
#if defined(__APPLE__) && defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && __MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
#define MAC_OS_10_6_DETECTED
#endif
/* Define redis_fstat to fstat or fstat64() */
#if defined(__APPLE__) && !defined(MAC_OS_X_VERSION_10_6)
#if defined(__APPLE__) && !defined(MAC_OS_10_6_DETECTED)
#define redis_fstat fstat64
#define redis_stat stat64
#else
@@ -96,7 +100,7 @@
#define HAVE_ACCEPT4 1
#endif
#if (defined(__APPLE__) && defined(MAC_OS_X_VERSION_10_6)) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined (__NetBSD__)
#if (defined(__APPLE__) && defined(MAC_OS_10_6_DETECTED)) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined (__NetBSD__)
#define HAVE_KQUEUE 1
#endif
@@ -293,7 +297,7 @@ void setproctitle(const char *fmt, ...);
#include <kernel/OS.h>
#define redis_set_thread_title(name) rename_thread(find_thread(0), name)
#else
#if (defined __APPLE__ && defined(MAC_OS_X_VERSION_10_7))
#if (defined __APPLE__ && defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && __MAC_OS_X_VERSION_MAX_ALLOWED >= 1070)
int pthread_setname_np(const char *name);
#include <pthread.h>
#define redis_set_thread_title(name) pthread_setname_np(name)
+13 -12
View File
@@ -115,7 +115,7 @@ robj *lookupKey(redisDb *db, robj *key, int flags) {
* Don't do it if we have a saving child, as this will trigger
* a copy on write madness. */
if (server.current_client && server.current_client->flags & CLIENT_NO_TOUCH &&
server.current_client->cmd->proc != touchCommand)
server.executing_client->cmd->proc != touchCommand)
flags |= LOOKUP_NOTOUCH;
if (!hasActiveChildProcess() && !(flags & LOOKUP_NOTOUCH)){
if (server.maxmemory_policy & MAXMEMORY_FLAG_LFU) {
@@ -333,7 +333,7 @@ robj *dbRandomKey(redisDb *db) {
key = dictGetKey(de);
keyobj = createStringObject(key,sdslen(key));
if (dictFind(db->expires,key)) {
if (allvolatile && server.masterhost && --maxtries == 0) {
if (allvolatile && (server.masterhost || isPausedActions(PAUSE_ACTION_EXPIRE)) && --maxtries == 0) {
/* If the DB is composed only of keys with an expire set,
* it could happen that all the keys are already logically
* expired in the slave, so the function cannot stop because
@@ -495,7 +495,7 @@ long long emptyDbStructure(redisDb *dbarray, int dbnum, int async,
long long emptyData(int dbnum, int flags, void(callback)(dict*)) {
int async = (flags & EMPTYDB_ASYNC);
int with_functions = !(flags & EMPTYDB_NOFUNCTIONS);
RedisModuleFlushInfoV1 fi = {REDISMODULE_FLUSHINFO_VERSION,!async,dbnum};
ValkeyModuleFlushInfoV1 fi = {VALKEYMODULE_FLUSHINFO_VERSION,!async,dbnum};
long long removed = 0;
if (dbnum < -1 || dbnum >= server.dbnum) {
@@ -504,8 +504,8 @@ long long emptyData(int dbnum, int flags, void(callback)(dict*)) {
}
/* Fire the flushdb modules event. */
moduleFireServerEvent(REDISMODULE_EVENT_FLUSHDB,
REDISMODULE_SUBEVENT_FLUSHDB_START,
moduleFireServerEvent(VALKEYMODULE_EVENT_FLUSHDB,
VALKEYMODULE_SUBEVENT_FLUSHDB_START,
&fi);
/* Make sure the WATCHed keys are affected by the FLUSH* commands.
@@ -530,8 +530,8 @@ long long emptyData(int dbnum, int flags, void(callback)(dict*)) {
/* Also fire the end event. Note that this event will fire almost
* immediately after the start event if the flush is asynchronous. */
moduleFireServerEvent(REDISMODULE_EVENT_FLUSHDB,
REDISMODULE_SUBEVENT_FLUSHDB_END,
moduleFireServerEvent(VALKEYMODULE_EVENT_FLUSHDB,
VALKEYMODULE_SUBEVENT_FLUSHDB_END,
&fi);
return removed;
@@ -828,7 +828,7 @@ int objectTypeCompare(robj *o, long long target) {
return 1;
}
/* module type compare */
long long mt = (long long)REDISMODULE_TYPE_SIGN(((moduleValue *)o->ptr)->type->id);
long long mt = (long long)VALKEYMODULE_TYPE_SIGN(((moduleValue *)o->ptr)->type->id);
if (target != -mt)
return 0;
else
@@ -921,7 +921,7 @@ long long getObjectTypeByName(char *name) {
}
moduleType *mt = moduleTypeLookupModuleByNameIgnoreCase(name);
if (mt != NULL) return -(REDISMODULE_TYPE_SIGN(mt->id));
if (mt != NULL) return -(VALKEYMODULE_TYPE_SIGN(mt->id));
return LLONG_MAX;
}
@@ -1631,8 +1631,8 @@ void swapdbCommand(client *c) {
addReplyError(c,"DB index is out of range");
return;
} else {
RedisModuleSwapDbInfo si = {REDISMODULE_SWAPDBINFO_VERSION,id1,id2};
moduleFireServerEvent(REDISMODULE_EVENT_SWAPDB,0,&si);
ValkeyModuleSwapDbInfo si = {VALKEYMODULE_SWAPDBINFO_VERSION,id1,id2};
moduleFireServerEvent(VALKEYMODULE_EVENT_SWAPDB,0,&si);
server.dirty++;
addReply(c,shared.ok);
}
@@ -2294,7 +2294,8 @@ int sortROGetKeys(struct redisCommand *cmd, robj **argv, int argc, getKeysResult
keys = getKeysPrepareResult(result, 1);
keys[0].pos = 1; /* <sort-key> is always present. */
keys[0].flags = CMD_KEY_RO | CMD_KEY_ACCESS;
return 1;
result->numkeys = 1;
return result->numkeys;
}
/* Helper function to extract keys from the SORT command.
+23 -11
View File
@@ -253,7 +253,7 @@ void xorObjectDigest(redisDb *db, robj *keyobj, unsigned char *digest, robj *o)
}
streamIteratorStop(&si);
} else if (o->type == OBJ_MODULE) {
RedisModuleDigest md = {{0},{0},keyobj,db->id};
ValkeyModuleDigest md = {{0},{0},keyobj,db->id};
moduleValue *mv = o->ptr;
moduleType *mt = mv->type;
moduleInitDigestContext(md);
@@ -431,6 +431,9 @@ void debugCommand(client *c) {
" Show low level info about `key` and associated value.",
"DROP-CLUSTER-PACKET-FILTER <packet-type>",
" Drop all packets that match the filtered type. Set to -1 allow all packets.",
"CLOSE-CLUSTER-LINK-ON-PACKET-DROP <0|1>",
" This is valid only when DROP-CLUSTER-PACKET-FILTER is set to a valid packet type.",
" When set to 1, the cluster link is closed after dropping a packet based on the filter.",
"OOM",
" Crash the server simulating an out-of-memory error.",
"PANIC",
@@ -495,6 +498,9 @@ void debugCommand(client *c) {
" Enable or disable the reply buffer resize cron job",
"CLUSTERLINK KILL <to|from|all> <node-id>",
" Kills the link based on the direction to/from (both) with the provided node." ,
"CLIENT-ENFORCE-REPLY-LIST <0|1>",
" When set to 1, it enforces the use of the client reply list directly",
" and avoids using the client's static buffer.",
NULL
};
addReplyHelp(c, help);
@@ -599,8 +605,11 @@ NULL
if (getLongFromObjectOrReply(c, c->argv[2], &packet_type, NULL) != C_OK)
return;
server.cluster_drop_packet_filter = packet_type;
addReply(c,shared.ok);
} else if (!strcasecmp(c->argv[1]->ptr,"object") && c->argc == 3) {
addReply(c, shared.ok);
} else if (!strcasecmp(c->argv[1]->ptr, "close-cluster-link-on-packet-drop") && c->argc == 3) {
server.debug_cluster_close_link_on_packet_drop = atoi(c->argv[2]->ptr) != 0;
addReply(c, shared.ok);
} else if (!strcasecmp(c->argv[1]->ptr, "object") && c->argc == 3) {
dictEntry *de;
robj *val;
char *strenc;
@@ -1042,6 +1051,9 @@ NULL
addReplyErrorFormat(c, "Unknown direction %s", (char*) c->argv[3]->ptr);
}
addReply(c,shared.ok);
} else if (!strcasecmp(c->argv[1]->ptr, "client-enforce-reply-list") && c->argc == 3) {
server.debug_client_enforce_reply_list = atoi(c->argv[2]->ptr);
addReply(c, shared.ok);
} else {
addReplySubcommandSyntaxError(c);
return;
@@ -1190,7 +1202,7 @@ static void* getAndSetMcontextEip(ucontext_t *uc, void *eip) {
} \
return old_val; \
} while(0)
#if defined(__APPLE__) && !defined(MAC_OS_X_VERSION_10_6)
#if defined(__APPLE__) && !defined(MAC_OS_10_6_DETECTED)
/* OSX < 10.6 */
#if defined(__x86_64__)
GET_SET_RETURN(uc->uc_mcontext->__ss.__rip, eip);
@@ -1199,7 +1211,7 @@ static void* getAndSetMcontextEip(ucontext_t *uc, void *eip) {
#else
GET_SET_RETURN(uc->uc_mcontext->__ss.__srr0, eip);
#endif
#elif defined(__APPLE__) && defined(MAC_OS_X_VERSION_10_6)
#elif defined(__APPLE__) && defined(MAC_OS_10_6_DETECTED)
/* OSX >= 10.6 */
#if defined(_STRUCT_X86_THREAD_STATE64) && !defined(__i386__)
GET_SET_RETURN(uc->uc_mcontext->__ss.__rip, eip);
@@ -1290,7 +1302,7 @@ void logRegisters(ucontext_t *uc) {
} while(0)
/* OSX */
#if defined(__APPLE__) && defined(MAC_OS_X_VERSION_10_6)
#if defined(__APPLE__) && defined(MAC_OS_10_6_DETECTED)
/* OSX AMD64 */
#if defined(_STRUCT_X86_THREAD_STATE64) && !defined(__i386__)
serverLog(LL_WARNING,
@@ -2122,7 +2134,7 @@ void sigsegvHandler(int sig, siginfo_t *info, void *secret) {
bugReportStart();
serverLog(LL_WARNING,
"Redis %s crashed by signal: %d, si_code: %d", REDIS_VERSION, sig, info->si_code);
SERVER_NAME " %s crashed by signal: %d, si_code: %d", VALKEY_VERSION, sig, info->si_code);
if (sig == SIGSEGV || sig == SIGBUS) {
serverLog(LL_WARNING,
"Accessing address: %p", (void*)info->si_addr);
@@ -2196,10 +2208,10 @@ void bugReportEnd(int killViaSignal, int sig) {
serverLogRaw(LL_WARNING|LL_RAW,
"\n=== REDIS BUG REPORT END. Make sure to include from START to END. ===\n\n"
" Please report the crash by opening an issue on github:\n\n"
" http://github.com/redis/redis/issues\n\n"
" If a Redis module was involved, please open in the module's repo instead.\n\n"
" Suspect RAM error? Use redis-server --test-memory to verify it.\n\n"
" Some other issues could be detected by redis-server --check-system\n"
" http://github.com/valkey-io/valkey/issues\n\n"
" If a module was involved, please open in the module's repo instead.\n\n"
" Suspect RAM error? Use valkey-server --test-memory to verify it.\n\n"
" Some other issues could be detected by valkey-server --check-system\n"
);
/* free(messages); Don't call free() with possibly corrupted memory. */
+1
View File
@@ -941,6 +941,7 @@ void activeDefragCycle(void) {
defrag_later_cursor = 0;
current_db = -1;
cursor = 0;
expires_cursor = 0;
db = NULL;
goto update_metrics;
}
+5 -10
View File
@@ -1414,30 +1414,25 @@ static int _dictExpandIfNeeded(dict *d)
* table (global setting) or we should avoid it but the ratio between
* elements/buckets is over the "safe" threshold, we resize doubling
* the number of buckets. */
if (!dictTypeExpandAllowed(d))
return DICT_OK;
if ((dict_can_resize == DICT_RESIZE_ENABLE &&
d->ht_used[0] >= DICTHT_SIZE(d->ht_size_exp[0])) ||
(dict_can_resize != DICT_RESIZE_FORBID &&
d->ht_used[0] / DICTHT_SIZE(d->ht_size_exp[0]) > dict_force_resize_ratio))
{
if (!dictTypeExpandAllowed(d))
return DICT_OK;
return dictExpand(d, d->ht_used[0] + 1);
}
return DICT_OK;
}
/* TODO: clz optimization */
/* Our hash table capability is a power of two */
static signed char _dictNextExp(unsigned long size)
{
unsigned char e = DICT_HT_INITIAL_EXP;
if (size <= DICT_HT_INITIAL_SIZE) return DICT_HT_INITIAL_EXP;
if (size >= LONG_MAX) return (8*sizeof(long)-1);
while(1) {
if (((unsigned long)1<<e) >= size)
return e;
e++;
}
return 8*sizeof(long) - __builtin_clzl(size-1);
}
/* Finds and returns the position within the dict where the provided key should
+9 -1
View File
@@ -27,6 +27,13 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* This file initializes the global LUA object and registers functions to call Valkey API from within the LUA language.
* It heavily invokes LUA's C API documented at https://www.lua.org/pil/24.html. There are 2 entrypoint functions in this file:
* 1. evalCommand() - Gets invoked every time a user runs LUA script via eval command on Valkey.
* 2. scriptingInit() - initServer() function from server.c invokes this to initialize LUA at startup.
* It is also invoked between 2 eval invocations to reset Lua.
*/
#include "server.h"
#include "sha1.h"
#include "rand.h"
@@ -272,6 +279,7 @@ void scriptingRelease(int async) {
else
dictRelease(lctx.lua_scripts);
lctx.lua_scripts_mem = 0;
lua_gc(lctx.lua, LUA_GCCOLLECT, 0);
lua_close(lctx.lua);
}
@@ -1579,7 +1587,7 @@ ldbLog(sdsnew(" next line of code."));
luaPushError(lua, "script aborted for user request");
luaError(lua);
} else if (argc > 1 &&
(!strcasecmp(argv[0],"r") || !strcasecmp(argv[0],"redis"))) {
(!strcasecmp(argv[0],"r") || !strcasecmp(argv[0],REDIS_API_NAME) || !strcasecmp(argv[0],SERVER_API_NAME))) {
ldbRedis(lua,argv,argc);
ldbSendLogs();
} else if ((!strcasecmp(argv[0],"p") || !strcasecmp(argv[0],"print"))) {
+2
View File
@@ -667,6 +667,7 @@ int performEvictions(void) {
*
* AOF and Output buffer memory will be freed eventually so
* we only care about memory used by the key space. */
enterExecutionUnit(1, 0);
delta = (long long) zmalloc_used_memory();
latencyStartMonitor(eviction_latency);
dbGenericDelete(db,keyobj,server.lazyfree_lazy_eviction,DB_FLAG_KEY_EVICTED);
@@ -679,6 +680,7 @@ int performEvictions(void) {
notifyKeyspaceEvent(NOTIFY_EVICTED, "evicted",
keyobj, db->id);
propagateDeletion(db,keyobj,server.lazyfree_lazy_eviction);
exitExecutionUnit();
postExecutionUnitOperations();
decrRefCount(keyobj);
keys_freed++;
+2
View File
@@ -54,10 +54,12 @@
int activeExpireCycleTryExpire(redisDb *db, dictEntry *de, long long now) {
long long t = dictGetSignedIntegerVal(de);
if (now > t) {
enterExecutionUnit(1, 0);
sds key = dictGetKey(de);
robj *keyobj = createStringObject(key,sdslen(key));
deleteExpiredKeyAndPropagate(db,keyobj);
decrRefCount(keyobj);
exitExecutionUnit();
return 1;
} else {
return 0;
+5
View File
@@ -439,6 +439,11 @@ int luaEngineInitEngine(void) {
luaRegisterVersion(lua_engine_ctx->lua);
luaSetErrorMetatable(lua_engine_ctx->lua);
lua_setfield(lua_engine_ctx->lua, -2, SERVER_API_NAME);
/* Get the server object and also set it to the Redis API
* compatibility namespace. */
lua_getfield(lua_engine_ctx->lua, -1, SERVER_API_NAME);
lua_setfield(lua_engine_ctx->lua, -2, REDIS_API_NAME);
luaSetErrorMetatable(lua_engine_ctx->lua);
+1 -1
View File
@@ -45,7 +45,7 @@
#include "server.h"
#include "script.h"
#include "redismodule.h"
#include "valkeymodule.h"
typedef struct functionLibInfo functionLibInfo;
+5
View File
@@ -2,6 +2,7 @@
#include "bio.h"
#include "atomicvar.h"
#include "functions.h"
#include "cluster.h"
static redisAtomic size_t lazyfree_objects = 0;
static redisAtomic size_t lazyfreed_objects = 0;
@@ -177,6 +178,10 @@ void emptyDbAsync(redisDb *db) {
dict *oldht1 = db->dict, *oldht2 = db->expires;
db->dict = dictCreate(&dbDictType);
db->expires = dictCreate(&dbExpiresDictType);
if (server.cluster_enabled) {
slotToKeyDestroy(db);
slotToKeyInit(db);
}
atomicIncr(lazyfree_objects,dictSize(oldht1));
bioCreateLazyFreeJob(lazyfreeFreeDatabase,2,oldht1,oldht2);
}
+2 -2
View File
@@ -44,7 +44,7 @@ void lolwut6Command(client *c);
* This is what unstable versions of Redis will display. */
void lolwutUnstableCommand(client *c) {
sds rendered = sdsnew("Redis ver. ");
rendered = sdscat(rendered,REDIS_VERSION);
rendered = sdscat(rendered,VALKEY_VERSION);
rendered = sdscatlen(rendered,"\n",1);
addReplyVerbatim(c,rendered,sdslen(rendered),"txt");
sdsfree(rendered);
@@ -52,7 +52,7 @@ void lolwutUnstableCommand(client *c) {
/* LOLWUT [VERSION <version>] [... version specific arguments ...] */
void lolwutCommand(client *c) {
char *v = REDIS_VERSION;
char *v = VALKEY_VERSION;
char verstr[64];
if (c->argc >= 3 && !strcasecmp(c->argv[1]->ptr,"version")) {
+1 -1
View File
@@ -169,7 +169,7 @@ void lolwut5Command(client *c) {
sds rendered = renderCanvas(canvas);
rendered = sdscat(rendered,
"\nGeorg Nees - schotter, plotter on paper, 1968. Redis ver. ");
rendered = sdscat(rendered,REDIS_VERSION);
rendered = sdscat(rendered,VALKEY_VERSION);
rendered = sdscatlen(rendered,"\n",1);
addReplyVerbatim(c,rendered,sdslen(rendered),"txt");
sdsfree(rendered);
+1 -1
View File
@@ -193,7 +193,7 @@ void lolwut6Command(client *c) {
rendered = sdscat(rendered,
"\nDedicated to the 8 bit game developers of past and present.\n"
"Original 8 bit image from Plaguemon by hikikomori. Redis ver. ");
rendered = sdscat(rendered,REDIS_VERSION);
rendered = sdscat(rendered,VALKEY_VERSION);
rendered = sdscatlen(rendered,"\n",1);
addReplyVerbatim(c,rendered,sdslen(rendered),"txt");
sdsfree(rendered);
+1 -1
View File
@@ -12,5 +12,5 @@ echo "#define REDIS_GIT_SHA1 \"$GIT_SHA1\"" > release.h
echo "#define REDIS_GIT_DIRTY \"$GIT_DIRTY\"" >> release.h
echo "#define REDIS_BUILD_ID \"$BUILD_ID\"" >> release.h
echo "#include \"version.h\"" >> release.h
echo "#define REDIS_BUILD_ID_RAW REDIS_VERSION REDIS_BUILD_ID REDIS_GIT_DIRTY REDIS_GIT_SHA1" >> release.h
echo "#define REDIS_BUILD_ID_RAW SERVER_NAME VALKEY_VERSION REDIS_BUILD_ID REDIS_GIT_DIRTY REDIS_GIT_SHA1" >> release.h
touch release.c # Force recompile of release.c
+2854 -2827
View File
File diff suppressed because it is too large Load Diff
+8 -8
View File
@@ -25,42 +25,42 @@ all: helloworld.so hellotype.so helloblock.so hellocluster.so hellotimer.so hell
.c.xo:
$(CC) -I. $(CFLAGS) $(SHOBJ_CFLAGS) -fPIC -c $< -o $@
helloworld.xo: ../redismodule.h
helloworld.xo: ../valkeymodule.h
helloworld.so: helloworld.xo
$(LD) -o $@ $^ $(SHOBJ_LDFLAGS) $(LIBS) -lc
hellotype.xo: ../redismodule.h
hellotype.xo: ../valkeymodule.h
hellotype.so: hellotype.xo
$(LD) -o $@ $^ $(SHOBJ_LDFLAGS) $(LIBS) -lc
helloblock.xo: ../redismodule.h
helloblock.xo: ../valkeymodule.h
helloblock.so: helloblock.xo
$(LD) -o $@ $^ $(SHOBJ_LDFLAGS) $(LIBS) -lpthread -lc
hellocluster.xo: ../redismodule.h
hellocluster.xo: ../valkeymodule.h
hellocluster.so: hellocluster.xo
$(LD) -o $@ $^ $(SHOBJ_LDFLAGS) $(LIBS) -lc
hellotimer.xo: ../redismodule.h
hellotimer.xo: ../valkeymodule.h
hellotimer.so: hellotimer.xo
$(LD) -o $@ $^ $(SHOBJ_LDFLAGS) $(LIBS) -lc
hellodict.xo: ../redismodule.h
hellodict.xo: ../valkeymodule.h
hellodict.so: hellodict.xo
$(LD) -o $@ $^ $(SHOBJ_LDFLAGS) $(LIBS) -lc
hellohook.xo: ../redismodule.h
hellohook.xo: ../valkeymodule.h
hellohook.so: hellohook.xo
$(LD) -o $@ $^ $(SHOBJ_LDFLAGS) $(LIBS) -lc
helloacl.xo: ../redismodule.h
helloacl.xo: ../valkeymodule.h
helloacl.so: helloacl.xo
$(LD) -o $@ $^ $(SHOBJ_LDFLAGS) $(LIBS) -lc
+29 -29
View File
@@ -31,7 +31,7 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "../redismodule.h"
#include "../valkeymodule.h"
#include <pthread.h>
#include <unistd.h>
@@ -42,8 +42,8 @@ static uint64_t global_auth_client_id = 0;
/* HELLOACL.REVOKE
* Synchronously revoke access from a user. */
int RevokeCommand_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc);
VALKEYMODULE_NOT_USED(argv);
VALKEYMODULE_NOT_USED(argc);
if (global_auth_client_id) {
RedisModule_DeauthenticateAndCloseClient(ctx, global_auth_client_id);
@@ -56,8 +56,8 @@ int RevokeCommand_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, in
/* HELLOACL.RESET
* Synchronously delete and re-create a module user. */
int ResetCommand_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc);
VALKEYMODULE_NOT_USED(argv);
VALKEYMODULE_NOT_USED(argc);
RedisModule_FreeModuleUser(global);
global = RedisModule_CreateModuleUser("global");
@@ -71,16 +71,16 @@ int ResetCommand_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int
/* Callback handler for user changes, use this to notify a module of
* changes to users authenticated by the module */
void HelloACL_UserChanged(uint64_t client_id, void *privdata) {
REDISMODULE_NOT_USED(privdata);
REDISMODULE_NOT_USED(client_id);
VALKEYMODULE_NOT_USED(privdata);
VALKEYMODULE_NOT_USED(client_id);
global_auth_client_id = 0;
}
/* HELLOACL.AUTHGLOBAL
* Synchronously assigns a module user to the current context. */
int AuthGlobalCommand_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc);
VALKEYMODULE_NOT_USED(argv);
VALKEYMODULE_NOT_USED(argc);
if (global_auth_client_id) {
return RedisModule_ReplyWithError(ctx, "Global user currently used");
@@ -95,15 +95,15 @@ int AuthGlobalCommand_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv
/* Reply callback for auth command HELLOACL.AUTHASYNC */
int HelloACL_Reply(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc);
VALKEYMODULE_NOT_USED(argv);
VALKEYMODULE_NOT_USED(argc);
size_t length;
RedisModuleString *user_string = RedisModule_GetBlockedClientPrivateData(ctx);
const char *name = RedisModule_StringPtrLen(user_string, &length);
if (RedisModule_AuthenticateClientWithACLUser(ctx, name, length, NULL, NULL, NULL) ==
REDISMODULE_ERR) {
VALKEYMODULE_ERR) {
return RedisModule_ReplyWithError(ctx, "Invalid Username or password");
}
return RedisModule_ReplyWithSimpleString(ctx, "OK");
@@ -111,14 +111,14 @@ int HelloACL_Reply(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
/* Timeout callback for auth command HELLOACL.AUTHASYNC */
int HelloACL_Timeout(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc);
VALKEYMODULE_NOT_USED(argv);
VALKEYMODULE_NOT_USED(argc);
return RedisModule_ReplyWithSimpleString(ctx, "Request timedout");
}
/* Private data frees data for HELLOACL.AUTHASYNC command. */
void HelloACL_FreeData(RedisModuleCtx *ctx, void *privdata) {
REDISMODULE_NOT_USED(ctx);
VALKEYMODULE_NOT_USED(ctx);
RedisModule_FreeString(NULL, privdata);
}
@@ -151,33 +151,33 @@ int AuthAsyncCommand_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv,
return RedisModule_ReplyWithError(ctx, "-ERR Can't start thread");
}
return REDISMODULE_OK;
return VALKEYMODULE_OK;
}
/* This function must be present on each Redis module. It is used in order to
* register the commands into the Redis server. */
int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc);
VALKEYMODULE_NOT_USED(argv);
VALKEYMODULE_NOT_USED(argc);
if (RedisModule_Init(ctx,"helloacl",1,REDISMODULE_APIVER_1)
== REDISMODULE_ERR) return REDISMODULE_ERR;
if (RedisModule_Init(ctx,"helloacl",1,VALKEYMODULE_APIVER_1)
== VALKEYMODULE_ERR) return VALKEYMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"helloacl.reset",
ResetCommand_RedisCommand,"",0,0,0) == REDISMODULE_ERR)
return REDISMODULE_ERR;
ResetCommand_RedisCommand,"",0,0,0) == VALKEYMODULE_ERR)
return VALKEYMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"helloacl.revoke",
RevokeCommand_RedisCommand,"",0,0,0) == REDISMODULE_ERR)
return REDISMODULE_ERR;
RevokeCommand_RedisCommand,"",0,0,0) == VALKEYMODULE_ERR)
return VALKEYMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"helloacl.authglobal",
AuthGlobalCommand_RedisCommand,"no-auth",0,0,0) == REDISMODULE_ERR)
return REDISMODULE_ERR;
AuthGlobalCommand_RedisCommand,"no-auth",0,0,0) == VALKEYMODULE_ERR)
return VALKEYMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"helloacl.authasync",
AuthAsyncCommand_RedisCommand,"no-auth",0,0,0) == REDISMODULE_ERR)
return REDISMODULE_ERR;
AuthAsyncCommand_RedisCommand,"no-auth",0,0,0) == VALKEYMODULE_ERR)
return VALKEYMODULE_ERR;
global = RedisModule_CreateModuleUser("global");
RedisModule_SetModuleUserACL(global, "allcommands");
@@ -186,5 +186,5 @@ int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
global_auth_client_id = 0;
return REDISMODULE_OK;
return VALKEYMODULE_OK;
}
+21 -21
View File
@@ -31,7 +31,7 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "../redismodule.h"
#include "../valkeymodule.h"
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
@@ -39,22 +39,22 @@
/* Reply callback for blocking command HELLO.BLOCK */
int HelloBlock_Reply(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc);
VALKEYMODULE_NOT_USED(argv);
VALKEYMODULE_NOT_USED(argc);
int *myint = RedisModule_GetBlockedClientPrivateData(ctx);
return RedisModule_ReplyWithLongLong(ctx,*myint);
}
/* Timeout callback for blocking command HELLO.BLOCK */
int HelloBlock_Timeout(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc);
VALKEYMODULE_NOT_USED(argv);
VALKEYMODULE_NOT_USED(argc);
return RedisModule_ReplyWithSimpleString(ctx,"Request timedout");
}
/* Private data freeing callback for HELLO.BLOCK command. */
void HelloBlock_FreeData(RedisModuleCtx *ctx, void *privdata) {
REDISMODULE_NOT_USED(ctx);
VALKEYMODULE_NOT_USED(ctx);
RedisModule_Free(privdata);
}
@@ -98,11 +98,11 @@ int HelloBlock_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int a
long long delay;
long long timeout;
if (RedisModule_StringToLongLong(argv[1],&delay) != REDISMODULE_OK) {
if (RedisModule_StringToLongLong(argv[1],&delay) != VALKEYMODULE_OK) {
return RedisModule_ReplyWithError(ctx,"ERR invalid count");
}
if (RedisModule_StringToLongLong(argv[2],&timeout) != REDISMODULE_OK) {
if (RedisModule_StringToLongLong(argv[2],&timeout) != VALKEYMODULE_OK) {
return RedisModule_ReplyWithError(ctx,"ERR invalid count");
}
@@ -125,7 +125,7 @@ int HelloBlock_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int a
RedisModule_AbortBlock(bc);
return RedisModule_ReplyWithError(ctx,"-ERR Can't start thread");
}
return REDISMODULE_OK;
return VALKEYMODULE_OK;
}
/* The thread entry point that actually executes the blocking part
@@ -141,7 +141,7 @@ void *HelloKeys_ThreadMain(void *arg) {
long long cursor = 0;
size_t replylen = 0;
RedisModule_ReplyWithArray(ctx,REDISMODULE_POSTPONED_LEN);
RedisModule_ReplyWithArray(ctx,VALKEYMODULE_POSTPONED_LEN);
do {
RedisModule_ThreadSafeContextLock(ctx);
RedisModuleCallReply *reply = RedisModule_Call(ctx,
@@ -178,7 +178,7 @@ void *HelloKeys_ThreadMain(void *arg) {
* that were in the database from the start to the end are guaranteed to be
* there. */
int HelloKeys_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv);
VALKEYMODULE_NOT_USED(argv);
if (argc != 1) return RedisModule_WrongArity(ctx);
pthread_t tid;
@@ -195,24 +195,24 @@ int HelloKeys_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int ar
RedisModule_AbortBlock(bc);
return RedisModule_ReplyWithError(ctx,"-ERR Can't start thread");
}
return REDISMODULE_OK;
return VALKEYMODULE_OK;
}
/* This function must be present on each Redis module. It is used in order to
* register the commands into the Redis server. */
int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc);
VALKEYMODULE_NOT_USED(argv);
VALKEYMODULE_NOT_USED(argc);
if (RedisModule_Init(ctx,"helloblock",1,REDISMODULE_APIVER_1)
== REDISMODULE_ERR) return REDISMODULE_ERR;
if (RedisModule_Init(ctx,"helloblock",1,VALKEYMODULE_APIVER_1)
== VALKEYMODULE_ERR) return VALKEYMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"hello.block",
HelloBlock_RedisCommand,"",0,0,0) == REDISMODULE_ERR)
return REDISMODULE_ERR;
HelloBlock_RedisCommand,"",0,0,0) == VALKEYMODULE_ERR)
return VALKEYMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"hello.keys",
HelloKeys_RedisCommand,"",0,0,0) == REDISMODULE_ERR)
return REDISMODULE_ERR;
HelloKeys_RedisCommand,"",0,0,0) == VALKEYMODULE_ERR)
return VALKEYMODULE_ERR;
return REDISMODULE_OK;
return VALKEYMODULE_OK;
}
+19 -19
View File
@@ -30,7 +30,7 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "../redismodule.h"
#include "../valkeymodule.h"
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
@@ -41,8 +41,8 @@
/* HELLOCLUSTER.PINGALL */
int PingallCommand_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc);
VALKEYMODULE_NOT_USED(argv);
VALKEYMODULE_NOT_USED(argc);
RedisModule_SendClusterMessage(ctx,NULL,MSGTYPE_PING,"Hey",3);
return RedisModule_ReplyWithSimpleString(ctx, "OK");
@@ -50,8 +50,8 @@ int PingallCommand_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, i
/* HELLOCLUSTER.LIST */
int ListCommand_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc);
VALKEYMODULE_NOT_USED(argv);
VALKEYMODULE_NOT_USED(argc);
size_t numnodes;
char **ids = RedisModule_GetClusterNodesList(ctx,&numnodes);
@@ -64,17 +64,17 @@ int ListCommand_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int
int port;
RedisModule_GetClusterNodeInfo(ctx,ids[j],NULL,NULL,&port,NULL);
RedisModule_ReplyWithArray(ctx,2);
RedisModule_ReplyWithStringBuffer(ctx,ids[j],REDISMODULE_NODE_ID_LEN);
RedisModule_ReplyWithStringBuffer(ctx,ids[j],VALKEYMODULE_NODE_ID_LEN);
RedisModule_ReplyWithLongLong(ctx,port);
}
RedisModule_FreeClusterNodesList(ids);
return REDISMODULE_OK;
return VALKEYMODULE_OK;
}
/* Callback for message MSGTYPE_PING */
void PingReceiver(RedisModuleCtx *ctx, const char *sender_id, uint8_t type, const unsigned char *payload, uint32_t len) {
RedisModule_Log(ctx,"notice","PING (type %d) RECEIVED from %.*s: '%.*s'",
type,REDISMODULE_NODE_ID_LEN,sender_id,(int)len, payload);
type,VALKEYMODULE_NODE_ID_LEN,sender_id,(int)len, payload);
RedisModule_SendClusterMessage(ctx,NULL,MSGTYPE_PONG,"Ohi!",4);
RedisModuleCallReply *reply = RedisModule_Call(ctx, "INCR", "c", "pings_received");
RedisModule_FreeCallReply(reply);
@@ -83,25 +83,25 @@ void PingReceiver(RedisModuleCtx *ctx, const char *sender_id, uint8_t type, cons
/* Callback for message MSGTYPE_PONG. */
void PongReceiver(RedisModuleCtx *ctx, const char *sender_id, uint8_t type, const unsigned char *payload, uint32_t len) {
RedisModule_Log(ctx,"notice","PONG (type %d) RECEIVED from %.*s: '%.*s'",
type,REDISMODULE_NODE_ID_LEN,sender_id,(int)len, payload);
type,VALKEYMODULE_NODE_ID_LEN,sender_id,(int)len, payload);
}
/* This function must be present on each Redis module. It is used in order to
* register the commands into the Redis server. */
int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc);
VALKEYMODULE_NOT_USED(argv);
VALKEYMODULE_NOT_USED(argc);
if (RedisModule_Init(ctx,"hellocluster",1,REDISMODULE_APIVER_1)
== REDISMODULE_ERR) return REDISMODULE_ERR;
if (RedisModule_Init(ctx,"hellocluster",1,VALKEYMODULE_APIVER_1)
== VALKEYMODULE_ERR) return VALKEYMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"hellocluster.pingall",
PingallCommand_RedisCommand,"readonly",0,0,0) == REDISMODULE_ERR)
return REDISMODULE_ERR;
PingallCommand_RedisCommand,"readonly",0,0,0) == VALKEYMODULE_ERR)
return VALKEYMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"hellocluster.list",
ListCommand_RedisCommand,"readonly",0,0,0) == REDISMODULE_ERR)
return REDISMODULE_ERR;
ListCommand_RedisCommand,"readonly",0,0,0) == VALKEYMODULE_ERR)
return VALKEYMODULE_ERR;
/* Disable Redis Cluster sharding and redirections. This way every node
* will be able to access every possible key, regardless of the hash slot.
@@ -109,10 +109,10 @@ int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
* variable. Normally you do that in order for the distributed system
* you create as a module to have total freedom in the keyspace
* manipulation. */
RedisModule_SetClusterFlags(ctx,REDISMODULE_CLUSTER_FLAG_NO_REDIRECTION);
RedisModule_SetClusterFlags(ctx,VALKEYMODULE_CLUSTER_FLAG_NO_REDIRECTION);
/* Register our handlers for different message types. */
RedisModule_RegisterClusterMessageReceiver(ctx,MSGTYPE_PING,PingReceiver);
RedisModule_RegisterClusterMessageReceiver(ctx,MSGTYPE_PONG,PongReceiver);
return REDISMODULE_OK;
return VALKEYMODULE_OK;
}
+16 -16
View File
@@ -33,7 +33,7 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "../redismodule.h"
#include "../valkeymodule.h"
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
@@ -76,7 +76,7 @@ int cmd_KEYRANGE(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
/* Parse the count argument. */
long long count;
if (RedisModule_StringToLongLong(argv[3],&count) != REDISMODULE_OK) {
if (RedisModule_StringToLongLong(argv[3],&count) != VALKEYMODULE_OK) {
return RedisModule_ReplyWithError(ctx,"ERR invalid count");
}
@@ -88,10 +88,10 @@ int cmd_KEYRANGE(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
char *key;
size_t keylen;
long long replylen = 0; /* Keep track of the emitted array len. */
RedisModule_ReplyWithArray(ctx,REDISMODULE_POSTPONED_LEN);
RedisModule_ReplyWithArray(ctx,VALKEYMODULE_POSTPONED_LEN);
while((key = RedisModule_DictNextC(iter,&keylen,NULL)) != NULL) {
if (replylen >= count) break;
if (RedisModule_DictCompare(iter,"<=",argv[2]) == REDISMODULE_ERR)
if (RedisModule_DictCompare(iter,"<=",argv[2]) == VALKEYMODULE_ERR)
break;
RedisModule_ReplyWithStringBuffer(ctx,key,keylen);
replylen++;
@@ -100,32 +100,32 @@ int cmd_KEYRANGE(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
/* Cleanup. */
RedisModule_DictIteratorStop(iter);
return REDISMODULE_OK;
return VALKEYMODULE_OK;
}
/* This function must be present on each Redis module. It is used in order to
* register the commands into the Redis server. */
int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc);
VALKEYMODULE_NOT_USED(argv);
VALKEYMODULE_NOT_USED(argc);
if (RedisModule_Init(ctx,"hellodict",1,REDISMODULE_APIVER_1)
== REDISMODULE_ERR) return REDISMODULE_ERR;
if (RedisModule_Init(ctx,"hellodict",1,VALKEYMODULE_APIVER_1)
== VALKEYMODULE_ERR) return VALKEYMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"hellodict.set",
cmd_SET,"write deny-oom",1,1,0) == REDISMODULE_ERR)
return REDISMODULE_ERR;
cmd_SET,"write deny-oom",1,1,0) == VALKEYMODULE_ERR)
return VALKEYMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"hellodict.get",
cmd_GET,"readonly",1,1,0) == REDISMODULE_ERR)
return REDISMODULE_ERR;
cmd_GET,"readonly",1,1,0) == VALKEYMODULE_ERR)
return VALKEYMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"hellodict.keyrange",
cmd_KEYRANGE,"readonly",1,1,0) == REDISMODULE_ERR)
return REDISMODULE_ERR;
cmd_KEYRANGE,"readonly",1,1,0) == VALKEYMODULE_ERR)
return VALKEYMODULE_ERR;
/* Create our global dictionary. Here we'll set our keys and values. */
Keyspace = RedisModule_CreateDict(NULL);
return REDISMODULE_OK;
return VALKEYMODULE_OK;
}
+12 -12
View File
@@ -30,7 +30,7 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "../redismodule.h"
#include "../valkeymodule.h"
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
@@ -39,23 +39,23 @@
/* Client state change callback. */
void clientChangeCallback(RedisModuleCtx *ctx, RedisModuleEvent e, uint64_t sub, void *data)
{
REDISMODULE_NOT_USED(ctx);
REDISMODULE_NOT_USED(e);
VALKEYMODULE_NOT_USED(ctx);
VALKEYMODULE_NOT_USED(e);
RedisModuleClientInfo *ci = data;
printf("Client %s event for client #%llu %s:%d\n",
(sub == REDISMODULE_SUBEVENT_CLIENT_CHANGE_CONNECTED) ?
(sub == VALKEYMODULE_SUBEVENT_CLIENT_CHANGE_CONNECTED) ?
"connection" : "disconnection",
(unsigned long long)ci->id,ci->addr,ci->port);
}
void flushdbCallback(RedisModuleCtx *ctx, RedisModuleEvent e, uint64_t sub, void *data)
{
REDISMODULE_NOT_USED(ctx);
REDISMODULE_NOT_USED(e);
VALKEYMODULE_NOT_USED(ctx);
VALKEYMODULE_NOT_USED(e);
RedisModuleFlushInfo *fi = data;
if (sub == REDISMODULE_SUBEVENT_FLUSHDB_START) {
if (sub == VALKEYMODULE_SUBEVENT_FLUSHDB_START) {
if (fi->dbnum != -1) {
RedisModuleCallReply *reply;
reply = RedisModule_Call(ctx,"DBSIZE","");
@@ -78,15 +78,15 @@ void flushdbCallback(RedisModuleCtx *ctx, RedisModuleEvent e, uint64_t sub, void
/* This function must be present on each Redis module. It is used in order to
* register the commands into the Redis server. */
int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc);
VALKEYMODULE_NOT_USED(argv);
VALKEYMODULE_NOT_USED(argc);
if (RedisModule_Init(ctx,"hellohook",1,REDISMODULE_APIVER_1)
== REDISMODULE_ERR) return REDISMODULE_ERR;
if (RedisModule_Init(ctx,"hellohook",1,VALKEYMODULE_APIVER_1)
== VALKEYMODULE_ERR) return VALKEYMODULE_ERR;
RedisModule_SubscribeToServerEvent(ctx,
RedisModuleEvent_ClientChange, clientChangeCallback);
RedisModule_SubscribeToServerEvent(ctx,
RedisModuleEvent_FlushDB, flushdbCallback);
return REDISMODULE_OK;
return VALKEYMODULE_OK;
}
+12 -12
View File
@@ -30,7 +30,7 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "../redismodule.h"
#include "../valkeymodule.h"
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
@@ -38,22 +38,22 @@
/* Timer callback. */
void timerHandler(RedisModuleCtx *ctx, void *data) {
REDISMODULE_NOT_USED(ctx);
VALKEYMODULE_NOT_USED(ctx);
printf("Fired %s!\n", (char *)data);
RedisModule_Free(data);
}
/* HELLOTIMER.TIMER*/
int TimerCommand_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc);
VALKEYMODULE_NOT_USED(argv);
VALKEYMODULE_NOT_USED(argc);
for (int j = 0; j < 10; j++) {
int delay = rand() % 5000;
char *buf = RedisModule_Alloc(256);
snprintf(buf,256,"After %d", delay);
RedisModuleTimerID tid = RedisModule_CreateTimer(ctx,delay,timerHandler,buf);
REDISMODULE_NOT_USED(tid);
VALKEYMODULE_NOT_USED(tid);
}
return RedisModule_ReplyWithSimpleString(ctx, "OK");
}
@@ -61,15 +61,15 @@ int TimerCommand_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int
/* This function must be present on each Redis module. It is used in order to
* register the commands into the Redis server. */
int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc);
VALKEYMODULE_NOT_USED(argv);
VALKEYMODULE_NOT_USED(argc);
if (RedisModule_Init(ctx,"hellotimer",1,REDISMODULE_APIVER_1)
== REDISMODULE_ERR) return REDISMODULE_ERR;
if (RedisModule_Init(ctx,"hellotimer",1,VALKEYMODULE_APIVER_1)
== VALKEYMODULE_ERR) return VALKEYMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"hellotimer.timer",
TimerCommand_RedisCommand,"readonly",0,0,0) == REDISMODULE_ERR)
return REDISMODULE_ERR;
TimerCommand_RedisCommand,"readonly",0,0,0) == VALKEYMODULE_ERR)
return VALKEYMODULE_ERR;
return REDISMODULE_OK;
return VALKEYMODULE_OK;
}
+47 -47
View File
@@ -35,7 +35,7 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "../redismodule.h"
#include "../valkeymodule.h"
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
@@ -105,22 +105,22 @@ int HelloTypeInsert_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv,
if (argc != 3) return RedisModule_WrongArity(ctx);
RedisModuleKey *key = RedisModule_OpenKey(ctx,argv[1],
REDISMODULE_READ|REDISMODULE_WRITE);
VALKEYMODULE_READ|VALKEYMODULE_WRITE);
int type = RedisModule_KeyType(key);
if (type != REDISMODULE_KEYTYPE_EMPTY &&
if (type != VALKEYMODULE_KEYTYPE_EMPTY &&
RedisModule_ModuleTypeGetType(key) != HelloType)
{
return RedisModule_ReplyWithError(ctx,REDISMODULE_ERRORMSG_WRONGTYPE);
return RedisModule_ReplyWithError(ctx,VALKEYMODULE_ERRORMSG_WRONGTYPE);
}
long long value;
if ((RedisModule_StringToLongLong(argv[2],&value) != REDISMODULE_OK)) {
if ((RedisModule_StringToLongLong(argv[2],&value) != VALKEYMODULE_OK)) {
return RedisModule_ReplyWithError(ctx,"ERR invalid value: must be a signed 64 bit integer");
}
/* Create an empty value object if the key is currently empty. */
struct HelloTypeObject *hto;
if (type == REDISMODULE_KEYTYPE_EMPTY) {
if (type == VALKEYMODULE_KEYTYPE_EMPTY) {
hto = createHelloTypeObject();
RedisModule_ModuleTypeSetValue(key,HelloType,hto);
} else {
@@ -133,7 +133,7 @@ int HelloTypeInsert_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv,
RedisModule_ReplyWithLongLong(ctx,hto->len);
RedisModule_ReplicateVerbatim(ctx);
return REDISMODULE_OK;
return VALKEYMODULE_OK;
}
/* HELLOTYPE.RANGE key first count */
@@ -142,17 +142,17 @@ int HelloTypeRange_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, i
if (argc != 4) return RedisModule_WrongArity(ctx);
RedisModuleKey *key = RedisModule_OpenKey(ctx,argv[1],
REDISMODULE_READ|REDISMODULE_WRITE);
VALKEYMODULE_READ|VALKEYMODULE_WRITE);
int type = RedisModule_KeyType(key);
if (type != REDISMODULE_KEYTYPE_EMPTY &&
if (type != VALKEYMODULE_KEYTYPE_EMPTY &&
RedisModule_ModuleTypeGetType(key) != HelloType)
{
return RedisModule_ReplyWithError(ctx,REDISMODULE_ERRORMSG_WRONGTYPE);
return RedisModule_ReplyWithError(ctx,VALKEYMODULE_ERRORMSG_WRONGTYPE);
}
long long first, count;
if (RedisModule_StringToLongLong(argv[2],&first) != REDISMODULE_OK ||
RedisModule_StringToLongLong(argv[3],&count) != REDISMODULE_OK ||
if (RedisModule_StringToLongLong(argv[2],&first) != VALKEYMODULE_OK ||
RedisModule_StringToLongLong(argv[3],&count) != VALKEYMODULE_OK ||
first < 0 || count < 0)
{
return RedisModule_ReplyWithError(ctx,
@@ -161,7 +161,7 @@ int HelloTypeRange_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, i
struct HelloTypeObject *hto = RedisModule_ModuleTypeGetValue(key);
struct HelloTypeNode *node = hto ? hto->head : NULL;
RedisModule_ReplyWithArray(ctx,REDISMODULE_POSTPONED_LEN);
RedisModule_ReplyWithArray(ctx,VALKEYMODULE_POSTPONED_LEN);
long long arraylen = 0;
while(node && count--) {
RedisModule_ReplyWithLongLong(ctx,node->value);
@@ -169,7 +169,7 @@ int HelloTypeRange_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, i
node = node->next;
}
RedisModule_ReplySetArrayLength(ctx,arraylen);
return REDISMODULE_OK;
return VALKEYMODULE_OK;
}
/* HELLOTYPE.LEN key */
@@ -178,17 +178,17 @@ int HelloTypeLen_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int
if (argc != 2) return RedisModule_WrongArity(ctx);
RedisModuleKey *key = RedisModule_OpenKey(ctx,argv[1],
REDISMODULE_READ|REDISMODULE_WRITE);
VALKEYMODULE_READ|VALKEYMODULE_WRITE);
int type = RedisModule_KeyType(key);
if (type != REDISMODULE_KEYTYPE_EMPTY &&
if (type != VALKEYMODULE_KEYTYPE_EMPTY &&
RedisModule_ModuleTypeGetType(key) != HelloType)
{
return RedisModule_ReplyWithError(ctx,REDISMODULE_ERRORMSG_WRONGTYPE);
return RedisModule_ReplyWithError(ctx,VALKEYMODULE_ERRORMSG_WRONGTYPE);
}
struct HelloTypeObject *hto = RedisModule_ModuleTypeGetValue(key);
RedisModule_ReplyWithLongLong(ctx,hto ? hto->len : 0);
return REDISMODULE_OK;
return VALKEYMODULE_OK;
}
/* ====================== Example of a blocking command ==================== */
@@ -197,17 +197,17 @@ int HelloTypeLen_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int
* called when the key we blocked for is ready: we need to check if we
* can really serve the client, and reply OK or ERR accordingly. */
int HelloBlock_Reply(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc);
VALKEYMODULE_NOT_USED(argv);
VALKEYMODULE_NOT_USED(argc);
RedisModuleString *keyname = RedisModule_GetBlockedClientReadyKey(ctx);
RedisModuleKey *key = RedisModule_OpenKey(ctx,keyname,REDISMODULE_READ);
RedisModuleKey *key = RedisModule_OpenKey(ctx,keyname,VALKEYMODULE_READ);
int type = RedisModule_KeyType(key);
if (type != REDISMODULE_KEYTYPE_MODULE ||
if (type != VALKEYMODULE_KEYTYPE_MODULE ||
RedisModule_ModuleTypeGetType(key) != HelloType)
{
RedisModule_CloseKey(key);
return REDISMODULE_ERR;
return VALKEYMODULE_ERR;
}
/* In case the key is able to serve our blocked client, let's directly
@@ -218,14 +218,14 @@ int HelloBlock_Reply(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
/* Timeout callback for blocking command HELLOTYPE.BRANGE */
int HelloBlock_Timeout(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc);
VALKEYMODULE_NOT_USED(argv);
VALKEYMODULE_NOT_USED(argc);
return RedisModule_ReplyWithSimpleString(ctx,"Request timedout");
}
/* Private data freeing callback for HELLOTYPE.BRANGE command. */
void HelloBlock_FreeData(RedisModuleCtx *ctx, void *privdata) {
REDISMODULE_NOT_USED(ctx);
VALKEYMODULE_NOT_USED(ctx);
RedisModule_Free(privdata);
}
@@ -236,31 +236,31 @@ int HelloTypeBRange_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv,
if (argc != 5) return RedisModule_WrongArity(ctx);
RedisModule_AutoMemory(ctx); /* Use automatic memory management. */
RedisModuleKey *key = RedisModule_OpenKey(ctx,argv[1],
REDISMODULE_READ|REDISMODULE_WRITE);
VALKEYMODULE_READ|VALKEYMODULE_WRITE);
int type = RedisModule_KeyType(key);
if (type != REDISMODULE_KEYTYPE_EMPTY &&
if (type != VALKEYMODULE_KEYTYPE_EMPTY &&
RedisModule_ModuleTypeGetType(key) != HelloType)
{
return RedisModule_ReplyWithError(ctx,REDISMODULE_ERRORMSG_WRONGTYPE);
return RedisModule_ReplyWithError(ctx,VALKEYMODULE_ERRORMSG_WRONGTYPE);
}
/* Parse the timeout before even trying to serve the client synchronously,
* so that we always fail ASAP on syntax errors. */
long long timeout;
if (RedisModule_StringToLongLong(argv[4],&timeout) != REDISMODULE_OK) {
if (RedisModule_StringToLongLong(argv[4],&timeout) != VALKEYMODULE_OK) {
return RedisModule_ReplyWithError(ctx,
"ERR invalid timeout parameter");
}
/* Can we serve the reply synchronously? */
if (type != REDISMODULE_KEYTYPE_EMPTY) {
if (type != VALKEYMODULE_KEYTYPE_EMPTY) {
return HelloTypeRange_RedisCommand(ctx,argv,argc-1);
}
/* Otherwise let's block on the key. */
void *privdata = RedisModule_Alloc(100);
RedisModule_BlockClientOnKeys(ctx,HelloBlock_Reply,HelloBlock_Timeout,HelloBlock_FreeData,timeout,argv+1,1,privdata);
return REDISMODULE_OK;
return VALKEYMODULE_OK;
}
/* ========================== "hellotype" type methods ======================= */
@@ -323,14 +323,14 @@ void HelloTypeDigest(RedisModuleDigest *md, void *value) {
/* This function must be present on each Redis module. It is used in order to
* register the commands into the Redis server. */
int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc);
VALKEYMODULE_NOT_USED(argv);
VALKEYMODULE_NOT_USED(argc);
if (RedisModule_Init(ctx,"hellotype",1,REDISMODULE_APIVER_1)
== REDISMODULE_ERR) return REDISMODULE_ERR;
if (RedisModule_Init(ctx,"hellotype",1,VALKEYMODULE_APIVER_1)
== VALKEYMODULE_ERR) return VALKEYMODULE_ERR;
RedisModuleTypeMethods tm = {
.version = REDISMODULE_TYPE_METHOD_VERSION,
.version = VALKEYMODULE_TYPE_METHOD_VERSION,
.rdb_load = HelloTypeRdbLoad,
.rdb_save = HelloTypeRdbSave,
.aof_rewrite = HelloTypeAofRewrite,
@@ -340,23 +340,23 @@ int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
};
HelloType = RedisModule_CreateDataType(ctx,"hellotype",0,&tm);
if (HelloType == NULL) return REDISMODULE_ERR;
if (HelloType == NULL) return VALKEYMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"hellotype.insert",
HelloTypeInsert_RedisCommand,"write deny-oom",1,1,1) == REDISMODULE_ERR)
return REDISMODULE_ERR;
HelloTypeInsert_RedisCommand,"write deny-oom",1,1,1) == VALKEYMODULE_ERR)
return VALKEYMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"hellotype.range",
HelloTypeRange_RedisCommand,"readonly",1,1,1) == REDISMODULE_ERR)
return REDISMODULE_ERR;
HelloTypeRange_RedisCommand,"readonly",1,1,1) == VALKEYMODULE_ERR)
return VALKEYMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"hellotype.len",
HelloTypeLen_RedisCommand,"readonly",1,1,1) == REDISMODULE_ERR)
return REDISMODULE_ERR;
HelloTypeLen_RedisCommand,"readonly",1,1,1) == VALKEYMODULE_ERR)
return VALKEYMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"hellotype.brange",
HelloTypeBRange_RedisCommand,"readonly",1,1,1) == REDISMODULE_ERR)
return REDISMODULE_ERR;
HelloTypeBRange_RedisCommand,"readonly",1,1,1) == VALKEYMODULE_ERR)
return VALKEYMODULE_ERR;
return REDISMODULE_OK;
return VALKEYMODULE_OK;
}
+110 -110
View File
@@ -34,7 +34,7 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "../redismodule.h"
#include "../valkeymodule.h"
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
@@ -46,10 +46,10 @@
* fetch the currently selected DB, the other in order to send the client
* an integer reply as response. */
int HelloSimple_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc);
VALKEYMODULE_NOT_USED(argv);
VALKEYMODULE_NOT_USED(argc);
RedisModule_ReplyWithLongLong(ctx,RedisModule_GetSelectedDb(ctx));
return REDISMODULE_OK;
return VALKEYMODULE_OK;
}
/* HELLO.PUSH.NATIVE re-implements RPUSH, and shows the low level modules API
@@ -63,13 +63,13 @@ int HelloPushNative_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv,
if (argc != 3) return RedisModule_WrongArity(ctx);
RedisModuleKey *key = RedisModule_OpenKey(ctx,argv[1],
REDISMODULE_READ|REDISMODULE_WRITE);
VALKEYMODULE_READ|VALKEYMODULE_WRITE);
RedisModule_ListPush(key,REDISMODULE_LIST_TAIL,argv[2]);
RedisModule_ListPush(key,VALKEYMODULE_LIST_TAIL,argv[2]);
size_t newlen = RedisModule_ValueLength(key);
RedisModule_CloseKey(key);
RedisModule_ReplyWithLongLong(ctx,newlen);
return REDISMODULE_OK;
return VALKEYMODULE_OK;
}
/* HELLO.PUSH.CALL implements RPUSH using an higher level approach, calling
@@ -87,7 +87,7 @@ int HelloPushCall_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, in
long long len = RedisModule_CallReplyInteger(reply);
RedisModule_FreeCallReply(reply);
RedisModule_ReplyWithLongLong(ctx,len);
return REDISMODULE_OK;
return VALKEYMODULE_OK;
}
/* HELLO.PUSH.CALL2
@@ -102,7 +102,7 @@ int HelloPushCall2_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, i
reply = RedisModule_Call(ctx,"RPUSH","ss",argv[1],argv[2]);
RedisModule_ReplyWithCallReply(ctx,reply);
RedisModule_FreeCallReply(reply);
return REDISMODULE_OK;
return VALKEYMODULE_OK;
}
/* HELLO.LIST.SUM.LEN returns the total length of all the items inside
@@ -124,7 +124,7 @@ int HelloListSumLen_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv,
}
RedisModule_FreeCallReply(reply);
RedisModule_ReplyWithLongLong(ctx,strlen);
return REDISMODULE_OK;
return VALKEYMODULE_OK;
}
/* HELLO.LIST.SPLICE srclist dstlist count
@@ -135,23 +135,23 @@ int HelloListSplice_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv,
if (argc != 4) return RedisModule_WrongArity(ctx);
RedisModuleKey *srckey = RedisModule_OpenKey(ctx,argv[1],
REDISMODULE_READ|REDISMODULE_WRITE);
VALKEYMODULE_READ|VALKEYMODULE_WRITE);
RedisModuleKey *dstkey = RedisModule_OpenKey(ctx,argv[2],
REDISMODULE_READ|REDISMODULE_WRITE);
VALKEYMODULE_READ|VALKEYMODULE_WRITE);
/* Src and dst key must be empty or lists. */
if ((RedisModule_KeyType(srckey) != REDISMODULE_KEYTYPE_LIST &&
RedisModule_KeyType(srckey) != REDISMODULE_KEYTYPE_EMPTY) ||
(RedisModule_KeyType(dstkey) != REDISMODULE_KEYTYPE_LIST &&
RedisModule_KeyType(dstkey) != REDISMODULE_KEYTYPE_EMPTY))
if ((RedisModule_KeyType(srckey) != VALKEYMODULE_KEYTYPE_LIST &&
RedisModule_KeyType(srckey) != VALKEYMODULE_KEYTYPE_EMPTY) ||
(RedisModule_KeyType(dstkey) != VALKEYMODULE_KEYTYPE_LIST &&
RedisModule_KeyType(dstkey) != VALKEYMODULE_KEYTYPE_EMPTY))
{
RedisModule_CloseKey(srckey);
RedisModule_CloseKey(dstkey);
return RedisModule_ReplyWithError(ctx,REDISMODULE_ERRORMSG_WRONGTYPE);
return RedisModule_ReplyWithError(ctx,VALKEYMODULE_ERRORMSG_WRONGTYPE);
}
long long count;
if ((RedisModule_StringToLongLong(argv[3],&count) != REDISMODULE_OK) ||
if ((RedisModule_StringToLongLong(argv[3],&count) != VALKEYMODULE_OK) ||
(count < 0)) {
RedisModule_CloseKey(srckey);
RedisModule_CloseKey(dstkey);
@@ -161,9 +161,9 @@ int HelloListSplice_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv,
while(count-- > 0) {
RedisModuleString *ele;
ele = RedisModule_ListPop(srckey,REDISMODULE_LIST_TAIL);
ele = RedisModule_ListPop(srckey,VALKEYMODULE_LIST_TAIL);
if (ele == NULL) break;
RedisModule_ListPush(dstkey,REDISMODULE_LIST_HEAD,ele);
RedisModule_ListPush(dstkey,VALKEYMODULE_LIST_HEAD,ele);
RedisModule_FreeString(ctx,ele);
}
@@ -171,7 +171,7 @@ int HelloListSplice_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv,
RedisModule_CloseKey(srckey);
RedisModule_CloseKey(dstkey);
RedisModule_ReplyWithLongLong(ctx,len);
return REDISMODULE_OK;
return VALKEYMODULE_OK;
}
/* Like the HELLO.LIST.SPLICE above, but uses automatic memory management
@@ -182,21 +182,21 @@ int HelloListSpliceAuto_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **ar
RedisModule_AutoMemory(ctx);
RedisModuleKey *srckey = RedisModule_OpenKey(ctx,argv[1],
REDISMODULE_READ|REDISMODULE_WRITE);
VALKEYMODULE_READ|VALKEYMODULE_WRITE);
RedisModuleKey *dstkey = RedisModule_OpenKey(ctx,argv[2],
REDISMODULE_READ|REDISMODULE_WRITE);
VALKEYMODULE_READ|VALKEYMODULE_WRITE);
/* Src and dst key must be empty or lists. */
if ((RedisModule_KeyType(srckey) != REDISMODULE_KEYTYPE_LIST &&
RedisModule_KeyType(srckey) != REDISMODULE_KEYTYPE_EMPTY) ||
(RedisModule_KeyType(dstkey) != REDISMODULE_KEYTYPE_LIST &&
RedisModule_KeyType(dstkey) != REDISMODULE_KEYTYPE_EMPTY))
if ((RedisModule_KeyType(srckey) != VALKEYMODULE_KEYTYPE_LIST &&
RedisModule_KeyType(srckey) != VALKEYMODULE_KEYTYPE_EMPTY) ||
(RedisModule_KeyType(dstkey) != VALKEYMODULE_KEYTYPE_LIST &&
RedisModule_KeyType(dstkey) != VALKEYMODULE_KEYTYPE_EMPTY))
{
return RedisModule_ReplyWithError(ctx,REDISMODULE_ERRORMSG_WRONGTYPE);
return RedisModule_ReplyWithError(ctx,VALKEYMODULE_ERRORMSG_WRONGTYPE);
}
long long count;
if ((RedisModule_StringToLongLong(argv[3],&count) != REDISMODULE_OK) ||
if ((RedisModule_StringToLongLong(argv[3],&count) != VALKEYMODULE_OK) ||
(count < 0))
{
return RedisModule_ReplyWithError(ctx,"ERR invalid count");
@@ -205,14 +205,14 @@ int HelloListSpliceAuto_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **ar
while(count-- > 0) {
RedisModuleString *ele;
ele = RedisModule_ListPop(srckey,REDISMODULE_LIST_TAIL);
ele = RedisModule_ListPop(srckey,VALKEYMODULE_LIST_TAIL);
if (ele == NULL) break;
RedisModule_ListPush(dstkey,REDISMODULE_LIST_HEAD,ele);
RedisModule_ListPush(dstkey,VALKEYMODULE_LIST_HEAD,ele);
}
size_t len = RedisModule_ValueLength(srckey);
RedisModule_ReplyWithLongLong(ctx,len);
return REDISMODULE_OK;
return VALKEYMODULE_OK;
}
/* HELLO.RAND.ARRAY <count>
@@ -221,7 +221,7 @@ int HelloListSpliceAuto_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **ar
int HelloRandArray_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
if (argc != 2) return RedisModule_WrongArity(ctx);
long long count;
if (RedisModule_StringToLongLong(argv[1],&count) != REDISMODULE_OK ||
if (RedisModule_StringToLongLong(argv[1],&count) != VALKEYMODULE_OK ||
count < 0)
return RedisModule_ReplyWithError(ctx,"ERR invalid count");
@@ -230,7 +230,7 @@ int HelloRandArray_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, i
* the elements of the array. */
RedisModule_ReplyWithArray(ctx,count);
while(count--) RedisModule_ReplyWithLongLong(ctx,rand());
return REDISMODULE_OK;
return VALKEYMODULE_OK;
}
/* This is a simple command to test replication. Because of the "!" modified
@@ -239,8 +239,8 @@ int HelloRandArray_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, i
* comments the function implementation). */
int HelloRepl1_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
{
REDISMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc);
VALKEYMODULE_NOT_USED(argv);
VALKEYMODULE_NOT_USED(argc);
RedisModule_AutoMemory(ctx);
/* This will be replicated *after* the two INCR statements, since
@@ -262,7 +262,7 @@ int HelloRepl1_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int a
RedisModule_ReplyWithLongLong(ctx,0);
return REDISMODULE_OK;
return VALKEYMODULE_OK;
}
/* Another command to show replication. In this case, we call
@@ -280,27 +280,27 @@ int HelloRepl2_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int a
RedisModule_AutoMemory(ctx); /* Use automatic memory management. */
RedisModuleKey *key = RedisModule_OpenKey(ctx,argv[1],
REDISMODULE_READ|REDISMODULE_WRITE);
VALKEYMODULE_READ|VALKEYMODULE_WRITE);
if (RedisModule_KeyType(key) != REDISMODULE_KEYTYPE_LIST)
return RedisModule_ReplyWithError(ctx,REDISMODULE_ERRORMSG_WRONGTYPE);
if (RedisModule_KeyType(key) != VALKEYMODULE_KEYTYPE_LIST)
return RedisModule_ReplyWithError(ctx,VALKEYMODULE_ERRORMSG_WRONGTYPE);
size_t listlen = RedisModule_ValueLength(key);
long long sum = 0;
/* Rotate and increment. */
while(listlen--) {
RedisModuleString *ele = RedisModule_ListPop(key,REDISMODULE_LIST_TAIL);
RedisModuleString *ele = RedisModule_ListPop(key,VALKEYMODULE_LIST_TAIL);
long long val;
if (RedisModule_StringToLongLong(ele,&val) != REDISMODULE_OK) val = 0;
if (RedisModule_StringToLongLong(ele,&val) != VALKEYMODULE_OK) val = 0;
val++;
sum += val;
RedisModuleString *newele = RedisModule_CreateStringFromLongLong(ctx,val);
RedisModule_ListPush(key,REDISMODULE_LIST_HEAD,newele);
RedisModule_ListPush(key,VALKEYMODULE_LIST_HEAD,newele);
}
RedisModule_ReplyWithLongLong(ctx,sum);
RedisModule_ReplicateVerbatim(ctx);
return REDISMODULE_OK;
return VALKEYMODULE_OK;
}
/* This is an example of strings DMA access. Given a key containing a string
@@ -315,19 +315,19 @@ int HelloToggleCase_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv,
if (argc != 2) return RedisModule_WrongArity(ctx);
RedisModuleKey *key = RedisModule_OpenKey(ctx,argv[1],
REDISMODULE_READ|REDISMODULE_WRITE);
VALKEYMODULE_READ|VALKEYMODULE_WRITE);
int keytype = RedisModule_KeyType(key);
if (keytype != REDISMODULE_KEYTYPE_STRING &&
keytype != REDISMODULE_KEYTYPE_EMPTY)
if (keytype != VALKEYMODULE_KEYTYPE_STRING &&
keytype != VALKEYMODULE_KEYTYPE_EMPTY)
{
RedisModule_CloseKey(key);
return RedisModule_ReplyWithError(ctx,REDISMODULE_ERRORMSG_WRONGTYPE);
return RedisModule_ReplyWithError(ctx,VALKEYMODULE_ERRORMSG_WRONGTYPE);
}
if (keytype == REDISMODULE_KEYTYPE_STRING) {
if (keytype == VALKEYMODULE_KEYTYPE_STRING) {
size_t len, j;
char *s = RedisModule_StringDMA(key,&len,REDISMODULE_WRITE);
char *s = RedisModule_StringDMA(key,&len,VALKEYMODULE_WRITE);
for (j = 0; j < len; j++) {
if (isupper(s[j])) {
s[j] = tolower(s[j]);
@@ -340,7 +340,7 @@ int HelloToggleCase_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv,
RedisModule_CloseKey(key);
RedisModule_ReplyWithSimpleString(ctx,"OK");
RedisModule_ReplicateVerbatim(ctx);
return REDISMODULE_OK;
return VALKEYMODULE_OK;
}
/* HELLO.MORE.EXPIRE key milliseconds.
@@ -353,13 +353,13 @@ int HelloMoreExpire_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv,
mstime_t addms, expire;
if (RedisModule_StringToLongLong(argv[2],&addms) != REDISMODULE_OK)
if (RedisModule_StringToLongLong(argv[2],&addms) != VALKEYMODULE_OK)
return RedisModule_ReplyWithError(ctx,"ERR invalid expire time");
RedisModuleKey *key = RedisModule_OpenKey(ctx,argv[1],
REDISMODULE_READ|REDISMODULE_WRITE);
VALKEYMODULE_READ|VALKEYMODULE_WRITE);
expire = RedisModule_GetExpire(key);
if (expire != REDISMODULE_NO_EXPIRE) {
if (expire != VALKEYMODULE_NO_EXPIRE) {
expire += addms;
RedisModule_SetExpire(key,expire);
}
@@ -376,16 +376,16 @@ int HelloZsumRange_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, i
double score_start, score_end;
if (argc != 4) return RedisModule_WrongArity(ctx);
if (RedisModule_StringToDouble(argv[2],&score_start) != REDISMODULE_OK ||
RedisModule_StringToDouble(argv[3],&score_end) != REDISMODULE_OK)
if (RedisModule_StringToDouble(argv[2],&score_start) != VALKEYMODULE_OK ||
RedisModule_StringToDouble(argv[3],&score_end) != VALKEYMODULE_OK)
{
return RedisModule_ReplyWithError(ctx,"ERR invalid range");
}
RedisModuleKey *key = RedisModule_OpenKey(ctx,argv[1],
REDISMODULE_READ|REDISMODULE_WRITE);
if (RedisModule_KeyType(key) != REDISMODULE_KEYTYPE_ZSET) {
return RedisModule_ReplyWithError(ctx,REDISMODULE_ERRORMSG_WRONGTYPE);
VALKEYMODULE_READ|VALKEYMODULE_WRITE);
if (RedisModule_KeyType(key) != VALKEYMODULE_KEYTYPE_ZSET) {
return RedisModule_ReplyWithError(ctx,VALKEYMODULE_ERRORMSG_WRONGTYPE);
}
double scoresum_a = 0;
@@ -417,7 +417,7 @@ int HelloZsumRange_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, i
RedisModule_ReplyWithArray(ctx,2);
RedisModule_ReplyWithDouble(ctx,scoresum_a);
RedisModule_ReplyWithDouble(ctx,scoresum_b);
return REDISMODULE_OK;
return VALKEYMODULE_OK;
}
/* HELLO.LEXRANGE key min_lex max_lex min_age max_age
@@ -433,17 +433,17 @@ int HelloLexRange_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, in
if (argc != 6) return RedisModule_WrongArity(ctx);
RedisModuleKey *key = RedisModule_OpenKey(ctx,argv[1],
REDISMODULE_READ|REDISMODULE_WRITE);
if (RedisModule_KeyType(key) != REDISMODULE_KEYTYPE_ZSET) {
return RedisModule_ReplyWithError(ctx,REDISMODULE_ERRORMSG_WRONGTYPE);
VALKEYMODULE_READ|VALKEYMODULE_WRITE);
if (RedisModule_KeyType(key) != VALKEYMODULE_KEYTYPE_ZSET) {
return RedisModule_ReplyWithError(ctx,VALKEYMODULE_ERRORMSG_WRONGTYPE);
}
if (RedisModule_ZsetFirstInLexRange(key,argv[2],argv[3]) != REDISMODULE_OK) {
if (RedisModule_ZsetFirstInLexRange(key,argv[2],argv[3]) != VALKEYMODULE_OK) {
return RedisModule_ReplyWithError(ctx,"invalid range");
}
int arraylen = 0;
RedisModule_ReplyWithArray(ctx,REDISMODULE_POSTPONED_LEN);
RedisModule_ReplyWithArray(ctx,VALKEYMODULE_POSTPONED_LEN);
while(!RedisModule_ZsetRangeEndReached(key)) {
double score;
RedisModuleString *ele = RedisModule_ZsetRangeCurrentElement(key,&score);
@@ -455,7 +455,7 @@ int HelloLexRange_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, in
RedisModule_ZsetRangeStop(key);
RedisModule_ReplySetArrayLength(ctx,arraylen);
RedisModule_CloseKey(key);
return REDISMODULE_OK;
return VALKEYMODULE_OK;
}
/* HELLO.HCOPY key srcfield dstfield
@@ -470,22 +470,22 @@ int HelloHCopy_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int a
if (argc != 4) return RedisModule_WrongArity(ctx);
RedisModuleKey *key = RedisModule_OpenKey(ctx,argv[1],
REDISMODULE_READ|REDISMODULE_WRITE);
VALKEYMODULE_READ|VALKEYMODULE_WRITE);
int type = RedisModule_KeyType(key);
if (type != REDISMODULE_KEYTYPE_HASH &&
type != REDISMODULE_KEYTYPE_EMPTY)
if (type != VALKEYMODULE_KEYTYPE_HASH &&
type != VALKEYMODULE_KEYTYPE_EMPTY)
{
return RedisModule_ReplyWithError(ctx,REDISMODULE_ERRORMSG_WRONGTYPE);
return RedisModule_ReplyWithError(ctx,VALKEYMODULE_ERRORMSG_WRONGTYPE);
}
/* Get the old field value. */
RedisModuleString *oldval;
RedisModule_HashGet(key,REDISMODULE_HASH_NONE,argv[2],&oldval,NULL);
RedisModule_HashGet(key,VALKEYMODULE_HASH_NONE,argv[2],&oldval,NULL);
if (oldval) {
RedisModule_HashSet(key,REDISMODULE_HASH_NONE,argv[3],oldval,NULL);
RedisModule_HashSet(key,VALKEYMODULE_HASH_NONE,argv[3],oldval,NULL);
}
RedisModule_ReplyWithLongLong(ctx,oldval != NULL);
return REDISMODULE_OK;
return VALKEYMODULE_OK;
}
/* HELLO.LEFTPAD str len ch
@@ -512,7 +512,7 @@ int HelloLeftPad_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int
if (argc != 4) return RedisModule_WrongArity(ctx);
if ((RedisModule_StringToLongLong(argv[2],&padlen) != REDISMODULE_OK) ||
if ((RedisModule_StringToLongLong(argv[2],&padlen) != VALKEYMODULE_OK) ||
(padlen< 0)) {
return RedisModule_ReplyWithError(ctx,"ERR invalid padding length");
}
@@ -537,14 +537,14 @@ int HelloLeftPad_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int
memcpy(buf+padlen,str,strlen);
RedisModule_ReplyWithStringBuffer(ctx,buf,padlen+strlen);
return REDISMODULE_OK;
return VALKEYMODULE_OK;
}
/* This function must be present on each Redis module. It is used in order to
* register the commands into the Redis server. */
int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
if (RedisModule_Init(ctx,"helloworld",1,REDISMODULE_APIVER_1)
== REDISMODULE_ERR) return REDISMODULE_ERR;
if (RedisModule_Init(ctx,"helloworld",1,VALKEYMODULE_APIVER_1)
== VALKEYMODULE_ERR) return VALKEYMODULE_ERR;
/* Log the list of parameters passing loading the module. */
for (int j = 0; j < argc; j++) {
@@ -553,69 +553,69 @@ int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
}
if (RedisModule_CreateCommand(ctx,"hello.simple",
HelloSimple_RedisCommand,"readonly",0,0,0) == REDISMODULE_ERR)
return REDISMODULE_ERR;
HelloSimple_RedisCommand,"readonly",0,0,0) == VALKEYMODULE_ERR)
return VALKEYMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"hello.push.native",
HelloPushNative_RedisCommand,"write deny-oom",1,1,1) == REDISMODULE_ERR)
return REDISMODULE_ERR;
HelloPushNative_RedisCommand,"write deny-oom",1,1,1) == VALKEYMODULE_ERR)
return VALKEYMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"hello.push.call",
HelloPushCall_RedisCommand,"write deny-oom",1,1,1) == REDISMODULE_ERR)
return REDISMODULE_ERR;
HelloPushCall_RedisCommand,"write deny-oom",1,1,1) == VALKEYMODULE_ERR)
return VALKEYMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"hello.push.call2",
HelloPushCall2_RedisCommand,"write deny-oom",1,1,1) == REDISMODULE_ERR)
return REDISMODULE_ERR;
HelloPushCall2_RedisCommand,"write deny-oom",1,1,1) == VALKEYMODULE_ERR)
return VALKEYMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"hello.list.sum.len",
HelloListSumLen_RedisCommand,"readonly",1,1,1) == REDISMODULE_ERR)
return REDISMODULE_ERR;
HelloListSumLen_RedisCommand,"readonly",1,1,1) == VALKEYMODULE_ERR)
return VALKEYMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"hello.list.splice",
HelloListSplice_RedisCommand,"write deny-oom",1,2,1) == REDISMODULE_ERR)
return REDISMODULE_ERR;
HelloListSplice_RedisCommand,"write deny-oom",1,2,1) == VALKEYMODULE_ERR)
return VALKEYMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"hello.list.splice.auto",
HelloListSpliceAuto_RedisCommand,
"write deny-oom",1,2,1) == REDISMODULE_ERR)
return REDISMODULE_ERR;
"write deny-oom",1,2,1) == VALKEYMODULE_ERR)
return VALKEYMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"hello.rand.array",
HelloRandArray_RedisCommand,"readonly",0,0,0) == REDISMODULE_ERR)
return REDISMODULE_ERR;
HelloRandArray_RedisCommand,"readonly",0,0,0) == VALKEYMODULE_ERR)
return VALKEYMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"hello.repl1",
HelloRepl1_RedisCommand,"write",0,0,0) == REDISMODULE_ERR)
return REDISMODULE_ERR;
HelloRepl1_RedisCommand,"write",0,0,0) == VALKEYMODULE_ERR)
return VALKEYMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"hello.repl2",
HelloRepl2_RedisCommand,"write",1,1,1) == REDISMODULE_ERR)
return REDISMODULE_ERR;
HelloRepl2_RedisCommand,"write",1,1,1) == VALKEYMODULE_ERR)
return VALKEYMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"hello.toggle.case",
HelloToggleCase_RedisCommand,"write",1,1,1) == REDISMODULE_ERR)
return REDISMODULE_ERR;
HelloToggleCase_RedisCommand,"write",1,1,1) == VALKEYMODULE_ERR)
return VALKEYMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"hello.more.expire",
HelloMoreExpire_RedisCommand,"write",1,1,1) == REDISMODULE_ERR)
return REDISMODULE_ERR;
HelloMoreExpire_RedisCommand,"write",1,1,1) == VALKEYMODULE_ERR)
return VALKEYMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"hello.zsumrange",
HelloZsumRange_RedisCommand,"readonly",1,1,1) == REDISMODULE_ERR)
return REDISMODULE_ERR;
HelloZsumRange_RedisCommand,"readonly",1,1,1) == VALKEYMODULE_ERR)
return VALKEYMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"hello.lexrange",
HelloLexRange_RedisCommand,"readonly",1,1,1) == REDISMODULE_ERR)
return REDISMODULE_ERR;
HelloLexRange_RedisCommand,"readonly",1,1,1) == VALKEYMODULE_ERR)
return VALKEYMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"hello.hcopy",
HelloHCopy_RedisCommand,"write deny-oom",1,1,1) == REDISMODULE_ERR)
return REDISMODULE_ERR;
HelloHCopy_RedisCommand,"write deny-oom",1,1,1) == VALKEYMODULE_ERR)
return VALKEYMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"hello.leftpad",
HelloLeftPad_RedisCommand,"",1,1,1) == REDISMODULE_ERR)
return REDISMODULE_ERR;
HelloLeftPad_RedisCommand,"",1,1,1) == VALKEYMODULE_ERR)
return VALKEYMODULE_ERR;
return REDISMODULE_OK;
return VALKEYMODULE_OK;
}
+33 -12
View File
@@ -102,9 +102,22 @@ void linkClient(client *c) {
static void clientSetDefaultAuth(client *c) {
/* If the default user does not require authentication, the user is
* directly authenticated. */
c->user = DefaultUser;
c->authenticated = (c->user->flags & USER_FLAG_NOPASS) &&
!(c->user->flags & USER_FLAG_DISABLED);
clientSetUser(c, DefaultUser, (DefaultUser->flags & USER_FLAG_NOPASS) && !(DefaultUser->flags & USER_FLAG_DISABLED));
}
/* Attach the user u to this client.
* Also, mark the client authentication state. In case the client is marked as authenticated,
* it will also set the ever_authenticated flag on the client in order to avoid low level
* limiting of the client output buffer.*/
void clientSetUser(client *c, user *u, int authenticated) {
c->user = u;
c->authenticated = authenticated;
if (authenticated)
c->ever_authenticated = authenticated;
}
static int clientEverAuthenticated(client *c) {
return c->ever_authenticated;
}
int authRequired(client *c) {
@@ -170,6 +183,7 @@ client *createClient(connection *conn) {
c->ctime = c->lastinteraction = server.unixtime;
c->duration = 0;
clientSetDefaultAuth(c);
c->ever_authenticated = 0;
c->replstate = REPL_STATE_NONE;
c->repl_start_cmd_stream_on_ack = 0;
c->reploff = 0;
@@ -329,7 +343,8 @@ int prepareClientToWrite(client *c) {
REDIS_NO_SANITIZE("bounds")
size_t _addReplyToBuffer(client *c, const char *s, size_t len) {
size_t available = c->buf_usable_size - c->bufpos;
/* If the debug enforcing to use the reply list is enabled.*/
if (server.debug_client_enforce_reply_list) return 0;
/* If there already are entries in the reply list, we cannot
* add anything more to the static buffer. */
if (listLength(c->reply) > 0) return 0;
@@ -1291,8 +1306,8 @@ void clientAcceptHandler(connection *conn) {
}
server.stat_numconnections++;
moduleFireServerEvent(REDISMODULE_EVENT_CLIENT_CHANGE,
REDISMODULE_SUBEVENT_CLIENT_CHANGE_CONNECTED,
moduleFireServerEvent(VALKEYMODULE_EVENT_CLIENT_CHANGE,
VALKEYMODULE_SUBEVENT_CLIENT_CHANGE_CONNECTED,
c);
}
@@ -1555,8 +1570,8 @@ void freeClient(client *c) {
/* For connected clients, call the disconnection event of modules hooks. */
if (c->conn) {
moduleFireServerEvent(REDISMODULE_EVENT_CLIENT_CHANGE,
REDISMODULE_SUBEVENT_CLIENT_CHANGE_DISCONNECTED,
moduleFireServerEvent(VALKEYMODULE_EVENT_CLIENT_CHANGE,
VALKEYMODULE_SUBEVENT_CLIENT_CHANGE_DISCONNECTED,
c);
}
@@ -1669,8 +1684,8 @@ void freeClient(client *c) {
refreshGoodSlavesCount();
/* Fire the replica change modules event. */
if (c->replstate == SLAVE_STATE_ONLINE)
moduleFireServerEvent(REDISMODULE_EVENT_REPLICA_CHANGE,
REDISMODULE_SUBEVENT_REPLICA_CHANGE_OFFLINE,
moduleFireServerEvent(VALKEYMODULE_EVENT_REPLICA_CHANGE,
VALKEYMODULE_SUBEVENT_REPLICA_CHANGE_OFFLINE,
NULL);
}
@@ -2198,7 +2213,9 @@ int processInlineBuffer(client *c) {
/* Create redis objects for all arguments. */
for (c->argc = 0, j = 0; j < argc; j++) {
c->argv[c->argc] = createObject(OBJ_STRING,argv[j]);
/* Strings returned from sdssplitargs() may have unused capacity that we can trim. */
argv[j] = sdsRemoveFreeSpace(argv[j], 1);
c->argv[c->argc] = createObject(OBJ_STRING, argv[j]);
c->argc++;
c->argv_len_sum += sdslen(argv[j]);
}
@@ -3603,7 +3620,7 @@ void helloCommand(client *c) {
addReplyBulkCString(c,"redis");
addReplyBulkCString(c,"version");
addReplyBulkCString(c,REDIS_VERSION);
addReplyBulkCString(c,VALKEY_VERSION);
addReplyBulkCString(c,"proto");
addReplyLongLong(c,c->resp);
@@ -3852,6 +3869,10 @@ int checkClientOutputBufferLimits(client *c) {
int soft = 0, hard = 0, class;
unsigned long used_mem = getClientOutputBufferMemoryUsage(c);
/* For unauthenticated clients which were also never authenticated before the output buffer is limited to prevent
* them from abusing it by not reading the replies */
if (used_mem > REPLY_BUFFER_SIZE_UNAUTHENTICATED_CLIENT && authRequired(c) && !clientEverAuthenticated(c)) return 1;
class = getClientType(c);
/* For the purpose of output buffer limiting, masters are handled
* like normal clients. */
+20 -12
View File
@@ -1127,30 +1127,38 @@ size_t objectComputeSize(robj *key, robj *o, size_t sample_size, int dbid) {
* overhead of the pending entries in the groups and consumers
* PELs. */
if (s->cgroups) {
raxStart(&ri,s->cgroups);
raxSeek(&ri,"^",NULL,0);
while(raxNext(&ri)) {
raxStart(&ri, s->cgroups);
raxSeek(&ri, "^", NULL, 0);
samples = 0;
elesize = 0;
while (samples < sample_size && raxNext(&ri)) {
streamCG *cg = ri.data;
asize += sizeof(*cg);
asize += streamRadixTreeMemoryUsage(cg->pel);
asize += sizeof(streamNACK)*raxSize(cg->pel);
elesize += sizeof(*cg);
elesize += streamRadixTreeMemoryUsage(cg->pel);
elesize += sizeof(streamNACK) * raxSize(cg->pel);
/* For each consumer we also need to add the basic data
* structures and the PEL memory usage. */
raxIterator cri;
raxStart(&cri,cg->consumers);
raxSeek(&cri,"^",NULL,0);
while(raxNext(&cri)) {
raxStart(&cri, cg->consumers);
raxSeek(&cri, "^", NULL, 0);
size_t inner_samples = 0;
size_t inner_elesize = 0;
while (inner_samples < sample_size && raxNext(&cri)) {
streamConsumer *consumer = cri.data;
asize += sizeof(*consumer);
asize += sdslen(consumer->name);
asize += streamRadixTreeMemoryUsage(consumer->pel);
inner_elesize += sizeof(*consumer);
inner_elesize += sdslen(consumer->name);
inner_elesize += streamRadixTreeMemoryUsage(consumer->pel);
/* Don't count NACKs again, they are shared with the
* consumer group PEL. */
inner_samples++;
}
raxStop(&cri);
if (inner_samples) elesize += (double)inner_elesize / inner_samples * raxSize(cg->consumers);
samples++;
}
raxStop(&ri);
if (samples) asize += (double)elesize / samples * raxSize(s->cgroups);
}
} else if (o->type == OBJ_MODULE) {
asize = moduleGetMemUsage(key, o, sample_size, dbid);
+64 -18
View File
@@ -104,6 +104,9 @@ quicklistBookmark *_quicklistBookmarkFindByName(quicklist *ql, const char *name)
quicklistBookmark *_quicklistBookmarkFindByNode(quicklist *ql, quicklistNode *node);
void _quicklistBookmarkDelete(quicklist *ql, quicklistBookmark *bm);
quicklistNode *_quicklistSplitNode(quicklistNode *node, int offset, int after);
quicklistNode *_quicklistMergeNodes(quicklist *quicklist, quicklistNode *center);
/* Simple way to give quicklistEntry structs default values with one call. */
#define initEntry(e) \
do { \
@@ -378,6 +381,15 @@ REDIS_STATIC void __quicklistCompress(const quicklist *quicklist,
quicklistCompressNode(reverse);
}
/* This macro is used to compress a node.
*
* If the 'recompress' flag of the node is true, we compress it directly without
* checking whether it is within the range of compress depth.
* However, it's important to ensure that the 'recompress' flag of head and tail
* is always false, as we always assume that head and tail are not compressed.
*
* If the 'recompress' flag of the node is false, we check whether the node is
* within the range of compress depth before compressing it. */
#define quicklistCompress(_ql, _node) \
do { \
if ((_node)->recompress) \
@@ -529,19 +541,25 @@ REDIS_STATIC int _quicklistNodeAllowMerge(const quicklistNode *a,
(node)->sz = lpBytes((node)->entry); \
} while (0)
static quicklistNode* __quicklistCreatePlainNode(void *value, size_t sz) {
static quicklistNode* __quicklistCreateNode(int container, void *value, size_t sz) {
quicklistNode *new_node = quicklistCreateNode();
new_node->entry = zmalloc(sz);
new_node->container = QUICKLIST_NODE_CONTAINER_PLAIN;
memcpy(new_node->entry, value, sz);
new_node->container = container;
if (container == QUICKLIST_NODE_CONTAINER_PLAIN) {
new_node->entry = zmalloc(sz);
memcpy(new_node->entry, value, sz);
} else {
new_node->entry = lpPrepend(lpNew(0), value, sz);
}
new_node->sz = sz;
new_node->count++;
return new_node;
}
static void __quicklistInsertPlainNode(quicklist *quicklist, quicklistNode *old_node,
void *value, size_t sz, int after) {
__quicklistInsertNode(quicklist, old_node, __quicklistCreatePlainNode(value, sz), after);
void *value, size_t sz, int after)
{
quicklistNode *new_node = __quicklistCreateNode(QUICKLIST_NODE_CONTAINER_PLAIN, value, sz);
__quicklistInsertNode(quicklist, old_node, new_node, after);
quicklist->count++;
}
@@ -741,9 +759,13 @@ void quicklistReplaceEntry(quicklistIter *iter, quicklistEntry *entry,
void *data, size_t sz)
{
quicklist* quicklist = iter->quicklist;
quicklistNode *node = entry->node;
unsigned char *newentry;
if (likely(!QL_NODE_IS_PLAIN(entry->node) && !isLargeElement(sz))) {
entry->node->entry = lpReplace(entry->node->entry, &entry->zi, data, sz);
if (likely(!QL_NODE_IS_PLAIN(entry->node) && !isLargeElement(sz) &&
(newentry = lpReplace(entry->node->entry, &entry->zi, data, sz)) != NULL))
{
entry->node->entry = newentry;
quicklistNodeUpdateSz(entry->node);
/* quicklistNext() and quicklistGetIteratorEntryAtIdx() provide an uncompressed node */
quicklistCompress(quicklist, entry->node);
@@ -758,17 +780,37 @@ void quicklistReplaceEntry(quicklistIter *iter, quicklistEntry *entry,
quicklistInsertAfter(iter, entry, data, sz);
__quicklistDelNode(quicklist, entry->node);
}
} else {
entry->node->dont_compress = 1; /* Prevent compression in quicklistInsertAfter() */
quicklistInsertAfter(iter, entry, data, sz);
} else { /* The node is full or data is a large element */
quicklistNode *split_node = NULL, *new_node;
node->dont_compress = 1; /* Prevent compression in __quicklistInsertNode() */
/* If the entry is not at the tail, split the node at the entry's offset. */
if (entry->offset != node->count - 1 && entry->offset != -1)
split_node = _quicklistSplitNode(node, entry->offset, 1);
/* Create a new node and insert it after the original node.
* If the original node was split, insert the split node after the new node. */
new_node = __quicklistCreateNode(isLargeElement(sz) ?
QUICKLIST_NODE_CONTAINER_PLAIN : QUICKLIST_NODE_CONTAINER_PACKED, data, sz);
__quicklistInsertNode(quicklist, node, new_node, 1);
if (split_node) __quicklistInsertNode(quicklist, new_node, split_node, 1);
quicklist->count++;
/* Delete the replaced element. */
if (entry->node->count == 1) {
__quicklistDelNode(quicklist, entry->node);
} else {
unsigned char *p = lpSeek(entry->node->entry, -1);
quicklistDelIndex(quicklist, entry->node, &p);
entry->node->dont_compress = 0; /* Re-enable compression */
quicklistCompress(quicklist, entry->node);
quicklistCompress(quicklist, entry->node->next);
new_node = _quicklistMergeNodes(quicklist, new_node);
/* We can't know if the current node and its sibling nodes are correctly compressed,
* and we don't know if they are within the range of compress depth, so we need to
* use quicklistCompress() for compression, which checks if node is within compress
* depth before compressing. */
quicklistCompress(quicklist, new_node);
quicklistCompress(quicklist, new_node->prev);
if (new_node->next) quicklistCompress(quicklist, new_node->next);
}
}
@@ -826,6 +868,8 @@ REDIS_STATIC quicklistNode *_quicklistListpackMerge(quicklist *quicklist,
}
keep->count = lpLength(keep->entry);
quicklistNodeUpdateSz(keep);
keep->recompress = 0; /* Prevent 'keep' from being recompressed if
* it becomes head or tail after merging. */
nokeep->count = 0;
__quicklistDelNode(quicklist, nokeep);
@@ -844,9 +888,10 @@ REDIS_STATIC quicklistNode *_quicklistListpackMerge(quicklist *quicklist,
* - (center->next, center->next->next)
* - (center->prev, center)
* - (center, center->next)
*
* Returns the new 'center' after merging.
*/
REDIS_STATIC void _quicklistMergeNodes(quicklist *quicklist,
quicklistNode *center) {
REDIS_STATIC quicklistNode *_quicklistMergeNodes(quicklist *quicklist, quicklistNode *center) {
int fill = quicklist->fill;
quicklistNode *prev, *prev_prev, *next, *next_next, *target;
prev = prev_prev = next = next_next = target = NULL;
@@ -886,8 +931,9 @@ REDIS_STATIC void _quicklistMergeNodes(quicklist *quicklist,
/* Use result of center merge (or original) to merge with next node. */
if (_quicklistNodeAllowMerge(target, target->next, fill)) {
_quicklistListpackMerge(quicklist, target, target->next);
target = _quicklistListpackMerge(quicklist, target, target->next);
}
return target;
}
/* Split 'node' into two parts, parameterized by 'offset' and 'after'.
@@ -1002,7 +1048,7 @@ REDIS_STATIC void _quicklistInsert(quicklistIter *iter, quicklistEntry *entry,
} else {
quicklistDecompressNodeForUse(node);
new_node = _quicklistSplitNode(node, entry->offset, after);
quicklistNode *entry_node = __quicklistCreatePlainNode(value, sz);
quicklistNode *entry_node = __quicklistCreateNode(QUICKLIST_NODE_CONTAINER_PLAIN, value, sz);
__quicklistInsertNode(quicklist, node, entry_node, after);
__quicklistInsertNode(quicklist, entry_node, new_node, after);
quicklist->count++;
@@ -3224,7 +3270,7 @@ int quicklistTest(int argc, char *argv[], int flags) {
memcpy(s, "helloworld", 10);
memcpy(s + sz - 10, "1234567890", 10);
quicklistNode *node = __quicklistCreatePlainNode(s, sz);
quicklistNode *node = __quicklistCreateNode(QUICKLIST_NODE_CONTAINER_PLAIN, s, sz);
/* Just to avoid triggering the assertion in __quicklistCompressNode(),
* it disables the passing of quicklist head or tail node. */
+1
View File
@@ -1194,6 +1194,7 @@ int raxRemove(rax *rax, unsigned char *s, size_t len, void **old) {
memcpy(&h,cp,sizeof(h));
rax_free(tofree); rax->numnodes--;
if (h->iskey || (!h->iscompr && h->size != 1)) break;
if (comprsize + h->size > RAX_NODE_MAX_SIZE) break;
}
debugnode("New node",new);
+27 -24
View File
@@ -1079,7 +1079,7 @@ ssize_t rdbSaveObject(rio *rdb, robj *o, robj *key, int dbid) {
}
} else if (o->type == OBJ_MODULE) {
/* Save a module-specific value. */
RedisModuleIO io;
ValkeyModuleIO io;
moduleValue *mv = o->ptr;
moduleType *mt = mv->type;
@@ -1195,7 +1195,7 @@ int rdbSaveInfoAuxFields(rio *rdb, int rdbflags, rdbSaveInfo *rsi) {
int aof_base = (rdbflags & RDBFLAGS_AOF_PREAMBLE) != 0;
/* Add a few fields about the state when the RDB was created. */
if (rdbSaveAuxFieldStrStr(rdb,"redis-ver",REDIS_VERSION) == -1) return -1;
if (rdbSaveAuxFieldStrStr(rdb,"valkey-ver",VALKEY_VERSION) == -1) return -1;
if (rdbSaveAuxFieldStrInt(rdb,"redis-bits",redis_bits) == -1) return -1;
if (rdbSaveAuxFieldStrInt(rdb,"ctime",time(NULL)) == -1) return -1;
if (rdbSaveAuxFieldStrInt(rdb,"used-mem",zmalloc_used_memory()) == -1) return -1;
@@ -1215,7 +1215,7 @@ int rdbSaveInfoAuxFields(rio *rdb, int rdbflags, rdbSaveInfo *rsi) {
ssize_t rdbSaveSingleModuleAux(rio *rdb, int when, moduleType *mt) {
/* Save a module-specific aux value. */
RedisModuleIO io;
ValkeyModuleIO io;
int retval = 0;
moduleInitIOContext(io,mt,rdb,NULL,-1);
@@ -1384,7 +1384,7 @@ int rdbSaveRio(int req, rio *rdb, int *error, int rdbflags, rdbSaveInfo *rsi) {
snprintf(magic,sizeof(magic),"REDIS%04d",RDB_VERSION);
if (rdbWriteRaw(rdb,magic,9) == -1) goto werr;
if (rdbSaveInfoAuxFields(rdb,rdbflags,rsi) == -1) goto werr;
if (!(req & SLAVE_REQ_RDB_EXCLUDE_DATA) && rdbSaveModulesAux(rdb, REDISMODULE_AUX_BEFORE_RDB) == -1) goto werr;
if (!(req & SLAVE_REQ_RDB_EXCLUDE_DATA) && rdbSaveModulesAux(rdb, VALKEYMODULE_AUX_BEFORE_RDB) == -1) goto werr;
/* save functions */
if (!(req & SLAVE_REQ_RDB_EXCLUDE_FUNCTIONS) && rdbSaveFunctions(rdb) == -1) goto werr;
@@ -1396,7 +1396,7 @@ int rdbSaveRio(int req, rio *rdb, int *error, int rdbflags, rdbSaveInfo *rsi) {
}
}
if (!(req & SLAVE_REQ_RDB_EXCLUDE_DATA) && rdbSaveModulesAux(rdb, REDISMODULE_AUX_AFTER_RDB) == -1) goto werr;
if (!(req & SLAVE_REQ_RDB_EXCLUDE_DATA) && rdbSaveModulesAux(rdb, VALKEYMODULE_AUX_AFTER_RDB) == -1) goto werr;
/* EOF opcode */
if (rdbSaveType(rdb,RDB_OPCODE_EOF) == -1) goto werr;
@@ -2803,7 +2803,7 @@ robj *rdbLoadObject(int rdbtype, rio *rdb, sds key, int dbid, int *error) {
rdbReportCorruptRDB("The RDB file contains module data I can't load: no matching module type '%s'", name);
return NULL;
}
RedisModuleIO io;
ValkeyModuleIO io;
robj keyobj;
initStaticStringObject(keyobj,key);
moduleInitIOContext(io,mt,rdb,&keyobj,dbid);
@@ -2870,12 +2870,12 @@ void startLoading(size_t size, int rdbflags, int async) {
/* Fire the loading modules start event. */
int subevent;
if (rdbflags & RDBFLAGS_AOF_PREAMBLE)
subevent = REDISMODULE_SUBEVENT_LOADING_AOF_START;
subevent = VALKEYMODULE_SUBEVENT_LOADING_AOF_START;
else if(rdbflags & RDBFLAGS_REPLICATION)
subevent = REDISMODULE_SUBEVENT_LOADING_REPL_START;
subevent = VALKEYMODULE_SUBEVENT_LOADING_REPL_START;
else
subevent = REDISMODULE_SUBEVENT_LOADING_RDB_START;
moduleFireServerEvent(REDISMODULE_EVENT_LOADING,subevent,NULL);
subevent = VALKEYMODULE_SUBEVENT_LOADING_RDB_START;
moduleFireServerEvent(VALKEYMODULE_EVENT_LOADING,subevent,NULL);
}
/* Mark that we are loading in the global state and setup the fields
@@ -2913,10 +2913,10 @@ void stopLoading(int success) {
rdbFileBeingLoaded = NULL;
/* Fire the loading modules end event. */
moduleFireServerEvent(REDISMODULE_EVENT_LOADING,
moduleFireServerEvent(VALKEYMODULE_EVENT_LOADING,
success?
REDISMODULE_SUBEVENT_LOADING_ENDED:
REDISMODULE_SUBEVENT_LOADING_FAILED,
VALKEYMODULE_SUBEVENT_LOADING_ENDED:
VALKEYMODULE_SUBEVENT_LOADING_FAILED,
NULL);
}
@@ -2924,22 +2924,22 @@ void startSaving(int rdbflags) {
/* Fire the persistence modules start event. */
int subevent;
if (rdbflags & RDBFLAGS_AOF_PREAMBLE && getpid() != server.pid)
subevent = REDISMODULE_SUBEVENT_PERSISTENCE_AOF_START;
subevent = VALKEYMODULE_SUBEVENT_PERSISTENCE_AOF_START;
else if (rdbflags & RDBFLAGS_AOF_PREAMBLE)
subevent = REDISMODULE_SUBEVENT_PERSISTENCE_SYNC_AOF_START;
subevent = VALKEYMODULE_SUBEVENT_PERSISTENCE_SYNC_AOF_START;
else if (getpid()!=server.pid)
subevent = REDISMODULE_SUBEVENT_PERSISTENCE_RDB_START;
subevent = VALKEYMODULE_SUBEVENT_PERSISTENCE_RDB_START;
else
subevent = REDISMODULE_SUBEVENT_PERSISTENCE_SYNC_RDB_START;
moduleFireServerEvent(REDISMODULE_EVENT_PERSISTENCE,subevent,NULL);
subevent = VALKEYMODULE_SUBEVENT_PERSISTENCE_SYNC_RDB_START;
moduleFireServerEvent(VALKEYMODULE_EVENT_PERSISTENCE,subevent,NULL);
}
void stopSaving(int success) {
/* Fire the persistence modules end event. */
moduleFireServerEvent(REDISMODULE_EVENT_PERSISTENCE,
moduleFireServerEvent(VALKEYMODULE_EVENT_PERSISTENCE,
success?
REDISMODULE_SUBEVENT_PERSISTENCE_ENDED:
REDISMODULE_SUBEVENT_PERSISTENCE_FAILED,
VALKEYMODULE_SUBEVENT_PERSISTENCE_ENDED:
VALKEYMODULE_SUBEVENT_PERSISTENCE_FAILED,
NULL);
}
@@ -3138,7 +3138,10 @@ int rdbLoadRioWithLoadingCtx(rio *rdb, int rdbflags, rdbSaveInfo *rsi, rdbLoadin
} else if (!strcasecmp(auxkey->ptr,"lua")) {
/* Won't load the script back in memory anymore. */
} else if (!strcasecmp(auxkey->ptr,"redis-ver")) {
serverLog(LL_NOTICE,"Loading RDB produced by version %s",
serverLog(LL_NOTICE,"Loading RDB produced by Redis version %s",
(char*)auxval->ptr);
} else if (!strcasecmp(auxkey->ptr,"valkey-ver")) {
serverLog(LL_NOTICE,"Loading RDB produced by valkey version %s",
(char*)auxval->ptr);
} else if (!strcasecmp(auxkey->ptr,"ctime")) {
time_t age = time(NULL)-strtol(auxval->ptr,NULL,10);
@@ -3195,7 +3198,7 @@ int rdbLoadRioWithLoadingCtx(rio *rdb, int rdbflags, rdbSaveInfo *rsi, rdbLoadin
exit(1);
}
RedisModuleIO io;
ValkeyModuleIO io;
moduleInitIOContext(io,mt,rdb,NULL,-1);
/* Call the rdb_load method of the module providing the 10 bit
* encoding version in the lower 10 bits of the module ID. */
@@ -3204,7 +3207,7 @@ int rdbLoadRioWithLoadingCtx(rio *rdb, int rdbflags, rdbSaveInfo *rsi, rdbLoadin
moduleFreeContext(io.ctx);
zfree(io.ctx);
}
if (rc != REDISMODULE_OK || io.error) {
if (rc != VALKEYMODULE_OK || io.error) {
moduleTypeNameByID(name,moduleid);
serverLog(LL_WARNING,"The RDB file contains module AUX data for the module type '%s', that the responsible module is not able to load. Check for modules log above for additional clues.", name);
goto eoferr;
+1 -4
View File
@@ -81,9 +81,6 @@
#define RDB_TYPE_MODULE_PRE_GA 6 /* Used in 4.0 release candidates */
#define RDB_TYPE_MODULE_2 7 /* Module value with annotations for parsing without
the generating module being loaded. */
/* NOTE: WHEN ADDING NEW RDB TYPE, UPDATE rdbIsObjectType() BELOW */
/* Object types for encoded objects. */
#define RDB_TYPE_HASH_ZIPMAP 9
#define RDB_TYPE_LIST_ZIPLIST 10
#define RDB_TYPE_SET_INTSET 11
@@ -97,7 +94,7 @@
#define RDB_TYPE_STREAM_LISTPACKS_2 19
#define RDB_TYPE_SET_LISTPACK 20
#define RDB_TYPE_STREAM_LISTPACKS_3 21
/* NOTE: WHEN ADDING NEW RDB TYPE, UPDATE rdbIsObjectType() BELOW */
/* NOTE: WHEN ADDING NEW RDB TYPE, UPDATE rdbIsObjectType(), and rdb_type_string[] */
/* Test if a type is an object type. */
#define rdbIsObjectType(t) (((t) >= 0 && (t) <= 7) || ((t) >= 9 && (t) <= 21))
+712 -1674
View File
File diff suppressed because it is too large Load Diff
+27 -26
View File
@@ -821,8 +821,8 @@ int masterTryPartialResynchronization(client *c, long long psync_offset) {
refreshGoodSlavesCount();
/* Fire the replica change modules event. */
moduleFireServerEvent(REDISMODULE_EVENT_REPLICA_CHANGE,
REDISMODULE_SUBEVENT_REPLICA_CHANGE_ONLINE,
moduleFireServerEvent(VALKEYMODULE_EVENT_REPLICA_CHANGE,
VALKEYMODULE_SUBEVENT_REPLICA_CHANGE_ONLINE,
NULL);
return C_OK; /* The caller can return, no full resync needed. */
@@ -1304,8 +1304,8 @@ int replicaPutOnline(client *slave) {
refreshGoodSlavesCount();
/* Fire the replica change modules event. */
moduleFireServerEvent(REDISMODULE_EVENT_REPLICA_CHANGE,
REDISMODULE_SUBEVENT_REPLICA_CHANGE_ONLINE,
moduleFireServerEvent(VALKEYMODULE_EVENT_REPLICA_CHANGE,
VALKEYMODULE_SUBEVENT_REPLICA_CHANGE_ONLINE,
NULL);
serverLog(LL_NOTICE,"Synchronization with replica %s succeeded",
replicationGetSlaveName(slave));
@@ -1777,7 +1777,7 @@ void replicationCreateMasterClient(connection *conn, int dbid) {
* connection. */
server.master->flags |= CLIENT_MASTER;
server.master->authenticated = 1;
clientSetUser(server.master, NULL, 1);
server.master->reploff = server.master_initial_offset;
server.master->read_reploff = server.master->reploff;
server.master->user = NULL; /* This client can do everything. */
@@ -2064,8 +2064,8 @@ void readSyncBulkPayload(connection *conn) {
diskless_load_tempDb = disklessLoadInitTempDb();
temp_functions_lib_ctx = functionsLibCtxCreate();
moduleFireServerEvent(REDISMODULE_EVENT_REPL_ASYNC_LOAD,
REDISMODULE_SUBEVENT_REPL_ASYNC_LOAD_STARTED,
moduleFireServerEvent(VALKEYMODULE_EVENT_REPL_ASYNC_LOAD,
VALKEYMODULE_SUBEVENT_REPL_ASYNC_LOAD_STARTED,
NULL);
} else {
replicationAttachToNewMaster();
@@ -2138,8 +2138,8 @@ void readSyncBulkPayload(connection *conn) {
if (server.repl_diskless_load == REPL_DISKLESS_LOAD_SWAPDB) {
/* Discard potentially partially loaded tempDb. */
moduleFireServerEvent(REDISMODULE_EVENT_REPL_ASYNC_LOAD,
REDISMODULE_SUBEVENT_REPL_ASYNC_LOAD_ABORTED,
moduleFireServerEvent(VALKEYMODULE_EVENT_REPL_ASYNC_LOAD,
VALKEYMODULE_SUBEVENT_REPL_ASYNC_LOAD_ABORTED,
NULL);
disklessLoadDiscardTempDb(diskless_load_tempDb);
@@ -2169,8 +2169,8 @@ void readSyncBulkPayload(connection *conn) {
/* swap existing functions ctx with the temporary one */
functionsLibCtxSwapWithCurrent(temp_functions_lib_ctx);
moduleFireServerEvent(REDISMODULE_EVENT_REPL_ASYNC_LOAD,
REDISMODULE_SUBEVENT_REPL_ASYNC_LOAD_COMPLETED,
moduleFireServerEvent(VALKEYMODULE_EVENT_REPL_ASYNC_LOAD,
VALKEYMODULE_SUBEVENT_REPL_ASYNC_LOAD_COMPLETED,
NULL);
/* Delete the old db as it's useless now. */
@@ -2250,6 +2250,7 @@ void readSyncBulkPayload(connection *conn) {
}
zfree(server.repl_transfer_tmpfile);
close(server.repl_transfer_fd);
server.repl_transfer_fd = -1;
server.repl_transfer_tmpfile = NULL;
}
@@ -2260,8 +2261,8 @@ void readSyncBulkPayload(connection *conn) {
server.repl_down_since = 0;
/* Fire the master link modules event. */
moduleFireServerEvent(REDISMODULE_EVENT_MASTER_LINK_CHANGE,
REDISMODULE_SUBEVENT_MASTER_LINK_UP,
moduleFireServerEvent(VALKEYMODULE_EVENT_PRIMARY_LINK_CHANGE,
VALKEYMODULE_SUBEVENT_PRIMARY_LINK_UP,
NULL);
/* After a full resynchronization we use the replication ID and
@@ -3035,14 +3036,14 @@ void replicationSetMaster(char *ip, int port) {
}
/* Fire the role change modules event. */
moduleFireServerEvent(REDISMODULE_EVENT_REPLICATION_ROLE_CHANGED,
REDISMODULE_EVENT_REPLROLECHANGED_NOW_REPLICA,
moduleFireServerEvent(VALKEYMODULE_EVENT_REPLICATION_ROLE_CHANGED,
VALKEYMODULE_EVENT_REPLROLECHANGED_NOW_REPLICA,
NULL);
/* Fire the master link modules event. */
if (server.repl_state == REPL_STATE_CONNECTED)
moduleFireServerEvent(REDISMODULE_EVENT_MASTER_LINK_CHANGE,
REDISMODULE_SUBEVENT_MASTER_LINK_DOWN,
moduleFireServerEvent(VALKEYMODULE_EVENT_PRIMARY_LINK_CHANGE,
VALKEYMODULE_SUBEVENT_PRIMARY_LINK_DOWN,
NULL);
server.repl_state = REPL_STATE_CONNECT;
@@ -3057,8 +3058,8 @@ void replicationUnsetMaster(void) {
/* Fire the master link modules event. */
if (server.repl_state == REPL_STATE_CONNECTED)
moduleFireServerEvent(REDISMODULE_EVENT_MASTER_LINK_CHANGE,
REDISMODULE_SUBEVENT_MASTER_LINK_DOWN,
moduleFireServerEvent(VALKEYMODULE_EVENT_PRIMARY_LINK_CHANGE,
VALKEYMODULE_SUBEVENT_PRIMARY_LINK_DOWN,
NULL);
/* Clear masterhost first, since the freeClient calls
@@ -3099,8 +3100,8 @@ void replicationUnsetMaster(void) {
server.repl_down_since = 0;
/* Fire the role change modules event. */
moduleFireServerEvent(REDISMODULE_EVENT_REPLICATION_ROLE_CHANGED,
REDISMODULE_EVENT_REPLROLECHANGED_NOW_MASTER,
moduleFireServerEvent(VALKEYMODULE_EVENT_REPLICATION_ROLE_CHANGED,
VALKEYMODULE_EVENT_REPLROLECHANGED_NOW_PRIMARY,
NULL);
/* Restart the AOF subsystem in case we shut it down during a sync when
@@ -3113,8 +3114,8 @@ void replicationUnsetMaster(void) {
void replicationHandleMasterDisconnection(void) {
/* Fire the master link modules event. */
if (server.repl_state == REPL_STATE_CONNECTED)
moduleFireServerEvent(REDISMODULE_EVENT_MASTER_LINK_CHANGE,
REDISMODULE_SUBEVENT_MASTER_LINK_DOWN,
moduleFireServerEvent(VALKEYMODULE_EVENT_PRIMARY_LINK_CHANGE,
VALKEYMODULE_SUBEVENT_PRIMARY_LINK_DOWN,
NULL);
server.master = NULL;
@@ -3396,14 +3397,14 @@ void replicationResurrectCachedMaster(connection *conn) {
server.master->conn = conn;
connSetPrivateData(server.master->conn, server.master);
server.master->flags &= ~(CLIENT_CLOSE_AFTER_REPLY|CLIENT_CLOSE_ASAP);
server.master->authenticated = 1;
clientSetUser(server.master, NULL, 1);
server.master->lastinteraction = server.unixtime;
server.repl_state = REPL_STATE_CONNECTED;
server.repl_down_since = 0;
/* Fire the master link modules event. */
moduleFireServerEvent(REDISMODULE_EVENT_MASTER_LINK_CHANGE,
REDISMODULE_SUBEVENT_MASTER_LINK_UP,
moduleFireServerEvent(VALKEYMODULE_EVENT_PRIMARY_LINK_CHANGE,
VALKEYMODULE_SUBEVENT_PRIMARY_LINK_UP,
NULL);
/* Re-add to the list of clients. */
+42 -7
View File
@@ -56,7 +56,8 @@ static char *libraries_allow_list[] = {
/* Redis Lua API globals */
static char *redis_api_allow_list[] = {
"redis",
SERVER_API_NAME,
REDIS_API_NAME,
"__redis__err__handler", /* error handler for eval, currently located on globals.
Should move to registry. */
NULL,
@@ -818,8 +819,17 @@ static robj **luaArgsToRedisArgv(lua_State *lua, int *argc, int *argv_len) {
/* We can't use lua_tolstring() for number -> string conversion
* since Lua uses a format specifier that loses precision. */
lua_Number num = lua_tonumber(lua,j+1);
obj_len = fpconv_dtoa((double)num, dbuf);
dbuf[obj_len] = '\0';
/* Integer printing function is much faster, check if we can safely use it.
* Since lua_Number is not explicitly an integer or a double, we need to make an effort
* to convert it as an integer when that's possible, since the string could later be used
* in a context that doesn't support scientific notation (e.g. 1e9 instead of 100000000). */
long long lvalue;
if (double2ll((double)num, &lvalue))
obj_len = ll2string(dbuf, sizeof(dbuf), lvalue);
else {
obj_len = fpconv_dtoa((double)num, dbuf);
dbuf[obj_len] = '\0';
}
obj_s = dbuf;
} else {
obj_s = (char*)lua_tolstring(lua,j+1,&obj_len);
@@ -1373,6 +1383,7 @@ void luaSetTableProtectionRecursively(lua_State *lua) {
}
void luaRegisterVersion(lua_State* lua) {
/* For legacy compatibility reasons include Redis versions. */
lua_pushstring(lua,"REDIS_VERSION_NUM");
lua_pushnumber(lua,REDIS_VERSION_NUM);
lua_settable(lua,-3);
@@ -1380,6 +1391,19 @@ void luaRegisterVersion(lua_State* lua) {
lua_pushstring(lua,"REDIS_VERSION");
lua_pushstring(lua,REDIS_VERSION);
lua_settable(lua,-3);
/* Now push the Valkey version information. */
lua_pushstring(lua,"VALKEY_VERSION_NUM");
lua_pushnumber(lua,VALKEY_VERSION_NUM);
lua_settable(lua,-3);
lua_pushstring(lua,"VALKEY_VERSION");
lua_pushstring(lua,VALKEY_VERSION);
lua_settable(lua,-3);
lua_pushstring(lua,"SERVER_NAME");
lua_pushstring(lua,SERVER_NAME);
lua_settable(lua,-3);
}
void luaRegisterLogFunction(lua_State* lua) {
@@ -1480,9 +1504,14 @@ void luaRegisterRedisAPI(lua_State* lua) {
lua_pushcfunction(lua,luaRedisAclCheckCmdPermissionsCommand);
lua_settable(lua,-3);
/* Finally set the table as 'redis' global var. */
/* Finally set the table as 'server' global var.
* We will also alias it to 'redis' global var for backwards compatibility. */
lua_setglobal(lua,SERVER_API_NAME);
/* lua_getglobal invocation retrieves the 'server' variable value to the stack.
* lua_setglobal invocation uses the value from stack to set 'redis' global variable.
* This is not a deep copy but is enough for our purpose here. */
lua_getglobal(lua,SERVER_API_NAME);
lua_setglobal(lua,REDIS_API_NAME);
/* Replace math.random and math.randomseed with our implementations. */
lua_getglobal(lua,"math");
@@ -1558,7 +1587,13 @@ static void luaMaskCountHook(lua_State *lua, lua_Debug *ar) {
scriptRunCtx* rctx = luaGetFromRegistry(lua, REGISTRY_RUN_CTX_NAME);
serverAssert(rctx); /* Only supported inside script invocation */
if (scriptInterrupt(rctx) == SCRIPT_KILL) {
serverLog(LL_NOTICE,"Lua script killed by user with SCRIPT KILL.");
char *err = NULL;
if (rctx->flags & SCRIPT_EVAL_MODE) {
err = "Script killed by user with SCRIPT KILL.";
} else {
err = "Script killed by user with FUNCTION KILL.";
}
serverLog(LL_NOTICE, "%s", err);
/*
* Set the hook to invoke all the time so the user
@@ -1567,7 +1602,7 @@ static void luaMaskCountHook(lua_State *lua, lua_Debug *ar) {
*/
lua_sethook(lua, luaMaskCountHook, LUA_MASKLINE, 0);
luaPushError(lua,"Script killed by user with SCRIPT KILL...");
luaPushError(lua, err);
luaError(lua);
}
}
+1
View File
@@ -57,6 +57,7 @@
#define REGISTRY_RUN_CTX_NAME "__RUN_CTX__"
#define REGISTRY_SET_GLOBALS_PROTECTION_NAME "__GLOBAL_PROTECTION__"
#define REDIS_API_NAME "redis"
#define SERVER_API_NAME "server"
typedef struct errorInfo {
sds msg;
+15 -13
View File
@@ -349,20 +349,22 @@ sds sdsResize(sds s, size_t size, int would_regrow) {
* type. */
int use_realloc = (oldtype==type || (type < oldtype && type > SDS_TYPE_8));
size_t newlen = use_realloc ? oldhdrlen+size+1 : hdrlen+size+1;
int alloc_already_optimal = 0;
#if defined(USE_JEMALLOC)
/* je_nallocx returns the expected allocation size for the newlen.
* We aim to avoid calling realloc() when using Jemalloc if there is no
* change in the allocation size, as it incurs a cost even if the
* allocation size stays the same. */
alloc_already_optimal = (je_nallocx(newlen, 0) == zmalloc_size(sh));
#endif
if (use_realloc && !alloc_already_optimal) {
newsh = s_realloc(sh, newlen);
if (newsh == NULL) return NULL;
s = (char*)newsh+oldhdrlen;
} else if (!alloc_already_optimal) {
if (use_realloc) {
int alloc_already_optimal = 0;
#if defined(USE_JEMALLOC)
/* je_nallocx returns the expected allocation size for the newlen.
* We aim to avoid calling realloc() when using Jemalloc if there is no
* change in the allocation size, as it incurs a cost even if the
* allocation size stays the same. */
alloc_already_optimal = (je_nallocx(newlen, 0) == zmalloc_size(sh));
#endif
if (!alloc_already_optimal) {
newsh = s_realloc(sh, newlen);
if (newsh == NULL) return NULL;
s = (char*)newsh+oldhdrlen;
}
} else {
newsh = s_malloc(newlen);
if (newsh == NULL) return NULL;
memcpy((char*)newsh+hdrlen, s, len);
+1 -2
View File
@@ -1846,8 +1846,7 @@ void loadSentinelConfigFromQueue(void) {
return;
loaderr:
fprintf(stderr, "\n*** FATAL CONFIG FILE ERROR (Redis %s) ***\n",
REDIS_VERSION);
fprintf(stderr, "\n*** FATAL CONFIG FILE ERROR (Version %s) ***\n", VALKEY_VERSION);
fprintf(stderr, "Reading the configuration file, at line %d\n", linenum);
fprintf(stderr, ">>> '%s'\n", line);
fprintf(stderr, "%s\n", err);
+69 -45
View File
@@ -532,7 +532,7 @@ dictType keylistDictType = {
};
/* Modules system dictionary type. Keys are module name,
* values are pointer to RedisModule struct. */
* values are pointer to ValkeyModule struct. */
dictType modulesDictType = {
dictSdsCaseHash, /* hash function */
NULL, /* key dup */
@@ -671,8 +671,8 @@ void resetChildState(void) {
server.stat_current_save_keys_total = 0;
updateDictResizePolicy();
closeChildInfoPipe();
moduleFireServerEvent(REDISMODULE_EVENT_FORK_CHILD,
REDISMODULE_SUBEVENT_FORK_CHILD_DIED,
moduleFireServerEvent(VALKEYMODULE_EVENT_FORK_CHILD,
VALKEYMODULE_SUBEVENT_FORK_CHILD_DIED,
NULL);
}
@@ -1514,8 +1514,8 @@ int serverCron(struct aeEventLoop *eventLoop, long long id, void *clientData) {
}
/* Fire the cron loop modules event. */
RedisModuleCronLoopV1 ei = {REDISMODULE_CRON_LOOP_VERSION,server.hz};
moduleFireServerEvent(REDISMODULE_EVENT_CRON_LOOP,
ValkeyModuleCronLoopV1 ei = {VALKEYMODULE_CRON_LOOP_VERSION,server.hz};
moduleFireServerEvent(VALKEYMODULE_EVENT_CRON_LOOP,
0,
&ei);
@@ -1677,8 +1677,8 @@ void beforeSleep(struct aeEventLoop *eventLoop) {
activeExpireCycle(ACTIVE_EXPIRE_CYCLE_FAST);
if (moduleCount()) {
moduleFireServerEvent(REDISMODULE_EVENT_EVENTLOOP,
REDISMODULE_SUBEVENT_EVENTLOOP_BEFORE_SLEEP,
moduleFireServerEvent(VALKEYMODULE_EVENT_EVENTLOOP,
VALKEYMODULE_SUBEVENT_EVENTLOOP_BEFORE_SLEEP,
NULL);
}
@@ -1794,8 +1794,8 @@ void afterSleep(struct aeEventLoop *eventLoop) {
latencyStartMonitor(latency);
moduleAcquireGIL();
moduleFireServerEvent(REDISMODULE_EVENT_EVENTLOOP,
REDISMODULE_SUBEVENT_EVENTLOOP_AFTER_SLEEP,
moduleFireServerEvent(VALKEYMODULE_EVENT_EVENTLOOP,
VALKEYMODULE_SUBEVENT_EVENTLOOP_AFTER_SLEEP,
NULL);
latencyEndMonitor(latency);
latencyAddSampleIfNeeded("module-acquire-GIL",latency);
@@ -2118,7 +2118,7 @@ void initServerConfig(void) {
/* Command table -- we initialize it here as it is part of the
* initial configuration, since command names may be changed via
* redis.conf using the rename-command directive. */
* valkey.conf using the rename-command directive. */
server.commands = dictCreate(&commandTableDictType);
server.orig_commands = dictCreate(&commandTableDictType);
populateCommandTable();
@@ -2607,6 +2607,7 @@ void initServer(void) {
server.reply_buffer_peak_reset_time = REPLY_BUFFER_DEFAULT_PEAK_RESET_TIME;
server.reply_buffer_resizing_enabled = 1;
server.client_mem_usage_buckets = NULL;
server.debug_client_enforce_reply_list = 0;
resetReplicationBuffer();
/* Make sure the locale is set on startup based on the config file. */
@@ -3039,7 +3040,7 @@ void populateCommandTable(void) {
retval1 = dictAdd(server.commands, sdsdup(c->fullname), c);
/* Populate an additional dictionary that will be unaffected
* by rename-command statements in redis.conf. */
* by rename-command statements in valkey.conf. */
retval2 = dictAdd(server.orig_commands, sdsdup(c->fullname), c);
serverAssert(retval1 == DICT_OK && retval2 == DICT_OK);
}
@@ -3193,7 +3194,7 @@ struct redisCommand *lookupCommandByCString(const char *s) {
/* Lookup the command in the current table, if not found also check in
* the original table containing the original command names unaffected by
* redis.conf rename-command statement.
* valkey.conf rename-command statement.
*
* This is used by functions rewriting the argument vector such as
* rewriteClientCommandVector() in order to set client->cmd pointer
@@ -3512,12 +3513,20 @@ void call(client *c, int flags) {
* re-processing and unblock the client.*/
c->flags |= CLIENT_EXECUTING_COMMAND;
/* Setting the CLIENT_REPROCESSING_COMMAND flag so that during the actual
* processing of the command proc, the client is aware that it is being
* re-processed. */
if (reprocessing_command) c->flags |= CLIENT_REPROCESSING_COMMAND;
monotime monotonic_start = 0;
if (monotonicGetType() == MONOTONIC_CLOCK_HW)
monotonic_start = getMonotonicUs();
c->cmd->proc(c);
/* Clear the CLIENT_REPROCESSING_COMMAND flag after the proc is executed. */
if (reprocessing_command) c->flags &= ~CLIENT_REPROCESSING_COMMAND;
exitExecutionUnit();
/* In case client is blocked after trying to execute the command,
@@ -3575,7 +3584,7 @@ void call(client *c, int flags) {
/* Send the command to clients in MONITOR mode if applicable,
* since some administrative commands are considered too dangerous to be shown.
* Other exceptions is a client which is unblocked and retring to process the command
* Other exceptions is a client which is unblocked and retrying to process the command
* or we are currently in the process of loading AOF. */
if (update_command_stats && !reprocessing_command &&
!(c->cmd->flags & (CMD_SKIP_MONITOR|CMD_ADMIN))) {
@@ -3952,7 +3961,8 @@ int processCommand(client *c) {
} else {
flagTransaction(c);
}
clusterRedirectClient(c,n,c->slot,error_code);
clusterRedirectClient(c, n, c->slot, error_code);
c->duration = 0;
c->cmd->rejected_calls++;
return C_OK;
}
@@ -4424,7 +4434,7 @@ int finishShutdown(void) {
if (server.aof_manifest) aofManifestFree(server.aof_manifest);
/* Fire the shutdown modules event. */
moduleFireServerEvent(REDISMODULE_EVENT_SHUTDOWN,0,NULL);
moduleFireServerEvent(VALKEYMODULE_EVENT_SHUTDOWN,0,NULL);
/* Remove the pid file if possible and needed. */
if (server.daemonize || server.pidfile) {
@@ -4448,7 +4458,7 @@ int finishShutdown(void) {
serverLog(LL_WARNING,"%s is now ready to exit, bye bye...",
server.sentinel_mode ? "Sentinel" : "Redis");
server.sentinel_mode ? "Sentinel" : "Valkey");
return C_OK;
error:
@@ -5489,6 +5499,8 @@ sds genRedisInfoString(dict *section_dict, int all_sections, int everything) {
info = sdscatfmt(info,
"# Server\r\n"
"redis_version:%s\r\n"
"server_name:%s\r\n"
"valkey_version:%s\r\n"
"redis_git_sha1:%s\r\n"
"redis_git_dirty:%i\r\n"
"redis_build_id:%s\r\n"
@@ -5513,6 +5525,8 @@ sds genRedisInfoString(dict *section_dict, int all_sections, int everything) {
"config_file:%s\r\n"
"io_threads_active:%i\r\n",
REDIS_VERSION,
SERVER_NAME,
VALKEY_VERSION,
redisGitSHA1(),
strtol(redisGitDirty(),NULL,10) > 0,
redisBuildIdString(),
@@ -6376,8 +6390,8 @@ void daemonize(void) {
}
void version(void) {
printf("Redis server v=%s sha=%s:%d malloc=%s bits=%d build=%llx\n",
REDIS_VERSION,
printf("Server v=%s sha=%s:%d malloc=%s bits=%d build=%llx\n",
VALKEY_VERSION,
redisGitSHA1(),
atoi(redisGitDirty()) > 0,
ZMALLOC_LIB,
@@ -6387,23 +6401,23 @@ void version(void) {
}
void usage(void) {
fprintf(stderr,"Usage: ./redis-server [/path/to/redis.conf] [options] [-]\n");
fprintf(stderr," ./redis-server - (read config from stdin)\n");
fprintf(stderr," ./redis-server -v or --version\n");
fprintf(stderr," ./redis-server -h or --help\n");
fprintf(stderr," ./redis-server --test-memory <megabytes>\n");
fprintf(stderr," ./redis-server --check-system\n");
fprintf(stderr,"Usage: ./valkey-server [/path/to/valkey.conf] [options] [-]\n");
fprintf(stderr," ./valkey-server - (read config from stdin)\n");
fprintf(stderr," ./valkey-server -v or --version\n");
fprintf(stderr," ./valkey-server -h or --help\n");
fprintf(stderr," ./valkey-server --test-memory <megabytes>\n");
fprintf(stderr," ./valkey-server --check-system\n");
fprintf(stderr,"\n");
fprintf(stderr,"Examples:\n");
fprintf(stderr," ./redis-server (run the server with default conf)\n");
fprintf(stderr," echo 'maxmemory 128mb' | ./redis-server -\n");
fprintf(stderr," ./redis-server /etc/redis/6379.conf\n");
fprintf(stderr," ./redis-server --port 7777\n");
fprintf(stderr," ./redis-server --port 7777 --replicaof 127.0.0.1 8888\n");
fprintf(stderr," ./redis-server /etc/myredis.conf --loglevel verbose -\n");
fprintf(stderr," ./redis-server /etc/myredis.conf --loglevel verbose\n\n");
fprintf(stderr," ./valkey-server (run the server with default conf)\n");
fprintf(stderr," echo 'maxmemory 128mb' | ./valkey-server -\n");
fprintf(stderr," ./valkey-server /etc/valkey/6379.conf\n");
fprintf(stderr," ./valkey-server --port 7777\n");
fprintf(stderr," ./valkey-server --port 7777 --replicaof 127.0.0.1 8888\n");
fprintf(stderr," ./valkey-server /etc/myvalkey.conf --loglevel verbose -\n");
fprintf(stderr," ./valkey-server /etc/myvalkey.conf --loglevel verbose\n\n");
fprintf(stderr,"Sentinel mode:\n");
fprintf(stderr," ./redis-server /etc/sentinel.conf --sentinel\n");
fprintf(stderr," ./valkey-server /etc/sentinel.conf --sentinel\n");
exit(1);
}
@@ -6418,7 +6432,7 @@ void redisAsciiArt(void) {
/* Show the ASCII logo if: log file is stdout AND stdout is a
* tty AND syslog logging is disabled. Also show logo if the user
* forced us to do so via redis.conf. */
* forced us to do so via valkey.conf. */
int show_logo = ((!server.syslog_enabled &&
server.logfile[0] == '\0' &&
isatty(fileno(stdout))) ||
@@ -6431,7 +6445,7 @@ void redisAsciiArt(void) {
);
} else {
snprintf(buf,1024*16,ascii_logo,
REDIS_VERSION,
VALKEY_VERSION,
redisGitSHA1(),
strtol(redisGitDirty(),NULL,10) > 0,
(sizeof(long) == 8) ? "64" : "32",
@@ -6648,8 +6662,8 @@ int redisFork(int purpose) {
}
updateDictResizePolicy();
moduleFireServerEvent(REDISMODULE_EVENT_FORK_CHILD,
REDISMODULE_SUBEVENT_FORK_CHILD_BORN,
moduleFireServerEvent(VALKEYMODULE_EVENT_FORK_CHILD,
VALKEYMODULE_SUBEVENT_FORK_CHILD_BORN,
NULL);
}
return childpid;
@@ -6748,9 +6762,12 @@ void dismissMemoryInChild(void) {
void memtest(size_t megabytes, int passes);
/* Returns 1 if there is --sentinel among the arguments or if
* executable name contains "redis-sentinel". */
* executable name contains "valkey-sentinel". */
int checkForSentinelMode(int argc, char **argv, char *exec_name) {
if (strstr(exec_name,"redis-sentinel") != NULL) return 1;
if (strstr(exec_name,"valkey-sentinel") != NULL) return 1;
/* valkey may install symlinks like redis-sentinel -> valkey-sentinel. */
if (strstr(exec_name, "redis-sentinel") != NULL) return 1;
for (int j = 1; j < argc; j++)
if (!strcmp(argv[j],"--sentinel")) return 1;
@@ -6836,7 +6853,7 @@ void redisOutOfMemoryHandler(size_t allocation_size) {
allocation_size);
}
/* Callback for sdstemplate on proc-title-template. See redis.conf for
/* Callback for sdstemplate on proc-title-template. See valkey.conf for
* supported variables.
*/
static sds redisProcTitleGetVariable(const sds varname, void *arg)
@@ -7129,8 +7146,16 @@ int main(int argc, char **argv) {
/* Check if we need to start in redis-check-rdb/aof mode. We just execute
* the program main. However the program is part of the Redis executable
* so that we can easily execute an RDB check on loading errors. */
if (strstr(exec_name,"redis-check-rdb") != NULL)
if (strstr(exec_name,"valkey-check-rdb") != NULL)
redis_check_rdb_main(argc,argv,NULL);
else if (strstr(exec_name,"valkey-check-aof") != NULL)
redis_check_aof_main(argc,argv);
/* valkey may install symlinks like
* redis-server -> valkey-server, redis-check-rdb -> valkey-check-rdb,
* redis-check-aof -> valkey-check-aof, etc. */
if (strstr(exec_name,"redis-check-rdb") != NULL)
redis_check_rdb_main(argc, argv, NULL);
else if (strstr(exec_name,"redis-check-aof") != NULL)
redis_check_aof_main(argc,argv);
@@ -7280,17 +7305,16 @@ int main(int argc, char **argv) {
int background = server.daemonize && !server.supervised;
if (background) daemonize();
serverLog(LL_NOTICE, "oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo");
serverLog(LL_NOTICE,
"Redis version=%s, bits=%d, commit=%s, modified=%d, pid=%d, just started",
REDIS_VERSION,
serverLog(LL_NOTICE, "oO0OoO0OoO0Oo Valkey is starting oO0OoO0OoO0Oo");
serverLog(LL_NOTICE, "Valkey version=%s, bits=%d, commit=%s, modified=%d, pid=%d, just started",
VALKEY_VERSION,
(sizeof(long) == 8) ? 64 : 32,
redisGitSHA1(),
strtol(redisGitDirty(),NULL,10) > 0,
(int)getpid());
if (argc == 1) {
serverLog(LL_WARNING, "Warning: no config file specified, using the default config. In order to specify a config file use %s /path/to/redis.conf", argv[0]);
serverLog(LL_WARNING, "Warning: no config file specified, using the default config. In order to specify a config file use %s /path/to/valkey.conf", argv[0]);
} else {
serverLog(LL_NOTICE, "Configuration loaded");
}
+58 -51
View File
@@ -80,9 +80,9 @@ typedef long long ustime_t; /* microsecond time type. */
#include "rax.h" /* Radix tree */
#include "connection.h" /* Connection abstraction */
#define REDISMODULE_CORE 1
#define VALKEYMODULE_CORE 1
typedef struct redisObject robj;
#include "redismodule.h" /* Redis modules API defines. */
#include "valkeymodule.h" /* Redis modules API defines. */
/* Following includes allow test functions to be called from Redis main() */
#include "zipmap.h"
@@ -182,6 +182,7 @@ struct hdr_histogram;
#define REDIS_AUTOSYNC_BYTES (1024*1024*4) /* Sync file every 4MB. */
#define REPLY_BUFFER_DEFAULT_PEAK_RESET_TIME 5000 /* 5 seconds */
#define REPLY_BUFFER_SIZE_UNAUTHENTICATED_CLIENT 1024 /* 1024 bytes */
/* When configuring the server eventloop, we setup it so that the total number
* of file descriptors we can handle are server.maxclients + RESERVED_FDS +
@@ -400,6 +401,7 @@ extern int configOOMScoreAdjValuesDefaults[CONFIG_OOM_COUNT];
auth had been authenticated from the Module. */
#define CLIENT_MODULE_PREVENT_AOF_PROP (1ULL<<48) /* Module client do not want to propagate to AOF */
#define CLIENT_MODULE_PREVENT_REPL_PROP (1ULL<<49) /* Module client do not want to propagate to replica */
#define CLIENT_REPROCESSING_COMMAND (1ULL<<50) /* The client is re-processing the command. */
/* Client block type (btype field in client structure)
* if CLIENT_BLOCKED flag is set. */
@@ -700,7 +702,7 @@ typedef enum {
/* The "module" object type is a special one that signals that the object
* is one directly managed by a Redis module. In this case the value points
* to a moduleValue struct, which contains the object value (which is only
* handled by the module itself) and the RedisModuleType struct which lists
* handled by the module itself) and the ValkeyModuleType struct which lists
* function pointers in order to serialize, deserialize, AOF-rewrite and
* free the object.
*
@@ -713,52 +715,52 @@ typedef enum {
#define OBJ_TYPE_MAX 7 /* Maximum number of object types */
/* Extract encver / signature from a module type ID. */
#define REDISMODULE_TYPE_ENCVER_BITS 10
#define REDISMODULE_TYPE_ENCVER_MASK ((1<<REDISMODULE_TYPE_ENCVER_BITS)-1)
#define REDISMODULE_TYPE_ENCVER(id) ((id) & REDISMODULE_TYPE_ENCVER_MASK)
#define REDISMODULE_TYPE_SIGN(id) (((id) & ~((uint64_t)REDISMODULE_TYPE_ENCVER_MASK)) >>REDISMODULE_TYPE_ENCVER_BITS)
#define VALKEYMODULE_TYPE_ENCVER_BITS 10
#define VALKEYMODULE_TYPE_ENCVER_MASK ((1<<VALKEYMODULE_TYPE_ENCVER_BITS)-1)
#define VALKEYMODULE_TYPE_ENCVER(id) ((id) & VALKEYMODULE_TYPE_ENCVER_MASK)
#define VALKEYMODULE_TYPE_SIGN(id) (((id) & ~((uint64_t)VALKEYMODULE_TYPE_ENCVER_MASK)) >>VALKEYMODULE_TYPE_ENCVER_BITS)
/* Bit flags for moduleTypeAuxSaveFunc */
#define REDISMODULE_AUX_BEFORE_RDB (1<<0)
#define REDISMODULE_AUX_AFTER_RDB (1<<1)
#define VALKEYMODULE_AUX_BEFORE_RDB (1<<0)
#define VALKEYMODULE_AUX_AFTER_RDB (1<<1)
struct RedisModule;
struct RedisModuleIO;
struct RedisModuleDigest;
struct RedisModuleCtx;
struct ValkeyModule;
struct ValkeyModuleIO;
struct ValkeyModuleDigest;
struct ValkeyModuleCtx;
struct moduleLoadQueueEntry;
struct RedisModuleKeyOptCtx;
struct RedisModuleCommand;
struct ValkeyModuleKeyOptCtx;
struct ValkeyModuleCommand;
/* Each module type implementation should export a set of methods in order
* to serialize and deserialize the value in the RDB file, rewrite the AOF
* log, create the digest for "DEBUG DIGEST", and free the value when a key
* is deleted. */
typedef void *(*moduleTypeLoadFunc)(struct RedisModuleIO *io, int encver);
typedef void (*moduleTypeSaveFunc)(struct RedisModuleIO *io, void *value);
typedef int (*moduleTypeAuxLoadFunc)(struct RedisModuleIO *rdb, int encver, int when);
typedef void (*moduleTypeAuxSaveFunc)(struct RedisModuleIO *rdb, int when);
typedef void (*moduleTypeRewriteFunc)(struct RedisModuleIO *io, struct redisObject *key, void *value);
typedef void (*moduleTypeDigestFunc)(struct RedisModuleDigest *digest, void *value);
typedef void *(*moduleTypeLoadFunc)(struct ValkeyModuleIO *io, int encver);
typedef void (*moduleTypeSaveFunc)(struct ValkeyModuleIO *io, void *value);
typedef int (*moduleTypeAuxLoadFunc)(struct ValkeyModuleIO *rdb, int encver, int when);
typedef void (*moduleTypeAuxSaveFunc)(struct ValkeyModuleIO *rdb, int when);
typedef void (*moduleTypeRewriteFunc)(struct ValkeyModuleIO *io, struct redisObject *key, void *value);
typedef void (*moduleTypeDigestFunc)(struct ValkeyModuleDigest *digest, void *value);
typedef size_t (*moduleTypeMemUsageFunc)(const void *value);
typedef void (*moduleTypeFreeFunc)(void *value);
typedef size_t (*moduleTypeFreeEffortFunc)(struct redisObject *key, const void *value);
typedef void (*moduleTypeUnlinkFunc)(struct redisObject *key, void *value);
typedef void *(*moduleTypeCopyFunc)(struct redisObject *fromkey, struct redisObject *tokey, const void *value);
typedef int (*moduleTypeDefragFunc)(struct RedisModuleDefragCtx *ctx, struct redisObject *key, void **value);
typedef size_t (*moduleTypeMemUsageFunc2)(struct RedisModuleKeyOptCtx *ctx, const void *value, size_t sample_size);
typedef void (*moduleTypeFreeFunc2)(struct RedisModuleKeyOptCtx *ctx, void *value);
typedef size_t (*moduleTypeFreeEffortFunc2)(struct RedisModuleKeyOptCtx *ctx, const void *value);
typedef void (*moduleTypeUnlinkFunc2)(struct RedisModuleKeyOptCtx *ctx, void *value);
typedef void *(*moduleTypeCopyFunc2)(struct RedisModuleKeyOptCtx *ctx, const void *value);
typedef int (*moduleTypeAuthCallback)(struct RedisModuleCtx *ctx, void *username, void *password, const char **err);
typedef int (*moduleTypeDefragFunc)(struct ValkeyModuleDefragCtx *ctx, struct redisObject *key, void **value);
typedef size_t (*moduleTypeMemUsageFunc2)(struct ValkeyModuleKeyOptCtx *ctx, const void *value, size_t sample_size);
typedef void (*moduleTypeFreeFunc2)(struct ValkeyModuleKeyOptCtx *ctx, void *value);
typedef size_t (*moduleTypeFreeEffortFunc2)(struct ValkeyModuleKeyOptCtx *ctx, const void *value);
typedef void (*moduleTypeUnlinkFunc2)(struct ValkeyModuleKeyOptCtx *ctx, void *value);
typedef void *(*moduleTypeCopyFunc2)(struct ValkeyModuleKeyOptCtx *ctx, const void *value);
typedef int (*moduleTypeAuthCallback)(struct ValkeyModuleCtx *ctx, void *username, void *password, const char **err);
/* The module type, which is referenced in each value of a given type, defines
* the methods and links to the module exporting the type. */
typedef struct RedisModuleType {
typedef struct ValkeyModuleType {
uint64_t id; /* Higher 54 bits of type ID + 10 lower bits of encoding ver. */
struct RedisModule *module;
struct ValkeyModule *module;
moduleTypeLoadFunc rdb_load;
moduleTypeSaveFunc rdb_save;
moduleTypeRewriteFunc aof_rewrite;
@@ -801,7 +803,7 @@ typedef struct moduleValue {
} moduleValue;
/* This structure represents a module inside the system. */
struct RedisModule {
struct ValkeyModule {
void *handle; /* Module dlopen() handle. */
char *name; /* Module name. */
int ver; /* Module version. We use just progressive integers. */
@@ -815,24 +817,24 @@ struct RedisModule {
int in_call; /* RM_Call() nesting level */
int in_hook; /* Hooks callback nesting level for this module (0 or 1). */
int options; /* Module options and capabilities. */
int blocked_clients; /* Count of RedisModuleBlockedClient in this module. */
RedisModuleInfoFunc info_cb; /* Callback for module to add INFO fields. */
RedisModuleDefragFunc defrag_cb; /* Callback for global data defrag. */
int blocked_clients; /* Count of ValkeyModuleBlockedClient in this module. */
ValkeyModuleInfoFunc info_cb; /* Callback for module to add INFO fields. */
ValkeyModuleDefragFunc defrag_cb; /* Callback for global data defrag. */
struct moduleLoadQueueEntry *loadmod; /* Module load arguments for config rewrite. */
int num_commands_with_acl_categories; /* Number of commands in this module included in acl categories */
int onload; /* Flag to identify if the call is being made from Onload (0 or 1) */
};
typedef struct RedisModule RedisModule;
typedef struct ValkeyModule ValkeyModule;
/* This is a wrapper for the 'rio' streams used inside rdb.c in Redis, so that
* the user does not have to take the total count of the written bytes nor
* to care about error conditions. */
struct RedisModuleIO {
struct ValkeyModuleIO {
size_t bytes; /* Bytes read / written so far. */
rio *rio; /* Rio stream. */
moduleType *type; /* Module type doing the operation. */
int error; /* True if error condition happened. */
struct RedisModuleCtx *ctx; /* Optional context, see RM_GetContextFromIO()*/
struct ValkeyModuleCtx *ctx; /* Optional context, see RM_GetContextFromIO()*/
struct redisObject *key; /* Optional name of key processed */
int dbid; /* The dbid of the key being processed, -1 when unknown. */
sds pre_flush_buffer; /* A buffer that should be flushed before next write operation
@@ -857,7 +859,7 @@ struct RedisModuleIO {
* a data structure, so that a digest can be created in a way that correctly
* reflects the values. See the DEBUG DIGEST command implementation for more
* background. */
struct RedisModuleDigest {
struct ValkeyModuleDigest {
unsigned char o[20]; /* Ordered elements. */
unsigned char x[20]; /* Xored elements. */
struct redisObject *key; /* Optional name of key processed */
@@ -1032,11 +1034,11 @@ typedef struct blockingState {
long long reploffset; /* Replication offset to reach. */
/* BLOCKED_MODULE */
void *module_blocked_handle; /* RedisModuleBlockedClient structure.
void *module_blocked_handle; /* ValkeyModuleBlockedClient structure.
which is opaque for the Redis core, only
handled in module.c. */
void *async_rm_call_handle; /* RedisModuleAsyncRMCallPromise structure.
void *async_rm_call_handle; /* ValkeyModuleAsyncRMCallPromise structure.
which is opaque for the Redis core, only
handled in module.c. */
} blockingState;
@@ -1190,6 +1192,7 @@ typedef struct client {
time_t lastinteraction; /* Time of the last interaction, used for timeout */
time_t obuf_soft_limit_reached_time;
int authenticated; /* Needed when the default user requires auth. */
int ever_authenticated; /* Indicate a client was ever successfully authenticated during it's lifetime */
int replstate; /* Replication state if this is a slave. */
int repl_start_cmd_stream_on_ack; /* Install slave write handler on first ACK. */
int repldbfd; /* Replication DB file descriptor. */
@@ -1223,13 +1226,13 @@ typedef struct client {
listNode *client_list_node; /* list node in client list */
listNode *postponed_list_node; /* list node within the postponed list */
listNode *pending_read_list_node; /* list node in clients pending read list */
void *module_blocked_client; /* Pointer to the RedisModuleBlockedClient associated with this
void *module_blocked_client; /* Pointer to the ValkeyModuleBlockedClient associated with this
* client. This is set in case of module authentication before the
* unblocked client is reprocessed to handle reply callbacks. */
void *module_auth_ctx; /* Ongoing / attempted module based auth callback's ctx.
* This is only tracked within the context of the command attempting
* authentication. If not NULL, it means module auth is in progress. */
RedisModuleUserChangedFunc auth_callback; /* Module callback to execute
ValkeyModuleUserChangedFunc auth_callback; /* Module callback to execute
* when the authenticated user
* changes. */
void *auth_callback_privdata; /* Private data that is passed when the auth
@@ -1627,6 +1630,7 @@ struct redisServer {
int enable_protected_configs; /* Enable the modification of protected configs, see PROTECTED_ACTION_ALLOWED_* */
int enable_debug_cmd; /* Enable DEBUG commands, see PROTECTED_ACTION_ALLOWED_* */
int enable_module_cmd; /* Enable MODULE commands, see PROTECTED_ACTION_ALLOWED_* */
int debug_client_enforce_reply_list; /* Force client to always use the reply list */
/* RDB / AOF loading information */
volatile sig_atomic_t loading; /* We are loading data from disk if true */
@@ -1716,7 +1720,7 @@ struct redisServer {
durationStats duration_stats[EL_DURATION_TYPE_NUM];
/* Configuration */
int verbosity; /* Loglevel in redis.conf */
int verbosity; /* Loglevel verbosity */
int maxidletime; /* Client timeout in seconds */
int tcpkeepalive; /* Set SO_KEEPALIVE if non-zero. */
int active_expire_enabled; /* Can be disabled for testing purposes. */
@@ -1989,13 +1993,15 @@ struct redisServer {
int cluster_module_flags; /* Set of flags that Redis modules are able
to set in order to suppress certain
native Redis Cluster features. Check the
REDISMODULE_CLUSTER_FLAG_*. */
VALKEYMODULE_CLUSTER_FLAG_*. */
int cluster_allow_reads_when_down; /* Are reads allowed when the cluster
is down? */
int cluster_config_file_lock_fd; /* cluster config fd, will be flocked. */
unsigned long long cluster_link_msg_queue_limit_bytes; /* Memory usage limit on individual link msg queue */
int cluster_drop_packet_filter; /* Debug config that allows tactically
* dropping packets of a specific type */
/* Debug config that goes along with cluster_drop_packet_filter. When set, the link is closed on packet drop. */
uint32_t debug_cluster_close_link_on_packet_drop : 1;
/* Scripting */
mstime_t busy_reply_threshold; /* Script / module timeout in milliseconds */
int pre_command_oom_state; /* OOM before command (script?) was started */
@@ -2088,7 +2094,7 @@ typedef struct {
* 2. keynum: there's an arg that contains the number of key args somewhere before the keys themselves
*/
/* WARNING! Must be synced with generate-command-code.py and RedisModuleKeySpecBeginSearchType */
/* WARNING! Must be synced with generate-command-code.py and ValkeyModuleKeySpecBeginSearchType */
typedef enum {
KSPEC_BS_INVALID = 0, /* Must be 0 */
KSPEC_BS_UNKNOWN,
@@ -2096,7 +2102,7 @@ typedef enum {
KSPEC_BS_KEYWORD
} kspec_bs_type;
/* WARNING! Must be synced with generate-command-code.py and RedisModuleKeySpecFindKeysType */
/* WARNING! Must be synced with generate-command-code.py and ValkeyModuleKeySpecFindKeysType */
typedef enum {
KSPEC_FK_INVALID = 0, /* Must be 0 */
KSPEC_FK_UNKNOWN,
@@ -2104,7 +2110,7 @@ typedef enum {
KSPEC_FK_KEYNUM
} kspec_fk_type;
/* WARNING! This struct must match RedisModuleCommandKeySpec */
/* WARNING! This struct must match ValkeyModuleCommandKeySpec */
typedef struct {
/* Declarative data */
const char *notes;
@@ -2184,7 +2190,7 @@ typedef struct jsonObject {
#endif
/* WARNING! This struct must match RedisModuleCommandHistoryEntry */
/* WARNING! This struct must match ValkeyModuleCommandHistoryEntry */
typedef struct {
const char *since;
const char *changes;
@@ -2289,7 +2295,7 @@ typedef int redisGetKeysProc(struct redisCommand *cmd, robj **argv, int argc, ge
*
* The following additional flags are only used in order to put commands
* in a specific ACL category. Commands can have multiple ACL categories.
* See redis.conf for the exact meaning of each.
* See valkey.conf for the exact meaning of each.
*
* @keyspace, @read, @write, @set, @sortedset, @list, @hash, @string, @bitmap,
* @hyperloglog, @stream, @admin, @fast, @slow, @pubsub, @blocking, @dangerous,
@@ -2358,7 +2364,7 @@ struct redisCommand {
dict *subcommands_dict; /* A dictionary that holds the subcommands, the key is the subcommand sds name
* (not the fullname), and the value is the redisCommand structure pointer. */
struct redisCommand *parent;
struct RedisModuleCommand *module_cmd; /* A pointer to the module command data (NULL if native command) */
struct ValkeyModuleCommand *module_cmd; /* A pointer to the module command data (NULL if native command) */
};
struct redisError {
@@ -2477,7 +2483,7 @@ moduleType *moduleTypeLookupModuleByNameIgnoreCase(const char *name);
void moduleTypeNameByID(char *name, uint64_t moduleid);
const char *moduleTypeModuleName(moduleType *mt);
const char *moduleNameFromCommand(struct redisCommand *cmd);
void moduleFreeContext(struct RedisModuleCtx *ctx);
void moduleFreeContext(struct ValkeyModuleCtx *ctx);
void moduleCallCommandUnblockedHandler(client *c);
void unblockClientFromModule(client *c);
void moduleHandleBlockedClients(void);
@@ -2643,6 +2649,7 @@ void unprotectClient(client *c);
void initThreadedIO(void);
client *lookupClientByID(uint64_t id);
int authRequired(client *c);
void clientSetUser(client *c, user *u, int authenticated);
void putClientInPendingWriteQueue(client *c);
/* logreqres.c - logging of requests and responses */
+12 -11
View File
@@ -1424,11 +1424,6 @@ int streamRangeHasTombstones(stream *s, streamID *start, streamID *end) {
return 0;
}
if (streamCompareID(&s->first_id,&s->max_deleted_entry_id) > 0) {
/* The latest tombstone is before the first entry. */
return 0;
}
if (start) {
start_id = *start;
} else {
@@ -1521,7 +1516,12 @@ long long streamEstimateDistanceFromFirstEverEntry(stream *s, streamID *id) {
return s->entries_added;
}
int cmp_last = streamCompareID(id,&s->last_id);
if (!streamIDEqZero(id) && streamCompareID(id, &s->max_deleted_entry_id) < 0) {
/* The ID is before the last tombstone, so the counter is unknown. */
return SCG_INVALID_ENTRIES_READ;
}
int cmp_last = streamCompareID(id, &s->last_id);
if (cmp_last == 0) {
/* Return the exact counter of the last entry in the stream. */
return s->entries_added;
@@ -1700,11 +1700,12 @@ size_t streamReplyWithRange(client *c, stream *s, streamID *start, streamID *end
streamIteratorStart(&si,s,start,end,rev);
while(streamIteratorGetID(&si,&id,&numfields)) {
/* Update the group last_id if needed. */
if (group && streamCompareID(&id,&group->last_id) > 0) {
if (group->entries_read != SCG_INVALID_ENTRIES_READ && !streamRangeHasTombstones(s,&id,NULL)) {
/* A valid counter and no future tombstones mean we can
* increment the read counter to keep tracking the group's
* progress. */
if (group && streamCompareID(&id, &group->last_id) > 0) {
if (group->entries_read != SCG_INVALID_ENTRIES_READ &&
streamCompareID(&group->last_id, &s->first_id) >= 0 &&
!streamRangeHasTombstones(s, &group->last_id, NULL)) {
/* A valid counter and no tombstones in the group's last-delivered-id and the stream's last-generated-id,
* we can increment the read counter to keep tracking the group's progress. */
group->entries_read++;
} else if (s->entries_added) {
/* The group's counter may be invalid, so we try to obtain it. */
+3 -2
View File
@@ -1172,7 +1172,8 @@ unsigned long zsetLength(const robj *zobj) {
* and the value len hint indicates the approximate individual size of the added elements,
* they are used to determine the initial representation.
*
* If the hints are not known, and underestimation or 0 is suitable. */
* If the hints are not known, and underestimation or 0 is suitable.
* We should never pass a negative value because it will convert to a very large unsigned number. */
robj *zsetTypeCreate(size_t size_hint, size_t val_len_hint) {
if (size_hint <= server.zset_max_listpack_entries &&
val_len_hint <= server.zset_max_listpack_value)
@@ -3001,7 +3002,7 @@ static void zrangeResultFinalizeClient(zrange_result_handler *handler,
/* Result handler methods for storing the ZRANGESTORE to a zset. */
static void zrangeResultBeginStore(zrange_result_handler *handler, long length)
{
handler->dstobj = zsetTypeCreate(length, 0);
handler->dstobj = zsetTypeCreate(length >= 0 ? length : 0, 0);
}
static void zrangeResultEmitCBufferForStore(zrange_result_handler *handler,
+46 -21
View File
@@ -27,7 +27,7 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
#define REDISMODULE_CORE_MODULE /* A module that's part of the redis core, uses server.h too. */
#define VALKEYMODULE_CORE_MODULE /* A module that's part of the redis core, uses server.h too. */
#include "server.h"
#include "connhelpers.h"
@@ -453,6 +453,10 @@ typedef struct tls_connection {
SSL *ssl;
char *ssl_error;
listNode *pending_list_node;
/* Per https://docs.openssl.org/master/man3/SSL_write, after a write call with partially written data,
* we must make subsequent write calls with the same length. We use this field to keep track of
* the previous write length. */
size_t last_failed_write_data_len;
} tls_connection;
static connection *createTLSConnection(int client_side) {
@@ -888,11 +892,23 @@ static int connTLSWrite(connection *conn_, const void *data, size_t data_len) {
if (conn->c.state != CONN_STATE_CONNECTED) return -1;
ERR_clear_error();
/* In case when last write failed due to some internal reason, retry has to provide
* at least the same amount of bytes (https://docs.openssl.org/master/man3/SSL_write).
* If that condition is not met, OpenSSL will return "SSL routines::bad length".
* Currently we only suspect this can happen during primary cron sending '\n'
* indication to the replica, so we silently return from this function without
* impacting the connection state. */
if (data_len < conn->last_failed_write_data_len) {
// TODO: place debugAssert for this case once the known issue described is resolved
return -1;
}
ret = SSL_write(conn->ssl, data, data_len);
conn->last_failed_write_data_len = ret <= 0 ? data_len : 0;
return updateStateAfterSSLIO(conn, ret, 1);
}
static int connTLSWritev(connection *conn_, const struct iovec *iov, int iovcnt) {
tls_connection *conn = (tls_connection *)conn_;
if (iovcnt == 1) return connTLSWrite(conn_, iov[0].iov_base, iov[0].iov_len);
/* Accumulate the amount of bytes of each buffer and check if it exceeds NET_MAX_WRITES_PER_EVENT. */
@@ -902,10 +918,15 @@ static int connTLSWritev(connection *conn_, const struct iovec *iov, int iovcnt)
if (iov_bytes_len > NET_MAX_WRITES_PER_EVENT) break;
}
/* The amount of all buffers is greater than NET_MAX_WRITES_PER_EVENT,
* which is not worth doing so much memory copying to reduce system calls,
* therefore, invoke connTLSWrite() multiple times to avoid memory copies. */
if (iov_bytes_len > NET_MAX_WRITES_PER_EVENT) {
/* In case the amount of all buffers is greater than NET_MAX_WRITES_PER_EVENT,
* it might not worth doing so much memory copying to reduce system calls,
* therefore, invoke connTLSWrite() multiple times to avoid memory copies.
* However, in case when last write failed we still have to repeat sending last_failed_write_data_len
* bytes. Because of openssl implementation we cannot repeat sending writes with length smaller than
* the last failed write (https://docs.openssl.org/master/man3/SSL_write) so in case the first io buffer
* does not provide at least the same amount of bytes as previous failed write, we will have to fallback to
* memory copy to a static buffer before calling SSL_write. */
if (iov_bytes_len > NET_MAX_WRITES_PER_EVENT && iovcnt > 0 && iov[0].iov_len >= conn->last_failed_write_data_len) {
ssize_t tot_sent = 0;
for (int i = 0; i < iovcnt; i++) {
ssize_t sent = connTLSWrite(conn_, iov[i].iov_base, iov[i].iov_len);
@@ -916,13 +937,17 @@ static int connTLSWritev(connection *conn_, const struct iovec *iov, int iovcnt)
return tot_sent;
}
/* The amount of all buffers is less than NET_MAX_WRITES_PER_EVENT,
* which is worth doing more memory copies in exchange for fewer system calls,
* so concatenate these scattered buffers into a contiguous piece of memory
* and send it away by one call to connTLSWrite(). */
/* The amount of all buffers is less than NET_MAX_WRITES_PER_EVENT,
* which is worth doing more memory copies in exchange for fewer system calls,
* so concatenate these scattered buffers into a contiguous piece of memory
* and send it away by one call to connTLSWrite().
* However, code can fallback here in case when last write failed and first
* element of io is buffer not big enough to provide required amount of bytes
* to retry, so iov_bytes_len may exceed NET_MAX_WRITES_PER_EVENT by the amount
* of remaining bytes from last taken io. */
char buf[iov_bytes_len];
size_t offset = 0;
for (int i = 0; i < iovcnt; i++) {
for (int i = 0; i < iovcnt && offset < iov_bytes_len; i++) {
memcpy(buf + offset, iov[i].iov_base, iov[i].iov_len);
offset += iov[i].iov_len;
}
@@ -1169,36 +1194,36 @@ int RedisRegisterConnectionTypeTLS(void) {
#include "release.h"
int RedisModule_OnLoad(void *ctx, RedisModuleString **argv, int argc) {
int ValkeyModule_OnLoad(void *ctx, ValkeyModuleString **argv, int argc) {
UNUSED(argv);
UNUSED(argc);
/* Connection modules must be part of the same build as redis. */
if (strcmp(REDIS_BUILD_ID_RAW, redisBuildIdRaw())) {
serverLog(LL_NOTICE, "Connection type %s was not built together with the redis-server used.", CONN_TYPE_TLS);
return REDISMODULE_ERR;
return VALKEYMODULE_ERR;
}
if (RedisModule_Init(ctx,"tls",1,REDISMODULE_APIVER_1) == REDISMODULE_ERR)
return REDISMODULE_ERR;
if (ValkeyModule_Init(ctx,"tls",1,VALKEYMODULE_APIVER_1) == VALKEYMODULE_ERR)
return VALKEYMODULE_ERR;
/* Connection modules is available only bootup. */
if ((RedisModule_GetContextFlags(ctx) & REDISMODULE_CTX_FLAGS_SERVER_STARTUP) == 0) {
if ((ValkeyModule_GetContextFlags(ctx) & VALKEYMODULE_CTX_FLAGS_SERVER_STARTUP) == 0) {
serverLog(LL_NOTICE, "Connection type %s can be loaded only during bootup", CONN_TYPE_TLS);
return REDISMODULE_ERR;
return VALKEYMODULE_ERR;
}
RedisModule_SetModuleOptions(ctx, REDISMODULE_OPTIONS_HANDLE_REPL_ASYNC_LOAD);
ValkeyModule_SetModuleOptions(ctx, VALKEYMODULE_OPTIONS_HANDLE_REPL_ASYNC_LOAD);
if(connTypeRegister(&CT_TLS) != C_OK)
return REDISMODULE_ERR;
return VALKEYMODULE_ERR;
return REDISMODULE_OK;
return VALKEYMODULE_OK;
}
int RedisModule_OnUnload(void *arg) {
int ValkeyModule_OnUnload(void *arg) {
UNUSED(arg);
serverLog(LL_NOTICE, "Connection type %s can not be unloaded", CONN_TYPE_TLS);
return REDISMODULE_ERR;
return VALKEYMODULE_ERR;
}
#endif
+10 -4
View File
@@ -54,8 +54,11 @@
/* Glob-style pattern matching. */
static int stringmatchlen_impl(const char *pattern, int patternLen,
const char *string, int stringLen, int nocase, int *skipLongerMatches)
const char *string, int stringLen, int nocase, int *skipLongerMatches, int nesting)
{
/* Protection against abusive patterns. */
if (nesting > 1000) return 0;
while(patternLen && stringLen) {
switch(pattern[0]) {
case '*':
@@ -67,7 +70,7 @@ static int stringmatchlen_impl(const char *pattern, int patternLen,
return 1; /* match */
while(stringLen) {
if (stringmatchlen_impl(pattern+1, patternLen-1,
string, stringLen, nocase, skipLongerMatches))
string, stringLen, nocase, skipLongerMatches, nesting+1))
return 1; /* match */
if (*skipLongerMatches)
return 0; /* no match */
@@ -189,7 +192,7 @@ static int stringmatchlen_impl(const char *pattern, int patternLen,
int stringmatchlen(const char *pattern, int patternLen,
const char *string, int stringLen, int nocase) {
int skipLongerMatches = 0;
return stringmatchlen_impl(pattern,patternLen,string,stringLen,nocase,&skipLongerMatches);
return stringmatchlen_impl(pattern,patternLen,string,stringLen,nocase,&skipLongerMatches,0);
}
int stringmatch(const char *pattern, const char *string, int nocase) {
@@ -1138,7 +1141,10 @@ int fsyncFileDir(const char *filename) {
int reclaimFilePageCache(int fd, size_t offset, size_t length) {
#ifdef HAVE_FADVISE
int ret = posix_fadvise(fd, offset, length, POSIX_FADV_DONTNEED);
if (ret) return -1;
if (ret) {
errno = ret;
return -1;
}
return 0;
#else
UNUSED(fd);
@@ -1424,7 +1424,7 @@ int parseOptions(int argc, char **argv) {
config.numclients = atoi(argv[++i]);
} else if (!strcmp(argv[i],"-v") || !strcmp(argv[i], "--version")) {
sds version = benchmarkVersion();
printf("redis-benchmark %s\n", version);
printf("valkey-benchmark %s\n", version);
sdsfree(version);
exit(0);
} else if (!strcmp(argv[i],"-n")) {
@@ -1606,12 +1606,12 @@ usage:
printf(
"%s%s%s", /* Split to avoid strings longer than 4095 (-Woverlength-strings). */
"Usage: redis-benchmark [OPTIONS] [COMMAND ARGS...]\n\n"
"Usage: valkey-benchmark [OPTIONS] [COMMAND ARGS...]\n\n"
"Options:\n"
" -h <hostname> Server hostname (default 127.0.0.1)\n"
" -p <port> Server port (default 6379)\n"
" -s <socket> Server socket (overrides host and port)\n"
" -a <password> Password for Redis Auth\n"
" -a <password> Password for Valkey Auth\n"
" --user <username> Used to send ACL style 'AUTH username pass'. Needs -a.\n"
" -u <uri> Server URI.\n"
" -c <clients> Number of parallel connections (default 50).\n"
@@ -1655,17 +1655,17 @@ tls_usage,
" --version Output version and exit.\n\n"
"Examples:\n\n"
" Run the benchmark with the default configuration against 127.0.0.1:6379:\n"
" $ redis-benchmark\n\n"
" $ valkey-benchmark\n\n"
" Use 20 parallel clients, for a total of 100k requests, against 192.168.1.1:\n"
" $ redis-benchmark -h 192.168.1.1 -p 6379 -n 100000 -c 20\n\n"
" $ valkey-benchmark -h 192.168.1.1 -p 6379 -n 100000 -c 20\n\n"
" Fill 127.0.0.1:6379 with about 1 million keys only using the SET test:\n"
" $ redis-benchmark -t set -n 1000000 -r 100000000\n\n"
" $ valkey-benchmark -t set -n 1000000 -r 100000000\n\n"
" Benchmark 127.0.0.1:6379 for a few commands producing CSV output:\n"
" $ redis-benchmark -t ping,set,get -n 100000 --csv\n\n"
" $ valkey-benchmark -t ping,set,get -n 100000 --csv\n\n"
" Benchmark a specific command line:\n"
" $ redis-benchmark -r 10000 -n 10000 eval 'return redis.call(\"ping\")' 0\n\n"
" $ valkey-benchmark -r 10000 -n 10000 eval 'return redis.call(\"ping\")' 0\n\n"
" Fill a list with 10000 random elements:\n"
" $ redis-benchmark -r 10000 -n 10000 lpush mylist __rand_int__\n\n"
" $ valkey-benchmark -r 10000 -n 10000 lpush mylist __rand_int__\n\n"
" On user specified command lines __rand_int__ is replaced with a random integer\n"
" with a range of values selected by the -r option.\n"
);
@@ -199,7 +199,7 @@ int processAnnotations(FILE *fp, char *filename, int last_file) {
printf("Failed to truncate AOF %s to timestamp %ld to offset %ld because it is not the last file.\n",
filename, to_timestamp, (long int)epos);
printf("If you insist, please delete all files after this file according to the manifest "
"file and delete the corresponding records in manifest file manually. Then re-run redis-check-aof.\n");
"file and delete the corresponding records in manifest file manually. Then re-run valkey-check-aof.\n");
exit(1);
}
/* Truncate remaining AOF if exceeding 'to_timestamp' */
@@ -233,6 +233,7 @@ int checkSingleAof(char *aof_filename, char *aof_filepath, int last_file, int fi
struct redis_stat sb;
if (redis_fstat(fileno(fp),&sb) == -1) {
printf("Cannot stat file: %s, aborting...\n", aof_filename);
fclose(fp);
exit(1);
}
@@ -343,6 +344,7 @@ int fileIsRDB(char *filepath) {
struct redis_stat sb;
if (redis_fstat(fileno(fp), &sb) == -1) {
printf("Cannot stat file: %s\n", filepath);
fclose(fp);
exit(1);
}
@@ -379,6 +381,7 @@ int fileIsManifest(char *filepath) {
struct redis_stat sb;
if (redis_fstat(fileno(fp), &sb) == -1) {
printf("Cannot stat file: %s\n", filepath);
fclose(fp);
exit(1);
}
@@ -395,15 +398,20 @@ int fileIsManifest(char *filepath) {
break;
} else {
printf("Cannot read file: %s\n", filepath);
fclose(fp);
exit(1);
}
}
/* Skip comments lines */
/* We will skip comments lines.
* At present, the manifest format is fixed, see aofInfoFormat.
* We will break directly as long as it encounters other items. */
if (buf[0] == '#') {
continue;
} else if (!memcmp(buf, "file", strlen("file"))) {
is_manifest = 1;
} else {
break;
}
}
@@ -416,7 +424,7 @@ int fileIsManifest(char *filepath) {
* AOF_RDB_PREAMBLE: Old-style RDB-preamble AOF
* AOF_MULTI_PART: manifest in Multi Part AOF
*
* redis-check-aof tool will automatically perform different
* valkey-check-aof tool will automatically perform different
* verification logic according to different file formats.
* */
input_file_type getInputFileType(char *filepath) {
@@ -98,7 +98,9 @@ char *rdb_type_string[] = {
"hash-listpack",
"zset-listpack",
"quicklist-v2",
"stream-v2",
"set-listpack",
"stream-v3",
};
/* Show a few stats collected into 'rdbstate' */
@@ -419,7 +421,7 @@ int redis_check_rdb_main(int argc, char **argv, FILE *fp) {
exit(1);
} else if (!strcmp(argv[1],"-v") || !strcmp(argv[1], "--version")) {
sds version = checkRdbVersion();
printf("redis-check-rdb %s\n", version);
printf("valkey-check-rdb %s\n", version);
sdsfree(version);
exit(0);
}
+50 -47
View File
@@ -77,9 +77,9 @@
#define REDIS_CLI_KEEPALIVE_INTERVAL 15 /* seconds */
#define REDIS_CLI_DEFAULT_PIPE_TIMEOUT 30 /* seconds */
#define REDIS_CLI_HISTFILE_ENV "REDISCLI_HISTFILE"
#define REDIS_CLI_HISTFILE_DEFAULT ".rediscli_history"
#define CLI_HISTFILE_DEFAULT ".valkeycli_history"
#define REDIS_CLI_RCFILE_ENV "REDISCLI_RCFILE"
#define REDIS_CLI_RCFILE_DEFAULT ".redisclirc"
#define CLI_RCFILE_DEFAULT ".valkeyclirc"
#define REDIS_CLI_AUTH_ENV "REDISCLI_AUTH"
#define REDIS_CLI_CLUSTER_YES_ENV "REDISCLI_CLUSTER_YES"
@@ -322,7 +322,7 @@ static void cliRefreshPrompt(void) {
sds prompt = sdsempty();
if (config.hostsocket != NULL) {
prompt = sdscatfmt(prompt,"redis %s",config.hostsocket);
prompt = sdscatfmt(prompt,"valkey %s",config.hostsocket);
} else {
char addr[256];
formatAddr(addr, sizeof(addr), config.conn_info.hostip, config.conn_info.hostport);
@@ -850,7 +850,7 @@ static size_t cliLegacyCountCommands(struct commandDocs *commands, sds version)
* Stores the result in config.server_version.
* When not connected, or not possible, returns NULL. */
static sds cliGetServerVersion(void) {
static const char *key = "\nredis_version:";
static const char *key = "\nvalkey_version:";
redisReply *serverInfo = NULL;
char *pos;
@@ -868,7 +868,7 @@ static sds cliGetServerVersion(void) {
assert(serverInfo->type == REDIS_REPLY_STRING || serverInfo->type == REDIS_REPLY_VERB);
sds info = serverInfo->str;
/* Finds the first appearance of "redis_version" in the INFO SERVER reply. */
/* Finds the first appearance of "valkey_version" in the INFO SERVER reply. */
pos = strstr(info, key);
if (pos) {
pos += strlen(key);
@@ -964,17 +964,17 @@ static void cliOutputCommandHelp(struct commandDocs *help, int group) {
static void cliOutputGenericHelp(void) {
sds version = cliVersion();
printf(
"redis-cli %s\n"
"To get help about Redis commands type:\n"
"valkey-cli %s\n"
"To get help about Valkey commands type:\n"
" \"help @<group>\" to get a list of commands in <group>\n"
" \"help <command>\" for help on <command>\n"
" \"help <tab>\" to get a list of possible help topics\n"
" \"quit\" to exit\n"
"\n"
"To set redis-cli preferences:\n"
"To set valkey-cli preferences:\n"
" \":set hints\" enable online hints\n"
" \":set nohints\" disable online hints\n"
"Set your preferences in ~/.redisclirc\n",
"Set your preferences in ~/.valkeyclirc\n",
version
);
sdsfree(version);
@@ -1657,6 +1657,7 @@ static int cliConnect(int flags) {
redisFree(context);
config.dbnum = 0;
config.in_multi = 0;
config.pubsub_mode = 0;
cliRefreshPrompt();
}
@@ -1680,7 +1681,7 @@ static int cliConnect(int flags) {
if (context->err) {
if (!(flags & CC_QUIET)) {
fprintf(stderr,"Could not connect to Redis at ");
fprintf(stderr,"Could not connect to Valkey at ");
if (config.hostsocket == NULL ||
(config.cluster_mode && config.cluster_reissue_command))
{
@@ -2683,7 +2684,7 @@ static int parseOptions(int argc, char **argv) {
} else if (!strcmp(argv[i],"--user") && !lastarg) {
config.conn_info.user = sdsnew(argv[++i]);
} else if (!strcmp(argv[i],"-u") && !lastarg) {
parseRedisUri(argv[++i],"redis-cli",&config.conn_info,&config.tls);
parseRedisUri(argv[++i],"valkey-cli",&config.conn_info,&config.tls);
if (config.conn_info.hostport < 0 || config.conn_info.hostport > 65535) {
fprintf(stderr, "Invalid server port.\n");
exit(1);
@@ -2898,7 +2899,7 @@ static int parseOptions(int argc, char **argv) {
#endif
} else if (!strcmp(argv[i],"-v") || !strcmp(argv[i], "--version")) {
sds version = cliVersion();
printf("redis-cli %s\n", version);
printf("valkey-cli %s\n", version);
sdsfree(version);
exit(0);
} else if (!strcmp(argv[i],"-2")) {
@@ -3012,9 +3013,9 @@ static void usage(int err) {
"";
fprintf(target,
"redis-cli %s\n"
"valkey-cli %s\n"
"\n"
"Usage: redis-cli [OPTIONS] [cmd [arg [arg ...]]]\n"
"Usage: valkey-cli [OPTIONS] [cmd [arg [arg ...]]]\n"
" -h <hostname> Server hostname (default: 127.0.0.1).\n"
" -p <port> Server port (default: 6379).\n"
" -s <socket> Server socket (overrides hostname and port).\n"
@@ -3073,17 +3074,17 @@ version,tls_usage);
" Use filename of \"-\" to write to stdout.\n"
" --functions-rdb <filename> Like --rdb but only get the functions (not the keys)\n"
" when getting the RDB dump file.\n"
" --pipe Transfer raw Redis protocol from stdin to server.\n"
" --pipe Transfer raw RESP protocol from stdin to server.\n"
" --pipe-timeout <n> In --pipe mode, abort with error if after sending all data.\n"
" no reply is received within <n> seconds.\n"
" Default timeout: %d. Use 0 to wait forever.\n",
REDIS_CLI_DEFAULT_PIPE_TIMEOUT);
fprintf(target,
" --bigkeys Sample Redis keys looking for keys with many elements (complexity).\n"
" --memkeys Sample Redis keys looking for keys consuming a lot of memory.\n"
" --memkeys-samples <n> Sample Redis keys looking for keys consuming a lot of memory.\n"
" --bigkeys Sample keys looking for keys with many elements (complexity).\n"
" --memkeys Sample keys looking for keys consuming a lot of memory.\n"
" --memkeys-samples <n> Sample keys looking for keys consuming a lot of memory.\n"
" And define number of key elements to sample\n"
" --hotkeys Sample Redis keys looking for hot keys.\n"
" --hotkeys Sample keys looking for hot keys.\n"
" only works when maxmemory-policy is *lfu.\n"
" --scan List all keys using the SCAN command.\n"
" --pattern <pat> Keys pattern when using the --scan, --bigkeys or --hotkeys\n"
@@ -3094,7 +3095,7 @@ version,tls_usage);
" --intrinsic-latency <sec> Run a test to measure intrinsic system latency.\n"
" The test will run for the specified amount of seconds.\n"
" --eval <file> Send an EVAL command using the Lua script at <file>.\n"
" --ldb Used with --eval enable the Redis Lua debugger.\n"
" --ldb Used with --eval enable the Server Lua debugger.\n"
" --ldb-sync-mode Like --ldb but uses the synchronous Lua debugger, in\n"
" this mode the server is blocked and script changes are\n"
" not rolled back from the server memory.\n"
@@ -3112,18 +3113,19 @@ version,tls_usage);
" Use --cluster help to list all available cluster manager commands.\n"
"\n"
"Examples:\n"
" cat /etc/passwd | redis-cli -x set mypasswd\n"
" redis-cli -D \"\" --raw dump key > key.dump && redis-cli -X dump_tag restore key2 0 dump_tag replace < key.dump\n"
" redis-cli -r 100 lpush mylist x\n"
" redis-cli -r 100 -i 1 info | grep used_memory_human:\n"
" redis-cli --quoted-input set '\"null-\\x00-separated\"' value\n"
" redis-cli --eval myscript.lua key1 key2 , arg1 arg2 arg3\n"
" redis-cli --scan --pattern '*:12345*'\n"
" redis-cli --scan --pattern '*:12345*' --count 100\n"
" valkey-cli -u redis://default:PASSWORD@localhost:6379/0\n"
" cat /etc/passwd | valkey-cli -x set mypasswd\n"
" valkey-cli -D \"\" --raw dump key > key.dump && valkey-cli -X dump_tag restore key2 0 dump_tag replace < key.dump\n"
" valkey-cli -r 100 lpush mylist x\n"
" valkey-cli -r 100 -i 1 info | grep used_memory_human:\n"
" valkey-cli --quoted-input set '\"null-\\x00-separated\"' value\n"
" valkey-cli --eval myscript.lua key1 key2 , arg1 arg2 arg3\n"
" valkey-cli --scan --pattern '*:12345*'\n"
" valkey-cli --scan --pattern '*:12345*' --count 100\n"
"\n"
" (Note: when using --eval the comma separates KEYS[] from ARGV[] items)\n"
"\n"
"When no command is given, redis-cli starts in interactive mode.\n"
"When no command is given, valkey-cli starts in interactive mode.\n"
"Type \"help\" in interactive mode for information on available commands\n"
"and settings.\n"
"\n");
@@ -3219,27 +3221,27 @@ static sds *cliSplitArgs(char *line, int *argc) {
}
/* Set the CLI preferences. This function is invoked when an interactive
* ":command" is called, or when reading ~/.redisclirc file, in order to
* ":command" is called, or when reading ~/.valkeyclirc file, in order to
* set user preferences. */
void cliSetPreferences(char **argv, int argc, int interactive) {
if (!strcasecmp(argv[0],":set") && argc >= 2) {
if (!strcasecmp(argv[1],"hints")) pref.hints = 1;
else if (!strcasecmp(argv[1],"nohints")) pref.hints = 0;
else {
printf("%sunknown redis-cli preference '%s'\n",
interactive ? "" : ".redisclirc: ",
printf("%sunknown valkey-cli preference '%s'\n",
interactive ? "" : ".valkeyclirc: ",
argv[1]);
}
} else {
printf("%sunknown redis-cli internal command '%s'\n",
interactive ? "" : ".redisclirc: ",
printf("%sunknown valkey-cli internal command '%s'\n",
interactive ? "" : ".valkeyclirc: ",
argv[0]);
}
}
/* Load the ~/.redisclirc file if any. */
/* Load the ~/.valkeyclirc file if any. */
void cliLoadPreferences(void) {
sds rcfile = getDotfilePath(REDIS_CLI_RCFILE_ENV,REDIS_CLI_RCFILE_DEFAULT);
sds rcfile = getDotfilePath(REDIS_CLI_RCFILE_ENV,CLI_RCFILE_DEFAULT);
if (rcfile == NULL) return;
FILE *fp = fopen(rcfile,"r");
char buf[1024];
@@ -3336,7 +3338,7 @@ static void repl(void) {
/* Only use history and load the rc file when stdin is a tty. */
if (isatty(fileno(stdin))) {
historyfile = getDotfilePath(REDIS_CLI_HISTFILE_ENV,REDIS_CLI_HISTFILE_DEFAULT);
historyfile = getDotfilePath(REDIS_CLI_HISTFILE_ENV,CLI_HISTFILE_DEFAULT);
//keep in-memory history always regardless if history file can be determined
history = 1;
if (historyfile != NULL) {
@@ -3381,7 +3383,7 @@ static void repl(void) {
repeat = strtol(argv[0], &endptr, 10);
if (argc > 1 && *endptr == '\0') {
if (errno == ERANGE || errno == EINVAL || repeat <= 0) {
fputs("Invalid redis-cli repeat command option value.\n", stdout);
fputs("Invalid valkey-cli repeat command option value.\n", stdout);
sdsfreesplitres(argv, argc);
linenoiseFree(line);
continue;
@@ -3982,7 +3984,7 @@ static sds clusterManagerGetNodeRDBFilename(clusterManagerNode *node) {
sds filename = sdsnew(config.cluster_manager_command.backup_dir);
if (filename[sdslen(filename) - 1] != '/')
filename = sdscat(filename, "/");
filename = sdscatprintf(filename, "redis-node-%s-%d-%s.rdb", node->ip,
filename = sdscatprintf(filename, "valkey-node-%s-%d-%s.rdb", node->ip,
node->port, node->name);
return filename;
}
@@ -4058,7 +4060,7 @@ static int clusterManagerNodeConnect(clusterManagerNode *node) {
}
}
if (node->context->err) {
fprintf(stderr,"Could not connect to Redis at ");
fprintf(stderr,"Could not connect to Valkey at ");
fprintf(stderr,"%s:%d: %s\n", node->ip, node->port,
node->context->errstr);
redisFree(node->context);
@@ -5930,7 +5932,7 @@ static int clusterManagerFixSlotsCoverage(char *all_slots) {
CLUSTER_MANAGER_CMD_FLAG_FIX_WITH_UNREACHABLE_MASTERS;
if (cluster_manager.unreachable_masters > 0 && !force_fix) {
clusterManagerLogWarn("*** Fixing slots coverage with %d unreachable masters is dangerous: redis-cli will assume that slots about masters that are not reachable are not covered, and will try to reassign them to the reachable nodes. This can cause data loss and is rarely what you want to do. If you really want to proceed use the --cluster-fix-with-unreachable-masters option.\n", cluster_manager.unreachable_masters);
clusterManagerLogWarn("*** Fixing slots coverage with %d unreachable masters is dangerous: valkey-cli will assume that slots about masters that are not reachable are not covered, and will try to reassign them to the reachable nodes. This can cause data loss and is rarely what you want to do. If you really want to proceed use the --cluster-fix-with-unreachable-masters option.\n", cluster_manager.unreachable_masters);
exit(1);
}
@@ -6132,7 +6134,7 @@ static int clusterManagerFixOpenSlot(int slot) {
CLUSTER_MANAGER_CMD_FLAG_FIX_WITH_UNREACHABLE_MASTERS;
if (cluster_manager.unreachable_masters > 0 && !force_fix) {
clusterManagerLogWarn("*** Fixing open slots with %d unreachable masters is dangerous: redis-cli will assume that slots about masters that are not reachable are not covered, and will try to reassign them to the reachable nodes. This can cause data loss and is rarely what you want to do. If you really want to proceed use the --cluster-fix-with-unreachable-masters option.\n", cluster_manager.unreachable_masters);
clusterManagerLogWarn("*** Fixing open slots with %d unreachable masters is dangerous: valkey-cli will assume that slots about masters that are not reachable are not covered, and will try to reassign them to the reachable nodes. This can cause data loss and is rarely what you want to do. If you really want to proceed use the --cluster-fix-with-unreachable-masters option.\n", cluster_manager.unreachable_masters);
exit(1);
}
@@ -6443,7 +6445,7 @@ static int clusterManagerFixOpenSlot(int slot) {
} else {
unhandled_case:
success = 0;
clusterManagerLogErr("[ERR] Sorry, redis-cli can't fix this slot "
clusterManagerLogErr("[ERR] Sorry, valkey-cli can't fix this slot "
"yet (work in progress). Slot is set as "
"migrating in %s, as importing in %s, "
"owner is %s:%d\n", migrating_str,
@@ -6898,7 +6900,7 @@ static int clusterManagerCommandCreate(int argc, char **argv) {
if (masters_count < 3) {
clusterManagerLogErr(
"*** ERROR: Invalid configuration for cluster creation.\n"
"*** Redis Cluster requires at least 3 master nodes.\n"
"*** Valkey Cluster requires at least 3 master nodes.\n"
"*** This is not possible with %d nodes and %d replicas per node.",
node_len, replicas);
clusterManagerLogErr("\n*** At least %d nodes are required.\n",
@@ -7218,7 +7220,7 @@ static int clusterManagerCommandAddNode(int argc, char **argv) {
reply = CLUSTER_MANAGER_COMMAND(refnode, "FUNCTION DUMP");
if (!clusterManagerCheckRedisReply(refnode, reply, &err)) {
clusterManagerLogInfo(">>> Failed retrieving Functions from the cluster, "
"skip this step as Redis version do not support function command (error = '%s')\n", err? err : "NULL reply");
"skip this step as Valkey version do not support function command (error = '%s')\n", err? err : "NULL reply");
if (err) zfree(err);
} else {
assert(reply->type == REDIS_REPLY_STRING);
@@ -7869,7 +7871,7 @@ static int clusterManagerCommandImport(int argc, char **argv) {
redisContext *src_ctx = redisConnect(src_ip, src_port);
if (src_ctx->err) {
success = 0;
fprintf(stderr,"Could not connect to Redis at %s:%d: %s.\n", src_ip,
fprintf(stderr,"Could not connect to Valkey at %s:%d: %s.\n", src_ip,
src_port, src_ctx->errstr);
goto cleanup;
}
@@ -8838,7 +8840,8 @@ static redisReply *sendScan(unsigned long long *it) {
reply = redisCommand(context, "SCAN %llu MATCH %b COUNT %d",
*it, config.pattern, sdslen(config.pattern), config.count);
else
reply = redisCommand(context,"SCAN %llu",*it);
reply = redisCommand(context, "SCAN %llu COUNT %d",
*it, config.count);
/* Handle any error conditions */
if(reply == NULL) {
+1698
View File
File diff suppressed because it is too large Load Diff
+8 -2
View File
@@ -1,2 +1,8 @@
#define REDIS_VERSION "255.255.255"
#define REDIS_VERSION_NUM 0x00ffffff
#define SERVER_NAME "valkey"
#define VALKEY_VERSION "7.2.9"
#define VALKEY_VERSION_NUM 0x00070209
/* Redis compatibility version, should never
* exceed 7.2.x. */
#define REDIS_VERSION "7.2.4"
#define REDIS_VERSION_NUM 0x00070204
+1 -1
View File
@@ -84,7 +84,7 @@ test "Cluster consistency during live resharding" {
flush stdout
set target [dict get [get_myself [randomInt 5]] id]
set tribpid [lindex [exec \
../../../src/redis-cli --cluster reshard \
../../../src/valkey-cli --cluster reshard \
127.0.0.1:[get_instance_attrib redis 0 port] \
--cluster-from all \
--cluster-to $target \
@@ -38,7 +38,7 @@ test "Set allow-replica-migration yes" {
set master0_id [dict get [get_myself 0] id]
test "Resharding all the master #0 slots away from it" {
set output [exec \
../../../src/redis-cli --cluster rebalance \
../../../src/valkey-cli --cluster rebalance \
127.0.0.1:[get_instance_attrib redis 0 port] \
{*}[rediscli_tls_config "../../../tests"] \
--cluster-weight ${master0_id}=0 >@ stdout ]
@@ -59,7 +59,7 @@ test "Resharding back some slot to master #0" {
# new resharding.
after 10000
set output [exec \
../../../src/redis-cli --cluster rebalance \
../../../src/valkey-cli --cluster rebalance \
127.0.0.1:[get_instance_attrib redis 0 port] \
{*}[rediscli_tls_config "../../../tests"] \
--cluster-weight ${master0_id}=.01 \
@@ -37,7 +37,7 @@ test "Set allow-replica-migration no" {
set master0_id [dict get [get_myself 0] id]
test "Resharding all the master #0 slots away from it" {
set output [exec \
../../../src/redis-cli --cluster rebalance \
../../../src/valkey-cli --cluster rebalance \
127.0.0.1:[get_instance_attrib redis 0 port] \
{*}[rediscli_tls_config "../../../tests"] \
--cluster-weight ${master0_id}=0 >@ stdout ]
+2 -2
View File
@@ -1,7 +1,7 @@
# Read the standard input and only shows dots in the output, filtering out
# all the other characters. Designed to avoid bufferization so that when
# we get the output of redis-trib and want to show just the dots, we'll see
# the dots as soon as redis-trib will output them.
# we get the output of valkey-trib and want to show just the dots, we'll see
# the dots as soon as valkey-trib will output them.
fconfigure stdin -buffering none
+6 -6
View File
@@ -8,25 +8,25 @@ proc config_set_all_nodes {keyword value} {
proc fix_cluster {addr} {
set code [catch {
exec ../../../src/redis-cli {*}[rediscli_tls_config "../../../tests"] --cluster fix $addr << yes
exec ../../../src/valkey-cli {*}[rediscli_tls_config "../../../tests"] --cluster fix $addr << yes
} result]
if {$code != 0} {
puts "redis-cli --cluster fix returns non-zero exit code, output below:\n$result"
puts "valkey-cli --cluster fix returns non-zero exit code, output below:\n$result"
}
# Note: redis-cli --cluster fix may return a non-zero exit code if nodes don't agree,
# Note: valkey-cli --cluster fix may return a non-zero exit code if nodes don't agree,
# but we can ignore that and rely on the check below.
assert_cluster_state ok
wait_for_condition 100 100 {
[catch {exec ../../../src/redis-cli {*}[rediscli_tls_config "../../../tests"] --cluster check $addr} result] == 0
[catch {exec ../../../src/valkey-cli {*}[rediscli_tls_config "../../../tests"] --cluster check $addr} result] == 0
} else {
puts "redis-cli --cluster check returns non-zero exit code, output below:\n$result"
puts "valkey-cli --cluster check returns non-zero exit code, output below:\n$result"
fail "Cluster could not settle with configuration"
}
}
proc wait_cluster_stable {} {
wait_for_condition 1000 50 {
[catch {exec ../../../src/redis-cli --cluster \
[catch {exec ../../../src/valkey-cli --cluster \
check 127.0.0.1:[get_instance_attrib redis 0 port] \
{*}[rediscli_tls_config "../../../tests"] \
}] == 0
+5 -5
View File
@@ -48,9 +48,9 @@ if {[catch {cd tmp}]} {
# the provided configuration file. Returns the PID of the process.
proc exec_instance {type dirname cfgfile} {
if {$type eq "redis"} {
set prgname redis-server
set prgname valkey-server
} elseif {$type eq "sentinel"} {
set prgname redis-sentinel
set prgname valkey-sentinel
} else {
error "Unknown instance type."
}
@@ -87,7 +87,7 @@ proc spawn_instance {type base_port count {conf {}} {base_conf_file ""}} {
if {$::tls} {
if {$::tls_module} {
puts $cfg [format "loadmodule %s/../../../src/redis-tls.so" [pwd]]
puts $cfg [format "loadmodule %s/../../../src/valkey-tls.so" [pwd]]
}
puts $cfg "tls-port $port"
@@ -342,7 +342,7 @@ proc pause_on_error {} {
set cmd [lindex $argv 0]
if {$cmd eq {continue}} {
break
} elseif {$cmd eq {show-redis-logs}} {
} elseif {$cmd eq {show-valkey-logs}} {
set count 10
if {[lindex $argv 1] ne {}} {set count [lindex $argv 1]}
foreach_redis_id id {
@@ -393,7 +393,7 @@ proc pause_on_error {} {
} elseif {$cmd eq {help}} {
puts "ls List Sentinel and Redis instances."
puts "show-sentinel-logs \[N\] Show latest N lines of logs."
puts "show-redis-logs \[N\] Show latest N lines of logs."
puts "show-valkey-logs \[N\] Show latest N lines of logs."
puts "S <id> cmd ... arg Call command in Sentinel <id>."
puts "R <id> cmd ... arg Call command in Redis <id>."
puts "SI <id> <field> Show Sentinel <id> INFO <field>."
+1 -1
View File
@@ -8,7 +8,7 @@ tags {"aof external:skip"} {
# was subsequently appended to the new AOF, resulting in duplicate commands.
start_server_aof [list dir $server_path] {
set client [redis [dict get $srv host] [dict get $srv port] 0 $::tls]
set bench [open "|src/redis-benchmark -q -s [dict get $srv unixsocket] -c 20 -n 20000 incr foo" "r+"]
set bench [open "|src/valkey-benchmark -q -s [dict get $srv unixsocket] -c 20 -n 20000 incr foo" "r+"]
wait_for_condition 100 1 {
[$client get foo] > 0

Some files were not shown because too many files have changed in this diff Show More