Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ba0a3b0137 | ||
|
|
c7952082d0 | ||
|
|
cc84b38f55 | ||
|
|
6e3a0482f2 | ||
|
|
5fbdfb0898 | ||
|
|
a206ec10f4 | ||
|
|
9b45ca22a1 | ||
|
|
8e975e2251 | ||
|
|
d5b4425f74 | ||
|
|
e337cdd763 | ||
|
|
61243b9b22 | ||
|
|
8eefb05609 | ||
|
|
1549a4bc27 | ||
|
|
dbcf7394b3 | ||
|
|
27ffb82e3b | ||
|
|
28245745f7 | ||
|
|
4522953882 | ||
|
|
0204089bf5 | ||
|
|
bfd615d485 | ||
|
|
c4c71b0ecc | ||
|
|
3c226143f2 | ||
|
|
be65f2e57d | ||
|
|
1810c6f2df | ||
|
|
6d683fca9f | ||
|
|
04e00f7db5 | ||
|
|
359425d0bb | ||
|
|
586af0fe01 | ||
|
|
4119e3b359 | ||
|
|
b88e03bbf7 | ||
|
|
d2e98b14dc | ||
|
|
90a22d63fd | ||
|
|
47b14ef377 | ||
|
|
cd79981faf | ||
|
|
77decba670 | ||
|
|
6413dade34 | ||
|
|
373f51e9fe | ||
|
|
a888fabc81 | ||
|
|
933b03140b | ||
|
|
31473a4d58 | ||
|
|
a35225204b | ||
|
|
d752c6fa20 | ||
|
|
945673489f | ||
|
|
692e12479a | ||
|
|
ae911e898d | ||
|
|
a3e1acd944 | ||
|
|
d8c86482e4 | ||
|
|
6fb955d941 | ||
|
|
f55e7c5ffa | ||
|
|
88e3151743 | ||
|
|
e9adffc3dd | ||
|
|
8ab95da167 | ||
|
|
f3134538f5 | ||
|
|
8be025b198 | ||
|
|
b5b2b7e187 | ||
|
|
57a86925f9 | ||
|
|
98035ded96 | ||
|
|
5629882f32 | ||
|
|
cb09d23fc6 | ||
|
|
e1c78a4b71 | ||
|
|
9028417de2 | ||
|
|
4795df6189 | ||
|
|
9a1723d665 | ||
|
|
97fea764ff | ||
|
|
326b5ed0ce | ||
|
|
96cecf709a | ||
|
|
d49faad4f7 | ||
|
|
3ccbc84f09 | ||
|
|
9872dcaa6b | ||
|
|
6838d170e2 | ||
|
|
0b4a0fb95f | ||
|
|
4e1d985fe4 | ||
|
|
f0171def80 | ||
|
|
7c927ceb85 | ||
|
|
17c906109a | ||
|
|
d203361731 | ||
|
|
f736254b72 | ||
|
|
e97a2d2e3d | ||
|
|
84e0d835ad | ||
|
|
d21b292d6c | ||
|
|
a59a0b3265 | ||
|
|
0e64577ae8 | ||
|
|
e8774bf911 | ||
|
|
37548047de | ||
|
|
b1d3b057f9 | ||
|
|
cd898efeae | ||
|
|
11c301d02e | ||
|
|
fe7716366e | ||
|
|
ce0d3812f9 | ||
|
|
410df42ca6 | ||
|
|
62a6989c4f | ||
|
|
5616624244 | ||
|
|
6d235257f6 | ||
|
|
c179b82482 | ||
|
|
764e74273a | ||
|
|
92ba3d3443 | ||
|
|
9b12bdc374 | ||
|
|
6fa83d8905 | ||
|
|
4ab8949b26 | ||
|
|
5a2ebc9112 | ||
|
|
f4a72e7482 | ||
|
|
4288a08782 | ||
|
|
608dc468de | ||
|
|
d4d3ac84d1 | ||
|
|
fd10fdc8f5 | ||
|
|
080069dabd | ||
|
|
0ef32c8c40 | ||
|
|
2123819a71 | ||
|
|
ebee48c4a2 | ||
|
|
c1da6e3993 | ||
|
|
a651e8e683 | ||
|
|
511868bb07 | ||
|
|
2b33b547d3 | ||
|
|
143a32d683 | ||
|
|
f5577e7419 | ||
|
|
585e60edd9 | ||
|
|
81965923be | ||
|
|
af3eb77b74 | ||
|
|
f0754d70f1 | ||
|
|
c4d6b45f50 | ||
|
|
8130caf97f | ||
|
|
08ce534557 | ||
|
|
cb7edc4abc | ||
|
|
5d9ac5948f | ||
|
|
52940f0899 |
@@ -5,6 +5,8 @@ extend-exclude = [
|
||||
"deps/",
|
||||
# crc16_slottable is primarily pre-generated random strings.
|
||||
"src/crc16_slottable.h",
|
||||
# 00-RELEASENOTES includes non-English names that might be flagged as typos in other contexts.
|
||||
"00-RELEASENOTES",
|
||||
]
|
||||
|
||||
[default.extend-words]
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
# This is a file that can be used by git-blame to ignore some revisions.
|
||||
# (git 2.23+, released in August 2019)
|
||||
#
|
||||
# Can be configured as follow:
|
||||
#
|
||||
# $ git config blame.ignoreRevsFile .git-blame-ignore-revs
|
||||
#
|
||||
# For more information you can look at git-blame(1) man page.
|
||||
|
||||
# Applied clang-format (#323)
|
||||
c41dd77a3e93e02be3c4bc75d8c76b7b4169a4ce
|
||||
|
||||
# Removed terms `master` and `slave` from the source code (#591)
|
||||
54c97479356ecf41b4b63733494a1be2ab919e17
|
||||
@@ -36,7 +36,7 @@ jobs:
|
||||
build-valkey:
|
||||
# Capture source tarball and generate checksum for it
|
||||
name: Build package ${{ matrix.distro.target }} ${{ matrix.distro.arch }}
|
||||
runs-on: 'ubuntu-latest'
|
||||
runs-on: "ubuntu-latest"
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix: ${{ fromJSON(inputs.build_matrix) }}
|
||||
@@ -51,15 +51,15 @@ jobs:
|
||||
with:
|
||||
arch: aarch64
|
||||
distro: ${{matrix.distro.target}}
|
||||
install: apt-get update && apt-get install -y build-essential libssl-dev
|
||||
run: make -C src all BUILD_TLS=yes
|
||||
install: apt-get update && apt-get install -y build-essential libssl-dev libsystemd-dev
|
||||
run: make -C src all BUILD_TLS=yes USE_SYSTEMD=yes
|
||||
|
||||
- name: Create Tarball and SHA256sums
|
||||
run: |
|
||||
TAR_FILE_NAME=valkey-${{inputs.version}}-${{matrix.distro.platform}}-${{ matrix.distro.arch}}
|
||||
mkdir -p $TAR_FILE_NAME/bin $TAR_FILE_NAME/share
|
||||
cp -rfv src/valkey-* $TAR_FILE_NAME/bin
|
||||
cp -v /home/runner/work/valkey/valkey/COPYING $TAR_FILE_NAME/share/LICENSE
|
||||
mkdir -p "$TAR_FILE_NAME/bin" "$TAR_FILE_NAME/share"
|
||||
rsync -av --exclude='*.c' --exclude='*.d' --exclude='*.o' src/valkey-* "$TAR_FILE_NAME/bin/"
|
||||
cp -v /home/runner/work/valkey/valkey/COPYING "$TAR_FILE_NAME/share/LICENSE"
|
||||
tar -czvf $TAR_FILE_NAME.tar.gz $TAR_FILE_NAME
|
||||
sha256sum $TAR_FILE_NAME.tar.gz > $TAR_FILE_NAME.tar.gz.sha256
|
||||
mkdir -p packages-files
|
||||
|
||||
@@ -36,7 +36,7 @@ jobs:
|
||||
build-valkey:
|
||||
# Capture source tarball and generate checksum for it
|
||||
name: Build package ${{ matrix.distro.target }} ${{ matrix.distro.arch }}
|
||||
runs-on: 'ubuntu-latest'
|
||||
runs-on: "ubuntu-latest"
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix: ${{ fromJSON(inputs.build_matrix) }}
|
||||
@@ -47,22 +47,26 @@ jobs:
|
||||
ref: ${{ inputs.version }}
|
||||
|
||||
- name: Install dependencies
|
||||
run: sudo apt-get update && sudo apt-get install -y build-essential libssl-dev jq wget awscli
|
||||
run: sudo apt-get update && sudo apt-get install -y build-essential libssl-dev libsystemd-dev
|
||||
|
||||
- name: Make Valkey
|
||||
run: make -C src all BUILD_TLS=yes
|
||||
run: make -C src all BUILD_TLS=yes USE_SYSTEMD=yes
|
||||
|
||||
- name: Create Tarball and SHA256sums
|
||||
run: |
|
||||
TAR_FILE_NAME=valkey-${{inputs.version}}-${{matrix.distro.platform}}-${{ matrix.distro.arch}}
|
||||
mkdir -p $TAR_FILE_NAME/bin $TAR_FILE_NAME/share
|
||||
cp -rfv src/valkey-* $TAR_FILE_NAME/bin
|
||||
cp -v /home/runner/work/valkey/valkey/COPYING $TAR_FILE_NAME/share/LICENSE
|
||||
mkdir -p "$TAR_FILE_NAME/bin" "$TAR_FILE_NAME/share"
|
||||
rsync -av --exclude='*.c' --exclude='*.d' --exclude='*.o' src/valkey-* "$TAR_FILE_NAME/bin/"
|
||||
cp -v /home/runner/work/valkey/valkey/COPYING "$TAR_FILE_NAME/share/LICENSE"
|
||||
tar -czvf $TAR_FILE_NAME.tar.gz $TAR_FILE_NAME
|
||||
sha256sum $TAR_FILE_NAME.tar.gz > $TAR_FILE_NAME.tar.gz.sha256
|
||||
mkdir -p packages-files
|
||||
cp -rfv $TAR_FILE_NAME.tar* packages-files/
|
||||
|
||||
- name: Install AWS cli.
|
||||
run: |
|
||||
sudo apt-get install -y awscli
|
||||
|
||||
- name: Configure AWS credentials
|
||||
run: |
|
||||
aws configure set region us-west-2
|
||||
|
||||
@@ -2,6 +2,10 @@ name: CI
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
concurrency:
|
||||
group: ci-${{ github.head_ref || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
|
||||
@@ -5,6 +5,10 @@ on:
|
||||
paths:
|
||||
- 'src/**'
|
||||
|
||||
concurrency:
|
||||
group: clang-${{ github.head_ref || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
clang-format-check:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
@@ -4,6 +4,10 @@ name: "Codecov"
|
||||
# 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
|
||||
|
||||
@@ -4,7 +4,11 @@ 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
|
||||
|
||||
@@ -3,11 +3,17 @@ 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 0 * * *'
|
||||
- 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'
|
||||
|
||||
+18
-14
@@ -29,6 +29,10 @@ on:
|
||||
description: "git branch or sha to use"
|
||||
default: "unstable"
|
||||
|
||||
concurrency:
|
||||
group: daily-${{ github.head_ref || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
@@ -61,7 +65,7 @@ jobs:
|
||||
run: sudo apt-get install tcl8.6 tclx
|
||||
- name: test
|
||||
if: true && !contains(github.event.inputs.skiptests, 'valkey')
|
||||
run: ./runtest --accurate --verbose --dump-logs ${{github.event.inputs.test_args}}
|
||||
run: ./runtest ${{ github.event_name != 'pull_request' && '--accurate' || '' }} --verbose --dump-logs ${{github.event.inputs.test_args}}
|
||||
- name: module api test
|
||||
if: true && !contains(github.event.inputs.skiptests, 'modules')
|
||||
run: CFLAGS='-Werror' ./runtest-moduleapi --verbose --dump-logs ${{github.event.inputs.test_args}}
|
||||
@@ -110,7 +114,7 @@ jobs:
|
||||
run: apt-get install -y tcl8.6 tclx procps
|
||||
- name: test
|
||||
if: true && !contains(github.event.inputs.skiptests, 'valkey')
|
||||
run: ./runtest --accurate --verbose --dump-logs ${{github.event.inputs.test_args}}
|
||||
run: ./runtest ${{ github.event_name != 'pull_request' && '--accurate' || '' }} --verbose --dump-logs ${{github.event.inputs.test_args}}
|
||||
- name: module api test
|
||||
if: true && !contains(github.event.inputs.skiptests, 'modules')
|
||||
run: CFLAGS='-Werror' ./runtest-moduleapi --verbose --dump-logs ${{github.event.inputs.test_args}}
|
||||
@@ -155,7 +159,7 @@ jobs:
|
||||
run: sudo apt-get install tcl8.6 tclx
|
||||
- name: test
|
||||
if: true && !contains(github.event.inputs.skiptests, 'valkey')
|
||||
run: ./runtest --accurate --verbose --dump-logs ${{github.event.inputs.test_args}}
|
||||
run: ./runtest ${{ github.event_name != 'pull_request' && '--accurate' || '' }} --verbose --dump-logs ${{github.event.inputs.test_args}}
|
||||
- name: module api test
|
||||
if: true && !contains(github.event.inputs.skiptests, 'modules')
|
||||
run: CFLAGS='-Werror' ./runtest-moduleapi --verbose --dump-logs ${{github.event.inputs.test_args}}
|
||||
@@ -194,7 +198,7 @@ jobs:
|
||||
run: sudo apt-get install tcl8.6 tclx
|
||||
- name: test
|
||||
if: true && !contains(github.event.inputs.skiptests, 'valkey')
|
||||
run: ./runtest --accurate --verbose --dump-logs ${{github.event.inputs.test_args}}
|
||||
run: ./runtest ${{ github.event_name != 'pull_request' && '--accurate' || '' }} --verbose --dump-logs ${{github.event.inputs.test_args}}
|
||||
- name: module api test
|
||||
if: true && !contains(github.event.inputs.skiptests, 'modules')
|
||||
run: CFLAGS='-Werror' ./runtest-moduleapi --verbose --dump-logs ${{github.event.inputs.test_args}}
|
||||
@@ -235,7 +239,7 @@ jobs:
|
||||
run: sudo apt-get install tcl8.6 tclx
|
||||
- name: test
|
||||
if: true && !contains(github.event.inputs.skiptests, 'valkey')
|
||||
run: ./runtest --accurate --verbose --dump-logs ${{github.event.inputs.test_args}}
|
||||
run: ./runtest ${{ github.event_name != 'pull_request' && '--accurate' || '' }} --verbose --dump-logs ${{github.event.inputs.test_args}}
|
||||
- name: module api test
|
||||
if: true && !contains(github.event.inputs.skiptests, 'modules')
|
||||
run: |
|
||||
@@ -286,7 +290,7 @@ jobs:
|
||||
- name: test
|
||||
if: true && !contains(github.event.inputs.skiptests, 'valkey')
|
||||
run: |
|
||||
./runtest --accurate --verbose --dump-logs --tls --dump-logs ${{github.event.inputs.test_args}}
|
||||
./runtest ${{ github.event_name != 'pull_request' && '--accurate' || '' }} --verbose --dump-logs --tls --dump-logs ${{github.event.inputs.test_args}}
|
||||
- name: module api test
|
||||
if: true && !contains(github.event.inputs.skiptests, 'modules')
|
||||
run: |
|
||||
@@ -332,7 +336,7 @@ jobs:
|
||||
- name: test
|
||||
if: true && !contains(github.event.inputs.skiptests, 'valkey')
|
||||
run: |
|
||||
./runtest --accurate --verbose --dump-logs ${{github.event.inputs.test_args}}
|
||||
./runtest ${{ github.event_name != 'pull_request' && '--accurate' || '' }} --verbose --dump-logs ${{github.event.inputs.test_args}}
|
||||
- name: module api test
|
||||
if: true && !contains(github.event.inputs.skiptests, 'modules')
|
||||
run: |
|
||||
@@ -375,10 +379,10 @@ jobs:
|
||||
run: sudo apt-get install tcl8.6 tclx
|
||||
- name: test
|
||||
if: true && !contains(github.event.inputs.skiptests, 'valkey')
|
||||
run: ./runtest --config io-threads 2 --config events-per-io-thread 0 --accurate --verbose --tags network --dump-logs ${{github.event.inputs.test_args}}
|
||||
run: ./runtest --io-threads --accurate --verbose --tags network --dump-logs ${{github.event.inputs.test_args}}
|
||||
- name: cluster tests
|
||||
if: true && !contains(github.event.inputs.skiptests, 'cluster')
|
||||
run: ./runtest-cluster --config io-threads 2 --config events-per-io-thread 0 ${{github.event.inputs.cluster_test_args}}
|
||||
run: ./runtest-cluster --io-threads ${{github.event.inputs.cluster_test_args}}
|
||||
|
||||
test-ubuntu-reclaim-cache:
|
||||
runs-on: ubuntu-latest
|
||||
@@ -753,7 +757,7 @@ jobs:
|
||||
run: dnf -y install tcl tcltls
|
||||
- name: test
|
||||
if: true && !contains(github.event.inputs.skiptests, 'valkey')
|
||||
run: ./runtest --accurate --verbose --dump-logs ${{github.event.inputs.test_args}}
|
||||
run: ./runtest ${{ github.event_name != 'pull_request' && '--accurate' || '' }} --verbose --dump-logs ${{github.event.inputs.test_args}}
|
||||
- name: module api test
|
||||
if: true && !contains(github.event.inputs.skiptests, 'modules')
|
||||
run: CFLAGS='-Werror' ./runtest-moduleapi --verbose --dump-logs ${{github.event.inputs.test_args}}
|
||||
@@ -822,7 +826,7 @@ jobs:
|
||||
- name: test
|
||||
if: true && !contains(github.event.inputs.skiptests, 'valkey')
|
||||
run: |
|
||||
./runtest --accurate --verbose --dump-logs --tls-module --dump-logs ${{github.event.inputs.test_args}}
|
||||
./runtest ${{ github.event_name != 'pull_request' && '--accurate' || '' }} --verbose --dump-logs --tls-module --dump-logs ${{github.event.inputs.test_args}}
|
||||
- name: module api test
|
||||
if: true && !contains(github.event.inputs.skiptests, 'modules')
|
||||
run: |
|
||||
@@ -934,7 +938,7 @@ jobs:
|
||||
run: make SERVER_CFLAGS='-Werror'
|
||||
- name: test
|
||||
if: true && !contains(github.event.inputs.skiptests, 'valkey')
|
||||
run: ./runtest --accurate --verbose --tags -ipv6 --clients 1 --no-latency --dump-logs ${{github.event.inputs.test_args}}
|
||||
run: ./runtest ${{ github.event_name != 'pull_request' && '--accurate' || '' }} --verbose --clients 1 --no-latency --dump-logs ${{github.event.inputs.test_args}}
|
||||
- name: module api test
|
||||
if: true && !contains(github.event.inputs.skiptests, 'modules')
|
||||
run: CFLAGS='-Werror' ./runtest-moduleapi --verbose --clients 1 --no-latency --dump-logs ${{github.event.inputs.test_args}}
|
||||
@@ -1086,7 +1090,7 @@ jobs:
|
||||
run: apk add tcl procps tclx
|
||||
- name: test
|
||||
if: true && !contains(github.event.inputs.skiptests, 'valkey')
|
||||
run: ./runtest --accurate --verbose --dump-logs ${{github.event.inputs.test_args}}
|
||||
run: ./runtest ${{ github.event_name != 'pull_request' && '--accurate' || '' }} --verbose --dump-logs ${{github.event.inputs.test_args}}
|
||||
- name: module api test
|
||||
if: true && !contains(github.event.inputs.skiptests, 'modules')
|
||||
run: CFLAGS='-Werror' ./runtest-moduleapi --verbose --dump-logs ${{github.event.inputs.test_args}}
|
||||
@@ -1127,7 +1131,7 @@ jobs:
|
||||
run: apk add tcl procps tclx
|
||||
- name: test
|
||||
if: true && !contains(github.event.inputs.skiptests, 'valkey')
|
||||
run: ./runtest --accurate --verbose --dump-logs ${{github.event.inputs.test_args}}
|
||||
run: ./runtest ${{ github.event_name != 'pull_request' && '--accurate' || '' }} --verbose --dump-logs ${{github.event.inputs.test_args}}
|
||||
- name: module api test
|
||||
if: true && !contains(github.event.inputs.skiptests, 'modules')
|
||||
run: CFLAGS='-Werror' ./runtest-moduleapi --verbose --dump-logs ${{github.event.inputs.test_args}}
|
||||
|
||||
@@ -4,7 +4,11 @@ on:
|
||||
pull_request:
|
||||
push:
|
||||
schedule:
|
||||
- cron: '0 0 * * *'
|
||||
- cron: '0 2 * * *'
|
||||
|
||||
concurrency:
|
||||
group: external-${{ github.head_ref || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
@@ -8,6 +8,10 @@ on:
|
||||
paths:
|
||||
- 'src/commands/*.json'
|
||||
|
||||
concurrency:
|
||||
group: reply-schemas-linter-${{ github.head_ref || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
|
||||
@@ -9,6 +9,10 @@ on:
|
||||
push:
|
||||
pull_request:
|
||||
|
||||
concurrency:
|
||||
group: spellcheck-${{ github.head_ref || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
|
||||
+408
-11
@@ -1,16 +1,413 @@
|
||||
Hello! This file is just a placeholder, since this is the "unstable" branch
|
||||
of Valkey, the place where all the development happens.
|
||||
Valkey 8.0 release notes
|
||||
========================
|
||||
--------------------------------------------------------------------------------
|
||||
Upgrade urgency levels:
|
||||
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.
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
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.
|
||||
================================================================================
|
||||
Valkey 8.0.1 - Released Tue 1 Oct 2024
|
||||
================================================================================
|
||||
|
||||
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:
|
||||
Upgrade urgency SECURITY: This release includes security fixes we recommend you
|
||||
apply as soon as possible.
|
||||
|
||||
https://valkey.io/download/
|
||||
Bug fixes
|
||||
=========
|
||||
* Fix a build issue with RDMA when using additional make parameters. (#1074)
|
||||
* Fix an issue where `CLUSTER SLOTS` might return the wrong tcp or tls port when called
|
||||
from inside a script or from a module. (#1072)
|
||||
* Fix a crash when `CLUSTER SLOTS` or `CLUSTER SHARDS` is called from inside
|
||||
a script or from a module. (#1063)
|
||||
* Fix a build issue on systems where `<threads.h>` is unavailable. (#1053)
|
||||
* Fix an issue with the default `sentinel.conf` being invalid. (#1040)
|
||||
|
||||
More information is available at https://valkey.io
|
||||
Security fixes
|
||||
==============
|
||||
|
||||
Happy hacking!
|
||||
* (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 8.0.0 GA - Released Sun 15 Sep 2024
|
||||
================================================================================
|
||||
Upgrade urgency LOW: This is the first release of Valkey 8.0, which
|
||||
includes stability and performance improvements over the second release
|
||||
candidate. This release is fully compatible with Redis OSS 7.2.4.
|
||||
|
||||
Logging and Tooling Improvements
|
||||
================================
|
||||
* Added full client info to SHUTDOWN and CLUSTER FAILOVER logs for better traceability
|
||||
of requests. (#875)
|
||||
|
||||
Bug fixes
|
||||
=========
|
||||
* Resolved issues in replicationSetPrimary where the primary node's IP/port updates were
|
||||
not correctly handled in the cluster gossip section. (#965)
|
||||
* Fixed AOF base suffix during rewrites when modifying the aof-use-rdb-preamble setting,
|
||||
ensuring correct suffix caching to prevent inconsistencies. (#886)
|
||||
* Addressed rare crashes in async IO threads with TLS by preventing concurrent read and
|
||||
write job overlap. (#1011)
|
||||
* Prevented AOF from being incorrectly disabled after loading RDB data, ensuring proper
|
||||
re-enabling of AOF. (#1001)
|
||||
* Triggered a save of the cluster configuration file before shutdown to prevent
|
||||
inconsistencies caused by unsaved node configuration changes. (#822)
|
||||
* Fixed timing issue in CLUSTER SETSLOT to ensure replicas handle migration correctly
|
||||
when receiving the command before the gossip update. (#981)
|
||||
|
||||
Performance
|
||||
===========
|
||||
* Optimized the handling of temporary set objects in SUNION and SDIFF commands, resulting
|
||||
in a 41% performance improvement for SUNION and 27% for SDIFF. (#996)
|
||||
|
||||
Behavior Changes
|
||||
================
|
||||
* Replicas now flush old data after checking RDB file is valid during disk-based replication,
|
||||
preventing partial data loss and ensuring a clean data load. (#926)
|
||||
|
||||
================================================================================
|
||||
Valkey 8.0.0 RC2 - Released Tue 2 Sep 2024
|
||||
================================================================================
|
||||
Upgrade urgency LOW: This is the second release candidate of Valkey 8.0, which
|
||||
generally includes stability and performance improvements over the first release
|
||||
candidate. This release is fully compatible with Redis OSS 7.2.4.
|
||||
|
||||
New Features
|
||||
============
|
||||
* Add support for setting the group on a unix domain socket. (#901)
|
||||
* Experimental - RDMA: Support user keepalive command. (#916)
|
||||
|
||||
Logging and Tooling Improvements
|
||||
================================
|
||||
* Improve logging when a cluster is unable to failover. (#780)
|
||||
* Add epoch information to failover auth denied logs. (#816)
|
||||
* Improve messaging when valkey-cli cluster --fix meet check failed. (#867)
|
||||
* Log unexpected $ENDOFF responses in dual channel replication. (#839)
|
||||
* Skip IPv6 tests when it is unsupported on TCLSH. (#910)
|
||||
* Add a light weight version of DEBUG OBJECT. (#881)
|
||||
* Add lfu support for DEBUG OBJECT command, added lfu_freq and
|
||||
lfu_access_time_minutes fields. (#479)
|
||||
|
||||
Bug fixes
|
||||
=========
|
||||
* Correctly expose client infomation in the slowlog when running commands in scripts. (#805)
|
||||
* Fix a bug where lastbgsave_status was unecessarily being updated when dual
|
||||
channel replication failed. (#811)
|
||||
* Fix a bug which caused dual channel replication to get stuck because of a TLS
|
||||
issue. (#837)
|
||||
* Fix a bug which caused bouncing `-REDIRECT` messages during a FAILOVER (#871)
|
||||
* Avoid re-establishing replication to a node that is already the primary in `CLUSTER REPLICATE`. (#884)
|
||||
* Fix `CLUSTER SETSLOT` with `BLOCK` to only wait for replicas that are online. (#879)
|
||||
* Fix `valkey-cli` to make source node ignores NOREPLICAS when doing the last CLUSTER SETSLOT (#928)
|
||||
* Exclude '.' and ':' from `isValidAuxChar`'s banned charset to better support
|
||||
IPV6 addresses. (#963)
|
||||
* Better handle `-REDIRECT` messages in the MULTI context. (#895)
|
||||
|
||||
Performance
|
||||
===========
|
||||
* Improve multithreaded performance with memory prefetching. (#861)
|
||||
* Optimize ZUNION[STORE] command by removing unnecessary accumulator dict. (#829)
|
||||
* Optimize linear search of WAIT and WAITAOF when unblocking the client. (#787)
|
||||
* Move prepareClientToWrite out of loop for lrange command to remove redundant calls. (#860)
|
||||
* Optimize various commands by using sdsAllocSize instead of sdsZmallocSize. (#923)
|
||||
* Using intrinsics to optimize counting HyperLogLog trailing bits. (#846)
|
||||
* Free client's MULTI state when it becomes dirty to reduce memory usage. (#961)
|
||||
* Optimize the fast path of SET if the expiration time has already expired. (#865)
|
||||
|
||||
Compatibility Improvements
|
||||
==========================
|
||||
* Add 4 sentinel command `GET-PRIMARY-ADDR-BY-NAME`, `PRIMARY`, `PRIMARIES`, and
|
||||
`IS-PRIMARY-DOWN-BY-ADDR` to allow clients to use inclusive language. (#789)
|
||||
|
||||
Behavior Changes
|
||||
================
|
||||
* Block unsubscribe related commands for clients that are not in subscribed mode. (#759)
|
||||
|
||||
Configuration Changes
|
||||
=====================
|
||||
* Change repl-backlog-size from 1MB to 10MB by default. (#911)
|
||||
* Remove the protected flag from `dual-channel-replication`. (#908)
|
||||
|
||||
================================================================================
|
||||
Valkey 8.0.0 RC1 - Released Thu 1 Aug 2024
|
||||
================================================================================
|
||||
Upgrade urgency LOW: This is the first release candidate of Valkey 8.0, with
|
||||
performance, reliability, and observability improvements. It includes asynchronous
|
||||
I/O threading, better cluster scaling reliability, dual primary-replica channel
|
||||
for faster full synchronization, per-slot metrics for resource management, and
|
||||
experimental RDMA support for increased throughput and reduced latency. This
|
||||
release is fully compatible with Redis OSS 7.2.4.
|
||||
|
||||
Un-deprecated Commands - Cluster
|
||||
================================
|
||||
* Un-deprecate the `CLUSTER SLOTS` command. (#536)
|
||||
|
||||
New/Modified Commands - Core
|
||||
============================
|
||||
* Add `SCRIPT SHOW` sub-command to dump scripts via SHA1. (#617)
|
||||
* Add `NOSCORES` option to `ZSCAN` command. (#324)
|
||||
* Add `NOVALUES` option to `HSCAN` command. (Redis#12765)
|
||||
* Expose Lua `os.clock()` API to allow scripts to determine how long the
|
||||
script has been executing. (Redis#12971)
|
||||
* Implement `CLIENT KILL MAXAGE <MAXAGE>`. (Redis#12299)
|
||||
* Allow running `WAITAOF` in scripts, remove `NOSCRIPT` flag. (Redis#12977)
|
||||
* Support `XREAD[GROUP]` with `BLOCK` option in scripts. (Redis#12596)
|
||||
* Introduce `+` as a special ID for the last item in stream on `XREAD`
|
||||
Command. (Redis#7388, Redis#13117)
|
||||
|
||||
New/Modified Commands - Cluster
|
||||
===============================
|
||||
* Introduce `CLUSTER SLOT-STATS` command which allows tracking of per slot
|
||||
metrics for key count, CPU utilization, network bytes in, and network
|
||||
bytes out. (#20, #351)
|
||||
* Add `TIMEOUT` option to `CLUSTER SETSLOT` command. (#556, #445)
|
||||
|
||||
New/Modified Metrics - Core
|
||||
===========================
|
||||
* Introduce per-client metrics for network traffic and command execution
|
||||
in `CLIENT LIST` and `CLIENT INFO`. (#327)
|
||||
* Add metrics for DB memory overhead and rehashing status to `INFO MEMORY`
|
||||
and `MEMORY STATS`. (Redis#12913)
|
||||
* Add `pubsub_clients` metric to `INFO CLIENTS`. (Redis#12849)
|
||||
* Add metrics for client buffer limit disconnections to `INFO`. (Redis#12476)
|
||||
* Add metrics for monitoring clients using `WATCH` command and watched keys.
|
||||
(Redis#12966)
|
||||
* Added allocator muzzy memory metrics to `INFO MEMORY` and `MEMORY STATS`.
|
||||
(Redis#12996)
|
||||
|
||||
New Features - Core
|
||||
===================
|
||||
* Support replica redirect for read/write operations to primary in standalone
|
||||
mode. (#325)
|
||||
* Add server config for cluster blacklist TTL. (#738)
|
||||
* Add availability zone server config. (#700)
|
||||
|
||||
New Features - Cluster
|
||||
======================
|
||||
* Support IPv4 and IPv6 dual stack and client-specific IPs in clusters. (#736)
|
||||
* Support `BY/GET` options for `SORT/SORT_RO` in cluster mode when pattern
|
||||
implies a single slot. (Redis#12728)
|
||||
|
||||
Compatibility Improvements - Core
|
||||
=================================
|
||||
* Derive RDB and module child process names based on server start name for
|
||||
compatibility. (#454)
|
||||
* Update server identity in `serverPanic` output based on `extended-redis-compatibility`
|
||||
config. (#415)
|
||||
|
||||
Compatibility Improvements - Sentinel
|
||||
=====================================
|
||||
* Accept `redis-sentinel` to start Valkey in sentinel mode. (#731)
|
||||
|
||||
Performance/Efficiency Improvements - Core
|
||||
==========================================
|
||||
* Introduce dual channel for more efficient full sync replication. (#60)
|
||||
* Introduce async IO threading for improved multi-threaded performance.
|
||||
(#763, #758)
|
||||
* Embed key directly in main dictionary entry for improved memory efficiency.
|
||||
(#541)
|
||||
* Use thread-local storage to reduce atomic contention in updating memory
|
||||
metrics. (#674)
|
||||
* Reduce redundant calls to `prepareClientToWrite` for continuous `addReply*`.
|
||||
(#670)
|
||||
* Optimize the logic for checking conversion to skip list during `ZADD` operations.
|
||||
(#806)
|
||||
* Optimize `sdsfree` with `zfree_with_size` to avoid redundant size calculation.
|
||||
(#453)
|
||||
* Combine events to eliminate redundant `kevent(2)` calls. (#638)
|
||||
* Introduce shared query buffer for client reads to reduce memory usage. (#258)
|
||||
* Optimize CRC64 performance for large batches by processing bytes in parallel.
|
||||
(#350)
|
||||
* Use `SOCK_NONBLOCK` to reduce system calls for outgoing connections. (#293)
|
||||
* Enable `accept4()` detection on specific versions of various platforms. (#294)
|
||||
* Convert CRC16 slot table to fixed-size array for improved memory efficiency.
|
||||
(Redis#13112)
|
||||
* Run `SCRIPT FLUSH` truly asynchronously and close Lua interpreter in a
|
||||
background thread. (Redis#13087)
|
||||
* Optimize `DEL` command to avoid redundant deletions for expired keys. (Redis#13080)
|
||||
* Improve defragmentation for large bins to enhance memory efficiency. (Redis#12996)
|
||||
* Optimize hash table resizing to include empty dictionaries. (Redis#12819)
|
||||
* Reduce performance impact of dictionary rehashing by optimizing bucket processing.
|
||||
(Redis#12899)
|
||||
* Optimize performance for simultaneous client `[P|S]UNSUBSCRIBE`. (Redis#12838)
|
||||
* Optimize CPU cache efficiency during dictionary rehashing. (Redis#5692)
|
||||
* Optimize `ZRANGE` offset location from linear search to skip list jump. (Redis#12450)
|
||||
* Fix `aeSetDontWait` timing to avoid unnecessary waits in `aeProcessEvent`. (Redis#12068)
|
||||
|
||||
Performance/Efficiency Improvements - Cluster
|
||||
=============================================
|
||||
* Add lightweight cluster message header for Pub/Sub messages. (#654)
|
||||
* Minor performance improvement in Valkey cluster by avoid initializing key
|
||||
buffer in `getKeysResult`. (#631)
|
||||
* Cache `CLUSTER SLOTS` response to improve throughput and reduce latency. (#53)
|
||||
* Replace slots_to_channels radix tree with slot-specific dictionaries for
|
||||
shard channels. (Redis#12804)
|
||||
* Optimize `KEYS` command when pattern includes hashtag and implies a single
|
||||
slot. (Redis#12754)
|
||||
* Optimize `SCAN` command with `MATCH` when pattern implies a single slot.
|
||||
(Redis#12536)
|
||||
* Replace cluster metadata with slot specific dictionaries to reduce memory
|
||||
usage when using Valkey cluster. (Redis#11695, Redis#12704)
|
||||
|
||||
Reliability Improvements - Core
|
||||
===============================
|
||||
* Limit tracking custom errors (e.g. from Lua) while allowing normal errors
|
||||
to be tracked (#500, Redis#13141)
|
||||
* Manage maximum number of new connections per cycle to prevent connection
|
||||
storms. (Redis#12178)
|
||||
|
||||
Reliability Improvements - Cluster
|
||||
==================================
|
||||
* Reduce fail-over time in Valkey cluster when multiple sequential fail-overs
|
||||
occurred by resetting `failover_auth_time` when the new primary node goes
|
||||
down. (#782)
|
||||
* Restrict node failure marking to primaries with assigned slots. (#634)
|
||||
* Enhance cluster meet reliability under link failures. (#461)
|
||||
* Improve reliability of slot migration in Valkey clusters. (#445)
|
||||
|
||||
Usability Improvements - Core
|
||||
=============================
|
||||
* Re-brand and refine latency report messages. (#644)
|
||||
* Optimize `ACL LOAD` to avoid disconnecting clients whose users are unchanged.
|
||||
(Redis#12171)
|
||||
|
||||
Usability Improvements - Cluster
|
||||
================================
|
||||
* Adjust log levels for various cluster-related logs to improve clarity. (#633)
|
||||
* Maintain deterministic ordering of replica(s) in `CLUSTER SLOTS` response. (#265)
|
||||
|
||||
Usability Improvements - CLI
|
||||
================================
|
||||
* Add prompt message when Ctrl-C is pressed in `valkey-cli`. (#702)
|
||||
* Keep an in-memory history of all commands in `valkey-cli` so that sensitive
|
||||
commands can be shown within the same session. (Redis#12862)
|
||||
|
||||
Module Improvements - Core
|
||||
==========================
|
||||
* Add `ValkeyModule_TryCalloc()` and `ValkeyModule_TryRealloc()` to handle
|
||||
allocation failures gracefully. (Redis#12985)
|
||||
* Make `ValkeyModule_Yield` thread-safe by handling events in the main thread.
|
||||
(Redis#12905)
|
||||
* Allow modules to declare new ACL categories. (Redis#12486)
|
||||
|
||||
Module Improvements - Cluster
|
||||
=============================
|
||||
* Add API `ValkeyModule_ClusterKeySlot` and `ValkeyModule_ClusterCanonicalKeyNameInSlot`.
|
||||
(Redis#13069)
|
||||
|
||||
Behavior Changes - Core
|
||||
=======================
|
||||
* Re-brand the Lua debugger. (#603)
|
||||
* Change default pidfile from `redis.pid` to `valkey.pid`. (#378)
|
||||
* Abort transactions on nested `MULTI` or `WATCH` commands. (#723)
|
||||
* Ensure keys that match the `SCAN` filter are not lazily expired and return
|
||||
an error for invalid types. (#501)
|
||||
* Rename `redis` in AOF logs and proc title to `valkey-aof-rewrite`. (#393)
|
||||
* Change default syslog-ident from `redis` to `valkey`. (#390)
|
||||
* Update `Redis` to `Valkey` in `serverLog` messages in server.c file. (#231)
|
||||
* Remove `Redis` from various error reply messages. See GitHub PR for more
|
||||
details. (#206)
|
||||
* Reject empty strings for configs `dir`, `dbfilename`, and `cluster-config-file`.
|
||||
(#636)
|
||||
* Change key-spec flag from `RW` to `OW` for `SINTERSTORE` command. (Redis#12917)
|
||||
* Return more precise error messages for some cases verifying keys during script
|
||||
execution. (Redis#12707)
|
||||
* Return errors for `BITCOUNT` and `BITPOS` with non-existing keys or invalid
|
||||
arguments instead of zero. (Redis#11734)
|
||||
* Validate `BITCOUNT` arguments before key existence check. (Redis#12394)
|
||||
* Redact ACL username information and mark `*-key-file-pass` configs as
|
||||
sensitive. (Redis#12860)
|
||||
* Allow `MULTI/EXEC` to use a small amount of additional memory beyond the
|
||||
used-memory limit. (Redis#12961)
|
||||
|
||||
Behavior Changes - Cluster
|
||||
==========================
|
||||
* Allow `CLUSTER NODES/INFO/MYID/MYSHARDID` during loading state. (#596)
|
||||
* Make cluster replicas return `ASK` and `TRYAGAIN` during slot migration. (#495)
|
||||
|
||||
Behavior Changes - Sentinel
|
||||
===========================
|
||||
* Replace `master-reboot-down-after-period` with `primary-reboot-down-after-period`
|
||||
in `sentinel.conf`. (#647)
|
||||
|
||||
Bug Fixes - Core
|
||||
================
|
||||
* Fix a bug that caused LRU/LFU inconsistencies for some integer objects. (#250)
|
||||
* Fix a bug where Valkey may use a sub-optimal encoding for some data types.
|
||||
(Redis#13148)
|
||||
* Fix propagation of `entries_read` by calling `streamPropagateGroupID`
|
||||
unconditionally. (Redis#12898)
|
||||
* Fix race condition issues between the main thread and module threads.
|
||||
(Redis#12817)
|
||||
* Wake blocked clients ASAP in next `beforeSleep` for `WAITAOF`. (Redis#12627)
|
||||
* Fix crash in crash-report and improve thread management with RW locks.
|
||||
(Redis#12623)
|
||||
|
||||
Bug Fixes - Cluster
|
||||
===================
|
||||
* Fix a bug where a shard returns the incorrect slot slot information in
|
||||
`CLUSTER SHARDS` command on primary failure. (#790)
|
||||
* Allow module authentication to succeed when the cluster is down. (#693)
|
||||
* Fix `PONG` message processing for primary-ship tracking during fail-overs.
|
||||
(Redis#13055)
|
||||
* Prevent double freeing of cluster link with `DEBUG CLUSTERLINK KILL`.
|
||||
(Redis#12930)
|
||||
* Unsubscribe all clients from replica for shard channel if the primary
|
||||
ownership changes. (Redis#12577)
|
||||
|
||||
Bug Fixes - Tooling
|
||||
===============
|
||||
* Fix `valkey-check-aof` misidentifying data in manifest format as MP-AOF.
|
||||
(Redis#12958)
|
||||
* Fix `valkey-cli` to respect the `--count` option without requiring
|
||||
`--pattern`. (Redis#13092)
|
||||
* Fix `valkey-benchmark` to distribute operations across all slots owned by
|
||||
a node in cluster mode. (Redis#12986)
|
||||
|
||||
Internal Codebase Improvements
|
||||
==============================
|
||||
* Enable debug asserts for cluster and sentinel tests. (#588)
|
||||
* Introduce a minimal debugger for Tcl integration test suite. (#683)
|
||||
* Set up clang-format GitHub action for automated code formatting checks. (#538)
|
||||
* Replace custom atomic logic with C11 _Atomics. (#490)
|
||||
* Add fast fail option for Tcl test cases. (#482)
|
||||
* Introduce a simple unit test framework. (#460)
|
||||
* An initial simple unit test framework. (#344)
|
||||
* Introduce Codecov for automated code coverage tracking. (#316)
|
||||
* Remove deprecated `redis-trib` CLI program. (#281)
|
||||
* Add `-fno-omit-frame-pointer` to default compilation flags to improve
|
||||
debuggability. (Redis#12973)
|
||||
* Refactor the per-slot dict-array db.c into a new kvstore data structure.
|
||||
(Redis#12822)
|
||||
* Unified database rehash method for both standalone and cluster modes.
|
||||
(Redis#12848)
|
||||
* Clarify and decouple the sampling logic in eviction to improve readability.
|
||||
(Redis#12781)
|
||||
* Rewrite large printf calls to smaller ones for readability. (Redis#12257)
|
||||
|
||||
Experimental
|
||||
============
|
||||
* Introduce Valkey Over RDMA transport (experimental). (#477)
|
||||
|
||||
We appreciate the efforts of all who contributed code to this release!
|
||||
|
||||
lan Slang, Binbin, Brennan, Chen Tianjie, Cui Fliter, Daniel House, Darren Jiang,
|
||||
David Carlier, Debing Sun, Dingrui, Dmitry Polyakovsky, Eran Liberty, Gabi Ganam,
|
||||
George Guimares, Guillaume Koenig, Guybe, Harkrishn Patro, Hassaan Khan, Hwang Si Yeon,
|
||||
ICHINOSE Shogo, icy17, Ikko Eltociear Ashimine, iKun, Itamar Haber, Jachin, Jacob Murphy,
|
||||
Jason Elbaum, Jeff Liu, John Sully, John Vandenberg, Jonathan Wright, Jonghoonpark, Joe Hu,
|
||||
Josiah Carlson, Juho Kim, judeng, Jun Luo, K.G. Wang, Karthik Subbarao, Karthick Ariyaratnam,
|
||||
kell0gg, Kyle Kim, Leibale Eidelman, LiiNen, Lipeng Zhu, Lior Kogan, Lior Lahav, Madelyn Olson,
|
||||
Makdon, Maria Markova, Mason Hall, Matthew Douglass, meiravgri, michalbiesek, Mike Dolan,
|
||||
Mikel Olasagasti Uranga, Moshe Kaplan, mwish, naglera, NAM UK KIM, Neal Gompa, nitaicaro,
|
||||
Nir Rattner, Oran Agra, Ouri Half, Ozan Tezcan, Parth, PatrickJS, Pengfei Han, Pierre, Ping Xie,
|
||||
poiuj, pshankinclarke, ranshid, Ronen Kalish, Roshan Khatri, Samuel Adetunji, Sankar, secwall,
|
||||
Sergey Fedorov, Sher_Sun, Shivshankar, skyfirelee, Slava Koyfman, Subhi Al Hasan, sundb,
|
||||
Ted Lyngmo, Thomas Fline, tison, Tom Morris, Tyler Bream, uriyage, Viktor Söderqvist, Vitaly,
|
||||
Vitah Lin, VoletiRam, w. ian douglas, WangYu, Wen Hui, Wenwen Chen, Yaacov Hazan, Yanqi Lv,
|
||||
Yehoshua Hershberg, Yves LeBras, zalj, Zhao Zhao, zhenwei pi, zisong.cw
|
||||
|
||||
@@ -17,7 +17,7 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
|
||||
BSD 3-Clause License
|
||||
|
||||
Copyright (c) 2006-2020, Salvatore Sanfilippo
|
||||
Copyright (c) 2006-2020, Redis Ltd.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
@@ -1,106 +0,0 @@
|
||||
[Note: This was the manifesto of Redis. It does not represent the ideals of Valkey, but is
|
||||
kept in remembrance for the ideals that Salvatore had for the project.]
|
||||
|
||||
Redis Manifesto
|
||||
===============
|
||||
|
||||
1 - A DSL for Abstract Data Types. Redis is a DSL (Domain Specific Language)
|
||||
that manipulates abstract data types and implemented as a TCP daemon.
|
||||
Commands manipulate a key space where keys are binary-safe strings and
|
||||
values are different kinds of abstract data types. Every data type
|
||||
represents an abstract version of a fundamental data structure. For instance
|
||||
Redis Lists are an abstract representation of linked lists. In Redis, the
|
||||
essence of a data type isn't just the kind of operations that the data types
|
||||
support, but also the space and time complexity of the data type and the
|
||||
operations performed upon it.
|
||||
|
||||
2 - Memory storage is #1. The Redis data set, composed of defined key-value
|
||||
pairs, is primarily stored in the computer's memory. The amount of memory in
|
||||
all kinds of computers, including entry-level servers, is increasing
|
||||
significantly each year. Memory is fast, and allows Redis to have very
|
||||
predictable performance. Datasets composed of 10k or 40 millions keys will
|
||||
perform similarly. Complex data types like Redis Sorted Sets are easy to
|
||||
implement and manipulate in memory with good performance, making Redis very
|
||||
simple. Redis will continue to explore alternative options (where data can
|
||||
be optionally stored on disk, say) but the main goal of the project remains
|
||||
the development of an in-memory database.
|
||||
|
||||
3 - Fundamental data structures for a fundamental API. The Redis API is a direct
|
||||
consequence of fundamental data structures. APIs can often be arbitrary but
|
||||
not an API that resembles the nature of fundamental data structures. If we
|
||||
ever meet intelligent life forms from another part of the universe, they'll
|
||||
likely know, understand and recognize the same basic data structures we have
|
||||
in our computer science books. Redis will avoid intermediate layers in API,
|
||||
so that the complexity is obvious and more complex operations can be
|
||||
performed as the sum of the basic operations.
|
||||
|
||||
4 - We believe in code efficiency. Computers get faster and faster, yet we
|
||||
believe that abusing computing capabilities is not wise: the amount of
|
||||
operations you can do for a given amount of energy remains anyway a
|
||||
significant parameter: it allows to do more with less computers and, at
|
||||
the same time, having a smaller environmental impact. Similarly Redis is
|
||||
able to "scale down" to smaller devices. It is perfectly usable in a
|
||||
Raspberry Pi and other small ARM based computers. Faster code having
|
||||
just the layers of abstractions that are really needed will also result,
|
||||
often, in more predictable performances. We think likewise about memory
|
||||
usage, one of the fundamental goals of the Redis project is to
|
||||
incrementally build more and more memory efficient data structures, so that
|
||||
problems that were not approachable in RAM in the past will be perfectly
|
||||
fine to handle in the future.
|
||||
|
||||
5 - Code is like a poem; it's not just something we write to reach some
|
||||
practical result. Sometimes people that are far from the Redis philosophy
|
||||
suggest using other code written by other authors (frequently in other
|
||||
languages) in order to implement something Redis currently lacks. But to us
|
||||
this is like if Shakespeare decided to end Enrico IV using the Paradiso from
|
||||
the Divina Commedia. Is using any external code a bad idea? Not at all. Like
|
||||
in "One Thousand and One Nights" smaller self contained stories are embedded
|
||||
in a bigger story, we'll be happy to use beautiful self contained libraries
|
||||
when needed. At the same time, when writing the Redis story we're trying to
|
||||
write smaller stories that will fit in to other code.
|
||||
|
||||
6 - We're against complexity. We believe designing systems is a fight against
|
||||
complexity. We'll accept to fight the complexity when it's worthwhile but
|
||||
we'll try hard to recognize when a small feature is not worth 1000s of lines
|
||||
of code. Most of the time the best way to fight complexity is by not
|
||||
creating it at all. Complexity is also a form of lock-in: code that is
|
||||
very hard to understand cannot be modified by users in an independent way
|
||||
regardless of the license. One of the main Redis goals is to remain
|
||||
understandable, enough for a single programmer to have a clear idea of how
|
||||
it works in detail just reading the source code for a couple of weeks.
|
||||
|
||||
7 - Threading is not a silver bullet. Instead of making Redis threaded we
|
||||
believe on the idea of an efficient (mostly) single threaded Redis core.
|
||||
Multiple of such cores, that may run in the same computer or may run
|
||||
in multiple computers, are abstracted away as a single big system by
|
||||
higher order protocols and features: Redis Cluster and the upcoming
|
||||
Redis Proxy are our main goals. A shared nothing approach is not just
|
||||
much simpler (see the previous point in this document), is also optimal
|
||||
in NUMA systems. In the specific case of Redis it allows for each instance
|
||||
to have a more limited amount of data, making the Redis persist-by-fork
|
||||
approach more sounding. In the future we may explore parallelism only for
|
||||
I/O, which is the low hanging fruit: minimal complexity could provide an
|
||||
improved single process experience.
|
||||
|
||||
8 - Two levels of API. The Redis API has two levels: 1) a subset of the API fits
|
||||
naturally into a distributed version of Redis and 2) a more complex API that
|
||||
supports multi-key operations. Both are useful if used judiciously but
|
||||
there's no way to make the more complex multi-keys API distributed in an
|
||||
opaque way without violating our other principles. We don't want to provide
|
||||
the illusion of something that will work magically when actually it can't in
|
||||
all cases. Instead we'll provide commands to quickly migrate keys from one
|
||||
instance to another to perform multi-key operations and expose the
|
||||
trade-offs to the user.
|
||||
|
||||
9 - We optimize for joy. We believe writing code is a lot of hard work, and the
|
||||
only way it can be worth is by enjoying it. When there is no longer joy in
|
||||
writing code, the best thing to do is stop. To prevent this, we'll avoid
|
||||
taking paths that will make Redis less of a joy to develop.
|
||||
|
||||
10 - All the above points are put together in what we call opportunistic
|
||||
programming: trying to get the most for the user with minimal increases
|
||||
in complexity (hanging fruits). Solve 95% of the problem with 5% of the
|
||||
code when it is acceptable. Avoid a fixed schedule but follow the flow of
|
||||
user requests, inspiration, Redis internal readiness for certain features
|
||||
(sometimes many past changes reach a critical point making a previously
|
||||
complex feature very easy to obtain).
|
||||
@@ -1,10 +1,8 @@
|
||||
[](https://codecov.io/gh/valkey-io/valkey)
|
||||
|
||||
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.
|
||||
This README is just a fast *quick start* document. More details can be found under [valkey.io](https://valkey.io/)
|
||||
|
||||
What is Valkey?
|
||||
--------------
|
||||
@@ -27,10 +25,18 @@ It is as simple as:
|
||||
% make
|
||||
|
||||
To build with TLS support, you'll need OpenSSL development libraries (e.g.
|
||||
libssl-dev on Debian/Ubuntu) and run:
|
||||
libssl-dev on Debian/Ubuntu).
|
||||
|
||||
To build TLS support as Valkey built-in:
|
||||
|
||||
% make BUILD_TLS=yes
|
||||
|
||||
TO build TLS as Valkey module:
|
||||
|
||||
% make BUILD_TLS=module
|
||||
|
||||
Note that sentinel mode does not support TLS module.
|
||||
|
||||
To build with experimental RDMA support you'll need RDMA development libraries
|
||||
(e.g. librdmacm-dev and libibverbs-dev on Debian/Ubuntu). For now, Valkey only
|
||||
supports RDMA as connection module mode. Run:
|
||||
@@ -54,12 +60,16 @@ After building Valkey, it is a good idea to test it using:
|
||||
|
||||
% make test
|
||||
|
||||
If TLS is built, running the tests with TLS enabled (you will need `tcl-tls`
|
||||
installed):
|
||||
The above runs the main integration tests. Additional tests are started using:
|
||||
|
||||
% ./utils/gen-test-certs.sh
|
||||
% ./runtest --tls
|
||||
% make test-unit # Unit tests
|
||||
% make test-modules # Tests of the module API
|
||||
% make test-sentinel # Valkey Sentinel integration tests
|
||||
% make test-cluster # Valkey Cluster integration tests
|
||||
|
||||
More about running the integration tests can be found in
|
||||
[tests/README.md](tests/README.md) and for unit tests, see
|
||||
[src/unit/README.md](src/unit/README.md).
|
||||
|
||||
Fixing build problems with dependencies or cached build options
|
||||
---------
|
||||
@@ -158,8 +168,41 @@ line, with exactly the same name.
|
||||
Running Valkey with TLS:
|
||||
------------------
|
||||
|
||||
Please consult the [TLS.md](TLS.md) file for more information on
|
||||
how to use Valkey with TLS.
|
||||
### Running manually
|
||||
To manually run a Valkey server with TLS mode (assuming `./gen-test-certs.sh` was invoked so sample certificates/keys are available):
|
||||
|
||||
* TLS built-in mode:
|
||||
```
|
||||
./src/valkey-server --tls-port 6379 --port 0 \
|
||||
--tls-cert-file ./tests/tls/valkey.crt \
|
||||
--tls-key-file ./tests/tls/valkey.key \
|
||||
--tls-ca-cert-file ./tests/tls/ca.crt
|
||||
```
|
||||
|
||||
* TLS module mode:
|
||||
```
|
||||
./src/valkey-server --tls-port 6379 --port 0 \
|
||||
--tls-cert-file ./tests/tls/valkey.crt \
|
||||
--tls-key-file ./tests/tls/valkey.key \
|
||||
--tls-ca-cert-file ./tests/tls/ca.crt \
|
||||
--loadmodule src/valkey-tls.so
|
||||
```
|
||||
|
||||
Note that you can disable TCP by specifying `--port 0` explicitly.
|
||||
It's also possible to have both TCP and TLS available at the same time,
|
||||
but you'll have to assign different ports.
|
||||
|
||||
Use `valkey-cli` to connect to the Valkey server:
|
||||
```
|
||||
./src/valkey-cli --tls \
|
||||
--cert ./tests/tls/valkey.crt \
|
||||
--key ./tests/tls/valkey.key \
|
||||
--cacert ./tests/tls/ca.crt
|
||||
```
|
||||
|
||||
Specifying `--tls-replication yes` makes a replica connect to the primary.
|
||||
|
||||
Using `--tls-cluster yes` makes Valkey Cluster use TLS across nodes.
|
||||
|
||||
Running Valkey with RDMA:
|
||||
------------------
|
||||
|
||||
@@ -1,106 +0,0 @@
|
||||
TLS Support
|
||||
===========
|
||||
|
||||
Getting Started
|
||||
---------------
|
||||
|
||||
### Building
|
||||
|
||||
To build with TLS support you'll need OpenSSL development libraries (e.g.
|
||||
libssl-dev on Debian/Ubuntu).
|
||||
|
||||
To build TLS support as Valkey built-in:
|
||||
Run `make BUILD_TLS=yes`.
|
||||
|
||||
Or to build TLS as Valkey module:
|
||||
Run `make BUILD_TLS=module`.
|
||||
|
||||
Note that sentinel mode does not support TLS module.
|
||||
|
||||
### Tests
|
||||
|
||||
To run Valkey test suite with TLS, you'll need TLS support for TCL (i.e.
|
||||
`tcl-tls` package on Debian/Ubuntu).
|
||||
|
||||
1. Run `./utils/gen-test-certs.sh` to generate a root CA and a server
|
||||
certificate.
|
||||
|
||||
2. Run `./runtest --tls` or `./runtest-cluster --tls` to run Valkey and Valkey
|
||||
Cluster tests in TLS mode.
|
||||
|
||||
3. Run `./runtest --tls-module` or `./runtest-cluster --tls-module` to
|
||||
run Valkey and Valkey cluster tests in TLS mode with Valkey module.
|
||||
|
||||
### Running manually
|
||||
|
||||
To manually run a Valkey server with TLS mode (assuming `gen-test-certs.sh` was
|
||||
invoked so sample certificates/keys are available):
|
||||
|
||||
For TLS built-in mode:
|
||||
|
||||
./src/valkey-server --tls-port 6379 --port 0 \
|
||||
--tls-cert-file ./tests/tls/valkey.crt \
|
||||
--tls-key-file ./tests/tls/valkey.key \
|
||||
--tls-ca-cert-file ./tests/tls/ca.crt
|
||||
|
||||
For TLS module mode:
|
||||
|
||||
./src/valkey-server --tls-port 6379 --port 0 \
|
||||
--tls-cert-file ./tests/tls/valkey.crt \
|
||||
--tls-key-file ./tests/tls/valkey.key \
|
||||
--tls-ca-cert-file ./tests/tls/ca.crt \
|
||||
--loadmodule src/valkey-tls.so
|
||||
|
||||
To connect to this Valkey server with `valkey-cli`:
|
||||
|
||||
./src/valkey-cli --tls \
|
||||
--cert ./tests/tls/valkey.crt \
|
||||
--key ./tests/tls/valkey.key \
|
||||
--cacert ./tests/tls/ca.crt
|
||||
|
||||
Specifying `port 0` will disable TCP. It's also possible to have
|
||||
both TCP and TLS available, but you'll need to assign different ports.
|
||||
|
||||
To make a Replica connect to the master using TLS, use `--tls-replication yes`,
|
||||
and to make Valkey Cluster use TLS across nodes use `--tls-cluster yes`.
|
||||
|
||||
Connections
|
||||
-----------
|
||||
|
||||
All socket operations now go through a connection abstraction layer that hides
|
||||
I/O and read/write event handling from the caller.
|
||||
|
||||
**Multi-threading I/O is not currently supported for TLS**, as a TLS connection
|
||||
needs to do its own manipulation of AE events which is not thread safe. The
|
||||
solution is probably to manage independent AE loops for I/O threads and longer
|
||||
term association of connections with threads. This may potentially improve
|
||||
overall performance as well.
|
||||
|
||||
Sync IO for TLS is currently implemented in a hackish way, i.e. making the
|
||||
socket blocking and configuring socket-level timeout. This means the timeout
|
||||
value may not be so accurate, and there would be a lot of syscall overhead.
|
||||
However I believe that getting rid of syncio completely in favor of pure async
|
||||
work is probably a better move than trying to fix that. For replication it would
|
||||
probably not be so hard. For cluster keys migration it might be more difficult,
|
||||
but there are probably other good reasons to improve that part anyway.
|
||||
|
||||
To-Do List
|
||||
----------
|
||||
|
||||
- [ ] valkey-benchmark support. The current implementation is a mix of using
|
||||
hiredis for parsing and basic networking (establishing connections), but
|
||||
directly manipulating sockets for most actions. This will need to be cleaned
|
||||
up for proper TLS support. The best approach is probably to migrate to hiredis
|
||||
async mode.
|
||||
- [ ] valkey-cli `--slave` and `--rdb` support.
|
||||
|
||||
Multi-port
|
||||
----------
|
||||
|
||||
Consider the implications of allowing TLS to be configured on a separate port,
|
||||
making Valkey listening on multiple ports:
|
||||
|
||||
1. Startup banner port notification
|
||||
2. Proctitle
|
||||
3. How slaves announce themselves
|
||||
4. Cluster bus port calculation
|
||||
Vendored
+1
-1
@@ -6,7 +6,7 @@
|
||||
* [1] https://www.cs.tufts.edu/~nr/cs257/archive/florian-loitsch/printf.pdf
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* Copyright (c) 2021, Redis Labs
|
||||
* Copyright (c) 2021, Redis Ltd.
|
||||
* Copyright (c) 2013-2019, night-shift <as.smljk at gmail dot com>
|
||||
* Copyright (c) 2009, Florian Loitsch < florian.loitsch at inria dot fr >
|
||||
* All rights reserved.
|
||||
|
||||
Vendored
+1
-1
@@ -1,4 +1,4 @@
|
||||
Copyright (c) 2009-2011, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
Copyright (c) 2009-2011, Redis Ltd.
|
||||
Copyright (c) 2010-2011, Pieter Noordhuis <pcnoordhuis at gmail dot com>
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Vendored
+1
-1
@@ -1,5 +1,5 @@
|
||||
# Hiredis Makefile
|
||||
# Copyright (C) 2010-2011 Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
# Copyright (C) 2010-2011 Redis Ltd.
|
||||
# Copyright (C) 2010-2011 Pieter Noordhuis <pcnoordhuis at gmail dot com>
|
||||
# This file is released under the BSD license, see the COPYING file
|
||||
|
||||
|
||||
Vendored
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2011, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* Copyright (c) 2009-2011, Redis Ltd.
|
||||
* Copyright (c) 2010-2011, Pieter Noordhuis <pcnoordhuis at gmail dot com>
|
||||
*
|
||||
* All rights reserved.
|
||||
|
||||
Vendored
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2011, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* Copyright (c) 2009-2011, Redis Ltd.
|
||||
* Copyright (c) 2010-2011, Pieter Noordhuis <pcnoordhuis at gmail dot com>
|
||||
*
|
||||
* All rights reserved.
|
||||
|
||||
Vendored
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2011, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* Copyright (c) 2009-2011, Redis Ltd.
|
||||
* Copyright (c) 2010-2011, Pieter Noordhuis <pcnoordhuis at gmail dot com>
|
||||
*
|
||||
* All rights reserved.
|
||||
|
||||
Vendored
+1
-1
@@ -5,7 +5,7 @@
|
||||
* tables of power of two in size are used, collisions are handled by
|
||||
* chaining. See the source code for more information... :)
|
||||
*
|
||||
* Copyright (c) 2006-2010, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* Copyright (c) 2006-2010, Redis Ltd.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
||||
Vendored
+1
-1
@@ -5,7 +5,7 @@
|
||||
* tables of power of two in size are used, collisions are handled by
|
||||
* chaining. See the source code for more information... :)
|
||||
*
|
||||
* Copyright (c) 2006-2010, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* Copyright (c) 2006-2010, Redis Ltd.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2020, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* Copyright (c) 2020, Redis Ltd.
|
||||
* Copyright (c) 2020, Pieter Noordhuis <pcnoordhuis at gmail dot com>
|
||||
* Copyright (c) 2020, Matt Stancliff <matt at genges dot com>,
|
||||
* Jan-Erik Rediger <janerik at fnordig dot com>
|
||||
|
||||
Vendored
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2011, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* Copyright (c) 2009-2011, Redis Ltd.
|
||||
* Copyright (c) 2010-2014, Pieter Noordhuis <pcnoordhuis at gmail dot com>
|
||||
* Copyright (c) 2015, Matt Stancliff <matt at genges dot com>,
|
||||
* Jan-Erik Rediger <janerik at fnordig dot com>
|
||||
|
||||
Vendored
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2011, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* Copyright (c) 2009-2011, Redis Ltd.
|
||||
* Copyright (c) 2010-2014, Pieter Noordhuis <pcnoordhuis at gmail dot com>
|
||||
* Copyright (c) 2015, Matt Stancliff <matt at genges dot com>,
|
||||
* Jan-Erik Rediger <janerik at fnordig dot com>
|
||||
|
||||
Vendored
+1
-1
@@ -1,6 +1,6 @@
|
||||
|
||||
/*
|
||||
* Copyright (c) 2019, Redis Labs
|
||||
* Copyright (c) 2019, Redis Ltd.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
|
||||
Vendored
+1
-1
@@ -1,6 +1,6 @@
|
||||
/* Extracted from anet.c to work properly with Hiredis error reporting.
|
||||
*
|
||||
* Copyright (c) 2009-2011, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* Copyright (c) 2009-2011, Redis Ltd.
|
||||
* Copyright (c) 2010-2014, Pieter Noordhuis <pcnoordhuis at gmail dot com>
|
||||
* Copyright (c) 2015, Matt Stancliff <matt at genges dot com>,
|
||||
* Jan-Erik Rediger <janerik at fnordig dot com>
|
||||
|
||||
Vendored
+1
-1
@@ -1,6 +1,6 @@
|
||||
/* Extracted from anet.c to work properly with Hiredis error reporting.
|
||||
*
|
||||
* Copyright (c) 2009-2011, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* Copyright (c) 2009-2011, Redis Ltd.
|
||||
* Copyright (c) 2010-2014, Pieter Noordhuis <pcnoordhuis at gmail dot com>
|
||||
* Copyright (c) 2015, Matt Stancliff <matt at genges dot com>,
|
||||
* Jan-Erik Rediger <janerik at fnordig dot com>
|
||||
|
||||
Vendored
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2011, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* Copyright (c) 2009-2011, Redis Ltd.
|
||||
* Copyright (c) 2010-2011, Pieter Noordhuis <pcnoordhuis at gmail dot com>
|
||||
*
|
||||
* All rights reserved.
|
||||
|
||||
Vendored
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2011, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* Copyright (c) 2009-2011, Redis Ltd.
|
||||
* Copyright (c) 2010-2011, Pieter Noordhuis <pcnoordhuis at gmail dot com>
|
||||
*
|
||||
* All rights reserved.
|
||||
|
||||
Vendored
+1
-2
@@ -1,8 +1,7 @@
|
||||
/* SDSLib 2.0 -- A C dynamic strings library
|
||||
*
|
||||
* Copyright (c) 2006-2015, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* Copyright (c) 2006-2015, Redis Ltd.
|
||||
* Copyright (c) 2015, Oran Agra
|
||||
* Copyright (c) 2015, Redis Labs, Inc
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
||||
Vendored
+1
-2
@@ -1,8 +1,7 @@
|
||||
/* SDSLib 2.0 -- A C dynamic strings library
|
||||
*
|
||||
* Copyright (c) 2006-2015, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* Copyright (c) 2006-2015, Redis Ltd.
|
||||
* Copyright (c) 2015, Oran Agra
|
||||
* Copyright (c) 2015, Redis Labs, Inc
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
||||
Vendored
+1
-2
@@ -1,8 +1,7 @@
|
||||
/* SDSLib 2.0 -- A C dynamic strings library
|
||||
*
|
||||
* Copyright (c) 2006-2015, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* Copyright (c) 2006-2015, Redis Ltd.
|
||||
* Copyright (c) 2015, Oran Agra
|
||||
* Copyright (c) 2015, Redis Labs, Inc
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
||||
Vendored
+2
-2
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2011, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* Copyright (c) 2009-2011, Redis Ltd.
|
||||
* Copyright (c) 2010-2011, Pieter Noordhuis <pcnoordhuis at gmail dot com>
|
||||
* Copyright (c) 2019, Redis Labs
|
||||
* Copyright (c) 2019, Redis Ltd.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
|
||||
Vendored
+1
-1
@@ -10,7 +10,7 @@
|
||||
*
|
||||
* ------------------------------------------------------------------------
|
||||
*
|
||||
* Copyright (c) 2010-2016, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* Copyright (c) 2010-2016, Redis Ltd.
|
||||
* Copyright (c) 2010-2013, Pieter Noordhuis <pcnoordhuis at gmail dot com>
|
||||
*
|
||||
* All rights reserved.
|
||||
|
||||
Vendored
+1
-1
@@ -7,7 +7,7 @@
|
||||
*
|
||||
* ------------------------------------------------------------------------
|
||||
*
|
||||
* Copyright (c) 2010-2014, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* Copyright (c) 2010-2014, Redis Ltd.
|
||||
* Copyright (c) 2010-2013, Pieter Noordhuis <pcnoordhuis at gmail dot com>
|
||||
*
|
||||
* All rights reserved.
|
||||
|
||||
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; }
|
||||
|
||||
Vendored
+3
-3
@@ -10,7 +10,7 @@
|
||||
#define LUACMSGPACK_NAME "cmsgpack"
|
||||
#define LUACMSGPACK_SAFE_NAME "cmsgpack_safe"
|
||||
#define LUACMSGPACK_VERSION "lua-cmsgpack 0.4.0"
|
||||
#define LUACMSGPACK_COPYRIGHT "Copyright (C) 2012, Salvatore Sanfilippo"
|
||||
#define LUACMSGPACK_COPYRIGHT "Copyright (C) 2012, Redis Ltd."
|
||||
#define LUACMSGPACK_DESCRIPTION "MessagePack C implementation for Lua"
|
||||
|
||||
/* Allows a preprocessor directive to override MAX_NESTING */
|
||||
@@ -39,7 +39,7 @@
|
||||
|
||||
/* =============================================================================
|
||||
* MessagePack implementation and bindings for Lua 5.1/5.2.
|
||||
* Copyright(C) 2012 Salvatore Sanfilippo <antirez@gmail.com>
|
||||
* Copyright(C) 2012 Redis Ltd.
|
||||
*
|
||||
* http://github.com/antirez/lua-cmsgpack
|
||||
*
|
||||
@@ -958,7 +958,7 @@ LUALIB_API int luaopen_cmsgpack_safe(lua_State *L) {
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Copyright (C) 2012 Salvatore Sanfilippo. All rights reserved.
|
||||
* Copyright (C) 2012 Redis Ltd. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
|
||||
@@ -56,4 +56,5 @@ $TCLSH tests/test_helper.tcl \
|
||||
--single unit/moduleapi/moduleauth \
|
||||
--single unit/moduleapi/rdbloadsave \
|
||||
--single unit/moduleapi/crash \
|
||||
--single unit/moduleapi/getchannels \
|
||||
"${@}"
|
||||
|
||||
+2
-2
@@ -120,7 +120,7 @@ sentinel monitor mymaster 127.0.0.1 6379 2
|
||||
# Sentinel instances, should be configured along the following lines:
|
||||
#
|
||||
# user sentinel-user >somepassword +client +subscribe +publish \
|
||||
# +ping +info +multi +slaveof +config +client +exec on
|
||||
# +ping +info +multi +slaveof +config +client +exec &__sentinel__:hello on
|
||||
|
||||
# sentinel down-after-milliseconds <master-name> <milliseconds>
|
||||
#
|
||||
@@ -355,4 +355,4 @@ SENTINEL announce-hostnames no
|
||||
# accept a -LOADING response after a primary has been rebooted, before failing
|
||||
# over.
|
||||
|
||||
SENTINEL primary-reboot-down-after-period myprimary 0
|
||||
SENTINEL primary-reboot-down-after-period mymaster 0
|
||||
|
||||
@@ -30,3 +30,4 @@ SortIncludes: false
|
||||
AllowAllParametersOfDeclarationOnNextLine: false
|
||||
BinPackParameters: false
|
||||
AlignAfterOpenBracket: Align
|
||||
InsertNewlineAtEOF: true
|
||||
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
# Valkey Makefile
|
||||
# Copyright (C) 2009 Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
# Copyright (C) 2009 Redis Ltd.
|
||||
# This file is released under the BSD license, see the COPYING file
|
||||
#
|
||||
# The Makefile composes the final FINAL_CFLAGS and FINAL_LDFLAGS using
|
||||
@@ -423,7 +423,7 @@ endif
|
||||
ENGINE_NAME=valkey
|
||||
SERVER_NAME=$(ENGINE_NAME)-server$(PROG_SUFFIX)
|
||||
ENGINE_SENTINEL_NAME=$(ENGINE_NAME)-sentinel$(PROG_SUFFIX)
|
||||
ENGINE_SERVER_OBJ=threads_mngr.o adlist.o quicklist.o ae.o anet.o dict.o kvstore.o server.o sds.o zmalloc.o lzf_c.o lzf_d.o pqsort.o zipmap.o sha1.o ziplist.o release.o io_threads.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 cluster_legacy.o cluster_slot_stats.o crc16.o endianconv.o slowlog.o eval.o bio.o rio.o rand.o memtest.o syscheck.o crcspeed.o crccombine.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
|
||||
ENGINE_SERVER_OBJ=threads_mngr.o adlist.o quicklist.o ae.o anet.o dict.o kvstore.o server.o sds.o zmalloc.o lzf_c.o lzf_d.o pqsort.o zipmap.o sha1.o ziplist.o release.o memory_prefetch.o io_threads.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 cluster_legacy.o cluster_slot_stats.o crc16.o endianconv.o slowlog.o eval.o bio.o rio.o rand.o memtest.o syscheck.o crcspeed.o crccombine.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
|
||||
ENGINE_CLI_NAME=$(ENGINE_NAME)-cli$(PROG_SUFFIX)
|
||||
ENGINE_CLI_OBJ=anet.o adlist.o dict.o valkey-cli.o zmalloc.o release.o ae.o serverassert.o crcspeed.o crccombine.o crc64.o siphash.o crc16.o monotonic.o cli_common.o mt19937-64.o strl.o cli_commands.o
|
||||
ENGINE_BENCHMARK_NAME=$(ENGINE_NAME)-benchmark$(PROG_SUFFIX)
|
||||
@@ -513,7 +513,7 @@ $(TLS_MODULE_NAME): $(SERVER_NAME)
|
||||
$(QUIET_CC)$(CC) -o $@ tls.c -shared -fPIC $(TLS_MODULE_CFLAGS) $(TLS_CLIENT_LIBS)
|
||||
|
||||
# valkey-rdma.so
|
||||
$(RDMA_MODULE_NAME): $(REDIS_SERVER_NAME)
|
||||
$(RDMA_MODULE_NAME): $(SERVER_NAME)
|
||||
$(QUIET_CC)$(CC) -o $@ rdma.c -shared -fPIC $(RDMA_MODULE_CFLAGS)
|
||||
|
||||
# valkey-cli
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* Copyright (c) 2018, Redis Ltd.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -1079,7 +1079,7 @@ int ACLSetSelector(aclSelector *selector, const char *op, size_t oplen) {
|
||||
flags |= ACL_READ_PERMISSION;
|
||||
} else if (toupper(op[offset]) == 'W' && !(flags & ACL_WRITE_PERMISSION)) {
|
||||
flags |= ACL_WRITE_PERMISSION;
|
||||
} else if (op[offset] == '~') {
|
||||
} else if (op[offset] == '~' && flags) {
|
||||
offset++;
|
||||
break;
|
||||
} else {
|
||||
@@ -2678,7 +2678,7 @@ void addACLLogEntry(client *c, int reason, int context, int argpos, sds username
|
||||
/* if we have a real client from the network, use it (could be missing on module timers) */
|
||||
client *realclient = server.current_client ? server.current_client : c;
|
||||
|
||||
le->cinfo = catClientInfoString(sdsempty(), realclient);
|
||||
le->cinfo = catClientInfoString(sdsempty(), realclient, 0);
|
||||
le->context = context;
|
||||
|
||||
/* Try to match this entry with past ones, to see if we can just
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
/* adlist.c - A generic doubly linked list implementation
|
||||
*
|
||||
* Copyright (c) 2006-2010, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* Copyright (c) 2006-2010, Redis Ltd.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
/* adlist.h - A generic doubly linked list implementation
|
||||
*
|
||||
* Copyright (c) 2006-2012, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* Copyright (c) 2006-2012, Redis Ltd.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* for the Jim's event-loop (Jim is a Tcl interpreter) but later translated
|
||||
* it in form of a library for easy reuse.
|
||||
*
|
||||
* Copyright (c) 2006-2010, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* Copyright (c) 2006-2010, Redis Ltd.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* for the Jim's event-loop (Jim is a Tcl interpreter) but later translated
|
||||
* it in form of a library for easy reuse.
|
||||
*
|
||||
* Copyright (c) 2006-2012, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* Copyright (c) 2006-2012, Redis Ltd.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
/* Linux epoll(2) based ae.c module
|
||||
*
|
||||
* Copyright (c) 2009-2012, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* Copyright (c) 2009-2012, Redis Ltd.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
/* Select()-based ae.c module.
|
||||
*
|
||||
* Copyright (c) 2009-2012, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* Copyright (c) 2009-2012, Redis Ltd.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
||||
+22
-5
@@ -1,6 +1,6 @@
|
||||
/* anet.c -- Basic TCP socket stuff made a bit less boring
|
||||
*
|
||||
* Copyright (c) 2006-2012, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* Copyright (c) 2006-2012, Redis Ltd.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -45,6 +45,7 @@
|
||||
#include <errno.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <grp.h>
|
||||
|
||||
#include "anet.h"
|
||||
#include "config.h"
|
||||
@@ -505,7 +506,7 @@ int anetTcpNonBlockBestEffortBindConnect(char *err, const char *addr, int port,
|
||||
return anetTcpGenericConnect(err, addr, port, source_addr, ANET_CONNECT_NONBLOCK | ANET_CONNECT_BE_BINDING);
|
||||
}
|
||||
|
||||
static int anetListen(char *err, int s, struct sockaddr *sa, socklen_t len, int backlog, mode_t perm) {
|
||||
static int anetListen(char *err, int s, struct sockaddr *sa, socklen_t len, int backlog, mode_t perm, char *group) {
|
||||
if (bind(s, sa, len) == -1) {
|
||||
anetSetError(err, "bind: %s", strerror(errno));
|
||||
close(s);
|
||||
@@ -514,6 +515,22 @@ static int anetListen(char *err, int s, struct sockaddr *sa, socklen_t len, int
|
||||
|
||||
if (sa->sa_family == AF_LOCAL && perm) chmod(((struct sockaddr_un *)sa)->sun_path, perm);
|
||||
|
||||
if (sa->sa_family == AF_LOCAL && group != NULL) {
|
||||
struct group *grp;
|
||||
if ((grp = getgrnam(group)) == NULL) {
|
||||
anetSetError(err, "getgrnam error for group '%s': %s", group, strerror(errno));
|
||||
close(s);
|
||||
return ANET_ERR;
|
||||
}
|
||||
|
||||
/* Owner of the socket remains same. */
|
||||
if (chown(((struct sockaddr_un *)sa)->sun_path, -1, grp->gr_gid) == -1) {
|
||||
anetSetError(err, "chown error for group '%s': %s", group, strerror(errno));
|
||||
close(s);
|
||||
return ANET_ERR;
|
||||
}
|
||||
}
|
||||
|
||||
if (listen(s, backlog) == -1) {
|
||||
anetSetError(err, "listen: %s", strerror(errno));
|
||||
close(s);
|
||||
@@ -553,7 +570,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, 0) == ANET_ERR) s = ANET_ERR;
|
||||
if (anetListen(err, s, p->ai_addr, p->ai_addrlen, backlog, 0, NULL) == ANET_ERR) s = ANET_ERR;
|
||||
goto end;
|
||||
}
|
||||
if (p == NULL) {
|
||||
@@ -577,7 +594,7 @@ int anetTcp6Server(char *err, int port, char *bindaddr, int backlog) {
|
||||
return _anetTcpServer(err, port, bindaddr, AF_INET6, backlog);
|
||||
}
|
||||
|
||||
int anetUnixServer(char *err, char *path, mode_t perm, int backlog) {
|
||||
int anetUnixServer(char *err, char *path, mode_t perm, int backlog, char *group) {
|
||||
int s;
|
||||
struct sockaddr_un sa;
|
||||
|
||||
@@ -593,7 +610,7 @@ int anetUnixServer(char *err, char *path, mode_t perm, int backlog) {
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
sa.sun_family = AF_LOCAL;
|
||||
valkey_strlcpy(sa.sun_path, path, sizeof(sa.sun_path));
|
||||
if (anetListen(err, s, (struct sockaddr *)&sa, sizeof(sa), backlog, perm) == ANET_ERR) return ANET_ERR;
|
||||
if (anetListen(err, s, (struct sockaddr *)&sa, sizeof(sa), backlog, perm, group) == ANET_ERR) return ANET_ERR;
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
/* anet.c -- Basic TCP socket stuff made a bit less boring
|
||||
*
|
||||
* Copyright (c) 2006-2012, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* Copyright (c) 2006-2012, Redis Ltd.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -56,7 +56,7 @@ int anetTcpNonBlockBestEffortBindConnect(char *err, const char *addr, int port,
|
||||
int anetResolve(char *err, char *host, char *ipbuf, size_t ipbuf_len, int flags);
|
||||
int anetTcpServer(char *err, int port, char *bindaddr, int backlog);
|
||||
int anetTcp6Server(char *err, int port, char *bindaddr, int backlog);
|
||||
int anetUnixServer(char *err, char *path, mode_t perm, int backlog);
|
||||
int anetUnixServer(char *err, char *path, mode_t perm, int backlog, char *group);
|
||||
int anetTcpAccept(char *err, int serversock, char *ip, size_t ip_len, int *port);
|
||||
int anetUnixAccept(char *err, int serversock);
|
||||
int anetNonBlock(char *err, int fd);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2012, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* Copyright (c) 2009-2012, Redis Ltd.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -423,7 +423,7 @@ void aofManifestFreeAndUpdate(aofManifest *am) {
|
||||
* appendonly.aof.1.base.aof (server.aof_use_rdb_preamble is no)
|
||||
* appendonly.aof.1.base.rdb (server.aof_use_rdb_preamble is yes)
|
||||
*/
|
||||
sds getNewBaseFileNameAndMarkPreAsHistory(aofManifest *am) {
|
||||
sds getNewBaseFileNameAndMarkPreAsHistory(aofManifest *am, int aof_use_rdb_preamble) {
|
||||
serverAssert(am != NULL);
|
||||
if (am->base_aof_info) {
|
||||
serverAssert(am->base_aof_info->file_type == AOF_FILE_TYPE_BASE);
|
||||
@@ -431,7 +431,7 @@ sds getNewBaseFileNameAndMarkPreAsHistory(aofManifest *am) {
|
||||
listAddNodeHead(am->history_aof_list, am->base_aof_info);
|
||||
}
|
||||
|
||||
char *format_suffix = server.aof_use_rdb_preamble ? RDB_FORMAT_SUFFIX : AOF_FORMAT_SUFFIX;
|
||||
char *format_suffix = aof_use_rdb_preamble ? RDB_FORMAT_SUFFIX : AOF_FORMAT_SUFFIX;
|
||||
|
||||
aofInfo *ai = aofInfoCreate();
|
||||
ai->file_name = sdscatprintf(sdsempty(), "%s.%lld%s%s", server.aof_filename, ++am->curr_base_file_seq,
|
||||
@@ -712,7 +712,7 @@ void aofOpenIfNeededOnServerStart(void) {
|
||||
/* If we start with an empty dataset, we will force create a BASE file. */
|
||||
size_t incr_aof_len = listLength(server.aof_manifest->incr_aof_list);
|
||||
if (!server.aof_manifest->base_aof_info && !incr_aof_len) {
|
||||
sds base_name = getNewBaseFileNameAndMarkPreAsHistory(server.aof_manifest);
|
||||
sds base_name = getNewBaseFileNameAndMarkPreAsHistory(server.aof_manifest, server.aof_use_rdb_preamble);
|
||||
sds base_filepath = makePath(server.aof_dirname, base_name);
|
||||
if (rewriteAppendOnlyFile(base_filepath) != C_OK) {
|
||||
exit(1);
|
||||
@@ -1371,6 +1371,7 @@ struct client *createAOFClient(void) {
|
||||
*/
|
||||
c->raw_flag = 0;
|
||||
c->flag.deny_blocking = 1;
|
||||
c->flag.fake = 1;
|
||||
|
||||
/* We set the fake client as a replica waiting for the synchronization
|
||||
* so that the server will not try to send replies to this client. */
|
||||
@@ -2445,6 +2446,7 @@ int rewriteAppendOnlyFileBackground(void) {
|
||||
serverLog(LL_NOTICE, "Background append only file rewriting started by pid %ld", (long)childpid);
|
||||
server.aof_rewrite_scheduled = 0;
|
||||
server.aof_rewrite_time_start = time(NULL);
|
||||
server.aof_rewrite_use_rdb_preamble = server.aof_use_rdb_preamble;
|
||||
return C_OK;
|
||||
}
|
||||
return C_OK; /* unreached */
|
||||
@@ -2557,7 +2559,7 @@ void backgroundRewriteDoneHandler(int exitcode, int bysignal) {
|
||||
|
||||
/* Get a new BASE file name and mark the previous (if we have)
|
||||
* as the HISTORY type. */
|
||||
sds new_base_filename = getNewBaseFileNameAndMarkPreAsHistory(temp_am);
|
||||
sds new_base_filename = getNewBaseFileNameAndMarkPreAsHistory(temp_am, server.aof_rewrite_use_rdb_preamble);
|
||||
serverAssert(new_base_filename != NULL);
|
||||
new_base_filepath = makePath(server.aof_dirname, new_base_filename);
|
||||
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2012, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* Copyright (c) 2009-2012, Redis Ltd.
|
||||
* Copyright (c) 2024, Valkey contributors
|
||||
* All rights reserved.
|
||||
*
|
||||
|
||||
+1
-1
@@ -45,7 +45,7 @@
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* Copyright (c) 2015, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* Copyright (c) 2015, Redis Ltd.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* Copyright (c) 2009-2012, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* Copyright (c) 2009-2012, Redis Ltd.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2012, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* Copyright (c) 2009-2012, Redis Ltd.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
/* Bit operations.
|
||||
*
|
||||
* Copyright (c) 2009-2012, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* Copyright (c) 2009-2012, Redis Ltd.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
||||
+15
-5
@@ -1,6 +1,6 @@
|
||||
/* blocked.c - generic support for blocking operations like BLPOP & WAIT.
|
||||
*
|
||||
* Copyright (c) 2009-2012, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* Copyright (c) 2009-2012, Redis Ltd.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -76,10 +76,13 @@ static void releaseBlockedEntry(client *c, dictEntry *de, int remove_key);
|
||||
void initClientBlockingState(client *c) {
|
||||
c->bstate.btype = BLOCKED_NONE;
|
||||
c->bstate.timeout = 0;
|
||||
c->bstate.unblock_on_nokey = 0;
|
||||
c->bstate.keys = dictCreate(&objectKeyHeapPointerValueDictType);
|
||||
c->bstate.numreplicas = 0;
|
||||
c->bstate.numlocal = 0;
|
||||
c->bstate.reploffset = 0;
|
||||
c->bstate.unblock_on_nokey = 0;
|
||||
c->bstate.generic_blocked_list_node = NULL;
|
||||
c->bstate.module_blocked_handle = NULL;
|
||||
c->bstate.async_rm_call_handle = NULL;
|
||||
}
|
||||
|
||||
@@ -191,8 +194,9 @@ void unblockClient(client *c, int queue_for_reprocessing) {
|
||||
if (moduleClientIsBlockedOnKeys(c)) unblockClientWaitingData(c);
|
||||
unblockClientFromModule(c);
|
||||
} else if (c->bstate.btype == BLOCKED_POSTPONE) {
|
||||
listDelNode(server.postponed_clients, c->postponed_list_node);
|
||||
c->postponed_list_node = NULL;
|
||||
serverAssert(c->bstate.postponed_list_node);
|
||||
listDelNode(server.postponed_clients, c->bstate.postponed_list_node);
|
||||
c->bstate.postponed_list_node = NULL;
|
||||
} else if (c->bstate.btype == BLOCKED_SHUTDOWN) {
|
||||
/* No special cleanup. */
|
||||
} else {
|
||||
@@ -595,6 +599,11 @@ void blockClientForReplicaAck(client *c, mstime_t timeout, long long offset, lon
|
||||
c->bstate.numreplicas = numreplicas;
|
||||
c->bstate.numlocal = numlocal;
|
||||
listAddNodeHead(server.clients_waiting_acks, c);
|
||||
/* Note that we remember the linked list node where the client is stored,
|
||||
* this way removing the client in unblockClientWaitingReplicas() will not
|
||||
* require a linear scan, but just a constant time operation. */
|
||||
serverAssert(c->bstate.client_waiting_acks_list_node == NULL);
|
||||
c->bstate.client_waiting_acks_list_node = listFirst(server.clients_waiting_acks);
|
||||
blockClient(c, BLOCKED_WAIT);
|
||||
}
|
||||
|
||||
@@ -605,7 +614,8 @@ void blockPostponeClient(client *c) {
|
||||
c->bstate.timeout = 0;
|
||||
blockClient(c, BLOCKED_POSTPONE);
|
||||
listAddNodeTail(server.postponed_clients, c);
|
||||
c->postponed_list_node = listLast(server.postponed_clients);
|
||||
serverAssert(c->bstate.postponed_list_node == NULL);
|
||||
c->bstate.postponed_list_node = listLast(server.postponed_clients);
|
||||
/* Mark this client to execute its command */
|
||||
c->flag.pending_command = 1;
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2021, Redis Labs Ltd.
|
||||
* Copyright (c) 2009-2021, Redis Ltd.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2021, Redis Labs Ltd.
|
||||
* Copyright (c) 2009-2021, Redis Ltd.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* Copyright (c) 2016, Redis Ltd.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
/* CLI (command line interface) common methods
|
||||
*
|
||||
* Copyright (c) 2020, Redis Labs
|
||||
* Copyright (c) 2020, Redis Ltd.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
||||
+16
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2012, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* Copyright (c) 2009-2012, Redis Ltd.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -262,6 +262,8 @@ void restoreCommand(client *c) {
|
||||
if (ttl && !absttl) ttl += commandTimeSnapshot();
|
||||
if (ttl && checkAlreadyExpired(ttl)) {
|
||||
if (deleted) {
|
||||
/* Here we don't use deleteExpiredKeyFromOverwriteAndPropagate because
|
||||
* strictly speaking, the `delete` is triggered by the `replace`. */
|
||||
robj *aux = server.lazyfree_lazy_server_del ? shared.unlink : shared.del;
|
||||
rewriteClientCommandVector(c, 2, aux, key);
|
||||
signalModifiedKey(c, c->db, key);
|
||||
@@ -748,7 +750,16 @@ int verifyClusterNodeId(const char *name, int length) {
|
||||
}
|
||||
|
||||
int isValidAuxChar(int c) {
|
||||
return isalnum(c) || (strchr("!#$%&()*+.:;<>?@[]^{|}~", c) == NULL);
|
||||
/* Return true if the character is alphanumeric */
|
||||
if (isalnum(c)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* List of invalid characters */
|
||||
static const char *invalid_charset = "!#$%&()*+;<>?@[]^{|}~";
|
||||
|
||||
/* Return true if the character is NOT in the invalid charset */
|
||||
return strchr(invalid_charset, c) == NULL;
|
||||
}
|
||||
|
||||
int isValidAuxString(char *s, unsigned int length) {
|
||||
@@ -820,6 +831,8 @@ void clusterCommandHelp(client *c) {
|
||||
"SLOTS",
|
||||
" Return information about slots range mappings. Each range is made of:",
|
||||
" start, end, primary and replicas IP addresses, ports and ids",
|
||||
"SLOT-STATS",
|
||||
" Return an array of slot usage statistics for slots assigned to the current node.",
|
||||
"SHARDS",
|
||||
" Return information about slot range mappings and the nodes associated with them.",
|
||||
NULL};
|
||||
@@ -1415,7 +1428,7 @@ void clusterCommandSlots(client *c) {
|
||||
* ... continued until done
|
||||
*/
|
||||
int conn_type = 0;
|
||||
if (connIsTLS(c->conn)) conn_type |= CACHE_CONN_TYPE_TLS;
|
||||
if (shouldReturnTlsInfo()) conn_type |= CACHE_CONN_TYPE_TLS;
|
||||
if (isClientConnIpV6(c)) conn_type |= CACHE_CONN_TYPE_IPv6;
|
||||
if (c->resp == 3) conn_type |= CACHE_CONN_TYPE_RESP3;
|
||||
|
||||
|
||||
+1
-1
@@ -39,6 +39,7 @@ void clusterInitLast(void);
|
||||
void clusterCron(void);
|
||||
void clusterBeforeSleep(void);
|
||||
int verifyClusterConfigWithData(void);
|
||||
void clusterHandleServerShutdown(void);
|
||||
|
||||
int clusterSendModuleMessageToTarget(const char *target,
|
||||
uint64_t module_id,
|
||||
@@ -83,7 +84,6 @@ int getNodeDefaultClientPort(clusterNode *n);
|
||||
clusterNode *getMyClusterNode(void);
|
||||
int getClusterSize(void);
|
||||
int getMyShardSlotCount(void);
|
||||
int handleDebugClusterCommand(client *c);
|
||||
int clusterNodePending(clusterNode *node);
|
||||
int clusterNodeIsPrimary(clusterNode *n);
|
||||
char **getClusterNodesList(size_t *numnodes);
|
||||
|
||||
+168
-64
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2012, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* Copyright (c) 2009-2012, Redis Ltd.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -62,14 +62,13 @@ void clusterSendPing(clusterLink *link, int type);
|
||||
void clusterSendFail(char *nodename);
|
||||
void clusterSendFailoverAuthIfNeeded(clusterNode *node, clusterMsg *request);
|
||||
void clusterUpdateState(void);
|
||||
int clusterNodeCoversSlot(clusterNode *n, int slot);
|
||||
list *clusterGetNodesInMyShard(clusterNode *node);
|
||||
int clusterNodeAddReplica(clusterNode *primary, clusterNode *replica);
|
||||
int clusterAddSlot(clusterNode *n, int slot);
|
||||
int clusterDelSlot(int slot);
|
||||
int clusterDelNodeSlots(clusterNode *node);
|
||||
int clusterNodeSetSlotBit(clusterNode *n, int slot);
|
||||
void clusterSetPrimary(clusterNode *n, int closeSlots);
|
||||
static void clusterSetPrimary(clusterNode *n, int closeSlots, int full_sync_required);
|
||||
void clusterHandleReplicaFailover(void);
|
||||
void clusterHandleReplicaMigration(int max_replicas);
|
||||
int bitmapTestBit(unsigned char *bitmap, int pos);
|
||||
@@ -93,7 +92,6 @@ void moduleCallClusterReceivers(const char *sender_id,
|
||||
uint32_t len);
|
||||
const char *clusterGetMessageTypeString(int type);
|
||||
void removeChannelsInSlot(unsigned int slot);
|
||||
unsigned int countKeysInSlot(unsigned int hashslot);
|
||||
unsigned int countChannelsInSlot(unsigned int hashslot);
|
||||
unsigned int delKeysInSlot(unsigned int hashslot);
|
||||
void clusterAddNodeToShard(const char *shard_id, clusterNode *node);
|
||||
@@ -1193,6 +1191,28 @@ void clusterInitLast(void) {
|
||||
}
|
||||
}
|
||||
|
||||
/* Called when a cluster node receives SHUTDOWN. */
|
||||
void clusterHandleServerShutdown(void) {
|
||||
/* The error logs have been logged in the save function if the save fails. */
|
||||
serverLog(LL_NOTICE, "Saving the cluster configuration file before exiting.");
|
||||
clusterSaveConfig(1);
|
||||
|
||||
#if !defined(__sun)
|
||||
/* Unlock the cluster config file before shutdown, see clusterLockConfig.
|
||||
*
|
||||
* This is needed if you shutdown a very large server process, it will take
|
||||
* a while for the OS to release resources and unlock the cluster configuration
|
||||
* file. Therefore, if we immediately try to restart the server process, it
|
||||
* may not be able to acquire the lock on the cluster configuration file and
|
||||
* fail to start. We explicitly releases the lock on the cluster configuration
|
||||
* file on shutdown, rather than relying on the OS to release the lock, which
|
||||
* is a cleaner and safer way to release acquired resources. */
|
||||
if (server.cluster_config_file_lock_fd != -1) {
|
||||
flock(server.cluster_config_file_lock_fd, LOCK_UN | LOCK_NB);
|
||||
}
|
||||
#endif /* __sun */
|
||||
}
|
||||
|
||||
/* Reset a node performing a soft or hard reset:
|
||||
*
|
||||
* 1) All other nodes are forgotten.
|
||||
@@ -2277,6 +2297,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 (nodeIsReplica(myself) && myself->replicaof == node)
|
||||
replicationSetPrimary(node->ip, getNodeDefaultReplicationPort(node), 0);
|
||||
}
|
||||
} else if (!node) {
|
||||
/* If it's not in NOADDR state and we don't have it, we
|
||||
@@ -2370,7 +2407,7 @@ int nodeUpdateAddressIfNeeded(clusterNode *node, clusterLink *link, clusterMsg *
|
||||
/* Check if this is our primary and we have to change the
|
||||
* replication target as well. */
|
||||
if (nodeIsReplica(myself) && myself->replicaof == node)
|
||||
replicationSetPrimary(node->ip, getNodeDefaultReplicationPort(node));
|
||||
replicationSetPrimary(node->ip, getNodeDefaultReplicationPort(node), 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -2432,6 +2469,9 @@ void clusterUpdateSlotsConfigWith(clusterNode *sender, uint64_t senderConfigEpoc
|
||||
return;
|
||||
}
|
||||
|
||||
/* Sender and myself in the same shard? */
|
||||
int are_in_same_shard = areInSameShard(sender, myself);
|
||||
|
||||
for (j = 0; j < CLUSTER_SLOTS; j++) {
|
||||
if (bitmapTestBit(slots, j)) {
|
||||
sender_slots++;
|
||||
@@ -2474,7 +2514,7 @@ void clusterUpdateSlotsConfigWith(clusterNode *sender, uint64_t senderConfigEpoc
|
||||
* the same shard and we should retain the migrating_slots_to state
|
||||
* for the slot in question */
|
||||
if (server.cluster->migrating_slots_to[j] != NULL) {
|
||||
if (!areInSameShard(sender, myself)) {
|
||||
if (!are_in_same_shard) {
|
||||
serverLog(LL_NOTICE, "Slot %d is no longer being migrated to node %.40s (%s) in shard %.40s.",
|
||||
j, server.cluster->migrating_slots_to[j]->name,
|
||||
server.cluster->migrating_slots_to[j]->human_nodename,
|
||||
@@ -2595,7 +2635,7 @@ void clusterUpdateSlotsConfigWith(clusterNode *sender, uint64_t senderConfigEpoc
|
||||
* the new primary if my current config epoch is lower than the
|
||||
* sender's. */
|
||||
if (!new_primary && myself->replicaof != sender && sender_slots == 0 && myself->numslots == 0 &&
|
||||
nodeEpoch(myself) < senderConfigEpoch && areInSameShard(sender, myself)) {
|
||||
nodeEpoch(myself) < senderConfigEpoch && are_in_same_shard) {
|
||||
new_primary = sender;
|
||||
}
|
||||
|
||||
@@ -2619,16 +2659,18 @@ void clusterUpdateSlotsConfigWith(clusterNode *sender, uint64_t senderConfigEpoc
|
||||
* sender. In this case we don't reconfigure ourselves as a replica
|
||||
* of the sender. */
|
||||
if (new_primary && cur_primary->numslots == 0) {
|
||||
if (server.cluster_allow_replica_migration || areInSameShard(sender, myself)) {
|
||||
if (server.cluster_allow_replica_migration || are_in_same_shard) {
|
||||
serverLog(LL_NOTICE,
|
||||
"Configuration change detected. Reconfiguring myself "
|
||||
"as a replica of node %.40s (%s) in shard %.40s",
|
||||
sender->name, sender->human_nodename, sender->shard_id);
|
||||
/* Don't clear the migrating/importing states if this is a replica that
|
||||
* just gets promoted to the new primary in the shard. */
|
||||
clusterSetPrimary(sender, !areInSameShard(sender, myself));
|
||||
* just gets promoted to the new primary in the shard.
|
||||
*
|
||||
* If the sender and myself are in the same shard, try psync. */
|
||||
clusterSetPrimary(sender, !are_in_same_shard, !are_in_same_shard);
|
||||
clusterDoBeforeSleep(CLUSTER_TODO_SAVE_CONFIG | CLUSTER_TODO_UPDATE_STATE | CLUSTER_TODO_FSYNC_CONFIG);
|
||||
} else if ((sender_slots >= migrated_our_slots) && !areInSameShard(sender, myself)) {
|
||||
} else if (nodeIsPrimary(myself) && (sender_slots >= migrated_our_slots) && !are_in_same_shard) {
|
||||
/* When all our slots are lost to the sender and the sender belongs to
|
||||
* a different shard, this is likely due to a client triggered slot
|
||||
* migration. Don't reconfigure this node to migrate to the new shard
|
||||
@@ -3136,7 +3178,10 @@ int clusterProcessPacket(clusterLink *link) {
|
||||
/* Add this node if it is new for us and the msg type is MEET.
|
||||
* In this stage we don't try to add the node with the right
|
||||
* flags, replicaof pointer, and so forth, as this details will be
|
||||
* resolved when we'll receive PONGs from the node. */
|
||||
* resolved when we'll receive PONGs from the node. The exception
|
||||
* to this is the flag that indicates extensions are supported, as
|
||||
* we want to send extensions right away in the return PONG in order
|
||||
* to reduce the amount of time needed to stabilize the shard ID. */
|
||||
if (!sender && type == CLUSTERMSG_TYPE_MEET) {
|
||||
clusterNode *node;
|
||||
|
||||
@@ -3144,6 +3189,10 @@ int clusterProcessPacket(clusterLink *link) {
|
||||
serverAssert(nodeIp2String(node->ip, link, hdr->myip) == C_OK);
|
||||
getClientPortFromClusterMsg(hdr, &node->tls_port, &node->tcp_port);
|
||||
node->cport = ntohs(hdr->cport);
|
||||
if (hdr->mflags[0] & CLUSTERMSG_FLAG0_EXT_DATA) {
|
||||
node->flags |= CLUSTER_NODE_EXTENSIONS_SUPPORTED;
|
||||
}
|
||||
setClusterNodeToInboundClusterLink(node, link);
|
||||
clusterAddNode(node);
|
||||
clusterDoBeforeSleep(CLUSTER_TODO_SAVE_CONFIG);
|
||||
}
|
||||
@@ -3309,10 +3358,43 @@ int clusterProcessPacket(clusterLink *link) {
|
||||
if (sender->replicaof) clusterNodeRemoveReplica(sender->replicaof, sender);
|
||||
serverLog(LL_NOTICE, "Node %.40s (%s) is now a replica of node %.40s (%s) in shard %.40s",
|
||||
sender->name, sender->human_nodename, sender_claimed_primary->name,
|
||||
sender_claimed_primary->human_nodename, sender->shard_id);
|
||||
sender_claimed_primary->human_nodename, sender_claimed_primary->shard_id);
|
||||
clusterNodeAddReplica(sender_claimed_primary, sender);
|
||||
sender->replicaof = sender_claimed_primary;
|
||||
|
||||
/* The chain reduction logic requires correctly establishing the replication relationship.
|
||||
* A key decision when designating a new primary for 'myself' is determining whether
|
||||
* 'myself' and the new primary belong to the same shard, which would imply shared
|
||||
* replication history and allow a safe partial synchronization (psync).
|
||||
*
|
||||
* This decision hinges on the shard_id, a per-node property that helps verify if the
|
||||
* two nodes share the same replication history. It's critical not to update myself's
|
||||
* shard_id prematurely during this process. Doing so could incorrectly associate
|
||||
* 'myself' with the sender's shard_id, leading the subsequent clusterSetPrimary call
|
||||
* to falsely assume that 'myself' and the new primary have been in the same shard.
|
||||
* This mistake could result in data loss by incorrectly permitting a psync.
|
||||
*
|
||||
* Therefore, it's essential to delay any shard_id updates until after the replication
|
||||
* relationship has been properly established and verified. */
|
||||
if (myself->replicaof && myself->replicaof->replicaof && myself->replicaof->replicaof != myself) {
|
||||
/* Safeguard against sub-replicas.
|
||||
*
|
||||
* A replica's primary can turn itself into a replica if its last slot
|
||||
* is removed. If no other node takes over the slot, there is nothing
|
||||
* else to trigger replica migration. In this case, they are not in the
|
||||
* same shard, so a full sync is required.
|
||||
*
|
||||
* Or a replica's primary can turn itself into a replica of its other
|
||||
* replica during a failover. In this case, they are in the same shard,
|
||||
* so we can try a psync. */
|
||||
serverLog(LL_NOTICE, "I'm a sub-replica! Reconfiguring myself as a replica of %.40s from %.40s",
|
||||
myself->replicaof->replicaof->name, myself->replicaof->name);
|
||||
clusterSetPrimary(myself->replicaof->replicaof, 1,
|
||||
!areInSameShard(myself->replicaof->replicaof, myself));
|
||||
clusterDoBeforeSleep(CLUSTER_TODO_SAVE_CONFIG | CLUSTER_TODO_UPDATE_STATE |
|
||||
CLUSTER_TODO_FSYNC_CONFIG);
|
||||
}
|
||||
|
||||
/* Update the shard_id when a replica is connected to its
|
||||
* primary in the very first time. */
|
||||
updateShardId(sender, sender_claimed_primary->shard_id);
|
||||
@@ -3380,18 +3462,6 @@ int clusterProcessPacket(clusterLink *link) {
|
||||
}
|
||||
}
|
||||
|
||||
/* Explicitly check for a replication loop before attempting the replication
|
||||
* chain folding logic. */
|
||||
if (myself->replicaof && myself->replicaof->replicaof && myself->replicaof->replicaof != myself) {
|
||||
/* Safeguard against sub-replicas. A replica's primary can turn itself
|
||||
* into a replica if its last slot is removed. If no other node takes
|
||||
* over the slot, there is nothing else to trigger replica migration. */
|
||||
serverLog(LL_NOTICE, "I'm a sub-replica! Reconfiguring myself as a replica of %.40s from %.40s",
|
||||
myself->replicaof->replicaof->name, myself->replicaof->name);
|
||||
clusterSetPrimary(myself->replicaof->replicaof, 1);
|
||||
clusterDoBeforeSleep(CLUSTER_TODO_SAVE_CONFIG | CLUSTER_TODO_UPDATE_STATE | CLUSTER_TODO_FSYNC_CONFIG);
|
||||
}
|
||||
|
||||
/* If our config epoch collides with the sender's try to fix
|
||||
* the problem. */
|
||||
if (sender && nodeIsPrimary(myself) && nodeIsPrimary(sender) &&
|
||||
@@ -4250,14 +4320,14 @@ void clusterSendFailoverAuthIfNeeded(clusterNode *node, clusterMsg *request) {
|
||||
* with CLUSTERMSG_FLAG0_FORCEACK (manual failover). */
|
||||
if (clusterNodeIsPrimary(node) || primary == NULL || (!nodeFailed(primary) && !force_ack)) {
|
||||
if (clusterNodeIsPrimary(node)) {
|
||||
serverLog(LL_WARNING, "Failover auth denied to %.40s (%s): it is a primary node", node->name,
|
||||
node->human_nodename);
|
||||
serverLog(LL_WARNING, "Failover auth denied to %.40s (%s) for epoch %llu: it is a primary node", node->name,
|
||||
node->human_nodename, (unsigned long long)requestCurrentEpoch);
|
||||
} else if (primary == NULL) {
|
||||
serverLog(LL_WARNING, "Failover auth denied to %.40s (%s): I don't know its primary", node->name,
|
||||
node->human_nodename);
|
||||
serverLog(LL_WARNING, "Failover auth denied to %.40s (%s) for epoch %llu: I don't know its primary",
|
||||
node->name, node->human_nodename, (unsigned long long)requestCurrentEpoch);
|
||||
} else if (!nodeFailed(primary)) {
|
||||
serverLog(LL_WARNING, "Failover auth denied to %.40s (%s): its primary is up", node->name,
|
||||
node->human_nodename);
|
||||
serverLog(LL_WARNING, "Failover auth denied to %.40s (%s) for epoch %llu: its primary is up", node->name,
|
||||
node->human_nodename, (unsigned long long)requestCurrentEpoch);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -4356,9 +4426,6 @@ int clusterGetReplicaRank(void) {
|
||||
* 2) Also, the log is emitted again if the primary is still down and
|
||||
* the reason for not failing over is still the same, but more than
|
||||
* CLUSTER_CANT_FAILOVER_RELOG_PERIOD seconds elapsed.
|
||||
* 3) Finally, the function only logs if the replica is down for more than
|
||||
* five seconds + NODE_TIMEOUT. This way nothing is logged when a
|
||||
* failover starts in a reasonable time.
|
||||
*
|
||||
* The function is called with the reason why the replica can't failover
|
||||
* which is one of the integer macros CLUSTER_CANT_FAILOVER_*.
|
||||
@@ -4367,7 +4434,6 @@ int clusterGetReplicaRank(void) {
|
||||
void clusterLogCantFailover(int reason) {
|
||||
char *msg;
|
||||
static time_t lastlog_time = 0;
|
||||
mstime_t nolog_fail_time = server.cluster_node_timeout + 5000;
|
||||
|
||||
/* Don't log if we have the same reason for some time. */
|
||||
if (reason == server.cluster->cant_failover_reason &&
|
||||
@@ -4376,13 +4442,6 @@ void clusterLogCantFailover(int reason) {
|
||||
|
||||
server.cluster->cant_failover_reason = reason;
|
||||
|
||||
/* We also don't emit any log if the primary failed no long ago, the
|
||||
* goal of this function is to log replicas in a stalled condition for
|
||||
* a long time. */
|
||||
if (myself->replicaof && nodeFailed(myself->replicaof) &&
|
||||
(mstime() - myself->replicaof->fail_time) < nolog_fail_time)
|
||||
return;
|
||||
|
||||
switch (reason) {
|
||||
case CLUSTER_CANT_FAILOVER_DATA_AGE:
|
||||
msg = "Disconnected from primary for longer than allowed. "
|
||||
@@ -4703,7 +4762,9 @@ void clusterHandleReplicaMigration(int max_replicas) {
|
||||
!(server.cluster_module_flags & CLUSTER_MODULE_FLAG_NO_FAILOVER)) {
|
||||
serverLog(LL_NOTICE, "Migrating to orphaned primary %.40s (%s) in shard %.40s", target->name,
|
||||
target->human_nodename, target->shard_id);
|
||||
clusterSetPrimary(target, 1);
|
||||
/* We are migrating to a different shard that has a completely different
|
||||
* replication history, so a full sync is required. */
|
||||
clusterSetPrimary(target, 1, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5016,7 +5077,7 @@ void clusterCron(void) {
|
||||
* enable it if we know the address of our primary and it appears to
|
||||
* be up. */
|
||||
if (nodeIsReplica(myself) && server.primary_host == NULL && myself->replicaof && nodeHasAddr(myself->replicaof)) {
|
||||
replicationSetPrimary(myself->replicaof->ip, getNodeDefaultReplicationPort(myself->replicaof));
|
||||
replicationSetPrimary(myself->replicaof->ip, getNodeDefaultReplicationPort(myself->replicaof), 0);
|
||||
}
|
||||
|
||||
/* Abort a manual failover if the timeout is reached. */
|
||||
@@ -5409,7 +5470,7 @@ static inline void removeAllNotOwnedShardChannelSubscriptions(void) {
|
||||
|
||||
/* Set the specified node 'n' as primary for this node.
|
||||
* If this node is currently a primary, it is turned into a replica. */
|
||||
void clusterSetPrimary(clusterNode *n, int closeSlots) {
|
||||
static void clusterSetPrimary(clusterNode *n, int closeSlots, int full_sync_required) {
|
||||
serverAssert(n != myself);
|
||||
serverAssert(myself->numslots == 0);
|
||||
|
||||
@@ -5423,7 +5484,7 @@ void clusterSetPrimary(clusterNode *n, int closeSlots) {
|
||||
myself->replicaof = n;
|
||||
updateShardId(myself, n->shard_id);
|
||||
clusterNodeAddReplica(n, myself);
|
||||
replicationSetPrimary(n->ip, getNodeDefaultReplicationPort(n));
|
||||
replicationSetPrimary(n->ip, getNodeDefaultReplicationPort(n), full_sync_required);
|
||||
removeAllNotOwnedShardChannelSubscriptions();
|
||||
resetManualFailover();
|
||||
|
||||
@@ -6163,6 +6224,9 @@ int clusterParseSetSlotCommand(client *c, int *slot_out, clusterNode **node_out,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If 'myself' is a replica, 'c' must be the primary client. */
|
||||
serverAssert(!nodeIsReplica(myself) || c == server.primary);
|
||||
|
||||
if ((slot = getSlotOrReply(c, c->argv[2])) == -1) return 0;
|
||||
|
||||
if (!strcasecmp(c->argv[3]->ptr, "migrating") && c->argc >= 5) {
|
||||
@@ -6270,7 +6334,7 @@ void clusterCommandSetSlot(client *c) {
|
||||
* To mitigate this issue, the following order needs to be enforced for slot
|
||||
* migration finalization such that the replicas finalize the slot ownership
|
||||
* before the primary:
|
||||
. *
|
||||
*
|
||||
* 1. Client C issues SETSLOT n NODE B against node B.
|
||||
* 2. Primary B replicates `SETSLOT n NODE B` to all of its replicas (e.g., B', B'').
|
||||
* 3. Upon replication completion, primary B executes `SETSLOT n NODE B` and
|
||||
@@ -6290,17 +6354,25 @@ void clusterCommandSetSlot(client *c) {
|
||||
* non-replicated behavior.*/
|
||||
listIter li;
|
||||
listNode *ln;
|
||||
int legacy_replica_found = 0;
|
||||
int num_eligible_replicas = 0;
|
||||
listRewind(server.replicas, &li);
|
||||
while ((ln = listNext(&li))) {
|
||||
client *r = ln->value;
|
||||
if (r->replica_version < 0x702ff /* 7.2.255 */) {
|
||||
legacy_replica_found++;
|
||||
break;
|
||||
|
||||
/* We think that when the command comes in, the primary only needs to
|
||||
* wait for the online replicas. The admin can easily check if there
|
||||
* are replicas that are down for an extended period of time. If they
|
||||
* decide to move forward anyways, we should not block it. If a replica
|
||||
* failed right before the replication and was not included in the
|
||||
* replication, it would also unlikely win the election.
|
||||
*
|
||||
* And 0x702ff is 7.2.255, we only support new versions in this case. */
|
||||
if (r->repl_state == REPLICA_STATE_ONLINE && r->replica_version > 0x702ff) {
|
||||
num_eligible_replicas++;
|
||||
}
|
||||
}
|
||||
|
||||
if (!legacy_replica_found) {
|
||||
if (num_eligible_replicas != 0) {
|
||||
forceCommandPropagation(c, PROPAGATE_REPL);
|
||||
/* We are a primary and this is the first time we see this `SETSLOT`
|
||||
* command. Force-replicate the command to all of our replicas
|
||||
@@ -6310,7 +6382,7 @@ void clusterCommandSetSlot(client *c) {
|
||||
* 2. The repl offset target is set to the primary's current repl offset + 1.
|
||||
* There is no concern of partial replication because replicas always
|
||||
* ack the repl offset at the command boundary. */
|
||||
blockClientForReplicaAck(c, timeout_ms, server.primary_repl_offset + 1, myself->num_replicas, 0);
|
||||
blockClientForReplicaAck(c, timeout_ms, server.primary_repl_offset + 1, num_eligible_replicas, 0);
|
||||
/* Mark client as pending command for execution after replication to replicas. */
|
||||
c->flag.pending_command = 1;
|
||||
replicationRequestAckFromReplicas();
|
||||
@@ -6319,7 +6391,7 @@ void clusterCommandSetSlot(client *c) {
|
||||
}
|
||||
|
||||
/* Slot states have been updated on the compatible replicas (if any).
|
||||
* Now exuecte the command on the primary. */
|
||||
* Now execute the command on the primary. */
|
||||
if (!strcasecmp(c->argv[3]->ptr, "migrating")) {
|
||||
serverLog(LL_NOTICE, "Migrating slot %d to node %.40s (%s)", slot, n->name, n->human_nodename);
|
||||
server.cluster->migrating_slots_to[slot] = n;
|
||||
@@ -6343,21 +6415,41 @@ void clusterCommandSetSlot(client *c) {
|
||||
server.cluster->migrating_slots_to[slot] = NULL;
|
||||
}
|
||||
|
||||
int slot_was_mine = server.cluster->slots[slot] == myself;
|
||||
clusterNode *my_primary = clusterNodeGetPrimary(myself);
|
||||
int slot_was_mine = server.cluster->slots[slot] == my_primary;
|
||||
clusterDelSlot(slot);
|
||||
clusterAddSlot(n, slot);
|
||||
int shard_is_empty = my_primary->numslots == 0;
|
||||
|
||||
/* If we are a primary left without slots, we should turn into a
|
||||
* replica of the new primary. */
|
||||
if (slot_was_mine && n != myself && myself->numslots == 0 && server.cluster_allow_replica_migration) {
|
||||
/* If replica migration is allowed, check if the primary of this shard
|
||||
* loses its last slot and the shard becomes empty. In this case, we
|
||||
* should turn into a replica of the new primary. */
|
||||
if (server.cluster_allow_replica_migration && slot_was_mine && shard_is_empty) {
|
||||
serverAssert(n != my_primary);
|
||||
serverLog(LL_NOTICE,
|
||||
"Lost my last slot during slot migration. Reconfiguring myself "
|
||||
"as a replica of %.40s (%s) in shard %.40s",
|
||||
n->name, n->human_nodename, n->shard_id);
|
||||
clusterSetPrimary(n, 1);
|
||||
/* `c` is the primary client if `myself` is a replica, prevent it
|
||||
* from being freed by clusterSetPrimary. */
|
||||
if (nodeIsReplica(myself)) protectClient(c);
|
||||
/* We are migrating to a different shard that has a completely different
|
||||
* replication history, so a full sync is required. */
|
||||
clusterSetPrimary(n, 1, 1);
|
||||
if (nodeIsReplica(myself)) unprotectClient(c);
|
||||
clusterDoBeforeSleep(CLUSTER_TODO_SAVE_CONFIG | CLUSTER_TODO_UPDATE_STATE | CLUSTER_TODO_FSYNC_CONFIG);
|
||||
}
|
||||
|
||||
/* If replica migration is not allowed, check if the primary of this shard
|
||||
* loses its last slot and the shard becomes empty. In this case, we will
|
||||
* print the exact same log as during the gossip process. */
|
||||
if (!server.cluster_allow_replica_migration && nodeIsPrimary(myself) && slot_was_mine && shard_is_empty) {
|
||||
serverAssert(n != my_primary);
|
||||
serverLog(LL_NOTICE,
|
||||
"My last slot was migrated to node %.40s (%s) in shard %.40s. I am now an empty primary.",
|
||||
n->name, n->human_nodename, n->shard_id);
|
||||
}
|
||||
|
||||
/* If this node or this node's primary was importing this slot,
|
||||
* assigning the slot to itself also clears the importing status. */
|
||||
if ((n == myself || n == myself->replicaof) && server.cluster->importing_slots_from[slot]) {
|
||||
@@ -6559,8 +6651,18 @@ int clusterCommandSpecial(client *c) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Set the primary. */
|
||||
clusterSetPrimary(n, 1);
|
||||
/* If `n` is already my primary, there is no need to re-establish the
|
||||
* replication connection. */
|
||||
if (myself->replicaof == n) {
|
||||
addReply(c, shared.ok);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Set the primary.
|
||||
* If the instance is a primary, it is an empty primary.
|
||||
* If the instance is a replica, it had a totally different replication history.
|
||||
* In these both cases, myself as a replica has to do a full sync. */
|
||||
clusterSetPrimary(n, 1, 1);
|
||||
clusterBroadcastPong(CLUSTER_BROADCAST_ALL);
|
||||
clusterDoBeforeSleep(CLUSTER_TODO_UPDATE_STATE | CLUSTER_TODO_SAVE_CONFIG);
|
||||
addReply(c, shared.ok);
|
||||
@@ -6604,25 +6706,27 @@ int clusterCommandSpecial(client *c) {
|
||||
}
|
||||
resetManualFailover();
|
||||
server.cluster->mf_end = mstime() + CLUSTER_MF_TIMEOUT;
|
||||
sds client = catClientInfoString(sdsempty(), c, server.hide_user_data_from_log);
|
||||
|
||||
if (takeover) {
|
||||
/* A takeover does not perform any initial check. It just
|
||||
* generates a new configuration epoch for this node without
|
||||
* consensus, claims the primary's slots, and broadcast the new
|
||||
* configuration. */
|
||||
serverLog(LL_NOTICE, "Taking over the primary (user request).");
|
||||
serverLog(LL_NOTICE, "Taking over the primary (user request from '%s').", client);
|
||||
clusterBumpConfigEpochWithoutConsensus();
|
||||
clusterFailoverReplaceYourPrimary();
|
||||
} else if (force) {
|
||||
/* If this is a forced failover, we don't need to talk with our
|
||||
* primary to agree about the offset. We just failover taking over
|
||||
* it without coordination. */
|
||||
serverLog(LL_NOTICE, "Forced failover user request accepted.");
|
||||
serverLog(LL_NOTICE, "Forced failover user request accepted (user request from '%s').", client);
|
||||
server.cluster->mf_can_start = 1;
|
||||
} else {
|
||||
serverLog(LL_NOTICE, "Manual failover user request accepted.");
|
||||
serverLog(LL_NOTICE, "Manual failover user request accepted (user request from '%s').", client);
|
||||
clusterSendMFStart(myself->replicaof);
|
||||
}
|
||||
sdsfree(client);
|
||||
addReply(c, shared.ok);
|
||||
} else if (!strcasecmp(c->argv[1]->ptr, "set-config-epoch") && c->argc == 3) {
|
||||
/* CLUSTER SET-CONFIG-EPOCH <epoch>
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
#define CLUSTER_CANT_FAILOVER_WAITING_DELAY 2
|
||||
#define CLUSTER_CANT_FAILOVER_EXPIRED 3
|
||||
#define CLUSTER_CANT_FAILOVER_WAITING_VOTES 4
|
||||
#define CLUSTER_CANT_FAILOVER_RELOG_PERIOD (10) /* seconds. */
|
||||
#define CLUSTER_CANT_FAILOVER_RELOG_PERIOD 1 /* seconds. */
|
||||
|
||||
/* clusterState todo_before_sleep flags. */
|
||||
#define CLUSTER_TODO_HANDLE_FAILOVER (1 << 0)
|
||||
|
||||
@@ -143,6 +143,7 @@ static void clusterSlotStatsUpdateNetworkBytesOutForReplication(long long len) {
|
||||
if (c == NULL || !canAddNetworkBytesOut(c)) return;
|
||||
|
||||
serverAssert(c->slot >= 0 && c->slot < CLUSTER_SLOTS);
|
||||
serverAssert(nodeIsPrimary(server.cluster->myself));
|
||||
if (len < 0) serverAssert(server.cluster->slot_stats[c->slot].network_bytes_out >= (uint64_t)llabs(len));
|
||||
server.cluster->slot_stats[c->slot].network_bytes_out += (len * listLength(server.replicas));
|
||||
}
|
||||
|
||||
+94
-4
@@ -5605,6 +5605,28 @@ struct COMMAND_ARG SENTINEL_GET_MASTER_ADDR_BY_NAME_Args[] = {
|
||||
{MAKE_ARG("primary-name",ARG_TYPE_STRING,-1,NULL,NULL,NULL,CMD_ARG_NONE,0,NULL)},
|
||||
};
|
||||
|
||||
/********** SENTINEL GET_PRIMARY_ADDR_BY_NAME ********************/
|
||||
|
||||
#ifndef SKIP_CMD_HISTORY_TABLE
|
||||
/* SENTINEL GET_PRIMARY_ADDR_BY_NAME history */
|
||||
#define SENTINEL_GET_PRIMARY_ADDR_BY_NAME_History NULL
|
||||
#endif
|
||||
|
||||
#ifndef SKIP_CMD_TIPS_TABLE
|
||||
/* SENTINEL GET_PRIMARY_ADDR_BY_NAME tips */
|
||||
#define SENTINEL_GET_PRIMARY_ADDR_BY_NAME_Tips NULL
|
||||
#endif
|
||||
|
||||
#ifndef SKIP_CMD_KEY_SPECS_TABLE
|
||||
/* SENTINEL GET_PRIMARY_ADDR_BY_NAME key specs */
|
||||
#define SENTINEL_GET_PRIMARY_ADDR_BY_NAME_Keyspecs NULL
|
||||
#endif
|
||||
|
||||
/* SENTINEL GET_PRIMARY_ADDR_BY_NAME argument table */
|
||||
struct COMMAND_ARG SENTINEL_GET_PRIMARY_ADDR_BY_NAME_Args[] = {
|
||||
{MAKE_ARG("primary-name",ARG_TYPE_STRING,-1,NULL,NULL,NULL,CMD_ARG_NONE,0,NULL)},
|
||||
};
|
||||
|
||||
/********** SENTINEL HELP ********************/
|
||||
|
||||
#ifndef SKIP_CMD_HISTORY_TABLE
|
||||
@@ -5669,6 +5691,31 @@ struct COMMAND_ARG SENTINEL_IS_MASTER_DOWN_BY_ADDR_Args[] = {
|
||||
{MAKE_ARG("runid",ARG_TYPE_STRING,-1,NULL,NULL,NULL,CMD_ARG_NONE,0,NULL)},
|
||||
};
|
||||
|
||||
/********** SENTINEL IS_PRIMARY_DOWN_BY_ADDR ********************/
|
||||
|
||||
#ifndef SKIP_CMD_HISTORY_TABLE
|
||||
/* SENTINEL IS_PRIMARY_DOWN_BY_ADDR history */
|
||||
#define SENTINEL_IS_PRIMARY_DOWN_BY_ADDR_History NULL
|
||||
#endif
|
||||
|
||||
#ifndef SKIP_CMD_TIPS_TABLE
|
||||
/* SENTINEL IS_PRIMARY_DOWN_BY_ADDR tips */
|
||||
#define SENTINEL_IS_PRIMARY_DOWN_BY_ADDR_Tips NULL
|
||||
#endif
|
||||
|
||||
#ifndef SKIP_CMD_KEY_SPECS_TABLE
|
||||
/* SENTINEL IS_PRIMARY_DOWN_BY_ADDR key specs */
|
||||
#define SENTINEL_IS_PRIMARY_DOWN_BY_ADDR_Keyspecs NULL
|
||||
#endif
|
||||
|
||||
/* SENTINEL IS_PRIMARY_DOWN_BY_ADDR argument table */
|
||||
struct COMMAND_ARG SENTINEL_IS_PRIMARY_DOWN_BY_ADDR_Args[] = {
|
||||
{MAKE_ARG("ip",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)},
|
||||
{MAKE_ARG("current-epoch",ARG_TYPE_INTEGER,-1,NULL,NULL,NULL,CMD_ARG_NONE,0,NULL)},
|
||||
{MAKE_ARG("runid",ARG_TYPE_STRING,-1,NULL,NULL,NULL,CMD_ARG_NONE,0,NULL)},
|
||||
};
|
||||
|
||||
/********** SENTINEL MASTER ********************/
|
||||
|
||||
#ifndef SKIP_CMD_HISTORY_TABLE
|
||||
@@ -5767,6 +5814,45 @@ struct COMMAND_ARG SENTINEL_MONITOR_Args[] = {
|
||||
#define SENTINEL_PENDING_SCRIPTS_Keyspecs NULL
|
||||
#endif
|
||||
|
||||
/********** SENTINEL PRIMARIES ********************/
|
||||
|
||||
#ifndef SKIP_CMD_HISTORY_TABLE
|
||||
/* SENTINEL PRIMARIES history */
|
||||
#define SENTINEL_PRIMARIES_History NULL
|
||||
#endif
|
||||
|
||||
#ifndef SKIP_CMD_TIPS_TABLE
|
||||
/* SENTINEL PRIMARIES tips */
|
||||
#define SENTINEL_PRIMARIES_Tips NULL
|
||||
#endif
|
||||
|
||||
#ifndef SKIP_CMD_KEY_SPECS_TABLE
|
||||
/* SENTINEL PRIMARIES key specs */
|
||||
#define SENTINEL_PRIMARIES_Keyspecs NULL
|
||||
#endif
|
||||
|
||||
/********** SENTINEL PRIMARY ********************/
|
||||
|
||||
#ifndef SKIP_CMD_HISTORY_TABLE
|
||||
/* SENTINEL PRIMARY history */
|
||||
#define SENTINEL_PRIMARY_History NULL
|
||||
#endif
|
||||
|
||||
#ifndef SKIP_CMD_TIPS_TABLE
|
||||
/* SENTINEL PRIMARY tips */
|
||||
#define SENTINEL_PRIMARY_Tips NULL
|
||||
#endif
|
||||
|
||||
#ifndef SKIP_CMD_KEY_SPECS_TABLE
|
||||
/* SENTINEL PRIMARY key specs */
|
||||
#define SENTINEL_PRIMARY_Keyspecs NULL
|
||||
#endif
|
||||
|
||||
/* SENTINEL PRIMARY argument table */
|
||||
struct COMMAND_ARG SENTINEL_PRIMARY_Args[] = {
|
||||
{MAKE_ARG("primary-name",ARG_TYPE_STRING,-1,NULL,NULL,NULL,CMD_ARG_NONE,0,NULL)},
|
||||
};
|
||||
|
||||
/********** SENTINEL REMOVE ********************/
|
||||
|
||||
#ifndef SKIP_CMD_HISTORY_TABLE
|
||||
@@ -5942,15 +6028,19 @@ struct COMMAND_STRUCT SENTINEL_Subcommands[] = {
|
||||
{MAKE_CMD("debug","Lists or updates the current configurable parameters of Sentinel.","O(N) where N is the number of configurable parameters","7.0.0",CMD_DOC_NONE,NULL,NULL,"sentinel",COMMAND_GROUP_SENTINEL,SENTINEL_DEBUG_History,0,SENTINEL_DEBUG_Tips,0,sentinelCommand,-2,CMD_ADMIN|CMD_SENTINEL|CMD_ONLY_SENTINEL,0,SENTINEL_DEBUG_Keyspecs,0,NULL,1),.args=SENTINEL_DEBUG_Args},
|
||||
{MAKE_CMD("failover","Forces a Sentinel failover.",NULL,"2.8.4",CMD_DOC_NONE,NULL,NULL,"sentinel",COMMAND_GROUP_SENTINEL,SENTINEL_FAILOVER_History,0,SENTINEL_FAILOVER_Tips,0,sentinelCommand,3,CMD_ADMIN|CMD_SENTINEL|CMD_ONLY_SENTINEL,0,SENTINEL_FAILOVER_Keyspecs,0,NULL,1),.args=SENTINEL_FAILOVER_Args},
|
||||
{MAKE_CMD("flushconfig","Rewrites the Sentinel configuration file.","O(1)","2.8.4",CMD_DOC_NONE,NULL,NULL,"sentinel",COMMAND_GROUP_SENTINEL,SENTINEL_FLUSHCONFIG_History,0,SENTINEL_FLUSHCONFIG_Tips,0,sentinelCommand,2,CMD_ADMIN|CMD_SENTINEL|CMD_ONLY_SENTINEL,0,SENTINEL_FLUSHCONFIG_Keyspecs,0,NULL,0)},
|
||||
{MAKE_CMD("get-master-addr-by-name","Returns the port and address of a primary instance.","O(1)","2.8.4",CMD_DOC_NONE,NULL,NULL,"sentinel",COMMAND_GROUP_SENTINEL,SENTINEL_GET_MASTER_ADDR_BY_NAME_History,0,SENTINEL_GET_MASTER_ADDR_BY_NAME_Tips,0,sentinelCommand,3,CMD_ADMIN|CMD_SENTINEL|CMD_ONLY_SENTINEL,0,SENTINEL_GET_MASTER_ADDR_BY_NAME_Keyspecs,0,NULL,1),.args=SENTINEL_GET_MASTER_ADDR_BY_NAME_Args},
|
||||
{MAKE_CMD("get-master-addr-by-name","Returns the port and address of a primary instance.","O(1)","2.8.4",CMD_DOC_DEPRECATED,"`SENTINEL GET-PRIMARY-ADDR-BY-NAME`","8.0.0","sentinel",COMMAND_GROUP_SENTINEL,SENTINEL_GET_MASTER_ADDR_BY_NAME_History,0,SENTINEL_GET_MASTER_ADDR_BY_NAME_Tips,0,sentinelCommand,3,CMD_ADMIN|CMD_SENTINEL|CMD_ONLY_SENTINEL,0,SENTINEL_GET_MASTER_ADDR_BY_NAME_Keyspecs,0,NULL,1),.args=SENTINEL_GET_MASTER_ADDR_BY_NAME_Args},
|
||||
{MAKE_CMD("get-primary-addr-by-name","Returns the port and address of a primary instance.","O(1)","8.0.0",CMD_DOC_NONE,NULL,NULL,"sentinel",COMMAND_GROUP_SENTINEL,SENTINEL_GET_PRIMARY_ADDR_BY_NAME_History,0,SENTINEL_GET_PRIMARY_ADDR_BY_NAME_Tips,0,sentinelCommand,3,CMD_ADMIN|CMD_SENTINEL|CMD_ONLY_SENTINEL,0,SENTINEL_GET_PRIMARY_ADDR_BY_NAME_Keyspecs,0,NULL,1),.args=SENTINEL_GET_PRIMARY_ADDR_BY_NAME_Args},
|
||||
{MAKE_CMD("help","Returns helpful text about the different subcommands.","O(1)","6.2.0",CMD_DOC_NONE,NULL,NULL,"sentinel",COMMAND_GROUP_SENTINEL,SENTINEL_HELP_History,0,SENTINEL_HELP_Tips,0,sentinelCommand,2,CMD_LOADING|CMD_STALE|CMD_SENTINEL|CMD_ONLY_SENTINEL,0,SENTINEL_HELP_Keyspecs,0,NULL,0)},
|
||||
{MAKE_CMD("info-cache","Returns the cached `INFO` replies from the deployment's instances.","O(N) where N is the number of instances","3.2.0",CMD_DOC_NONE,NULL,NULL,"sentinel",COMMAND_GROUP_SENTINEL,SENTINEL_INFO_CACHE_History,0,SENTINEL_INFO_CACHE_Tips,0,sentinelCommand,-3,CMD_ADMIN|CMD_SENTINEL|CMD_ONLY_SENTINEL,0,SENTINEL_INFO_CACHE_Keyspecs,0,NULL,1),.args=SENTINEL_INFO_CACHE_Args},
|
||||
{MAKE_CMD("is-master-down-by-addr","Determines whether a primary instance is down.","O(1)","2.8.4",CMD_DOC_NONE,NULL,NULL,"sentinel",COMMAND_GROUP_SENTINEL,SENTINEL_IS_MASTER_DOWN_BY_ADDR_History,0,SENTINEL_IS_MASTER_DOWN_BY_ADDR_Tips,0,sentinelCommand,6,CMD_ADMIN|CMD_SENTINEL|CMD_ONLY_SENTINEL,0,SENTINEL_IS_MASTER_DOWN_BY_ADDR_Keyspecs,0,NULL,4),.args=SENTINEL_IS_MASTER_DOWN_BY_ADDR_Args},
|
||||
{MAKE_CMD("master","Returns the state of a primary instance.","O(1)","2.8.4",CMD_DOC_NONE,NULL,NULL,"sentinel",COMMAND_GROUP_SENTINEL,SENTINEL_MASTER_History,0,SENTINEL_MASTER_Tips,0,sentinelCommand,3,CMD_ADMIN|CMD_SENTINEL|CMD_ONLY_SENTINEL,0,SENTINEL_MASTER_Keyspecs,0,NULL,1),.args=SENTINEL_MASTER_Args},
|
||||
{MAKE_CMD("masters","Returns a list of monitored primaries.","O(N) where N is the number of primaries","2.8.4",CMD_DOC_NONE,NULL,NULL,"sentinel",COMMAND_GROUP_SENTINEL,SENTINEL_MASTERS_History,0,SENTINEL_MASTERS_Tips,0,sentinelCommand,2,CMD_ADMIN|CMD_SENTINEL|CMD_ONLY_SENTINEL,0,SENTINEL_MASTERS_Keyspecs,0,NULL,0)},
|
||||
{MAKE_CMD("is-master-down-by-addr","Determines whether a primary instance is down.","O(1)","2.8.4",CMD_DOC_DEPRECATED,"`SENTINEL IS-PRIMARY-DOWN-BY-ADDR`","8.0.0","sentinel",COMMAND_GROUP_SENTINEL,SENTINEL_IS_MASTER_DOWN_BY_ADDR_History,0,SENTINEL_IS_MASTER_DOWN_BY_ADDR_Tips,0,sentinelCommand,6,CMD_ADMIN|CMD_SENTINEL|CMD_ONLY_SENTINEL,0,SENTINEL_IS_MASTER_DOWN_BY_ADDR_Keyspecs,0,NULL,4),.args=SENTINEL_IS_MASTER_DOWN_BY_ADDR_Args},
|
||||
{MAKE_CMD("is-primary-down-by-addr","Determines whether a primary instance is down.","O(1)","8.0.0",CMD_DOC_NONE,NULL,NULL,"sentinel",COMMAND_GROUP_SENTINEL,SENTINEL_IS_PRIMARY_DOWN_BY_ADDR_History,0,SENTINEL_IS_PRIMARY_DOWN_BY_ADDR_Tips,0,sentinelCommand,6,CMD_ADMIN|CMD_SENTINEL|CMD_ONLY_SENTINEL,0,SENTINEL_IS_PRIMARY_DOWN_BY_ADDR_Keyspecs,0,NULL,4),.args=SENTINEL_IS_PRIMARY_DOWN_BY_ADDR_Args},
|
||||
{MAKE_CMD("master","Returns the state of a primary instance.","O(1)","2.8.4",CMD_DOC_DEPRECATED,"`SENTINEL PRIMARY`","8.0.0","sentinel",COMMAND_GROUP_SENTINEL,SENTINEL_MASTER_History,0,SENTINEL_MASTER_Tips,0,sentinelCommand,3,CMD_ADMIN|CMD_SENTINEL|CMD_ONLY_SENTINEL,0,SENTINEL_MASTER_Keyspecs,0,NULL,1),.args=SENTINEL_MASTER_Args},
|
||||
{MAKE_CMD("masters","Returns a list of monitored primaries.","O(N) where N is the number of primaries","2.8.4",CMD_DOC_DEPRECATED,"`SENTINEL PRIMARIES`","8.0.0","sentinel",COMMAND_GROUP_SENTINEL,SENTINEL_MASTERS_History,0,SENTINEL_MASTERS_Tips,0,sentinelCommand,2,CMD_ADMIN|CMD_SENTINEL|CMD_ONLY_SENTINEL,0,SENTINEL_MASTERS_Keyspecs,0,NULL,0)},
|
||||
{MAKE_CMD("monitor","Starts monitoring.","O(1)","2.8.4",CMD_DOC_NONE,NULL,NULL,"sentinel",COMMAND_GROUP_SENTINEL,SENTINEL_MONITOR_History,0,SENTINEL_MONITOR_Tips,0,sentinelCommand,6,CMD_ADMIN|CMD_SENTINEL|CMD_ONLY_SENTINEL,0,SENTINEL_MONITOR_Keyspecs,0,NULL,4),.args=SENTINEL_MONITOR_Args},
|
||||
{MAKE_CMD("myid","Returns the Sentinel instance ID.","O(1)","6.2.0",CMD_DOC_NONE,NULL,NULL,"sentinel",COMMAND_GROUP_SENTINEL,SENTINEL_MYID_History,0,SENTINEL_MYID_Tips,0,sentinelCommand,2,CMD_ADMIN|CMD_SENTINEL|CMD_ONLY_SENTINEL,0,SENTINEL_MYID_Keyspecs,0,NULL,0)},
|
||||
{MAKE_CMD("pending-scripts","Returns information about pending scripts for Sentinel.",NULL,"2.8.4",CMD_DOC_NONE,NULL,NULL,"sentinel",COMMAND_GROUP_SENTINEL,SENTINEL_PENDING_SCRIPTS_History,0,SENTINEL_PENDING_SCRIPTS_Tips,0,sentinelCommand,2,CMD_ADMIN|CMD_SENTINEL|CMD_ONLY_SENTINEL,0,SENTINEL_PENDING_SCRIPTS_Keyspecs,0,NULL,0)},
|
||||
{MAKE_CMD("primaries","Returns a list of monitored primaries.","O(N) where N is the number of primaries","8.0.0",CMD_DOC_NONE,NULL,NULL,"sentinel",COMMAND_GROUP_SENTINEL,SENTINEL_PRIMARIES_History,0,SENTINEL_PRIMARIES_Tips,0,sentinelCommand,2,CMD_ADMIN|CMD_SENTINEL|CMD_ONLY_SENTINEL,0,SENTINEL_PRIMARIES_Keyspecs,0,NULL,0)},
|
||||
{MAKE_CMD("primary","Returns the state of a primary instance.","O(1)","8.0.0",CMD_DOC_NONE,NULL,NULL,"sentinel",COMMAND_GROUP_SENTINEL,SENTINEL_PRIMARY_History,0,SENTINEL_PRIMARY_Tips,0,sentinelCommand,3,CMD_ADMIN|CMD_SENTINEL|CMD_ONLY_SENTINEL,0,SENTINEL_PRIMARY_Keyspecs,0,NULL,1),.args=SENTINEL_PRIMARY_Args},
|
||||
{MAKE_CMD("remove","Stops monitoring.","O(1)","2.8.4",CMD_DOC_NONE,NULL,NULL,"sentinel",COMMAND_GROUP_SENTINEL,SENTINEL_REMOVE_History,0,SENTINEL_REMOVE_Tips,0,sentinelCommand,3,CMD_ADMIN|CMD_SENTINEL|CMD_ONLY_SENTINEL,0,SENTINEL_REMOVE_Keyspecs,0,NULL,1),.args=SENTINEL_REMOVE_Args},
|
||||
{MAKE_CMD("replicas","Returns a list of the monitored replicas.","O(N) where N is the number of replicas","5.0.0",CMD_DOC_NONE,NULL,NULL,"sentinel",COMMAND_GROUP_SENTINEL,SENTINEL_REPLICAS_History,0,SENTINEL_REPLICAS_Tips,0,sentinelCommand,3,CMD_ADMIN|CMD_SENTINEL|CMD_ONLY_SENTINEL,0,SENTINEL_REPLICAS_Keyspecs,0,NULL,1),.args=SENTINEL_REPLICAS_Args},
|
||||
{MAKE_CMD("reset","Resets primaries by name matching a pattern.","O(N) where N is the number of monitored primaries","2.8.4",CMD_DOC_NONE,NULL,NULL,"sentinel",COMMAND_GROUP_SENTINEL,SENTINEL_RESET_History,0,SENTINEL_RESET_Tips,0,sentinelCommand,3,CMD_ADMIN|CMD_SENTINEL|CMD_ONLY_SENTINEL,0,SENTINEL_RESET_Keyspecs,0,NULL,1),.args=SENTINEL_RESET_Args},
|
||||
|
||||
@@ -7,6 +7,12 @@
|
||||
"arity": 3,
|
||||
"container": "SENTINEL",
|
||||
"function": "sentinelCommand",
|
||||
"deprecated_since": "8.0.0",
|
||||
"replaced_by": "`SENTINEL GET-PRIMARY-ADDR-BY-NAME`",
|
||||
"doc_flags": [
|
||||
"DEPRECATED"
|
||||
],
|
||||
|
||||
"command_flags": [
|
||||
"ADMIN",
|
||||
"SENTINEL",
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"GET-PRIMARY-ADDR-BY-NAME": {
|
||||
"summary": "Returns the port and address of a primary instance.",
|
||||
"complexity": "O(1)",
|
||||
"group": "sentinel",
|
||||
"since": "8.0.0",
|
||||
"arity": 3,
|
||||
"container": "SENTINEL",
|
||||
"function": "sentinelCommand",
|
||||
"command_flags": [
|
||||
"ADMIN",
|
||||
"SENTINEL",
|
||||
"ONLY_SENTINEL"
|
||||
],
|
||||
"reply_schema": {
|
||||
"type": "array",
|
||||
"minItems": 2,
|
||||
"maxItems": 2,
|
||||
"items": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "IP addr or hostname."
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Port.",
|
||||
"pattern": "[0-9]+"
|
||||
}
|
||||
]
|
||||
},
|
||||
"arguments": [
|
||||
{
|
||||
"name": "primary-name",
|
||||
"type": "string"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,11 @@
|
||||
"arity": 6,
|
||||
"container": "SENTINEL",
|
||||
"function": "sentinelCommand",
|
||||
"deprecated_since": "8.0.0",
|
||||
"replaced_by": "`SENTINEL IS-PRIMARY-DOWN-BY-ADDR`",
|
||||
"doc_flags": [
|
||||
"DEPRECATED"
|
||||
],
|
||||
"command_flags": [
|
||||
"ADMIN",
|
||||
"SENTINEL",
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
{
|
||||
"IS-PRIMARY-DOWN-BY-ADDR": {
|
||||
"summary": "Determines whether a primary instance is down.",
|
||||
"complexity": "O(1)",
|
||||
"group": "sentinel",
|
||||
"since": "8.0.0",
|
||||
"arity": 6,
|
||||
"container": "SENTINEL",
|
||||
"function": "sentinelCommand",
|
||||
"command_flags": [
|
||||
"ADMIN",
|
||||
"SENTINEL",
|
||||
"ONLY_SENTINEL"
|
||||
],
|
||||
"reply_schema": {
|
||||
"type": "array",
|
||||
"minItems": 3,
|
||||
"maxItems": 3,
|
||||
"items": [
|
||||
{
|
||||
"oneOf": [
|
||||
{
|
||||
"const": 0,
|
||||
"description": "Primary is up."
|
||||
},
|
||||
{
|
||||
"const": 1,
|
||||
"description": "Primary is down."
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Sentinel address."
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "Port."
|
||||
}
|
||||
]
|
||||
},
|
||||
"arguments": [
|
||||
{
|
||||
"name": "ip",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "port",
|
||||
"type": "integer"
|
||||
},
|
||||
{
|
||||
"name": "current-epoch",
|
||||
"type": "integer"
|
||||
},
|
||||
{
|
||||
"name": "runid",
|
||||
"type": "string"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,11 @@
|
||||
"arity": 3,
|
||||
"container": "SENTINEL",
|
||||
"function": "sentinelCommand",
|
||||
"deprecated_since": "8.0.0",
|
||||
"replaced_by": "`SENTINEL PRIMARY`",
|
||||
"doc_flags": [
|
||||
"DEPRECATED"
|
||||
],
|
||||
"command_flags": [
|
||||
"ADMIN",
|
||||
"SENTINEL",
|
||||
|
||||
@@ -7,6 +7,11 @@
|
||||
"arity": 2,
|
||||
"container": "SENTINEL",
|
||||
"function": "sentinelCommand",
|
||||
"deprecated_since": "8.0.0",
|
||||
"replaced_by": "`SENTINEL PRIMARIES`",
|
||||
"doc_flags": [
|
||||
"DEPRECATED"
|
||||
],
|
||||
"command_flags": [
|
||||
"ADMIN",
|
||||
"SENTINEL",
|
||||
@@ -14,7 +19,7 @@
|
||||
],
|
||||
"reply_schema": {
|
||||
"type": "array",
|
||||
"description": "List of monitored primaries, and their state.",
|
||||
"description": "List of monitored primaries, and their states.",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"PRIMARIES": {
|
||||
"summary": "Returns a list of monitored primaries.",
|
||||
"complexity": "O(N) where N is the number of primaries",
|
||||
"group": "sentinel",
|
||||
"since": "8.0.0",
|
||||
"arity": 2,
|
||||
"container": "SENTINEL",
|
||||
"function": "sentinelCommand",
|
||||
"command_flags": [
|
||||
"ADMIN",
|
||||
"SENTINEL",
|
||||
"ONLY_SENTINEL"
|
||||
],
|
||||
"reply_schema": {
|
||||
"type": "array",
|
||||
"description": "List of monitored primaries, and their states.",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"PRIMARY": {
|
||||
"summary": "Returns the state of a primary instance.",
|
||||
"complexity": "O(1)",
|
||||
"group": "sentinel",
|
||||
"since": "8.0.0",
|
||||
"arity": 3,
|
||||
"container": "SENTINEL",
|
||||
"function": "sentinelCommand",
|
||||
"command_flags": [
|
||||
"ADMIN",
|
||||
"SENTINEL",
|
||||
"ONLY_SENTINEL"
|
||||
],
|
||||
"reply_schema": {
|
||||
"type": "object",
|
||||
"description": "The state and info of the specified primary.",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"arguments": [
|
||||
{
|
||||
"name": "primary-name",
|
||||
"type": "string"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
+13
-9
@@ -1,6 +1,6 @@
|
||||
/* Configuration file parsing and CONFIG GET/SET commands implementation.
|
||||
*
|
||||
* Copyright (c) 2009-2012, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* Copyright (c) 2009-2012, Redis Ltd.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -3067,14 +3067,14 @@ standardConfig static_configs[] = {
|
||||
createBoolConfig("stop-writes-on-bgsave-error", NULL, MODIFIABLE_CONFIG, server.stop_writes_on_bgsave_err, 1, NULL, NULL),
|
||||
createBoolConfig("set-proc-title", NULL, IMMUTABLE_CONFIG, server.set_proc_title, 1, NULL, NULL), /* Should setproctitle be used? */
|
||||
createBoolConfig("dynamic-hz", NULL, MODIFIABLE_CONFIG, server.dynamic_hz, 1, NULL, NULL), /* Adapt hz to # of clients.*/
|
||||
createBoolConfig("lazyfree-lazy-eviction", NULL, DEBUG_CONFIG | MODIFIABLE_CONFIG, server.lazyfree_lazy_eviction, 0, NULL, NULL),
|
||||
createBoolConfig("lazyfree-lazy-expire", NULL, DEBUG_CONFIG | MODIFIABLE_CONFIG, server.lazyfree_lazy_expire, 0, NULL, NULL),
|
||||
createBoolConfig("lazyfree-lazy-server-del", NULL, DEBUG_CONFIG | MODIFIABLE_CONFIG, server.lazyfree_lazy_server_del, 0, NULL, NULL),
|
||||
createBoolConfig("lazyfree-lazy-user-del", NULL, DEBUG_CONFIG | MODIFIABLE_CONFIG, server.lazyfree_lazy_user_del, 0, NULL, NULL),
|
||||
createBoolConfig("lazyfree-lazy-user-flush", NULL, DEBUG_CONFIG | MODIFIABLE_CONFIG, server.lazyfree_lazy_user_flush, 0, NULL, NULL),
|
||||
createBoolConfig("lazyfree-lazy-eviction", NULL, DEBUG_CONFIG | MODIFIABLE_CONFIG, server.lazyfree_lazy_eviction, 1, NULL, NULL),
|
||||
createBoolConfig("lazyfree-lazy-expire", NULL, DEBUG_CONFIG | MODIFIABLE_CONFIG, server.lazyfree_lazy_expire, 1, NULL, NULL),
|
||||
createBoolConfig("lazyfree-lazy-server-del", NULL, DEBUG_CONFIG | MODIFIABLE_CONFIG, server.lazyfree_lazy_server_del, 1, NULL, NULL),
|
||||
createBoolConfig("lazyfree-lazy-user-del", NULL, DEBUG_CONFIG | MODIFIABLE_CONFIG, server.lazyfree_lazy_user_del, 1, NULL, NULL),
|
||||
createBoolConfig("lazyfree-lazy-user-flush", NULL, DEBUG_CONFIG | MODIFIABLE_CONFIG, server.lazyfree_lazy_user_flush, 1, NULL, NULL),
|
||||
createBoolConfig("repl-disable-tcp-nodelay", NULL, MODIFIABLE_CONFIG, server.repl_disable_tcp_nodelay, 0, NULL, NULL),
|
||||
createBoolConfig("repl-diskless-sync", NULL, DEBUG_CONFIG | MODIFIABLE_CONFIG, server.repl_diskless_sync, 1, NULL, NULL),
|
||||
createBoolConfig("dual-channel-replication-enabled", NULL, DEBUG_CONFIG | MODIFIABLE_CONFIG | PROTECTED_CONFIG, server.dual_channel_replication, 0, NULL, NULL),
|
||||
createBoolConfig("dual-channel-replication-enabled", NULL, DEBUG_CONFIG | MODIFIABLE_CONFIG, server.dual_channel_replication, 0, NULL, NULL),
|
||||
createBoolConfig("aof-rewrite-incremental-fsync", NULL, MODIFIABLE_CONFIG, server.aof_rewrite_incremental_fsync, 1, NULL, NULL),
|
||||
createBoolConfig("no-appendfsync-on-rewrite", NULL, MODIFIABLE_CONFIG, server.aof_no_fsync_on_rewrite, 0, NULL, NULL),
|
||||
createBoolConfig("cluster-require-full-coverage", NULL, MODIFIABLE_CONFIG, server.cluster_require_full_coverage, 1, NULL, NULL),
|
||||
@@ -3083,7 +3083,7 @@ standardConfig static_configs[] = {
|
||||
createBoolConfig("aof-use-rdb-preamble", NULL, MODIFIABLE_CONFIG, server.aof_use_rdb_preamble, 1, NULL, NULL),
|
||||
createBoolConfig("aof-timestamp-enabled", NULL, MODIFIABLE_CONFIG, server.aof_timestamp_enabled, 0, NULL, NULL),
|
||||
createBoolConfig("cluster-replica-no-failover", "cluster-slave-no-failover", MODIFIABLE_CONFIG, server.cluster_replica_no_failover, 0, NULL, updateClusterFlags), /* Failover by default. */
|
||||
createBoolConfig("replica-lazy-flush", "slave-lazy-flush", MODIFIABLE_CONFIG, server.repl_replica_lazy_flush, 0, NULL, NULL),
|
||||
createBoolConfig("replica-lazy-flush", "slave-lazy-flush", MODIFIABLE_CONFIG, server.repl_replica_lazy_flush, 1, NULL, NULL),
|
||||
createBoolConfig("replica-serve-stale-data", "slave-serve-stale-data", MODIFIABLE_CONFIG, server.repl_serve_stale_data, 1, NULL, NULL),
|
||||
createBoolConfig("replica-read-only", "slave-read-only", DEBUG_CONFIG | MODIFIABLE_CONFIG, server.repl_replica_ro, 1, NULL, NULL),
|
||||
createBoolConfig("replica-ignore-maxmemory", "slave-ignore-maxmemory", MODIFIABLE_CONFIG, server.repl_replica_ignore_maxmemory, 1, NULL, NULL),
|
||||
@@ -3106,10 +3106,12 @@ standardConfig static_configs[] = {
|
||||
createBoolConfig("extended-redis-compatibility", NULL, MODIFIABLE_CONFIG, server.extended_redis_compat, 0, NULL, updateExtendedRedisCompat),
|
||||
createBoolConfig("enable-debug-assert", NULL, IMMUTABLE_CONFIG | HIDDEN_CONFIG, server.enable_debug_assert, 0, NULL, NULL),
|
||||
createBoolConfig("cluster-slot-stats-enabled", NULL, MODIFIABLE_CONFIG, server.cluster_slot_stats_enabled, 0, NULL, NULL),
|
||||
createBoolConfig("hide-user-data-from-log", NULL, MODIFIABLE_CONFIG, server.hide_user_data_from_log, 1, NULL, NULL),
|
||||
|
||||
/* String Configs */
|
||||
createStringConfig("aclfile", NULL, IMMUTABLE_CONFIG, ALLOW_EMPTY_STRING, server.acl_filename, "", NULL, NULL),
|
||||
createStringConfig("unixsocket", NULL, IMMUTABLE_CONFIG, EMPTY_STRING_IS_NULL, server.unixsocket, NULL, NULL, NULL),
|
||||
createStringConfig("unixsocketgroup", NULL, IMMUTABLE_CONFIG, EMPTY_STRING_IS_NULL, server.unixsocketgroup, NULL, NULL, NULL),
|
||||
createStringConfig("pidfile", NULL, IMMUTABLE_CONFIG, EMPTY_STRING_IS_NULL, server.pidfile, NULL, NULL, NULL),
|
||||
createStringConfig("replica-announce-ip", "slave-announce-ip", MODIFIABLE_CONFIG, EMPTY_STRING_IS_NULL, server.replica_announce_ip, NULL, NULL, NULL),
|
||||
createStringConfig("primaryuser", "masteruser", MODIFIABLE_CONFIG | SENSITIVE_CONFIG, EMPTY_STRING_IS_NULL, server.primary_user, NULL, NULL, NULL),
|
||||
@@ -3135,6 +3137,7 @@ standardConfig static_configs[] = {
|
||||
createStringConfig("req-res-logfile", NULL, IMMUTABLE_CONFIG | HIDDEN_CONFIG, EMPTY_STRING_IS_NULL, server.req_res_logfile, NULL, NULL, NULL),
|
||||
#endif
|
||||
createStringConfig("locale-collate", NULL, MODIFIABLE_CONFIG, ALLOW_EMPTY_STRING, server.locale_collate, "", NULL, updateLocaleCollate),
|
||||
createStringConfig("debug-context", NULL, MODIFIABLE_CONFIG | DEBUG_CONFIG | HIDDEN_CONFIG, ALLOW_EMPTY_STRING, server.debug_context, "", NULL, NULL),
|
||||
|
||||
/* SDS Configs */
|
||||
createSDSConfig("primaryauth", "masterauth", MODIFIABLE_CONFIG | SENSITIVE_CONFIG, EMPTY_STRING_IS_NULL, server.primary_auth, NULL, NULL, NULL),
|
||||
@@ -3164,6 +3167,7 @@ standardConfig static_configs[] = {
|
||||
createIntConfig("port", NULL, MODIFIABLE_CONFIG, 0, 65535, server.port, 6379, INTEGER_CONFIG, NULL, updatePort), /* TCP port. */
|
||||
createIntConfig("io-threads", NULL, DEBUG_CONFIG | IMMUTABLE_CONFIG, 1, 128, server.io_threads_num, 1, INTEGER_CONFIG, NULL, NULL), /* Single threaded by default */
|
||||
createIntConfig("events-per-io-thread", NULL, MODIFIABLE_CONFIG, 0, INT_MAX, server.events_per_io_thread, 2, INTEGER_CONFIG, NULL, NULL),
|
||||
createIntConfig("prefetch-batch-max-size", NULL, MODIFIABLE_CONFIG, 0, 128, server.prefetch_batch_max_size, 16, INTEGER_CONFIG, NULL, NULL),
|
||||
createIntConfig("auto-aof-rewrite-percentage", NULL, MODIFIABLE_CONFIG, 0, INT_MAX, server.aof_rewrite_perc, 100, INTEGER_CONFIG, NULL, NULL),
|
||||
createIntConfig("cluster-replica-validity-factor", "cluster-slave-validity-factor", MODIFIABLE_CONFIG, 0, INT_MAX, server.cluster_replica_validity_factor, 10, INTEGER_CONFIG, NULL, NULL), /* replica max data age factor. */
|
||||
createIntConfig("list-max-listpack-size", "list-max-ziplist-size", MODIFIABLE_CONFIG, INT_MIN, INT_MAX, server.list_max_listpack_size, -2, INTEGER_CONFIG, NULL, NULL),
|
||||
@@ -3223,7 +3227,7 @@ standardConfig static_configs[] = {
|
||||
createLongLongConfig("latency-monitor-threshold", NULL, MODIFIABLE_CONFIG, 0, LLONG_MAX, server.latency_monitor_threshold, 0, INTEGER_CONFIG, NULL, NULL),
|
||||
createLongLongConfig("proto-max-bulk-len", NULL, DEBUG_CONFIG | MODIFIABLE_CONFIG, 1024 * 1024, LONG_MAX, server.proto_max_bulk_len, 512ll * 1024 * 1024, MEMORY_CONFIG, NULL, NULL), /* Bulk request max size */
|
||||
createLongLongConfig("stream-node-max-entries", NULL, MODIFIABLE_CONFIG, 0, LLONG_MAX, server.stream_node_max_entries, 100, INTEGER_CONFIG, NULL, NULL),
|
||||
createLongLongConfig("repl-backlog-size", NULL, MODIFIABLE_CONFIG, 1, LLONG_MAX, server.repl_backlog_size, 1024 * 1024, MEMORY_CONFIG, NULL, updateReplBacklogSize), /* Default: 1mb */
|
||||
createLongLongConfig("repl-backlog-size", NULL, MODIFIABLE_CONFIG, 1, LLONG_MAX, server.repl_backlog_size, 10 * 1024 * 1024, MEMORY_CONFIG, NULL, updateReplBacklogSize), /* Default: 10mb */
|
||||
|
||||
/* Unsigned Long Long configs */
|
||||
createULongLongConfig("maxmemory", NULL, MODIFIABLE_CONFIG, 0, ULLONG_MAX, server.maxmemory, 0, MEMORY_CONFIG, NULL, updateMaxmemory),
|
||||
|
||||
+17
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2012, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* Copyright (c) 2009-2012, Redis Ltd.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -348,4 +348,20 @@ void setcpuaffinity(const char *cpulist);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Check for GCC version >= 4.9 */
|
||||
#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9))
|
||||
#define HAS_BUILTIN_PREFETCH 1
|
||||
/* Check for Clang version >= 3.6 */
|
||||
#elif defined(__clang__) && (__clang_major__ > 3 || (__clang_major__ == 3 && __clang_minor__ >= 6))
|
||||
#define HAS_BUILTIN_PREFETCH 1
|
||||
#else
|
||||
#define HAS_BUILTIN_PREFETCH 0
|
||||
#endif
|
||||
|
||||
#if HAS_BUILTIN_PREFETCH
|
||||
#define valkey_prefetch(addr) __builtin_prefetch(addr)
|
||||
#else
|
||||
#define valkey_prefetch(addr) ((void)(addr))
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
+3
-2
@@ -1,6 +1,6 @@
|
||||
|
||||
/*
|
||||
* Copyright (c) 2019, Redis Labs
|
||||
* Copyright (c) 2019, Redis Ltd.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -144,7 +144,8 @@ struct connListener {
|
||||
int bindaddr_count;
|
||||
int port;
|
||||
ConnectionType *ct;
|
||||
void *priv; /* used by connection type specified data */
|
||||
void *priv1; /* used by connection type specified data */
|
||||
void *priv2; /* used by connection type specified data */
|
||||
};
|
||||
|
||||
/* The connection module does not deal with listening and accepting sockets,
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
|
||||
/*
|
||||
* Copyright (c) 2019, Redis Labs
|
||||
* Copyright (c) 2019, Redis Ltd.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
|
||||
/*
|
||||
* Copyright 2001-2010 Georges Menie (www.menie.org)
|
||||
* Copyright 2010-2012 Salvatore Sanfilippo (adapted to Redis coding style)
|
||||
* Copyright 2010-2012 Redis Ltd. (adapted to Redis coding style)
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2012, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* Copyright (c) 2009-2012, Redis Ltd.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -55,6 +55,7 @@ typedef enum {
|
||||
keyStatus expireIfNeeded(serverDb *db, robj *key, int flags);
|
||||
int keyIsExpired(serverDb *db, robj *key);
|
||||
static void dbSetValue(serverDb *db, robj *key, robj *val, int overwrite, dictEntry *de);
|
||||
static int getKVStoreIndexForKey(sds key);
|
||||
|
||||
/* Update LFU when an object is accessed.
|
||||
* Firstly, decrement the counter if the decrement time is reached.
|
||||
@@ -125,7 +126,7 @@ robj *lookupKey(serverDb *db, robj *key, int flags) {
|
||||
if (!hasActiveChildProcess() && !(flags & LOOKUP_NOTOUCH)) {
|
||||
if (!canUseSharedObject() && val->refcount == OBJ_SHARED_REFCOUNT) {
|
||||
val = dupStringObject(val);
|
||||
kvstoreDictSetVal(db->keys, getKeySlot(key->ptr), de, val);
|
||||
kvstoreDictSetVal(db->keys, getKVStoreIndexForKey(key->ptr), de, val);
|
||||
}
|
||||
if (server.maxmemory_policy & MAXMEMORY_FLAG_LFU) {
|
||||
updateLFU(val);
|
||||
@@ -202,15 +203,15 @@ robj *lookupKeyWriteOrReply(client *c, robj *key, robj *reply) {
|
||||
* if the key already exists, otherwise, it can fall back to dbOverwrite. */
|
||||
static void dbAddInternal(serverDb *db, robj *key, robj *val, int update_if_existing) {
|
||||
dictEntry *existing;
|
||||
int slot = getKeySlot(key->ptr);
|
||||
dictEntry *de = kvstoreDictAddRaw(db->keys, slot, key->ptr, &existing);
|
||||
int dict_index = getKVStoreIndexForKey(key->ptr);
|
||||
dictEntry *de = kvstoreDictAddRaw(db->keys, dict_index, key->ptr, &existing);
|
||||
if (update_if_existing && existing) {
|
||||
dbSetValue(db, key, val, 1, existing);
|
||||
return;
|
||||
}
|
||||
serverAssertWithInfo(NULL, key, de != NULL);
|
||||
initObjectLRUOrLFU(val);
|
||||
kvstoreDictSetVal(db->keys, slot, de, val);
|
||||
kvstoreDictSetVal(db->keys, dict_index, de, val);
|
||||
signalKeyAsReady(db, key, val->type);
|
||||
notifyKeyspaceEvent(NOTIFY_NEW, "new", key, db->id);
|
||||
}
|
||||
@@ -219,32 +220,33 @@ void dbAdd(serverDb *db, robj *key, robj *val) {
|
||||
dbAddInternal(db, key, val, 0);
|
||||
}
|
||||
|
||||
/* Returns key's hash slot when cluster mode is enabled, or 0 when disabled.
|
||||
* The only difference between this function and getKeySlot, is that it's not using cached key slot from the
|
||||
* current_client and always calculates CRC hash. This is useful when slot needs to be calculated for a key that user
|
||||
* didn't request for, such as in case of eviction. */
|
||||
int calculateKeySlot(sds key) {
|
||||
return server.cluster_enabled ? keyHashSlot(key, (int)sdslen(key)) : 0;
|
||||
/* Returns which dict index should be used with kvstore for a given key. */
|
||||
static int getKVStoreIndexForKey(sds key) {
|
||||
return server.cluster_enabled ? getKeySlot(key) : 0;
|
||||
}
|
||||
|
||||
/* Return slot-specific dictionary for key based on key's hash slot when cluster mode is enabled, else 0.*/
|
||||
/* Returns the cluster hash slot for a given key, trying to use the cached slot that
|
||||
* stored on the server.current_client first. If there is no cached value, it will compute the hash slot
|
||||
* and then cache the value.*/
|
||||
int getKeySlot(sds key) {
|
||||
serverAssert(server.cluster_enabled);
|
||||
/* This is performance optimization that uses pre-set slot id from the current command,
|
||||
* in order to avoid calculation of the key hash.
|
||||
*
|
||||
* This optimization is only used when current_client flag `CLIENT_EXECUTING_COMMAND` is set.
|
||||
* It only gets set during the execution of command under `call` method. Other flows requesting
|
||||
* the key slot would fallback to calculateKeySlot.
|
||||
* the key slot would fallback to keyHashSlot.
|
||||
*
|
||||
* Modules and scripts executed on the primary may get replicated as multi-execs that operate on multiple slots,
|
||||
* so we must always recompute the slot for commands coming from the primary.
|
||||
*/
|
||||
if (server.current_client && server.current_client->slot >= 0 && server.current_client->flag.executing_command &&
|
||||
!server.current_client->flag.primary) {
|
||||
debugServerAssertWithInfo(server.current_client, NULL, calculateKeySlot(key) == server.current_client->slot);
|
||||
debugServerAssertWithInfo(server.current_client, NULL,
|
||||
(int)keyHashSlot(key, (int)sdslen(key)) == server.current_client->slot);
|
||||
return server.current_client->slot;
|
||||
}
|
||||
int slot = calculateKeySlot(key);
|
||||
int slot = keyHashSlot(key, (int)sdslen(key));
|
||||
/* For the case of replicated commands from primary, getNodeByQuery() never gets called,
|
||||
* and thus c->slot never gets populated. That said, if this command ends up accessing a key,
|
||||
* we are able to backfill c->slot here, where the key's hash calculation is made. */
|
||||
@@ -267,11 +269,11 @@ int getKeySlot(sds key) {
|
||||
* In this case a copy of `key` is copied in kvstore, the caller must ensure the `key` is properly freed.
|
||||
*/
|
||||
int dbAddRDBLoad(serverDb *db, sds key, robj *val) {
|
||||
int slot = getKeySlot(key);
|
||||
dictEntry *de = kvstoreDictAddRaw(db->keys, slot, key, NULL);
|
||||
int dict_index = server.cluster_enabled ? getKeySlot(key) : 0;
|
||||
dictEntry *de = kvstoreDictAddRaw(db->keys, dict_index, key, NULL);
|
||||
if (de == NULL) return 0;
|
||||
initObjectLRUOrLFU(val);
|
||||
kvstoreDictSetVal(db->keys, slot, de, val);
|
||||
kvstoreDictSetVal(db->keys, dict_index, de, val);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -288,8 +290,8 @@ int dbAddRDBLoad(serverDb *db, sds key, robj *val) {
|
||||
*
|
||||
* The program is aborted if the key was not already present. */
|
||||
static void dbSetValue(serverDb *db, robj *key, robj *val, int overwrite, dictEntry *de) {
|
||||
int slot = getKeySlot(key->ptr);
|
||||
if (!de) de = kvstoreDictFind(db->keys, slot, key->ptr);
|
||||
int dict_index = getKVStoreIndexForKey(key->ptr);
|
||||
if (!de) de = kvstoreDictFind(db->keys, dict_index, key->ptr);
|
||||
serverAssertWithInfo(NULL, key, de != NULL);
|
||||
robj *old = dictGetVal(de);
|
||||
|
||||
@@ -309,7 +311,7 @@ static void dbSetValue(serverDb *db, robj *key, robj *val, int overwrite, dictEn
|
||||
/* Because of RM_StringDMA, old may be changed, so we need get old again */
|
||||
old = dictGetVal(de);
|
||||
}
|
||||
kvstoreDictSetVal(db->keys, slot, de, val);
|
||||
kvstoreDictSetVal(db->keys, dict_index, de, val);
|
||||
/* For efficiency, let the I/O thread that allocated an object also deallocate it. */
|
||||
if (tryOffloadFreeObjToIOThreads(old) == C_OK) {
|
||||
/* OK */
|
||||
@@ -404,8 +406,8 @@ robj *dbRandomKey(serverDb *db) {
|
||||
int dbGenericDelete(serverDb *db, robj *key, int async, int flags) {
|
||||
dictEntry **plink;
|
||||
int table;
|
||||
int slot = getKeySlot(key->ptr);
|
||||
dictEntry *de = kvstoreDictTwoPhaseUnlinkFind(db->keys, slot, key->ptr, &plink, &table);
|
||||
int dict_index = getKVStoreIndexForKey(key->ptr);
|
||||
dictEntry *de = kvstoreDictTwoPhaseUnlinkFind(db->keys, dict_index, key->ptr, &plink, &table);
|
||||
if (de) {
|
||||
robj *val = dictGetVal(de);
|
||||
/* RM_StringDMA may call dbUnshareStringValue which may free val, so we
|
||||
@@ -421,13 +423,13 @@ int dbGenericDelete(serverDb *db, robj *key, int async, int flags) {
|
||||
if (async) {
|
||||
/* Because of dbUnshareStringValue, the val in de may change. */
|
||||
freeObjAsync(key, dictGetVal(de), db->id);
|
||||
kvstoreDictSetVal(db->keys, slot, de, NULL);
|
||||
kvstoreDictSetVal(db->keys, dict_index, de, NULL);
|
||||
}
|
||||
/* Deleting an entry from the expires dict will not free the sds of
|
||||
* the key, because it is shared with the main dictionary. */
|
||||
kvstoreDictDelete(db->expires, slot, key->ptr);
|
||||
kvstoreDictDelete(db->expires, dict_index, key->ptr);
|
||||
|
||||
kvstoreDictTwoPhaseUnlinkFree(db->keys, slot, de, plink, table);
|
||||
kvstoreDictTwoPhaseUnlinkFree(db->keys, dict_index, de, plink, table);
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
@@ -584,8 +586,8 @@ serverDb *initTempDb(void) {
|
||||
serverDb *tempDb = zcalloc(sizeof(serverDb) * server.dbnum);
|
||||
for (int i = 0; i < server.dbnum; i++) {
|
||||
tempDb[i].id = i;
|
||||
tempDb[i].keys = kvstoreCreate(&dbDictType, slot_count_bits, flags);
|
||||
tempDb[i].expires = kvstoreCreate(&dbExpiresDictType, slot_count_bits, flags);
|
||||
tempDb[i].keys = kvstoreCreate(&kvstoreKeysDictType, slot_count_bits, flags);
|
||||
tempDb[i].expires = kvstoreCreate(&kvstoreExpiresDictType, slot_count_bits, flags);
|
||||
}
|
||||
|
||||
return tempDb;
|
||||
@@ -1278,7 +1280,7 @@ void shutdownCommand(client *c) {
|
||||
}
|
||||
|
||||
blockClientShutdown(c);
|
||||
if (prepareForShutdown(flags) == C_OK) exit(0);
|
||||
if (prepareForShutdown(c, flags) == C_OK) exit(0);
|
||||
/* If we're here, then shutdown is ongoing (the client is still blocked) or
|
||||
* failed (the client has received an error). */
|
||||
}
|
||||
@@ -1664,7 +1666,7 @@ void swapdbCommand(client *c) {
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
int removeExpire(serverDb *db, robj *key) {
|
||||
return kvstoreDictDelete(db->expires, getKeySlot(key->ptr), key->ptr) == DICT_OK;
|
||||
return kvstoreDictDelete(db->expires, getKVStoreIndexForKey(key->ptr), key->ptr) == DICT_OK;
|
||||
}
|
||||
|
||||
/* Set an expire to the specified key. If the expire is set in the context
|
||||
@@ -1675,10 +1677,10 @@ void setExpire(client *c, serverDb *db, robj *key, long long when) {
|
||||
dictEntry *kde, *de, *existing;
|
||||
|
||||
/* Reuse the sds from the main dict in the expire dict */
|
||||
int slot = getKeySlot(key->ptr);
|
||||
kde = kvstoreDictFind(db->keys, slot, key->ptr);
|
||||
int dict_index = getKVStoreIndexForKey(key->ptr);
|
||||
kde = kvstoreDictFind(db->keys, dict_index, key->ptr);
|
||||
serverAssertWithInfo(NULL, key, kde != NULL);
|
||||
de = kvstoreDictAddRaw(db->expires, slot, dictGetKey(kde), &existing);
|
||||
de = kvstoreDictAddRaw(db->expires, dict_index, dictGetKey(kde), &existing);
|
||||
if (existing) {
|
||||
dictSetSignedIntegerVal(existing, when);
|
||||
} else {
|
||||
@@ -1712,6 +1714,19 @@ void deleteExpiredKeyAndPropagate(serverDb *db, robj *keyobj) {
|
||||
server.stat_expiredkeys++;
|
||||
}
|
||||
|
||||
/* Delete the specified expired key from overwriting and propagate the DEL or UNLINK. */
|
||||
void deleteExpiredKeyFromOverwriteAndPropagate(client *c, robj *keyobj) {
|
||||
int deleted = dbGenericDelete(c->db, keyobj, server.lazyfree_lazy_expire, DB_FLAG_KEY_EXPIRED);
|
||||
serverAssertWithInfo(c, keyobj, deleted);
|
||||
server.dirty++;
|
||||
|
||||
/* Replicate/AOF this as an explicit DEL or UNLINK. */
|
||||
robj *aux = server.lazyfree_lazy_expire ? shared.unlink : shared.del;
|
||||
rewriteClientCommandVector(c, 2, aux, keyobj);
|
||||
signalModifiedKey(c, c->db, keyobj);
|
||||
notifyKeyspaceEvent(NOTIFY_GENERIC, "del", keyobj, c->db->id);
|
||||
}
|
||||
|
||||
/* Propagate an implicit key deletion into replicas and the AOF file.
|
||||
* When a key was deleted in the primary by eviction, expiration or a similar
|
||||
* mechanism a DEL/UNLINK operation for this key is sent
|
||||
@@ -1883,7 +1898,7 @@ int dbExpandExpires(serverDb *db, uint64_t db_size, int try_expand) {
|
||||
}
|
||||
|
||||
static dictEntry *dbFindGeneric(kvstore *kvs, void *key) {
|
||||
return kvstoreDictFind(kvs, getKeySlot(key), key);
|
||||
return kvstoreDictFind(kvs, server.cluster_enabled ? getKeySlot(key) : 0, key);
|
||||
}
|
||||
|
||||
dictEntry *dbFind(serverDb *db, void *key) {
|
||||
|
||||
+53
-21
@@ -1,6 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2020, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* Copyright (c) 2020, Redis Labs, Inc
|
||||
* Copyright (c) 2009-2020, Redis Ltd.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -38,6 +37,7 @@
|
||||
#include "cluster.h"
|
||||
#include "threads_mngr.h"
|
||||
#include "io_threads.h"
|
||||
#include "sds.h"
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <signal.h>
|
||||
@@ -426,8 +426,10 @@ void debugCommand(client *c) {
|
||||
"MALLCTL-STR <key> [<val>]",
|
||||
" Get or set a malloc tuning string.",
|
||||
#endif
|
||||
"OBJECT <key>",
|
||||
"OBJECT <key> [fast]",
|
||||
" Show low level info about `key` and associated value.",
|
||||
" Some fields of the default behavior may be time consuming to fetch,",
|
||||
" and `fast` can be passed to avoid fetching them.",
|
||||
"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>",
|
||||
@@ -520,7 +522,7 @@ void debugCommand(client *c) {
|
||||
int flags = !strcasecmp(c->argv[1]->ptr, "restart")
|
||||
? (RESTART_SERVER_GRACEFULLY | RESTART_SERVER_CONFIG_REWRITE)
|
||||
: RESTART_SERVER_NONE;
|
||||
restartServer(flags, delay);
|
||||
restartServer(c, flags, delay);
|
||||
addReplyError(c, "failed to restart the server. Check server logs.");
|
||||
} else if (!strcasecmp(c->argv[1]->ptr, "oom")) {
|
||||
void *ptr = zmalloc(SIZE_MAX / 2); /* Should trigger an out of memory. */
|
||||
@@ -604,11 +606,14 @@ void debugCommand(client *c) {
|
||||
} 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);
|
||||
addReply(c, shared.ok);
|
||||
} else if (!strcasecmp(c->argv[1]->ptr, "object") && c->argc == 3) {
|
||||
} else if (!strcasecmp(c->argv[1]->ptr, "object") && (c->argc == 3 || c->argc == 4)) {
|
||||
dictEntry *de;
|
||||
robj *val;
|
||||
char *strenc;
|
||||
|
||||
int fast = 0;
|
||||
if (c->argc == 4 && !strcasecmp(c->argv[3]->ptr, "fast")) fast = 1;
|
||||
|
||||
if ((de = dbFind(c->db, c->argv[2]->ptr)) == NULL) {
|
||||
addReplyErrorObject(c, shared.nokeyerr);
|
||||
return;
|
||||
@@ -639,22 +644,27 @@ void debugCommand(client *c) {
|
||||
used = snprintf(nextra, remaining, " ql_compressed:%d", compressed);
|
||||
nextra += used;
|
||||
remaining -= used;
|
||||
/* Add total uncompressed size */
|
||||
unsigned long sz = 0;
|
||||
for (quicklistNode *node = ql->head; node; node = node->next) {
|
||||
sz += node->sz;
|
||||
if (!fast) {
|
||||
/* Add total uncompressed size */
|
||||
unsigned long sz = 0;
|
||||
for (quicklistNode *node = ql->head; node; node = node->next) {
|
||||
sz += node->sz;
|
||||
}
|
||||
used = snprintf(nextra, remaining, " ql_uncompressed_size:%lu", sz);
|
||||
nextra += used;
|
||||
remaining -= used;
|
||||
}
|
||||
used = snprintf(nextra, remaining, " ql_uncompressed_size:%lu", sz);
|
||||
nextra += used;
|
||||
remaining -= used;
|
||||
}
|
||||
|
||||
addReplyStatusFormat(c,
|
||||
"Value at:%p refcount:%d "
|
||||
"encoding:%s serializedlength:%zu "
|
||||
"lru:%d lru_seconds_idle:%llu%s",
|
||||
(void *)val, val->refcount, strenc, rdbSavedObjectLen(val, c->argv[2], c->db->id),
|
||||
val->lru, estimateObjectIdleTime(val) / 1000, extra);
|
||||
sds s = sdsempty();
|
||||
s = sdscatprintf(s, "Value at:%p refcount:%d encoding:%s", (void *)val, val->refcount, strenc);
|
||||
if (!fast) s = sdscatprintf(s, " serializedlength:%zu", rdbSavedObjectLen(val, c->argv[2], c->db->id));
|
||||
/* Either lru or lfu field could work correctly which depends on server.maxmemory_policy. */
|
||||
s = sdscatprintf(s, " lru:%d lru_seconds_idle:%llu", val->lru, estimateObjectIdleTime(val) / 1000);
|
||||
s = sdscatprintf(s, " lfu_freq:%lu lfu_access_time_minutes:%u", LFUDecrAndReturn(val), val->lru >> 8);
|
||||
s = sdscatprintf(s, "%s", extra);
|
||||
addReplyStatusLength(c, s, sdslen(s));
|
||||
sdsfree(s);
|
||||
} else if (!strcasecmp(c->argv[1]->ptr, "sdslen") && c->argc == 3) {
|
||||
dictEntry *de;
|
||||
robj *val;
|
||||
@@ -673,7 +683,7 @@ void debugCommand(client *c) {
|
||||
addReplyStatusFormat(c,
|
||||
"key_sds_len:%lld, key_sds_avail:%lld, key_zmalloc: %lld, "
|
||||
"val_sds_len:%lld, val_sds_avail:%lld, val_zmalloc: %lld",
|
||||
(long long)sdslen(key), (long long)sdsavail(key), (long long)sdsZmallocSize(key),
|
||||
(long long)sdslen(key), (long long)sdsavail(key), (long long)sdsAllocSize(key),
|
||||
(long long)sdslen(val->ptr), (long long)sdsavail(val->ptr),
|
||||
(long long)getStringObjectSdsUsedMemory(val));
|
||||
}
|
||||
@@ -1031,6 +1041,16 @@ __attribute__((noinline)) void _serverAssert(const char *estr, const char *file,
|
||||
bugReportEnd(0, 0);
|
||||
}
|
||||
|
||||
/* Checks if the argument at the given index should be redacted from logs. */
|
||||
int shouldRedactArg(const client *c, int idx) {
|
||||
serverAssert(idx < c->argc);
|
||||
/* Don't redact if the config is disabled */
|
||||
if (!server.hide_user_data_from_log) return 0;
|
||||
/* first_sensitive_arg_idx value should be changed based on the command type. */
|
||||
int first_sensitive_arg_idx = 1;
|
||||
return idx >= first_sensitive_arg_idx;
|
||||
}
|
||||
|
||||
void _serverAssertPrintClientInfo(const client *c) {
|
||||
int j;
|
||||
char conninfo[CONN_INFO_LEN];
|
||||
@@ -1041,6 +1061,10 @@ void _serverAssertPrintClientInfo(const client *c) {
|
||||
serverLog(LL_WARNING, "client->conn = %s", connGetInfo(c->conn, conninfo, sizeof(conninfo)));
|
||||
serverLog(LL_WARNING, "client->argc = %d", c->argc);
|
||||
for (j = 0; j < c->argc; j++) {
|
||||
if (shouldRedactArg(c, j)) {
|
||||
serverLog(LL_WARNING, "client->argv[%d]: %zu bytes", j, sdslen((sds)c->argv[j]->ptr));
|
||||
continue;
|
||||
}
|
||||
char buf[128];
|
||||
char *arg;
|
||||
|
||||
@@ -1241,6 +1265,10 @@ static void *getAndSetMcontextEip(ucontext_t *uc, void *eip) {
|
||||
|
||||
VALKEY_NO_SANITIZE("address")
|
||||
void logStackContent(void **sp) {
|
||||
if (server.hide_user_data_from_log) {
|
||||
serverLog(LL_NOTICE, "hide-user-data-from-log is on, skip logging stack content to avoid spilling user data.");
|
||||
return;
|
||||
}
|
||||
int i;
|
||||
for (i = 15; i >= 0; i--) {
|
||||
unsigned long addr = (unsigned long)sp + i;
|
||||
@@ -1816,7 +1844,7 @@ void logServerInfo(void) {
|
||||
}
|
||||
serverLogRaw(LL_WARNING | LL_RAW, infostring);
|
||||
serverLogRaw(LL_WARNING | LL_RAW, "\n------ CLIENT LIST OUTPUT ------\n");
|
||||
clients = getAllClientsInfoString(-1);
|
||||
clients = getAllClientsInfoString(-1, server.hide_user_data_from_log);
|
||||
serverLogRaw(LL_WARNING | LL_RAW, clients);
|
||||
sdsfree(infostring);
|
||||
sdsfree(clients);
|
||||
@@ -1851,11 +1879,15 @@ void logCurrentClient(client *cc, const char *title) {
|
||||
int j;
|
||||
|
||||
serverLog(LL_WARNING | LL_RAW, "\n------ %s CLIENT INFO ------\n", title);
|
||||
client = catClientInfoString(sdsempty(), cc);
|
||||
client = catClientInfoString(sdsempty(), cc, server.hide_user_data_from_log);
|
||||
serverLog(LL_WARNING | LL_RAW, "%s\n", client);
|
||||
sdsfree(client);
|
||||
serverLog(LL_WARNING | LL_RAW, "argc: '%d'\n", cc->argc);
|
||||
for (j = 0; j < cc->argc; j++) {
|
||||
if (shouldRedactArg(cc, j)) {
|
||||
serverLog(LL_WARNING | LL_RAW, "argv[%d]: %zu bytes\n", j, sdslen((sds)cc->argv[j]->ptr));
|
||||
continue;
|
||||
}
|
||||
robj *decoded;
|
||||
decoded = getDecodedObject(cc->argv[j]);
|
||||
sds repr = sdscatrepr(sdsempty(), decoded->ptr, min(sdslen(decoded->ptr), 128));
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*
|
||||
* Copyright (c) 2016, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* Copyright (c) 2016, Redis Ltd.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@
|
||||
* We do that by scanning the keyspace and for each pointer we have, we can try to
|
||||
* ask the allocator if moving it to a new address will help reduce fragmentation.
|
||||
*
|
||||
* Copyright (c) 2020, Redis Labs, Inc
|
||||
* Copyright (c) 2020, Redis Ltd.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
||||
+194
-450
File diff suppressed because it is too large
Load Diff
+2
-9
@@ -5,7 +5,7 @@
|
||||
* tables of power of two in size are used, collisions are handled by
|
||||
* chaining. See the source code for more information... :)
|
||||
*
|
||||
* Copyright (c) 2006-2012, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* Copyright (c) 2006-2012, Redis Ltd.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -70,10 +70,6 @@ typedef struct dictType {
|
||||
* computing the length of the key + header when buf is NULL. */
|
||||
size_t (*embedKey)(unsigned char *buf, size_t buf_len, const void *key, unsigned char *header_size);
|
||||
|
||||
|
||||
/* Data */
|
||||
void *userdata;
|
||||
|
||||
/* Flags */
|
||||
/* The 'no_value' flag, if set, indicates that values are not used, i.e. the
|
||||
* dict is a set. When this flag is set, it's not possible to access the
|
||||
@@ -229,6 +225,7 @@ void dictInitIterator(dictIterator *iter, dict *d);
|
||||
void dictInitSafeIterator(dictIterator *iter, dict *d);
|
||||
void dictResetIterator(dictIterator *iter);
|
||||
dictEntry *dictNext(dictIterator *iter);
|
||||
dictEntry *dictGetNext(const dictEntry *de);
|
||||
void dictReleaseIterator(dictIterator *iter);
|
||||
dictEntry *dictGetRandomKey(dict *d);
|
||||
dictEntry *dictGetFairRandomKey(dict *d);
|
||||
@@ -253,8 +250,4 @@ dictStats *dictGetStatsHt(dict *d, int htidx, int full);
|
||||
void dictCombineStats(dictStats *from, dictStats *into);
|
||||
void dictFreeStats(dictStats *stats);
|
||||
|
||||
#ifdef SERVER_TEST
|
||||
int dictTest(int argc, char *argv[], int flags);
|
||||
#endif
|
||||
|
||||
#endif /* __DICT_H */
|
||||
|
||||
+1
-1
@@ -13,7 +13,7 @@
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* Copyright (c) 2011-2012, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* Copyright (c) 2011-2012, Redis Ltd.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* Copyright (c) 2011-2012, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* Copyright (c) 2011-2012, Redis Ltd.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
||||
+5
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2012, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* Copyright (c) 2009-2012, Redis Ltd.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -42,6 +42,7 @@
|
||||
#include "monotonic.h"
|
||||
#include "resp_parser.h"
|
||||
#include "script_lua.h"
|
||||
#include "sds.h"
|
||||
|
||||
#include <lua.h>
|
||||
#include <lauxlib.h>
|
||||
@@ -259,6 +260,7 @@ void scriptingInit(int setup) {
|
||||
if (lctx.lua_client == NULL) {
|
||||
lctx.lua_client = createClient(NULL);
|
||||
lctx.lua_client->flag.script = 1;
|
||||
lctx.lua_client->flag.fake = 1;
|
||||
|
||||
/* We do not want to allow blocking commands inside Lua */
|
||||
lctx.lua_client->flag.deny_blocking = 1;
|
||||
@@ -490,7 +492,7 @@ sds luaCreateFunction(client *c, robj *body, int evalsha) {
|
||||
l->node = luaScriptsLRUAdd(c, sha, evalsha);
|
||||
int retval = dictAdd(lctx.lua_scripts, sha, l);
|
||||
serverAssertWithInfo(c ? c : lctx.lua_client, NULL, retval == DICT_OK);
|
||||
lctx.lua_scripts_mem += sdsZmallocSize(sha) + getStringObjectSdsUsedMemory(body);
|
||||
lctx.lua_scripts_mem += sdsAllocSize(sha) + getStringObjectSdsUsedMemory(body);
|
||||
incrRefCount(body);
|
||||
return sha;
|
||||
}
|
||||
@@ -516,7 +518,7 @@ void luaDeleteFunction(client *c, sds sha) {
|
||||
/* We only delete `EVAL` scripts, which must exist in the LRU list. */
|
||||
serverAssert(l->node);
|
||||
listDelNode(lctx.lua_scripts_lru_list, l->node);
|
||||
lctx.lua_scripts_mem -= sdsZmallocSize(sha) + getStringObjectSdsUsedMemory(l->body);
|
||||
lctx.lua_scripts_mem -= sdsAllocSize(sha) + getStringObjectSdsUsedMemory(l->body);
|
||||
dictFreeUnlinkedEntry(lctx.lua_scripts, de);
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* Copyright (c) 2009-2016, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* Copyright (c) 2009-2016, Redis Ltd.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
||||
+2
-12
@@ -2,7 +2,7 @@
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* Copyright (c) 2009-2016, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* Copyright (c) 2009-2016, Redis Ltd.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -668,17 +668,7 @@ void expireGenericCommand(client *c, long long basetime, int unit) {
|
||||
}
|
||||
|
||||
if (checkAlreadyExpired(when)) {
|
||||
robj *aux;
|
||||
|
||||
int deleted = dbGenericDelete(c->db, key, server.lazyfree_lazy_expire, DB_FLAG_KEY_EXPIRED);
|
||||
serverAssertWithInfo(c, key, deleted);
|
||||
server.dirty++;
|
||||
|
||||
/* Replicate/AOF this as an explicit DEL or UNLINK. */
|
||||
aux = server.lazyfree_lazy_expire ? shared.unlink : shared.del;
|
||||
rewriteClientCommandVector(c, 2, aux, key);
|
||||
signalModifiedKey(c, c->db, key);
|
||||
notifyKeyspaceEvent(NOTIFY_GENERIC, "del", key, c->db->id);
|
||||
deleteExpiredKeyFromOverwriteAndPropagate(c, key);
|
||||
addReply(c, shared.cone);
|
||||
return;
|
||||
} else {
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2012, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* Copyright (c) 2009-2012, Redis Ltd.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
||||
+82
-2
@@ -44,9 +44,9 @@
|
||||
/* Everything below this line is automatically generated by
|
||||
* generate-fmtargs.py. Do not manually edit. */
|
||||
|
||||
#define ARG_N(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, _83, _84, _85, _86, _87, _88, _89, _90, _91, _92, _93, _94, _95, _96, _97, _98, _99, _100, _101, _102, _103, _104, _105, _106, _107, _108, _109, _110, _111, _112, _113, _114, _115, _116, _117, _118, _119, _120, N, ...) N
|
||||
#define ARG_N(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, _83, _84, _85, _86, _87, _88, _89, _90, _91, _92, _93, _94, _95, _96, _97, _98, _99, _100, _101, _102, _103, _104, _105, _106, _107, _108, _109, _110, _111, _112, _113, _114, _115, _116, _117, _118, _119, _120, _121, _122, _123, _124, _125, _126, _127, _128, _129, _130, _131, _132, _133, _134, _135, _136, _137, _138, _139, _140, _141, _142, _143, _144, _145, _146, _147, _148, _149, _150, _151, _152, _153, _154, _155, _156, _157, _158, _159, _160, _161, _162, _163, _164, _165, _166, _167, _168, _169, _170, _171, _172, _173, _174, _175, _176, _177, _178, _179, _180, _181, _182, _183, _184, _185, _186, _187, _188, _189, _190, _191, _192, _193, _194, _195, _196, _197, _198, _199, _200, N, ...) N
|
||||
|
||||
#define RSEQ_N() 120, 119, 118, 117, 116, 115, 114, 113, 112, 111, 110, 109, 108, 107, 106, 105, 104, 103, 102, 101, 100, 99, 98, 97, 96, 95, 94, 93, 92, 91, 90, 89, 88, 87, 86, 85, 84, 83, 82, 81, 80, 79, 78, 77, 76, 75, 74, 73, 72, 71, 70, 69, 68, 67, 66, 65, 64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0
|
||||
#define RSEQ_N() 200, 199, 198, 197, 196, 195, 194, 193, 192, 191, 190, 189, 188, 187, 186, 185, 184, 183, 182, 181, 180, 179, 178, 177, 176, 175, 174, 173, 172, 171, 170, 169, 168, 167, 166, 165, 164, 163, 162, 161, 160, 159, 158, 157, 156, 155, 154, 153, 152, 151, 150, 149, 148, 147, 146, 145, 144, 143, 142, 141, 140, 139, 138, 137, 136, 135, 134, 133, 132, 131, 130, 129, 128, 127, 126, 125, 124, 123, 122, 121, 120, 119, 118, 117, 116, 115, 114, 113, 112, 111, 110, 109, 108, 107, 106, 105, 104, 103, 102, 101, 100, 99, 98, 97, 96, 95, 94, 93, 92, 91, 90, 89, 88, 87, 86, 85, 84, 83, 82, 81, 80, 79, 78, 77, 76, 75, 74, 73, 72, 71, 70, 69, 68, 67, 66, 65, 64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0
|
||||
|
||||
#define COMPACT_FMT_2(fmt, value) fmt
|
||||
#define COMPACT_FMT_4(fmt, value, ...) fmt COMPACT_FMT_2(__VA_ARGS__)
|
||||
@@ -108,6 +108,46 @@
|
||||
#define COMPACT_FMT_116(fmt, value, ...) fmt COMPACT_FMT_114(__VA_ARGS__)
|
||||
#define COMPACT_FMT_118(fmt, value, ...) fmt COMPACT_FMT_116(__VA_ARGS__)
|
||||
#define COMPACT_FMT_120(fmt, value, ...) fmt COMPACT_FMT_118(__VA_ARGS__)
|
||||
#define COMPACT_FMT_122(fmt, value, ...) fmt COMPACT_FMT_120(__VA_ARGS__)
|
||||
#define COMPACT_FMT_124(fmt, value, ...) fmt COMPACT_FMT_122(__VA_ARGS__)
|
||||
#define COMPACT_FMT_126(fmt, value, ...) fmt COMPACT_FMT_124(__VA_ARGS__)
|
||||
#define COMPACT_FMT_128(fmt, value, ...) fmt COMPACT_FMT_126(__VA_ARGS__)
|
||||
#define COMPACT_FMT_130(fmt, value, ...) fmt COMPACT_FMT_128(__VA_ARGS__)
|
||||
#define COMPACT_FMT_132(fmt, value, ...) fmt COMPACT_FMT_130(__VA_ARGS__)
|
||||
#define COMPACT_FMT_134(fmt, value, ...) fmt COMPACT_FMT_132(__VA_ARGS__)
|
||||
#define COMPACT_FMT_136(fmt, value, ...) fmt COMPACT_FMT_134(__VA_ARGS__)
|
||||
#define COMPACT_FMT_138(fmt, value, ...) fmt COMPACT_FMT_136(__VA_ARGS__)
|
||||
#define COMPACT_FMT_140(fmt, value, ...) fmt COMPACT_FMT_138(__VA_ARGS__)
|
||||
#define COMPACT_FMT_142(fmt, value, ...) fmt COMPACT_FMT_140(__VA_ARGS__)
|
||||
#define COMPACT_FMT_144(fmt, value, ...) fmt COMPACT_FMT_142(__VA_ARGS__)
|
||||
#define COMPACT_FMT_146(fmt, value, ...) fmt COMPACT_FMT_144(__VA_ARGS__)
|
||||
#define COMPACT_FMT_148(fmt, value, ...) fmt COMPACT_FMT_146(__VA_ARGS__)
|
||||
#define COMPACT_FMT_150(fmt, value, ...) fmt COMPACT_FMT_148(__VA_ARGS__)
|
||||
#define COMPACT_FMT_152(fmt, value, ...) fmt COMPACT_FMT_150(__VA_ARGS__)
|
||||
#define COMPACT_FMT_154(fmt, value, ...) fmt COMPACT_FMT_152(__VA_ARGS__)
|
||||
#define COMPACT_FMT_156(fmt, value, ...) fmt COMPACT_FMT_154(__VA_ARGS__)
|
||||
#define COMPACT_FMT_158(fmt, value, ...) fmt COMPACT_FMT_156(__VA_ARGS__)
|
||||
#define COMPACT_FMT_160(fmt, value, ...) fmt COMPACT_FMT_158(__VA_ARGS__)
|
||||
#define COMPACT_FMT_162(fmt, value, ...) fmt COMPACT_FMT_160(__VA_ARGS__)
|
||||
#define COMPACT_FMT_164(fmt, value, ...) fmt COMPACT_FMT_162(__VA_ARGS__)
|
||||
#define COMPACT_FMT_166(fmt, value, ...) fmt COMPACT_FMT_164(__VA_ARGS__)
|
||||
#define COMPACT_FMT_168(fmt, value, ...) fmt COMPACT_FMT_166(__VA_ARGS__)
|
||||
#define COMPACT_FMT_170(fmt, value, ...) fmt COMPACT_FMT_168(__VA_ARGS__)
|
||||
#define COMPACT_FMT_172(fmt, value, ...) fmt COMPACT_FMT_170(__VA_ARGS__)
|
||||
#define COMPACT_FMT_174(fmt, value, ...) fmt COMPACT_FMT_172(__VA_ARGS__)
|
||||
#define COMPACT_FMT_176(fmt, value, ...) fmt COMPACT_FMT_174(__VA_ARGS__)
|
||||
#define COMPACT_FMT_178(fmt, value, ...) fmt COMPACT_FMT_176(__VA_ARGS__)
|
||||
#define COMPACT_FMT_180(fmt, value, ...) fmt COMPACT_FMT_178(__VA_ARGS__)
|
||||
#define COMPACT_FMT_182(fmt, value, ...) fmt COMPACT_FMT_180(__VA_ARGS__)
|
||||
#define COMPACT_FMT_184(fmt, value, ...) fmt COMPACT_FMT_182(__VA_ARGS__)
|
||||
#define COMPACT_FMT_186(fmt, value, ...) fmt COMPACT_FMT_184(__VA_ARGS__)
|
||||
#define COMPACT_FMT_188(fmt, value, ...) fmt COMPACT_FMT_186(__VA_ARGS__)
|
||||
#define COMPACT_FMT_190(fmt, value, ...) fmt COMPACT_FMT_188(__VA_ARGS__)
|
||||
#define COMPACT_FMT_192(fmt, value, ...) fmt COMPACT_FMT_190(__VA_ARGS__)
|
||||
#define COMPACT_FMT_194(fmt, value, ...) fmt COMPACT_FMT_192(__VA_ARGS__)
|
||||
#define COMPACT_FMT_196(fmt, value, ...) fmt COMPACT_FMT_194(__VA_ARGS__)
|
||||
#define COMPACT_FMT_198(fmt, value, ...) fmt COMPACT_FMT_196(__VA_ARGS__)
|
||||
#define COMPACT_FMT_200(fmt, value, ...) fmt COMPACT_FMT_198(__VA_ARGS__)
|
||||
|
||||
#define COMPACT_VALUES_2(fmt, value) value
|
||||
#define COMPACT_VALUES_4(fmt, value, ...) value, COMPACT_VALUES_2(__VA_ARGS__)
|
||||
@@ -169,5 +209,45 @@
|
||||
#define COMPACT_VALUES_116(fmt, value, ...) value, COMPACT_VALUES_114(__VA_ARGS__)
|
||||
#define COMPACT_VALUES_118(fmt, value, ...) value, COMPACT_VALUES_116(__VA_ARGS__)
|
||||
#define COMPACT_VALUES_120(fmt, value, ...) value, COMPACT_VALUES_118(__VA_ARGS__)
|
||||
#define COMPACT_VALUES_122(fmt, value, ...) value, COMPACT_VALUES_120(__VA_ARGS__)
|
||||
#define COMPACT_VALUES_124(fmt, value, ...) value, COMPACT_VALUES_122(__VA_ARGS__)
|
||||
#define COMPACT_VALUES_126(fmt, value, ...) value, COMPACT_VALUES_124(__VA_ARGS__)
|
||||
#define COMPACT_VALUES_128(fmt, value, ...) value, COMPACT_VALUES_126(__VA_ARGS__)
|
||||
#define COMPACT_VALUES_130(fmt, value, ...) value, COMPACT_VALUES_128(__VA_ARGS__)
|
||||
#define COMPACT_VALUES_132(fmt, value, ...) value, COMPACT_VALUES_130(__VA_ARGS__)
|
||||
#define COMPACT_VALUES_134(fmt, value, ...) value, COMPACT_VALUES_132(__VA_ARGS__)
|
||||
#define COMPACT_VALUES_136(fmt, value, ...) value, COMPACT_VALUES_134(__VA_ARGS__)
|
||||
#define COMPACT_VALUES_138(fmt, value, ...) value, COMPACT_VALUES_136(__VA_ARGS__)
|
||||
#define COMPACT_VALUES_140(fmt, value, ...) value, COMPACT_VALUES_138(__VA_ARGS__)
|
||||
#define COMPACT_VALUES_142(fmt, value, ...) value, COMPACT_VALUES_140(__VA_ARGS__)
|
||||
#define COMPACT_VALUES_144(fmt, value, ...) value, COMPACT_VALUES_142(__VA_ARGS__)
|
||||
#define COMPACT_VALUES_146(fmt, value, ...) value, COMPACT_VALUES_144(__VA_ARGS__)
|
||||
#define COMPACT_VALUES_148(fmt, value, ...) value, COMPACT_VALUES_146(__VA_ARGS__)
|
||||
#define COMPACT_VALUES_150(fmt, value, ...) value, COMPACT_VALUES_148(__VA_ARGS__)
|
||||
#define COMPACT_VALUES_152(fmt, value, ...) value, COMPACT_VALUES_150(__VA_ARGS__)
|
||||
#define COMPACT_VALUES_154(fmt, value, ...) value, COMPACT_VALUES_152(__VA_ARGS__)
|
||||
#define COMPACT_VALUES_156(fmt, value, ...) value, COMPACT_VALUES_154(__VA_ARGS__)
|
||||
#define COMPACT_VALUES_158(fmt, value, ...) value, COMPACT_VALUES_156(__VA_ARGS__)
|
||||
#define COMPACT_VALUES_160(fmt, value, ...) value, COMPACT_VALUES_158(__VA_ARGS__)
|
||||
#define COMPACT_VALUES_162(fmt, value, ...) value, COMPACT_VALUES_160(__VA_ARGS__)
|
||||
#define COMPACT_VALUES_164(fmt, value, ...) value, COMPACT_VALUES_162(__VA_ARGS__)
|
||||
#define COMPACT_VALUES_166(fmt, value, ...) value, COMPACT_VALUES_164(__VA_ARGS__)
|
||||
#define COMPACT_VALUES_168(fmt, value, ...) value, COMPACT_VALUES_166(__VA_ARGS__)
|
||||
#define COMPACT_VALUES_170(fmt, value, ...) value, COMPACT_VALUES_168(__VA_ARGS__)
|
||||
#define COMPACT_VALUES_172(fmt, value, ...) value, COMPACT_VALUES_170(__VA_ARGS__)
|
||||
#define COMPACT_VALUES_174(fmt, value, ...) value, COMPACT_VALUES_172(__VA_ARGS__)
|
||||
#define COMPACT_VALUES_176(fmt, value, ...) value, COMPACT_VALUES_174(__VA_ARGS__)
|
||||
#define COMPACT_VALUES_178(fmt, value, ...) value, COMPACT_VALUES_176(__VA_ARGS__)
|
||||
#define COMPACT_VALUES_180(fmt, value, ...) value, COMPACT_VALUES_178(__VA_ARGS__)
|
||||
#define COMPACT_VALUES_182(fmt, value, ...) value, COMPACT_VALUES_180(__VA_ARGS__)
|
||||
#define COMPACT_VALUES_184(fmt, value, ...) value, COMPACT_VALUES_182(__VA_ARGS__)
|
||||
#define COMPACT_VALUES_186(fmt, value, ...) value, COMPACT_VALUES_184(__VA_ARGS__)
|
||||
#define COMPACT_VALUES_188(fmt, value, ...) value, COMPACT_VALUES_186(__VA_ARGS__)
|
||||
#define COMPACT_VALUES_190(fmt, value, ...) value, COMPACT_VALUES_188(__VA_ARGS__)
|
||||
#define COMPACT_VALUES_192(fmt, value, ...) value, COMPACT_VALUES_190(__VA_ARGS__)
|
||||
#define COMPACT_VALUES_194(fmt, value, ...) value, COMPACT_VALUES_192(__VA_ARGS__)
|
||||
#define COMPACT_VALUES_196(fmt, value, ...) value, COMPACT_VALUES_194(__VA_ARGS__)
|
||||
#define COMPACT_VALUES_198(fmt, value, ...) value, COMPACT_VALUES_196(__VA_ARGS__)
|
||||
#define COMPACT_VALUES_200(fmt, value, ...) value, COMPACT_VALUES_198(__VA_ARGS__)
|
||||
|
||||
#endif
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user