Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5145221fe7 | ||
|
|
3c9b32757e | ||
|
|
71c1c6c3b0 | ||
|
|
494f5a0a2d | ||
|
|
a50a800d84 | ||
|
|
4ebe349e3b | ||
|
|
b0ca495ee8 | ||
|
|
3370ca2d4d | ||
|
|
1eb8a40303 | ||
|
|
dfd313bfa4 | ||
|
|
070d3bca98 | ||
|
|
83e9c2dde2 | ||
|
|
ec0e7530d4 | ||
|
|
2bae93e422 | ||
|
|
0fc9eee621 | ||
|
|
dfad76aeb5 | ||
|
|
47b9859947 | ||
|
|
dec35fc141 | ||
|
|
b249c7d801 | ||
|
|
ef2d8c7502 | ||
|
|
1462a15b6a | ||
|
|
5630a27364 | ||
|
|
266c4b8ca1 | ||
|
|
c643770523 | ||
|
|
adab0ab950 | ||
|
|
62b791fcd6 | ||
|
|
bc32754998 | ||
|
|
07c7c7a8d9 | ||
|
|
7b1c150d10 | ||
|
|
4462e49392 | ||
|
|
3844ff9554 | ||
|
|
59f3f2f36c | ||
|
|
49238e5b52 | ||
|
|
6cd2c48836 | ||
|
|
c73aab2a1e | ||
|
|
a24f5aa772 | ||
|
|
3cfc00f979 | ||
|
|
36d8e4ea4c | ||
|
|
ccc7eb9131 | ||
|
|
46e8abaa99 | ||
|
|
d1b29eea0a | ||
|
|
19e89d048e | ||
|
|
518f2955c9 | ||
|
|
e378431e95 | ||
|
|
274b8ccf76 | ||
|
|
3c3d6d7839 | ||
|
|
eaeda0c6bd | ||
|
|
e332e1fd39 | ||
|
|
25a13621c9 | ||
|
|
ea228b5443 | ||
|
|
128dfa3c19 | ||
|
|
506692ab6d | ||
|
|
615160558e | ||
|
|
9f72272e18 | ||
|
|
14e90172a5 | ||
|
|
92cfd887b1 | ||
|
|
0d77bb919f | ||
|
|
cb89e0f36d | ||
|
|
527ab8e9a3 | ||
|
|
45b9e8639c | ||
|
|
f8655f00cf | ||
|
|
fd99738684 | ||
|
|
0b65d81b9d | ||
|
|
7a9b220e0a | ||
|
|
6e38f7874f | ||
|
|
7c094c8439 | ||
|
|
cd7ca4c9c0 | ||
|
|
6513ac47b3 | ||
|
|
b67292acbf | ||
|
|
e6ed6f91b1 | ||
|
|
f99cb12b9c | ||
|
|
977d162690 | ||
|
|
9abcee6214 | ||
|
|
aacf75f2fb | ||
|
|
7176676a34 | ||
|
|
c41fd60d8d | ||
|
|
45172387f5 | ||
|
|
95dc162858 | ||
|
|
cfe8b9637b | ||
|
|
2c9255310a | ||
|
|
ec67e6f9ed | ||
|
|
3827624e3c | ||
|
|
05428aed4b | ||
|
|
6ecea600f0 | ||
|
|
5571f95373 | ||
|
|
5937a59be0 | ||
|
|
a4cd0526d3 | ||
|
|
8cd5faa63d | ||
|
|
ede3eb14bb | ||
|
|
e1344755f6 | ||
|
|
2fdf7bda64 | ||
|
|
c8c1942f07 | ||
|
|
0d64300faa | ||
|
|
3bf3c737c4 | ||
|
|
f51d7599c9 | ||
|
|
7a0f6bef40 | ||
|
|
af077cb972 | ||
|
|
e957ae0444 | ||
|
|
0d4eb06171 | ||
|
|
eaed026574 | ||
|
|
b02b49b9ba | ||
|
|
8207559757 | ||
|
|
21caff001d | ||
|
|
86d20aa745 | ||
|
|
5d2aff4677 | ||
|
|
8f897ce91f | ||
|
|
b4543045dc | ||
|
|
a379db854f | ||
|
|
08f508d668 | ||
|
|
d90d042c70 | ||
|
|
984c0a2c79 | ||
|
|
6d9b16fb9f | ||
|
|
85abdd5e97 | ||
|
|
99572fc2b0 | ||
|
|
16abb019a7 | ||
|
|
1ff79d5ed8 | ||
|
|
248c2792ca | ||
|
|
c8feb6a5d1 | ||
|
|
df9f982ec9 | ||
|
|
23828d6b34 | ||
|
|
7b171abce7 | ||
|
|
461c529ea6 | ||
|
|
18a88dcae5 | ||
|
|
ce7b03a297 | ||
|
|
0221ecc5ec | ||
|
|
f630e56e10 | ||
|
|
a129ac30c4 | ||
|
|
1b36f39759 | ||
|
|
edc059db65 | ||
|
|
d272828706 | ||
|
|
4d7dcf2103 | ||
|
|
0e5e12e353 | ||
|
|
0b32fa00e7 | ||
|
|
192086838d | ||
|
|
08e94adea9 | ||
|
|
96a63b3fac | ||
|
|
e2867a879f | ||
|
|
8d6fbe827f | ||
|
|
0f184975e4 | ||
|
|
bcea2da0e4 | ||
|
|
f983fc31a2 | ||
|
|
85e25ebc9b | ||
|
|
7bb645ef14 | ||
|
|
d48f885bf9 | ||
|
|
ffcb4e222b | ||
|
|
6a5f8eaf1b | ||
|
|
75c2746c95 | ||
|
|
25486f1647 | ||
|
|
573579acfa | ||
|
|
78a168a538 | ||
|
|
8c7484d9bf | ||
|
|
b61785fc37 | ||
|
|
babf19e1f1 | ||
|
|
4fcde04dcc | ||
|
|
94fcf4318e | ||
|
|
fb75e2f9df | ||
|
|
d27f439e67 | ||
|
|
885f969d50 | ||
|
|
13332e28c3 | ||
|
|
b3d4653ccb | ||
|
|
af5784c031 | ||
|
|
f5d8b9f536 | ||
|
|
3cfeaea24c | ||
|
|
f598645e7e | ||
|
|
b2ff9407e2 | ||
|
|
2872565dd1 | ||
|
|
1ba9929633 | ||
|
|
d3972ad5a8 | ||
|
|
bacdcbe18b | ||
|
|
8da5b6333f | ||
|
|
ef746b0dff | ||
|
|
04c2d0dfe9 | ||
|
|
c79091d72e | ||
|
|
f30986f299 | ||
|
|
1abedeeb7e | ||
|
|
9c4237c17e | ||
|
|
3a9009d3bd | ||
|
|
20339015f0 | ||
|
|
2c9af0f00d | ||
|
|
122e375eeb | ||
|
|
d70a9d1653 | ||
|
|
e52f3bfdd1 | ||
|
|
94b5ec459a | ||
|
|
802a70e3ad | ||
|
|
22c9e05439 | ||
|
|
44eff3aad4 | ||
|
|
8e5683fb1c | ||
|
|
bb9130d9c6 | ||
|
|
9d1150494b | ||
|
|
19d6702358 | ||
|
|
629b757cc4 | ||
|
|
708a7e9ea1 | ||
|
|
67bb61fa5c | ||
|
|
93fee40390 | ||
|
|
64aa4537ba | ||
|
|
5bcce7a39d | ||
|
|
20b20d404c | ||
|
|
139d93266d | ||
|
|
4d78a6061f | ||
|
|
c2ebbd0668 | ||
|
|
68d6dffe50 | ||
|
|
22087fc2b4 | ||
|
|
b3d6f4bbf2 | ||
|
|
d5f5378d47 | ||
|
|
93784e2ee3 | ||
|
|
41275dd3d3 | ||
|
|
42d7d976ed | ||
|
|
606f3502c9 | ||
|
|
146644355e | ||
|
|
ff1c49d07b | ||
|
|
cd05870817 | ||
|
|
1bc735bf30 | ||
|
|
b1fe900842 | ||
|
|
df68e754a7 | ||
|
|
f4ba22d9b6 | ||
|
|
45f46a1a5a |
@@ -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
|
||||
+28
-20
@@ -2,22 +2,29 @@ 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@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
- 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
|
||||
./runtest --verbose --tags -slow --dump-logs
|
||||
- name: module api test
|
||||
run: ./runtest-moduleapi --verbose --dump-logs
|
||||
run: CFLAGS='-Werror' ./runtest-moduleapi --verbose --dump-logs
|
||||
- name: validate commands.def up to date
|
||||
run: |
|
||||
touch src/commands/ping.json
|
||||
@@ -28,57 +35,58 @@ jobs:
|
||||
test-sanitizer-address:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
- 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
|
||||
run: ./runtest --verbose --tags -slow --dump-logs
|
||||
- name: module api test
|
||||
run: ./runtest-moduleapi --verbose --dump-logs
|
||||
run: CFLAGS='-Werror' ./runtest-moduleapi --verbose --dump-logs
|
||||
|
||||
build-debian-old:
|
||||
runs-on: ubuntu-latest
|
||||
container: debian:buster
|
||||
container: debian:bullseye
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
- 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@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
- 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@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
- 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@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
- 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@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
|
||||
- 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'
|
||||
|
||||
|
||||
@@ -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@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
|
||||
- name: Install lcov and run test
|
||||
run: |
|
||||
sudo apt-get install lcov
|
||||
make lcov
|
||||
|
||||
- name: Upload code coverage
|
||||
uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5.5.2
|
||||
with:
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
file: ./src/valkey.info
|
||||
@@ -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@b5ebac6f4c00c8ccddb7cdcd45fdb248329f808a # v3.32.2
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v2
|
||||
uses: github/codeql-action/autobuild@b5ebac6f4c00c8ccddb7cdcd45fdb248329f808a # v3.32.2
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v2
|
||||
uses: github/codeql-action/analyze@b5ebac6f4c00c8ccddb7cdcd45fdb248329f808a # v3.32.2
|
||||
|
||||
@@ -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@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
- 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
|
||||
+454
-325
File diff suppressed because it is too large
Load Diff
@@ -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@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
- 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@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.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@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
- 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@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.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@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
- 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@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
|
||||
with:
|
||||
name: test-external-redis-log
|
||||
path: external-redis.log
|
||||
name: test-external-nodebug-log
|
||||
path: external-server.log
|
||||
|
||||
@@ -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@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
- name: Setup nodejs
|
||||
uses: actions/setup-node@v3
|
||||
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
|
||||
- name: Install packages
|
||||
run: npm install ajv
|
||||
- name: linter
|
||||
|
||||
@@ -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@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
|
||||
- name: pip cache
|
||||
uses: actions/cache@v3
|
||||
- name: Install typos
|
||||
uses: taiki-e/install-action@d4422f254e595ee762a758628fe4f16ce050fa2e # v2.67.28
|
||||
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@28959ce8df70de7be546dd1250a005dd32156697 # v4.0.1
|
||||
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
@@ -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/*
|
||||
|
||||
+288
-11
@@ -1,16 +1,293 @@
|
||||
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.13 - Tue 05 May 2026
|
||||
================================================================================
|
||||
|
||||
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!
|
||||
Security fixes
|
||||
==============
|
||||
* (CVE-2026-23479) Use-After-Free in unblock client flow
|
||||
* (CVE-2026-25243) Invalid Memory Access in RESTORE command
|
||||
* (CVE-2026-23631) Use-after-free when full sync occurs during a yielding Lua/function execution
|
||||
|
||||
================================================================================
|
||||
Valkey 7.2.12 - Released Mon 23 February 2026
|
||||
================================================================================
|
||||
|
||||
Upgrade urgency SECURITY: This release includes security fixes we recommend you
|
||||
apply as soon as possible.
|
||||
|
||||
Security fixes
|
||||
==============
|
||||
* (CVE-2026-21863) Remote DoS with malformed Valkey Cluster bus message
|
||||
* (CVE-2025-67733) RESP Protocol Injection via Lua error_reply
|
||||
|
||||
Bug fixes
|
||||
=========
|
||||
* Fix ltrim should not call signalModifiedKey when no elements are removed (#2787)
|
||||
* Fix potential infinite loop in clusterNodeGetMaster (#2830)
|
||||
* Avoids crash during MODULE UNLOAD when ACL rules reference a module command and subcommand (#3160)
|
||||
|
||||
================================================================================
|
||||
Valkey 7.2.11 - Released Fri 03 October 2025
|
||||
================================================================================
|
||||
|
||||
Upgrade urgency SECURITY: This release includes security fixes we recommend you
|
||||
apply as soon as possible.
|
||||
|
||||
Security fixes
|
||||
==============
|
||||
* (CVE-2025-49844) A Lua script may lead to remote code execution
|
||||
* (CVE-2025-46817) A Lua script may lead to integer overflow and potential RCE
|
||||
* (CVE-2025-46818) A Lua script can be executed in the context of another user
|
||||
* (CVE-2025-46819) LUA out-of-bound read
|
||||
|
||||
Bug fixes
|
||||
=========
|
||||
|
||||
* Ensure empty error tables in Lua scripts don't crash Valkey (#2229)
|
||||
* Fix client tracking memory overhead calculation (#2360)
|
||||
|
||||
================================================================================
|
||||
Valkey 7.2.10 - Released Fri 20 June 2025
|
||||
================================================================================
|
||||
|
||||
Upgrade urgency HIGH: This release includes CVE fix for valkey-check-aof tool, we recommend you
|
||||
apply as soon as possible if you use the tool.
|
||||
|
||||
Bug fixes
|
||||
=========
|
||||
* Fix a bug that allowed clients to process commands when the server has paused command processing (#2231)
|
||||
* Fix a crash when a module attempts to write auxiliary data with AOF enabled (#2132)
|
||||
* Fix a bug where the engine may crash when establishing new outbound TLS connections (#2140)
|
||||
* Fix a bug where a cluster bus packet may be incorrectly marked as invalid (#2144)
|
||||
* Fix a bug where CLUSTER SLOTS/NODES information can be stale after updating node port/tls-port (#2186)
|
||||
* Fix a bug where replica in cluster mode can't finish failover when config epoch is outdated (#2232)
|
||||
* Fix a bug to avoid CLIENT UNBLOCK command to unblock paused clients (#2117)
|
||||
|
||||
Security fixes
|
||||
==============
|
||||
* CVE-2025-27151 Check length of AOF file name in valkey-check-aof (#2146)
|
||||
* CVE-2025-32023 prevent out-of-bounds write during hyperloglog operations (#2314)
|
||||
* CVE-2025-48367 retry accept on transient errors (#2315)
|
||||
|
||||
================================================================================
|
||||
Valkey 7.2.9 - Released Wed 23 Apr 2025
|
||||
================================================================================
|
||||
|
||||
Upgrade urgency SECURITY: This release includes security fixes we recommend you
|
||||
apply as soon as possible.
|
||||
|
||||
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!
|
||||
|
||||
@@ -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).
|
||||
[](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
@@ -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 you’ve 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,
|
||||
we’ll 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 vendor’s 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
@@ -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
|
||||
Vendored
+4
-3
@@ -340,13 +340,14 @@ static int luaB_assert (lua_State *L) {
|
||||
|
||||
|
||||
static int luaB_unpack (lua_State *L) {
|
||||
int i, e, n;
|
||||
int i, e;
|
||||
unsigned int n;
|
||||
luaL_checktype(L, 1, LUA_TTABLE);
|
||||
i = luaL_optint(L, 2, 1);
|
||||
e = luaL_opt(L, luaL_checkint, 3, luaL_getn(L, 1));
|
||||
if (i > e) return 0; /* empty range */
|
||||
n = e - i + 1; /* number of elements */
|
||||
if (n <= 0 || !lua_checkstack(L, n)) /* n <= 0 means arith. overflow */
|
||||
n = (unsigned int)e - (unsigned int)i; /* number of elements minus 1 */
|
||||
if (n >= INT_MAX || !lua_checkstack(L, ++n))
|
||||
return luaL_error(L, "too many results to unpack");
|
||||
lua_rawgeti(L, 1, i); /* push arg[i] (avoiding overflow problems) */
|
||||
while (i++ < e) /* push arg[i + 1...e] */
|
||||
|
||||
Vendored
+21
-12
@@ -138,6 +138,7 @@ static void inclinenumber (LexState *ls) {
|
||||
|
||||
|
||||
void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, TString *source) {
|
||||
ls->t.token = 0;
|
||||
ls->decpoint = '.';
|
||||
ls->L = L;
|
||||
ls->lookahead.token = TK_EOS; /* no look-ahead token */
|
||||
@@ -207,8 +208,13 @@ static void read_numeral (LexState *ls, SemInfo *seminfo) {
|
||||
}
|
||||
|
||||
|
||||
static int skip_sep (LexState *ls) {
|
||||
int count = 0;
|
||||
/*
|
||||
** reads a sequence '[=*[' or ']=*]', leaving the last bracket.
|
||||
** If a sequence is well-formed, return its number of '='s + 2; otherwise,
|
||||
** return 1 if there is no '='s or 0 otherwise (an unfinished '[==...').
|
||||
*/
|
||||
static size_t skip_sep (LexState *ls) {
|
||||
size_t count = 0;
|
||||
int s = ls->current;
|
||||
lua_assert(s == '[' || s == ']');
|
||||
save_and_next(ls);
|
||||
@@ -216,11 +222,13 @@ static int skip_sep (LexState *ls) {
|
||||
save_and_next(ls);
|
||||
count++;
|
||||
}
|
||||
return (ls->current == s) ? count : (-count) - 1;
|
||||
return (ls->current == s) ? count + 2
|
||||
: (count == 0) ? 1
|
||||
: 0;
|
||||
}
|
||||
|
||||
|
||||
static void read_long_string (LexState *ls, SemInfo *seminfo, int sep) {
|
||||
static void read_long_string (LexState *ls, SemInfo *seminfo, size_t sep) {
|
||||
int cont = 0;
|
||||
(void)(cont); /* avoid warnings when `cont' is not used */
|
||||
save_and_next(ls); /* skip 2nd `[' */
|
||||
@@ -270,8 +278,8 @@ static void read_long_string (LexState *ls, SemInfo *seminfo, int sep) {
|
||||
}
|
||||
} endloop:
|
||||
if (seminfo)
|
||||
seminfo->ts = luaX_newstring(ls, luaZ_buffer(ls->buff) + (2 + sep),
|
||||
luaZ_bufflen(ls->buff) - 2*(2 + sep));
|
||||
seminfo->ts = luaX_newstring(ls, luaZ_buffer(ls->buff) + sep,
|
||||
luaZ_bufflen(ls->buff) - 2 * sep);
|
||||
}
|
||||
|
||||
|
||||
@@ -346,9 +354,9 @@ static int llex (LexState *ls, SemInfo *seminfo) {
|
||||
/* else is a comment */
|
||||
next(ls);
|
||||
if (ls->current == '[') {
|
||||
int sep = skip_sep(ls);
|
||||
size_t sep = skip_sep(ls);
|
||||
luaZ_resetbuffer(ls->buff); /* `skip_sep' may dirty the buffer */
|
||||
if (sep >= 0) {
|
||||
if (sep >= 2) {
|
||||
read_long_string(ls, NULL, sep); /* long comment */
|
||||
luaZ_resetbuffer(ls->buff);
|
||||
continue;
|
||||
@@ -360,13 +368,14 @@ static int llex (LexState *ls, SemInfo *seminfo) {
|
||||
continue;
|
||||
}
|
||||
case '[': {
|
||||
int sep = skip_sep(ls);
|
||||
if (sep >= 0) {
|
||||
size_t sep = skip_sep(ls);
|
||||
if (sep >= 2) {
|
||||
read_long_string(ls, seminfo, sep);
|
||||
return TK_STRING;
|
||||
}
|
||||
else if (sep == -1) return '[';
|
||||
else luaX_lexerror(ls, "invalid long string delimiter", TK_STRING);
|
||||
else if (sep == 0) /* '[=...' missing second bracket */
|
||||
luaX_lexerror(ls, "invalid long string delimiter", TK_STRING);
|
||||
return '[';
|
||||
}
|
||||
case '=': {
|
||||
next(ls);
|
||||
|
||||
Vendored
+5
-1
@@ -384,13 +384,17 @@ Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, const char *name) {
|
||||
struct LexState lexstate;
|
||||
struct FuncState funcstate;
|
||||
lexstate.buff = buff;
|
||||
luaX_setinput(L, &lexstate, z, luaS_new(L, name));
|
||||
TString *tname = luaS_new(L, name);
|
||||
setsvalue2s(L, L->top, tname);
|
||||
incr_top(L);
|
||||
luaX_setinput(L, &lexstate, z, tname);
|
||||
open_func(&lexstate, &funcstate);
|
||||
funcstate.f->is_vararg = VARARG_ISVARARG; /* main func. is always vararg */
|
||||
luaX_next(&lexstate); /* read first token */
|
||||
chunk(&lexstate);
|
||||
check(&lexstate, TK_EOS);
|
||||
close_func(&lexstate);
|
||||
--L->top;
|
||||
lua_assert(funcstate.prev == NULL);
|
||||
lua_assert(funcstate.f->nups == 0);
|
||||
lua_assert(lexstate.fs == NULL);
|
||||
|
||||
Vendored
+1
-2
@@ -434,8 +434,7 @@ static TValue *newkey (lua_State *L, Table *t, const TValue *key) {
|
||||
** search function for integers
|
||||
*/
|
||||
const TValue *luaH_getnum (Table *t, int key) {
|
||||
/* (1 <= key && key <= t->sizearray) */
|
||||
if (cast(unsigned int, key-1) < cast(unsigned int, t->sizearray))
|
||||
if (1 <= key && key <= t->sizearray)
|
||||
return &t->array[key-1];
|
||||
else {
|
||||
lua_Number nk = cast_num(key);
|
||||
|
||||
Vendored
+1
@@ -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; }
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/bin/sh
|
||||
TCL_VERSIONS="8.5 8.6 8.7"
|
||||
TCL_VERSIONS="8.5 8.6 8.7 9.0"
|
||||
TCLSH=""
|
||||
|
||||
for VERSION in $TCL_VERSIONS; do
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
#!/bin/sh
|
||||
TCL_VERSIONS="8.5 8.6 8.7"
|
||||
TCL_VERSIONS="8.5 8.6 8.7 9.0"
|
||||
TCLSH=""
|
||||
|
||||
for VERSION in $TCL_VERSIONS; do
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
#!/bin/sh
|
||||
TCL_VERSIONS="8.5 8.6 8.7"
|
||||
TCL_VERSIONS="8.5 8.6 8.7 9.0"
|
||||
TCLSH=""
|
||||
[ -z "$MAKE" ] && MAKE=make
|
||||
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
#!/bin/sh
|
||||
TCL_VERSIONS="8.5 8.6 8.7"
|
||||
TCL_VERSIONS="8.5 8.6 8.7 9.0"
|
||||
TCLSH=""
|
||||
|
||||
for VERSION in $TCL_VERSIONS; do
|
||||
|
||||
+27
-30
@@ -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
|
||||
|
||||
+81
-34
@@ -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)
|
||||
@@ -359,6 +390,9 @@ all: $(REDIS_SERVER_NAME) $(REDIS_SENTINEL_NAME) $(REDIS_CLI_NAME) $(REDIS_BENCH
|
||||
@echo "Hint: It's a good idea to run 'make test' ;)"
|
||||
@echo ""
|
||||
|
||||
all-with-unit-tests: all
|
||||
.PHONY: all-with-unit-tests
|
||||
|
||||
Makefile.dep:
|
||||
-$(REDIS_CC) -MM $(ALL_SOURCES) > Makefile.dep 2> /dev/null || true
|
||||
|
||||
@@ -377,8 +411,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 +432,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 +507,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 +525,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 +534,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 +544,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))
|
||||
|
||||
@@ -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},
|
||||
@@ -146,6 +146,7 @@ void ACLResetFirstArgs(aclSelector *selector);
|
||||
void ACLAddAllowedFirstArg(aclSelector *selector, unsigned long id, const char *sub);
|
||||
void ACLFreeLogEntry(void *le);
|
||||
int ACLSetSelector(aclSelector *selector, const char *op, size_t oplen);
|
||||
struct redisCommand *ACLLookupCommand(const char *name);
|
||||
|
||||
/* The length of the string representation of a hashed password. */
|
||||
#define HASH_PASSWORD_LEN (SHA256_BLOCK_SIZE*2)
|
||||
@@ -456,8 +457,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) {
|
||||
@@ -489,10 +489,14 @@ void ACLCopyUser(user *dst, user *src) {
|
||||
}
|
||||
}
|
||||
|
||||
static void ACLFreeUserAndKillClientsVoid(void *u) {
|
||||
ACLFreeUserAndKillClients(u);
|
||||
}
|
||||
|
||||
/* Free all the users registered in the radix tree 'users' and free the
|
||||
* radix tree itself. */
|
||||
void ACLFreeUsersSet(rax *users) {
|
||||
raxFreeWithCallback(users,(void(*)(void*))ACLFreeUserAndKillClients);
|
||||
raxFreeWithCallback(users,ACLFreeUserAndKillClientsVoid);
|
||||
}
|
||||
|
||||
/* Given a command ID, this function set by reference 'word' and 'bit'
|
||||
@@ -723,6 +727,57 @@ int ACLCountCategoryBitsForSelector(aclSelector *selector, unsigned long *on, un
|
||||
return C_OK;
|
||||
}
|
||||
|
||||
/* Check if any ACL user has command rules referencing the specified module.
|
||||
* If rule_out is not NULL, it will be set to a duplicate of the first matching
|
||||
* rule.
|
||||
* Returns 1 if any rules are found, 0 otherwise. */
|
||||
int ACLModuleHasCommandRules(const struct ValkeyModule *module, sds *rule_out) {
|
||||
raxIterator ri;
|
||||
raxStart(&ri, Users);
|
||||
raxSeek(&ri, "^", NULL, 0);
|
||||
while (raxNext(&ri)) {
|
||||
user *u = ri.data;
|
||||
listIter li;
|
||||
listNode *ln;
|
||||
listRewind(u->selectors, &li);
|
||||
while ((ln = listNext(&li)) != NULL) {
|
||||
aclSelector *selector = listNodeValue(ln);
|
||||
if (sdslen(selector->command_rules) == 0) continue;
|
||||
|
||||
int argc = 0;
|
||||
sds *argv = sdssplitargs(selector->command_rules, &argc);
|
||||
if (!argv) continue;
|
||||
|
||||
for (int i = 0; i < argc; i++) {
|
||||
sds rule = argv[i];
|
||||
if (rule[0] != '+' && rule[0] != '-') continue;
|
||||
if (rule[1] == '@') continue;
|
||||
|
||||
struct redisCommand *cmd = ACLLookupCommand(rule + 1);
|
||||
if (!cmd) {
|
||||
const char *subsep = strchr(rule + 1, '|');
|
||||
if (subsep) {
|
||||
size_t base_len = (size_t)(subsep - (rule + 1));
|
||||
sds base = sdsnewlen(rule + 1, base_len);
|
||||
cmd = ACLLookupCommand(base);
|
||||
sdsfree(base);
|
||||
}
|
||||
}
|
||||
if (!cmd || !(cmd->flags & CMD_MODULE)) continue;
|
||||
if (moduleFromCommand(cmd) != module) continue;
|
||||
|
||||
if (rule_out) *rule_out = sdsdup(rule);
|
||||
sdsfreesplitres(argv, argc);
|
||||
raxStop(&ri);
|
||||
return 1;
|
||||
}
|
||||
sdsfreesplitres(argv, argc);
|
||||
}
|
||||
}
|
||||
raxStop(&ri);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This function returns an SDS string representing the specified selector ACL
|
||||
* rules related to command execution, in the same format you could set them
|
||||
* back using ACL SETUSER. The function will return just the set of rules needed
|
||||
@@ -1046,6 +1101,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 +1111,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 +1521,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 +2267,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 +2529,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) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
+37
-5
@@ -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,13 +511,42 @@ 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;
|
||||
}
|
||||
|
||||
/* For some error cases indicates transient errors and accept can be retried
|
||||
* in order to serve other pending connections. This function should be called with the last errno,
|
||||
* right after anetTcpaccept or anetUnixAccept returned an error in order to retry them. */
|
||||
int anetRetryAcceptOnError(int err) {
|
||||
/* This is a transient error which can happen, for example, when
|
||||
* a client initiates a TCP handshake (SYN),
|
||||
* the server receives and queues it in the pending connections queue (the SYN queue),
|
||||
* but before accept() is called, the connection is aborted.
|
||||
* in such cases we can continue accepting other connections. ß*/
|
||||
if (err == ECONNABORTED)
|
||||
return 1;
|
||||
|
||||
#if defined(__linux__)
|
||||
/* https://www.man7.org/linux/man-pages/man2/accept4.2 suggests that:
|
||||
* Linux accept() (and accept4()) passes already-pending network
|
||||
errors on the new socket as an error code from accept(). This
|
||||
behavior differs from other BSD socket implementations. For
|
||||
reliable operation the application should detect the network
|
||||
errors defined for the protocol after accept() and treat them like
|
||||
EAGAIN by retrying. In the case of TCP/IP, these are ENETDOWN,
|
||||
EPROTO, ENOPROTOOPT, EHOSTDOWN, ENONET, EHOSTUNREACH, EOPNOTSUPP,
|
||||
and ENETUNREACH. */
|
||||
if (err == ENETDOWN || err == EPROTO || err == ENOPROTOOPT ||
|
||||
err == EHOSTDOWN || err == ENONET || err == EHOSTUNREACH ||
|
||||
err == EOPNOTSUPP || err == ENETUNREACH) {
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Accept a connection and also make sure the socket is non-blocking, and CLOEXEC.
|
||||
* returns the new socket FD, or -1 on error. */
|
||||
static int anetGenericAccept(char *err, int s, struct sockaddr *sa, socklen_t *len) {
|
||||
|
||||
@@ -71,5 +71,6 @@ int anetPipe(int fds[2], int read_flags, int write_flags);
|
||||
int anetSetSockMarkId(char *err, int fd, uint32_t id);
|
||||
int anetGetError(int fd);
|
||||
int anetIsFifo(char *filepath);
|
||||
int anetRetryAcceptOnError(int err);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -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
@@ -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";
|
||||
|
||||
@@ -140,9 +140,10 @@ void bioInit(void) {
|
||||
* function accepts in order to pass the job ID the thread is
|
||||
* responsible for. */
|
||||
for (j = 0; j < BIO_WORKER_NUM; j++) {
|
||||
void *arg = (void*)(unsigned long) j;
|
||||
if (pthread_create(&thread,&attr,bioProcessBackgroundJobs,arg) != 0) {
|
||||
serverLog(LL_WARNING, "Fatal: Can't initialize Background Jobs. Error message: %s", strerror(errno));
|
||||
void *arg = (void *)(unsigned long)j;
|
||||
int err = pthread_create(&thread, &attr, bioProcessBackgroundJobs, arg);
|
||||
if (err) {
|
||||
serverLog(LL_WARNING, "Fatal: Can't initialize Background Jobs. Error message: %s", strerror(err));
|
||||
exit(1);
|
||||
}
|
||||
bio_threads[j] = thread;
|
||||
@@ -221,9 +222,9 @@ void *bioProcessBackgroundJobs(void *arg) {
|
||||
* receive the watchdog signal. */
|
||||
sigemptyset(&sigset);
|
||||
sigaddset(&sigset, SIGALRM);
|
||||
if (pthread_sigmask(SIG_BLOCK, &sigset, NULL))
|
||||
serverLog(LL_WARNING,
|
||||
"Warning: can't mask SIGALRM in bio.c thread: %s", strerror(errno));
|
||||
int err = pthread_sigmask(SIG_BLOCK, &sigset, NULL);
|
||||
if (err)
|
||||
serverLog(LL_WARNING, "Warning: can't mask SIGALRM in bio.c thread: %s", strerror(err));
|
||||
|
||||
while(1) {
|
||||
listNode *ln;
|
||||
|
||||
+33
-3
@@ -223,6 +223,22 @@ void unblockClient(client *c, int queue_for_reprocessing) {
|
||||
if (queue_for_reprocessing) queueClientForReprocessing(c);
|
||||
}
|
||||
|
||||
/* Check if the specified client can be safely timed out using
|
||||
* unblockClientOnTimeout(). */
|
||||
int blockedClientMayTimeout(client *c) {
|
||||
if (c->bstate.btype == BLOCKED_MODULE) {
|
||||
return moduleBlockedClientMayTimeout(c);
|
||||
}
|
||||
|
||||
if (c->bstate.btype == BLOCKED_LIST ||
|
||||
c->bstate.btype == BLOCKED_ZSET ||
|
||||
c->bstate.btype == BLOCKED_STREAM ||
|
||||
c->bstate.btype == BLOCKED_WAIT) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This function gets called when a blocked client timed out in order to
|
||||
* send it a reply of some kind. After this function is called,
|
||||
* unblockClient() will be called with the same client as argument. */
|
||||
@@ -370,7 +386,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 +413,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 +646,7 @@ void blockPostponeClient(client *c) {
|
||||
|
||||
/* Block client due to shutdown command */
|
||||
void blockClientShutdown(client *c) {
|
||||
c->bstate.timeout = 0;
|
||||
blockClient(c, BLOCKED_SHUTDOWN);
|
||||
}
|
||||
|
||||
@@ -652,6 +673,7 @@ static void unblockClientOnKey(client *c, robj *key) {
|
||||
* we need to re process the command again */
|
||||
if (c->flags & CLIENT_PENDING_COMMAND) {
|
||||
c->flags &= ~CLIENT_PENDING_COMMAND;
|
||||
c->flags |= CLIENT_REPROCESSING_COMMAND;
|
||||
/* We want the command processing and the unblock handler (see RM_Call 'K' option)
|
||||
* to run atomically, this is why we must enter the execution unit here before
|
||||
* running the command, and exit the execution unit after calling the unblock handler (if exists).
|
||||
@@ -660,7 +682,13 @@ static void unblockClientOnKey(client *c, robj *key) {
|
||||
client *old_client = server.current_client;
|
||||
server.current_client = c;
|
||||
enterExecutionUnit(1, 0);
|
||||
processCommandAndResetClient(c);
|
||||
if (processCommandAndResetClient(c) == C_ERR) {
|
||||
/* Client was freed during command processing, exit immediately */
|
||||
exitExecutionUnit();
|
||||
server.current_client = old_client;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(c->flags & CLIENT_BLOCKED)) {
|
||||
if (c->flags & CLIENT_MODULE) {
|
||||
moduleCallCommandUnblockedHandler(c);
|
||||
@@ -670,6 +698,8 @@ static void unblockClientOnKey(client *c, robj *key) {
|
||||
}
|
||||
exitExecutionUnit();
|
||||
afterCommand(c);
|
||||
/* Clear the reprocessing command flag after the proc is executed. */
|
||||
c->flags &= ~CLIENT_REPROCESSING_COMMAND;
|
||||
server.current_client = old_client;
|
||||
}
|
||||
}
|
||||
|
||||
+57
-57
@@ -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;
|
||||
@@ -554,7 +554,7 @@ CallReply *callReplyCreateError(sds reply, void *private_data) {
|
||||
sdsfree(reply);
|
||||
}
|
||||
list *deferred_error_list = listCreate();
|
||||
listSetFreeMethod(deferred_error_list, (void (*)(void*))sdsfree);
|
||||
listSetFreeMethod(deferred_error_list, sdsfreeVoid);
|
||||
listAddNodeTail(deferred_error_list, sdsnew(err_buff));
|
||||
return callReplyCreate(err_buff, deferred_error_list, private_data);
|
||||
}
|
||||
|
||||
+1
-1
@@ -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);
|
||||
|
||||
+265
-100
@@ -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. */
|
||||
@@ -89,6 +95,7 @@ unsigned int delKeysInSlot(unsigned int hashslot);
|
||||
void clusterAddNodeToShard(const char *shard_id, clusterNode *node);
|
||||
list *clusterLookupNodeListByShardId(const char *shard_id);
|
||||
void clusterRemoveNodeFromShard(clusterNode *node);
|
||||
void clusterSaveConfigOrDie(int do_fsync);
|
||||
int auxShardIdSetter(clusterNode *n, void *value, int length);
|
||||
sds auxShardIdGetter(clusterNode *n, sds s);
|
||||
int auxShardIdPresent(clusterNode *n);
|
||||
@@ -119,6 +126,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) \
|
||||
@@ -232,16 +253,25 @@ int isValidAuxString(char *s, unsigned int length) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int shard_id_reconciled = 0;
|
||||
|
||||
int auxShardIdSetter(clusterNode *n, void *value, int length) {
|
||||
if (verifyClusterNodeId(value, length) == C_ERR) {
|
||||
return C_ERR;
|
||||
}
|
||||
memcpy(n->shard_id, value, CLUSTER_NAMELEN);
|
||||
/* if n already has replicas, make sure they all agree
|
||||
* on the shard id */
|
||||
* on the shard id. If not, update them. */
|
||||
for (int i = 0; i < n->numslaves; i++) {
|
||||
if (memcmp(n->slaves[i]->shard_id, n->shard_id, CLUSTER_NAMELEN) != 0) {
|
||||
return C_ERR;
|
||||
serverLog(LL_NOTICE,
|
||||
"Node %.40s has a different shard id (%.40s) than its master's shard id %.40s (%.40s). "
|
||||
"Updating replica's shard id to match master's shard id.",
|
||||
n->slaves[i]->name, n->slaves[i]->shard_id, n->name, n->shard_id);
|
||||
clusterRemoveNodeFromShard(n->slaves[i]);
|
||||
memcpy(n->slaves[i]->shard_id, n->shard_id, CLUSTER_NAMELEN);
|
||||
clusterAddNodeToShard(n->shard_id, n->slaves[i]);
|
||||
shard_id_reconciled = 1;
|
||||
}
|
||||
}
|
||||
clusterAddNodeToShard(value, n);
|
||||
@@ -322,9 +352,16 @@ int auxTlsPortPresent(clusterNode *n) {
|
||||
typedef struct {
|
||||
size_t totlen; /* Total length of this block including the message */
|
||||
int refcount; /* Number of cluster link send msg queues containing the message */
|
||||
clusterMsg msg;
|
||||
struct {
|
||||
clusterMsg msg;
|
||||
} data[];
|
||||
} clusterMsgSendBlock;
|
||||
|
||||
/* Helper function to extract a light message from a send block. */
|
||||
static clusterMsg *getMessageFromSendBlock(clusterMsgSendBlock *msgblock) {
|
||||
return &msgblock->data[0].msg;
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* Initialization
|
||||
* -------------------------------------------------------------------------- */
|
||||
@@ -340,6 +377,7 @@ int clusterLoadConfig(char *filename) {
|
||||
struct stat sb;
|
||||
char *line;
|
||||
int maxline, j;
|
||||
int dirty = 0;
|
||||
|
||||
if (fp == NULL) {
|
||||
if (errno == ENOENT) {
|
||||
@@ -588,9 +626,17 @@ int clusterLoadConfig(char *filename) {
|
||||
} else if (clusterGetNodesInMyShard(master) != NULL &&
|
||||
memcmp(master->shard_id, n->shard_id, CLUSTER_NAMELEN) != 0)
|
||||
{
|
||||
/* If the primary has been added to a shard, make sure this
|
||||
* node has the same persisted shard id as the primary. */
|
||||
goto fmterr;
|
||||
/* If the master has been added to a shard and this replica has
|
||||
* a different shard id stored in nodes.conf, update it to match
|
||||
* the master instead of aborting the startup. */
|
||||
serverLog(LL_NOTICE,
|
||||
"Node %.40s has a different shard id (%.40s) than its master %.40s (%.40s). "
|
||||
"Updating replica's shard id to match master's shard id.",
|
||||
n->name, n->shard_id, master->name, master->shard_id);
|
||||
clusterRemoveNodeFromShard(n);
|
||||
memcpy(n->shard_id, master->shard_id, CLUSTER_NAMELEN);
|
||||
clusterAddNodeToShard(master->shard_id, n);
|
||||
dirty = 1;
|
||||
}
|
||||
n->slaveof = master;
|
||||
clusterNodeAddSlave(master,n);
|
||||
@@ -681,6 +727,8 @@ int clusterLoadConfig(char *filename) {
|
||||
if (clusterGetMaxEpoch() > server.cluster->currentEpoch) {
|
||||
server.cluster->currentEpoch = clusterGetMaxEpoch();
|
||||
}
|
||||
if (dirty || shard_id_reconciled) clusterSaveConfigOrDie(1);
|
||||
shard_id_reconciled = 0;
|
||||
return C_OK;
|
||||
|
||||
fmterr:
|
||||
@@ -874,6 +922,7 @@ void clusterUpdateMyselfFlags(void) {
|
||||
void clusterUpdateMyselfAnnouncedPorts(void) {
|
||||
if (!myself) return;
|
||||
deriveAnnouncedPorts(&myself->tcp_port,&myself->tls_port,&myself->cport);
|
||||
clusterDoBeforeSleep(CLUSTER_TODO_SAVE_CONFIG);
|
||||
}
|
||||
|
||||
/* We want to take myself->ip in sync with the cluster-announce-ip option.
|
||||
@@ -901,6 +950,7 @@ void clusterUpdateMyselfIp(void) {
|
||||
} else {
|
||||
myself->ip[0] = '\0'; /* Force autodetection. */
|
||||
}
|
||||
clusterDoBeforeSleep(CLUSTER_TODO_SAVE_CONFIG);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -938,13 +988,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 +1024,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 +1170,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;
|
||||
@@ -1153,12 +1206,12 @@ void clusterReset(int hard) {
|
||||
* CLUSTER communication link
|
||||
* -------------------------------------------------------------------------- */
|
||||
static clusterMsgSendBlock *createClusterMsgSendBlock(int type, uint32_t msglen) {
|
||||
uint32_t blocklen = msglen + sizeof(clusterMsgSendBlock) - sizeof(clusterMsg);
|
||||
uint32_t blocklen = msglen + offsetof(clusterMsgSendBlock, data);
|
||||
clusterMsgSendBlock *msgblock = zcalloc(blocklen);
|
||||
msgblock->refcount = 1;
|
||||
msgblock->totlen = blocklen;
|
||||
server.stat_cluster_links_memory += blocklen;
|
||||
clusterBuildMessageHdr(&msgblock->msg,type,msglen);
|
||||
clusterBuildMessageHdr(getMessageFromSendBlock(msgblock), type, msglen);
|
||||
return msgblock;
|
||||
}
|
||||
|
||||
@@ -1276,6 +1329,7 @@ void clusterAcceptHandler(aeEventLoop *el, int fd, void *privdata, int mask) {
|
||||
while(max--) {
|
||||
cfd = anetTcpAccept(server.neterr, fd, cip, sizeof(cip), &cport);
|
||||
if (cfd == ANET_ERR) {
|
||||
if (anetRetryAcceptOnError(errno)) continue;
|
||||
if (errno != EWOULDBLOCK)
|
||||
serverLog(LL_VERBOSE,
|
||||
"Error accepting cluster node: %s", server.neterr);
|
||||
@@ -1670,6 +1724,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 +1998,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 +2042,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 +2191,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 +2250,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 +2289,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 +2467,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 +2639,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 +2681,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 +2703,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 +2711,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 +2733,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 +2805,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;
|
||||
}
|
||||
|
||||
@@ -2736,17 +2827,38 @@ int clusterProcessPacket(clusterLink *link) {
|
||||
explen = sizeof(clusterMsg)-sizeof(union clusterMsgData);
|
||||
explen += (sizeof(clusterMsgDataGossip)*count);
|
||||
|
||||
/* Make sure that the number of gossip messages fit in the remaining
|
||||
* space in the message. */
|
||||
if (totlen < explen) {
|
||||
serverLog(LL_WARNING,
|
||||
"Received invalid %s packet with gossip count %d that exceeds "
|
||||
"total packet length (%lld)",
|
||||
clusterGetMessageTypeString(type), count, (unsigned long long)totlen);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* If there is extension data, which doesn't have a fixed length,
|
||||
* loop through them and validate the length of it now. */
|
||||
if (hdr->mflags[0] & CLUSTERMSG_FLAG0_EXT_DATA) {
|
||||
clusterMsgPingExt *ext = getInitialPingExt(hdr, count);
|
||||
while (extensions--) {
|
||||
uint16_t extlen = getPingExtLength(ext);
|
||||
/* Make sure there is at least enough memory for the extension information so
|
||||
* we can parse it. */
|
||||
if ((totlen - explen) < sizeof(clusterMsgPingExt)) {
|
||||
serverLog(LL_WARNING,
|
||||
"Received invalid %s packet with extension data that exceeds "
|
||||
"total packet length (%lld)",
|
||||
clusterGetMessageTypeString(type), (unsigned long long)totlen);
|
||||
return 1;
|
||||
}
|
||||
uint32_t extlen = getPingExtLength(ext);
|
||||
if (extlen % 8 != 0) {
|
||||
serverLog(LL_WARNING, "Received a %s packet without proper padding (%d bytes)",
|
||||
clusterGetMessageTypeString(type), (int) extlen);
|
||||
return 1;
|
||||
}
|
||||
/* Similar check to earlier, but we want to make sure the extension length is valid
|
||||
* this time. */
|
||||
if ((totlen - explen) < extlen) {
|
||||
serverLog(LL_WARNING, "Received invalid %s packet with extension data that exceeds "
|
||||
"total packet length (%lld)", clusterGetMessageTypeString(type),
|
||||
@@ -2791,6 +2903,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 +3005,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 +3132,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);
|
||||
}
|
||||
@@ -3069,9 +3197,11 @@ int clusterProcessPacket(clusterLink *link) {
|
||||
senderConfigEpoch)
|
||||
{
|
||||
serverLog(LL_VERBOSE,
|
||||
"Node %.40s has old slots configuration, sending "
|
||||
"an UPDATE message about %.40s",
|
||||
sender->name, server.cluster->slots[j]->name);
|
||||
"Node %.40s (%s) has old slots configuration, sending "
|
||||
"an UPDATE message about %.40s (%s)",
|
||||
sender->name, sender->human_nodename,
|
||||
server.cluster->slots[j]->name,
|
||||
server.cluster->slots[j]->human_nodename);
|
||||
clusterSendUpdate(sender->link,
|
||||
server.cluster->slots[j]);
|
||||
|
||||
@@ -3149,10 +3279,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++;
|
||||
@@ -3236,7 +3366,7 @@ void clusterWriteHandler(connection *conn) {
|
||||
while (totwritten < NET_MAX_WRITES_PER_EVENT && listLength(link->send_msg_queue) > 0) {
|
||||
listNode *head = listFirst(link->send_msg_queue);
|
||||
clusterMsgSendBlock *msgblock = (clusterMsgSendBlock*)head->value;
|
||||
clusterMsg *msg = &msgblock->msg;
|
||||
clusterMsg *msg = getMessageFromSendBlock(msgblock);
|
||||
size_t msg_offset = link->head_msg_send_offset;
|
||||
size_t msg_len = ntohl(msg->totlen);
|
||||
|
||||
@@ -3303,12 +3433,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);
|
||||
@@ -3410,7 +3546,7 @@ void clusterSendMessage(clusterLink *link, clusterMsgSendBlock *msgblock) {
|
||||
if (!link) {
|
||||
return;
|
||||
}
|
||||
if (listLength(link->send_msg_queue) == 0 && msgblock->msg.totlen != 0)
|
||||
if (listLength(link->send_msg_queue) == 0 && getMessageFromSendBlock(msgblock)->totlen != 0)
|
||||
connSetWriteHandlerWithBarrier(link->conn, clusterWriteHandler, 1);
|
||||
|
||||
listAddNodeTail(link->send_msg_queue, msgblock);
|
||||
@@ -3421,7 +3557,7 @@ void clusterSendMessage(clusterLink *link, clusterMsgSendBlock *msgblock) {
|
||||
server.stat_cluster_links_memory += sizeof(listNode);
|
||||
|
||||
/* Populate sent messages stats. */
|
||||
uint16_t type = ntohs(msgblock->msg.type);
|
||||
uint16_t type = ntohs(getMessageFromSendBlock(msgblock)->type);
|
||||
if (type < CLUSTERMSG_TYPE_COUNT)
|
||||
server.cluster->stats_bus_messages_sent[type]++;
|
||||
}
|
||||
@@ -3587,12 +3723,14 @@ 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);
|
||||
clusterMsgSendBlock *msgblock = createClusterMsgSendBlock(type, estlen);
|
||||
clusterMsg *hdr = &msgblock->msg;
|
||||
clusterMsg *hdr = getMessageFromSendBlock(msgblock);
|
||||
|
||||
if (!link->inbound && type == CLUSTERMSG_TYPE_PING)
|
||||
link->node->ping_sent = mstime();
|
||||
@@ -3655,7 +3793,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);
|
||||
@@ -3723,7 +3867,7 @@ clusterMsgSendBlock *clusterCreatePublishMsgBlock(robj *channel, robj *message,
|
||||
msglen += sizeof(clusterMsgDataPublish) - 8 + channel_len + message_len;
|
||||
clusterMsgSendBlock *msgblock = createClusterMsgSendBlock(type, msglen);
|
||||
|
||||
clusterMsg *hdr = &msgblock->msg;
|
||||
clusterMsg *hdr = getMessageFromSendBlock(msgblock);
|
||||
hdr->data.publish.msg.channel_len = htonl(channel_len);
|
||||
hdr->data.publish.msg.message_len = htonl(message_len);
|
||||
memcpy(hdr->data.publish.msg.bulk_data,channel->ptr,sdslen(channel->ptr));
|
||||
@@ -3746,7 +3890,7 @@ void clusterSendFail(char *nodename) {
|
||||
+ sizeof(clusterMsgDataFail);
|
||||
clusterMsgSendBlock *msgblock = createClusterMsgSendBlock(CLUSTERMSG_TYPE_FAIL, msglen);
|
||||
|
||||
clusterMsg *hdr = &msgblock->msg;
|
||||
clusterMsg *hdr = getMessageFromSendBlock(msgblock);
|
||||
memcpy(hdr->data.fail.about.nodename,nodename,CLUSTER_NAMELEN);
|
||||
|
||||
clusterBroadcastMessage(msgblock);
|
||||
@@ -3763,7 +3907,7 @@ void clusterSendUpdate(clusterLink *link, clusterNode *node) {
|
||||
+ sizeof(clusterMsgDataUpdate);
|
||||
clusterMsgSendBlock *msgblock = createClusterMsgSendBlock(CLUSTERMSG_TYPE_UPDATE, msglen);
|
||||
|
||||
clusterMsg *hdr = &msgblock->msg;
|
||||
clusterMsg *hdr = getMessageFromSendBlock(msgblock);
|
||||
memcpy(hdr->data.update.nodecfg.nodename,node->name,CLUSTER_NAMELEN);
|
||||
hdr->data.update.nodecfg.configEpoch = htonu64(node->configEpoch);
|
||||
memcpy(hdr->data.update.nodecfg.slots,node->slots,sizeof(node->slots));
|
||||
@@ -3785,7 +3929,7 @@ void clusterSendModule(clusterLink *link, uint64_t module_id, uint8_t type,
|
||||
msglen += sizeof(clusterMsgModule) - 3 + len;
|
||||
clusterMsgSendBlock *msgblock = createClusterMsgSendBlock(CLUSTERMSG_TYPE_MODULE, msglen);
|
||||
|
||||
clusterMsg *hdr = &msgblock->msg;
|
||||
clusterMsg *hdr = getMessageFromSendBlock(msgblock);
|
||||
hdr->data.module.msg.module_id = module_id; /* Already endian adjusted. */
|
||||
hdr->data.module.msg.type = type;
|
||||
hdr->data.module.msg.len = htonl(len);
|
||||
@@ -3867,11 +4011,10 @@ void clusterRequestFailoverAuth(void) {
|
||||
uint32_t msglen = sizeof(clusterMsg)-sizeof(union clusterMsgData);
|
||||
clusterMsgSendBlock *msgblock = createClusterMsgSendBlock(CLUSTERMSG_TYPE_FAILOVER_AUTH_REQUEST, msglen);
|
||||
|
||||
clusterMsg *hdr = &msgblock->msg;
|
||||
/* If this is a manual failover, set the CLUSTERMSG_FLAG0_FORCEACK bit
|
||||
* in the header to communicate the nodes receiving the message that
|
||||
* they should authorized the failover even if the master is working. */
|
||||
if (server.cluster->mf_end) hdr->mflags[0] |= CLUSTERMSG_FLAG0_FORCEACK;
|
||||
if (server.cluster->mf_end) msgblock->data[0].msg.mflags[0] |= CLUSTERMSG_FLAG0_FORCEACK;
|
||||
clusterBroadcastMessage(msgblock);
|
||||
clusterMsgSendBlockDecrRefCount(msgblock);
|
||||
}
|
||||
@@ -3990,6 +4133,16 @@ void clusterSendFailoverAuthIfNeeded(clusterNode *node, clusterMsg *request) {
|
||||
node->name, node->human_nodename, j,
|
||||
(unsigned long long) server.cluster->slots[j]->configEpoch,
|
||||
(unsigned long long) requestConfigEpoch);
|
||||
|
||||
/* Send an UPDATE message to the replica. After receiving the UPDATE message,
|
||||
* the replica will update the slots config so that it can initiate a failover
|
||||
* again later. Otherwise the replica will never get votes if the primary is down. */
|
||||
serverLog(LL_VERBOSE,
|
||||
"Node %.40s (%s) has old slots configuration, sending "
|
||||
"an UPDATE message about %.40s (%s)",
|
||||
node->name, node->human_nodename,
|
||||
server.cluster->slots[j]->name, server.cluster->slots[j]->human_nodename);
|
||||
clusterSendUpdate(node->link, server.cluster->slots[j]);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -4234,7 +4387,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 +4890,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 +4926,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 +5078,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 +5171,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 +5724,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 +5843,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 +5852,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 +6103,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 +6469,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 +7595,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 +7626,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 +7639,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 +7787,15 @@ unsigned int countKeysInSlot(unsigned int hashslot) {
|
||||
return (*server.db->slots_to_keys).by_slot[hashslot].count;
|
||||
}
|
||||
|
||||
clusterNode *clusterNodeGetMaster(clusterNode *node) {
|
||||
clusterNode *master = node;
|
||||
while (master->slaveof != NULL) {
|
||||
master = master->slaveof;
|
||||
if (master == node) break;
|
||||
}
|
||||
return master;
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* Operation(s) on channel rax tree.
|
||||
* -------------------------------------------------------------------------- */
|
||||
|
||||
@@ -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
@@ -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)},
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -14,6 +14,10 @@
|
||||
"STALE",
|
||||
"SENTINEL"
|
||||
],
|
||||
"command_tips": [
|
||||
"REQUEST_POLICY:ALL_NODES",
|
||||
"RESPONSE_POLICY:ALL_SUCCEEDED"
|
||||
],
|
||||
"reply_schema": {
|
||||
"const": "OK"
|
||||
}
|
||||
|
||||
@@ -24,6 +24,10 @@
|
||||
"STALE",
|
||||
"SENTINEL"
|
||||
],
|
||||
"command_tips": [
|
||||
"REQUEST_POLICY:ALL_NODES",
|
||||
"RESPONSE_POLICY:ALL_SUCCEEDED"
|
||||
],
|
||||
"reply_schema": {
|
||||
"const": "OK"
|
||||
},
|
||||
|
||||
@@ -13,6 +13,10 @@
|
||||
"STALE",
|
||||
"SENTINEL"
|
||||
],
|
||||
"command_tips": [
|
||||
"REQUEST_POLICY:ALL_NODES",
|
||||
"RESPONSE_POLICY:ALL_SUCCEEDED"
|
||||
],
|
||||
"acl_categories": [
|
||||
"CONNECTION"
|
||||
],
|
||||
|
||||
@@ -13,6 +13,10 @@
|
||||
"STALE",
|
||||
"SENTINEL"
|
||||
],
|
||||
"command_tips": [
|
||||
"REQUEST_POLICY:ALL_NODES",
|
||||
"RESPONSE_POLICY:ALL_SUCCEEDED"
|
||||
],
|
||||
"acl_categories": [
|
||||
"CONNECTION"
|
||||
],
|
||||
|
||||
@@ -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": {
|
||||
|
||||
@@ -13,6 +13,10 @@
|
||||
"LOADING",
|
||||
"STALE"
|
||||
],
|
||||
"command_tips": [
|
||||
"REQUEST_POLICY:ALL_NODES",
|
||||
"RESPONSE_POLICY:ALL_SUCCEEDED"
|
||||
],
|
||||
"reply_schema": {
|
||||
"const": "OK"
|
||||
}
|
||||
|
||||
@@ -13,6 +13,10 @@
|
||||
"LOADING",
|
||||
"STALE"
|
||||
],
|
||||
"command_tips": [
|
||||
"REQUEST_POLICY:ALL_NODES",
|
||||
"RESPONSE_POLICY:ALL_SUCCEEDED"
|
||||
],
|
||||
"reply_schema": {
|
||||
"const": "OK"
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
],
|
||||
"command_tips": [
|
||||
"REQUEST_POLICY:ALL_NODES",
|
||||
"RESPONSE_POLICY:ALL_SUCCEEDED"
|
||||
"RESPONSE_POLICY:AGG_SUM"
|
||||
],
|
||||
"reply_schema": {
|
||||
"type": "integer",
|
||||
|
||||
@@ -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": {
|
||||
|
||||
@@ -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": {
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
]
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+18
-7
@@ -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++) {
|
||||
@@ -2460,6 +2459,7 @@ static int updatePort(const char **err) {
|
||||
listener->bindaddr_count = server.bindaddr_count;
|
||||
listener->port = server.port;
|
||||
listener->ct = connectionByType(CONN_TYPE_SOCKET);
|
||||
clusterUpdateMyselfAnnouncedPorts();
|
||||
if (changeListener(listener) == C_ERR) {
|
||||
*err = "Unable to listen on this port. Check server logs.";
|
||||
return 0;
|
||||
@@ -2565,6 +2565,15 @@ static int updateOOMScoreAdj(const char **err) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int updateLuaEnableInsecureApi(const char **err) {
|
||||
UNUSED(err);
|
||||
if (server.lua_insecure_api_current != server.lua_enable_insecure_api) {
|
||||
scriptingReset(server.lazyfree_lazy_user_flush ? 1 : 0);
|
||||
}
|
||||
server.lua_insecure_api_current = server.lua_enable_insecure_api;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int updateRequirePass(const char **err) {
|
||||
UNUSED(err);
|
||||
/* The old "requirepass" directive just translates to setting
|
||||
@@ -2674,6 +2683,7 @@ static int applyTLSPort(const char **err) {
|
||||
listener->bindaddr_count = server.bindaddr_count;
|
||||
listener->port = server.tls_port;
|
||||
listener->ct = connectionByType(CONN_TYPE_TLS);
|
||||
clusterUpdateMyselfAnnouncedPorts();
|
||||
if (changeListener(listener) == C_ERR) {
|
||||
*err = "Unable to listen on this port. Check server logs.";
|
||||
return 0;
|
||||
@@ -3095,6 +3105,7 @@ standardConfig static_configs[] = {
|
||||
createBoolConfig("latency-tracking", NULL, MODIFIABLE_CONFIG, server.latency_tracking_enabled, 1, NULL, NULL),
|
||||
createBoolConfig("aof-disable-auto-gc", NULL, MODIFIABLE_CONFIG | HIDDEN_CONFIG, server.aof_disable_auto_gc, 0, NULL, updateAofAutoGCEnabled),
|
||||
createBoolConfig("replica-ignore-disk-write-errors", NULL, MODIFIABLE_CONFIG, server.repl_ignore_disk_write_error, 0, NULL, NULL),
|
||||
createBoolConfig("lua-enable-insecure-api", "lua-enable-deprecated-api", MODIFIABLE_CONFIG | HIDDEN_CONFIG | PROTECTED_CONFIG, server.lua_enable_insecure_api, 0, NULL, updateLuaEnableInsecureApi),
|
||||
|
||||
/* String Configs */
|
||||
createStringConfig("aclfile", NULL, IMMUTABLE_CONFIG, ALLOW_EMPTY_STRING, server.acl_filename, "", NULL, NULL),
|
||||
|
||||
+7
-3
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -1042,7 +1042,7 @@ void scanGenericCommand(client *c, robj *o, unsigned long cursor) {
|
||||
* The exception to the above is ZSET, where we do allocate temporary
|
||||
* strings even when scanning a dict. */
|
||||
if (o && (!ht || o->type == OBJ_ZSET)) {
|
||||
listSetFreeMethod(keys, (void (*)(void*))sdsfree);
|
||||
listSetFreeMethod(keys, sdsfreeVoid);
|
||||
}
|
||||
|
||||
if (ht) {
|
||||
@@ -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
@@ -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. */
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
+13
-2
@@ -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"
|
||||
@@ -261,6 +268,9 @@ void scriptingInit(int setup) {
|
||||
luaSetTableProtectionRecursively(lua);
|
||||
lua_pop(lua, 1);
|
||||
|
||||
/* Set metatables of basic types (string, number, nil etc.) readonly. */
|
||||
luaSetTableProtectionForBasicTypes(lua);
|
||||
|
||||
lctx.lua = lua;
|
||||
}
|
||||
|
||||
@@ -272,6 +282,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);
|
||||
}
|
||||
|
||||
@@ -673,7 +684,7 @@ void ldbInit(void) {
|
||||
ldb.conn = NULL;
|
||||
ldb.active = 0;
|
||||
ldb.logs = listCreate();
|
||||
listSetFreeMethod(ldb.logs,(void (*)(void*))sdsfree);
|
||||
listSetFreeMethod(ldb.logs,sdsfreeVoid);
|
||||
ldb.children = listCreate();
|
||||
ldb.src = NULL;
|
||||
ldb.lines = 0;
|
||||
@@ -1579,7 +1590,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"))) {
|
||||
|
||||
+3
-1
@@ -151,7 +151,7 @@ void evictionPoolPopulate(int dbid, dict *sampledict, dict *keydict, struct evic
|
||||
for (j = 0; j < count; j++) {
|
||||
unsigned long long idle;
|
||||
sds key;
|
||||
robj *o;
|
||||
robj *o = NULL;
|
||||
dictEntry *de;
|
||||
|
||||
de = samples[j];
|
||||
@@ -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++;
|
||||
|
||||
@@ -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;
|
||||
|
||||
+8
-1
@@ -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);
|
||||
@@ -489,8 +494,10 @@ int luaEngineInitEngine(void) {
|
||||
lua_enablereadonlytable(lua_engine_ctx->lua, -1, 1); /* protect the metatable */
|
||||
lua_setmetatable(lua_engine_ctx->lua, -2);
|
||||
lua_enablereadonlytable(lua_engine_ctx->lua, -1, 1); /* protect the new global table */
|
||||
lua_replace(lua_engine_ctx->lua, LUA_GLOBALSINDEX); /* set new global table as the new globals */
|
||||
lua_replace(lua_engine_ctx->lua, LUA_GLOBALSINDEX); /* set new global table as the new globals */
|
||||
|
||||
/* Set metatables of basic types (string, number, nil etc.) readonly. */
|
||||
luaSetTableProtectionForBasicTypes(lua_engine_ctx->lua);
|
||||
|
||||
engine *lua_engine = zmalloc(sizeof(*lua_engine));
|
||||
*lua_engine = (engine) {
|
||||
|
||||
+5
-1
@@ -167,6 +167,10 @@ static void engineLibraryFree(functionLibInfo* li) {
|
||||
zfree(li);
|
||||
}
|
||||
|
||||
static void engineLibraryFreeVoid(void *li) {
|
||||
engineLibraryFree(li);
|
||||
}
|
||||
|
||||
static void engineLibraryDispose(dict *d, void *obj) {
|
||||
UNUSED(d);
|
||||
engineLibraryFree(obj);
|
||||
@@ -349,7 +353,7 @@ static int libraryJoin(functionsLibCtx *functions_lib_ctx_dst, functionsLibCtx *
|
||||
} else {
|
||||
if (!old_libraries_list) {
|
||||
old_libraries_list = listCreate();
|
||||
listSetFreeMethod(old_libraries_list, (void (*)(void*))engineLibraryFree);
|
||||
listSetFreeMethod(old_libraries_list, engineLibraryFreeVoid);
|
||||
}
|
||||
libraryUnlink(functions_lib_ctx_dst, old_li);
|
||||
listAddNodeTail(old_libraries_list, old_li);
|
||||
|
||||
+1
-1
@@ -45,7 +45,7 @@
|
||||
|
||||
#include "server.h"
|
||||
#include "script.h"
|
||||
#include "redismodule.h"
|
||||
#include "valkeymodule.h"
|
||||
|
||||
typedef struct functionLibInfo functionLibInfo;
|
||||
|
||||
|
||||
+42
-5
@@ -587,6 +587,7 @@ int hllSparseToDense(robj *o) {
|
||||
struct hllhdr *hdr, *oldhdr = (struct hllhdr*)sparse;
|
||||
int idx = 0, runlen, regval;
|
||||
uint8_t *p = (uint8_t*)sparse, *end = p+sdslen(sparse);
|
||||
int valid = 1;
|
||||
|
||||
/* If the representation is already the right one return ASAP. */
|
||||
hdr = (struct hllhdr*) sparse;
|
||||
@@ -606,16 +607,27 @@ int hllSparseToDense(robj *o) {
|
||||
while(p < end) {
|
||||
if (HLL_SPARSE_IS_ZERO(p)) {
|
||||
runlen = HLL_SPARSE_ZERO_LEN(p);
|
||||
if ((runlen + idx) > HLL_REGISTERS) { /* Overflow. */
|
||||
valid = 0;
|
||||
break;
|
||||
}
|
||||
idx += runlen;
|
||||
p++;
|
||||
} else if (HLL_SPARSE_IS_XZERO(p)) {
|
||||
runlen = HLL_SPARSE_XZERO_LEN(p);
|
||||
if ((runlen + idx) > HLL_REGISTERS) { /* Overflow. */
|
||||
valid = 0;
|
||||
break;
|
||||
}
|
||||
idx += runlen;
|
||||
p += 2;
|
||||
} else {
|
||||
runlen = HLL_SPARSE_VAL_LEN(p);
|
||||
regval = HLL_SPARSE_VAL_VALUE(p);
|
||||
if ((runlen + idx) > HLL_REGISTERS) break; /* Overflow. */
|
||||
if ((runlen + idx) > HLL_REGISTERS) { /* Overflow. */
|
||||
valid = 0;
|
||||
break;
|
||||
}
|
||||
while(runlen--) {
|
||||
HLL_DENSE_SET_REGISTER(hdr->registers,idx,regval);
|
||||
idx++;
|
||||
@@ -626,7 +638,7 @@ int hllSparseToDense(robj *o) {
|
||||
|
||||
/* If the sparse representation was valid, we expect to find idx
|
||||
* set to HLL_REGISTERS. */
|
||||
if (idx != HLL_REGISTERS) {
|
||||
if (!valid || idx != HLL_REGISTERS) {
|
||||
sdsfree(dense);
|
||||
return C_ERR;
|
||||
}
|
||||
@@ -923,27 +935,40 @@ int hllSparseAdd(robj *o, unsigned char *ele, size_t elesize) {
|
||||
void hllSparseRegHisto(uint8_t *sparse, int sparselen, int *invalid, int* reghisto) {
|
||||
int idx = 0, runlen, regval;
|
||||
uint8_t *end = sparse+sparselen, *p = sparse;
|
||||
int valid = 1;
|
||||
|
||||
while(p < end) {
|
||||
if (HLL_SPARSE_IS_ZERO(p)) {
|
||||
runlen = HLL_SPARSE_ZERO_LEN(p);
|
||||
if ((runlen + idx) > HLL_REGISTERS) { /* Overflow. */
|
||||
valid = 0;
|
||||
break;
|
||||
}
|
||||
idx += runlen;
|
||||
reghisto[0] += runlen;
|
||||
p++;
|
||||
} else if (HLL_SPARSE_IS_XZERO(p)) {
|
||||
runlen = HLL_SPARSE_XZERO_LEN(p);
|
||||
if ((runlen + idx) > HLL_REGISTERS) { /* Overflow. */
|
||||
valid = 0;
|
||||
break;
|
||||
}
|
||||
idx += runlen;
|
||||
reghisto[0] += runlen;
|
||||
p += 2;
|
||||
} else {
|
||||
runlen = HLL_SPARSE_VAL_LEN(p);
|
||||
regval = HLL_SPARSE_VAL_VALUE(p);
|
||||
if ((runlen + idx) > HLL_REGISTERS) { /* Overflow. */
|
||||
valid = 0;
|
||||
break;
|
||||
}
|
||||
idx += runlen;
|
||||
reghisto[regval] += runlen;
|
||||
p++;
|
||||
}
|
||||
}
|
||||
if (idx != HLL_REGISTERS && invalid) *invalid = 1;
|
||||
if ((!valid || idx != HLL_REGISTERS) && invalid) *invalid = 1;
|
||||
}
|
||||
|
||||
/* ========================= HyperLogLog Count ==============================
|
||||
@@ -1091,22 +1116,34 @@ int hllMerge(uint8_t *max, robj *hll) {
|
||||
} else {
|
||||
uint8_t *p = hll->ptr, *end = p + sdslen(hll->ptr);
|
||||
long runlen, regval;
|
||||
int valid = 1;
|
||||
|
||||
p += HLL_HDR_SIZE;
|
||||
i = 0;
|
||||
while(p < end) {
|
||||
if (HLL_SPARSE_IS_ZERO(p)) {
|
||||
runlen = HLL_SPARSE_ZERO_LEN(p);
|
||||
if ((runlen + i) > HLL_REGISTERS) { /* Overflow. */
|
||||
valid = 0;
|
||||
break;
|
||||
}
|
||||
i += runlen;
|
||||
p++;
|
||||
} else if (HLL_SPARSE_IS_XZERO(p)) {
|
||||
runlen = HLL_SPARSE_XZERO_LEN(p);
|
||||
if ((runlen + i) > HLL_REGISTERS) { /* Overflow. */
|
||||
valid = 0;
|
||||
break;
|
||||
}
|
||||
i += runlen;
|
||||
p += 2;
|
||||
} else {
|
||||
runlen = HLL_SPARSE_VAL_LEN(p);
|
||||
regval = HLL_SPARSE_VAL_VALUE(p);
|
||||
if ((runlen + i) > HLL_REGISTERS) break; /* Overflow. */
|
||||
if ((runlen + i) > HLL_REGISTERS) { /* Overflow. */
|
||||
valid = 0;
|
||||
break;
|
||||
}
|
||||
while(runlen--) {
|
||||
if (regval > max[i]) max[i] = regval;
|
||||
i++;
|
||||
@@ -1114,7 +1151,7 @@ int hllMerge(uint8_t *max, robj *hll) {
|
||||
p++;
|
||||
}
|
||||
}
|
||||
if (i != HLL_REGISTERS) return C_ERR;
|
||||
if (!valid || i != HLL_REGISTERS) return C_ERR;
|
||||
}
|
||||
return C_OK;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
+6
-1
@@ -253,6 +253,11 @@ void lpFree(unsigned char *lp) {
|
||||
lp_free(lp);
|
||||
}
|
||||
|
||||
/* Same as lpFree, but with a void* argument for use as a callback. */
|
||||
void lpFreeVoid(void *lp) {
|
||||
lp_free((unsigned char *)lp);
|
||||
}
|
||||
|
||||
/* Shrink the memory to fit. */
|
||||
unsigned char* lpShrinkToFit(unsigned char *lp) {
|
||||
size_t size = lpGetTotalBytes(lp);
|
||||
@@ -2506,7 +2511,7 @@ int listpackTest(int argc, char *argv[], int flags) {
|
||||
for (i = 0; i < iteration; i++) {
|
||||
lp = lpNew(0);
|
||||
ref = listCreate();
|
||||
listSetFreeMethod(ref,(void (*)(void*))sdsfree);
|
||||
listSetFreeMethod(ref,sdsfreeVoid);
|
||||
len = rand() % 256;
|
||||
|
||||
/* Create lists */
|
||||
|
||||
@@ -56,6 +56,7 @@ typedef struct {
|
||||
|
||||
unsigned char *lpNew(size_t capacity);
|
||||
void lpFree(unsigned char *lp);
|
||||
void lpFreeVoid(void *lp);
|
||||
unsigned char* lpShrinkToFit(unsigned char *lp);
|
||||
unsigned char *lpInsertString(unsigned char *lp, unsigned char *s, uint32_t slen,
|
||||
unsigned char *p, int where, unsigned char **newp);
|
||||
|
||||
+2
-2
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
|
||||
+2875
-2829
File diff suppressed because it is too large
Load Diff
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
+63
-24
@@ -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;
|
||||
@@ -500,7 +515,7 @@ void afterErrorReply(client *c, const char *s, size_t len, int flags) {
|
||||
if (c->flags & CLIENT_MODULE) {
|
||||
if (!c->deferred_reply_errors) {
|
||||
c->deferred_reply_errors = listCreate();
|
||||
listSetFreeMethod(c->deferred_reply_errors, (void (*)(void*))sdsfree);
|
||||
listSetFreeMethod(c->deferred_reply_errors, sdsfreeVoid);
|
||||
}
|
||||
listAddNodeTail(c->deferred_reply_errors, sdsnewlen(s, len));
|
||||
return;
|
||||
@@ -515,7 +530,7 @@ void afterErrorReply(client *c, const char *s, size_t len, int flags) {
|
||||
if (s[0] != '-') {
|
||||
incrementErrorCount("ERR", 3);
|
||||
} else {
|
||||
char *spaceloc = memchr(s, ' ', len < 32 ? len : 32);
|
||||
const char *spaceloc = memchr(s, ' ', len < 32 ? len : 32);
|
||||
if (spaceloc) {
|
||||
const size_t errEndPos = (size_t)(spaceloc - s);
|
||||
incrementErrorCount(s+1, errEndPos-1);
|
||||
@@ -636,13 +651,26 @@ void addReplyErrorSdsSafe(client *c, sds err) {
|
||||
addReplyErrorSdsEx(c, err, 0);
|
||||
}
|
||||
|
||||
/* Add error reply to the given client.
|
||||
* Supported flags:
|
||||
* ERR_REPLY_FLAG_NO_STATS_UPDATE - indicate not to perform any error stats updates
|
||||
* As a side effect the SDS string is freed. */
|
||||
void addReplyErrorSdsExSafe(client *c, sds err, int flags) {
|
||||
/* Trim any newlines at the end (ones will be added by addReplyErrorLength) */
|
||||
err = sdstrim(err, "\r\n");
|
||||
/* Make sure there are no newlines in the middle of the string, otherwise
|
||||
* invalid protocol is emitted. */
|
||||
err = sdsmapchars(err, "\r\n", " ", 2);
|
||||
addReplyErrorSdsEx(c, err, flags);
|
||||
}
|
||||
|
||||
/* Internal function used by addReplyErrorFormat, addReplyErrorFormatEx and RM_ReplyWithErrorFormat.
|
||||
* Refer to afterErrorReply for more information about the flags. */
|
||||
void addReplyErrorFormatInternal(client *c, int flags, const char *fmt, va_list ap) {
|
||||
va_list cpy;
|
||||
va_copy(cpy,ap);
|
||||
sds s = sdscatvprintf(sdsempty(),fmt,cpy);
|
||||
va_end(cpy);
|
||||
va_list copy;
|
||||
va_copy(copy,ap);
|
||||
sds s = sdscatvprintf(sdsempty(),fmt,copy);
|
||||
va_end(copy);
|
||||
/* Trim any newlines at the end (ones will be added by addReplyErrorLength) */
|
||||
s = sdstrim(s, "\r\n");
|
||||
/* Make sure there are no newlines in the middle of the string, otherwise
|
||||
@@ -776,7 +804,7 @@ void setDeferredReply(client *c, void *node, const char *s, size_t length) {
|
||||
* - It has enough room already allocated
|
||||
* - And not too large (avoid large memmove) */
|
||||
if (ln->prev != NULL && (prev = listNodeValue(ln->prev)) &&
|
||||
prev->size - prev->used > 0)
|
||||
prev->used < prev->size)
|
||||
{
|
||||
size_t len_to_copy = prev->size - prev->used;
|
||||
if (len_to_copy > length)
|
||||
@@ -1291,8 +1319,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);
|
||||
}
|
||||
|
||||
@@ -1476,9 +1504,13 @@ void unlinkClient(client *c) {
|
||||
c->flags &= ~CLIENT_PENDING_WRITE;
|
||||
}
|
||||
|
||||
/* Remove from the list of pending reads if needed. */
|
||||
serverAssert(io_threads_op == IO_THREADS_OP_IDLE);
|
||||
/* Remove from the list of pending reads if needed.
|
||||
* Detached module thread-safe contexts may free their fake clients from a
|
||||
* background thread while IO threads are active. Those clients are never
|
||||
* added to the pending read list, so only require idle IO threads when
|
||||
* this client was actually queued for threaded reads. */
|
||||
if (c->pending_read_list_node != NULL) {
|
||||
serverAssert(io_threads_op == IO_THREADS_OP_IDLE);
|
||||
listDelNode(server.clients_pending_read,c->pending_read_list_node);
|
||||
c->pending_read_list_node = NULL;
|
||||
}
|
||||
@@ -1555,8 +1587,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 +1701,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 +2230,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]);
|
||||
}
|
||||
@@ -3239,11 +3273,12 @@ NULL
|
||||
if (getLongLongFromObjectOrReply(c,c->argv[2],&id,NULL)
|
||||
!= C_OK) return;
|
||||
struct client *target = lookupClientByID(id);
|
||||
/* Note that we never try to unblock a client blocked on a module command, which
|
||||
/* Note that we never try to unblock a client blocked on a module command,
|
||||
* or a client blocked by CLIENT PAUSE or some other blocking type which
|
||||
* doesn't have a timeout callback (even in the case of UNBLOCK ERROR).
|
||||
* The reason is that we assume that if a command doesn't expect to be timedout,
|
||||
* it also doesn't expect to be unblocked by CLIENT UNBLOCK */
|
||||
if (target && target->flags & CLIENT_BLOCKED && moduleBlockedClientMayTimeout(target)) {
|
||||
if (target && target->flags & CLIENT_BLOCKED && blockedClientMayTimeout(target)) {
|
||||
if (unblock_error)
|
||||
unblockClientOnError(target,
|
||||
"-UNBLOCKED client unblocked via CLIENT UNBLOCK");
|
||||
@@ -3603,7 +3638,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);
|
||||
@@ -3799,7 +3834,7 @@ size_t getClientMemoryUsage(client *c, size_t *output_buffer_mem_usage) {
|
||||
|
||||
/* Add memory overhead of the tracking prefixes, this is an underestimation so we don't need to traverse the entire rax */
|
||||
if (c->client_tracking_prefixes)
|
||||
mem += c->client_tracking_prefixes->numnodes * (sizeof(raxNode) * sizeof(raxNode*));
|
||||
mem += c->client_tracking_prefixes->numnodes * (sizeof(raxNode) + sizeof(raxNode *));
|
||||
|
||||
return mem;
|
||||
}
|
||||
@@ -3852,6 +3887,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
@@ -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
@@ -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. */
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -1247,6 +1247,10 @@ ssize_t rdbSaveSingleModuleAux(rio *rdb, int when, moduleType *mt) {
|
||||
* to allow loading this RDB if the module is not present. */
|
||||
sdsfree(io.pre_flush_buffer);
|
||||
io.pre_flush_buffer = NULL;
|
||||
if (io.ctx) {
|
||||
moduleFreeContext(io.ctx);
|
||||
zfree(io.ctx);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
@@ -1384,7 +1388,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 +1400,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;
|
||||
@@ -2284,11 +2288,12 @@ robj *rdbLoadObject(int rdbtype, rio *rdb, sds key, int dbid, int *error) {
|
||||
|
||||
/* search for duplicate records */
|
||||
sds field = sdstrynewlen(fstr, flen);
|
||||
if (!field || dictAdd(dupSearchDict, field, NULL) != DICT_OK ||
|
||||
!lpSafeToAdd(lp, (size_t)flen + vlen)) {
|
||||
if (!field || !lpSafeToAdd(lp, (size_t)flen + vlen) ||
|
||||
dictAdd(dupSearchDict, field, NULL) != DICT_OK) {
|
||||
rdbReportCorruptRDB("Hash zipmap with dup elements, or big length (%u)", flen);
|
||||
dictRelease(dupSearchDict);
|
||||
sdsfree(field);
|
||||
lpFree(lp);
|
||||
zfree(encoded);
|
||||
o->ptr = NULL;
|
||||
decrRefCount(o);
|
||||
@@ -2757,7 +2762,6 @@ robj *rdbLoadObject(int rdbtype, rio *rdb, sds key, int dbid, int *error) {
|
||||
" loading a stream consumer "
|
||||
"group");
|
||||
decrRefCount(o);
|
||||
streamFreeNACK(nack);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
@@ -2803,7 +2807,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 +2874,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 +2917,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 +2928,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 +3142,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 +3202,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 +3211,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;
|
||||
|
||||
@@ -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
File diff suppressed because it is too large
Load Diff
+33
-27
@@ -200,7 +200,7 @@ void rebaseReplicationBuffer(long long base_repl_offset) {
|
||||
void resetReplicationBuffer(void) {
|
||||
server.repl_buffer_mem = 0;
|
||||
server.repl_buffer_blocks = listCreate();
|
||||
listSetFreeMethod(server.repl_buffer_blocks, (void (*)(void*))zfree);
|
||||
listSetFreeMethod(server.repl_buffer_blocks, zfree);
|
||||
}
|
||||
|
||||
int canFeedReplicaReplBuffer(client *replica) {
|
||||
@@ -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. */
|
||||
@@ -1863,6 +1863,11 @@ void replicationAttachToNewMaster(void) {
|
||||
/* Asynchronously read the SYNC payload we receive from a master */
|
||||
#define REPL_MAX_WRITTEN_BEFORE_FSYNC (1024*1024*8) /* 8 MB */
|
||||
void readSyncBulkPayload(connection *conn) {
|
||||
/* During full sync, the functions engine is freed right before loading
|
||||
* the RDB. To avoid this happening while a function is still running,
|
||||
* delay full sync processing until it finishes. */
|
||||
if (isInsideYieldingLongCommand()) return;
|
||||
|
||||
char buf[PROTO_IOBUF_LEN];
|
||||
ssize_t nread, readlen, nwritten;
|
||||
int use_diskless_load = useDisklessLoad();
|
||||
@@ -2064,8 +2069,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 +2143,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 +2174,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 +2255,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 +2266,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 +3041,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 +3063,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 +3105,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 +3119,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 +3402,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. */
|
||||
|
||||
+13
-13
@@ -60,7 +60,7 @@
|
||||
|
||||
static int parseBulk(ReplyParser *parser, void *p_ctx) {
|
||||
const char *proto = parser->curr_location;
|
||||
char *p = strchr(proto+1,'\r');
|
||||
const char *p = strchr(proto + 1, '\r');
|
||||
long long bulklen;
|
||||
parser->curr_location = p + 2; /* for \r\n */
|
||||
|
||||
@@ -79,7 +79,7 @@ static int parseBulk(ReplyParser *parser, void *p_ctx) {
|
||||
|
||||
static int parseSimpleString(ReplyParser *parser, void *p_ctx) {
|
||||
const char *proto = parser->curr_location;
|
||||
char *p = strchr(proto+1,'\r');
|
||||
const char *p = strchr(proto + 1, '\r');
|
||||
parser->curr_location = p + 2; /* for \r\n */
|
||||
parser->callbacks.simple_str_callback(p_ctx, proto+1, p-proto-1, proto, parser->curr_location - proto);
|
||||
return C_OK;
|
||||
@@ -87,7 +87,7 @@ static int parseSimpleString(ReplyParser *parser, void *p_ctx) {
|
||||
|
||||
static int parseError(ReplyParser *parser, void *p_ctx) {
|
||||
const char *proto = parser->curr_location;
|
||||
char *p = strchr(proto+1,'\r');
|
||||
const char *p = strchr(proto + 1, '\r');
|
||||
parser->curr_location = p + 2; // for \r\n
|
||||
parser->callbacks.error_callback(p_ctx, proto+1, p-proto-1, proto, parser->curr_location - proto);
|
||||
return C_OK;
|
||||
@@ -95,7 +95,7 @@ static int parseError(ReplyParser *parser, void *p_ctx) {
|
||||
|
||||
static int parseLong(ReplyParser *parser, void *p_ctx) {
|
||||
const char *proto = parser->curr_location;
|
||||
char *p = strchr(proto+1,'\r');
|
||||
const char *p = strchr(proto + 1, '\r');
|
||||
parser->curr_location = p + 2; /* for \r\n */
|
||||
long long val;
|
||||
string2ll(proto+1,p-proto-1,&val);
|
||||
@@ -105,7 +105,7 @@ static int parseLong(ReplyParser *parser, void *p_ctx) {
|
||||
|
||||
static int parseAttributes(ReplyParser *parser, void *p_ctx) {
|
||||
const char *proto = parser->curr_location;
|
||||
char *p = strchr(proto+1,'\r');
|
||||
const char *p = strchr(proto + 1, '\r');
|
||||
long long len;
|
||||
string2ll(proto+1,p-proto-1,&len);
|
||||
p += 2;
|
||||
@@ -116,7 +116,7 @@ static int parseAttributes(ReplyParser *parser, void *p_ctx) {
|
||||
|
||||
static int parseVerbatimString(ReplyParser *parser, void *p_ctx) {
|
||||
const char *proto = parser->curr_location;
|
||||
char *p = strchr(proto+1,'\r');
|
||||
const char *p = strchr(proto + 1, '\r');
|
||||
long long bulklen;
|
||||
parser->curr_location = p + 2; /* for \r\n */
|
||||
string2ll(proto+1,p-proto-1,&bulklen);
|
||||
@@ -129,7 +129,7 @@ static int parseVerbatimString(ReplyParser *parser, void *p_ctx) {
|
||||
|
||||
static int parseBigNumber(ReplyParser *parser, void *p_ctx) {
|
||||
const char *proto = parser->curr_location;
|
||||
char *p = strchr(proto+1,'\r');
|
||||
const char *p = strchr(proto + 1, '\r');
|
||||
parser->curr_location = p + 2; /* for \r\n */
|
||||
parser->callbacks.big_number_callback(p_ctx, proto+1, p-proto-1, proto, parser->curr_location - proto);
|
||||
return C_OK;
|
||||
@@ -137,7 +137,7 @@ static int parseBigNumber(ReplyParser *parser, void *p_ctx) {
|
||||
|
||||
static int parseNull(ReplyParser *parser, void *p_ctx) {
|
||||
const char *proto = parser->curr_location;
|
||||
char *p = strchr(proto+1,'\r');
|
||||
const char *p = strchr(proto + 1, '\r');
|
||||
parser->curr_location = p + 2; /* for \r\n */
|
||||
parser->callbacks.null_callback(p_ctx, proto, parser->curr_location - proto);
|
||||
return C_OK;
|
||||
@@ -145,7 +145,7 @@ static int parseNull(ReplyParser *parser, void *p_ctx) {
|
||||
|
||||
static int parseDouble(ReplyParser *parser, void *p_ctx) {
|
||||
const char *proto = parser->curr_location;
|
||||
char *p = strchr(proto+1,'\r');
|
||||
const char *p = strchr(proto + 1, '\r');
|
||||
parser->curr_location = p + 2; /* for \r\n */
|
||||
char buf[MAX_LONG_DOUBLE_CHARS+1];
|
||||
size_t len = p-proto-1;
|
||||
@@ -163,7 +163,7 @@ static int parseDouble(ReplyParser *parser, void *p_ctx) {
|
||||
|
||||
static int parseBool(ReplyParser *parser, void *p_ctx) {
|
||||
const char *proto = parser->curr_location;
|
||||
char *p = strchr(proto+1,'\r');
|
||||
const char *p = strchr(proto + 1, '\r');
|
||||
parser->curr_location = p + 2; /* for \r\n */
|
||||
parser->callbacks.bool_callback(p_ctx, proto[1] == 't', proto, parser->curr_location - proto);
|
||||
return C_OK;
|
||||
@@ -171,7 +171,7 @@ static int parseBool(ReplyParser *parser, void *p_ctx) {
|
||||
|
||||
static int parseArray(ReplyParser *parser, void *p_ctx) {
|
||||
const char *proto = parser->curr_location;
|
||||
char *p = strchr(proto+1,'\r');
|
||||
const char *p = strchr(proto + 1, '\r');
|
||||
long long len;
|
||||
string2ll(proto+1,p-proto-1,&len);
|
||||
p += 2;
|
||||
@@ -186,7 +186,7 @@ static int parseArray(ReplyParser *parser, void *p_ctx) {
|
||||
|
||||
static int parseSet(ReplyParser *parser, void *p_ctx) {
|
||||
const char *proto = parser->curr_location;
|
||||
char *p = strchr(proto+1,'\r');
|
||||
const char *p = strchr(proto + 1, '\r');
|
||||
long long len;
|
||||
string2ll(proto+1,p-proto-1,&len);
|
||||
p += 2;
|
||||
@@ -197,7 +197,7 @@ static int parseSet(ReplyParser *parser, void *p_ctx) {
|
||||
|
||||
static int parseMap(ReplyParser *parser, void *p_ctx) {
|
||||
const char *proto = parser->curr_location;
|
||||
char *p = strchr(proto+1,'\r');
|
||||
const char *p = strchr(proto + 1, '\r');
|
||||
long long len;
|
||||
string2ll(proto+1,p-proto-1,&len);
|
||||
p += 2;
|
||||
|
||||
+1
-1
@@ -80,7 +80,7 @@ client* scriptGetCaller(void) {
|
||||
int scriptInterrupt(scriptRunCtx *run_ctx) {
|
||||
if (run_ctx->flags & SCRIPT_TIMEDOUT) {
|
||||
/* script already timedout
|
||||
we just need to precess some events and return */
|
||||
we just need to process some events and return */
|
||||
processEventsWhileBlocked();
|
||||
return (run_ctx->flags & SCRIPT_KILLED) ? SCRIPT_KILL : SCRIPT_CONTINUE;
|
||||
}
|
||||
|
||||
+103
-17
@@ -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,
|
||||
@@ -66,7 +67,6 @@ static char *redis_api_allow_list[] = {
|
||||
static char *lua_builtins_allow_list[] = {
|
||||
"xpcall",
|
||||
"tostring",
|
||||
"getfenv",
|
||||
"setmetatable",
|
||||
"next",
|
||||
"assert",
|
||||
@@ -87,15 +87,16 @@ static char *lua_builtins_allow_list[] = {
|
||||
"loadstring",
|
||||
"ipairs",
|
||||
"_VERSION",
|
||||
"setfenv",
|
||||
"load",
|
||||
"error",
|
||||
NULL,
|
||||
};
|
||||
|
||||
/* Lua builtins which are not documented on the Lua documentation */
|
||||
static char *lua_builtins_not_documented_allow_list[] = {
|
||||
/* Lua builtins which are deprecated for sandboxing concerns */
|
||||
static char *lua_builtins_deprecated[] = {
|
||||
"newproxy",
|
||||
"setfenv",
|
||||
"getfenv",
|
||||
NULL,
|
||||
};
|
||||
|
||||
@@ -117,7 +118,6 @@ static char **allow_lists[] = {
|
||||
libraries_allow_list,
|
||||
redis_api_allow_list,
|
||||
lua_builtins_allow_list,
|
||||
lua_builtins_not_documented_allow_list,
|
||||
lua_builtins_removed_after_initialization_allow_list,
|
||||
NULL,
|
||||
};
|
||||
@@ -818,8 +818,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);
|
||||
@@ -1311,7 +1320,21 @@ static int luaNewIndexAllowList(lua_State *lua) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!*allow_l) {
|
||||
int allowed = (*allow_l != NULL);
|
||||
/* If not explicitly allowed, check if it's a deprecated function. If so,
|
||||
* allow it only if 'lua_enable_insecure_api' config is enabled. */
|
||||
int deprecated = 0;
|
||||
if (!allowed) {
|
||||
char **c = lua_builtins_deprecated;
|
||||
for (; *c; ++c) {
|
||||
if (strcmp(*c, variable_name) == 0) {
|
||||
deprecated = 1;
|
||||
allowed = server.lua_enable_insecure_api ? 1 : 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!allowed) {
|
||||
/* Search the value on the back list, if its there we know that it was removed
|
||||
* on purpose and there is no need to print a warning. */
|
||||
char **c = deny_list;
|
||||
@@ -1320,8 +1343,11 @@ static int luaNewIndexAllowList(lua_State *lua) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!*c) {
|
||||
serverLog(LL_WARNING, "A key '%s' was added to Lua globals which is not on the globals allow list nor listed on the deny list.", variable_name);
|
||||
if (!*c && !deprecated) {
|
||||
serverLog(LL_WARNING,
|
||||
"A key '%s' was added to Lua globals which is not on the globals allow list nor listed on the "
|
||||
"deny list.",
|
||||
variable_name);
|
||||
}
|
||||
} else {
|
||||
lua_rawset(lua, -3);
|
||||
@@ -1372,7 +1398,38 @@ void luaSetTableProtectionRecursively(lua_State *lua) {
|
||||
}
|
||||
}
|
||||
|
||||
void luaRegisterVersion(lua_State* lua) {
|
||||
/* Set the readonly flag on the metatable of basic types (string, nil etc.) */
|
||||
void luaSetTableProtectionForBasicTypes(lua_State *lua) {
|
||||
static const int types[] = {
|
||||
LUA_TSTRING,
|
||||
LUA_TNUMBER,
|
||||
LUA_TBOOLEAN,
|
||||
LUA_TNIL,
|
||||
LUA_TFUNCTION,
|
||||
LUA_TTHREAD,
|
||||
LUA_TLIGHTUSERDATA};
|
||||
|
||||
for (size_t i = 0; i < sizeof(types) / sizeof(types[0]); i++) {
|
||||
/* Push a dummy value of the type to get its metatable */
|
||||
switch (types[i]) {
|
||||
case LUA_TSTRING: lua_pushstring(lua, ""); break;
|
||||
case LUA_TNUMBER: lua_pushnumber(lua, 0); break;
|
||||
case LUA_TBOOLEAN: lua_pushboolean(lua, 0); break;
|
||||
case LUA_TNIL: lua_pushnil(lua); break;
|
||||
case LUA_TFUNCTION: lua_pushcfunction(lua, NULL); break;
|
||||
case LUA_TTHREAD: lua_newthread(lua); break;
|
||||
case LUA_TLIGHTUSERDATA: lua_pushlightuserdata(lua, (void*)lua); break;
|
||||
}
|
||||
if (lua_getmetatable(lua, -1)) {
|
||||
luaSetTableProtectionRecursively(lua);
|
||||
lua_pop(lua, 1); /* pop metatable */
|
||||
}
|
||||
lua_pop(lua, 1); /* pop dummy value */
|
||||
}
|
||||
}
|
||||
|
||||
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 +1437,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 +1550,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 +1633,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 +1648,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);
|
||||
}
|
||||
}
|
||||
@@ -1610,6 +1691,11 @@ void luaExtractErrorInformation(lua_State *lua, errorInfo *err_info) {
|
||||
err_info->ignore_err_stats_update = lua_toboolean(lua, -1);
|
||||
}
|
||||
lua_pop(lua, 1);
|
||||
|
||||
if (err_info->msg == NULL) {
|
||||
/* Ensure we never return a NULL msg. */
|
||||
err_info->msg = sdsnew("ERR unknown error");
|
||||
}
|
||||
}
|
||||
|
||||
void luaCallFunction(scriptRunCtx* run_ctx, lua_State *lua, robj** keys, size_t nkeys, robj** args, size_t nargs, int debug_enabled) {
|
||||
@@ -1700,7 +1786,7 @@ void luaCallFunction(scriptRunCtx* run_ctx, lua_State *lua, robj** keys, size_t
|
||||
err_info.source,
|
||||
err_info.line);
|
||||
}
|
||||
addReplyErrorSdsEx(c, final_msg, err_info.ignore_err_stats_update? ERR_REPLY_FLAG_NO_STATS_UPDATE : 0);
|
||||
addReplyErrorSdsExSafe(c, final_msg, err_info.ignore_err_stats_update? ERR_REPLY_FLAG_NO_STATS_UPDATE : 0);
|
||||
luaErrorInformationDiscard(&err_info);
|
||||
}
|
||||
lua_pop(lua,1); /* Consume the Lua error */
|
||||
|
||||
+4
-2
@@ -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;
|
||||
@@ -71,8 +72,9 @@ void luaRegisterGlobalProtectionFunction(lua_State *lua);
|
||||
void luaSetErrorMetatable(lua_State *lua);
|
||||
void luaSetAllowListProtection(lua_State *lua);
|
||||
void luaSetTableProtectionRecursively(lua_State *lua);
|
||||
void luaRegisterLogFunction(lua_State* lua);
|
||||
void luaRegisterVersion(lua_State* lua);
|
||||
void luaSetTableProtectionForBasicTypes(lua_State *lua);
|
||||
void luaRegisterLogFunction(lua_State *lua);
|
||||
void luaRegisterVersion(lua_State *lua);
|
||||
void luaPushErrorBuff(lua_State *lua, sds err_buff);
|
||||
void luaPushError(lua_State *lua, const char *error);
|
||||
int luaError(lua_State *lua);
|
||||
|
||||
@@ -197,6 +197,10 @@ void sdsfree(sds s) {
|
||||
s_free((char*)s-sdsHdrSize(s[-1]));
|
||||
}
|
||||
|
||||
void sdsfreeVoid(void *s) {
|
||||
sdsfree(s);
|
||||
}
|
||||
|
||||
/* Set the sds string length to the length as obtained with strlen(), so
|
||||
* considering as content only up to the first null term character.
|
||||
*
|
||||
@@ -349,20 +353,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);
|
||||
@@ -540,7 +546,7 @@ sds sdsfromlonglong(long long value) {
|
||||
|
||||
/* Like sdscatprintf() but gets va_list instead of being variadic. */
|
||||
sds sdscatvprintf(sds s, const char *fmt, va_list ap) {
|
||||
va_list cpy;
|
||||
va_list copy;
|
||||
char staticbuf[1024], *buf = staticbuf, *t;
|
||||
size_t buflen = strlen(fmt)*2;
|
||||
int bufstrlen;
|
||||
@@ -557,9 +563,9 @@ sds sdscatvprintf(sds s, const char *fmt, va_list ap) {
|
||||
/* Alloc enough space for buffer and \0 after failing to
|
||||
* fit the string in the current buffer size. */
|
||||
while(1) {
|
||||
va_copy(cpy,ap);
|
||||
bufstrlen = vsnprintf(buf, buflen, fmt, cpy);
|
||||
va_end(cpy);
|
||||
va_copy(copy,ap);
|
||||
bufstrlen = vsnprintf(buf, buflen, fmt, copy);
|
||||
va_end(copy);
|
||||
if (bufstrlen < 0) {
|
||||
if (buf != staticbuf) s_free(buf);
|
||||
return NULL;
|
||||
|
||||
@@ -221,6 +221,7 @@ sds sdsnew(const char *init);
|
||||
sds sdsempty(void);
|
||||
sds sdsdup(const sds s);
|
||||
void sdsfree(sds s);
|
||||
void sdsfreeVoid(void *s);
|
||||
sds sdsgrowzero(sds s, size_t len);
|
||||
sds sdscatlen(sds s, const void *t, size_t len);
|
||||
sds sdscat(sds s, const char *t);
|
||||
|
||||
+1
-2
@@ -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);
|
||||
|
||||
+63
-48
@@ -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. */
|
||||
@@ -2641,7 +2642,7 @@ void initServer(void) {
|
||||
server.db[j].avg_ttl = 0;
|
||||
server.db[j].defrag_later = listCreate();
|
||||
server.db[j].slots_to_keys = NULL; /* Set by clusterInit later on if necessary. */
|
||||
listSetFreeMethod(server.db[j].defrag_later,(void (*)(void*))sdsfree);
|
||||
listSetFreeMethod(server.db[j].defrag_later,sdsfreeVoid);
|
||||
}
|
||||
evictionPoolAlloc(); /* Initialize the LRU keys pool. */
|
||||
server.pubsub_channels = dictCreate(&keylistDictType);
|
||||
@@ -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
|
||||
@@ -3485,7 +3486,7 @@ void call(client *c, int flags) {
|
||||
* and a client which is reprocessing command again (after being unblocked).
|
||||
* Blocked clients can be blocked in different places and not always it means the call() function has been
|
||||
* called. For example this is required for avoiding double logging to monitors.*/
|
||||
int reprocessing_command = flags & CMD_CALL_REPROCESSING;
|
||||
int reprocessing_command = (c->flags & CLIENT_REPROCESSING_COMMAND) ? 1 : 0;
|
||||
|
||||
/* Initialization: clear the flags that must be set by the command on
|
||||
* demand, and initialize the array for additional commands propagation. */
|
||||
@@ -3575,7 +3576,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 +3953,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;
|
||||
}
|
||||
@@ -4156,7 +4158,6 @@ int processCommand(client *c) {
|
||||
addReply(c,shared.queued);
|
||||
} else {
|
||||
int flags = CMD_CALL_FULL;
|
||||
if (client_reprocessing_command) flags |= CMD_CALL_REPROCESSING;
|
||||
call(c,flags);
|
||||
if (listLength(server.ready_keys) && !isInsideYieldingLongCommand())
|
||||
handleClientsBlockedOnKeys();
|
||||
@@ -4424,7 +4425,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 +4449,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 +5490,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 +5516,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 +6381,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 +6392,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 +6423,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 +6436,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 +6653,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 +6753,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 +6844,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 +7137,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 +7296,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");
|
||||
}
|
||||
|
||||
+66
-53
@@ -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. */
|
||||
@@ -591,8 +593,7 @@ typedef enum {
|
||||
#define CMD_CALL_NONE 0
|
||||
#define CMD_CALL_PROPAGATE_AOF (1<<0)
|
||||
#define CMD_CALL_PROPAGATE_REPL (1<<1)
|
||||
#define CMD_CALL_REPROCESSING (1<<2)
|
||||
#define CMD_CALL_FROM_MODULE (1<<3) /* From RM_Call */
|
||||
#define CMD_CALL_FROM_MODULE (1<<2) /* From RM_Call */
|
||||
#define CMD_CALL_PROPAGATE (CMD_CALL_PROPAGATE_AOF|CMD_CALL_PROPAGATE_REPL)
|
||||
#define CMD_CALL_FULL (CMD_CALL_PROPAGATE)
|
||||
|
||||
@@ -700,7 +701,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 +714,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 +802,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 +816,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 +858,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 +1033,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 +1191,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 +1225,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 +1629,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 +1719,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,17 +1992,21 @@ 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 */
|
||||
int script_disable_deny_script; /* Allow running commands marked "no-script" inside a script. */
|
||||
int lua_enable_insecure_api; /* Config to enable insecure api */
|
||||
int lua_insecure_api_current; /* Current value of if insecure apis are enabled, used to determine if flush is needed. */
|
||||
/* Lazy free */
|
||||
int lazyfree_lazy_eviction;
|
||||
int lazyfree_lazy_expire;
|
||||
@@ -2088,7 +2095,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 +2103,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 +2111,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 +2191,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 +2296,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 +2365,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 +2484,8 @@ 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);
|
||||
ValkeyModule *moduleFromCommand(struct redisCommand *cmd);
|
||||
void moduleFreeContext(struct ValkeyModuleCtx *ctx);
|
||||
void moduleCallCommandUnblockedHandler(client *c);
|
||||
void unblockClientFromModule(client *c);
|
||||
void moduleHandleBlockedClients(void);
|
||||
@@ -2572,6 +2580,7 @@ void addReplyOrErrorObject(client *c, robj *reply);
|
||||
void afterErrorReply(client *c, const char *s, size_t len, int flags);
|
||||
void addReplyErrorFormatInternal(client *c, int flags, const char *fmt, va_list ap);
|
||||
void addReplyErrorSdsEx(client *c, sds err, int flags);
|
||||
void addReplyErrorSdsExSafe(client *c, sds err, int flags);
|
||||
void addReplyErrorSds(client *c, sds err);
|
||||
void addReplyErrorSdsSafe(client *c, sds err);
|
||||
void addReplyError(client *c, const char *err);
|
||||
@@ -2643,6 +2652,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 */
|
||||
@@ -2884,6 +2894,7 @@ int isMutuallyExclusiveChildType(int type);
|
||||
extern rax *Users;
|
||||
extern user *DefaultUser;
|
||||
void ACLInit(void);
|
||||
int ACLModuleHasCommandRules(const struct ValkeyModule *module, sds *rule_out);
|
||||
/* Return values for ACLCheckAllPerm(). */
|
||||
#define ACL_OK 0
|
||||
#define ACL_DENIED_CMD 1
|
||||
@@ -3344,6 +3355,7 @@ int ldbPendingChildren(void);
|
||||
sds luaCreateFunction(client *c, robj *body);
|
||||
void luaLdbLineHook(lua_State *lua, lua_Debug *ar);
|
||||
void freeLuaScriptsAsync(dict *lua_scripts);
|
||||
void scriptingReset(int async);
|
||||
void freeFunctionsAsync(functionsLibCtx *lib_ctx);
|
||||
int ldbIsEnabled(void);
|
||||
void ldbLog(sds entry);
|
||||
@@ -3372,6 +3384,7 @@ void unblockClient(client *c, int queue_for_reprocessing);
|
||||
void unblockClientOnTimeout(client *c);
|
||||
void unblockClientOnError(client *c, const char *err_str);
|
||||
void queueClientForReprocessing(client *c);
|
||||
int blockedClientMayTimeout(client *c);
|
||||
void replyToBlockedClientTimedOut(client *c);
|
||||
int getTimeoutFromObjectOrReply(client *c, robj *object, mstime_t *timeout, int unit);
|
||||
void disconnectAllBlockedClients(void);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user