mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-21 15:12:02 +00:00
Merge 'origin/master' into tracing_context_propagation to resolve conflicts
This commit is contained in:
commit
9d63cbe811
4
.github/workflows/backport_branches.yml
vendored
4
.github/workflows/backport_branches.yml
vendored
@ -437,7 +437,7 @@ jobs:
|
||||
cat >> "$GITHUB_ENV" << 'EOF'
|
||||
TEMP_PATH=${{runner.temp}}/stateless_debug
|
||||
REPORTS_PATH=${{runner.temp}}/reports_dir
|
||||
CHECK_NAME=Stateless tests (address)
|
||||
CHECK_NAME=Stateless tests (asan)
|
||||
REPO_COPY=${{runner.temp}}/stateless_debug/ClickHouse
|
||||
KILL_TIMEOUT=10800
|
||||
EOF
|
||||
@ -521,7 +521,7 @@ jobs:
|
||||
cat >> "$GITHUB_ENV" << 'EOF'
|
||||
TEMP_PATH=${{runner.temp}}/stress_thread
|
||||
REPORTS_PATH=${{runner.temp}}/reports_dir
|
||||
CHECK_NAME=Stress test (thread)
|
||||
CHECK_NAME=Stress test (tsan)
|
||||
REPO_COPY=${{runner.temp}}/stress_thread/ClickHouse
|
||||
EOF
|
||||
- name: Download json reports
|
||||
|
46
.github/workflows/master.yml
vendored
46
.github/workflows/master.yml
vendored
@ -1287,7 +1287,7 @@ jobs:
|
||||
cat >> "$GITHUB_ENV" << 'EOF'
|
||||
TEMP_PATH=${{runner.temp}}/stateless_debug
|
||||
REPORTS_PATH=${{runner.temp}}/reports_dir
|
||||
CHECK_NAME=Stateless tests (address)
|
||||
CHECK_NAME=Stateless tests (asan)
|
||||
REPO_COPY=${{runner.temp}}/stateless_debug/ClickHouse
|
||||
KILL_TIMEOUT=10800
|
||||
RUN_BY_HASH_NUM=0
|
||||
@ -1326,7 +1326,7 @@ jobs:
|
||||
cat >> "$GITHUB_ENV" << 'EOF'
|
||||
TEMP_PATH=${{runner.temp}}/stateless_debug
|
||||
REPORTS_PATH=${{runner.temp}}/reports_dir
|
||||
CHECK_NAME=Stateless tests (address)
|
||||
CHECK_NAME=Stateless tests (asan)
|
||||
REPO_COPY=${{runner.temp}}/stateless_debug/ClickHouse
|
||||
KILL_TIMEOUT=10800
|
||||
RUN_BY_HASH_NUM=1
|
||||
@ -1365,7 +1365,7 @@ jobs:
|
||||
cat >> "$GITHUB_ENV" << 'EOF'
|
||||
TEMP_PATH=${{runner.temp}}/stateless_tsan
|
||||
REPORTS_PATH=${{runner.temp}}/reports_dir
|
||||
CHECK_NAME=Stateless tests (thread)
|
||||
CHECK_NAME=Stateless tests (tsan)
|
||||
REPO_COPY=${{runner.temp}}/stateless_tsan/ClickHouse
|
||||
KILL_TIMEOUT=10800
|
||||
RUN_BY_HASH_NUM=0
|
||||
@ -1404,7 +1404,7 @@ jobs:
|
||||
cat >> "$GITHUB_ENV" << 'EOF'
|
||||
TEMP_PATH=${{runner.temp}}/stateless_tsan
|
||||
REPORTS_PATH=${{runner.temp}}/reports_dir
|
||||
CHECK_NAME=Stateless tests (thread)
|
||||
CHECK_NAME=Stateless tests (tsan)
|
||||
REPO_COPY=${{runner.temp}}/stateless_tsan/ClickHouse
|
||||
KILL_TIMEOUT=10800
|
||||
RUN_BY_HASH_NUM=1
|
||||
@ -1443,7 +1443,7 @@ jobs:
|
||||
cat >> "$GITHUB_ENV" << 'EOF'
|
||||
TEMP_PATH=${{runner.temp}}/stateless_tsan
|
||||
REPORTS_PATH=${{runner.temp}}/reports_dir
|
||||
CHECK_NAME=Stateless tests (thread)
|
||||
CHECK_NAME=Stateless tests (tsan)
|
||||
REPO_COPY=${{runner.temp}}/stateless_tsan/ClickHouse
|
||||
KILL_TIMEOUT=10800
|
||||
RUN_BY_HASH_NUM=2
|
||||
@ -1519,7 +1519,7 @@ jobs:
|
||||
cat >> "$GITHUB_ENV" << 'EOF'
|
||||
TEMP_PATH=${{runner.temp}}/stateless_memory
|
||||
REPORTS_PATH=${{runner.temp}}/reports_dir
|
||||
CHECK_NAME=Stateless tests (memory)
|
||||
CHECK_NAME=Stateless tests (msan)
|
||||
REPO_COPY=${{runner.temp}}/stateless_memory/ClickHouse
|
||||
KILL_TIMEOUT=10800
|
||||
RUN_BY_HASH_NUM=0
|
||||
@ -1558,7 +1558,7 @@ jobs:
|
||||
cat >> "$GITHUB_ENV" << 'EOF'
|
||||
TEMP_PATH=${{runner.temp}}/stateless_memory
|
||||
REPORTS_PATH=${{runner.temp}}/reports_dir
|
||||
CHECK_NAME=Stateless tests (memory)
|
||||
CHECK_NAME=Stateless tests (msan)
|
||||
REPO_COPY=${{runner.temp}}/stateless_memory/ClickHouse
|
||||
KILL_TIMEOUT=10800
|
||||
RUN_BY_HASH_NUM=1
|
||||
@ -1597,7 +1597,7 @@ jobs:
|
||||
cat >> "$GITHUB_ENV" << 'EOF'
|
||||
TEMP_PATH=${{runner.temp}}/stateless_memory
|
||||
REPORTS_PATH=${{runner.temp}}/reports_dir
|
||||
CHECK_NAME=Stateless tests (memory)
|
||||
CHECK_NAME=Stateless tests (msan)
|
||||
REPO_COPY=${{runner.temp}}/stateless_memory/ClickHouse
|
||||
KILL_TIMEOUT=10800
|
||||
RUN_BY_HASH_NUM=2
|
||||
@ -1830,7 +1830,7 @@ jobs:
|
||||
cat >> "$GITHUB_ENV" << 'EOF'
|
||||
TEMP_PATH=${{runner.temp}}/stateful_debug
|
||||
REPORTS_PATH=${{runner.temp}}/reports_dir
|
||||
CHECK_NAME=Stateful tests (address)
|
||||
CHECK_NAME=Stateful tests (asan)
|
||||
REPO_COPY=${{runner.temp}}/stateful_debug/ClickHouse
|
||||
KILL_TIMEOUT=3600
|
||||
EOF
|
||||
@ -1867,7 +1867,7 @@ jobs:
|
||||
cat >> "$GITHUB_ENV" << 'EOF'
|
||||
TEMP_PATH=${{runner.temp}}/stateful_tsan
|
||||
REPORTS_PATH=${{runner.temp}}/reports_dir
|
||||
CHECK_NAME=Stateful tests (thread)
|
||||
CHECK_NAME=Stateful tests (tsan)
|
||||
REPO_COPY=${{runner.temp}}/stateful_tsan/ClickHouse
|
||||
KILL_TIMEOUT=3600
|
||||
EOF
|
||||
@ -1904,7 +1904,7 @@ jobs:
|
||||
cat >> "$GITHUB_ENV" << 'EOF'
|
||||
TEMP_PATH=${{runner.temp}}/stateful_msan
|
||||
REPORTS_PATH=${{runner.temp}}/reports_dir
|
||||
CHECK_NAME=Stateful tests (memory)
|
||||
CHECK_NAME=Stateful tests (msan)
|
||||
REPO_COPY=${{runner.temp}}/stateful_msan/ClickHouse
|
||||
KILL_TIMEOUT=3600
|
||||
EOF
|
||||
@ -2018,7 +2018,7 @@ jobs:
|
||||
cat >> "$GITHUB_ENV" << 'EOF'
|
||||
TEMP_PATH=${{runner.temp}}/stress_thread
|
||||
REPORTS_PATH=${{runner.temp}}/reports_dir
|
||||
CHECK_NAME=Stress test (address)
|
||||
CHECK_NAME=Stress test (asan)
|
||||
REPO_COPY=${{runner.temp}}/stress_thread/ClickHouse
|
||||
EOF
|
||||
- name: Download json reports
|
||||
@ -2058,7 +2058,7 @@ jobs:
|
||||
cat >> "$GITHUB_ENV" << 'EOF'
|
||||
TEMP_PATH=${{runner.temp}}/stress_thread
|
||||
REPORTS_PATH=${{runner.temp}}/reports_dir
|
||||
CHECK_NAME=Stress test (thread)
|
||||
CHECK_NAME=Stress test (tsan)
|
||||
REPO_COPY=${{runner.temp}}/stress_thread/ClickHouse
|
||||
EOF
|
||||
- name: Download json reports
|
||||
@ -2094,7 +2094,7 @@ jobs:
|
||||
cat >> "$GITHUB_ENV" << 'EOF'
|
||||
TEMP_PATH=${{runner.temp}}/stress_memory
|
||||
REPORTS_PATH=${{runner.temp}}/reports_dir
|
||||
CHECK_NAME=Stress test (memory)
|
||||
CHECK_NAME=Stress test (msan)
|
||||
REPO_COPY=${{runner.temp}}/stress_memory/ClickHouse
|
||||
EOF
|
||||
- name: Download json reports
|
||||
@ -2130,7 +2130,7 @@ jobs:
|
||||
cat >> "$GITHUB_ENV" << 'EOF'
|
||||
TEMP_PATH=${{runner.temp}}/stress_undefined
|
||||
REPORTS_PATH=${{runner.temp}}/reports_dir
|
||||
CHECK_NAME=Stress test (undefined)
|
||||
CHECK_NAME=Stress test (ubsan)
|
||||
REPO_COPY=${{runner.temp}}/stress_undefined/ClickHouse
|
||||
EOF
|
||||
- name: Download json reports
|
||||
@ -2319,7 +2319,7 @@ jobs:
|
||||
cat >> "$GITHUB_ENV" << 'EOF'
|
||||
TEMP_PATH=${{runner.temp}}/integration_tests_tsan
|
||||
REPORTS_PATH=${{runner.temp}}/reports_dir
|
||||
CHECK_NAME=Integration tests (thread)
|
||||
CHECK_NAME=Integration tests (tsan)
|
||||
REPO_COPY=${{runner.temp}}/integration_tests_tsan/ClickHouse
|
||||
RUN_BY_HASH_NUM=0
|
||||
RUN_BY_HASH_TOTAL=4
|
||||
@ -2357,7 +2357,7 @@ jobs:
|
||||
cat >> "$GITHUB_ENV" << 'EOF'
|
||||
TEMP_PATH=${{runner.temp}}/integration_tests_tsan
|
||||
REPORTS_PATH=${{runner.temp}}/reports_dir
|
||||
CHECK_NAME=Integration tests (thread)
|
||||
CHECK_NAME=Integration tests (tsan)
|
||||
REPO_COPY=${{runner.temp}}/integration_tests_tsan/ClickHouse
|
||||
RUN_BY_HASH_NUM=1
|
||||
RUN_BY_HASH_TOTAL=4
|
||||
@ -2395,7 +2395,7 @@ jobs:
|
||||
cat >> "$GITHUB_ENV" << 'EOF'
|
||||
TEMP_PATH=${{runner.temp}}/integration_tests_tsan
|
||||
REPORTS_PATH=${{runner.temp}}/reports_dir
|
||||
CHECK_NAME=Integration tests (thread)
|
||||
CHECK_NAME=Integration tests (tsan)
|
||||
REPO_COPY=${{runner.temp}}/integration_tests_tsan/ClickHouse
|
||||
RUN_BY_HASH_NUM=2
|
||||
RUN_BY_HASH_TOTAL=4
|
||||
@ -2433,7 +2433,7 @@ jobs:
|
||||
cat >> "$GITHUB_ENV" << 'EOF'
|
||||
TEMP_PATH=${{runner.temp}}/integration_tests_tsan
|
||||
REPORTS_PATH=${{runner.temp}}/reports_dir
|
||||
CHECK_NAME=Integration tests (thread)
|
||||
CHECK_NAME=Integration tests (tsan)
|
||||
REPO_COPY=${{runner.temp}}/integration_tests_tsan/ClickHouse
|
||||
RUN_BY_HASH_NUM=3
|
||||
RUN_BY_HASH_TOTAL=4
|
||||
@ -2550,7 +2550,7 @@ jobs:
|
||||
cat >> "$GITHUB_ENV" << 'EOF'
|
||||
TEMP_PATH=${{runner.temp}}/ast_fuzzer_asan
|
||||
REPORTS_PATH=${{runner.temp}}/reports_dir
|
||||
CHECK_NAME=AST fuzzer (ASan)
|
||||
CHECK_NAME=AST fuzzer (asan)
|
||||
REPO_COPY=${{runner.temp}}/ast_fuzzer_asan/ClickHouse
|
||||
EOF
|
||||
- name: Download json reports
|
||||
@ -2586,7 +2586,7 @@ jobs:
|
||||
cat >> "$GITHUB_ENV" << 'EOF'
|
||||
TEMP_PATH=${{runner.temp}}/ast_fuzzer_tsan
|
||||
REPORTS_PATH=${{runner.temp}}/reports_dir
|
||||
CHECK_NAME=AST fuzzer (TSan)
|
||||
CHECK_NAME=AST fuzzer (tsan)
|
||||
REPO_COPY=${{runner.temp}}/ast_fuzzer_tsan/ClickHouse
|
||||
EOF
|
||||
- name: Download json reports
|
||||
@ -2622,7 +2622,7 @@ jobs:
|
||||
cat >> "$GITHUB_ENV" << 'EOF'
|
||||
TEMP_PATH=${{runner.temp}}/ast_fuzzer_ubsan
|
||||
REPORTS_PATH=${{runner.temp}}/reports_dir
|
||||
CHECK_NAME=AST fuzzer (UBSan)
|
||||
CHECK_NAME=AST fuzzer (ubsan)
|
||||
REPO_COPY=${{runner.temp}}/ast_fuzzer_ubsan/ClickHouse
|
||||
EOF
|
||||
- name: Download json reports
|
||||
@ -2658,7 +2658,7 @@ jobs:
|
||||
cat >> "$GITHUB_ENV" << 'EOF'
|
||||
TEMP_PATH=${{runner.temp}}/ast_fuzzer_msan
|
||||
REPORTS_PATH=${{runner.temp}}/reports_dir
|
||||
CHECK_NAME=AST fuzzer (MSan)
|
||||
CHECK_NAME=AST fuzzer (msan)
|
||||
REPO_COPY=${{runner.temp}}/ast_fuzzer_msan/ClickHouse
|
||||
EOF
|
||||
- name: Download json reports
|
||||
|
48
.github/workflows/pull_request.yml
vendored
48
.github/workflows/pull_request.yml
vendored
@ -1300,7 +1300,7 @@ jobs:
|
||||
cat >> "$GITHUB_ENV" << 'EOF'
|
||||
TEMP_PATH=${{runner.temp}}/stateless_debug
|
||||
REPORTS_PATH=${{runner.temp}}/reports_dir
|
||||
CHECK_NAME=Stateless tests (address)
|
||||
CHECK_NAME=Stateless tests (asan)
|
||||
REPO_COPY=${{runner.temp}}/stateless_debug/ClickHouse
|
||||
KILL_TIMEOUT=10800
|
||||
RUN_BY_HASH_NUM=0
|
||||
@ -1339,7 +1339,7 @@ jobs:
|
||||
cat >> "$GITHUB_ENV" << 'EOF'
|
||||
TEMP_PATH=${{runner.temp}}/stateless_debug
|
||||
REPORTS_PATH=${{runner.temp}}/reports_dir
|
||||
CHECK_NAME=Stateless tests (address)
|
||||
CHECK_NAME=Stateless tests (asan)
|
||||
REPO_COPY=${{runner.temp}}/stateless_debug/ClickHouse
|
||||
KILL_TIMEOUT=10800
|
||||
RUN_BY_HASH_NUM=1
|
||||
@ -1378,7 +1378,7 @@ jobs:
|
||||
cat >> "$GITHUB_ENV" << 'EOF'
|
||||
TEMP_PATH=${{runner.temp}}/stateless_tsan
|
||||
REPORTS_PATH=${{runner.temp}}/reports_dir
|
||||
CHECK_NAME=Stateless tests (thread)
|
||||
CHECK_NAME=Stateless tests (tsan)
|
||||
REPO_COPY=${{runner.temp}}/stateless_tsan/ClickHouse
|
||||
KILL_TIMEOUT=10800
|
||||
RUN_BY_HASH_NUM=0
|
||||
@ -1417,7 +1417,7 @@ jobs:
|
||||
cat >> "$GITHUB_ENV" << 'EOF'
|
||||
TEMP_PATH=${{runner.temp}}/stateless_tsan
|
||||
REPORTS_PATH=${{runner.temp}}/reports_dir
|
||||
CHECK_NAME=Stateless tests (thread)
|
||||
CHECK_NAME=Stateless tests (tsan)
|
||||
REPO_COPY=${{runner.temp}}/stateless_tsan/ClickHouse
|
||||
KILL_TIMEOUT=10800
|
||||
RUN_BY_HASH_NUM=1
|
||||
@ -1456,7 +1456,7 @@ jobs:
|
||||
cat >> "$GITHUB_ENV" << 'EOF'
|
||||
TEMP_PATH=${{runner.temp}}/stateless_tsan
|
||||
REPORTS_PATH=${{runner.temp}}/reports_dir
|
||||
CHECK_NAME=Stateless tests (thread)
|
||||
CHECK_NAME=Stateless tests (tsan)
|
||||
REPO_COPY=${{runner.temp}}/stateless_tsan/ClickHouse
|
||||
KILL_TIMEOUT=10800
|
||||
RUN_BY_HASH_NUM=2
|
||||
@ -1532,7 +1532,7 @@ jobs:
|
||||
cat >> "$GITHUB_ENV" << 'EOF'
|
||||
TEMP_PATH=${{runner.temp}}/stateless_memory
|
||||
REPORTS_PATH=${{runner.temp}}/reports_dir
|
||||
CHECK_NAME=Stateless tests (memory)
|
||||
CHECK_NAME=Stateless tests (msan)
|
||||
REPO_COPY=${{runner.temp}}/stateless_memory/ClickHouse
|
||||
KILL_TIMEOUT=10800
|
||||
RUN_BY_HASH_NUM=0
|
||||
@ -1571,7 +1571,7 @@ jobs:
|
||||
cat >> "$GITHUB_ENV" << 'EOF'
|
||||
TEMP_PATH=${{runner.temp}}/stateless_memory
|
||||
REPORTS_PATH=${{runner.temp}}/reports_dir
|
||||
CHECK_NAME=Stateless tests (memory)
|
||||
CHECK_NAME=Stateless tests (msan)
|
||||
REPO_COPY=${{runner.temp}}/stateless_memory/ClickHouse
|
||||
KILL_TIMEOUT=10800
|
||||
RUN_BY_HASH_NUM=1
|
||||
@ -1610,7 +1610,7 @@ jobs:
|
||||
cat >> "$GITHUB_ENV" << 'EOF'
|
||||
TEMP_PATH=${{runner.temp}}/stateless_memory
|
||||
REPORTS_PATH=${{runner.temp}}/reports_dir
|
||||
CHECK_NAME=Stateless tests (memory)
|
||||
CHECK_NAME=Stateless tests (msan)
|
||||
REPO_COPY=${{runner.temp}}/stateless_memory/ClickHouse
|
||||
KILL_TIMEOUT=10800
|
||||
RUN_BY_HASH_NUM=2
|
||||
@ -1766,7 +1766,7 @@ jobs:
|
||||
cat >> "$GITHUB_ENV" << 'EOF'
|
||||
TEMP_PATH=${{runner.temp}}/stateless_flaky_asan
|
||||
REPORTS_PATH=${{runner.temp}}/reports_dir
|
||||
CHECK_NAME=Stateless tests flaky check (address)
|
||||
CHECK_NAME=Stateless tests flaky check (asan)
|
||||
REPO_COPY=${{runner.temp}}/stateless_flaky_asan/ClickHouse
|
||||
KILL_TIMEOUT=3600
|
||||
EOF
|
||||
@ -1927,7 +1927,7 @@ jobs:
|
||||
cat >> "$GITHUB_ENV" << 'EOF'
|
||||
TEMP_PATH=${{runner.temp}}/stateful_debug
|
||||
REPORTS_PATH=${{runner.temp}}/reports_dir
|
||||
CHECK_NAME=Stateful tests (address)
|
||||
CHECK_NAME=Stateful tests (asan)
|
||||
REPO_COPY=${{runner.temp}}/stateful_debug/ClickHouse
|
||||
KILL_TIMEOUT=3600
|
||||
EOF
|
||||
@ -1964,7 +1964,7 @@ jobs:
|
||||
cat >> "$GITHUB_ENV" << 'EOF'
|
||||
TEMP_PATH=${{runner.temp}}/stateful_tsan
|
||||
REPORTS_PATH=${{runner.temp}}/reports_dir
|
||||
CHECK_NAME=Stateful tests (thread)
|
||||
CHECK_NAME=Stateful tests (tsan)
|
||||
REPO_COPY=${{runner.temp}}/stateful_tsan/ClickHouse
|
||||
KILL_TIMEOUT=3600
|
||||
EOF
|
||||
@ -2001,7 +2001,7 @@ jobs:
|
||||
cat >> "$GITHUB_ENV" << 'EOF'
|
||||
TEMP_PATH=${{runner.temp}}/stateful_msan
|
||||
REPORTS_PATH=${{runner.temp}}/reports_dir
|
||||
CHECK_NAME=Stateful tests (memory)
|
||||
CHECK_NAME=Stateful tests (msan)
|
||||
REPO_COPY=${{runner.temp}}/stateful_msan/ClickHouse
|
||||
KILL_TIMEOUT=3600
|
||||
EOF
|
||||
@ -2115,7 +2115,7 @@ jobs:
|
||||
cat >> "$GITHUB_ENV" << 'EOF'
|
||||
TEMP_PATH=${{runner.temp}}/stress_thread
|
||||
REPORTS_PATH=${{runner.temp}}/reports_dir
|
||||
CHECK_NAME=Stress test (address)
|
||||
CHECK_NAME=Stress test (asan)
|
||||
REPO_COPY=${{runner.temp}}/stress_thread/ClickHouse
|
||||
EOF
|
||||
- name: Download json reports
|
||||
@ -2155,7 +2155,7 @@ jobs:
|
||||
cat >> "$GITHUB_ENV" << 'EOF'
|
||||
TEMP_PATH=${{runner.temp}}/stress_thread
|
||||
REPORTS_PATH=${{runner.temp}}/reports_dir
|
||||
CHECK_NAME=Stress test (thread)
|
||||
CHECK_NAME=Stress test (tsan)
|
||||
REPO_COPY=${{runner.temp}}/stress_thread/ClickHouse
|
||||
EOF
|
||||
- name: Download json reports
|
||||
@ -2191,7 +2191,7 @@ jobs:
|
||||
cat >> "$GITHUB_ENV" << 'EOF'
|
||||
TEMP_PATH=${{runner.temp}}/stress_memory
|
||||
REPORTS_PATH=${{runner.temp}}/reports_dir
|
||||
CHECK_NAME=Stress test (memory)
|
||||
CHECK_NAME=Stress test (msan)
|
||||
REPO_COPY=${{runner.temp}}/stress_memory/ClickHouse
|
||||
EOF
|
||||
- name: Download json reports
|
||||
@ -2227,7 +2227,7 @@ jobs:
|
||||
cat >> "$GITHUB_ENV" << 'EOF'
|
||||
TEMP_PATH=${{runner.temp}}/stress_undefined
|
||||
REPORTS_PATH=${{runner.temp}}/reports_dir
|
||||
CHECK_NAME=Stress test (undefined)
|
||||
CHECK_NAME=Stress test (ubsan)
|
||||
REPO_COPY=${{runner.temp}}/stress_undefined/ClickHouse
|
||||
EOF
|
||||
- name: Download json reports
|
||||
@ -2302,7 +2302,7 @@ jobs:
|
||||
cat >> "$GITHUB_ENV" << 'EOF'
|
||||
TEMP_PATH=${{runner.temp}}/ast_fuzzer_asan
|
||||
REPORTS_PATH=${{runner.temp}}/reports_dir
|
||||
CHECK_NAME=AST fuzzer (ASan)
|
||||
CHECK_NAME=AST fuzzer (asan)
|
||||
REPO_COPY=${{runner.temp}}/ast_fuzzer_asan/ClickHouse
|
||||
EOF
|
||||
- name: Download json reports
|
||||
@ -2338,7 +2338,7 @@ jobs:
|
||||
cat >> "$GITHUB_ENV" << 'EOF'
|
||||
TEMP_PATH=${{runner.temp}}/ast_fuzzer_tsan
|
||||
REPORTS_PATH=${{runner.temp}}/reports_dir
|
||||
CHECK_NAME=AST fuzzer (TSan)
|
||||
CHECK_NAME=AST fuzzer (tsan)
|
||||
REPO_COPY=${{runner.temp}}/ast_fuzzer_tsan/ClickHouse
|
||||
EOF
|
||||
- name: Download json reports
|
||||
@ -2374,7 +2374,7 @@ jobs:
|
||||
cat >> "$GITHUB_ENV" << 'EOF'
|
||||
TEMP_PATH=${{runner.temp}}/ast_fuzzer_ubsan
|
||||
REPORTS_PATH=${{runner.temp}}/reports_dir
|
||||
CHECK_NAME=AST fuzzer (UBSan)
|
||||
CHECK_NAME=AST fuzzer (ubsan)
|
||||
REPO_COPY=${{runner.temp}}/ast_fuzzer_ubsan/ClickHouse
|
||||
EOF
|
||||
- name: Download json reports
|
||||
@ -2410,7 +2410,7 @@ jobs:
|
||||
cat >> "$GITHUB_ENV" << 'EOF'
|
||||
TEMP_PATH=${{runner.temp}}/ast_fuzzer_msan
|
||||
REPORTS_PATH=${{runner.temp}}/reports_dir
|
||||
CHECK_NAME=AST fuzzer (MSan)
|
||||
CHECK_NAME=AST fuzzer (msan)
|
||||
REPO_COPY=${{runner.temp}}/ast_fuzzer_msan/ClickHouse
|
||||
EOF
|
||||
- name: Download json reports
|
||||
@ -2599,7 +2599,7 @@ jobs:
|
||||
cat >> "$GITHUB_ENV" << 'EOF'
|
||||
TEMP_PATH=${{runner.temp}}/integration_tests_tsan
|
||||
REPORTS_PATH=${{runner.temp}}/reports_dir
|
||||
CHECK_NAME=Integration tests (thread)
|
||||
CHECK_NAME=Integration tests (tsan)
|
||||
REPO_COPY=${{runner.temp}}/integration_tests_tsan/ClickHouse
|
||||
RUN_BY_HASH_NUM=0
|
||||
RUN_BY_HASH_TOTAL=4
|
||||
@ -2637,7 +2637,7 @@ jobs:
|
||||
cat >> "$GITHUB_ENV" << 'EOF'
|
||||
TEMP_PATH=${{runner.temp}}/integration_tests_tsan
|
||||
REPORTS_PATH=${{runner.temp}}/reports_dir
|
||||
CHECK_NAME=Integration tests (thread)
|
||||
CHECK_NAME=Integration tests (tsan)
|
||||
REPO_COPY=${{runner.temp}}/integration_tests_tsan/ClickHouse
|
||||
RUN_BY_HASH_NUM=1
|
||||
RUN_BY_HASH_TOTAL=4
|
||||
@ -2675,7 +2675,7 @@ jobs:
|
||||
cat >> "$GITHUB_ENV" << 'EOF'
|
||||
TEMP_PATH=${{runner.temp}}/integration_tests_tsan
|
||||
REPORTS_PATH=${{runner.temp}}/reports_dir
|
||||
CHECK_NAME=Integration tests (thread)
|
||||
CHECK_NAME=Integration tests (tsan)
|
||||
REPO_COPY=${{runner.temp}}/integration_tests_tsan/ClickHouse
|
||||
RUN_BY_HASH_NUM=2
|
||||
RUN_BY_HASH_TOTAL=4
|
||||
@ -2713,7 +2713,7 @@ jobs:
|
||||
cat >> "$GITHUB_ENV" << 'EOF'
|
||||
TEMP_PATH=${{runner.temp}}/integration_tests_tsan
|
||||
REPORTS_PATH=${{runner.temp}}/reports_dir
|
||||
CHECK_NAME=Integration tests (thread)
|
||||
CHECK_NAME=Integration tests (tsan)
|
||||
REPO_COPY=${{runner.temp}}/integration_tests_tsan/ClickHouse
|
||||
RUN_BY_HASH_NUM=3
|
||||
RUN_BY_HASH_TOTAL=4
|
||||
|
6
.github/workflows/release.yml
vendored
6
.github/workflows/release.yml
vendored
@ -1,4 +1,4 @@
|
||||
name: ReleaseWorkflow
|
||||
name: PublishedReleaseCI
|
||||
# - Gets artifacts from S3
|
||||
# - Sends it to JFROG Artifactory
|
||||
# - Adds them to the release assets
|
||||
@ -15,7 +15,7 @@ jobs:
|
||||
- name: Set envs
|
||||
run: |
|
||||
cat >> "$GITHUB_ENV" << 'EOF'
|
||||
JFROG_API_KEY=${{ secrets.JFROG_KEY_API_PACKAGES }}
|
||||
JFROG_API_KEY=${{ secrets.JFROG_ARTIFACTORY_API_KEY }}
|
||||
TEMP_PATH=${{runner.temp}}/release_packages
|
||||
REPO_COPY=${{runner.temp}}/release_packages/ClickHouse
|
||||
EOF
|
||||
@ -30,7 +30,7 @@ jobs:
|
||||
cp -r "$GITHUB_WORKSPACE" "$TEMP_PATH"
|
||||
cd "$REPO_COPY"
|
||||
python3 ./tests/ci/push_to_artifactory.py --release "${{ github.ref }}" \
|
||||
--commit '${{ github.sha }}' --all
|
||||
--commit '${{ github.sha }}' --artifactory-url "${{ secrets.JFROG_ARTIFACTORY_URL }}" --all
|
||||
- name: Upload packages to release assets
|
||||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
|
40
.github/workflows/release_branches.yml
vendored
40
.github/workflows/release_branches.yml
vendored
@ -1,4 +1,4 @@
|
||||
name: ReleaseCI
|
||||
name: ReleaseBranchCI
|
||||
|
||||
env:
|
||||
# Force the stdout and stderr streams to be unbuffered
|
||||
@ -591,7 +591,7 @@ jobs:
|
||||
cat >> "$GITHUB_ENV" << 'EOF'
|
||||
TEMP_PATH=${{runner.temp}}/stateless_debug
|
||||
REPORTS_PATH=${{runner.temp}}/reports_dir
|
||||
CHECK_NAME=Stateless tests (address)
|
||||
CHECK_NAME=Stateless tests (asan)
|
||||
REPO_COPY=${{runner.temp}}/stateless_debug/ClickHouse
|
||||
KILL_TIMEOUT=10800
|
||||
RUN_BY_HASH_NUM=0
|
||||
@ -630,7 +630,7 @@ jobs:
|
||||
cat >> "$GITHUB_ENV" << 'EOF'
|
||||
TEMP_PATH=${{runner.temp}}/stateless_debug
|
||||
REPORTS_PATH=${{runner.temp}}/reports_dir
|
||||
CHECK_NAME=Stateless tests (address)
|
||||
CHECK_NAME=Stateless tests (asan)
|
||||
REPO_COPY=${{runner.temp}}/stateless_debug/ClickHouse
|
||||
KILL_TIMEOUT=10800
|
||||
RUN_BY_HASH_NUM=1
|
||||
@ -669,7 +669,7 @@ jobs:
|
||||
cat >> "$GITHUB_ENV" << 'EOF'
|
||||
TEMP_PATH=${{runner.temp}}/stateless_tsan
|
||||
REPORTS_PATH=${{runner.temp}}/reports_dir
|
||||
CHECK_NAME=Stateless tests (thread)
|
||||
CHECK_NAME=Stateless tests (tsan)
|
||||
REPO_COPY=${{runner.temp}}/stateless_tsan/ClickHouse
|
||||
KILL_TIMEOUT=10800
|
||||
RUN_BY_HASH_NUM=0
|
||||
@ -708,7 +708,7 @@ jobs:
|
||||
cat >> "$GITHUB_ENV" << 'EOF'
|
||||
TEMP_PATH=${{runner.temp}}/stateless_tsan
|
||||
REPORTS_PATH=${{runner.temp}}/reports_dir
|
||||
CHECK_NAME=Stateless tests (thread)
|
||||
CHECK_NAME=Stateless tests (tsan)
|
||||
REPO_COPY=${{runner.temp}}/stateless_tsan/ClickHouse
|
||||
KILL_TIMEOUT=10800
|
||||
RUN_BY_HASH_NUM=1
|
||||
@ -747,7 +747,7 @@ jobs:
|
||||
cat >> "$GITHUB_ENV" << 'EOF'
|
||||
TEMP_PATH=${{runner.temp}}/stateless_tsan
|
||||
REPORTS_PATH=${{runner.temp}}/reports_dir
|
||||
CHECK_NAME=Stateless tests (thread)
|
||||
CHECK_NAME=Stateless tests (tsan)
|
||||
REPO_COPY=${{runner.temp}}/stateless_tsan/ClickHouse
|
||||
KILL_TIMEOUT=10800
|
||||
RUN_BY_HASH_NUM=2
|
||||
@ -823,7 +823,7 @@ jobs:
|
||||
cat >> "$GITHUB_ENV" << 'EOF'
|
||||
TEMP_PATH=${{runner.temp}}/stateless_memory
|
||||
REPORTS_PATH=${{runner.temp}}/reports_dir
|
||||
CHECK_NAME=Stateless tests (memory)
|
||||
CHECK_NAME=Stateless tests (msan)
|
||||
REPO_COPY=${{runner.temp}}/stateless_memory/ClickHouse
|
||||
KILL_TIMEOUT=10800
|
||||
RUN_BY_HASH_NUM=0
|
||||
@ -862,7 +862,7 @@ jobs:
|
||||
cat >> "$GITHUB_ENV" << 'EOF'
|
||||
TEMP_PATH=${{runner.temp}}/stateless_memory
|
||||
REPORTS_PATH=${{runner.temp}}/reports_dir
|
||||
CHECK_NAME=Stateless tests (memory)
|
||||
CHECK_NAME=Stateless tests (msan)
|
||||
REPO_COPY=${{runner.temp}}/stateless_memory/ClickHouse
|
||||
KILL_TIMEOUT=10800
|
||||
RUN_BY_HASH_NUM=1
|
||||
@ -901,7 +901,7 @@ jobs:
|
||||
cat >> "$GITHUB_ENV" << 'EOF'
|
||||
TEMP_PATH=${{runner.temp}}/stateless_memory
|
||||
REPORTS_PATH=${{runner.temp}}/reports_dir
|
||||
CHECK_NAME=Stateless tests (memory)
|
||||
CHECK_NAME=Stateless tests (msan)
|
||||
REPO_COPY=${{runner.temp}}/stateless_memory/ClickHouse
|
||||
KILL_TIMEOUT=10800
|
||||
RUN_BY_HASH_NUM=2
|
||||
@ -1134,7 +1134,7 @@ jobs:
|
||||
cat >> "$GITHUB_ENV" << 'EOF'
|
||||
TEMP_PATH=${{runner.temp}}/stateful_debug
|
||||
REPORTS_PATH=${{runner.temp}}/reports_dir
|
||||
CHECK_NAME=Stateful tests (address)
|
||||
CHECK_NAME=Stateful tests (asan)
|
||||
REPO_COPY=${{runner.temp}}/stateful_debug/ClickHouse
|
||||
KILL_TIMEOUT=3600
|
||||
EOF
|
||||
@ -1171,7 +1171,7 @@ jobs:
|
||||
cat >> "$GITHUB_ENV" << 'EOF'
|
||||
TEMP_PATH=${{runner.temp}}/stateful_tsan
|
||||
REPORTS_PATH=${{runner.temp}}/reports_dir
|
||||
CHECK_NAME=Stateful tests (thread)
|
||||
CHECK_NAME=Stateful tests (tsan)
|
||||
REPO_COPY=${{runner.temp}}/stateful_tsan/ClickHouse
|
||||
KILL_TIMEOUT=3600
|
||||
EOF
|
||||
@ -1208,7 +1208,7 @@ jobs:
|
||||
cat >> "$GITHUB_ENV" << 'EOF'
|
||||
TEMP_PATH=${{runner.temp}}/stateful_msan
|
||||
REPORTS_PATH=${{runner.temp}}/reports_dir
|
||||
CHECK_NAME=Stateful tests (memory)
|
||||
CHECK_NAME=Stateful tests (msan)
|
||||
REPO_COPY=${{runner.temp}}/stateful_msan/ClickHouse
|
||||
KILL_TIMEOUT=3600
|
||||
EOF
|
||||
@ -1322,7 +1322,7 @@ jobs:
|
||||
cat >> "$GITHUB_ENV" << 'EOF'
|
||||
TEMP_PATH=${{runner.temp}}/stress_thread
|
||||
REPORTS_PATH=${{runner.temp}}/reports_dir
|
||||
CHECK_NAME=Stress test (address)
|
||||
CHECK_NAME=Stress test (asan)
|
||||
REPO_COPY=${{runner.temp}}/stress_thread/ClickHouse
|
||||
EOF
|
||||
- name: Download json reports
|
||||
@ -1362,7 +1362,7 @@ jobs:
|
||||
cat >> "$GITHUB_ENV" << 'EOF'
|
||||
TEMP_PATH=${{runner.temp}}/stress_thread
|
||||
REPORTS_PATH=${{runner.temp}}/reports_dir
|
||||
CHECK_NAME=Stress test (thread)
|
||||
CHECK_NAME=Stress test (tsan)
|
||||
REPO_COPY=${{runner.temp}}/stress_thread/ClickHouse
|
||||
EOF
|
||||
- name: Download json reports
|
||||
@ -1398,7 +1398,7 @@ jobs:
|
||||
cat >> "$GITHUB_ENV" << 'EOF'
|
||||
TEMP_PATH=${{runner.temp}}/stress_memory
|
||||
REPORTS_PATH=${{runner.temp}}/reports_dir
|
||||
CHECK_NAME=Stress test (memory)
|
||||
CHECK_NAME=Stress test (msan)
|
||||
REPO_COPY=${{runner.temp}}/stress_memory/ClickHouse
|
||||
EOF
|
||||
- name: Download json reports
|
||||
@ -1434,7 +1434,7 @@ jobs:
|
||||
cat >> "$GITHUB_ENV" << 'EOF'
|
||||
TEMP_PATH=${{runner.temp}}/stress_undefined
|
||||
REPORTS_PATH=${{runner.temp}}/reports_dir
|
||||
CHECK_NAME=Stress test (undefined)
|
||||
CHECK_NAME=Stress test (ubsan)
|
||||
REPO_COPY=${{runner.temp}}/stress_undefined/ClickHouse
|
||||
EOF
|
||||
- name: Download json reports
|
||||
@ -1623,7 +1623,7 @@ jobs:
|
||||
cat >> "$GITHUB_ENV" << 'EOF'
|
||||
TEMP_PATH=${{runner.temp}}/integration_tests_tsan
|
||||
REPORTS_PATH=${{runner.temp}}/reports_dir
|
||||
CHECK_NAME=Integration tests (thread)
|
||||
CHECK_NAME=Integration tests (tsan)
|
||||
REPO_COPY=${{runner.temp}}/integration_tests_tsan/ClickHouse
|
||||
RUN_BY_HASH_NUM=0
|
||||
RUN_BY_HASH_TOTAL=4
|
||||
@ -1661,7 +1661,7 @@ jobs:
|
||||
cat >> "$GITHUB_ENV" << 'EOF'
|
||||
TEMP_PATH=${{runner.temp}}/integration_tests_tsan
|
||||
REPORTS_PATH=${{runner.temp}}/reports_dir
|
||||
CHECK_NAME=Integration tests (thread)
|
||||
CHECK_NAME=Integration tests (tsan)
|
||||
REPO_COPY=${{runner.temp}}/integration_tests_tsan/ClickHouse
|
||||
RUN_BY_HASH_NUM=1
|
||||
RUN_BY_HASH_TOTAL=4
|
||||
@ -1699,7 +1699,7 @@ jobs:
|
||||
cat >> "$GITHUB_ENV" << 'EOF'
|
||||
TEMP_PATH=${{runner.temp}}/integration_tests_tsan
|
||||
REPORTS_PATH=${{runner.temp}}/reports_dir
|
||||
CHECK_NAME=Integration tests (thread)
|
||||
CHECK_NAME=Integration tests (tsan)
|
||||
REPO_COPY=${{runner.temp}}/integration_tests_tsan/ClickHouse
|
||||
RUN_BY_HASH_NUM=2
|
||||
RUN_BY_HASH_TOTAL=4
|
||||
@ -1737,7 +1737,7 @@ jobs:
|
||||
cat >> "$GITHUB_ENV" << 'EOF'
|
||||
TEMP_PATH=${{runner.temp}}/integration_tests_tsan
|
||||
REPORTS_PATH=${{runner.temp}}/reports_dir
|
||||
CHECK_NAME=Integration tests (thread)
|
||||
CHECK_NAME=Integration tests (tsan)
|
||||
REPO_COPY=${{runner.temp}}/integration_tests_tsan/ClickHouse
|
||||
RUN_BY_HASH_NUM=3
|
||||
RUN_BY_HASH_TOTAL=4
|
||||
|
22
base/glibc-compatibility/musl/dup3.c
Normal file
22
base/glibc-compatibility/musl/dup3.c
Normal file
@ -0,0 +1,22 @@
|
||||
#define _GNU_SOURCE
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include "syscall.h"
|
||||
|
||||
int dup3(int old, int new, int flags)
|
||||
{
|
||||
int r;
|
||||
#ifdef SYS_dup2
|
||||
if (old==new) return __syscall_ret(-EINVAL);
|
||||
if (flags & O_CLOEXEC) {
|
||||
while ((r=__syscall(SYS_dup3, old, new, flags))==-EBUSY);
|
||||
if (r!=-ENOSYS) return __syscall_ret(r);
|
||||
}
|
||||
while ((r=__syscall(SYS_dup2, old, new))==-EBUSY);
|
||||
if (flags & O_CLOEXEC) __syscall(SYS_fcntl, new, F_SETFD, FD_CLOEXEC);
|
||||
#else
|
||||
while ((r=__syscall(SYS_dup3, old, new, flags))==-EBUSY);
|
||||
#endif
|
||||
return __syscall_ret(r);
|
||||
}
|
26
base/glibc-compatibility/musl/inotify.c
Normal file
26
base/glibc-compatibility/musl/inotify.c
Normal file
@ -0,0 +1,26 @@
|
||||
#include <sys/inotify.h>
|
||||
#include <errno.h>
|
||||
#include "syscall.h"
|
||||
|
||||
int inotify_init()
|
||||
{
|
||||
return inotify_init1(0);
|
||||
}
|
||||
int inotify_init1(int flags)
|
||||
{
|
||||
int r = __syscall(SYS_inotify_init1, flags);
|
||||
#ifdef SYS_inotify_init
|
||||
if (r==-ENOSYS && !flags) r = __syscall(SYS_inotify_init);
|
||||
#endif
|
||||
return __syscall_ret(r);
|
||||
}
|
||||
|
||||
int inotify_add_watch(int fd, const char *pathname, uint32_t mask)
|
||||
{
|
||||
return syscall(SYS_inotify_add_watch, fd, pathname, mask);
|
||||
}
|
||||
|
||||
int inotify_rm_watch(int fd, int wd)
|
||||
{
|
||||
return syscall(SYS_inotify_rm_watch, fd, wd);
|
||||
}
|
2
contrib/NuRaft
vendored
2
contrib/NuRaft
vendored
@ -1 +1 @@
|
||||
Subproject commit 33f60f961d4914441b684af43e9e5535078ba54b
|
||||
Subproject commit bdba298189e29995892de78dcecf64d127444e81
|
2
contrib/libuv
vendored
2
contrib/libuv
vendored
@ -1 +1 @@
|
||||
Subproject commit 95081e7c16c9857babe6d4e2bc1c779198ea89ae
|
||||
Subproject commit 3a85b2eb3d83f369b8a8cafd329d7e9dc28f60cf
|
@ -15,6 +15,7 @@ set(uv_sources
|
||||
src/inet.c
|
||||
src/random.c
|
||||
src/strscpy.c
|
||||
src/strtok.c
|
||||
src/threadpool.c
|
||||
src/timer.c
|
||||
src/uv-common.c
|
||||
@ -75,13 +76,13 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
list(APPEND uv_defines _GNU_SOURCE _POSIX_C_SOURCE=200112)
|
||||
list(APPEND uv_libraries rt)
|
||||
list(APPEND uv_sources
|
||||
src/unix/epoll.c
|
||||
src/unix/linux-core.c
|
||||
src/unix/linux-inotify.c
|
||||
src/unix/linux-syscalls.c
|
||||
src/unix/procfs-exepath.c
|
||||
src/unix/random-getrandom.c
|
||||
src/unix/random-sysctl-linux.c
|
||||
src/unix/sysinfo-loadavg.c)
|
||||
src/unix/random-sysctl-linux.c)
|
||||
endif()
|
||||
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "NetBSD")
|
||||
@ -111,6 +112,7 @@ if(CMAKE_SYSTEM_NAME STREQUAL "OS/390")
|
||||
src/unix/pthread-fixes.c
|
||||
src/unix/pthread-barrier.c
|
||||
src/unix/os390.c
|
||||
src/unix/os390-proctitle.c
|
||||
src/unix/os390-syscalls.c)
|
||||
endif()
|
||||
|
||||
|
18
docs/changelogs/v22.8.4.7-lts.md
Normal file
18
docs/changelogs/v22.8.4.7-lts.md
Normal file
@ -0,0 +1,18 @@
|
||||
---
|
||||
sidebar_position: 1
|
||||
sidebar_label: 2022
|
||||
---
|
||||
|
||||
# 2022 Changelog
|
||||
|
||||
### ClickHouse release v22.8.4.7-lts (baad27bcd2f) FIXME as compared to v22.8.3.13-lts (6a15b73faea)
|
||||
|
||||
#### Bug Fix (user-visible misbehavior in official stable or prestable release)
|
||||
|
||||
* Backported in [#40760](https://github.com/ClickHouse/ClickHouse/issues/40760): Fix possible error 'Decimal math overflow' while parsing DateTime64. [#40546](https://github.com/ClickHouse/ClickHouse/pull/40546) ([Kruglov Pavel](https://github.com/Avogar)).
|
||||
* Backported in [#40811](https://github.com/ClickHouse/ClickHouse/issues/40811): In [#40595](https://github.com/ClickHouse/ClickHouse/issues/40595) it was reported that the `host_regexp` functionality was not working properly with a name to address resolution in `/etc/hosts`. It's fixed. [#40769](https://github.com/ClickHouse/ClickHouse/pull/40769) ([Arthur Passos](https://github.com/arthurpassos)).
|
||||
|
||||
#### NOT FOR CHANGELOG / INSIGNIFICANT
|
||||
|
||||
* Migrate artifactory [#40831](https://github.com/ClickHouse/ClickHouse/pull/40831) ([Mikhail f. Shiryaev](https://github.com/Felixoid)).
|
||||
|
@ -4,7 +4,7 @@ sidebar_position: 50
|
||||
sidebar_label: MySQL
|
||||
---
|
||||
|
||||
# MySQL
|
||||
# MySQL
|
||||
|
||||
Allows to connect to databases on a remote MySQL server and perform `INSERT` and `SELECT` queries to exchange data between ClickHouse and MySQL.
|
||||
|
||||
@ -99,7 +99,7 @@ mysql> select * from mysql_table;
|
||||
Database in ClickHouse, exchanging data with the MySQL server:
|
||||
|
||||
``` sql
|
||||
CREATE DATABASE mysql_db ENGINE = MySQL('localhost:3306', 'test', 'my_user', 'user_password')
|
||||
CREATE DATABASE mysql_db ENGINE = MySQL('localhost:3306', 'test', 'my_user', 'user_password') SETTINGS read_write_timeout=10000, connect_timeout=100;
|
||||
```
|
||||
|
||||
``` sql
|
||||
|
@ -6,28 +6,19 @@ title: "UK Property Price Paid"
|
||||
---
|
||||
|
||||
The dataset contains data about prices paid for real-estate property in England and Wales. The data is available since year 1995.
|
||||
The size of the dataset in uncompressed form is about 4 GiB and it will take about 278 MiB in ClickHouse.
|
||||
The size of the dataset in uncompressed form is about 4 GiB and it will take about 270 MiB in ClickHouse.
|
||||
|
||||
Source: https://www.gov.uk/government/statistical-data-sets/price-paid-data-downloads
|
||||
Source: https://www.gov.uk/government/statistical-data-sets/price-paid-data-downloads <br/>
|
||||
Description of the fields: https://www.gov.uk/guidance/about-the-price-paid-data
|
||||
|
||||
Contains HM Land Registry data © Crown copyright and database right 2021. This data is licensed under the Open Government Licence v3.0.
|
||||
|
||||
## Download the Dataset {#download-dataset}
|
||||
|
||||
Run the command:
|
||||
|
||||
```bash
|
||||
wget http://prod.publicdata.landregistry.gov.uk.s3-website-eu-west-1.amazonaws.com/pp-complete.csv
|
||||
```
|
||||
|
||||
Download will take about 2 minutes with good internet connection.
|
||||
|
||||
## Create the Table {#create-table}
|
||||
|
||||
```sql
|
||||
CREATE TABLE uk_price_paid
|
||||
(
|
||||
uuid UUID,
|
||||
price UInt32,
|
||||
date Date,
|
||||
postcode1 LowCardinality(String),
|
||||
@ -42,65 +33,68 @@ CREATE TABLE uk_price_paid
|
||||
town LowCardinality(String),
|
||||
district LowCardinality(String),
|
||||
county LowCardinality(String),
|
||||
category UInt8
|
||||
) ENGINE = MergeTree ORDER BY (postcode1, postcode2, addr1, addr2);
|
||||
category UInt8,
|
||||
category2 UInt8
|
||||
) ORDER BY (postcode1, postcode2, addr1, addr2);
|
||||
```
|
||||
|
||||
## Preprocess and Import Data {#preprocess-import-data}
|
||||
|
||||
We will use `clickhouse-local` tool for data preprocessing and `clickhouse-client` to upload it.
|
||||
|
||||
In this example, we define the structure of source data from the CSV file and specify a query to preprocess the data with `clickhouse-local`.
|
||||
In this example, we define the structure of source data from the CSV file and specify a query to preprocess the data with either `clickhouse-client` or the web based Play UI.
|
||||
|
||||
The preprocessing is:
|
||||
- splitting the postcode to two different columns `postcode1` and `postcode2` that is better for storage and queries;
|
||||
- splitting the postcode to two different columns `postcode1` and `postcode2` that are better for storage and queries;
|
||||
- coverting the `time` field to date as it only contains 00:00 time;
|
||||
- ignoring the [UUid](../../sql-reference/data-types/uuid.md) field because we don't need it for analysis;
|
||||
- transforming `type` and `duration` to more readable Enum fields with function [transform](../../sql-reference/functions/other-functions.md#transform);
|
||||
- transforming `is_new` and `category` fields from single-character string (`Y`/`N` and `A`/`B`) to [UInt8](../../sql-reference/data-types/int-uint.md#uint8-uint16-uint32-uint64-uint256-int8-int16-int32-int64-int128-int256) field with 0 and 1.
|
||||
|
||||
Preprocessed data is piped directly to `clickhouse-client` to be inserted into ClickHouse table in streaming fashion.
|
||||
|
||||
```bash
|
||||
clickhouse-local --input-format CSV --structure '
|
||||
uuid String,
|
||||
price UInt32,
|
||||
time DateTime,
|
||||
postcode String,
|
||||
a String,
|
||||
b String,
|
||||
c String,
|
||||
addr1 String,
|
||||
addr2 String,
|
||||
street String,
|
||||
locality String,
|
||||
town String,
|
||||
district String,
|
||||
county String,
|
||||
d String,
|
||||
e String
|
||||
' --query "
|
||||
WITH splitByChar(' ', postcode) AS p
|
||||
SELECT
|
||||
price,
|
||||
toDate(time) AS date,
|
||||
p[1] AS postcode1,
|
||||
p[2] AS postcode2,
|
||||
transform(a, ['T', 'S', 'D', 'F', 'O'], ['terraced', 'semi-detached', 'detached', 'flat', 'other']) AS type,
|
||||
b = 'Y' AS is_new,
|
||||
transform(c, ['F', 'L', 'U'], ['freehold', 'leasehold', 'unknown']) AS duration,
|
||||
addr1,
|
||||
addr2,
|
||||
street,
|
||||
locality,
|
||||
town,
|
||||
district,
|
||||
county,
|
||||
d = 'B' AS category
|
||||
FROM table" --date_time_input_format best_effort < pp-complete.csv | clickhouse-client --query "INSERT INTO uk_price_paid FORMAT TSV"
|
||||
INSERT INTO uk_price_paid
|
||||
WITH
|
||||
splitByChar(' ', postcode) AS p
|
||||
SELECT
|
||||
replaceRegexpAll(uuid_string, '{|}','') AS uuid,
|
||||
toUInt32(price_string) AS price,
|
||||
parseDateTimeBestEffortUS(time) AS date,
|
||||
p[1] AS postcode1,
|
||||
p[2] AS postcode2,
|
||||
transform(a, ['T', 'S', 'D', 'F', 'O'], ['terraced', 'semi-detached', 'detached', 'flat', 'other']) AS type,
|
||||
b = 'Y' AS is_new,
|
||||
transform(c, ['F', 'L', 'U'], ['freehold', 'leasehold', 'unknown']) AS duration,
|
||||
addr1,
|
||||
addr2,
|
||||
street,
|
||||
locality,
|
||||
town,
|
||||
district,
|
||||
county,
|
||||
d = 'B' AS category,
|
||||
e = 'B' AS category2
|
||||
FROM url(
|
||||
'http://prod.publicdata.landregistry.gov.uk.s3-website-eu-west-1.amazonaws.com/pp-complete.csv',
|
||||
'CSV',
|
||||
'uuid_string String,
|
||||
price_string String,
|
||||
time String,
|
||||
postcode String,
|
||||
a String,
|
||||
b String,
|
||||
c String,
|
||||
addr1 String,
|
||||
addr2 String,
|
||||
street String,
|
||||
locality String,
|
||||
town String,
|
||||
district String,
|
||||
county String,
|
||||
d String,
|
||||
e String'
|
||||
)
|
||||
SETTINGS max_http_get_redirects=1;
|
||||
```
|
||||
|
||||
It will take about 40 seconds.
|
||||
It will take about 2 minutes depending on where you are in the world, and where your ClickHouse servers are. Almost all of the time is the download time of the CSV file from the UK government server.
|
||||
|
||||
## Validate the Data {#validate-data}
|
||||
|
||||
@ -112,13 +106,13 @@ SELECT count() FROM uk_price_paid;
|
||||
|
||||
Result:
|
||||
|
||||
```text
|
||||
```response
|
||||
┌──count()─┐
|
||||
│ 26321785 │
|
||||
│ 27450499 │
|
||||
└──────────┘
|
||||
```
|
||||
|
||||
The size of dataset in ClickHouse is just 278 MiB, check it.
|
||||
The size of dataset in ClickHouse is just 540 MiB, check it.
|
||||
|
||||
Query:
|
||||
|
||||
@ -130,10 +124,14 @@ Result:
|
||||
|
||||
```text
|
||||
┌─formatReadableSize(total_bytes)─┐
|
||||
│ 278.80 MiB │
|
||||
│ 545.04 MiB │
|
||||
└─────────────────────────────────┘
|
||||
```
|
||||
|
||||
:::note
|
||||
The above size is for a replicated table, if you are using this dataset with a single instance the size will be half.
|
||||
:::
|
||||
|
||||
## Run Some Queries {#run-queries}
|
||||
|
||||
### Query 1. Average Price Per Year {#average-price}
|
||||
@ -146,7 +144,7 @@ SELECT toYear(date) AS year, round(avg(price)) AS price, bar(price, 0, 1000000,
|
||||
|
||||
Result:
|
||||
|
||||
```text
|
||||
```response
|
||||
┌─year─┬──price─┬─bar(round(avg(price)), 0, 1000000, 80)─┐
|
||||
│ 1995 │ 67932 │ █████▍ │
|
||||
│ 1996 │ 71505 │ █████▋ │
|
||||
|
@ -1,10 +1,10 @@
|
||||
---
|
||||
slug: /en/operations/backup
|
||||
sidebar_position: 49
|
||||
sidebar_label: Data Backup
|
||||
sidebar_label: Data backup and restore
|
||||
---
|
||||
|
||||
# Data Backup
|
||||
# Data backup and restore
|
||||
|
||||
While [replication](../engines/table-engines/mergetree-family/replication.md) provides protection from hardware failures, it does not protect against human errors: accidental deletion of data, deletion of the wrong table or a table on the wrong cluster, and software bugs that result in incorrect data processing or data corruption. In many cases mistakes like these will affect all replicas. ClickHouse has built-in safeguards to prevent some types of mistakes — for example, by default [you can’t just drop tables with a MergeTree-like engine containing more than 50 Gb of data](server-configuration-parameters/settings.md#max-table-size-to-drop). However, these safeguards do not cover all possible cases and can be circumvented.
|
||||
|
||||
@ -16,21 +16,181 @@ Each company has different resources available and business requirements, so the
|
||||
Keep in mind that if you backed something up and never tried to restore it, chances are that restore will not work properly when you actually need it (or at least it will take longer than business can tolerate). So whatever backup approach you choose, make sure to automate the restore process as well, and practice it on a spare ClickHouse cluster regularly.
|
||||
:::
|
||||
|
||||
## Duplicating Source Data Somewhere Else {#duplicating-source-data-somewhere-else}
|
||||
## Configure a backup destination
|
||||
|
||||
In the examples below you will see the backup destination specified like `Disk('backups', '1.zip')`. To prepare the destination add a file to `/etc/clickhouse-server/config.d/backup_disk.xml` specifying the backup destination. For example, this file defines disk named `backups` and then adds that disk to the **backups > allowed_disk** list:
|
||||
|
||||
```xml
|
||||
<clickhouse>
|
||||
<storage_configuration>
|
||||
<disks>
|
||||
<!--highlight-next-line -->
|
||||
<backups>
|
||||
<type>local</type>
|
||||
<path>/backups/</path>
|
||||
</backups>
|
||||
</disks>
|
||||
</storage_configuration>
|
||||
<!--highlight-start -->
|
||||
<backups>
|
||||
<allowed_disk>backups</allowed_disk>
|
||||
<allowed_path>/backups/</allowed_path>
|
||||
</backups>
|
||||
<!--highlight-end -->
|
||||
</clickhouse>
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
Backups can be either full or incremental, and can include tables (including materialized views, projections, and dictionaries), and databases. Backups can be synchronous (default) or asynchronous. They can be compressed. Backups can be password protected.
|
||||
|
||||
The BACKUP and RESTORE statements take a list of DATABASE and TABLE names, a destination (or source), options and settings:
|
||||
- The destination for the backup, or the source for the restore. This is based on the disk defined earlier. For example `Disk('backups', 'filename.zip')`
|
||||
- ASYNC: backup or restore asynchronously
|
||||
- PARTITIONS: a list of partitions to restore
|
||||
- SETTINGS:
|
||||
- [`compression_method`](en/sql-reference/statements/create/table/#column-compression-codecs) and compression_level
|
||||
- `password` for the file on disk
|
||||
- `base_backup`: the destination of the previous backup of this source. For example, `Disk('backups', '1.zip')`
|
||||
|
||||
## Usage examples
|
||||
|
||||
Backup and then restore a table:
|
||||
```
|
||||
BACKUP TABLE test.table TO Disk('backups', '1.zip')
|
||||
```
|
||||
|
||||
Corresponding restore:
|
||||
```
|
||||
RESTORE TABLE test.table FROM Disk('backups', '1.zip')
|
||||
```
|
||||
|
||||
:::note
|
||||
The above RESTORE would fail if the table `test.table` contains data, you would have to drop the table in order to test the RESTORE, or use the setting `allow_non_empty_tables=true`:
|
||||
```
|
||||
RESTORE TABLE test.table FROM Disk('backups', '1.zip')
|
||||
SETTINGS allow_non_empty_tables=true
|
||||
```
|
||||
:::
|
||||
|
||||
Tables can be restored, or backed up, with new names:
|
||||
```
|
||||
RESTORE TABLE test.table AS test.table2 FROM Disk('backups', '1.zip')
|
||||
```
|
||||
|
||||
```
|
||||
BACKUP TABLE test.table3 AS test.table4 TO Disk('backups', '2.zip')
|
||||
```
|
||||
|
||||
## Incremental backups
|
||||
|
||||
Incremental backups can be taken by specifying the `base_backup`.
|
||||
:::note
|
||||
Incremental backups depend on the base backup. The base backup must be kept available in order to be able to restore from an incremental backup.
|
||||
:::
|
||||
|
||||
Incrementally store new data. The setting `base_backup` causes data since a previous backup to `Disk('backups', 'd.zip')` to be stored to `Disk('backups', 'incremental-a.zip')`:
|
||||
```
|
||||
BACKUP TABLE test.table TO Disk('backups', 'incremental-a.zip')
|
||||
SETTINGS base_backup = Disk('backups', 'd.zip')
|
||||
```
|
||||
|
||||
Restore all data from the incremental backup and the base_backup into a new table `test.table2`:
|
||||
```
|
||||
RESTORE TABLE test.table AS test.table2
|
||||
FROM Disk('backups', 'incremental-a.zip');
|
||||
```
|
||||
|
||||
## Assign a password to the backup
|
||||
|
||||
Backups written to disk can have a password applied to the file:
|
||||
```
|
||||
BACKUP TABLE test.table
|
||||
TO Disk('backups', 'password-protected.zip')
|
||||
SETTINGS password='qwerty'
|
||||
```
|
||||
|
||||
Restore:
|
||||
```
|
||||
RESTORE TABLE test.table
|
||||
FROM Disk('backups', 'password-protected.zip')
|
||||
SETTINGS password='qwerty'
|
||||
```
|
||||
|
||||
## Compression settings
|
||||
|
||||
If you would like to specify the compression method or level:
|
||||
```
|
||||
BACKUP TABLE test.table
|
||||
TO Disk('backups', 'filename.zip')
|
||||
SETTINGS compression_method='lzma', compression_level=3
|
||||
```
|
||||
|
||||
## Restore specific partitions
|
||||
If specific partitions associated with a table need to be restored these can be specified. To restore partitions 1 and 4 from backup:
|
||||
```
|
||||
RESTORE TABLE test.table PARTITIONS '2', '3'
|
||||
FROM Disk('backups', 'filename.zip')
|
||||
```
|
||||
|
||||
## Check the status of backups
|
||||
|
||||
The backup command returns an `id` and `status`, and that `id` can be used to get the status of the backup. This is very useful to check the progress of long ASYNC backups. The example below shows a failure that happened when trying to overwrite an existing backup file:
|
||||
```sql
|
||||
BACKUP TABLE helloworld.my_first_table TO Disk('backups', '1.zip') ASYNC
|
||||
```
|
||||
```response
|
||||
┌─id───────────────────────────────────┬─status──────────┐
|
||||
│ 7678b0b3-f519-4e6e-811f-5a0781a4eb52 │ CREATING_BACKUP │
|
||||
└──────────────────────────────────────┴─────────────────┘
|
||||
|
||||
1 row in set. Elapsed: 0.001 sec.
|
||||
```
|
||||
|
||||
```
|
||||
SELECT
|
||||
*
|
||||
FROM system.backups
|
||||
where id='7678b0b3-f519-4e6e-811f-5a0781a4eb52'
|
||||
FORMAT Vertical
|
||||
```
|
||||
```response
|
||||
Row 1:
|
||||
──────
|
||||
id: 7678b0b3-f519-4e6e-811f-5a0781a4eb52
|
||||
name: Disk('backups', '1.zip')
|
||||
#highlight-next-line
|
||||
status: BACKUP_FAILED
|
||||
num_files: 0
|
||||
uncompressed_size: 0
|
||||
compressed_size: 0
|
||||
#highlight-next-line
|
||||
error: Code: 598. DB::Exception: Backup Disk('backups', '1.zip') already exists. (BACKUP_ALREADY_EXISTS) (version 22.8.2.11 (official build))
|
||||
start_time: 2022-08-30 09:21:46
|
||||
end_time: 2022-08-30 09:21:46
|
||||
|
||||
1 row in set. Elapsed: 0.002 sec.
|
||||
```
|
||||
|
||||
## Alternatives
|
||||
|
||||
ClickHouse stores data on disk, and there are many ways to backup disks. These are some alternatives that have been used in the past, and that may fit in well in your environment.
|
||||
|
||||
### Duplicating Source Data Somewhere Else {#duplicating-source-data-somewhere-else}
|
||||
|
||||
Often data that is ingested into ClickHouse is delivered through some sort of persistent queue, such as [Apache Kafka](https://kafka.apache.org). In this case it is possible to configure an additional set of subscribers that will read the same data stream while it is being written to ClickHouse and store it in cold storage somewhere. Most companies already have some default recommended cold storage, which could be an object store or a distributed filesystem like [HDFS](https://hadoop.apache.org/docs/stable/hadoop-project-dist/hadoop-hdfs/HdfsDesign.html).
|
||||
|
||||
## Filesystem Snapshots {#filesystem-snapshots}
|
||||
### Filesystem Snapshots {#filesystem-snapshots}
|
||||
|
||||
Some local filesystems provide snapshot functionality (for example, [ZFS](https://en.wikipedia.org/wiki/ZFS)), but they might not be the best choice for serving live queries. A possible solution is to create additional replicas with this kind of filesystem and exclude them from the [Distributed](../engines/table-engines/special/distributed.md) tables that are used for `SELECT` queries. Snapshots on such replicas will be out of reach of any queries that modify data. As a bonus, these replicas might have special hardware configurations with more disks attached per server, which would be cost-effective.
|
||||
|
||||
## clickhouse-copier {#clickhouse-copier}
|
||||
### clickhouse-copier {#clickhouse-copier}
|
||||
|
||||
[clickhouse-copier](../operations/utilities/clickhouse-copier.md) is a versatile tool that was initially created to re-shard petabyte-sized tables. It can also be used for backup and restore purposes because it reliably copies data between ClickHouse tables and clusters.
|
||||
|
||||
For smaller volumes of data, a simple `INSERT INTO ... SELECT ...` to remote tables might work as well.
|
||||
|
||||
## Manipulations with Parts {#manipulations-with-parts}
|
||||
### Manipulations with Parts {#manipulations-with-parts}
|
||||
|
||||
ClickHouse allows using the `ALTER TABLE ... FREEZE PARTITION ...` query to create a local copy of table partitions. This is implemented using hardlinks to the `/var/lib/clickhouse/shadow/` folder, so it usually does not consume extra disk space for old data. The created copies of files are not handled by ClickHouse server, so you can just leave them there: you will have a simple backup that does not require any additional external system, but it will still be prone to hardware issues. For this reason, it’s better to remotely copy them to another location and then remove the local copies. Distributed filesystems and object stores are still a good options for this, but normal attached file servers with a large enough capacity might work as well (in this case the transfer will occur via the network filesystem or maybe [rsync](https://en.wikipedia.org/wiki/Rsync)).
|
||||
Data can be restored from backup using the `ALTER TABLE ... ATTACH PARTITION ...`
|
||||
@ -39,4 +199,3 @@ For more information about queries related to partition manipulations, see the [
|
||||
|
||||
A third-party tool is available to automate this approach: [clickhouse-backup](https://github.com/AlexAkulov/clickhouse-backup).
|
||||
|
||||
[Original article](https://clickhouse.com/docs/en/operations/backup/) <!--hide-->
|
||||
|
@ -46,7 +46,7 @@ Binary operations on Decimal result in wider result type (with any order of argu
|
||||
Rules for scale:
|
||||
|
||||
- add, subtract: S = max(S1, S2).
|
||||
- multuply: S = S1 + S2.
|
||||
- multiply: S = S1 + S2.
|
||||
- divide: S = S1.
|
||||
|
||||
For similar operations between Decimal and integers, the result is Decimal of the same size as an argument.
|
||||
|
@ -1069,7 +1069,7 @@ Formats a Time according to the given Format string. Format is a constant expres
|
||||
**Syntax**
|
||||
|
||||
``` sql
|
||||
formatDateTime(Time, Format\[, Timezone\])
|
||||
formatDateTime(Time, Format[, Timezone])
|
||||
```
|
||||
|
||||
**Returned value(s)**
|
||||
@ -1105,6 +1105,7 @@ Using replacement fields, you can define a pattern for the resulting string. “
|
||||
| %w | weekday as a decimal number with Sunday as 0 (0-6) | 2 |
|
||||
| %y | Year, last two digits (00-99) | 18 |
|
||||
| %Y | Year | 2018 |
|
||||
| %z | Time offset from UTC as +HHMM or -HHMM | -0500 |
|
||||
| %% | a % sign | % |
|
||||
|
||||
**Example**
|
||||
|
@ -495,25 +495,23 @@ If the ‘s’ string is non-empty and does not contain the ‘c’ character at
|
||||
|
||||
Returns the string ‘s’ that was converted from the encoding in ‘from’ to the encoding in ‘to’.
|
||||
|
||||
## Base58Encode(plaintext), Base58Decode(encoded_text)
|
||||
## base58Encode(plaintext)
|
||||
|
||||
Accepts a String and encodes/decodes it using [Base58](https://tools.ietf.org/id/draft-msporny-base58-01.html) encoding scheme using "Bitcoin" alphabet.
|
||||
Accepts a String and encodes it using [Base58](https://tools.ietf.org/id/draft-msporny-base58-01.html) encoding scheme using "Bitcoin" alphabet.
|
||||
|
||||
**Syntax**
|
||||
|
||||
```sql
|
||||
base58Encode(decoded)
|
||||
base58Decode(encoded)
|
||||
base58Encode(plaintext)
|
||||
```
|
||||
|
||||
**Arguments**
|
||||
|
||||
- `decoded` — [String](../../sql-reference/data-types/string.md) column or constant.
|
||||
- `encoded` — [String](../../sql-reference/data-types/string.md) column or constant. If the string is not a valid base58-encoded value, an exception is thrown.
|
||||
- `plaintext` — [String](../../sql-reference/data-types/string.md) column or constant.
|
||||
|
||||
**Returned value**
|
||||
|
||||
- A string containing encoded/decoded value of 1st argument.
|
||||
- A string containing encoded value of 1st argument.
|
||||
|
||||
Type: [String](../../sql-reference/data-types/string.md).
|
||||
|
||||
@ -523,17 +521,48 @@ Query:
|
||||
|
||||
``` sql
|
||||
SELECT base58Encode('Encoded');
|
||||
SELECT base58Encode('3dc8KtHrwM');
|
||||
```
|
||||
|
||||
Result:
|
||||
```text
|
||||
┌─encodeBase58('Encoded')─┐
|
||||
│ 3dc8KtHrwM │
|
||||
└──────────────────────────────────┘
|
||||
┌─decodeBase58('3dc8KtHrwM')─┐
|
||||
│ Encoded │
|
||||
└────────────────────────────────────┘
|
||||
┌─base58Encode('Encoded')─┐
|
||||
│ 3dc8KtHrwM │
|
||||
└─────────────────────────┘
|
||||
```
|
||||
|
||||
## base58Decode(encoded_text)
|
||||
|
||||
Accepts a String and decodes it using [Base58](https://tools.ietf.org/id/draft-msporny-base58-01.html) encoding scheme using "Bitcoin" alphabet.
|
||||
|
||||
**Syntax**
|
||||
|
||||
```sql
|
||||
base58Decode(encoded_text)
|
||||
```
|
||||
|
||||
**Arguments**
|
||||
|
||||
- `encoded_text` — [String](../../sql-reference/data-types/string.md) column or constant. If the string is not a valid base58-encoded value, an exception is thrown.
|
||||
|
||||
**Returned value**
|
||||
|
||||
- A string containing decoded value of 1st argument.
|
||||
|
||||
Type: [String](../../sql-reference/data-types/string.md).
|
||||
|
||||
**Example**
|
||||
|
||||
Query:
|
||||
|
||||
``` sql
|
||||
SELECT base58Decode('3dc8KtHrwM');
|
||||
```
|
||||
|
||||
Result:
|
||||
```text
|
||||
┌─base58Decode('3dc8KtHrwM')─┐
|
||||
│ Encoded │
|
||||
└────────────────────────────┘
|
||||
```
|
||||
|
||||
## base64Encode(s)
|
||||
|
@ -9,8 +9,8 @@ sidebar_label: CONSTRAINT
|
||||
Constraints could be added or deleted using following syntax:
|
||||
|
||||
``` sql
|
||||
ALTER TABLE [db].name ADD CONSTRAINT constraint_name CHECK expression;
|
||||
ALTER TABLE [db].name DROP CONSTRAINT constraint_name;
|
||||
ALTER TABLE [db].name [ON CLUSTER cluster] ADD CONSTRAINT constraint_name CHECK expression;
|
||||
ALTER TABLE [db].name [ON CLUSTER cluster] DROP CONSTRAINT constraint_name;
|
||||
```
|
||||
|
||||
See more on [constraints](../../../sql-reference/statements/create/table.md#constraints).
|
||||
|
@ -11,7 +11,7 @@ sidebar_label: TTL
|
||||
You can change [table TTL](../../../engines/table-engines/mergetree-family/mergetree.md#mergetree-table-ttl) with a request of the following form:
|
||||
|
||||
``` sql
|
||||
ALTER TABLE table_name MODIFY TTL ttl_expression;
|
||||
ALTER TABLE [db.]table_name [ON CLUSTER cluster] MODIFY TTL ttl_expression;
|
||||
```
|
||||
|
||||
## REMOVE TTL
|
||||
@ -19,7 +19,7 @@ ALTER TABLE table_name MODIFY TTL ttl_expression;
|
||||
TTL-property can be removed from table with the following query:
|
||||
|
||||
```sql
|
||||
ALTER TABLE table_name REMOVE TTL
|
||||
ALTER TABLE [db.]table_name [ON CLUSTER cluster] REMOVE TTL
|
||||
```
|
||||
|
||||
**Example**
|
||||
|
@ -1017,7 +1017,7 @@ SELECT timeSlots(toDateTime64('1980-12-12 21:01:02.1234', 4, 'UTC'), toDecimal64
|
||||
**Синтаксис**
|
||||
|
||||
``` sql
|
||||
formatDateTime(Time, Format\[, Timezone\])
|
||||
formatDateTime(Time, Format[, Timezone])
|
||||
```
|
||||
|
||||
**Возвращаемое значение**
|
||||
|
@ -16,7 +16,7 @@ sidebar_label: "Функции для работы со строками"
|
||||
empty(x)
|
||||
```
|
||||
|
||||
Строка считается непустой, если содержит хотя бы один байт, пусть даже это пробел или нулевой байт.
|
||||
Строка считается непустой, если содержит хотя бы один байт, пусть даже это пробел или нулевой байт.
|
||||
|
||||
Функция также поддерживает работу с типами [Array](array-functions.md#function-empty) и [UUID](uuid-functions.md#empty).
|
||||
|
||||
@ -56,7 +56,7 @@ SELECT empty('text');
|
||||
notEmpty(x)
|
||||
```
|
||||
|
||||
Строка считается непустой, если содержит хотя бы один байт, пусть даже это пробел или нулевой байт.
|
||||
Строка считается непустой, если содержит хотя бы один байт, пусть даже это пробел или нулевой байт.
|
||||
|
||||
Функция также поддерживает работу с типами [Array](array-functions.md#function-notempty) и [UUID](uuid-functions.md#notempty).
|
||||
|
||||
@ -491,21 +491,21 @@ SELECT concat(key1, key2), sum(value) FROM key_val GROUP BY (key1, key2);
|
||||
|
||||
Возвращает сконвертированную из кодировки from в кодировку to строку s.
|
||||
|
||||
## Base58Encode(plaintext), Base58Decode(encoded_text) {#base58}
|
||||
## base58Encode(plaintext), base58Decode(encoded_text) {#base58}
|
||||
|
||||
Принимает на вход строку или колонку строк и кодирует/раскодирует их с помощью схемы кодирования [Base58](https://tools.ietf.org/id/draft-msporny-base58-01.html) с использованием стандартного алфавита Bitcoin.
|
||||
|
||||
**Синтаксис**
|
||||
|
||||
```sql
|
||||
encodeBase58(decoded)
|
||||
decodeBase58(encoded)
|
||||
base58Encode(decoded)
|
||||
base58Decode(encoded)
|
||||
```
|
||||
|
||||
**Аргументы**
|
||||
|
||||
- `decoded` — Колонка или строка типа [String](../../sql-reference/data-types/string.md).
|
||||
- `encoded` — Колонка или строка типа [String](../../sql-reference/data-types/string.md). Если входная строка не является корректным кодом для какой-либо другой строки, возникнет исключение `1001`.
|
||||
- `encoded` — Колонка или строка типа [String](../../sql-reference/data-types/string.md). Если входная строка не является корректным кодом для какой-либо другой строки, возникнет исключение.
|
||||
|
||||
**Возвращаемое значение**
|
||||
|
||||
@ -518,18 +518,18 @@ decodeBase58(encoded)
|
||||
Запрос:
|
||||
|
||||
``` sql
|
||||
SELECT encodeBase58('encode');
|
||||
SELECT decodeBase58('izCFiDUY');
|
||||
SELECT base58Encode('Encoded');
|
||||
SELECT base58Decode('3dc8KtHrwM');
|
||||
```
|
||||
|
||||
Результат:
|
||||
```text
|
||||
┌─encodeBase58('encode', 'flickr')─┐
|
||||
│ SvyTHb1D │
|
||||
└──────────────────────────────────┘
|
||||
┌─decodeBase58('izCFiDUY', 'ripple')─┐
|
||||
│ decode │
|
||||
└────────────────────────────────────┘
|
||||
┌─base58Encode('Encoded')─┐
|
||||
│ 3dc8KtHrwM │
|
||||
└─────────────────────────┘
|
||||
┌─base58Decode('3dc8KtHrwM')─┐
|
||||
│ Encoded │
|
||||
└────────────────────────────┘
|
||||
```
|
||||
|
||||
## base64Encode(s) {#base64encode}
|
||||
|
@ -11,8 +11,8 @@ sidebar_label: "Манипуляции с ограничениями"
|
||||
Добавить или удалить ограничение можно с помощью запросов
|
||||
|
||||
``` sql
|
||||
ALTER TABLE [db].name ADD CONSTRAINT constraint_name CHECK expression;
|
||||
ALTER TABLE [db].name DROP CONSTRAINT constraint_name;
|
||||
ALTER TABLE [db].name [ON CLUSTER cluster] ADD CONSTRAINT constraint_name CHECK expression;
|
||||
ALTER TABLE [db].name [ON CLUSTER cluster] DROP CONSTRAINT constraint_name;
|
||||
```
|
||||
|
||||
Запросы выполняют добавление или удаление метаданных об ограничениях таблицы `[db].name`, поэтому выполняются мгновенно.
|
||||
|
@ -11,7 +11,7 @@ sidebar_label: TTL
|
||||
Вы можете изменить [TTL для таблицы](../../../engines/table-engines/mergetree-family/mergetree.md#mergetree-column-ttl) запросом следующего вида:
|
||||
|
||||
``` sql
|
||||
ALTER TABLE table-name MODIFY TTL ttl-expression
|
||||
ALTER TABLE [db.]table-name [ON CLUSTER cluster] MODIFY TTL ttl-expression
|
||||
```
|
||||
|
||||
## REMOVE TTL {#remove-ttl}
|
||||
@ -19,7 +19,7 @@ ALTER TABLE table-name MODIFY TTL ttl-expression
|
||||
Удалить табличный TTL можно запросом следующего вида:
|
||||
|
||||
```sql
|
||||
ALTER TABLE table_name REMOVE TTL
|
||||
ALTER TABLE [db.]table_name [ON CLUSTER cluster] REMOVE TTL
|
||||
```
|
||||
|
||||
**Пример**
|
||||
@ -83,4 +83,4 @@ SELECT * FROM table_with_ttl;
|
||||
### Смотрите также
|
||||
|
||||
- Подробнее о [свойстве TTL](../../../engines/table-engines/mergetree-family/mergetree.md#mergetree-column-ttl).
|
||||
- Изменить столбец [с TTL](../../../sql-reference/statements/alter/column.md#alter_modify-column).
|
||||
- Изменить столбец [с TTL](../../../sql-reference/statements/alter/column.md#alter_modify-column).
|
||||
|
@ -956,7 +956,7 @@ SELECT
|
||||
**语法**
|
||||
|
||||
``` sql
|
||||
formatDateTime(Time, Format\[, Timezone\])
|
||||
formatDateTime(Time, Format[, Timezone])
|
||||
```
|
||||
|
||||
**返回值**
|
||||
|
@ -736,7 +736,9 @@ int Server::main(const std::vector<std::string> & /*args*/)
|
||||
std::vector<ProtocolServerAdapter> servers_to_start_before_tables;
|
||||
/// This object will periodically calculate some metrics.
|
||||
AsynchronousMetrics async_metrics(
|
||||
global_context, config().getUInt("asynchronous_metrics_update_period_s", 1),
|
||||
global_context,
|
||||
config().getUInt("asynchronous_metrics_update_period_s", 1),
|
||||
config().getUInt("asynchronous_heavy_metrics_update_period_s", 120),
|
||||
[&]() -> std::vector<ProtocolServerMetrics>
|
||||
{
|
||||
std::vector<ProtocolServerMetrics> metrics;
|
||||
|
@ -65,9 +65,31 @@
|
||||
in specified format like JSON.
|
||||
For example, as below:
|
||||
{"date_time":"1650918987.180175","thread_name":"#1","thread_id":"254545","level":"Trace","query_id":"","logger_name":"BaseDaemon","message":"Received signal 2","source_file":"../base/daemon/BaseDaemon.cpp; virtual void SignalListener::run()","source_line":"192"}
|
||||
To enable JSON logging support, just uncomment <formatting> tag below.
|
||||
To enable JSON logging support, please uncomment the entire <formatting> tag below.
|
||||
|
||||
a) You can modify key names by changing values under tag values inside <names> tag.
|
||||
For example, to change DATE_TIME to MY_DATE_TIME, you can do like:
|
||||
<date_time>MY_DATE_TIME</date_time>
|
||||
b) You can stop unwanted log properties to appear in logs. To do so, you can simply comment out (recommended)
|
||||
that property from this file.
|
||||
For example, if you do not want your log to print query_id, you can comment out only <query_id> tag.
|
||||
However, if you comment out all the tags under <names>, the program will print default values for as
|
||||
below.
|
||||
-->
|
||||
<!-- <formatting>json</formatting> -->
|
||||
<!-- <formatting>
|
||||
<type>json</type>
|
||||
<names>
|
||||
<date_time>date_time</date_time>
|
||||
<thread_name>thread_name</thread_name>
|
||||
<thread_id>thread_id</thread_id>
|
||||
<level>level</level>
|
||||
<query_id>query_id</query_id>
|
||||
<logger_name>logger_name</logger_name>
|
||||
<message>message</message>
|
||||
<source_file>source_file</source_file>
|
||||
<source_line>source_line</source_line>
|
||||
</names>
|
||||
</formatting> -->
|
||||
</logger>
|
||||
|
||||
<!-- Add headers to response in options request. OPTIONS method is used in CORS preflight requests. -->
|
||||
|
@ -79,7 +79,7 @@ public:
|
||||
/// No user, probably the user has been dropped while it was in the cache.
|
||||
cache.remove(params);
|
||||
}
|
||||
auto res = std::shared_ptr<ContextAccess>(new ContextAccess(access_control, params));
|
||||
auto res = std::make_shared<ContextAccess>(access_control, params);
|
||||
res->initialize();
|
||||
cache.add(params, res);
|
||||
return res;
|
||||
|
@ -110,7 +110,7 @@ namespace
|
||||
}
|
||||
|
||||
/// Returns the host name by its address.
|
||||
Strings getHostsByAddress(const IPAddress & address)
|
||||
std::unordered_set<String> getHostsByAddress(const IPAddress & address)
|
||||
{
|
||||
auto hosts = DNSResolver::instance().reverseResolve(address);
|
||||
|
||||
@ -526,7 +526,7 @@ bool AllowedClientHosts::contains(const IPAddress & client_address) const
|
||||
return true;
|
||||
|
||||
/// Check `name_regexps`.
|
||||
std::optional<Strings> resolved_hosts;
|
||||
std::optional<std::unordered_set<String>> resolved_hosts;
|
||||
auto check_name_regexp = [&](const String & name_regexp_)
|
||||
{
|
||||
try
|
||||
|
@ -410,7 +410,7 @@ std::shared_ptr<const ContextAccess> ContextAccess::getFullAccess()
|
||||
{
|
||||
static const std::shared_ptr<const ContextAccess> res = []
|
||||
{
|
||||
auto full_access = std::shared_ptr<ContextAccess>(new ContextAccess);
|
||||
auto full_access = std::make_shared<ContextAccess>();
|
||||
full_access->is_full_access = true;
|
||||
full_access->access = std::make_shared<AccessRights>(AccessRights::getFullAccess());
|
||||
full_access->access_with_implicit = full_access->access;
|
||||
|
@ -69,6 +69,9 @@ public:
|
||||
using Params = ContextAccessParams;
|
||||
const Params & getParams() const { return params; }
|
||||
|
||||
ContextAccess() { } /// NOLINT
|
||||
ContextAccess(const AccessControl & access_control_, const Params & params_);
|
||||
|
||||
/// Returns the current user. Throws if user is nullptr.
|
||||
UserPtr getUser() const;
|
||||
/// Same as above, but can return nullptr.
|
||||
@ -167,8 +170,6 @@ public:
|
||||
|
||||
private:
|
||||
friend class AccessControl;
|
||||
ContextAccess() {} /// NOLINT
|
||||
ContextAccess(const AccessControl & access_control_, const Params & params_);
|
||||
|
||||
void initialize();
|
||||
void setUser(const UserPtr & user_) const;
|
||||
|
@ -625,7 +625,7 @@ CheckBackupResult checkBaseBackupForFile(const SizeAndChecksum & base_backup_inf
|
||||
{
|
||||
/// We cannot reuse base backup because our file is smaller
|
||||
/// than file stored in previous backup
|
||||
if (new_entry_info.size > base_backup_info.first)
|
||||
if (new_entry_info.size < base_backup_info.first)
|
||||
return CheckBackupResult::HasNothing;
|
||||
|
||||
if (base_backup_info.first == new_entry_info.size)
|
||||
@ -682,8 +682,6 @@ ChecksumsForNewEntry calculateNewEntryChecksumsIfNeeded(BackupEntryPtr entry, si
|
||||
|
||||
void BackupImpl::writeFile(const String & file_name, BackupEntryPtr entry)
|
||||
{
|
||||
|
||||
std::lock_guard lock{mutex};
|
||||
if (open_mode != OpenMode::WRITE)
|
||||
throw Exception("Backup is not opened for writing", ErrorCodes::LOGICAL_ERROR);
|
||||
|
||||
@ -802,7 +800,12 @@ void BackupImpl::writeFile(const String & file_name, BackupEntryPtr entry)
|
||||
/// or have only prefix of it in previous backup. Let's go long path.
|
||||
|
||||
info.data_file_name = info.file_name;
|
||||
info.archive_suffix = current_archive_suffix;
|
||||
|
||||
if (use_archives)
|
||||
{
|
||||
std::lock_guard lock{mutex};
|
||||
info.archive_suffix = current_archive_suffix;
|
||||
}
|
||||
|
||||
bool is_data_file_required;
|
||||
coordination->addFileInfo(info, is_data_file_required);
|
||||
@ -818,9 +821,11 @@ void BackupImpl::writeFile(const String & file_name, BackupEntryPtr entry)
|
||||
/// if source and destination are compatible
|
||||
if (!use_archives && info.base_size == 0 && writer->supportNativeCopy(reader_description))
|
||||
{
|
||||
|
||||
/// Should be much faster than writing data through server.
|
||||
LOG_TRACE(log, "Will copy file {} using native copy", adjusted_path);
|
||||
/// Should be much faster than writing data through server
|
||||
|
||||
/// NOTE: `mutex` must be unlocked here otherwise writing will be in one thread maximum and hence slow.
|
||||
|
||||
writer->copyFileNative(entry->tryGetDiskIfExists(), entry->getFilePath(), info.data_file_name);
|
||||
}
|
||||
else
|
||||
@ -838,6 +843,11 @@ void BackupImpl::writeFile(const String & file_name, BackupEntryPtr entry)
|
||||
if (use_archives)
|
||||
{
|
||||
LOG_TRACE(log, "Adding file {} to archive", adjusted_path);
|
||||
|
||||
/// An archive must be written strictly in one thread, so it's correct to lock the mutex for all the time we're writing the file
|
||||
/// to the archive.
|
||||
std::lock_guard lock{mutex};
|
||||
|
||||
String archive_suffix = current_archive_suffix;
|
||||
bool next_suffix = false;
|
||||
if (current_archive_suffix.empty() && is_internal_backup)
|
||||
@ -859,6 +869,7 @@ void BackupImpl::writeFile(const String & file_name, BackupEntryPtr entry)
|
||||
}
|
||||
else
|
||||
{
|
||||
/// NOTE: `mutex` must be unlocked here otherwise writing will be in one thread maximum and hence slow.
|
||||
writer->copyFileThroughBuffer(std::move(read_buffer), info.data_file_name);
|
||||
}
|
||||
}
|
||||
|
@ -130,7 +130,7 @@ private:
|
||||
std::pair<String, std::shared_ptr<IArchiveWriter>> archive_writers[2];
|
||||
String current_archive_suffix;
|
||||
String lock_file_name;
|
||||
size_t num_files_written = 0;
|
||||
std::atomic<size_t> num_files_written = 0;
|
||||
bool writing_finalized = false;
|
||||
const Poco::Logger * log;
|
||||
};
|
||||
|
@ -247,6 +247,7 @@ add_object_library(clickhouse_databases Databases)
|
||||
add_object_library(clickhouse_databases_mysql Databases/MySQL)
|
||||
add_object_library(clickhouse_disks Disks)
|
||||
add_object_library(clickhouse_interpreters Interpreters)
|
||||
add_object_library(clickhouse_interpreters_cache Interpreters/Cache)
|
||||
add_object_library(clickhouse_interpreters_access Interpreters/Access)
|
||||
add_object_library(clickhouse_interpreters_mysql Interpreters/MySQL)
|
||||
add_object_library(clickhouse_interpreters_clusterproxy Interpreters/ClusterProxy)
|
||||
|
@ -91,13 +91,6 @@ static const NameSet exit_strings
|
||||
"q", "й", "\\q", "\\Q", "\\й", "\\Й", ":q", "Жй"
|
||||
};
|
||||
|
||||
static const std::initializer_list<std::pair<String, String>> backslash_aliases
|
||||
{
|
||||
{ "\\l", "SHOW DATABASES" },
|
||||
{ "\\d", "SHOW TABLES" },
|
||||
{ "\\c", "USE" },
|
||||
};
|
||||
|
||||
|
||||
namespace ErrorCodes
|
||||
{
|
||||
@ -1999,6 +1992,21 @@ void ClientBase::runInteractive()
|
||||
/// Enable bracketed-paste-mode so that we are able to paste multiline queries as a whole.
|
||||
lr.enableBracketedPaste();
|
||||
|
||||
static const std::initializer_list<std::pair<String, String>> backslash_aliases =
|
||||
{
|
||||
{ "\\l", "SHOW DATABASES" },
|
||||
{ "\\d", "SHOW TABLES" },
|
||||
{ "\\c", "USE" },
|
||||
};
|
||||
|
||||
static const std::initializer_list<String> repeat_last_input_aliases =
|
||||
{
|
||||
".", /// Vim shortcut
|
||||
"/" /// Oracle SQL Plus shortcut
|
||||
};
|
||||
|
||||
String last_input;
|
||||
|
||||
do
|
||||
{
|
||||
auto input = lr.readLine(prompt(), ":-] ");
|
||||
@ -2016,7 +2024,7 @@ void ClientBase::runInteractive()
|
||||
has_vertical_output_suffix = true;
|
||||
}
|
||||
|
||||
for (const auto& [alias, command] : backslash_aliases)
|
||||
for (const auto & [alias, command] : backslash_aliases)
|
||||
{
|
||||
auto it = std::search(input.begin(), input.end(), alias.begin(), alias.end());
|
||||
if (it != input.end() && std::all_of(input.begin(), it, isWhitespaceASCII))
|
||||
@ -2034,10 +2042,20 @@ void ClientBase::runInteractive()
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto & alias : repeat_last_input_aliases)
|
||||
{
|
||||
if (input == alias)
|
||||
{
|
||||
input = last_input;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (!processQueryText(input))
|
||||
break;
|
||||
last_input = input;
|
||||
}
|
||||
catch (const Exception & e)
|
||||
{
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include <Interpreters/castColumn.h>
|
||||
#include <Interpreters/convertFieldToType.h>
|
||||
#include <Common/HashTable/HashSet.h>
|
||||
#include <Processors/Transforms/ColumnGathererTransform.h>
|
||||
|
||||
namespace DB
|
||||
{
|
||||
@ -154,13 +155,15 @@ FieldInfo getFieldInfo(const Field & field)
|
||||
{
|
||||
FieldVisitorToScalarType to_scalar_type_visitor;
|
||||
applyVisitor(to_scalar_type_visitor, field);
|
||||
FieldVisitorToNumberOfDimensions to_number_dimension_visitor;
|
||||
|
||||
return
|
||||
{
|
||||
to_scalar_type_visitor.getScalarType(),
|
||||
to_scalar_type_visitor.haveNulls(),
|
||||
to_scalar_type_visitor.needConvertField(),
|
||||
applyVisitor(FieldVisitorToNumberOfDimensions(), field),
|
||||
applyVisitor(to_number_dimension_visitor, field),
|
||||
to_number_dimension_visitor.need_fold_dimension
|
||||
};
|
||||
}
|
||||
|
||||
@ -821,6 +824,44 @@ MutableColumnPtr ColumnObject::cloneResized(size_t new_size) const
|
||||
return applyForSubcolumns([&](const auto & subcolumn) { return subcolumn.cloneResized(new_size); });
|
||||
}
|
||||
|
||||
void ColumnObject::getPermutation(PermutationSortDirection, PermutationSortStability, size_t, int, Permutation & res) const
|
||||
{
|
||||
res.resize(num_rows);
|
||||
std::iota(res.begin(), res.end(), 0);
|
||||
}
|
||||
|
||||
void ColumnObject::compareColumn(const IColumn & rhs, size_t rhs_row_num,
|
||||
PaddedPODArray<UInt64> * row_indexes, PaddedPODArray<Int8> & compare_results,
|
||||
int direction, int nan_direction_hint) const
|
||||
{
|
||||
return doCompareColumn<ColumnObject>(assert_cast<const ColumnObject &>(rhs), rhs_row_num, row_indexes,
|
||||
compare_results, direction, nan_direction_hint);
|
||||
}
|
||||
|
||||
void ColumnObject::getExtremes(Field & min, Field & max) const
|
||||
{
|
||||
if (num_rows == 0)
|
||||
{
|
||||
min = Object();
|
||||
max = Object();
|
||||
}
|
||||
else
|
||||
{
|
||||
get(0, min);
|
||||
get(0, max);
|
||||
}
|
||||
}
|
||||
|
||||
MutableColumns ColumnObject::scatter(ColumnIndex num_columns, const Selector & selector) const
|
||||
{
|
||||
return scatterImpl<ColumnObject>(num_columns, selector);
|
||||
}
|
||||
|
||||
void ColumnObject::gather(ColumnGathererStream & gatherer)
|
||||
{
|
||||
gatherer.gather(*this);
|
||||
}
|
||||
|
||||
const ColumnObject::Subcolumn & ColumnObject::getSubcolumn(const PathInData & key) const
|
||||
{
|
||||
if (const auto * node = subcolumns.findLeaf(key))
|
||||
|
@ -15,7 +15,7 @@ namespace DB
|
||||
|
||||
namespace ErrorCodes
|
||||
{
|
||||
extern const int LOGICAL_ERROR;
|
||||
extern const int NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
/// Info that represents a scalar or array field in a decomposed view.
|
||||
@ -35,6 +35,10 @@ struct FieldInfo
|
||||
|
||||
/// Number of dimension in array. 0 if field is scalar.
|
||||
size_t num_dimensions;
|
||||
|
||||
/// If true then this field is an array of variadic dimension field
|
||||
/// and we need to normalize the dimension
|
||||
bool need_fold_dimension;
|
||||
};
|
||||
|
||||
FieldInfo getFieldInfo(const Field & field);
|
||||
@ -220,6 +224,19 @@ public:
|
||||
ColumnPtr replicate(const Offsets & offsets) const override;
|
||||
MutableColumnPtr cloneResized(size_t new_size) const override;
|
||||
|
||||
/// Order of rows in ColumnObject is undefined.
|
||||
void getPermutation(PermutationSortDirection, PermutationSortStability, size_t, int, Permutation & res) const override;
|
||||
void compareColumn(const IColumn & rhs, size_t rhs_row_num,
|
||||
PaddedPODArray<UInt64> * row_indexes, PaddedPODArray<Int8> & compare_results,
|
||||
int direction, int nan_direction_hint) const override;
|
||||
|
||||
void updatePermutation(PermutationSortDirection, PermutationSortStability, size_t, int, Permutation &, EqualRanges &) const override {}
|
||||
int compareAt(size_t, size_t, const IColumn &, int) const override { return 0; }
|
||||
void getExtremes(Field & min, Field & max) const override;
|
||||
|
||||
MutableColumns scatter(ColumnIndex num_columns, const Selector & selector) const override;
|
||||
void gather(ColumnGathererStream & gatherer) override;
|
||||
|
||||
/// All other methods throw exception.
|
||||
|
||||
StringRef getDataAt(size_t) const override { throwMustBeConcrete(); }
|
||||
@ -232,14 +249,7 @@ public:
|
||||
void updateWeakHash32(WeakHash32 &) const override { throwMustBeConcrete(); }
|
||||
void updateHashFast(SipHash &) const override { throwMustBeConcrete(); }
|
||||
void expand(const Filter &, bool) override { throwMustBeConcrete(); }
|
||||
int compareAt(size_t, size_t, const IColumn &, int) const override { throwMustBeConcrete(); }
|
||||
void compareColumn(const IColumn &, size_t, PaddedPODArray<UInt64> *, PaddedPODArray<Int8> &, int, int) const override { throwMustBeConcrete(); }
|
||||
bool hasEqualValues() const override { throwMustBeConcrete(); }
|
||||
void getPermutation(PermutationSortDirection, PermutationSortStability, size_t, int, Permutation &) const override { throwMustBeConcrete(); }
|
||||
void updatePermutation(PermutationSortDirection, PermutationSortStability, size_t, int, Permutation &, EqualRanges &) const override { throwMustBeConcrete(); }
|
||||
MutableColumns scatter(ColumnIndex, const Selector &) const override { throwMustBeConcrete(); }
|
||||
void gather(ColumnGathererStream &) override { throwMustBeConcrete(); }
|
||||
void getExtremes(Field &, Field &) const override { throwMustBeConcrete(); }
|
||||
size_t byteSizeAt(size_t) const override { throwMustBeConcrete(); }
|
||||
double getRatioOfDefaultRows(double) const override { throwMustBeConcrete(); }
|
||||
void getIndicesOfNonDefaultRows(Offsets &, size_t, size_t) const override { throwMustBeConcrete(); }
|
||||
@ -247,7 +257,7 @@ public:
|
||||
private:
|
||||
[[noreturn]] static void throwMustBeConcrete()
|
||||
{
|
||||
throw Exception("ColumnObject must be converted to ColumnTuple before use", ErrorCodes::LOGICAL_ERROR);
|
||||
throw Exception("ColumnObject must be converted to ColumnTuple before use", ErrorCodes::NOT_IMPLEMENTED);
|
||||
}
|
||||
|
||||
template <typename Func>
|
||||
|
@ -15,13 +15,23 @@ namespace DB
|
||||
|
||||
static void callback(void * arg, int status, int, struct hostent * host)
|
||||
{
|
||||
auto * ptr_records = reinterpret_cast<std::vector<std::string>*>(arg);
|
||||
auto * ptr_records = reinterpret_cast<std::unordered_set<std::string>*>(arg);
|
||||
if (status == ARES_SUCCESS && host->h_aliases)
|
||||
{
|
||||
/*
|
||||
* In some cases (e.g /etc/hosts), hostent::h_name is filled and hostent::h_aliases is empty.
|
||||
* Thus, we can't rely solely on hostent::h_aliases. More info on:
|
||||
* https://github.com/ClickHouse/ClickHouse/issues/40595#issuecomment-1230526931
|
||||
* */
|
||||
if (auto * ptr_record = host->h_name)
|
||||
{
|
||||
ptr_records->insert(ptr_record);
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
while (auto * ptr_record = host->h_aliases[i])
|
||||
{
|
||||
ptr_records->emplace_back(ptr_record);
|
||||
ptr_records->insert(ptr_record);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
@ -58,9 +68,9 @@ namespace DB
|
||||
* */
|
||||
}
|
||||
|
||||
std::vector<std::string> CaresPTRResolver::resolve(const std::string & ip)
|
||||
std::unordered_set<std::string> CaresPTRResolver::resolve(const std::string & ip)
|
||||
{
|
||||
std::vector<std::string> ptr_records;
|
||||
std::unordered_set<std::string> ptr_records;
|
||||
|
||||
resolve(ip, ptr_records);
|
||||
wait();
|
||||
@ -68,9 +78,9 @@ namespace DB
|
||||
return ptr_records;
|
||||
}
|
||||
|
||||
std::vector<std::string> CaresPTRResolver::resolve_v6(const std::string & ip)
|
||||
std::unordered_set<std::string> CaresPTRResolver::resolve_v6(const std::string & ip)
|
||||
{
|
||||
std::vector<std::string> ptr_records;
|
||||
std::unordered_set<std::string> ptr_records;
|
||||
|
||||
resolve_v6(ip, ptr_records);
|
||||
wait();
|
||||
@ -78,7 +88,7 @@ namespace DB
|
||||
return ptr_records;
|
||||
}
|
||||
|
||||
void CaresPTRResolver::resolve(const std::string & ip, std::vector<std::string> & response)
|
||||
void CaresPTRResolver::resolve(const std::string & ip, std::unordered_set<std::string> & response)
|
||||
{
|
||||
in_addr addr;
|
||||
|
||||
@ -87,7 +97,7 @@ namespace DB
|
||||
ares_gethostbyaddr(channel, reinterpret_cast<const void*>(&addr), sizeof(addr), AF_INET, callback, &response);
|
||||
}
|
||||
|
||||
void CaresPTRResolver::resolve_v6(const std::string & ip, std::vector<std::string> & response)
|
||||
void CaresPTRResolver::resolve_v6(const std::string & ip, std::unordered_set<std::string> & response)
|
||||
{
|
||||
in6_addr addr;
|
||||
inet_pton(AF_INET6, ip.c_str(), &addr);
|
||||
|
@ -25,16 +25,16 @@ namespace DB
|
||||
explicit CaresPTRResolver(provider_token);
|
||||
~CaresPTRResolver() override;
|
||||
|
||||
std::vector<std::string> resolve(const std::string & ip) override;
|
||||
std::unordered_set<std::string> resolve(const std::string & ip) override;
|
||||
|
||||
std::vector<std::string> resolve_v6(const std::string & ip) override;
|
||||
std::unordered_set<std::string> resolve_v6(const std::string & ip) override;
|
||||
|
||||
private:
|
||||
void wait();
|
||||
|
||||
void resolve(const std::string & ip, std::vector<std::string> & response);
|
||||
void resolve(const std::string & ip, std::unordered_set<std::string> & response);
|
||||
|
||||
void resolve_v6(const std::string & ip, std::vector<std::string> & response);
|
||||
void resolve_v6(const std::string & ip, std::unordered_set<std::string> & response);
|
||||
|
||||
ares_channel channel;
|
||||
};
|
||||
|
@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <unordered_set>
|
||||
|
||||
namespace DB
|
||||
{
|
||||
@ -10,9 +10,9 @@ namespace DB
|
||||
|
||||
virtual ~DNSPTRResolver() = default;
|
||||
|
||||
virtual std::vector<std::string> resolve(const std::string & ip) = 0;
|
||||
virtual std::unordered_set<std::string> resolve(const std::string & ip) = 0;
|
||||
|
||||
virtual std::vector<std::string> resolve_v6(const std::string & ip) = 0;
|
||||
virtual std::unordered_set<std::string> resolve_v6(const std::string & ip) = 0;
|
||||
|
||||
};
|
||||
}
|
||||
|
@ -136,7 +136,7 @@ static DNSResolver::IPAddresses resolveIPAddressImpl(const std::string & host)
|
||||
return addresses;
|
||||
}
|
||||
|
||||
static Strings reverseResolveImpl(const Poco::Net::IPAddress & address)
|
||||
static std::unordered_set<String> reverseResolveImpl(const Poco::Net::IPAddress & address)
|
||||
{
|
||||
auto ptr_resolver = DB::DNSPTRResolverProvider::get();
|
||||
|
||||
@ -234,7 +234,7 @@ std::vector<Poco::Net::SocketAddress> DNSResolver::resolveAddressList(const std:
|
||||
return addresses;
|
||||
}
|
||||
|
||||
Strings DNSResolver::reverseResolve(const Poco::Net::IPAddress & address)
|
||||
std::unordered_set<String> DNSResolver::reverseResolve(const Poco::Net::IPAddress & address)
|
||||
{
|
||||
if (impl->disable_cache)
|
||||
return reverseResolveImpl(address);
|
||||
|
@ -37,7 +37,7 @@ public:
|
||||
std::vector<Poco::Net::SocketAddress> resolveAddressList(const std::string & host, UInt16 port);
|
||||
|
||||
/// Accepts host IP and resolves its host names
|
||||
Strings reverseResolve(const Poco::Net::IPAddress & address);
|
||||
std::unordered_set<String> reverseResolve(const Poco::Net::IPAddress & address);
|
||||
|
||||
/// Get this server host name
|
||||
String getHostName();
|
||||
|
@ -14,10 +14,10 @@ using namespace std::chrono_literals;
|
||||
|
||||
constexpr std::chrono::microseconds ZERO_MICROSEC = 0us;
|
||||
|
||||
OvercommitTracker::OvercommitTracker(std::mutex & global_mutex_)
|
||||
OvercommitTracker::OvercommitTracker(DB::ProcessList * process_list_)
|
||||
: picked_tracker(nullptr)
|
||||
, process_list(process_list_)
|
||||
, cancellation_state(QueryCancellationState::NONE)
|
||||
, global_mutex(global_mutex_)
|
||||
, freed_memory(0)
|
||||
, required_memory(0)
|
||||
, next_id(0)
|
||||
@ -33,11 +33,11 @@ OvercommitResult OvercommitTracker::needToStopQuery(MemoryTracker * tracker, Int
|
||||
return OvercommitResult::NONE;
|
||||
// NOTE: Do not change the order of locks
|
||||
//
|
||||
// global_mutex must be acquired before overcommit_m, because
|
||||
// global mutex must be acquired before overcommit_m, because
|
||||
// method OvercommitTracker::onQueryStop(MemoryTracker *) is
|
||||
// always called with already acquired global_mutex in
|
||||
// always called with already acquired global mutex in
|
||||
// ProcessListEntry::~ProcessListEntry().
|
||||
std::unique_lock<std::mutex> global_lock(global_mutex);
|
||||
auto global_lock = process_list->unsafeLock();
|
||||
std::unique_lock<std::mutex> lk(overcommit_m);
|
||||
|
||||
size_t id = next_id++;
|
||||
@ -137,8 +137,8 @@ void OvercommitTracker::releaseThreads()
|
||||
cv.notify_all();
|
||||
}
|
||||
|
||||
UserOvercommitTracker::UserOvercommitTracker(DB::ProcessList * process_list, DB::ProcessListForUser * user_process_list_)
|
||||
: OvercommitTracker(process_list->mutex)
|
||||
UserOvercommitTracker::UserOvercommitTracker(DB::ProcessList * process_list_, DB::ProcessListForUser * user_process_list_)
|
||||
: OvercommitTracker(process_list_)
|
||||
, user_process_list(user_process_list_)
|
||||
{}
|
||||
|
||||
@ -169,8 +169,7 @@ void UserOvercommitTracker::pickQueryToExcludeImpl()
|
||||
}
|
||||
|
||||
GlobalOvercommitTracker::GlobalOvercommitTracker(DB::ProcessList * process_list_)
|
||||
: OvercommitTracker(process_list_->mutex)
|
||||
, process_list(process_list_)
|
||||
: OvercommitTracker(process_list_)
|
||||
{}
|
||||
|
||||
void GlobalOvercommitTracker::pickQueryToExcludeImpl()
|
||||
|
@ -36,6 +36,12 @@ struct OvercommitRatio
|
||||
|
||||
class MemoryTracker;
|
||||
|
||||
namespace DB
|
||||
{
|
||||
class ProcessList;
|
||||
struct ProcessListForUser;
|
||||
}
|
||||
|
||||
enum class OvercommitResult
|
||||
{
|
||||
NONE,
|
||||
@ -71,7 +77,7 @@ struct OvercommitTracker : boost::noncopyable
|
||||
virtual ~OvercommitTracker() = default;
|
||||
|
||||
protected:
|
||||
explicit OvercommitTracker(std::mutex & global_mutex_);
|
||||
explicit OvercommitTracker(DB::ProcessList * process_list_);
|
||||
|
||||
virtual void pickQueryToExcludeImpl() = 0;
|
||||
|
||||
@ -86,6 +92,12 @@ protected:
|
||||
// overcommit tracker is in SELECTED state.
|
||||
MemoryTracker * picked_tracker;
|
||||
|
||||
// Global mutex stored in ProcessList is used to synchronize
|
||||
// insertion and deletion of queries.
|
||||
// OvercommitTracker::pickQueryToExcludeImpl() implementations
|
||||
// require this mutex to be locked, because they read list (or sublist)
|
||||
// of queries.
|
||||
DB::ProcessList * process_list;
|
||||
private:
|
||||
|
||||
void pickQueryToExclude()
|
||||
@ -113,12 +125,6 @@ private:
|
||||
|
||||
QueryCancellationState cancellation_state;
|
||||
|
||||
// Global mutex which is used in ProcessList to synchronize
|
||||
// insertion and deletion of queries.
|
||||
// OvercommitTracker::pickQueryToExcludeImpl() implementations
|
||||
// require this mutex to be locked, because they read list (or sublist)
|
||||
// of queries.
|
||||
std::mutex & global_mutex;
|
||||
Int64 freed_memory;
|
||||
Int64 required_memory;
|
||||
|
||||
@ -128,15 +134,9 @@ private:
|
||||
bool allow_release;
|
||||
};
|
||||
|
||||
namespace DB
|
||||
{
|
||||
class ProcessList;
|
||||
struct ProcessListForUser;
|
||||
}
|
||||
|
||||
struct UserOvercommitTracker : OvercommitTracker
|
||||
{
|
||||
explicit UserOvercommitTracker(DB::ProcessList * process_list, DB::ProcessListForUser * user_process_list_);
|
||||
explicit UserOvercommitTracker(DB::ProcessList * process_list_, DB::ProcessListForUser * user_process_list_);
|
||||
|
||||
~UserOvercommitTracker() override = default;
|
||||
|
||||
@ -155,9 +155,6 @@ struct GlobalOvercommitTracker : OvercommitTracker
|
||||
|
||||
protected:
|
||||
void pickQueryToExcludeImpl() override;
|
||||
|
||||
private:
|
||||
DB::ProcessList * process_list;
|
||||
};
|
||||
|
||||
// This class is used to disallow tracking during logging to avoid deadlocks.
|
||||
|
@ -318,6 +318,7 @@ The server successfully detected this situation and will download merged part fr
|
||||
\
|
||||
M(FileSegmentWaitReadBufferMicroseconds, "Metric per file segment. Time spend waiting for internal read buffer (includes cache waiting)") \
|
||||
M(FileSegmentReadMicroseconds, "Metric per file segment. Time spend reading from file") \
|
||||
M(FileSegmentWriteMicroseconds, "Metric per file segment. Time spend writing cache") \
|
||||
M(FileSegmentCacheWriteMicroseconds, "Metric per file segment. Time spend writing data to cache") \
|
||||
M(FileSegmentPredownloadMicroseconds, "Metric per file segment. Time spent predownloading data to cache (predownloading - finishing file segment download (after someone who failed to do that) up to the point current thread was requested to do)") \
|
||||
M(FileSegmentUsedBytes, "Metric per file segment. How many bytes were actually used from current file segment") \
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include <mysqlxx/Pool.h>
|
||||
#include <base/sleep.h>
|
||||
#include <Poco/Util/LayeredConfiguration.h>
|
||||
#include <Common/logger_useful.h>
|
||||
#include <ctime>
|
||||
|
||||
|
||||
@ -260,7 +261,10 @@ void Pool::Entry::forceConnected() const
|
||||
else
|
||||
sleepForSeconds(MYSQLXX_POOL_SLEEP_ON_CONNECT_FAIL);
|
||||
|
||||
pool->logger.debug("Entry: Reconnecting to MySQL server %s", pool->description);
|
||||
pool->logger.debug(
|
||||
"Creating a new MySQL connection to %s with settings: connect_timeout=%u, read_write_timeout=%u",
|
||||
pool->description, pool->connect_timeout, pool->rw_timeout);
|
||||
|
||||
data->conn.connect(
|
||||
pool->db.c_str(),
|
||||
pool->server.c_str(),
|
||||
@ -325,6 +329,10 @@ Pool::Connection * Pool::allocConnection(bool dont_throw_if_failed_first_time)
|
||||
{
|
||||
logger.debug("Connecting to %s", description);
|
||||
|
||||
logger.debug(
|
||||
"Creating a new MySQL connection to %s with settings: connect_timeout=%u, read_write_timeout=%u",
|
||||
description, connect_timeout, rw_timeout);
|
||||
|
||||
conn_ptr->conn.connect(
|
||||
db.c_str(),
|
||||
server.c_str(),
|
||||
|
@ -168,6 +168,7 @@ PoolWithFailover::Entry PoolWithFailover::get()
|
||||
}
|
||||
|
||||
app.logger().warning("Connection to " + pool->getDescription() + " failed: " + e.displayText());
|
||||
|
||||
replica_name_to_error_detail.insert_or_assign(pool->getDescription(), ErrorDetail{e.code(), e.displayText()});
|
||||
|
||||
continue;
|
||||
@ -177,7 +178,10 @@ PoolWithFailover::Entry PoolWithFailover::get()
|
||||
}
|
||||
}
|
||||
|
||||
app.logger().error("Connection to all replicas failed " + std::to_string(try_no + 1) + " times");
|
||||
if (replicas_by_priority.size() > 1)
|
||||
app.logger().error("Connection to all mysql replicas failed " + std::to_string(try_no + 1) + " times");
|
||||
else
|
||||
app.logger().error("Connection to mysql failed " + std::to_string(try_no + 1) + " times");
|
||||
}
|
||||
|
||||
if (full_pool)
|
||||
@ -187,7 +191,11 @@ PoolWithFailover::Entry PoolWithFailover::get()
|
||||
}
|
||||
|
||||
DB::WriteBufferFromOwnString message;
|
||||
message << "Connections to all replicas failed: ";
|
||||
if (replicas_by_priority.size() > 1)
|
||||
message << "Connections to all mysql replicas failed: ";
|
||||
else
|
||||
message << "Connections to mysql failed: ";
|
||||
|
||||
for (auto it = replicas_by_priority.begin(); it != replicas_by_priority.end(); ++it)
|
||||
{
|
||||
for (auto jt = it->second.begin(); jt != it->second.end(); ++jt)
|
||||
|
@ -169,10 +169,24 @@ public:
|
||||
unsigned max_connections_ = MYSQLXX_POOL_DEFAULT_MAX_CONNECTIONS,
|
||||
unsigned enable_local_infile_ = MYSQLXX_DEFAULT_ENABLE_LOCAL_INFILE,
|
||||
bool opt_reconnect_ = MYSQLXX_DEFAULT_MYSQL_OPT_RECONNECT)
|
||||
: logger(Poco::Logger::get("mysqlxx::Pool")), default_connections(default_connections_),
|
||||
max_connections(max_connections_), db(db_), server(server_), user(user_), password(password_), port(port_), socket(socket_),
|
||||
connect_timeout(connect_timeout_), rw_timeout(rw_timeout_), enable_local_infile(enable_local_infile_),
|
||||
opt_reconnect(opt_reconnect_) {}
|
||||
: logger(Poco::Logger::get("mysqlxx::Pool"))
|
||||
, default_connections(default_connections_)
|
||||
, max_connections(max_connections_)
|
||||
, db(db_)
|
||||
, server(server_)
|
||||
, user(user_)
|
||||
, password(password_)
|
||||
, port(port_)
|
||||
, socket(socket_)
|
||||
, connect_timeout(connect_timeout_)
|
||||
, rw_timeout(rw_timeout_)
|
||||
, enable_local_infile(enable_local_infile_)
|
||||
, opt_reconnect(opt_reconnect_)
|
||||
{
|
||||
logger.debug(
|
||||
"Created MySQL Pool with settings: connect_timeout=%u, read_write_timeout=%u, default_connections_number=%u, max_connections_number=%u",
|
||||
connect_timeout, rw_timeout, default_connections, max_connections);
|
||||
}
|
||||
|
||||
Pool(const Pool & other)
|
||||
: logger(other.logger), default_connections{other.default_connections},
|
||||
|
@ -370,6 +370,7 @@ void KeeperServer::startup(const Poco::Util::AbstractConfiguration & config, boo
|
||||
{
|
||||
auto log_entries = log_store->log_entries(state_machine->last_commit_index() + 1, next_log_idx);
|
||||
|
||||
size_t preprocessed = 0;
|
||||
LOG_INFO(log, "Preprocessing {} log entries", log_entries->size());
|
||||
auto idx = state_machine->last_commit_index() + 1;
|
||||
for (const auto & entry : *log_entries)
|
||||
@ -378,7 +379,12 @@ void KeeperServer::startup(const Poco::Util::AbstractConfiguration & config, boo
|
||||
state_machine->pre_commit(idx, entry->get_buf());
|
||||
|
||||
++idx;
|
||||
++preprocessed;
|
||||
|
||||
if (preprocessed % 50000 == 0)
|
||||
LOG_TRACE(log, "Preprocessed {}/{} entries", preprocessed, log_entries->size());
|
||||
}
|
||||
LOG_INFO(log, "Preprocessing done");
|
||||
}
|
||||
|
||||
loadLatestConfig();
|
||||
|
@ -369,7 +369,15 @@ void KeeperStorage::UncommittedState::addDeltas(std::vector<Delta> new_deltas)
|
||||
const auto & added_delta = deltas.emplace_back(std::move(delta));
|
||||
|
||||
if (!added_delta.path.empty())
|
||||
{
|
||||
deltas_for_path[added_delta.path].push_back(&added_delta);
|
||||
applyDelta(added_delta);
|
||||
}
|
||||
else if (const auto * auth_delta = std::get_if<AddAuthDelta>(&added_delta.operation))
|
||||
{
|
||||
auto & uncommitted_auth = session_and_auth[auth_delta->session_id];
|
||||
uncommitted_auth.emplace_back(&auth_delta->auth_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -385,6 +393,26 @@ void KeeperStorage::UncommittedState::commit(int64_t commit_zxid)
|
||||
break;
|
||||
}
|
||||
|
||||
auto & front_delta = deltas.front();
|
||||
|
||||
if (!front_delta.path.empty())
|
||||
{
|
||||
auto & path_deltas = deltas_for_path.at(front_delta.path);
|
||||
assert(path_deltas.front() == &front_delta);
|
||||
path_deltas.pop_front();
|
||||
if (path_deltas.empty())
|
||||
deltas_for_path.erase(front_delta.path);
|
||||
}
|
||||
else if (auto * add_auth = std::get_if<AddAuthDelta>(&front_delta.operation))
|
||||
{
|
||||
auto & uncommitted_auth = session_and_auth[add_auth->session_id];
|
||||
assert(!uncommitted_auth.empty() && uncommitted_auth.front() == &add_auth->auth_id);
|
||||
uncommitted_auth.pop_front();
|
||||
if (uncommitted_auth.empty())
|
||||
session_and_auth.erase(add_auth->session_id);
|
||||
|
||||
}
|
||||
|
||||
deltas.pop_front();
|
||||
}
|
||||
|
||||
@ -405,10 +433,12 @@ void KeeperStorage::UncommittedState::rollback(int64_t rollback_zxid)
|
||||
deltas.back().zxid,
|
||||
rollback_zxid);
|
||||
|
||||
auto delta_it = deltas.rbegin();
|
||||
|
||||
// we need to undo ephemeral mapping modifications
|
||||
// CreateNodeDelta added ephemeral for session id -> we need to remove it
|
||||
// RemoveNodeDelta removed ephemeral for session id -> we need to add it back
|
||||
for (auto delta_it = deltas.rbegin(); delta_it != deltas.rend(); ++delta_it)
|
||||
for (; delta_it != deltas.rend(); ++delta_it)
|
||||
{
|
||||
if (delta_it->zxid < rollback_zxid)
|
||||
break;
|
||||
@ -431,29 +461,56 @@ void KeeperStorage::UncommittedState::rollback(int64_t rollback_zxid)
|
||||
}
|
||||
},
|
||||
delta_it->operation);
|
||||
|
||||
auto & path_deltas = deltas_for_path.at(delta_it->path);
|
||||
if (path_deltas.back() == &*delta_it)
|
||||
{
|
||||
path_deltas.pop_back();
|
||||
if (path_deltas.empty())
|
||||
deltas_for_path.erase(delta_it->path);
|
||||
}
|
||||
}
|
||||
else if (auto * add_auth = std::get_if<AddAuthDelta>(&delta_it->operation))
|
||||
{
|
||||
auto & uncommitted_auth = session_and_auth[add_auth->session_id];
|
||||
if (uncommitted_auth.back() == &add_auth->auth_id)
|
||||
{
|
||||
uncommitted_auth.pop_back();
|
||||
if (uncommitted_auth.empty())
|
||||
session_and_auth.erase(add_auth->session_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::erase_if(deltas, [rollback_zxid](const auto & delta) { return delta.zxid == rollback_zxid; });
|
||||
if (delta_it == deltas.rend())
|
||||
deltas.clear();
|
||||
else
|
||||
deltas.erase(delta_it.base(), deltas.end());
|
||||
|
||||
std::unordered_set<std::string> deleted_nodes;
|
||||
absl::flat_hash_set<std::string> deleted_nodes;
|
||||
std::erase_if(
|
||||
nodes,
|
||||
[&, rollback_zxid](const auto & node)
|
||||
{
|
||||
if (node.second.zxid == rollback_zxid)
|
||||
{
|
||||
deleted_nodes.emplace(node.first);
|
||||
deleted_nodes.emplace(std::move(node.first));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
// recalculate all the uncommitted deleted nodes
|
||||
for (const auto & delta : deltas)
|
||||
for (const auto & deleted_node : deleted_nodes)
|
||||
{
|
||||
if (!delta.path.empty() && deleted_nodes.contains(delta.path))
|
||||
applyDelta(delta);
|
||||
auto path_delta_it = deltas_for_path.find(deleted_node);
|
||||
if (path_delta_it != deltas_for_path.end())
|
||||
{
|
||||
for (const auto & delta : path_delta_it->second)
|
||||
{
|
||||
applyDelta(*delta);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -229,27 +229,42 @@ public:
|
||||
|
||||
bool hasACL(int64_t session_id, bool is_local, std::function<bool(const AuthID &)> predicate)
|
||||
{
|
||||
for (const auto & session_auth : storage.session_and_auth[session_id])
|
||||
const auto check_auth = [&](const auto & auth_ids)
|
||||
{
|
||||
if (predicate(session_auth))
|
||||
return true;
|
||||
}
|
||||
for (const auto & auth : auth_ids)
|
||||
{
|
||||
using TAuth = std::remove_reference_t<decltype(auth)>;
|
||||
|
||||
const AuthID * auth_ptr = nullptr;
|
||||
if constexpr (std::is_pointer_v<TAuth>)
|
||||
auth_ptr = auth;
|
||||
else
|
||||
auth_ptr = &auth;
|
||||
|
||||
if (predicate(*auth_ptr))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
if (is_local)
|
||||
return check_auth(storage.session_and_auth[session_id]);
|
||||
|
||||
if (check_auth(storage.session_and_auth[session_id]))
|
||||
return true;
|
||||
|
||||
// check if there are uncommitted
|
||||
const auto auth_it = session_and_auth.find(session_id);
|
||||
if (auth_it == session_and_auth.end())
|
||||
return false;
|
||||
|
||||
for (const auto & delta : deltas)
|
||||
{
|
||||
if (const auto * auth_delta = std::get_if<KeeperStorage::AddAuthDelta>(&delta.operation);
|
||||
auth_delta && auth_delta->session_id == session_id && predicate(auth_delta->auth_id))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return check_auth(auth_it->second);
|
||||
}
|
||||
|
||||
std::shared_ptr<Node> tryGetNodeFromStorage(StringRef path) const;
|
||||
|
||||
std::unordered_map<int64_t, std::list<const AuthID *>> session_and_auth;
|
||||
|
||||
struct UncommittedNode
|
||||
{
|
||||
std::shared_ptr<Node> node{nullptr};
|
||||
@ -257,7 +272,32 @@ public:
|
||||
int64_t zxid{0};
|
||||
};
|
||||
|
||||
mutable std::unordered_map<std::string, UncommittedNode> nodes;
|
||||
struct Hash
|
||||
{
|
||||
auto operator()(const std::string_view view) const
|
||||
{
|
||||
SipHash hash;
|
||||
hash.update(view);
|
||||
return hash.get64();
|
||||
}
|
||||
|
||||
using is_transparent = void; // required to make find() work with different type than key_type
|
||||
};
|
||||
|
||||
struct Equal
|
||||
{
|
||||
auto operator()(const std::string_view a,
|
||||
const std::string_view b) const
|
||||
{
|
||||
return a == b;
|
||||
}
|
||||
|
||||
using is_transparent = void; // required to make find() work with different type than key_type
|
||||
};
|
||||
|
||||
mutable std::unordered_map<std::string, UncommittedNode, Hash, Equal> nodes;
|
||||
std::unordered_map<std::string, std::list<const Delta *>, Hash, Equal> deltas_for_path;
|
||||
|
||||
std::list<Delta> deltas;
|
||||
KeeperStorage & storage;
|
||||
};
|
||||
|
@ -346,7 +346,7 @@ static constexpr UInt64 operator""_GiB(unsigned long long value)
|
||||
M(UInt64, max_temporary_non_const_columns, 0, "Similar to the 'max_temporary_columns' setting but applies only to non-constant columns. This makes sense, because constant columns are cheap and it is reasonable to allow more of them.", 0) \
|
||||
\
|
||||
M(UInt64, max_subquery_depth, 100, "If a query has more than specified number of nested subqueries, throw an exception. This allows you to have a sanity check to protect the users of your cluster from going insane with their queries.", 0) \
|
||||
M(UInt64, max_pipeline_depth, 1000, "If a query has more than specified stages in the query pipeline, throw an exception. Pipeline has stages for every relational operator. This allows to limit the complexity of the queries.", 0) \
|
||||
M(UInt64, max_analyze_depth, 5000, "Maximum number of analyses performed by interpreter.", 0) \
|
||||
M(UInt64, max_ast_depth, 1000, "Maximum depth of query syntax tree. Checked after parsing.", 0) \
|
||||
M(UInt64, max_ast_elements, 50000, "Maximum size of query syntax tree in number of nodes. Checked after parsing.", 0) \
|
||||
M(UInt64, max_expanded_ast_elements, 500000, "Maximum size of query syntax tree in number of nodes after expansion of aliases and the asterisk.", 0) \
|
||||
@ -554,7 +554,9 @@ static constexpr UInt64 operator""_GiB(unsigned long long value)
|
||||
M(UInt64, external_storage_connect_timeout_sec, DBMS_DEFAULT_CONNECT_TIMEOUT_SEC, "Connect timeout in seconds. Now supported only for MySQL", 0) \
|
||||
M(UInt64, external_storage_rw_timeout_sec, DBMS_DEFAULT_RECEIVE_TIMEOUT_SEC, "Read/write timeout in seconds. Now supported only for MySQL", 0) \
|
||||
\
|
||||
M(UnionMode, union_default_mode, UnionMode::Unspecified, "Set default Union Mode in SelectWithUnion query. Possible values: empty string, 'ALL', 'DISTINCT'. If empty, query without Union Mode will throw exception.", 0) \
|
||||
M(SetOperationMode, union_default_mode, SetOperationMode::Unspecified, "Set default mode in UNION query. Possible values: empty string, 'ALL', 'DISTINCT'. If empty, query without mode will throw exception.", 0) \
|
||||
M(SetOperationMode, intersect_default_mode, SetOperationMode::ALL, "Set default mode in INTERSECT query. Possible values: empty string, 'ALL', 'DISTINCT'. If empty, query without mode will throw exception.", 0) \
|
||||
M(SetOperationMode, except_default_mode, SetOperationMode::ALL, "Set default mode in EXCEPT query. Possible values: empty string, 'ALL', 'DISTINCT'. If empty, query without mode will throw exception.", 0) \
|
||||
M(Bool, optimize_aggregators_of_group_by_keys, true, "Eliminates min/max/any/anyLast aggregators of GROUP BY keys in SELECT section", 0) \
|
||||
M(Bool, optimize_group_by_function_keys, true, "Eliminates functions of other keys in GROUP BY section", 0) \
|
||||
M(Bool, legacy_column_name_of_tuple_literal, false, "List all names of element of large tuple literals in their column names instead of hash. This settings exists only for compatibility reasons. It makes sense to set to 'true', while doing rolling update of cluster from version lower than 21.7 to higher.", 0) \
|
||||
@ -672,6 +674,8 @@ static constexpr UInt64 operator""_GiB(unsigned long long value)
|
||||
MAKE_OBSOLETE(M, UInt64, background_message_broker_schedule_pool_size, 16) \
|
||||
MAKE_OBSOLETE(M, UInt64, background_distributed_schedule_pool_size, 16) \
|
||||
MAKE_OBSOLETE(M, DefaultDatabaseEngine, default_database_engine, DefaultDatabaseEngine::Atomic) \
|
||||
MAKE_OBSOLETE(M, UInt64, max_pipeline_depth, 0) \
|
||||
|
||||
/** The section above is for obsolete settings. Do not add anything there. */
|
||||
|
||||
|
||||
|
@ -114,10 +114,10 @@ IMPLEMENT_SETTING_MULTI_ENUM(MySQLDataTypesSupport, ErrorCodes::UNKNOWN_MYSQL_DA
|
||||
{"date2Date32", MySQLDataTypesSupport::DATE2DATE32},
|
||||
{"date2String", MySQLDataTypesSupport::DATE2STRING}})
|
||||
|
||||
IMPLEMENT_SETTING_ENUM(UnionMode, ErrorCodes::UNKNOWN_UNION,
|
||||
{{"", UnionMode::Unspecified},
|
||||
{"ALL", UnionMode::ALL},
|
||||
{"DISTINCT", UnionMode::DISTINCT}})
|
||||
IMPLEMENT_SETTING_ENUM(SetOperationMode, ErrorCodes::UNKNOWN_UNION,
|
||||
{{"", SetOperationMode::Unspecified},
|
||||
{"ALL", SetOperationMode::ALL},
|
||||
{"DISTINCT", SetOperationMode::DISTINCT}})
|
||||
|
||||
IMPLEMENT_SETTING_ENUM(DistributedDDLOutputMode, ErrorCodes::BAD_ARGUMENTS,
|
||||
{{"none", DistributedDDLOutputMode::NONE},
|
||||
|
@ -130,14 +130,14 @@ enum class MySQLDataTypesSupport
|
||||
|
||||
DECLARE_SETTING_MULTI_ENUM(MySQLDataTypesSupport)
|
||||
|
||||
enum class UnionMode
|
||||
enum class SetOperationMode
|
||||
{
|
||||
Unspecified = 0, // Query UNION without UnionMode will throw exception
|
||||
ALL, // Query UNION without UnionMode -> SELECT ... UNION ALL SELECT ...
|
||||
DISTINCT // Query UNION without UnionMode -> SELECT ... UNION DISTINCT SELECT ...
|
||||
Unspecified = 0, // Query UNION / EXCEPT / INTERSECT without SetOperationMode will throw exception
|
||||
ALL, // Query UNION / EXCEPT / INTERSECT without SetOperationMode -> SELECT ... UNION / EXCEPT / INTERSECT ALL SELECT ...
|
||||
DISTINCT // Query UNION / EXCEPT / INTERSECT without SetOperationMode -> SELECT ... UNION / EXCEPT / INTERSECT DISTINCT SELECT ...
|
||||
};
|
||||
|
||||
DECLARE_SETTING_ENUM(UnionMode)
|
||||
DECLARE_SETTING_ENUM(SetOperationMode)
|
||||
|
||||
enum class DistributedDDLOutputMode
|
||||
{
|
||||
|
@ -1016,8 +1016,8 @@ void BaseDaemon::setupWatchdog()
|
||||
if (config().getRawString("logger.stream_compress", "false") == "true")
|
||||
{
|
||||
Poco::AutoPtr<OwnPatternFormatter> pf;
|
||||
if (config().getString("logger.formatting", "") == "json")
|
||||
pf = new OwnJSONPatternFormatter;
|
||||
if (config().getString("logger.formatting.type", "") == "json")
|
||||
pf = new OwnJSONPatternFormatter(config());
|
||||
else
|
||||
pf = new OwnPatternFormatter;
|
||||
Poco::AutoPtr<DB::OwnFormattingChannel> log = new DB::OwnFormattingChannel(pf, new Poco::ConsoleChannel(std::cerr));
|
||||
|
@ -737,14 +737,31 @@ Field FieldVisitorReplaceScalars::operator()(const Array & x) const
|
||||
return res;
|
||||
}
|
||||
|
||||
size_t FieldVisitorToNumberOfDimensions::operator()(const Array & x) const
|
||||
size_t FieldVisitorToNumberOfDimensions::operator()(const Array & x)
|
||||
{
|
||||
const size_t size = x.size();
|
||||
size_t dimensions = 0;
|
||||
for (size_t i = 0; i < size; ++i)
|
||||
dimensions = std::max(dimensions, applyVisitor(*this, x[i]));
|
||||
{
|
||||
size_t element_dimensions = applyVisitor(*this, x[i]);
|
||||
if (i > 0 && element_dimensions != dimensions)
|
||||
need_fold_dimension = true;
|
||||
dimensions = std::max(dimensions, element_dimensions);
|
||||
}
|
||||
|
||||
return 1 + dimensions;
|
||||
}
|
||||
|
||||
Field FieldVisitorFoldDimension::operator()(const Array & x) const
|
||||
{
|
||||
if (num_dimensions_to_fold == 0)
|
||||
return x;
|
||||
const size_t size = x.size();
|
||||
Array res(size);
|
||||
for (size_t i = 0; i < size; ++i)
|
||||
{
|
||||
res[i] = applyVisitor(FieldVisitorFoldDimension(num_dimensions_to_fold - 1), x[i]);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
@ -114,10 +114,42 @@ private:
|
||||
class FieldVisitorToNumberOfDimensions : public StaticVisitor<size_t>
|
||||
{
|
||||
public:
|
||||
size_t operator()(const Array & x) const;
|
||||
size_t operator()(const Array & x);
|
||||
|
||||
template <typename T>
|
||||
size_t operator()(const T &) const { return 0; }
|
||||
|
||||
bool need_fold_dimension = false;
|
||||
};
|
||||
|
||||
/// Fold field (except Null) to the higher dimension, e.g. `1` -- fold 2 --> `[[1]]`
|
||||
/// used to normalize dimension of element in an array. e.g [1, [2]] --> [[1], [2]]
|
||||
class FieldVisitorFoldDimension : public StaticVisitor<Field>
|
||||
{
|
||||
public:
|
||||
explicit FieldVisitorFoldDimension(size_t num_dimensions_to_fold_) : num_dimensions_to_fold(num_dimensions_to_fold_) { }
|
||||
|
||||
Field operator()(const Array & x) const;
|
||||
|
||||
Field operator()(const Null & x) const { return x; }
|
||||
|
||||
template <typename T>
|
||||
Field operator()(const T & x) const
|
||||
{
|
||||
if (num_dimensions_to_fold == 0)
|
||||
return x;
|
||||
Array res(1,x);
|
||||
for (size_t i = 1; i < num_dimensions_to_fold; ++i)
|
||||
{
|
||||
Array new_res;
|
||||
new_res.push_back(std::move(res));
|
||||
res = std::move(new_res);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
private:
|
||||
size_t num_dimensions_to_fold;
|
||||
};
|
||||
|
||||
/// Receives range of objects, which contains collections
|
||||
|
@ -65,6 +65,8 @@ void SerializationObject<Parser>::deserializeTextImpl(IColumn & column, Reader &
|
||||
for (size_t i = 0; i < paths.size(); ++i)
|
||||
{
|
||||
auto field_info = getFieldInfo(values[i]);
|
||||
if (field_info.need_fold_dimension)
|
||||
values[i] = applyVisitor(FieldVisitorFoldDimension(field_info.num_dimensions), std::move(values[i]));
|
||||
if (isNothing(field_info.scalar_type))
|
||||
continue;
|
||||
|
||||
@ -258,7 +260,12 @@ void SerializationObject<Parser>::serializeBinaryBulkWithMultipleStreams(
|
||||
auto * state_object = checkAndGetState<SerializeStateObject>(state);
|
||||
|
||||
if (!column_object.isFinalized())
|
||||
throw Exception(ErrorCodes::LOGICAL_ERROR, "Cannot write non-finalized ColumnObject");
|
||||
{
|
||||
auto finalized_object = column_object.clone();
|
||||
assert_cast<ColumnObject &>(*finalized_object).finalize();
|
||||
serializeBinaryBulkWithMultipleStreams(*finalized_object, offset, limit, settings, state);
|
||||
return;
|
||||
}
|
||||
|
||||
auto [tuple_column, tuple_type] = unflattenObjectToTuple(column_object);
|
||||
|
||||
|
@ -183,15 +183,15 @@ DatabasePtr DatabaseFactory::getImpl(const ASTCreateQuery & create, const String
|
||||
|
||||
StorageMySQLConfiguration configuration;
|
||||
ASTs & arguments = engine->arguments->children;
|
||||
MySQLSettings mysql_settings;
|
||||
auto mysql_settings = std::make_unique<ConnectionMySQLSettings>();
|
||||
|
||||
if (auto named_collection = getExternalDataSourceConfiguration(arguments, context, true, true, mysql_settings))
|
||||
if (auto named_collection = getExternalDataSourceConfiguration(arguments, context, true, true, *mysql_settings))
|
||||
{
|
||||
auto [common_configuration, storage_specific_args, settings_changes] = named_collection.value();
|
||||
|
||||
configuration.set(common_configuration);
|
||||
configuration.addresses = {std::make_pair(configuration.host, configuration.port)};
|
||||
mysql_settings.applyChanges(settings_changes);
|
||||
mysql_settings->applyChanges(settings_changes);
|
||||
|
||||
if (!storage_specific_args.empty())
|
||||
throw Exception(ErrorCodes::BAD_ARGUMENTS,
|
||||
@ -228,15 +228,14 @@ DatabasePtr DatabaseFactory::getImpl(const ASTCreateQuery & create, const String
|
||||
{
|
||||
if (engine_name == "MySQL")
|
||||
{
|
||||
auto mysql_database_settings = std::make_unique<ConnectionMySQLSettings>();
|
||||
auto mysql_pool = createMySQLPoolWithFailover(configuration, mysql_settings);
|
||||
mysql_settings->loadFromQueryContext(context);
|
||||
mysql_settings->loadFromQuery(*engine_define); /// higher priority
|
||||
|
||||
mysql_database_settings->loadFromQueryContext(context);
|
||||
mysql_database_settings->loadFromQuery(*engine_define); /// higher priority
|
||||
auto mysql_pool = createMySQLPoolWithFailover(configuration, *mysql_settings);
|
||||
|
||||
return std::make_shared<DatabaseMySQL>(
|
||||
context, database_name, metadata_path, engine_define, configuration.database,
|
||||
std::move(mysql_database_settings), std::move(mysql_pool), create.attach);
|
||||
std::move(mysql_settings), std::move(mysql_pool), create.attach);
|
||||
}
|
||||
|
||||
MySQLClient client(configuration.host, configuration.port, configuration.username, configuration.password);
|
||||
|
@ -80,7 +80,7 @@ void CachedOnDiskReadBufferFromFile::appendFilesystemCacheLog(
|
||||
.file_segment_range = { file_segment_range.left, file_segment_range.right },
|
||||
.requested_range = { first_offset, read_until_position },
|
||||
.file_segment_size = file_segment_range.size(),
|
||||
.cache_attempted = true,
|
||||
.read_from_cache_attempted = true,
|
||||
.read_buffer_id = current_buffer_id,
|
||||
.profile_counters = std::make_shared<ProfileEvents::Counters::Snapshot>(
|
||||
current_file_segment_counters.getPartiallyAtomicSnapshot()),
|
||||
@ -703,22 +703,6 @@ bool CachedOnDiskReadBufferFromFile::updateImplementationBufferIfNeeded()
|
||||
size_t download_offset = file_segment->getDownloadOffset();
|
||||
bool cached_part_is_finished = download_offset == file_offset_of_buffer_end;
|
||||
|
||||
#ifndef NDEBUG
|
||||
size_t cache_file_size = getFileSizeFromReadBuffer(*implementation_buffer);
|
||||
size_t cache_file_read_offset = implementation_buffer->getFileOffsetOfBufferEnd();
|
||||
size_t implementation_buffer_finished = cache_file_size == cache_file_read_offset;
|
||||
|
||||
if (cached_part_is_finished != implementation_buffer_finished)
|
||||
{
|
||||
throw Exception(
|
||||
ErrorCodes::LOGICAL_ERROR,
|
||||
"Incorrect state of buffers. Current download offset: {}, file offset of buffer end: {}, "
|
||||
"cache file size: {}, cache file offset: {}, file segment info: {}",
|
||||
download_offset, file_offset_of_buffer_end, cache_file_size, cache_file_read_offset,
|
||||
file_segment->getInfoForLog());
|
||||
}
|
||||
#endif
|
||||
|
||||
if (cached_part_is_finished)
|
||||
{
|
||||
/// TODO: makes sense to reuse local file reader if we return here with CACHED read type again?
|
||||
|
@ -1,13 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include <Common/FileCache.h>
|
||||
#include <Interpreters/Cache/FileCache.h>
|
||||
#include <Common/logger_useful.h>
|
||||
#include <IO/SeekableReadBuffer.h>
|
||||
#include <IO/WriteBufferFromFile.h>
|
||||
#include <IO/ReadSettings.h>
|
||||
#include <IO/ReadBufferFromFileBase.h>
|
||||
#include <Interpreters/FilesystemCacheLog.h>
|
||||
#include <Common/FileSegment.h>
|
||||
#include <Interpreters/Cache/FileSegment.h>
|
||||
|
||||
|
||||
namespace CurrentMetrics
|
||||
|
@ -1,7 +1,7 @@
|
||||
#include "CachedOnDiskWriteBufferFromFile.h"
|
||||
|
||||
#include <Common/FileCacheFactory.h>
|
||||
#include <Common/FileSegment.h>
|
||||
#include <Interpreters/Cache/FileCacheFactory.h>
|
||||
#include <Interpreters/Cache/FileSegment.h>
|
||||
#include <Common/logger_useful.h>
|
||||
#include <Interpreters/FilesystemCacheLog.h>
|
||||
#include <Interpreters/Context.h>
|
||||
@ -11,6 +11,7 @@ namespace ProfileEvents
|
||||
{
|
||||
extern const Event CachedWriteBufferCacheWriteBytes;
|
||||
extern const Event CachedWriteBufferCacheWriteMicroseconds;
|
||||
extern const Event FileSegmentWriteMicroseconds;
|
||||
}
|
||||
|
||||
namespace DB
|
||||
@ -118,6 +119,9 @@ void CachedOnDiskWriteBufferFromFile::cacheData(char * data, size_t size)
|
||||
|
||||
ProfileEvents::increment(ProfileEvents::CachedWriteBufferCacheWriteBytes, size);
|
||||
ProfileEvents::increment(ProfileEvents::CachedWriteBufferCacheWriteMicroseconds, watch.elapsedMicroseconds());
|
||||
|
||||
current_file_segment_counters.increment(
|
||||
ProfileEvents::FileSegmentWriteMicroseconds, watch.elapsedMicroseconds());
|
||||
}
|
||||
|
||||
void CachedOnDiskWriteBufferFromFile::appendFilesystemCacheLog(const FileSegment & file_segment)
|
||||
@ -134,7 +138,7 @@ void CachedOnDiskWriteBufferFromFile::appendFilesystemCacheLog(const FileSegment
|
||||
.requested_range = {},
|
||||
.cache_type = FilesystemCacheLogElement::CacheType::WRITE_THROUGH_CACHE,
|
||||
.file_segment_size = file_segment_range.size(),
|
||||
.cache_attempted = false,
|
||||
.read_from_cache_attempted = false,
|
||||
.read_buffer_id = {},
|
||||
.profile_counters = std::make_shared<ProfileEvents::Counters::Snapshot>(current_file_segment_counters.getPartiallyAtomicSnapshot()),
|
||||
};
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
#include <IO/WriteBufferFromFileDecorator.h>
|
||||
#include <IO/WriteSettings.h>
|
||||
#include <Common/FileCache.h>
|
||||
#include <Interpreters/Cache/FileCache.h>
|
||||
#include <Interpreters/FilesystemCacheLog.h>
|
||||
|
||||
namespace Poco
|
||||
|
@ -81,7 +81,7 @@ void ReadBufferFromRemoteFSGather::appendFilesystemCacheLog()
|
||||
.file_segment_range = { 0, current_file_size },
|
||||
.cache_type = FilesystemCacheLogElement::CacheType::READ_FROM_FS_BYPASSING_CACHE,
|
||||
.file_segment_size = total_bytes_read_from_current_file,
|
||||
.cache_attempted = false,
|
||||
.read_from_cache_attempted = false,
|
||||
};
|
||||
|
||||
if (auto cache_log = Context::getGlobalContextInstance()->getFilesystemCacheLog())
|
||||
|
@ -4,8 +4,8 @@
|
||||
#include <IO/BoundedReadBuffer.h>
|
||||
#include <Disks/IO/CachedOnDiskWriteBufferFromFile.h>
|
||||
#include <Disks/IO/CachedOnDiskReadBufferFromFile.h>
|
||||
#include <Common/FileCache.h>
|
||||
#include <Common/FileCacheFactory.h>
|
||||
#include <Interpreters/Cache/FileCache.h>
|
||||
#include <Interpreters/Cache/FileCacheFactory.h>
|
||||
#include <Common/CurrentThread.h>
|
||||
#include <Common/logger_useful.h>
|
||||
#include <filesystem>
|
||||
|
@ -1,8 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <Disks/ObjectStorages/IObjectStorage.h>
|
||||
#include <Common/FileCache.h>
|
||||
#include <Common/FileCacheSettings.h>
|
||||
#include <Interpreters/Cache/FileCache.h>
|
||||
#include <Interpreters/Cache/FileCacheSettings.h>
|
||||
|
||||
namespace Poco
|
||||
{
|
||||
|
@ -1,6 +1,6 @@
|
||||
#include <Common/FileCacheSettings.h>
|
||||
#include <Common/FileCacheFactory.h>
|
||||
#include <Common/FileCache.h>
|
||||
#include <Interpreters/Cache/FileCacheSettings.h>
|
||||
#include <Interpreters/Cache/FileCacheFactory.h>
|
||||
#include <Interpreters/Cache/FileCache.h>
|
||||
#include <Common/logger_useful.h>
|
||||
#include <Common/assert_cast.h>
|
||||
#include <Disks/DiskFactory.h>
|
||||
|
@ -10,7 +10,6 @@
|
||||
#include <Common/quoteString.h>
|
||||
#include <Common/logger_useful.h>
|
||||
#include <Common/filesystemHelpers.h>
|
||||
#include <Common/FileCache.h>
|
||||
#include <Disks/ObjectStorages/Cached/CachedObjectStorage.h>
|
||||
#include <Disks/ObjectStorages/DiskObjectStorageRemoteMetadataRestoreHelper.h>
|
||||
#include <Disks/ObjectStorages/DiskObjectStorageTransaction.h>
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
#include <Disks/IDisk.h>
|
||||
#include <Disks/ObjectStorages/IObjectStorage.h>
|
||||
#include <Common/FileCache_fwd.h>
|
||||
#include <Disks/ObjectStorages/DiskObjectStorageRemoteMetadataRestoreHelper.h>
|
||||
#include <Disks/ObjectStorages/IMetadataStorage.h>
|
||||
#include <Disks/ObjectStorages/DiskObjectStorageTransaction.h>
|
||||
|
@ -3,6 +3,7 @@
|
||||
#include <Common/checkStackSize.h>
|
||||
#include <ranges>
|
||||
#include <Common/logger_useful.h>
|
||||
#include <Common/Exception.h>
|
||||
|
||||
|
||||
namespace DB
|
||||
@ -633,9 +634,11 @@ void DiskObjectStorageTransaction::commit()
|
||||
{
|
||||
operations_to_execute[i]->execute(metadata_transaction);
|
||||
}
|
||||
catch (Exception & ex)
|
||||
catch (...)
|
||||
{
|
||||
ex.addMessage(fmt::format("While executing operation #{} ({})", i, operations_to_execute[i]->getInfoForLog()));
|
||||
tryLogCurrentException(
|
||||
&Poco::Logger::get("DiskObjectStorageTransaction"),
|
||||
fmt::format("An error occurred while executing transaction's operation #{} ({})", i, operations_to_execute[i]->getInfoForLog()));
|
||||
|
||||
for (int64_t j = i; j >= 0; --j)
|
||||
{
|
||||
@ -643,9 +646,12 @@ void DiskObjectStorageTransaction::commit()
|
||||
{
|
||||
operations_to_execute[j]->undo();
|
||||
}
|
||||
catch (Exception & rollback_ex)
|
||||
catch (...)
|
||||
{
|
||||
rollback_ex.addMessage(fmt::format("While undoing operation #{}", i));
|
||||
tryLogCurrentException(
|
||||
&Poco::Logger::get("DiskObjectStorageTransaction"),
|
||||
fmt::format("An error occurred while undoing transaction's operation #{}", i));
|
||||
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
@ -17,7 +17,6 @@
|
||||
#include <Disks/ObjectStorages/StoredObject.h>
|
||||
#include <Disks/DiskType.h>
|
||||
#include <Common/ThreadPool.h>
|
||||
#include <Common/FileCache.h>
|
||||
#include <Disks/WriteMode.h>
|
||||
|
||||
|
||||
|
@ -1,8 +1,6 @@
|
||||
#include <Disks/ObjectStorages/LocalObjectStorage.h>
|
||||
|
||||
#include <Disks/ObjectStorages/DiskObjectStorageCommon.h>
|
||||
#include <Common/FileCache.h>
|
||||
#include <Common/FileCacheFactory.h>
|
||||
#include <Common/filesystemHelpers.h>
|
||||
#include <Common/logger_useful.h>
|
||||
#include <Disks/IO/createReadBufferFromFileBase.h>
|
||||
|
@ -22,8 +22,6 @@
|
||||
#include <Disks/DiskRestartProxy.h>
|
||||
#include <Disks/DiskLocal.h>
|
||||
|
||||
#include <Common/FileCacheFactory.h>
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
|
@ -6,7 +6,6 @@
|
||||
|
||||
#include <aws/core/client/DefaultRetryStrategy.h>
|
||||
#include <IO/S3Common.h>
|
||||
#include <Disks/DiskCacheWrapper.h>
|
||||
#include <Storages/StorageS3Settings.h>
|
||||
#include <Disks/ObjectStorages/S3/ProxyConfiguration.h>
|
||||
#include <Disks/ObjectStorages/S3/ProxyListConfiguration.h>
|
||||
@ -14,7 +13,6 @@
|
||||
#include <Disks/DiskRestartProxy.h>
|
||||
#include <Disks/DiskLocal.h>
|
||||
#include <Disks/ObjectStorages/DiskObjectStorageCommon.h>
|
||||
#include <Common/FileCacheFactory.h>
|
||||
|
||||
|
||||
namespace DB
|
||||
|
@ -272,6 +272,19 @@ private:
|
||||
writeNumber2(target + 6, ToSecondImpl::execute(source, timezone));
|
||||
}
|
||||
|
||||
static void timezoneOffset(char * target, Time source, const DateLUTImpl & timezone)
|
||||
{
|
||||
auto offset = TimezoneOffsetImpl::execute(source, timezone);
|
||||
if (offset < 0)
|
||||
{
|
||||
*target = '-';
|
||||
offset = -offset;
|
||||
}
|
||||
|
||||
writeNumber2(target + 1, offset / 3600);
|
||||
writeNumber2(target + 3, offset % 3600 / 60);
|
||||
}
|
||||
|
||||
static void quarter(char * target, Time source, const DateLUTImpl & timezone)
|
||||
{
|
||||
*target += ToQuarterImpl::execute(source, timezone);
|
||||
@ -632,6 +645,12 @@ public:
|
||||
result.append("0");
|
||||
break;
|
||||
|
||||
// Offset from UTC timezone as +hhmm or -hhmm
|
||||
case 'z':
|
||||
instructions.emplace_back(&Action<T>::timezoneOffset, 5);
|
||||
result.append("+0000");
|
||||
break;
|
||||
|
||||
/// Time components. If the argument is Date, not a DateTime, then this components will have default value.
|
||||
|
||||
// Minute (00-59)
|
||||
|
@ -9,6 +9,11 @@ namespace ErrorCodes
|
||||
extern const int ARGUMENT_OUT_OF_BOUND;
|
||||
}
|
||||
|
||||
ConcatSeekableReadBuffer::BufferInfo::BufferInfo(BufferInfo && src) noexcept
|
||||
: in(std::exchange(src.in, nullptr)), own_in(std::exchange(src.own_in, false)), size(std::exchange(src.size, 0))
|
||||
{
|
||||
}
|
||||
|
||||
ConcatSeekableReadBuffer::BufferInfo::~BufferInfo()
|
||||
{
|
||||
if (own_in)
|
||||
|
@ -30,7 +30,7 @@ private:
|
||||
struct BufferInfo
|
||||
{
|
||||
BufferInfo() = default;
|
||||
BufferInfo(BufferInfo &&) = default;
|
||||
BufferInfo(BufferInfo && src) noexcept;
|
||||
~BufferInfo();
|
||||
SeekableReadBuffer * in = nullptr;
|
||||
bool own_in = false;
|
||||
|
@ -18,29 +18,38 @@ public:
|
||||
{
|
||||
working_buffer = in.buffer();
|
||||
pos = in.position();
|
||||
hashing_begin = pos;
|
||||
}
|
||||
|
||||
/// calculate hash from the data already read
|
||||
if (!working_buffer.empty())
|
||||
uint128 getHash()
|
||||
{
|
||||
if (pos > hashing_begin)
|
||||
{
|
||||
calculateHash(pos, working_buffer.end() - pos);
|
||||
calculateHash(hashing_begin, pos - hashing_begin);
|
||||
hashing_begin = pos;
|
||||
}
|
||||
return IHashingBuffer<ReadBuffer>::getHash();
|
||||
}
|
||||
|
||||
private:
|
||||
bool nextImpl() override
|
||||
{
|
||||
if (pos > hashing_begin)
|
||||
calculateHash(hashing_begin, pos - hashing_begin);
|
||||
|
||||
in.position() = pos;
|
||||
bool res = in.next();
|
||||
working_buffer = in.buffer();
|
||||
pos = in.position();
|
||||
|
||||
// `pos` may be different from working_buffer.begin() when using sophisticated ReadBuffers.
|
||||
calculateHash(pos, working_buffer.end() - pos);
|
||||
pos = in.position();
|
||||
hashing_begin = pos;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
ReadBuffer & in;
|
||||
BufferBase::Position hashing_begin;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -636,8 +636,9 @@ concept WithResize = requires (T value)
|
||||
template <typename Vector>
|
||||
void readCSVStringInto(Vector & s, ReadBuffer & buf, const FormatSettings::CSV & settings)
|
||||
{
|
||||
/// Empty string
|
||||
if (buf.eof())
|
||||
throwReadAfterEOF();
|
||||
return;
|
||||
|
||||
const char delimiter = settings.delimiter;
|
||||
const char maybe_quote = *buf.position();
|
||||
|
@ -3,7 +3,7 @@
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
#include <Core/Defines.h>
|
||||
#include <Common/FileCache_fwd.h>
|
||||
#include <Interpreters/Cache/FileCache_fwd.h>
|
||||
#include <Common/Throttler_fwd.h>
|
||||
|
||||
namespace DB
|
||||
|
@ -121,9 +121,29 @@ std::shared_ptr<Aws::Http::HttpResponse> PocoHTTPClient::MakeRequest(
|
||||
Aws::Utils::RateLimits::RateLimiterInterface * readLimiter,
|
||||
Aws::Utils::RateLimits::RateLimiterInterface * writeLimiter) const
|
||||
{
|
||||
auto response = Aws::MakeShared<PocoHTTPResponse>("PocoHTTPClient", request);
|
||||
makeRequestInternal(*request, response, readLimiter, writeLimiter);
|
||||
return response;
|
||||
try
|
||||
{
|
||||
auto response = Aws::MakeShared<PocoHTTPResponse>("PocoHTTPClient", request);
|
||||
makeRequestInternal(*request, response, readLimiter, writeLimiter);
|
||||
return response;
|
||||
}
|
||||
catch (const Exception &)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
catch (const Poco::Exception & e)
|
||||
{
|
||||
throw Exception(Exception::CreateFromPocoTag{}, e);
|
||||
}
|
||||
catch (const std::exception & e)
|
||||
{
|
||||
throw Exception(Exception::CreateFromSTDTag{}, e);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
tryLogCurrentException(__PRETTY_FUNCTION__);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
namespace
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
#include <Common/logger_useful.h>
|
||||
#include <Common/Throttler.h>
|
||||
#include <Common/FileCache.h>
|
||||
#include <Interpreters/Cache/FileCache.h>
|
||||
|
||||
#include <IO/WriteBufferFromS3.h>
|
||||
#include <IO/WriteHelpers.h>
|
||||
|
@ -11,10 +11,10 @@
|
||||
#include <Common/CurrentMetrics.h>
|
||||
#include <Common/typeid_cast.h>
|
||||
#include <Common/filesystemHelpers.h>
|
||||
#include <Common/FileCacheFactory.h>
|
||||
#include <Interpreters/Cache/FileCacheFactory.h>
|
||||
#include <Common/getCurrentProcessFDCount.h>
|
||||
#include <Common/getMaxFileDescriptorCount.h>
|
||||
#include <Common/FileCache.h>
|
||||
#include <Interpreters/Cache/FileCache.h>
|
||||
#include <Server/ProtocolServerAdapter.h>
|
||||
#include <Storages/MarkCache.h>
|
||||
#include <Storages/StorageMergeTree.h>
|
||||
@ -77,9 +77,11 @@ static std::unique_ptr<ReadBufferFromFilePRead> openFileIfExists(const std::stri
|
||||
AsynchronousMetrics::AsynchronousMetrics(
|
||||
ContextPtr global_context_,
|
||||
int update_period_seconds,
|
||||
int heavy_metrics_update_period_seconds,
|
||||
const ProtocolServerMetricsFunc & protocol_server_metrics_func_)
|
||||
: WithContext(global_context_)
|
||||
, update_period(update_period_seconds)
|
||||
, heavy_metric_update_period(heavy_metrics_update_period_seconds)
|
||||
, protocol_server_metrics_func(protocol_server_metrics_func_)
|
||||
, log(&Poco::Logger::get("AsynchronousMetrics"))
|
||||
{
|
||||
@ -563,7 +565,7 @@ AsynchronousMetrics::NetworkInterfaceStatValues::operator-(const AsynchronousMet
|
||||
#endif
|
||||
|
||||
|
||||
void AsynchronousMetrics::update(std::chrono::system_clock::time_point update_time)
|
||||
void AsynchronousMetrics::update(TimePoint update_time)
|
||||
{
|
||||
Stopwatch watch;
|
||||
|
||||
@ -1584,6 +1586,8 @@ void AsynchronousMetrics::update(std::chrono::system_clock::time_point update_ti
|
||||
saveAllArenasMetric<size_t>(new_values, "muzzy_purged");
|
||||
#endif
|
||||
|
||||
updateHeavyMetricsIfNeeded(current_time, update_time, new_values);
|
||||
|
||||
/// Add more metrics as you wish.
|
||||
|
||||
new_values["AsynchronousMetricsCalculationTimeSpent"] = watch.elapsedSeconds();
|
||||
@ -1601,4 +1605,76 @@ void AsynchronousMetrics::update(std::chrono::system_clock::time_point update_ti
|
||||
values = new_values;
|
||||
}
|
||||
|
||||
void AsynchronousMetrics::updateDetachedPartsStats()
|
||||
{
|
||||
DetachedPartsStats current_values{};
|
||||
|
||||
for (const auto & db : DatabaseCatalog::instance().getDatabases())
|
||||
{
|
||||
if (!db.second->canContainMergeTreeTables())
|
||||
continue;
|
||||
|
||||
for (auto iterator = db.second->getTablesIterator(getContext()); iterator->isValid(); iterator->next())
|
||||
{
|
||||
const auto & table = iterator->table();
|
||||
if (!table)
|
||||
continue;
|
||||
|
||||
if (MergeTreeData * table_merge_tree = dynamic_cast<MergeTreeData *>(table.get()))
|
||||
{
|
||||
for (const auto & detached_part: table_merge_tree->getDetachedParts())
|
||||
{
|
||||
if (!detached_part.valid_name)
|
||||
continue;
|
||||
|
||||
if (detached_part.prefix.empty())
|
||||
++current_values.detached_by_user;
|
||||
|
||||
++current_values.count;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
detached_parts_stats = current_values;
|
||||
}
|
||||
|
||||
void AsynchronousMetrics::updateHeavyMetricsIfNeeded(TimePoint current_time, TimePoint update_time, AsynchronousMetricValues & new_values)
|
||||
{
|
||||
const auto time_after_previous_update = current_time - heavy_metric_previous_update_time;
|
||||
const bool update_heavy_metric = time_after_previous_update >= heavy_metric_update_period || first_run;
|
||||
|
||||
if (update_heavy_metric)
|
||||
{
|
||||
heavy_metric_previous_update_time = update_time;
|
||||
|
||||
Stopwatch watch;
|
||||
|
||||
/// Test shows that listing 100000 entries consuming around 0.15 sec.
|
||||
updateDetachedPartsStats();
|
||||
|
||||
watch.stop();
|
||||
|
||||
/// Normally heavy metrics don't delay the rest of the metrics calculation
|
||||
/// otherwise log the warning message
|
||||
auto log_level = std::make_pair(DB::LogsLevel::trace, Poco::Message::PRIO_TRACE);
|
||||
if (watch.elapsedSeconds() > (update_period.count() / 2.))
|
||||
log_level = std::make_pair(DB::LogsLevel::debug, Poco::Message::PRIO_DEBUG);
|
||||
else if (watch.elapsedSeconds() > (update_period.count() / 4. * 3))
|
||||
log_level = std::make_pair(DB::LogsLevel::warning, Poco::Message::PRIO_WARNING);
|
||||
LOG_IMPL(log, log_level.first, log_level.second,
|
||||
"Update heavy metrics. "
|
||||
"Update period {} sec. "
|
||||
"Update heavy metrics period {} sec. "
|
||||
"Heavy metrics calculation elapsed: {} sec.",
|
||||
update_period.count(),
|
||||
heavy_metric_update_period.count(),
|
||||
watch.elapsedSeconds());
|
||||
|
||||
}
|
||||
|
||||
new_values["NumberOfDetachedParts"] = detached_parts_stats.count;
|
||||
new_values["NumberOfDetachedByUserParts"] = detached_parts_stats.detached_by_user;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -50,6 +50,7 @@ public:
|
||||
AsynchronousMetrics(
|
||||
ContextPtr global_context_,
|
||||
int update_period_seconds,
|
||||
int heavy_metrics_update_period_seconds,
|
||||
const ProtocolServerMetricsFunc & protocol_server_metrics_func_);
|
||||
|
||||
~AsynchronousMetrics();
|
||||
@ -63,7 +64,11 @@ public:
|
||||
AsynchronousMetricValues getValues() const;
|
||||
|
||||
private:
|
||||
const std::chrono::seconds update_period;
|
||||
using Duration = std::chrono::seconds;
|
||||
using TimePoint = std::chrono::system_clock::time_point;
|
||||
|
||||
const Duration update_period;
|
||||
const Duration heavy_metric_update_period;
|
||||
ProtocolServerMetricsFunc protocol_server_metrics_func;
|
||||
|
||||
mutable std::mutex mutex;
|
||||
@ -74,7 +79,16 @@ private:
|
||||
/// Some values are incremental and we have to calculate the difference.
|
||||
/// On first run we will only collect the values to subtract later.
|
||||
bool first_run = true;
|
||||
std::chrono::system_clock::time_point previous_update_time;
|
||||
TimePoint previous_update_time;
|
||||
TimePoint heavy_metric_previous_update_time;
|
||||
|
||||
struct DetachedPartsStats
|
||||
{
|
||||
size_t count;
|
||||
size_t detached_by_user;
|
||||
};
|
||||
|
||||
DetachedPartsStats detached_parts_stats{};
|
||||
|
||||
#if defined(OS_LINUX) || defined(OS_FREEBSD)
|
||||
MemoryStatisticsOS memory_stat;
|
||||
@ -185,7 +199,10 @@ private:
|
||||
std::unique_ptr<ThreadFromGlobalPool> thread;
|
||||
|
||||
void run();
|
||||
void update(std::chrono::system_clock::time_point update_time);
|
||||
void update(TimePoint update_time);
|
||||
|
||||
void updateDetachedPartsStats();
|
||||
void updateHeavyMetricsIfNeeded(TimePoint current_time, TimePoint update_time, AsynchronousMetricValues & new_values);
|
||||
|
||||
Poco::Logger * log;
|
||||
};
|
||||
|
@ -2,7 +2,8 @@
|
||||
|
||||
#include <Common/randomSeed.h>
|
||||
#include <Common/SipHash.h>
|
||||
#include <Common/FileCacheSettings.h>
|
||||
#include <Interpreters/Cache/FileCacheSettings.h>
|
||||
#include <Interpreters/Cache/LRUFileCachePriority.h>
|
||||
#include <IO/ReadHelpers.h>
|
||||
#include <IO/WriteBufferFromFile.h>
|
||||
#include <IO/ReadSettings.h>
|
||||
@ -10,7 +11,6 @@
|
||||
#include <IO/Operators.h>
|
||||
#include <pcg-random/pcg_random.hpp>
|
||||
#include <filesystem>
|
||||
#include <Common/LRUFileCachePriority.h>
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
@ -59,6 +59,24 @@ String FileCache::getPathInLocalCache(const Key & key) const
|
||||
return fs::path(cache_base_path) / key_str.substr(0, 3) / key_str;
|
||||
}
|
||||
|
||||
void FileCache::removeKeyDirectoryIfExists(const Key & key, std::lock_guard<std::mutex> & /* cache_lock */) const
|
||||
{
|
||||
/// Note: it is guaranteed that there is no concurrency here with files deletion
|
||||
/// because cache key directories are create only in FileCache class under cache_lock.
|
||||
|
||||
auto key_str = key.toString();
|
||||
auto key_prefix_path = fs::path(cache_base_path) / key_str.substr(0, 3);
|
||||
auto key_path = key_prefix_path / key_str;
|
||||
|
||||
if (!fs::exists(key_path))
|
||||
return;
|
||||
|
||||
fs::remove_all(key_path);
|
||||
|
||||
if (fs::is_empty(key_prefix_path))
|
||||
fs::remove(key_prefix_path);
|
||||
}
|
||||
|
||||
static bool isQueryInitialized()
|
||||
{
|
||||
return CurrentThread::isInitialized()
|
||||
@ -71,10 +89,15 @@ bool FileCache::isReadOnly()
|
||||
return !isQueryInitialized();
|
||||
}
|
||||
|
||||
void FileCache::assertInitialized() const
|
||||
void FileCache::assertInitialized(std::lock_guard<std::mutex> & /* cache_lock */) const
|
||||
{
|
||||
if (!is_initialized)
|
||||
throw Exception(ErrorCodes::REMOTE_FS_OBJECT_CACHE_ERROR, "Cache not initialized");
|
||||
{
|
||||
if (initialization_exception)
|
||||
std::rethrow_exception(initialization_exception);
|
||||
else
|
||||
throw Exception(ErrorCodes::REMOTE_FS_OBJECT_CACHE_ERROR, "Cache not initialized");
|
||||
}
|
||||
}
|
||||
|
||||
void FileCache::initialize()
|
||||
@ -90,28 +113,43 @@ void FileCache::initialize()
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
tryLogCurrentException(__PRETTY_FUNCTION__);
|
||||
initialization_exception = std::current_exception();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fs::create_directories(cache_base_path);
|
||||
}
|
||||
|
||||
is_initialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
void FileCache::useCell(
|
||||
const FileSegmentCell & cell, FileSegments & result, std::lock_guard<std::mutex> & cache_lock) const
|
||||
const FileSegmentCell & cell, FileSegments & result, std::lock_guard<std::mutex> & cache_lock)
|
||||
{
|
||||
auto file_segment = cell.file_segment;
|
||||
|
||||
if (file_segment->isDownloaded()
|
||||
&& fs::file_size(getPathInLocalCache(file_segment->key(), file_segment->offset(), file_segment->isPersistent())) == 0)
|
||||
throw Exception(
|
||||
ErrorCodes::LOGICAL_ERROR,
|
||||
"Cannot have zero size downloaded file segments. {}",
|
||||
file_segment->getInfoForLog());
|
||||
if (file_segment->isDownloaded())
|
||||
{
|
||||
fs::path path = file_segment->getPathInLocalCache();
|
||||
if (!fs::exists(path))
|
||||
{
|
||||
throw Exception(
|
||||
ErrorCodes::LOGICAL_ERROR,
|
||||
"File path does not exist, but file has DOWNLOADED state. {}",
|
||||
file_segment->getInfoForLog());
|
||||
}
|
||||
|
||||
if (fs::file_size(path) == 0)
|
||||
{
|
||||
throw Exception(
|
||||
ErrorCodes::LOGICAL_ERROR,
|
||||
"Cannot have zero size downloaded file segments. {}",
|
||||
file_segment->getInfoForLog());
|
||||
}
|
||||
}
|
||||
|
||||
result.push_back(cell.file_segment);
|
||||
|
||||
@ -154,15 +192,8 @@ FileSegments FileCache::getImpl(
|
||||
const auto & file_segments = it->second;
|
||||
if (file_segments.empty())
|
||||
{
|
||||
auto key_path = getPathInLocalCache(key);
|
||||
|
||||
files.erase(key);
|
||||
|
||||
/// Note: it is guaranteed that there is no concurrency with files deletion,
|
||||
/// because cache files are deleted only inside FileCache and under cache lock.
|
||||
if (fs::exists(key_path))
|
||||
fs::remove_all(key_path);
|
||||
|
||||
removeKeyDirectoryIfExists(key, cache_lock);
|
||||
return {};
|
||||
}
|
||||
|
||||
@ -222,7 +253,12 @@ FileSegments FileCache::getImpl(
|
||||
}
|
||||
|
||||
FileSegments FileCache::splitRangeIntoCells(
|
||||
const Key & key, size_t offset, size_t size, FileSegment::State state, bool is_persistent, std::lock_guard<std::mutex> & cache_lock)
|
||||
const Key & key,
|
||||
size_t offset,
|
||||
size_t size,
|
||||
FileSegment::State state,
|
||||
bool is_persistent,
|
||||
std::lock_guard<std::mutex> & cache_lock)
|
||||
{
|
||||
assert(size > 0);
|
||||
|
||||
@ -346,16 +382,16 @@ void FileCache::fillHolesWithEmptyFileSegments(
|
||||
|
||||
FileSegmentsHolder FileCache::getOrSet(const Key & key, size_t offset, size_t size, bool is_persistent)
|
||||
{
|
||||
assertInitialized();
|
||||
|
||||
FileSegment::Range range(offset, offset + size - 1);
|
||||
|
||||
std::lock_guard cache_lock(mutex);
|
||||
|
||||
assertInitialized(cache_lock);
|
||||
|
||||
#ifndef NDEBUG
|
||||
assertCacheCorrectness(key, cache_lock);
|
||||
#endif
|
||||
|
||||
FileSegment::Range range(offset, offset + size - 1);
|
||||
|
||||
/// Get all segments which intersect with the given range.
|
||||
auto file_segments = getImpl(key, range, cache_lock);
|
||||
|
||||
@ -374,16 +410,16 @@ FileSegmentsHolder FileCache::getOrSet(const Key & key, size_t offset, size_t si
|
||||
|
||||
FileSegmentsHolder FileCache::get(const Key & key, size_t offset, size_t size)
|
||||
{
|
||||
assertInitialized();
|
||||
|
||||
FileSegment::Range range(offset, offset + size - 1);
|
||||
|
||||
std::lock_guard cache_lock(mutex);
|
||||
|
||||
assertInitialized(cache_lock);
|
||||
|
||||
#ifndef NDEBUG
|
||||
assertCacheCorrectness(key, cache_lock);
|
||||
#endif
|
||||
|
||||
FileSegment::Range range(offset, offset + size - 1);
|
||||
|
||||
/// Get all segments which intersect with the given range.
|
||||
auto file_segments = getImpl(key, range, cache_lock);
|
||||
|
||||
@ -417,7 +453,7 @@ FileCache::FileSegmentCell * FileCache::addCell(
|
||||
if (files[key].contains(offset))
|
||||
throw Exception(
|
||||
ErrorCodes::LOGICAL_ERROR,
|
||||
"Cache already exists for key: `{}`, offset: {}, size: {}.\nCurrent cache structure: {}",
|
||||
"Cache cell already exists for key: `{}`, offset: {}, size: {}.\nCurrent cache structure: {}",
|
||||
key.toString(), offset, size, dumpStructureUnlocked(key, cache_lock));
|
||||
|
||||
auto skip_or_download = [&]() -> FileSegmentPtr
|
||||
@ -605,9 +641,7 @@ bool FileCache::tryReserve(const Key & key, size_t offset, size_t size, std::loc
|
||||
auto remove_file_segment = [&](FileSegmentPtr file_segment, size_t file_segment_size)
|
||||
{
|
||||
query_context->remove(file_segment->key(), file_segment->offset(), file_segment_size, cache_lock);
|
||||
|
||||
std::lock_guard segment_lock(file_segment->mutex);
|
||||
remove(file_segment->key(), file_segment->offset(), cache_lock, segment_lock);
|
||||
remove(file_segment, cache_lock);
|
||||
};
|
||||
|
||||
assert(trash.empty());
|
||||
@ -724,19 +758,13 @@ bool FileCache::tryReserveForMainList(
|
||||
}
|
||||
}
|
||||
|
||||
auto remove_file_segment = [&](FileSegmentPtr file_segment)
|
||||
{
|
||||
std::lock_guard segment_lock(file_segment->mutex);
|
||||
remove(file_segment->key(), file_segment->offset(), cache_lock, segment_lock);
|
||||
};
|
||||
|
||||
/// This case is very unlikely, can happen in case of exception from
|
||||
/// file_segment->complete(), which would be a logical error.
|
||||
assert(trash.empty());
|
||||
for (auto & cell : trash)
|
||||
{
|
||||
if (auto file_segment = cell->file_segment)
|
||||
remove_file_segment(file_segment);
|
||||
remove(file_segment, cache_lock);
|
||||
}
|
||||
|
||||
if (is_overflow())
|
||||
@ -758,7 +786,7 @@ bool FileCache::tryReserveForMainList(
|
||||
for (auto & cell : to_evict)
|
||||
{
|
||||
if (auto file_segment = cell->file_segment)
|
||||
remove_file_segment(file_segment);
|
||||
remove(file_segment, cache_lock);
|
||||
}
|
||||
|
||||
if (main_priority->getCacheSize(cache_lock) > (1ull << 63))
|
||||
@ -772,10 +800,10 @@ bool FileCache::tryReserveForMainList(
|
||||
|
||||
void FileCache::removeIfExists(const Key & key)
|
||||
{
|
||||
assertInitialized();
|
||||
|
||||
std::lock_guard cache_lock(mutex);
|
||||
|
||||
assertInitialized(cache_lock);
|
||||
|
||||
auto it = files.find(key);
|
||||
if (it == files.end())
|
||||
return;
|
||||
@ -810,14 +838,10 @@ void FileCache::removeIfExists(const Key & key)
|
||||
}
|
||||
}
|
||||
|
||||
auto key_path = getPathInLocalCache(key);
|
||||
|
||||
if (!some_cells_were_skipped)
|
||||
{
|
||||
files.erase(key);
|
||||
|
||||
if (fs::exists(key_path))
|
||||
fs::remove_all(key_path);
|
||||
removeKeyDirectoryIfExists(key, cache_lock);
|
||||
}
|
||||
}
|
||||
|
||||
@ -869,27 +893,36 @@ void FileCache::removeIfReleasable()
|
||||
#endif
|
||||
}
|
||||
|
||||
void FileCache::remove(FileSegmentPtr file_segment, std::lock_guard<std::mutex> & cache_lock)
|
||||
{
|
||||
std::lock_guard segment_lock(file_segment->mutex);
|
||||
remove(file_segment->key(), file_segment->offset(), cache_lock, segment_lock);
|
||||
}
|
||||
|
||||
void FileCache::remove(
|
||||
Key key, size_t offset,
|
||||
std::lock_guard<std::mutex> & cache_lock, std::lock_guard<std::mutex> & /* segment_lock */)
|
||||
{
|
||||
LOG_DEBUG(log, "Remove from cache. Key: {}, offset: {}", key.toString(), offset);
|
||||
|
||||
auto * cell = getCell(key, offset, cache_lock);
|
||||
if (!cell)
|
||||
throw Exception(ErrorCodes::LOGICAL_ERROR, "No cache cell for key: {}, offset: {}", key.toString(), offset);
|
||||
String cache_file_path;
|
||||
|
||||
bool is_persistent_file_segment = cell->file_segment->isPersistent();
|
||||
|
||||
if (cell->queue_iterator)
|
||||
{
|
||||
cell->queue_iterator->removeAndGetNext(cache_lock);
|
||||
auto * cell = getCell(key, offset, cache_lock);
|
||||
if (!cell)
|
||||
throw Exception(ErrorCodes::LOGICAL_ERROR, "No cache cell for key: {}, offset: {}", key.toString(), offset);
|
||||
|
||||
if (cell->queue_iterator)
|
||||
{
|
||||
cell->queue_iterator->removeAndGetNext(cache_lock);
|
||||
}
|
||||
|
||||
cache_file_path = cell->file_segment->getPathInLocalCache();
|
||||
}
|
||||
|
||||
auto & offsets = files[key];
|
||||
offsets.erase(offset);
|
||||
|
||||
auto cache_file_path = getPathInLocalCache(key, offset, is_persistent_file_segment);
|
||||
if (fs::exists(cache_file_path))
|
||||
{
|
||||
try
|
||||
@ -898,19 +931,16 @@ void FileCache::remove(
|
||||
|
||||
if (is_initialized && offsets.empty())
|
||||
{
|
||||
auto key_path = getPathInLocalCache(key);
|
||||
|
||||
files.erase(key);
|
||||
|
||||
if (fs::exists(key_path))
|
||||
fs::remove_all(key_path);
|
||||
removeKeyDirectoryIfExists(key, cache_lock);
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
throw Exception(ErrorCodes::REMOTE_FS_OBJECT_CACHE_ERROR,
|
||||
"Removal of cached file failed. Key: {}, offset: {}, path: {}, error: {}",
|
||||
key.toString(), offset, cache_file_path, getCurrentExceptionMessage(false));
|
||||
throw Exception(
|
||||
ErrorCodes::REMOTE_FS_OBJECT_CACHE_ERROR,
|
||||
"Removal of cached file failed. Key: {}, offset: {}, path: {}, error: {}",
|
||||
key.toString(), offset, cache_file_path, getCurrentExceptionMessage(false));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1139,9 +1169,10 @@ FileCache::FileSegmentCell::FileSegmentCell(
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw Exception(ErrorCodes::REMOTE_FS_OBJECT_CACHE_ERROR,
|
||||
"Can create cell with either EMPTY, DOWNLOADED, DOWNLOADING state, got: {}",
|
||||
FileSegment::stateToString(file_segment->download_state));
|
||||
throw Exception(
|
||||
ErrorCodes::REMOTE_FS_OBJECT_CACHE_ERROR,
|
||||
"Can create cell with either EMPTY, DOWNLOADED, DOWNLOADING state, got: {}",
|
||||
FileSegment::stateToString(file_segment->download_state));
|
||||
}
|
||||
}
|
||||
|
@ -13,11 +13,11 @@
|
||||
|
||||
#include <Core/Types.h>
|
||||
#include <IO/ReadSettings.h>
|
||||
#include <Common/FileCache_fwd.h>
|
||||
#include <Common/FileSegment.h>
|
||||
#include <Common/IFileCachePriority.h>
|
||||
#include <Interpreters/Cache/FileCache_fwd.h>
|
||||
#include <Interpreters/Cache/FileSegment.h>
|
||||
#include <Interpreters/Cache/IFileCachePriority.h>
|
||||
#include <Common/logger_useful.h>
|
||||
#include <Common/FileCacheType.h>
|
||||
#include <Interpreters/Cache/FileCacheKey.h>
|
||||
|
||||
namespace DB
|
||||
{
|
||||
@ -140,7 +140,9 @@ private:
|
||||
bool enable_filesystem_query_cache_limit;
|
||||
|
||||
Poco::Logger * log;
|
||||
|
||||
bool is_initialized = false;
|
||||
std::exception_ptr initialization_exception;
|
||||
|
||||
mutable std::mutex mutex;
|
||||
|
||||
@ -152,6 +154,10 @@ private:
|
||||
std::lock_guard<std::mutex> & cache_lock,
|
||||
std::lock_guard<std::mutex> & segment_lock);
|
||||
|
||||
void remove(
|
||||
FileSegmentPtr file_segment,
|
||||
std::lock_guard<std::mutex> & cache_lock);
|
||||
|
||||
bool isLastFileSegmentHolder(
|
||||
const Key & key,
|
||||
size_t offset,
|
||||
@ -164,7 +170,7 @@ private:
|
||||
std::lock_guard<std::mutex> & cache_lock,
|
||||
std::lock_guard<std::mutex> & segment_lock);
|
||||
|
||||
void assertInitialized() const;
|
||||
void assertInitialized(std::lock_guard<std::mutex> & cache_lock) const;
|
||||
|
||||
struct FileSegmentCell : private boost::noncopyable
|
||||
{
|
||||
@ -220,7 +226,7 @@ private:
|
||||
bool is_persistent,
|
||||
std::lock_guard<std::mutex> & cache_lock);
|
||||
|
||||
void useCell(const FileSegmentCell & cell, FileSegments & result, std::lock_guard<std::mutex> & cache_lock) const;
|
||||
static void useCell(const FileSegmentCell & cell, FileSegments & result, std::lock_guard<std::mutex> & cache_lock);
|
||||
|
||||
bool tryReserveForMainList(
|
||||
const Key & key,
|
||||
@ -255,6 +261,8 @@ private:
|
||||
|
||||
void assertCacheCellsCorrectness(const FileSegmentsByOffset & cells_by_offset, std::lock_guard<std::mutex> & cache_lock);
|
||||
|
||||
void removeKeyDirectoryIfExists(const Key & key, std::lock_guard<std::mutex> & cache_lock) const;
|
||||
|
||||
/// Used to track and control the cache access of each query.
|
||||
/// Through it, we can realize the processing of different queries by the cache layer.
|
||||
struct QueryContext
|
@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <Common/FileCache_fwd.h>
|
||||
#include <Common/FileCacheSettings.h>
|
||||
#include <Interpreters/Cache/FileCache_fwd.h>
|
||||
#include <Interpreters/Cache/FileCacheSettings.h>
|
||||
|
||||
#include <boost/noncopyable.hpp>
|
||||
#include <unordered_map>
|
@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <Common/FileCache_fwd.h>
|
||||
#include <Interpreters/Cache/FileCache_fwd.h>
|
||||
|
||||
namespace Poco { namespace Util { class AbstractConfiguration; } } // NOLINT(cppcoreguidelines-virtual-class-destructor)
|
||||
|
@ -3,7 +3,7 @@
|
||||
#include <base/getThreadId.h>
|
||||
#include <base/scope_guard.h>
|
||||
#include <Common/logger_useful.h>
|
||||
#include <Common/FileCache.h>
|
||||
#include <Interpreters/Cache/FileCache.h>
|
||||
#include <Common/hex.h>
|
||||
#include <IO/WriteBufferFromString.h>
|
||||
#include <IO/Operators.h>
|
||||
@ -78,19 +78,19 @@ FileSegment::State FileSegment::state() const
|
||||
size_t FileSegment::getDownloadOffset() const
|
||||
{
|
||||
std::lock_guard segment_lock(mutex);
|
||||
return range().left + getDownloadedSize(segment_lock);
|
||||
return range().left + getDownloadedSizeUnlocked(segment_lock);
|
||||
}
|
||||
|
||||
size_t FileSegment::getDownloadedSize() const
|
||||
{
|
||||
std::lock_guard segment_lock(mutex);
|
||||
return getDownloadedSize(segment_lock);
|
||||
return getDownloadedSizeUnlocked(segment_lock);
|
||||
}
|
||||
|
||||
size_t FileSegment::getRemainingSizeToDownload() const
|
||||
{
|
||||
std::lock_guard segment_lock(mutex);
|
||||
return range().size() - downloaded_size;
|
||||
return range().size() - getDownloadedSizeUnlocked(segment_lock);
|
||||
}
|
||||
|
||||
bool FileSegment::isDetached() const
|
||||
@ -99,7 +99,7 @@ bool FileSegment::isDetached() const
|
||||
return is_detached;
|
||||
}
|
||||
|
||||
size_t FileSegment::getDownloadedSize(std::lock_guard<std::mutex> & /* segment_lock */) const
|
||||
size_t FileSegment::getDownloadedSizeUnlocked(std::lock_guard<std::mutex> & /* segment_lock */) const
|
||||
{
|
||||
if (download_state == State::DOWNLOADED)
|
||||
return downloaded_size;
|
||||
@ -159,7 +159,7 @@ void FileSegment::resetDownloader()
|
||||
|
||||
void FileSegment::resetDownloaderImpl(std::lock_guard<std::mutex> & segment_lock)
|
||||
{
|
||||
if (downloaded_size == range().size())
|
||||
if (getDownloadedSizeUnlocked(segment_lock) == range().size())
|
||||
setDownloaded(segment_lock);
|
||||
else
|
||||
download_state = State::PARTIALLY_DOWNLOADED;
|
||||
@ -241,14 +241,16 @@ void FileSegment::write(const char * from, size_t size, size_t offset_)
|
||||
"Not enough space is reserved. Available: {}, expected: {}", availableSize(), size);
|
||||
|
||||
if (!isDownloader())
|
||||
throw Exception(ErrorCodes::LOGICAL_ERROR,
|
||||
"Only downloader can do the downloading. (CallerId: {}, DownloaderId: {})",
|
||||
getCallerId(), downloader_id);
|
||||
throw Exception(
|
||||
ErrorCodes::LOGICAL_ERROR,
|
||||
"Only downloader can do the downloading. (CallerId: {}, DownloaderId: {})",
|
||||
getCallerId(), downloader_id);
|
||||
|
||||
if (downloaded_size == range().size())
|
||||
throw Exception(ErrorCodes::REMOTE_FS_OBJECT_CACHE_ERROR,
|
||||
"Attempt to write {} bytes to offset: {}, but current file segment is already fully downloaded",
|
||||
size, offset_);
|
||||
if (getDownloadedSize() == range().size())
|
||||
throw Exception(
|
||||
ErrorCodes::REMOTE_FS_OBJECT_CACHE_ERROR,
|
||||
"Attempt to write {} bytes to offset: {}, but current file segment is already fully downloaded",
|
||||
size, offset_);
|
||||
|
||||
auto download_offset = range().left + downloaded_size;
|
||||
if (offset_ != download_offset)
|
||||
@ -331,9 +333,9 @@ FileSegment::State FileSegment::wait()
|
||||
return download_state;
|
||||
}
|
||||
|
||||
bool FileSegment::reserve(size_t size)
|
||||
bool FileSegment::reserve(size_t size_to_reserve)
|
||||
{
|
||||
if (!size)
|
||||
if (!size_to_reserve)
|
||||
throw Exception(ErrorCodes::REMOTE_FS_OBJECT_CACHE_ERROR, "Zero space reservation is not allowed");
|
||||
|
||||
{
|
||||
@ -350,12 +352,16 @@ bool FileSegment::reserve(size_t size)
|
||||
caller_id, downloader_id);
|
||||
}
|
||||
|
||||
if (downloaded_size + size > range().size())
|
||||
throw Exception(ErrorCodes::REMOTE_FS_OBJECT_CACHE_ERROR,
|
||||
"Attempt to reserve space too much space ({}) for file segment with range: {} (downloaded size: {})",
|
||||
size, range().toString(), downloaded_size);
|
||||
size_t current_downloaded_size = getDownloadedSizeUnlocked(segment_lock);
|
||||
if (current_downloaded_size + size_to_reserve > range().size())
|
||||
{
|
||||
throw Exception(
|
||||
ErrorCodes::REMOTE_FS_OBJECT_CACHE_ERROR,
|
||||
"Attempt to reserve space too much space: {} ({})",
|
||||
size_to_reserve, getInfoForLogImpl(segment_lock));
|
||||
}
|
||||
|
||||
assert(reserved_size >= downloaded_size);
|
||||
assert(reserved_size >= current_downloaded_size);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -363,29 +369,45 @@ bool FileSegment::reserve(size_t size)
|
||||
* in case previous downloader did not fully download current file_segment
|
||||
* and the caller is going to continue;
|
||||
*/
|
||||
size_t free_space = reserved_size - downloaded_size;
|
||||
size_t size_to_reserve = size - free_space;
|
||||
|
||||
std::lock_guard cache_lock(cache->mutex);
|
||||
size_t current_downloaded_size = getDownloadedSize();
|
||||
assert(reserved_size >= current_downloaded_size);
|
||||
size_t already_reserved_size = reserved_size - current_downloaded_size;
|
||||
|
||||
bool reserved = cache->tryReserve(key(), offset(), size_to_reserve, cache_lock);
|
||||
|
||||
if (reserved)
|
||||
bool reserved = already_reserved_size >= size_to_reserve;
|
||||
if (!reserved)
|
||||
{
|
||||
std::lock_guard segment_lock(mutex);
|
||||
reserved_size += size;
|
||||
std::lock_guard cache_lock(cache->mutex);
|
||||
|
||||
size_to_reserve = size_to_reserve - already_reserved_size;
|
||||
reserved = cache->tryReserve(key(), offset(), size_to_reserve, cache_lock);
|
||||
|
||||
if (reserved)
|
||||
{
|
||||
std::lock_guard segment_lock(mutex);
|
||||
reserved_size += size_to_reserve;
|
||||
}
|
||||
}
|
||||
|
||||
return reserved;
|
||||
}
|
||||
|
||||
void FileSegment::setDownloaded(std::lock_guard<std::mutex> & /* segment_lock */)
|
||||
bool FileSegment::isDownloaded() const
|
||||
{
|
||||
std::lock_guard segment_lock(mutex);
|
||||
return isDownloadedUnlocked(segment_lock);
|
||||
}
|
||||
|
||||
bool FileSegment::isDownloadedUnlocked(std::lock_guard<std::mutex> & /* segment_lock */) const
|
||||
{
|
||||
return is_downloaded;
|
||||
}
|
||||
|
||||
void FileSegment::setDownloaded([[maybe_unused]] std::lock_guard<std::mutex> & segment_lock)
|
||||
{
|
||||
if (is_downloaded)
|
||||
return;
|
||||
|
||||
download_state = State::DOWNLOADED;
|
||||
is_downloaded = true;
|
||||
downloader_id.clear();
|
||||
|
||||
if (cache_writer)
|
||||
@ -394,6 +416,12 @@ void FileSegment::setDownloaded(std::lock_guard<std::mutex> & /* segment_lock */
|
||||
cache_writer.reset();
|
||||
remote_file_reader.reset();
|
||||
}
|
||||
|
||||
download_state = State::DOWNLOADED;
|
||||
is_downloaded = true;
|
||||
|
||||
assert(getDownloadedSizeUnlocked(segment_lock) > 0);
|
||||
assert(std::filesystem::file_size(getPathInLocalCache()) > 0);
|
||||
}
|
||||
|
||||
void FileSegment::setDownloadFailed(std::lock_guard<std::mutex> & /* segment_lock */)
|
||||
@ -426,7 +454,7 @@ void FileSegment::completeBatchAndResetDownloader()
|
||||
|
||||
resetDownloaderImpl(segment_lock);
|
||||
|
||||
LOG_TEST(log, "Complete batch. Current downloaded size: {}", downloaded_size);
|
||||
LOG_TEST(log, "Complete batch. Current downloaded size: {}", getDownloadedSizeUnlocked(segment_lock));
|
||||
|
||||
cv.notify_all();
|
||||
}
|
||||
@ -475,7 +503,7 @@ void FileSegment::completeBasedOnCurrentState(std::lock_guard<std::mutex> & cach
|
||||
bool is_downloader = isDownloaderImpl(segment_lock);
|
||||
bool is_last_holder = cache->isLastFileSegmentHolder(key(), offset(), cache_lock, segment_lock);
|
||||
bool can_update_segment_state = is_downloader || is_last_holder;
|
||||
size_t current_downloaded_size = getDownloadedSize(segment_lock);
|
||||
size_t current_downloaded_size = getDownloadedSizeUnlocked(segment_lock);
|
||||
|
||||
SCOPE_EXIT({
|
||||
if (is_downloader)
|
||||
@ -494,13 +522,6 @@ void FileSegment::completeBasedOnCurrentState(std::lock_guard<std::mutex> & cach
|
||||
download_state = State::PARTIALLY_DOWNLOADED;
|
||||
|
||||
resetDownloaderImpl(segment_lock);
|
||||
|
||||
if (cache_writer)
|
||||
{
|
||||
cache_writer->finalize();
|
||||
cache_writer.reset();
|
||||
remote_file_reader.reset();
|
||||
}
|
||||
}
|
||||
|
||||
switch (download_state)
|
||||
@ -514,8 +535,8 @@ void FileSegment::completeBasedOnCurrentState(std::lock_guard<std::mutex> & cach
|
||||
}
|
||||
case State::DOWNLOADED:
|
||||
{
|
||||
assert(downloaded_size == range().size());
|
||||
assert(is_downloaded);
|
||||
assert(getDownloadedSizeUnlocked(segment_lock) == range().size());
|
||||
assert(isDownloadedUnlocked(segment_lock));
|
||||
break;
|
||||
}
|
||||
case State::DOWNLOADING:
|
||||
@ -577,7 +598,7 @@ String FileSegment::getInfoForLogImpl(std::lock_guard<std::mutex> & segment_lock
|
||||
info << "File segment: " << range().toString() << ", ";
|
||||
info << "key: " << key().toString() << ", ";
|
||||
info << "state: " << download_state << ", ";
|
||||
info << "downloaded size: " << getDownloadedSize(segment_lock) << ", ";
|
||||
info << "downloaded size: " << getDownloadedSizeUnlocked(segment_lock) << ", ";
|
||||
info << "reserved size: " << reserved_size << ", ";
|
||||
info << "downloader id: " << (downloader_id.empty() ? "None" : downloader_id) << ", ";
|
||||
info << "caller id: " << getCallerId() << ", ";
|
||||
@ -673,7 +694,7 @@ FileSegmentPtr FileSegment::getSnapshot(const FileSegmentPtr & file_segment, std
|
||||
|
||||
snapshot->hits_count = file_segment->getHitsCount();
|
||||
snapshot->ref_count = file_segment.use_count();
|
||||
snapshot->downloaded_size = file_segment->getDownloadedSize(segment_lock);
|
||||
snapshot->downloaded_size = file_segment->getDownloadedSizeUnlocked(segment_lock);
|
||||
snapshot->download_state = file_segment->download_state;
|
||||
snapshot->is_persistent = file_segment->isPersistent();
|
||||
|
||||
@ -818,37 +839,32 @@ void FileSegmentRangeWriter::completeFileSegment(FileSegment & file_segment)
|
||||
if (file_segment.isDetached())
|
||||
return;
|
||||
|
||||
if (file_segment.getDownloadedSize() > 0)
|
||||
size_t current_downloaded_size = file_segment.getDownloadedSize();
|
||||
|
||||
/// file_segment->complete(DOWNLOADED) is not enough, because file segment capacity
|
||||
/// was initially set with a margin as `max_file_segment_size`. => We need to always
|
||||
/// resize to actual size after download finished.
|
||||
if (current_downloaded_size != file_segment.range().size())
|
||||
{
|
||||
file_segment.getOrSetDownloader();
|
||||
/// Current file segment is downloaded as a part of write-through cache
|
||||
/// and therefore cannot be concurrently accessed. Nevertheless, it can be
|
||||
/// accessed by cache system tables if someone read from them,
|
||||
/// therefore we need a mutex.
|
||||
std::lock_guard segment_lock(file_segment.mutex);
|
||||
|
||||
{
|
||||
/// file_segment->complete(DOWNLOADED) is not enough, because file segment capacity
|
||||
/// was initially set with a margin as `max_file_segment_size`. => We need to always
|
||||
/// resize to actual size after download finished.
|
||||
|
||||
/// Current file segment is downloaded as a part of write-through cache
|
||||
/// and therefore cannot be concurrently accessed. Nevertheless, it can be
|
||||
/// accessed by cache system tables if someone read from them,
|
||||
/// therefore we need a mutex.
|
||||
std::lock_guard segment_lock(file_segment.mutex);
|
||||
|
||||
assert(file_segment.downloaded_size <= file_segment.range().size());
|
||||
file_segment.segment_range = FileSegment::Range(
|
||||
file_segment.segment_range.left,
|
||||
file_segment.segment_range.left + file_segment.downloaded_size - 1);
|
||||
file_segment.reserved_size = file_segment.downloaded_size;
|
||||
}
|
||||
|
||||
file_segment.completeWithState(FileSegment::State::DOWNLOADED);
|
||||
|
||||
on_complete_file_segment_func(file_segment);
|
||||
assert(current_downloaded_size <= file_segment.range().size());
|
||||
file_segment.segment_range = FileSegment::Range(
|
||||
file_segment.segment_range.left,
|
||||
file_segment.segment_range.left + current_downloaded_size - 1);
|
||||
file_segment.reserved_size = current_downloaded_size;
|
||||
}
|
||||
else
|
||||
|
||||
{
|
||||
std::lock_guard cache_lock(cache->mutex);
|
||||
file_segment.completeWithoutState(cache_lock);
|
||||
}
|
||||
|
||||
on_complete_file_segment_func(file_segment);
|
||||
}
|
||||
|
||||
bool FileSegmentRangeWriter::write(const char * data, size_t size, size_t offset, bool is_persistent)
|
||||
@ -877,22 +893,27 @@ bool FileSegmentRangeWriter::write(const char * data, size_t size, size_t offset
|
||||
offset, current_file_segment_write_offset);
|
||||
}
|
||||
|
||||
if ((*current_file_segment_it)->getRemainingSizeToDownload() == 0)
|
||||
auto current_file_segment = *current_file_segment_it;
|
||||
if (current_file_segment->getRemainingSizeToDownload() == 0)
|
||||
{
|
||||
completeFileSegment(**current_file_segment_it);
|
||||
completeFileSegment(*current_file_segment);
|
||||
current_file_segment_it = allocateFileSegment(current_file_segment_write_offset, is_persistent);
|
||||
}
|
||||
else if ((*current_file_segment_it)->getDownloadOffset() != offset)
|
||||
else if (current_file_segment->getDownloadOffset() != offset)
|
||||
{
|
||||
throw Exception(
|
||||
ErrorCodes::LOGICAL_ERROR,
|
||||
"Cannot file segment download offset {} does not match current write offset {}",
|
||||
(*current_file_segment_it)->getDownloadOffset(), offset);
|
||||
current_file_segment->getDownloadOffset(), offset);
|
||||
}
|
||||
}
|
||||
|
||||
auto & file_segment = *current_file_segment_it;
|
||||
file_segment->getOrSetDownloader();
|
||||
|
||||
auto downloader = file_segment->getOrSetDownloader();
|
||||
if (downloader != FileSegment::getCallerId())
|
||||
throw Exception(ErrorCodes::LOGICAL_ERROR, "Failed to set a downloader. ({})", file_segment->getInfoForLog());
|
||||
|
||||
SCOPE_EXIT({
|
||||
file_segment->resetDownloader();
|
||||
});
|
@ -5,7 +5,8 @@
|
||||
#include <IO/WriteBufferFromFile.h>
|
||||
#include <IO/ReadBufferFromFileBase.h>
|
||||
#include <list>
|
||||
#include <Common/FileCacheType.h>
|
||||
#include <Interpreters/Cache/FileCacheKey.h>
|
||||
|
||||
|
||||
namespace Poco { class Logger; }
|
||||
|
||||
@ -130,7 +131,7 @@ public:
|
||||
|
||||
bool isDownloader() const;
|
||||
|
||||
bool isDownloaded() const { return is_downloaded.load(); }
|
||||
bool isDownloaded() const;
|
||||
|
||||
static String getCallerId();
|
||||
|
||||
@ -171,7 +172,7 @@ public:
|
||||
private:
|
||||
size_t availableSize() const { return reserved_size - downloaded_size; }
|
||||
|
||||
size_t getDownloadedSize(std::lock_guard<std::mutex> & segment_lock) const;
|
||||
size_t getDownloadedSizeUnlocked(std::lock_guard<std::mutex> & segment_lock) const;
|
||||
String getInfoForLogImpl(std::lock_guard<std::mutex> & segment_lock) const;
|
||||
void assertCorrectnessImpl(std::lock_guard<std::mutex> & segment_lock) const;
|
||||
bool hasFinalizedState() const;
|
||||
@ -187,6 +188,8 @@ private:
|
||||
void setDownloadFailed(std::lock_guard<std::mutex> & segment_lock);
|
||||
bool isDownloaderImpl(std::lock_guard<std::mutex> & segment_lock) const;
|
||||
|
||||
bool isDownloadedUnlocked(std::lock_guard<std::mutex> & segment_lock) const;
|
||||
|
||||
void wrapWithCacheInfo(Exception & e, const String & message, std::lock_guard<std::mutex> & segment_lock) const;
|
||||
|
||||
bool lastFileSegmentHolder() const;
|
||||
@ -236,7 +239,8 @@ private:
|
||||
/// In general case, all file segments are owned by cache.
|
||||
bool is_detached = false;
|
||||
|
||||
std::atomic<bool> is_downloaded{false};
|
||||
bool is_downloaded{false};
|
||||
|
||||
std::atomic<size_t> hits_count = 0; /// cache hits.
|
||||
std::atomic<size_t> ref_count = 0; /// Used for getting snapshot state
|
||||
|
@ -4,7 +4,7 @@
|
||||
#include <mutex>
|
||||
#include <Core/Types.h>
|
||||
#include <Common/Exception.h>
|
||||
#include <Common/FileCacheType.h>
|
||||
#include <Interpreters/Cache/FileCacheKey.h>
|
||||
|
||||
namespace DB
|
||||
{
|
@ -1,4 +1,4 @@
|
||||
#include <Common/LRUFileCachePriority.h>
|
||||
#include <Interpreters/Cache/LRUFileCachePriority.h>
|
||||
#include <Common/CurrentMetrics.h>
|
||||
|
||||
namespace CurrentMetrics
|
@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <list>
|
||||
#include <Common/IFileCachePriority.h>
|
||||
#include <Interpreters/Cache/IFileCachePriority.h>
|
||||
#include <Common/logger_useful.h>
|
||||
|
||||
namespace DB
|
@ -363,6 +363,28 @@ private:
|
||||
/// A flag, used to mark if reader needs to apply deleted rows mask.
|
||||
bool apply_deleted_mask = true;
|
||||
|
||||
public:
|
||||
/// Some counters for current query execution.
|
||||
/// Most of them are workarounds and should be removed in the future.
|
||||
struct KitchenSink
|
||||
{
|
||||
std::atomic<size_t> analyze_counter = 0;
|
||||
|
||||
KitchenSink() = default;
|
||||
|
||||
KitchenSink(const KitchenSink & rhs)
|
||||
: analyze_counter(rhs.analyze_counter.load())
|
||||
{}
|
||||
|
||||
KitchenSink & operator=(const KitchenSink & rhs)
|
||||
{
|
||||
analyze_counter = rhs.analyze_counter.load();
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
KitchenSink kitchen_sink;
|
||||
|
||||
private:
|
||||
using SampleBlockCache = std::unordered_map<std::string, Block>;
|
||||
mutable SampleBlockCache sample_block_cache;
|
||||
|
@ -42,7 +42,7 @@ NamesAndTypesList FilesystemCacheLogElement::getNamesAndTypes()
|
||||
{"total_requested_range", std::make_shared<DataTypeTuple>(types)},
|
||||
{"size", std::make_shared<DataTypeUInt64>()},
|
||||
{"read_type", std::make_shared<DataTypeString>()},
|
||||
{"cache_attempted", std::make_shared<DataTypeUInt8>()},
|
||||
{"read_from_cache_attempted", std::make_shared<DataTypeUInt8>()},
|
||||
{"ProfileEvents", std::make_shared<DataTypeMap>(std::make_shared<DataTypeString>(), std::make_shared<DataTypeUInt64>())},
|
||||
{"read_buffer_id", std::make_shared<DataTypeString>()},
|
||||
};
|
||||
@ -62,7 +62,7 @@ void FilesystemCacheLogElement::appendToBlock(MutableColumns & columns) const
|
||||
columns[i++]->insert(Tuple{requested_range.first, requested_range.second});
|
||||
columns[i++]->insert(file_segment_size);
|
||||
columns[i++]->insert(typeToString(cache_type));
|
||||
columns[i++]->insert(cache_attempted);
|
||||
columns[i++]->insert(read_from_cache_attempted);
|
||||
|
||||
if (profile_counters)
|
||||
{
|
||||
|
@ -41,7 +41,7 @@ struct FilesystemCacheLogElement
|
||||
std::pair<size_t, size_t> requested_range{};
|
||||
CacheType cache_type{};
|
||||
size_t file_segment_size;
|
||||
bool cache_attempted;
|
||||
bool read_from_cache_attempted;
|
||||
String read_buffer_id;
|
||||
std::shared_ptr<ProfileEvents::Counters::Snapshot> profile_counters;
|
||||
|
||||
|
@ -5,8 +5,8 @@
|
||||
#include <DataTypes/DataTypesNumber.h>
|
||||
#include <DataTypes/DataTypeString.h>
|
||||
#include <Storages/ColumnsDescription.h>
|
||||
#include <Common/FileCacheFactory.h>
|
||||
#include <Common/FileCache.h>
|
||||
#include <Interpreters/Cache/FileCacheFactory.h>
|
||||
#include <Interpreters/Cache/FileCache.h>
|
||||
#include <Access/Common/AccessFlags.h>
|
||||
#include <Core/Block.h>
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user