Compare commits
1 Commits
next-6.2
...
mykaul-pat
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
953fee7fb0 |
225
.clang-format
225
.clang-format
@@ -1,225 +0,0 @@
|
||||
---
|
||||
Language: Cpp
|
||||
AccessModifierOffset: -4
|
||||
AlignAfterOpenBracket: Align
|
||||
AlignArrayOfStructures: None
|
||||
AlignConsecutiveAssignments:
|
||||
Enabled: false
|
||||
AcrossEmptyLines: false
|
||||
AcrossComments: false
|
||||
AlignCompound: false
|
||||
PadOperators: true
|
||||
AlignConsecutiveBitFields:
|
||||
Enabled: false
|
||||
AcrossEmptyLines: false
|
||||
AcrossComments: false
|
||||
AlignCompound: false
|
||||
PadOperators: false
|
||||
AlignConsecutiveDeclarations:
|
||||
Enabled: false
|
||||
AcrossEmptyLines: false
|
||||
AcrossComments: false
|
||||
AlignCompound: false
|
||||
PadOperators: false
|
||||
AlignConsecutiveMacros:
|
||||
Enabled: false
|
||||
AcrossEmptyLines: false
|
||||
AcrossComments: false
|
||||
AlignCompound: false
|
||||
PadOperators: false
|
||||
AlignConsecutiveShortCaseStatements:
|
||||
Enabled: false
|
||||
AcrossEmptyLines: false
|
||||
AcrossComments: false
|
||||
AlignCaseColons: false
|
||||
AlignEscapedNewlines: Right
|
||||
AlignOperands: Align
|
||||
AlignTrailingComments:
|
||||
Kind: Always
|
||||
OverEmptyLines: 0
|
||||
AllowAllArgumentsOnNextLine: true
|
||||
AllowAllParametersOfDeclarationOnNextLine: true
|
||||
AllowShortBlocksOnASingleLine: Never
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
AllowShortEnumsOnASingleLine: true
|
||||
AllowShortFunctionsOnASingleLine: InlineOnly
|
||||
AllowShortIfStatementsOnASingleLine: Never
|
||||
AllowShortLambdasOnASingleLine: All
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AlwaysBreakAfterDefinitionReturnType: None
|
||||
AlwaysBreakAfterReturnType: None
|
||||
AlwaysBreakBeforeMultilineStrings: false
|
||||
AlwaysBreakTemplateDeclarations: Yes
|
||||
AttributeMacros:
|
||||
- __capability
|
||||
BinPackArguments: false
|
||||
BinPackParameters: false
|
||||
BitFieldColonSpacing: Both
|
||||
BraceWrapping:
|
||||
AfterCaseLabel: false
|
||||
AfterClass: false
|
||||
AfterControlStatement: Never
|
||||
AfterEnum: false
|
||||
AfterExternBlock: false
|
||||
AfterFunction: false
|
||||
AfterNamespace: false
|
||||
AfterObjCDeclaration: false
|
||||
AfterStruct: false
|
||||
AfterUnion: false
|
||||
BeforeCatch: false
|
||||
BeforeElse: false
|
||||
BeforeLambdaBody: false
|
||||
BeforeWhile: false
|
||||
IndentBraces: false
|
||||
SplitEmptyFunction: true
|
||||
SplitEmptyRecord: true
|
||||
SplitEmptyNamespace: true
|
||||
BreakAfterAttributes: Never
|
||||
BreakAfterJavaFieldAnnotations: false
|
||||
BreakArrays: true
|
||||
BreakBeforeBinaryOperators: None
|
||||
BreakBeforeConceptDeclarations: Always
|
||||
BreakBeforeBraces: Attach
|
||||
BreakBeforeInlineASMColon: OnlyMultiline
|
||||
BreakBeforeTernaryOperators: true
|
||||
BreakConstructorInitializers: BeforeComma
|
||||
BreakInheritanceList: BeforeColon
|
||||
BreakStringLiterals: true
|
||||
ColumnLimit: 160
|
||||
CommentPragmas: '^ IWYU pragma:'
|
||||
CompactNamespaces: false
|
||||
ConstructorInitializerIndentWidth: 4
|
||||
ContinuationIndentWidth: 4
|
||||
Cpp11BracedListStyle: true
|
||||
DerivePointerAlignment: false
|
||||
DisableFormat: false
|
||||
EmptyLineAfterAccessModifier: Never
|
||||
EmptyLineBeforeAccessModifier: LogicalBlock
|
||||
ExperimentalAutoDetectBinPacking: false
|
||||
FixNamespaceComments: true
|
||||
ForEachMacros:
|
||||
- foreach
|
||||
- Q_FOREACH
|
||||
- BOOST_FOREACH
|
||||
IfMacros:
|
||||
- KJ_IF_MAYBE
|
||||
IncludeBlocks: Preserve
|
||||
IncludeCategories:
|
||||
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
|
||||
Priority: 2
|
||||
SortPriority: 0
|
||||
CaseSensitive: false
|
||||
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
|
||||
Priority: 3
|
||||
SortPriority: 0
|
||||
CaseSensitive: false
|
||||
- Regex: '.*'
|
||||
Priority: 1
|
||||
SortPriority: 0
|
||||
CaseSensitive: false
|
||||
IncludeIsMainRegex: '(Test)?$'
|
||||
IncludeIsMainSourceRegex: ''
|
||||
IndentAccessModifiers: false
|
||||
IndentCaseBlocks: false
|
||||
IndentCaseLabels: false
|
||||
IndentExternBlock: AfterExternBlock
|
||||
IndentGotoLabels: true
|
||||
IndentPPDirectives: None
|
||||
IndentRequiresClause: true
|
||||
IndentWidth: 4
|
||||
IndentWrappedFunctionNames: false
|
||||
InsertBraces: false
|
||||
InsertNewlineAtEOF: true
|
||||
InsertTrailingCommas: None
|
||||
IntegerLiteralSeparator:
|
||||
Binary: 0
|
||||
BinaryMinDigits: 0
|
||||
Decimal: 0
|
||||
DecimalMinDigits: 0
|
||||
Hex: 0
|
||||
HexMinDigits: 0
|
||||
JavaScriptQuotes: Leave
|
||||
JavaScriptWrapImports: true
|
||||
KeepEmptyLinesAtTheStartOfBlocks: true
|
||||
KeepEmptyLinesAtEOF: false
|
||||
LambdaBodyIndentation: Signature
|
||||
LineEnding: DeriveLF
|
||||
MacroBlockBegin: ''
|
||||
MacroBlockEnd: ''
|
||||
MaxEmptyLinesToKeep: 2
|
||||
NamespaceIndentation: None
|
||||
PackConstructorInitializers: NextLine
|
||||
PenaltyBreakAssignment: 2
|
||||
PenaltyBreakBeforeFirstCallParameter: 19
|
||||
PenaltyBreakComment: 300
|
||||
PenaltyBreakFirstLessLess: 120
|
||||
PenaltyBreakOpenParenthesis: 0
|
||||
PenaltyBreakString: 1000
|
||||
PenaltyBreakTemplateDeclaration: 10
|
||||
PenaltyExcessCharacter: 1000000
|
||||
PenaltyIndentedWhitespace: 0
|
||||
PenaltyReturnTypeOnItsOwnLine: 60
|
||||
PointerAlignment: Left
|
||||
PPIndentWidth: -1
|
||||
QualifierAlignment: Leave
|
||||
ReferenceAlignment: Pointer
|
||||
ReflowComments: true
|
||||
RemoveBracesLLVM: false
|
||||
RemoveParentheses: Leave
|
||||
RemoveSemicolon: false
|
||||
RequiresClausePosition: OwnLine
|
||||
RequiresExpressionIndentation: OuterScope
|
||||
SeparateDefinitionBlocks: Leave
|
||||
ShortNamespaceLines: 1
|
||||
SortIncludes: CaseSensitive
|
||||
SortJavaStaticImport: Before
|
||||
SortUsingDeclarations: LexicographicNumeric
|
||||
SpaceAfterCStyleCast: false
|
||||
SpaceAfterLogicalNot: false
|
||||
SpaceAfterTemplateKeyword: true
|
||||
SpaceAroundPointerQualifiers: Default
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeCaseColon: false
|
||||
SpaceBeforeCpp11BracedList: false
|
||||
SpaceBeforeCtorInitializerColon: true
|
||||
SpaceBeforeInheritanceColon: true
|
||||
SpaceBeforeJsonColon: false
|
||||
SpaceBeforeParens: ControlStatements
|
||||
SpaceBeforeParensOptions:
|
||||
AfterControlStatements: true
|
||||
AfterForeachMacros: true
|
||||
AfterFunctionDefinitionName: false
|
||||
AfterFunctionDeclarationName: false
|
||||
AfterIfMacros: true
|
||||
AfterOverloadedOperator: false
|
||||
AfterRequiresInClause: false
|
||||
AfterRequiresInExpression: false
|
||||
BeforeNonEmptyParentheses: false
|
||||
SpaceBeforeRangeBasedForLoopColon: true
|
||||
SpaceBeforeSquareBrackets: false
|
||||
SpaceInEmptyBlock: false
|
||||
SpacesBeforeTrailingComments: 1
|
||||
SpacesInAngles: Never
|
||||
SpacesInContainerLiterals: true
|
||||
SpacesInLineCommentPrefix:
|
||||
Minimum: 1
|
||||
Maximum: -1
|
||||
SpacesInParens: Never
|
||||
SpacesInParensOptions:
|
||||
InCStyleCasts: false
|
||||
InConditionalStatements: false
|
||||
InEmptyParentheses: false
|
||||
Other: false
|
||||
SpacesInSquareBrackets: false
|
||||
Standard: Latest
|
||||
TabWidth: 8
|
||||
UseTab: Never
|
||||
VerilogBreakBetweenInstancePorts: true
|
||||
WhitespaceSensitiveMacros:
|
||||
- BOOST_PP_STRINGIZE
|
||||
- CF_SWIFT_NAME
|
||||
- NS_SWIFT_NAME
|
||||
- PP_STRINGIZE
|
||||
- STRINGIZE
|
||||
...
|
||||
|
||||
1
.gitattributes
vendored
1
.gitattributes
vendored
@@ -1,4 +1,3 @@
|
||||
*.cc diff=cpp
|
||||
*.hh diff=cpp
|
||||
*.svg binary
|
||||
docs/_static/api/js/* binary
|
||||
|
||||
56
.github/CODEOWNERS
vendored
56
.github/CODEOWNERS
vendored
@@ -1,5 +1,5 @@
|
||||
# AUTH
|
||||
auth/* @nuivall @ptrsmrn @KrzaQ
|
||||
auth/* @elcallio @vladzcloudius
|
||||
|
||||
# CACHE
|
||||
row_cache* @tgrabiec
|
||||
@@ -7,9 +7,9 @@ row_cache* @tgrabiec
|
||||
test/boost/mvcc* @tgrabiec
|
||||
|
||||
# CDC
|
||||
cdc/* @kbr-scylla @elcallio @piodul
|
||||
test/cql/cdc_* @kbr-scylla @elcallio @piodul
|
||||
test/boost/cdc_* @kbr-scylla @elcallio @piodul
|
||||
cdc/* @kbr- @elcallio @piodul @jul-stas
|
||||
test/cql/cdc_* @kbr- @elcallio @piodul @jul-stas
|
||||
test/boost/cdc_* @kbr- @elcallio @piodul @jul-stas
|
||||
|
||||
# COMMITLOG / BATCHLOG
|
||||
db/commitlog/* @elcallio @eliransin
|
||||
@@ -19,24 +19,24 @@ db/batch* @elcallio
|
||||
service/storage_proxy* @gleb-cloudius
|
||||
|
||||
# COMPACTION
|
||||
compaction/* @raphaelsc
|
||||
compaction/* @raphaelsc @nyh
|
||||
|
||||
# CQL TRANSPORT LAYER
|
||||
transport/*
|
||||
|
||||
# CQL QUERY LANGUAGE
|
||||
cql3/* @tgrabiec @nuivall @ptrsmrn @KrzaQ
|
||||
cql3/* @tgrabiec @cvybhu @nyh
|
||||
|
||||
# COUNTERS
|
||||
counters* @nuivall @ptrsmrn @KrzaQ
|
||||
tests/counter_test* @nuivall @ptrsmrn @KrzaQ
|
||||
counters* @jul-stas
|
||||
tests/counter_test* @jul-stas
|
||||
|
||||
# DOCS
|
||||
docs/* @annastuchlik @tzach
|
||||
docs/alternator @annastuchlik @tzach @nyh @nuivall @ptrsmrn @KrzaQ
|
||||
docs/alternator @annastuchlik @tzach @nyh @havaker @nuivall
|
||||
|
||||
# GOSSIP
|
||||
gms/* @tgrabiec @asias @kbr-scylla
|
||||
gms/* @tgrabiec @asias
|
||||
|
||||
# DOCKER
|
||||
dist/docker/*
|
||||
@@ -45,44 +45,44 @@ dist/docker/*
|
||||
utils/logalloc* @tgrabiec
|
||||
|
||||
# MATERIALIZED VIEWS
|
||||
db/view/* @nyh @piodul
|
||||
cql3/statements/*view* @nyh @piodul
|
||||
test/boost/view_* @nyh @piodul
|
||||
db/view/* @nyh @cvybhu @piodul
|
||||
cql3/statements/*view* @nyh @cvybhu @piodul
|
||||
test/boost/view_* @nyh @cvybhu @piodul
|
||||
|
||||
# PACKAGING
|
||||
dist/* @syuu1228
|
||||
|
||||
# REPAIR
|
||||
repair/* @tgrabiec @asias
|
||||
repair/* @tgrabiec @asias @nyh
|
||||
|
||||
# SCHEMA MANAGEMENT
|
||||
db/schema_tables* @tgrabiec
|
||||
db/legacy_schema_migrator* @tgrabiec
|
||||
service/migration* @tgrabiec
|
||||
schema* @tgrabiec
|
||||
db/schema_tables* @tgrabiec @nyh
|
||||
db/legacy_schema_migrator* @tgrabiec @nyh
|
||||
service/migration* @tgrabiec @nyh
|
||||
schema* @tgrabiec @nyh
|
||||
|
||||
# SECONDARY INDEXES
|
||||
index/* @nyh @piodul
|
||||
cql3/statements/*index* @nyh @piodul
|
||||
test/boost/*index* @nyh @piodul
|
||||
index/* @nyh @cvybhu @piodul
|
||||
cql3/statements/*index* @nyh @cvybhu @piodul
|
||||
test/boost/*index* @nyh @cvybhu @piodul
|
||||
|
||||
# SSTABLES
|
||||
sstables/* @tgrabiec @raphaelsc
|
||||
sstables/* @tgrabiec @raphaelsc @nyh
|
||||
|
||||
# STREAMING
|
||||
streaming/* @tgrabiec @asias
|
||||
service/storage_service.* @tgrabiec @asias
|
||||
|
||||
# ALTERNATOR
|
||||
alternator/* @nyh @nuivall @ptrsmrn @KrzaQ
|
||||
test/alternator/* @nyh @nuivall @ptrsmrn @KrzaQ
|
||||
alternator/* @nyh @havaker @nuivall
|
||||
test/alternator/* @nyh @havaker @nuivall
|
||||
|
||||
# HINTED HANDOFF
|
||||
db/hints/* @piodul @vladzcloudius @eliransin
|
||||
|
||||
# REDIS
|
||||
redis/* @syuu1228
|
||||
test/redis/* @syuu1228
|
||||
redis/* @nyh @syuu1228
|
||||
test/redis/* @nyh @syuu1228
|
||||
|
||||
# READERS
|
||||
reader_* @denesb
|
||||
@@ -94,8 +94,8 @@ test/boost/querier_cache_test.cc @denesb
|
||||
test/cql-pytest/* @nyh
|
||||
|
||||
# RAFT
|
||||
raft/* @kbr-scylla @gleb-cloudius @kostja
|
||||
test/raft/* @kbr-scylla @gleb-cloudius @kostja
|
||||
raft/* @kbr- @gleb-cloudius @kostja
|
||||
test/raft/* @kbr- @gleb-cloudius @kostja
|
||||
|
||||
# HEAT-WEIGHTED LOAD BALANCING
|
||||
db/heat_load_balance.* @nyh @gleb-cloudius
|
||||
|
||||
20
.github/clang-include-cleaner.json
vendored
20
.github/clang-include-cleaner.json
vendored
@@ -1,20 +0,0 @@
|
||||
{
|
||||
"problemMatcher": [
|
||||
{
|
||||
"owner": "clang-include-cleaner",
|
||||
"severity": "error",
|
||||
"pattern": [
|
||||
{
|
||||
"regexp": "^([^\\-\\+].*)$",
|
||||
"file": 1
|
||||
},
|
||||
{
|
||||
"regexp": "^(-\\s+[^\\s]+)\\s+@Line:(\\d+)$",
|
||||
"line": 2,
|
||||
"message": 1,
|
||||
"loop": true
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
18
.github/clang-matcher.json
vendored
18
.github/clang-matcher.json
vendored
@@ -1,18 +0,0 @@
|
||||
{
|
||||
"problemMatcher": [
|
||||
{
|
||||
"owner": "clang",
|
||||
"pattern": [
|
||||
{
|
||||
"regexp": "^([^:]+):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*?)\\s+\\[(.*?)\\]$",
|
||||
"file": 1,
|
||||
"line": 2,
|
||||
"column": 3,
|
||||
"severity": 4,
|
||||
"message": 5,
|
||||
"code": 6
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
92
.github/mergify.yml
vendored
92
.github/mergify.yml
vendored
@@ -1,92 +0,0 @@
|
||||
pull_request_rules:
|
||||
- name: put PR in draft if conflicts
|
||||
conditions:
|
||||
- label = conflicts
|
||||
- author = mergify[bot]
|
||||
- head ~= ^mergify/
|
||||
actions:
|
||||
edit:
|
||||
draft: true
|
||||
- name: Delete mergify backport branch
|
||||
conditions:
|
||||
- base~=branch-
|
||||
- or:
|
||||
- merged
|
||||
- closed
|
||||
actions:
|
||||
delete_head_branch:
|
||||
- name: Automate backport pull request 6.1
|
||||
conditions:
|
||||
- or:
|
||||
- closed
|
||||
- merged
|
||||
- or:
|
||||
- base=master
|
||||
- base=next
|
||||
- label=backport/6.1 # The PR must have this label to trigger the backport
|
||||
- label=promoted-to-master
|
||||
actions:
|
||||
copy:
|
||||
title: "[Backport 6.1] {{ title }}"
|
||||
body: |
|
||||
{{ body }}
|
||||
|
||||
{% for c in commits %}
|
||||
(cherry picked from commit {{ c.sha }})
|
||||
{% endfor %}
|
||||
|
||||
Refs #{{number}}
|
||||
branches:
|
||||
- branch-6.1
|
||||
assignees:
|
||||
- "{{ author }}"
|
||||
- name: Automate backport pull request 5.4
|
||||
conditions:
|
||||
- or:
|
||||
- closed
|
||||
- merged
|
||||
- or:
|
||||
- base=master
|
||||
- base=next
|
||||
- label=backport/5.4 # The PR must have this label to trigger the backport
|
||||
- label=promoted-to-master
|
||||
actions:
|
||||
copy:
|
||||
title: "[Backport 5.4] {{ title }}"
|
||||
body: |
|
||||
{{ body }}
|
||||
|
||||
{% for c in commits %}
|
||||
(cherry picked from commit {{ c.sha }})
|
||||
{% endfor %}
|
||||
|
||||
Refs #{{number}}
|
||||
branches:
|
||||
- branch-5.4
|
||||
assignees:
|
||||
- "{{ author }}"
|
||||
- name: Automate backport pull request 6.0
|
||||
conditions:
|
||||
- or:
|
||||
- closed
|
||||
- merged
|
||||
- or:
|
||||
- base=master
|
||||
- base=next
|
||||
- label=backport/6.0 # The PR must have this label to trigger the backport
|
||||
- label=promoted-to-master
|
||||
actions:
|
||||
copy:
|
||||
title: "[Backport 6.0] {{ title }}"
|
||||
body: |
|
||||
{{ body }}
|
||||
|
||||
{% for c in commits %}
|
||||
(cherry picked from commit {{ c.sha }})
|
||||
{% endfor %}
|
||||
|
||||
Refs #{{number}}
|
||||
branches:
|
||||
- branch-6.0
|
||||
assignees:
|
||||
- "{{ author }}"
|
||||
1
.github/pull_request_template.md
vendored
1
.github/pull_request_template.md
vendored
@@ -1 +0,0 @@
|
||||
**Please replace this line with justification for the backport/\* labels added to this PR**
|
||||
186
.github/scripts/auto-backport.py
vendored
186
.github/scripts/auto-backport.py
vendored
@@ -1,186 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import tempfile
|
||||
import logging
|
||||
|
||||
from github import Github, GithubException
|
||||
from git import Repo, GitCommandError
|
||||
|
||||
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
||||
try:
|
||||
github_token = os.environ["GITHUB_TOKEN"]
|
||||
except KeyError:
|
||||
print("Please set the 'GITHUB_TOKEN' environment variable")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def is_pull_request():
|
||||
return '--pull-request' in sys.argv[1:]
|
||||
|
||||
|
||||
def parse_args():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('--repo', type=str, required=True, help='Github repository name')
|
||||
parser.add_argument('--base-branch', type=str, default='refs/heads/master', help='Base branch')
|
||||
parser.add_argument('--commits', default=None, type=str, help='Range of promoted commits.')
|
||||
parser.add_argument('--pull-request', type=int, help='Pull request number to be backported')
|
||||
parser.add_argument('--head-commit', type=str, required=is_pull_request(), help='The HEAD of target branch after the pull request specified by --pull-request is merged')
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def create_pull_request(repo, new_branch_name, base_branch_name, pr, backport_pr_title, commits, is_draft=False):
|
||||
pr_body = f'{pr.body}\n\n'
|
||||
for commit in commits:
|
||||
pr_body += f'- (cherry picked from commit {commit})\n\n'
|
||||
pr_body += f'Parent PR: #{pr.number}'
|
||||
try:
|
||||
backport_pr = repo.create_pull(
|
||||
title=backport_pr_title,
|
||||
body=pr_body,
|
||||
head=f'scylladbbot:{new_branch_name}',
|
||||
base=base_branch_name,
|
||||
draft=is_draft
|
||||
)
|
||||
logging.info(f"Pull request created: {backport_pr.html_url}")
|
||||
backport_pr.add_to_assignees(pr.user)
|
||||
if is_draft:
|
||||
backport_pr.add_to_labels("conflicts")
|
||||
pr_comment = f"@{pr.user} - This PR was marked as draft because it has conflicts\n"
|
||||
pr_comment += "Please resolve them and mark this PR as ready for review"
|
||||
backport_pr.create_issue_comment(pr_comment)
|
||||
logging.info(f"Assigned PR to original author: {pr.user}")
|
||||
return backport_pr
|
||||
except GithubException as e:
|
||||
if 'A pull request already exists' in str(e):
|
||||
logging.warning(f'A pull request already exists for {pr.user}:{new_branch_name}')
|
||||
else:
|
||||
logging.error(f'Failed to create PR: {e}')
|
||||
|
||||
|
||||
def get_pr_commits(repo, pr, stable_branch, start_commit=None):
|
||||
commits = []
|
||||
if pr.merged:
|
||||
merge_commit = repo.get_commit(pr.merge_commit_sha)
|
||||
if len(merge_commit.parents) > 1: # Check if this merge commit includes multiple commits
|
||||
commits.append(pr.merge_commit_sha)
|
||||
else:
|
||||
if start_commit:
|
||||
promoted_commits = repo.compare(start_commit, stable_branch).commits
|
||||
else:
|
||||
promoted_commits = repo.get_commits(sha=stable_branch)
|
||||
for commit in pr.get_commits():
|
||||
for promoted_commit in promoted_commits:
|
||||
commit_title = commit.commit.message.splitlines()[0]
|
||||
# In Scylla-pkg and scylla-dtest, for example,
|
||||
# we don't create a merge commit for a PR with multiple commits,
|
||||
# according to the GitHub API, the last commit will be the merge commit,
|
||||
# which is not what we need when backporting (we need all the commits).
|
||||
# So here, we are validating the correct SHA for each commit so we can cherry-pick
|
||||
if promoted_commit.commit.message.startswith(commit_title):
|
||||
commits.append(promoted_commit.sha)
|
||||
|
||||
elif pr.state == 'closed':
|
||||
events = pr.get_issue_events()
|
||||
for event in events:
|
||||
if event.event == 'closed':
|
||||
commits.append(event.commit_id)
|
||||
return commits
|
||||
|
||||
|
||||
def create_pr_comment_and_remove_label(pr, comment_body):
|
||||
labels = pr.get_labels()
|
||||
pattern = re.compile(r"backport/\d+\.\d+$")
|
||||
for label in labels:
|
||||
if pattern.match(label.name):
|
||||
print(f"Removing label: {label.name}")
|
||||
comment_body += f'- {label.name}\n'
|
||||
pr.remove_from_labels(label)
|
||||
pr.create_issue_comment(comment_body)
|
||||
|
||||
|
||||
def backport(repo, pr, version, commits, backport_base_branch):
|
||||
new_branch_name = f'backport/{pr.number}/to-{version}'
|
||||
backport_pr_title = f'[Backport {version}] {pr.title}'
|
||||
repo_url = f'https://scylladbbot:{github_token}@github.com/{repo.full_name}.git'
|
||||
fork_repo = f'https://scylladbbot:{github_token}@github.com/scylladbbot/{repo.name}.git'
|
||||
with (tempfile.TemporaryDirectory() as local_repo_path):
|
||||
try:
|
||||
repo_local = Repo.clone_from(repo_url, local_repo_path, branch=backport_base_branch)
|
||||
repo_local.git.checkout(b=new_branch_name)
|
||||
is_draft = False
|
||||
for commit in commits:
|
||||
try:
|
||||
repo_local.git.cherry_pick(commit, '-m1', '-x')
|
||||
except GitCommandError as e:
|
||||
logging.warning(f'Cherry-pick conflict on commit {commit}: {e}')
|
||||
is_draft = True
|
||||
repo_local.git.add(A=True)
|
||||
repo_local.git.cherry_pick('--continue')
|
||||
if not repo.private and not repo.has_in_collaborators(pr.user.login):
|
||||
repo.add_to_collaborators(pr.user.login, permission="push")
|
||||
comment = f':warning: @{pr.user.login} you have been added as collaborator to scylladbbot fork '
|
||||
comment += f'Please check your inbox and approve the invitation, once it is done, please add the backport labels again'
|
||||
create_pr_comment_and_remove_label(pr, comment)
|
||||
return
|
||||
repo_local.git.push(fork_repo, new_branch_name, force=True)
|
||||
create_pull_request(repo, new_branch_name, backport_base_branch, pr, backport_pr_title, commits,
|
||||
is_draft=is_draft)
|
||||
|
||||
except GitCommandError as e:
|
||||
logging.warning(f"GitCommandError: {e}")
|
||||
|
||||
|
||||
def main():
|
||||
args = parse_args()
|
||||
base_branch = args.base_branch.split('/')[2]
|
||||
promoted_label = 'promoted-to-master'
|
||||
repo_name = args.repo
|
||||
if 'scylla-enterprise' in args.repo:
|
||||
promoted_label = 'promoted-to-enterprise'
|
||||
stable_branch = base_branch
|
||||
backport_branch = 'branch-'
|
||||
|
||||
backport_label_pattern = re.compile(r'backport/\d+\.\d+$')
|
||||
|
||||
g = Github(github_token)
|
||||
repo = g.get_repo(repo_name)
|
||||
closed_prs = []
|
||||
start_commit = None
|
||||
|
||||
if args.commits:
|
||||
start_commit, end_commit = args.commits.split('..')
|
||||
commits = repo.compare(start_commit, end_commit).commits
|
||||
for commit in commits:
|
||||
match = re.search(rf"Closes .*#([0-9]+)", commit.commit.message, re.IGNORECASE)
|
||||
if match:
|
||||
pr_number = int(match.group(1))
|
||||
pr = repo.get_pull(pr_number)
|
||||
closed_prs.append(pr)
|
||||
if args.pull_request:
|
||||
start_commit = args.head_commit
|
||||
pr = repo.get_pull(args.pull_request)
|
||||
closed_prs = [pr]
|
||||
|
||||
for pr in closed_prs:
|
||||
labels = [label.name for label in pr.labels]
|
||||
backport_labels = [label for label in labels if backport_label_pattern.match(label)]
|
||||
if promoted_label not in labels:
|
||||
print(f'no {promoted_label} label: {pr.number}')
|
||||
continue
|
||||
if not backport_labels:
|
||||
print(f'no backport label: {pr.number}')
|
||||
continue
|
||||
commits = get_pr_commits(repo, pr, stable_branch, start_commit)
|
||||
logging.info(f"Found PR #{pr.number} with commit {commits} and the following labels: {backport_labels}")
|
||||
for backport_label in backport_labels:
|
||||
version = backport_label.replace('backport/', '')
|
||||
backport_base_branch = backport_label.replace('backport/', backport_branch)
|
||||
backport(repo, pr, version, commits, backport_base_branch)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
87
.github/scripts/label_promoted_commits.py
vendored
87
.github/scripts/label_promoted_commits.py
vendored
@@ -1,87 +0,0 @@
|
||||
import argparse
|
||||
import re
|
||||
import sys
|
||||
import os
|
||||
from github import Github
|
||||
from github.GithubException import UnknownObjectException
|
||||
|
||||
try:
|
||||
github_token = os.environ["GITHUB_TOKEN"]
|
||||
except KeyError:
|
||||
print("Please set the 'GITHUB_TOKEN' environment variable")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def parser():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('--repository', type=str, required=True,
|
||||
help='Github repository name (e.g., scylladb/scylladb)')
|
||||
parser.add_argument('--commits', type=str, required=True, help='Range of promoted commits.')
|
||||
parser.add_argument('--label', type=str, default='promoted-to-master', help='Label to use')
|
||||
parser.add_argument('--ref', type=str, required=True, help='PR target branch')
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def add_comment_and_close_pr(pr, comment):
|
||||
if pr.state == 'open':
|
||||
pr.create_issue_comment(comment)
|
||||
pr.edit(state="closed")
|
||||
|
||||
|
||||
def mark_backport_done(repo, ref_pr_number, branch):
|
||||
pr = repo.get_pull(int(ref_pr_number))
|
||||
label_to_remove = f'backport/{branch}'
|
||||
label_to_add = f'{label_to_remove}-done'
|
||||
current_labels = [label.name for label in pr.get_labels()]
|
||||
if label_to_remove in current_labels:
|
||||
pr.remove_from_labels(label_to_remove)
|
||||
if label_to_add not in current_labels:
|
||||
pr.add_to_labels(label_to_add)
|
||||
|
||||
|
||||
def main():
|
||||
# This script is triggered by a push event to either the master branch or a branch named branch-x.y (where x and y represent version numbers). Based on the pushed branch, the script performs the following actions:
|
||||
# - When ref branch is `master`, it will add the `promoted-to-master` label, which we need later for the auto backport process
|
||||
# - When ref branch is `branch-x.y` (which means we backported a patch), it will replace in the original PR the `backport/x.y` label with `backport/x.y-done` and will close the backport PR (Since GitHub close only the one referring to default branch)
|
||||
args = parser()
|
||||
pr_pattern = re.compile(r'Closes .*#([0-9]+)')
|
||||
target_branch = re.search(r'branch-(\d+\.\d+)', args.ref)
|
||||
g = Github(github_token)
|
||||
repo = g.get_repo(args.repository, lazy=False)
|
||||
start_commit, end_commit = args.commits.split('..')
|
||||
commits = repo.compare(start_commit, end_commit).commits
|
||||
processed_prs = set()
|
||||
# Print commit information
|
||||
for commit in commits:
|
||||
print(f'Commit sha is: {commit.sha}')
|
||||
match = pr_pattern.search(commit.commit.message)
|
||||
if match:
|
||||
pr_number = int(match.group(1))
|
||||
if pr_number in processed_prs:
|
||||
continue
|
||||
if target_branch:
|
||||
pr = repo.get_pull(pr_number)
|
||||
branch_name = target_branch[1]
|
||||
refs_pr = re.findall(r'Parent PR: (?:#|https.*?)(\d+)', pr.body)
|
||||
if refs_pr:
|
||||
print(f'branch-{target_branch.group(1)}, pr number is: {pr_number}')
|
||||
# 1. change the backport label of the parent PR to note that
|
||||
# we've merged the corresponding backport PR
|
||||
# 2. close the backport PR and leave a comment on it to note
|
||||
# that it has been merged with a certain git commit.
|
||||
ref_pr_number = refs_pr[0]
|
||||
mark_backport_done(repo, ref_pr_number, branch_name)
|
||||
comment = f'Closed via {commit.sha}'
|
||||
add_comment_and_close_pr(pr, comment)
|
||||
else:
|
||||
try:
|
||||
pr = repo.get_pull(pr_number)
|
||||
pr.add_to_labels('promoted-to-master')
|
||||
print(f'master branch, pr number is: {pr_number}')
|
||||
except UnknownObjectException:
|
||||
print(f'{pr_number} is not a PR but an issue, no need to add label')
|
||||
processed_prs.add(pr_number)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
95
.github/scripts/sync_labels.py
vendored
95
.github/scripts/sync_labels.py
vendored
@@ -1,95 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
import argparse
|
||||
import os
|
||||
import sys
|
||||
from github import Github
|
||||
import re
|
||||
|
||||
try:
|
||||
github_token = os.environ["GITHUB_TOKEN"]
|
||||
except KeyError:
|
||||
print("Please set the 'GITHUB_TOKEN' environment variable")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def parser():
|
||||
parse = argparse.ArgumentParser()
|
||||
parse.add_argument('--repo', type=str, required=True, help='Github repository name (e.g., scylladb/scylladb)')
|
||||
parse.add_argument('--number', type=int, required=True, help='Pull request or issue number to sync labels from')
|
||||
parse.add_argument('--label', type=str, default=None, help='Label to add/remove from an issue or PR')
|
||||
parse.add_argument('--is_issue', action='store_true', help='Determined if label change is in Issue or not')
|
||||
parse.add_argument('--action', type=str, choices=['opened', 'labeled', 'unlabeled'], required=True, help='Sync labels action')
|
||||
return parse.parse_args()
|
||||
|
||||
|
||||
def copy_labels_from_linked_issues(repo, pr_number):
|
||||
pr = repo.get_pull(pr_number)
|
||||
if pr.body:
|
||||
linked_issue_numbers = set(re.findall(r'Fixes:? (?:#|https.*?/issues/)(\d+)', pr.body))
|
||||
for issue_number in linked_issue_numbers:
|
||||
try:
|
||||
issue = repo.get_issue(int(issue_number))
|
||||
for label in issue.labels:
|
||||
pr.add_to_labels(label.name)
|
||||
print(f"Labels from issue #{issue_number} copied to PR #{pr_number}")
|
||||
except Exception as e:
|
||||
print(f"Error processing issue #{issue_number}: {e}")
|
||||
|
||||
|
||||
def get_linked_pr_from_issue_number(repo, number):
|
||||
linked_prs = []
|
||||
for pr in repo.get_pulls(state='all', base='master'):
|
||||
if pr.body and f'{number}' in pr.body:
|
||||
linked_prs.append(pr.number)
|
||||
break
|
||||
else:
|
||||
continue
|
||||
return linked_prs
|
||||
|
||||
|
||||
def get_linked_issues_based_on_pr_body(repo, number):
|
||||
pr = repo.get_pull(number)
|
||||
repo_name = repo.full_name
|
||||
pattern = rf"(?:fix(?:|es|ed)|resolve(?:|d|s))\s*:?\s*(?:(?:(?:{repo_name})?#)|https://github\.com/{repo_name}/issues/)(\d+)"
|
||||
issue_number_from_pr_body = []
|
||||
if pr.body is None:
|
||||
return issue_number_from_pr_body
|
||||
matches = re.findall(pattern, pr.body, re.IGNORECASE)
|
||||
if matches:
|
||||
for match in matches:
|
||||
issue_number_from_pr_body.append(match)
|
||||
print(f"Found issue number: {match}")
|
||||
return issue_number_from_pr_body
|
||||
|
||||
|
||||
def sync_labels(repo, number, label, action, is_issue=False):
|
||||
if is_issue:
|
||||
linked_prs_or_issues = get_linked_pr_from_issue_number(repo, number)
|
||||
else:
|
||||
linked_prs_or_issues = get_linked_issues_based_on_pr_body(repo, number)
|
||||
for pr_or_issue_number in linked_prs_or_issues:
|
||||
if is_issue:
|
||||
target = repo.get_issue(pr_or_issue_number)
|
||||
else:
|
||||
target = repo.get_issue(int(pr_or_issue_number))
|
||||
if action == 'labeled':
|
||||
target.add_to_labels(label)
|
||||
print(f"Label '{label}' successfully added.")
|
||||
elif action == 'unlabeled':
|
||||
target.remove_from_labels(label)
|
||||
print(f"Label '{label}' successfully removed.")
|
||||
elif action == 'opened':
|
||||
copy_labels_from_linked_issues(repo, number)
|
||||
else:
|
||||
print("Invalid action. Use 'labeled', 'unlabeled' or 'opened'.")
|
||||
|
||||
|
||||
def main():
|
||||
args = parser()
|
||||
github = Github(github_token)
|
||||
repo = github.get_repo(args.repo)
|
||||
sync_labels(repo, args.number, args.label, args.action, args.is_issue)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
71
.github/workflows/add-label-when-promoted.yaml
vendored
71
.github/workflows/add-label-when-promoted.yaml
vendored
@@ -1,71 +0,0 @@
|
||||
name: Check if commits are promoted
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- branch-*.*
|
||||
- enterprise
|
||||
pull_request_target:
|
||||
types: [labeled]
|
||||
branches: [master, next, enterprise]
|
||||
|
||||
jobs:
|
||||
check-commit:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
pull-requests: write
|
||||
issues: write
|
||||
steps:
|
||||
- name: Dump GitHub context
|
||||
env:
|
||||
GITHUB_CONTEXT: ${{ toJson(github) }}
|
||||
run: echo "$GITHUB_CONTEXT"
|
||||
- name: Set Default Branch
|
||||
id: set_branch
|
||||
run: |
|
||||
if [[ "${{ github.repository }}" == *enterprise* ]]; then
|
||||
echo "DEFAULT_BRANCH=enterprise" >> $GITHUB_ENV
|
||||
else
|
||||
echo "DEFAULT_BRANCH=master" >> $GITHUB_ENV
|
||||
fi
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: ${{ github.repository }}
|
||||
ref: ${{ env.DEFAULT_BRANCH }}
|
||||
token: ${{ secrets.AUTO_BACKPORT_TOKEN }}
|
||||
fetch-depth: 0 # Fetch all history for all tags and branches
|
||||
- name: Set up Git identity
|
||||
run: |
|
||||
git config --global user.name "GitHub Action"
|
||||
git config --global user.email "action@github.com"
|
||||
git config --global merge.conflictstyle diff3
|
||||
- name: Install dependencies
|
||||
run: sudo apt-get install -y python3-github python3-git
|
||||
- name: Run python script
|
||||
if: github.event_name == 'push'
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.AUTO_BACKPORT_TOKEN }}
|
||||
run: python .github/scripts/label_promoted_commits.py --commits ${{ github.event.before }}..${{ github.sha }} --repository ${{ github.repository }} --ref ${{ github.ref }}
|
||||
- name: Run auto-backport.py when promotion completed
|
||||
if: ${{ github.event_name == 'push' && github.ref == format('refs/heads/{0}', env.DEFAULT_BRANCH) }}
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.AUTO_BACKPORT_TOKEN }}
|
||||
run: python .github/scripts/auto-backport.py --repo ${{ github.repository }} --base-branch ${{ github.ref }} --commits ${{ github.event.before }}..${{ github.sha }}
|
||||
- name: Check if label starts with 'backport/' and contains digits
|
||||
id: check_label
|
||||
run: |
|
||||
label_name="${{ github.event.label.name }}"
|
||||
if [[ "$label_name" =~ ^backport/[0-9]+\.[0-9]+$ ]]; then
|
||||
echo "Label matches backport/X.X pattern."
|
||||
echo "backport_label=true" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "Label does not match the required pattern."
|
||||
echo "backport_label=false" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
- name: Run auto-backport.py when label was added
|
||||
if: ${{ github.event_name == 'pull_request_target' && steps.check_label.outputs.backport_label == 'true' && github.event.pull_request.state == 'closed' }}
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.AUTO_BACKPORT_TOKEN }}
|
||||
run: python .github/scripts/auto-backport.py --repo ${{ github.repository }} --base-branch ${{ github.ref }} --pull-request ${{ github.event.pull_request.number }} --head-commit ${{ github.event.pull_request.base.sha }}
|
||||
@@ -1,33 +0,0 @@
|
||||
name: Fixes validation for backport PR
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, reopened, edited]
|
||||
branches: [branch-*]
|
||||
|
||||
jobs:
|
||||
check-fixes-prefix:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check PR body for "Fixes" prefix patterns
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const body = context.payload.pull_request.body;
|
||||
const repo = context.payload.repository.full_name;
|
||||
|
||||
// Regular expression pattern to check for "Fixes" prefix
|
||||
// Adjusted to dynamically insert the repository full name
|
||||
const pattern = `Fixes:? (?:#|${repo.replace('/', '\\/')}#|https://github\\.com/${repo.replace('/', '\\/')}/issues/)(\\d+)`;
|
||||
const regex = new RegExp(pattern);
|
||||
|
||||
if (!regex.test(body)) {
|
||||
const error = "PR body does not contain a valid 'Fixes' reference.";
|
||||
core.setFailed(error);
|
||||
await github.rest.issues.createComment({
|
||||
issue_number: context.issue.number,
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
body: `:warning: ${error}`
|
||||
});
|
||||
}
|
||||
39
.github/workflows/build-scylla.yaml
vendored
39
.github/workflows/build-scylla.yaml
vendored
@@ -1,39 +0,0 @@
|
||||
name: Build Scylla
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
build_mode:
|
||||
description: 'the build mode'
|
||||
type: string
|
||||
required: true
|
||||
outputs:
|
||||
md5sum:
|
||||
description: 'the md5sum for scylla executable'
|
||||
value: ${{ jobs.build.outputs.md5sum }}
|
||||
|
||||
jobs:
|
||||
read-toolchain:
|
||||
uses: ./.github/workflows/read-toolchain.yaml
|
||||
build:
|
||||
if: github.repository == 'scylladb/scylladb'
|
||||
needs:
|
||||
- read-toolchain
|
||||
runs-on: ubuntu-latest
|
||||
container: ${{ needs.read-toolchain.outputs.image }}
|
||||
outputs:
|
||||
md5sum: ${{ steps.checksum.outputs.md5sum }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Generate the building system
|
||||
run: |
|
||||
git config --global --add safe.directory $GITHUB_WORKSPACE
|
||||
./configure.py --mode ${{ inputs.build_mode }} --with scylla
|
||||
- run: |
|
||||
ninja build/${{ inputs.build_mode }}/scylla
|
||||
- id: checksum
|
||||
run: |
|
||||
checksum=$(md5sum build/${{ inputs.build_mode }}/scylla | cut -c -32)
|
||||
echo "md5sum=$checksum" >> $GITHUB_OUTPUT
|
||||
66
.github/workflows/clang-nightly.yaml
vendored
66
.github/workflows/clang-nightly.yaml
vendored
@@ -1,66 +0,0 @@
|
||||
name: clang-nightly
|
||||
|
||||
on:
|
||||
schedule:
|
||||
# only at 5AM Saturday
|
||||
- cron: '0 5 * * SAT'
|
||||
|
||||
env:
|
||||
# use the development branch explicitly
|
||||
CLANG_VERSION: 20
|
||||
BUILD_DIR: build
|
||||
|
||||
permissions: {}
|
||||
|
||||
# cancel the in-progress run upon a repush
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
clang-dev:
|
||||
name: Build with clang nightly
|
||||
if: github.repository == 'scylladb/scylladb'
|
||||
runs-on: ubuntu-latest
|
||||
container: fedora:40
|
||||
strategy:
|
||||
matrix:
|
||||
build_type:
|
||||
- Debug
|
||||
- RelWithDebInfo
|
||||
- Dev
|
||||
steps:
|
||||
- run: |
|
||||
sudo dnf -y install git
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
- name: Install build dependencies
|
||||
run: |
|
||||
# use the copr repo for llvm snapshot builds, see
|
||||
# https://copr.fedorainfracloud.org/coprs/g/fedora-llvm-team/llvm-snapshots/
|
||||
sudo dnf -y install 'dnf-command(copr)'
|
||||
sudo dnf copr enable -y @fedora-llvm-team/llvm-snapshots
|
||||
# do not install java dependencies, which is not only not used here
|
||||
sed -i.orig \
|
||||
-e '/tools\/.*\/install-dependencies.sh/d' \
|
||||
-e 's/(minio_download_jobs)/(true)/' \
|
||||
./install-dependencies.sh
|
||||
sudo ./install-dependencies.sh
|
||||
sudo dnf -y install lld
|
||||
- name: Generate the building system
|
||||
run: |
|
||||
cmake \
|
||||
-DCMAKE_BUILD_TYPE=${{ matrix.build_type }} \
|
||||
-DCMAKE_C_COMPILER=clang-$CLANG_VERSION \
|
||||
-DCMAKE_CXX_COMPILER=clang++-$CLANG_VERSION \
|
||||
-G Ninja \
|
||||
-B $BUILD_DIR \
|
||||
-S .
|
||||
# see https://github.com/actions/toolkit/blob/main/docs/problem-matchers.md
|
||||
- run: |
|
||||
echo "::add-matcher::.github/clang-matcher.json"
|
||||
- run: |
|
||||
cmake --build $BUILD_DIR --target scylla
|
||||
- run: |
|
||||
echo "::remove-matcher owner=clang::"
|
||||
64
.github/workflows/clang-tidy.yaml
vendored
64
.github/workflows/clang-tidy.yaml
vendored
@@ -1,64 +0,0 @@
|
||||
name: clang-tidy
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
paths-ignore:
|
||||
- '**/*.rst'
|
||||
- '**/*.md'
|
||||
- 'docs/**'
|
||||
- '.github/**'
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
BUILD_TYPE: RelWithDebInfo
|
||||
BUILD_DIR: build
|
||||
CLANG_TIDY_CHECKS: '-*,bugprone-use-after-move'
|
||||
|
||||
permissions: {}
|
||||
|
||||
# cancel the in-progress run upon a repush
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
read-toolchain:
|
||||
uses: ./.github/workflows/read-toolchain.yaml
|
||||
clang-tidy:
|
||||
name: Run clang-tidy
|
||||
needs:
|
||||
- read-toolchain
|
||||
runs-on: ubuntu-latest
|
||||
container: ${{ needs.read-toolchain.outputs.image }}
|
||||
steps:
|
||||
- env:
|
||||
IMAGE: ${{ needs.read-toolchain.image }}
|
||||
run: |
|
||||
echo ${{ needs.read-toolchain.image }}
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
- run: |
|
||||
sudo dnf -y install clang-tools-extra
|
||||
- name: Generate the building system
|
||||
run: |
|
||||
cmake \
|
||||
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
|
||||
-DCMAKE_C_COMPILER=clang \
|
||||
-DScylla_USE_LINKER=ld.lld \
|
||||
-DCMAKE_CXX_COMPILER=clang++ \
|
||||
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON \
|
||||
-DCMAKE_CXX_CLANG_TIDY="clang-tidy;--checks=$CLANG_TIDY_CHECKS" \
|
||||
-G Ninja \
|
||||
-B $BUILD_DIR \
|
||||
-S .
|
||||
# see https://github.com/actions/toolkit/blob/main/docs/problem-matchers.md
|
||||
- run: |
|
||||
echo "::add-matcher::.github/clang-matcher.json"
|
||||
- name: Build with clang-tidy enabled
|
||||
run: |
|
||||
cmake --build $BUILD_DIR --target scylla
|
||||
- run: |
|
||||
echo "::remove-matcher owner=clang::"
|
||||
17
.github/workflows/codespell.yaml
vendored
17
.github/workflows/codespell.yaml
vendored
@@ -1,17 +0,0 @@
|
||||
name: codespell
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
permissions: {}
|
||||
jobs:
|
||||
codespell:
|
||||
name: Check for spelling errors
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: codespell-project/actions-codespell@master
|
||||
with:
|
||||
only_warn: 1
|
||||
ignore_words_list: "ans,datas,fo,ser,ue,crate,nd,reenable,strat,stap,te,raison"
|
||||
skip: "./.git,./build,./tools,*.js,*.lock,./test,./licenses,./redis/lolwut.cc,*.svg"
|
||||
17
.github/workflows/docs-amplify-enhanced.yaml
vendored
Normal file
17
.github/workflows/docs-amplify-enhanced.yaml
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
name: "Docs / Amplify enhanced"
|
||||
|
||||
on: issue_comment
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.event.issue.pull_request }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Amplify enhanced
|
||||
env:
|
||||
TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
uses: scylladb/sphinx-scylladb-theme/.github/actions/amplify-enhanced@master
|
||||
9
.github/workflows/docs-pages.yaml
vendored
9
.github/workflows/docs-pages.yaml
vendored
@@ -4,14 +4,12 @@ name: "Docs / Publish"
|
||||
|
||||
env:
|
||||
FLAG: ${{ github.repository == 'scylladb/scylla-enterprise' && 'enterprise' || 'opensource' }}
|
||||
DEFAULT_BRANCH: ${{ github.repository == 'scylladb/scylla-enterprise' && 'enterprise' || 'master' }}
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- 'master'
|
||||
- 'enterprise'
|
||||
- 'branch-**'
|
||||
paths:
|
||||
- "docs/**"
|
||||
workflow_dispatch:
|
||||
@@ -21,15 +19,14 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
ref: ${{ env.DEFAULT_BRANCH }}
|
||||
persist-credentials: false
|
||||
fetch-depth: 0
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
uses: actions/setup-python@v3
|
||||
with:
|
||||
python-version: "3.10"
|
||||
python-version: 3.7
|
||||
- name: Set up env
|
||||
run: make -C docs FLAG="${{ env.FLAG }}" setupenv
|
||||
- name: Build docs
|
||||
|
||||
9
.github/workflows/docs-pr.yaml
vendored
9
.github/workflows/docs-pr.yaml
vendored
@@ -12,21 +12,20 @@ on:
|
||||
- enterprise
|
||||
paths:
|
||||
- "docs/**"
|
||||
- "db/config.hh"
|
||||
- "db/config.cc"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
persist-credentials: false
|
||||
fetch-depth: 0
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
uses: actions/setup-python@v3
|
||||
with:
|
||||
python-version: "3.10"
|
||||
python-version: 3.7
|
||||
- name: Set up env
|
||||
run: make -C docs FLAG="${{ env.FLAG }}" setupenv
|
||||
- name: Build docs
|
||||
|
||||
80
.github/workflows/iwyu.yaml
vendored
80
.github/workflows/iwyu.yaml
vendored
@@ -1,80 +0,0 @@
|
||||
name: iwyu
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
|
||||
env:
|
||||
BUILD_TYPE: RelWithDebInfo
|
||||
BUILD_DIR: build
|
||||
CLEANER_OUTPUT_PATH: build/clang-include-cleaner.log
|
||||
CLEANER_DIRS: test/unit exceptions alternator api auth cdc compaction
|
||||
|
||||
permissions: {}
|
||||
|
||||
# cancel the in-progress run upon a repush
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
read-toolchain:
|
||||
uses: ./.github/workflows/read-toolchain.yaml
|
||||
clang-include-cleaner:
|
||||
name: "Analyze #includes in source files"
|
||||
needs:
|
||||
- read-toolchain
|
||||
runs-on: ubuntu-latest
|
||||
container: ${{ needs.read-toolchain.outputs.image }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
- run: |
|
||||
sudo dnf -y install clang-tools-extra
|
||||
- name: Generate compilation database
|
||||
run: |
|
||||
cmake \
|
||||
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
|
||||
-DCMAKE_C_COMPILER=clang \
|
||||
-DCMAKE_CXX_COMPILER=clang++ \
|
||||
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON \
|
||||
-G Ninja \
|
||||
-B $BUILD_DIR \
|
||||
-S .
|
||||
- name: Build headers
|
||||
run: |
|
||||
swagger_targets=''
|
||||
for f in api/api-doc/*.json; do
|
||||
if test "${f#*.}" = json; then
|
||||
name=$(basename "$f" .json)
|
||||
if test $name != swagger20_header; then
|
||||
swagger_targets+=" scylla_swagger_gen_$name"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
cmake \
|
||||
--build build \
|
||||
--target seastar_http_request_parser \
|
||||
--target idl-sources \
|
||||
--target $swagger_targets
|
||||
- run: |
|
||||
echo "::add-matcher::.github/clang-include-cleaner.json"
|
||||
- name: clang-include-cleaner
|
||||
run: |
|
||||
for d in $CLEANER_DIRS; do
|
||||
find $d -name '*.cc' -o -name '*.hh' \
|
||||
-exec echo {} \; \
|
||||
-exec clang-include-cleaner \
|
||||
--ignore-headers=seastarx.hh \
|
||||
--print=changes \
|
||||
-p $BUILD_DIR \
|
||||
{} \; | tee --append $CLEANER_OUTPUT_PATH
|
||||
done
|
||||
- run: |
|
||||
echo "::remove-matcher owner=clang-include-cleaner::"
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: Logs (clang-include-cleaner)
|
||||
path: "./${{ env.CLEANER_OUTPUT_PATH }}"
|
||||
27
.github/workflows/make-pr-ready-for-review.yaml
vendored
27
.github/workflows/make-pr-ready-for-review.yaml
vendored
@@ -1,27 +0,0 @@
|
||||
name: Mark PR as Ready When Conflicts Label is Removed
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
types:
|
||||
- unlabeled
|
||||
|
||||
env:
|
||||
DEFAULT_BRANCH: 'master'
|
||||
|
||||
jobs:
|
||||
mark-ready:
|
||||
if: github.event.label.name == 'conflicts'
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: ${{ github.repository }}
|
||||
ref: ${{ env.DEFAULT_BRANCH }}
|
||||
token: ${{ secrets.AUTO_BACKPORT_TOKEN }}
|
||||
fetch-depth: 1
|
||||
- name: Mark pull request as ready for review
|
||||
run: gh pr ready "${{ github.event.pull_request.number }}"
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.AUTO_BACKPORT_TOKEN }}
|
||||
22
.github/workflows/pr-require-backport-label.yaml
vendored
22
.github/workflows/pr-require-backport-label.yaml
vendored
@@ -1,22 +0,0 @@
|
||||
name: PR require backport label
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, labeled, unlabeled, synchronize]
|
||||
branches:
|
||||
- master
|
||||
- next
|
||||
jobs:
|
||||
label:
|
||||
if: github.event.pull_request.draft == false
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
issues: write
|
||||
pull-requests: write
|
||||
steps:
|
||||
- uses: mheap/github-action-required-labels@v5
|
||||
with:
|
||||
mode: minimum
|
||||
count: 1
|
||||
labels: "backport/none\nbackport/\\d.\\d"
|
||||
use_regex: true
|
||||
add_comment: false
|
||||
23
.github/workflows/read-toolchain.yaml
vendored
23
.github/workflows/read-toolchain.yaml
vendored
@@ -1,23 +0,0 @@
|
||||
name: Read Toolchain
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
outputs:
|
||||
image:
|
||||
description: "the toolchain docker image"
|
||||
value: ${{ jobs.read-toolchain.outputs.image }}
|
||||
|
||||
jobs:
|
||||
read-toolchain:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
image: ${{ steps.read.outputs.image }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
sparse-checkout: tools/toolchain/image
|
||||
sparse-checkout-cone-mode: false
|
||||
- id: read
|
||||
run: |
|
||||
image=$(cat tools/toolchain/image)
|
||||
echo "image=$image" >> $GITHUB_OUTPUT
|
||||
35
.github/workflows/reproducible-build.yaml
vendored
35
.github/workflows/reproducible-build.yaml
vendored
@@ -1,35 +0,0 @@
|
||||
name: Check Reproducible Build
|
||||
|
||||
on:
|
||||
schedule:
|
||||
# 5AM every friday
|
||||
- cron: '0 5 * * FRI'
|
||||
|
||||
permissions: {}
|
||||
|
||||
env:
|
||||
BUILD_MODE: release
|
||||
jobs:
|
||||
build-a:
|
||||
uses: ./.github/workflows/build-scylla.yaml
|
||||
with:
|
||||
build_mode: release
|
||||
build-b:
|
||||
uses: ./.github/workflows/build-scylla.yaml
|
||||
with:
|
||||
build_mode: release
|
||||
compare-checksum:
|
||||
if: github.repository == 'scylladb/scylladb'
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- build-a
|
||||
- build-b
|
||||
steps:
|
||||
- env:
|
||||
CHECKSUM_A: ${{needs.build-a.outputs.md5sum}}
|
||||
CHECKSUM_B: ${{needs.build-b.outputs.md5sum}}
|
||||
run: |
|
||||
if [ $CHECKSUM_A != $CHECKSUM_B ]; then \
|
||||
echo "::error::mismatched checksums: $CHECKSUM_A != $CHECKSUM_B"; \
|
||||
exit 1; \
|
||||
fi
|
||||
50
.github/workflows/seastar.yaml
vendored
50
.github/workflows/seastar.yaml
vendored
@@ -1,50 +0,0 @@
|
||||
name: Build with the latest Seastar
|
||||
|
||||
on:
|
||||
schedule:
|
||||
# 5AM everyday
|
||||
- cron: '0 5 * * *'
|
||||
|
||||
permissions: {}
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
BUILD_DIR: build
|
||||
|
||||
jobs:
|
||||
build-with-the-latest-seastar:
|
||||
runs-on: ubuntu-latest
|
||||
# be consistent with tools/toolchain/image
|
||||
container: scylladb/scylla-toolchain:fedora-40-20240621
|
||||
strategy:
|
||||
matrix:
|
||||
build_type:
|
||||
- Debug
|
||||
- RelWithDebInfo
|
||||
- Dev
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
- run: |
|
||||
rm -rf seastar
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
repository: scylladb/seastar
|
||||
submodules: true
|
||||
path: seastar
|
||||
- name: Generate the building system
|
||||
run: |
|
||||
git config --global --add safe.directory $GITHUB_WORKSPACE
|
||||
cmake \
|
||||
-DCMAKE_BUILD_TYPE=${{ matrix.build_type }} \
|
||||
-DCMAKE_C_COMPILER=clang \
|
||||
-DCMAKE_CXX_COMPILER=clang++ \
|
||||
-G Ninja \
|
||||
-B $BUILD_DIR \
|
||||
-S .
|
||||
- run: |
|
||||
cmake --build $BUILD_DIR --target scylla
|
||||
49
.github/workflows/sync-labels.yaml
vendored
49
.github/workflows/sync-labels.yaml
vendored
@@ -1,49 +0,0 @@
|
||||
name: Sync labels
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
types: [opened, labeled, unlabeled]
|
||||
branches: [master, next]
|
||||
issues:
|
||||
types: [labeled, unlabeled]
|
||||
|
||||
jobs:
|
||||
label-sync:
|
||||
if: ${{ github.repository == 'scylladb/scylladb' }}
|
||||
name: Synchronize labels between PR and the issue(s) fixed by it
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
pull-requests: write
|
||||
issues: write
|
||||
steps:
|
||||
- name: Dump GitHub context
|
||||
env:
|
||||
GITHUB_CONTEXT: ${{ toJson(github) }}
|
||||
run: echo "$GITHUB_CONTEXT"
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
sparse-checkout: |
|
||||
.github/scripts/sync_labels.py
|
||||
sparse-checkout-cone-mode: false
|
||||
|
||||
- name: Install dependencies
|
||||
run: sudo apt-get install -y python3-github
|
||||
|
||||
- name: Pull request opened event
|
||||
if: ${{ github.event.action == 'opened' }}
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: python .github/scripts/sync_labels.py --repo ${{ github.repository }} --number ${{ github.event.number }} --action ${{ github.event.action }}
|
||||
|
||||
- name: Pull request labeled or unlabeled event
|
||||
if: github.event_name == 'pull_request_target' && startsWith(github.event.label.name, 'backport/')
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: python .github/scripts/sync_labels.py --repo ${{ github.repository }} --number ${{ github.event.number }} --action ${{ github.event.action }} --label ${{ github.event.label.name }}
|
||||
|
||||
- name: Issue labeled or unlabeled event
|
||||
if: github.event_name == 'issues' && startsWith(github.event.label.name, 'backport/')
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: python .github/scripts/sync_labels.py --repo ${{ github.repository }} --number ${{ github.event.issue.number }} --action ${{ github.event.action }} --is_issue --label ${{ github.event.label.name }}
|
||||
6
.gitignore
vendored
6
.gitignore
vendored
@@ -3,8 +3,6 @@
|
||||
.settings
|
||||
build
|
||||
build.ninja
|
||||
cmake-build-*
|
||||
build.ninja.new
|
||||
cscope.*
|
||||
/debian/
|
||||
dist/ami/files/*.rpm
|
||||
@@ -14,14 +12,13 @@ dist/ami/scylla_deploy.sh
|
||||
Cql.tokens
|
||||
.kdev4
|
||||
*.kdev4
|
||||
.idea
|
||||
CMakeLists.txt.user
|
||||
.cache
|
||||
.tox
|
||||
*.egg-info
|
||||
__pycache__CMakeLists.txt.user
|
||||
.gdbinit
|
||||
/resources
|
||||
resources
|
||||
.pytest_cache
|
||||
/expressions.tokens
|
||||
tags
|
||||
@@ -33,4 +30,3 @@ compile_commands.json
|
||||
.ccls-cache/
|
||||
.mypy_cache
|
||||
.envrc
|
||||
clang_build
|
||||
|
||||
8
.gitmodules
vendored
8
.gitmodules
vendored
@@ -1,14 +1,14 @@
|
||||
[submodule "seastar"]
|
||||
path = seastar
|
||||
url = ../scylla-seastar
|
||||
url = ../seastar
|
||||
ignore = dirty
|
||||
[submodule "swagger-ui"]
|
||||
path = swagger-ui
|
||||
url = ../scylla-swagger-ui
|
||||
ignore = dirty
|
||||
[submodule "abseil"]
|
||||
path = abseil
|
||||
url = ../abseil-cpp
|
||||
[submodule "scylla-jmx"]
|
||||
path = tools/jmx
|
||||
url = ../scylla-jmx
|
||||
[submodule "scylla-tools"]
|
||||
path = tools/java
|
||||
url = ../scylla-tools-java
|
||||
|
||||
149
CMakeLists.txt
149
CMakeLists.txt
@@ -2,106 +2,56 @@ cmake_minimum_required(VERSION 3.27)
|
||||
|
||||
project(scylla)
|
||||
|
||||
include(CTest)
|
||||
|
||||
list(APPEND CMAKE_MODULE_PATH
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/cmake
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/seastar/cmake)
|
||||
|
||||
# Set the possible values of build type for cmake-gui
|
||||
set(scylla_build_types
|
||||
"Debug" "RelWithDebInfo" "Dev" "Sanitize" "Coverage")
|
||||
if(DEFINED CMAKE_BUILD_TYPE)
|
||||
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS
|
||||
${scylla_build_types})
|
||||
if(NOT CMAKE_BUILD_TYPE)
|
||||
set(CMAKE_BUILD_TYPE "RelWithDebInfo" CACHE
|
||||
STRING "Choose the type of build." FORCE)
|
||||
message(WARNING "CMAKE_BUILD_TYPE not specified, Using 'RelWithDebInfo'")
|
||||
elseif(NOT CMAKE_BUILD_TYPE IN_LIST scylla_build_types)
|
||||
message(FATAL_ERROR "Unknown CMAKE_BUILD_TYPE: ${CMAKE_BUILD_TYPE}. "
|
||||
"Following types are supported: ${scylla_build_types}")
|
||||
endif()
|
||||
endif(DEFINED CMAKE_BUILD_TYPE)
|
||||
|
||||
include(mode.common)
|
||||
if(CMAKE_CONFIGURATION_TYPES)
|
||||
foreach(config ${CMAKE_CONFIGURATION_TYPES})
|
||||
include(mode.${config})
|
||||
list(APPEND scylla_build_modes ${scylla_build_mode_${config}})
|
||||
endforeach()
|
||||
add_custom_target(mode_list
|
||||
COMMAND ${CMAKE_COMMAND} -E echo "$<JOIN:${scylla_build_modes}, >"
|
||||
COMMENT "List configured modes"
|
||||
BYPRODUCTS mode-list.phony.stamp
|
||||
COMMAND_EXPAND_LISTS)
|
||||
else()
|
||||
include(mode.${CMAKE_BUILD_TYPE})
|
||||
add_custom_target(mode_list
|
||||
${CMAKE_COMMAND} -E echo "${scylla_build_mode}"
|
||||
COMMENT "List configured modes")
|
||||
"Debug" "Release" "Dev" "Sanitize" "Coverage")
|
||||
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS
|
||||
${scylla_build_types})
|
||||
if(NOT CMAKE_BUILD_TYPE)
|
||||
set(CMAKE_BUILD_TYPE "Release" CACHE
|
||||
STRING "Choose the type of build." FORCE)
|
||||
message(WARNING "CMAKE_BUILD_TYPE not specified, Using 'Release'")
|
||||
elseif(NOT CMAKE_BUILD_TYPE IN_LIST scylla_build_types)
|
||||
message(FATAL_ERROR "Unknown CMAKE_BUILD_TYPE: ${CMAKE_BUILD_TYPE}. "
|
||||
"Following types are supported: ${scylla_build_types}")
|
||||
endif()
|
||||
|
||||
string(TOUPPER "${CMAKE_BUILD_TYPE}" build_mode)
|
||||
include(mode.${build_mode})
|
||||
include(mode.common)
|
||||
add_compile_definitions(
|
||||
${Seastar_DEFINITIONS_${build_mode}}
|
||||
FMT_DEPRECATED_OSTREAM)
|
||||
include(limit_jobs)
|
||||
# Configure Seastar compile options to align with Scylla
|
||||
set(CMAKE_CXX_STANDARD "23" CACHE INTERNAL "")
|
||||
set(CMAKE_CXX_STANDARD "20" CACHE INTERNAL "")
|
||||
set(CMAKE_CXX_EXTENSIONS ON CACHE INTERNAL "")
|
||||
set(CMAKE_CXX_SCAN_FOR_MODULES OFF CACHE INTERNAL "")
|
||||
set(CMAKE_CXX_VISIBILITY_PRESET hidden)
|
||||
|
||||
set(Seastar_TESTING ON CACHE BOOL "" FORCE)
|
||||
set(Seastar_API_LEVEL 7 CACHE STRING "" FORCE)
|
||||
set(Seastar_DEPRECATED_OSTREAM_FORMATTERS OFF CACHE BOOL "" FORCE)
|
||||
set(Seastar_APPS ON CACHE BOOL "" FORCE)
|
||||
set(Seastar_EXCLUDE_APPS_FROM_ALL ON CACHE BOOL "" FORCE)
|
||||
set(Seastar_EXCLUDE_TESTS_FROM_ALL ON CACHE BOOL "" FORCE)
|
||||
set(Seastar_IO_URING OFF CACHE BOOL "" FORCE)
|
||||
set(Seastar_SCHEDULING_GROUPS_COUNT 16 CACHE STRING "" FORCE)
|
||||
set(Seastar_UNUSED_RESULT_ERROR ON CACHE BOOL "" FORCE)
|
||||
add_subdirectory(seastar)
|
||||
set(ABSL_PROPAGATE_CXX_STD ON CACHE BOOL "" FORCE)
|
||||
|
||||
find_package(Sanitizers QUIET)
|
||||
set(sanitizer_cxx_flags
|
||||
$<$<CONFIG:Debug,Sanitize>:$<TARGET_PROPERTY:Sanitizers::address,INTERFACE_COMPILE_OPTIONS>;$<TARGET_PROPERTY:Sanitizers::undefined_behavior,INTERFACE_COMPILE_OPTIONS>>)
|
||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||
set(ABSL_GCC_FLAGS ${sanitizer_cxx_flags})
|
||||
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||
set(ABSL_LLVM_FLAGS ${sanitizer_cxx_flags})
|
||||
endif()
|
||||
set(ABSL_DEFAULT_LINKOPTS
|
||||
$<$<CONFIG:Debug,Sanitize>:$<TARGET_PROPERTY:Sanitizers::address,INTERFACE_LINK_LIBRARIES>;$<TARGET_PROPERTY:Sanitizers::undefined_behavior,INTERFACE_LINK_LIBRARIES>>)
|
||||
add_subdirectory(abseil)
|
||||
add_library(absl-headers INTERFACE)
|
||||
target_include_directories(absl-headers SYSTEM INTERFACE
|
||||
"${PROJECT_SOURCE_DIR}/abseil")
|
||||
add_library(absl::headers ALIAS absl-headers)
|
||||
|
||||
# Exclude absl::strerror from the default "all" target since it's not
|
||||
# used in Scylla build and, moreover, makes use of deprecated glibc APIs,
|
||||
# such as sys_nerr, which are not exposed from "stdio.h" since glibc 2.32,
|
||||
# which happens to be the case for recent Fedora distribution versions.
|
||||
#
|
||||
# Need to use the internal "absl_strerror" target name instead of namespaced
|
||||
# variant because `set_target_properties` does not understand the latter form,
|
||||
# unfortunately.
|
||||
set_target_properties(absl_strerror PROPERTIES EXCLUDE_FROM_ALL TRUE)
|
||||
|
||||
# System libraries dependencies
|
||||
find_package(Boost REQUIRED
|
||||
COMPONENTS filesystem program_options system thread regex unit_test_framework)
|
||||
target_link_libraries(Boost::regex
|
||||
INTERFACE
|
||||
ICU::i18n
|
||||
ICU::uc)
|
||||
find_package(Lua REQUIRED)
|
||||
find_package(ZLIB REQUIRED)
|
||||
find_package(ICU COMPONENTS uc i18n REQUIRED)
|
||||
find_package(fmt 10.0.0 REQUIRED)
|
||||
find_package(absl COMPONENTS hash raw_hash_set REQUIRED)
|
||||
find_package(libdeflate REQUIRED)
|
||||
find_package(libxcrypt REQUIRED)
|
||||
find_package(Snappy REQUIRED)
|
||||
find_package(RapidJSON REQUIRED)
|
||||
find_package(Thrift REQUIRED)
|
||||
find_package(xxHash REQUIRED)
|
||||
find_package(zstd REQUIRED)
|
||||
|
||||
set(scylla_gen_build_dir "${CMAKE_BINARY_DIR}/gen")
|
||||
file(MAKE_DIRECTORY "${scylla_gen_build_dir}")
|
||||
@@ -109,14 +59,6 @@ file(MAKE_DIRECTORY "${scylla_gen_build_dir}")
|
||||
include(add_version_library)
|
||||
generate_scylla_version()
|
||||
|
||||
add_library(scylla-zstd STATIC
|
||||
zstd.cc)
|
||||
target_link_libraries(scylla-zstd
|
||||
PRIVATE
|
||||
db
|
||||
Seastar::seastar
|
||||
zstd::libzstd)
|
||||
|
||||
add_library(scylla-main STATIC)
|
||||
target_sources(scylla-main
|
||||
PRIVATE
|
||||
@@ -138,7 +80,6 @@ target_sources(scylla-main
|
||||
keys.cc
|
||||
multishard_mutation_query.cc
|
||||
mutation_query.cc
|
||||
node_ops/task_manager_module.cc
|
||||
partition_slice_builder.cc
|
||||
querier.cc
|
||||
query.cc
|
||||
@@ -152,52 +93,21 @@ target_sources(scylla-main
|
||||
serializer.cc
|
||||
sstables_loader.cc
|
||||
table_helper.cc
|
||||
tasks/task_handler.cc
|
||||
tasks/task_manager.cc
|
||||
timeout_config.cc
|
||||
unimplemented.cc
|
||||
validation.cc
|
||||
vint-serialization.cc)
|
||||
vint-serialization.cc
|
||||
zstd.cc)
|
||||
target_link_libraries(scylla-main
|
||||
PRIVATE
|
||||
"$<LINK_LIBRARY:WHOLE_ARCHIVE,scylla-zstd>"
|
||||
db
|
||||
absl::headers
|
||||
absl::btree
|
||||
absl::hash
|
||||
absl::raw_hash_set
|
||||
Seastar::seastar
|
||||
Snappy::snappy
|
||||
systemd
|
||||
ZLIB::ZLIB)
|
||||
|
||||
option(Scylla_CHECK_HEADERS
|
||||
"Add check-headers target for checking the self-containness of headers")
|
||||
if(Scylla_CHECK_HEADERS)
|
||||
add_custom_target(check-headers)
|
||||
# compatibility target used by CI, which builds "check-headers" only for
|
||||
# the "Dev" mode.
|
||||
# our CI currently builds "dev-headers" using ninja without specify a build
|
||||
# mode. where "dev" is actually a prefix encoded in the target name for the
|
||||
# underlying "headers" target. while we don't have this convention in CMake
|
||||
# targets. in contrast, the "check-headers" which is built for all
|
||||
# configurations defined by "CMAKE_DEFAULT_CONFIGS". however, we only need
|
||||
# to build "check-headers" for the "Dev" configuration. Therefore, before
|
||||
# updating the CI to use build "check-headers:Dev", let's add a new target
|
||||
# that specifically builds "check-headers" only for Dev configuration. The
|
||||
# new target will do nothing for other configurations.
|
||||
add_custom_target(dev-headers
|
||||
COMMAND ${CMAKE_COMMAND}
|
||||
"$<IF:$<CONFIG:Dev>,--build;${CMAKE_BINARY_DIR};--config;$<CONFIG>;--target;check-headers,-E;echo;skipping;dev-headers;in;$<CONFIG>>"
|
||||
COMMAND_EXPAND_LISTS)
|
||||
endif()
|
||||
|
||||
include(check_headers)
|
||||
check_headers(check-headers scylla-main
|
||||
GLOB ${CMAKE_CURRENT_SOURCE_DIR}/*.hh)
|
||||
|
||||
add_custom_target(compiler-training)
|
||||
|
||||
add_subdirectory(api)
|
||||
add_subdirectory(alternator)
|
||||
add_subdirectory(db)
|
||||
@@ -210,6 +120,7 @@ add_subdirectory(dht)
|
||||
add_subdirectory(gms)
|
||||
add_subdirectory(idl)
|
||||
add_subdirectory(index)
|
||||
add_subdirectory(interface)
|
||||
add_subdirectory(lang)
|
||||
add_subdirectory(locator)
|
||||
add_subdirectory(message)
|
||||
@@ -227,6 +138,7 @@ add_subdirectory(service)
|
||||
add_subdirectory(sstables)
|
||||
add_subdirectory(streaming)
|
||||
add_subdirectory(test)
|
||||
add_subdirectory(thrift)
|
||||
add_subdirectory(tools)
|
||||
add_subdirectory(tracing)
|
||||
add_subdirectory(transport)
|
||||
@@ -267,24 +179,23 @@ target_link_libraries(scylla PRIVATE
|
||||
sstables
|
||||
streaming
|
||||
test-perf
|
||||
thrift
|
||||
tools
|
||||
tracing
|
||||
transport
|
||||
types
|
||||
utils)
|
||||
target_link_libraries(Boost::regex
|
||||
INTERFACE
|
||||
ICU::i18n
|
||||
ICU::uc)
|
||||
|
||||
target_link_libraries(scylla PRIVATE
|
||||
seastar
|
||||
absl::headers
|
||||
Boost::program_options)
|
||||
|
||||
target_include_directories(scylla PRIVATE
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
"${scylla_gen_build_dir}")
|
||||
|
||||
add_custom_target(maybe-scylla
|
||||
DEPENDS $<$<CONFIG:Dev>:$<TARGET_FILE:scylla>>)
|
||||
add_dependencies(compiler-training
|
||||
maybe-scylla)
|
||||
|
||||
add_subdirectory(dist)
|
||||
|
||||
21
HACKING.md
21
HACKING.md
@@ -19,18 +19,18 @@ $ git submodule update --init --recursive
|
||||
### Dependencies
|
||||
|
||||
Scylla is fairly fussy about its build environment, requiring a very recent
|
||||
version of the C++23 compiler and numerous tools and libraries to build.
|
||||
version of the C++20 compiler and numerous tools and libraries to build.
|
||||
|
||||
Run `./install-dependencies.sh` (as root) to use your Linux distributions's
|
||||
package manager to install the appropriate packages on your build machine.
|
||||
However, this will only work on very recent distributions. For example,
|
||||
currently Fedora users must upgrade to Fedora 32 otherwise the C++ compiler
|
||||
will be too old, and not support the new C++23 standard that Scylla uses.
|
||||
will be too old, and not support the new C++20 standard that Scylla uses.
|
||||
|
||||
Alternatively, to avoid having to upgrade your build machine or install
|
||||
various packages on it, we provide another option - the **frozen toolchain**.
|
||||
This is a script, `./tools/toolchain/dbuild`, that can execute build or run
|
||||
commands inside a container that contains exactly the right build tools and
|
||||
commands inside a Docker image that contains exactly the right build tools and
|
||||
libraries. The `dbuild` technique is useful for beginners, but is also the way
|
||||
in which ScyllaDB produces official releases, so it is highly recommended.
|
||||
|
||||
@@ -43,12 +43,6 @@ $ ./tools/toolchain/dbuild ninja build/release/scylla
|
||||
$ ./tools/toolchain/dbuild ./build/release/scylla --developer-mode 1
|
||||
```
|
||||
|
||||
Note: do not mix environemtns - either perform all your work with dbuild, or natively on the host.
|
||||
Note2: you can get to an interactive shell within dbuild by running it without any parameters:
|
||||
```bash
|
||||
$ ./tools/toolchain/dbuild
|
||||
```
|
||||
|
||||
### Build system
|
||||
|
||||
**Note**: Compiling Scylla requires, conservatively, 2 GB of memory per native
|
||||
@@ -122,13 +116,6 @@ Run all tests through the test execution wrapper with
|
||||
$ ./test.py --mode={debug,release}
|
||||
```
|
||||
|
||||
or, if you are using `dbuild`, you need to build the code and the tests and then you can run them at will:
|
||||
|
||||
```bash
|
||||
$ ./tools/toolchain/dbuild ninja {debug,release,dev}-build
|
||||
$ ./tools/toolchain/dbuild ./test.py --mode {debug,release,dev}
|
||||
```
|
||||
|
||||
The `--name` argument can be specified to run a particular test.
|
||||
|
||||
Alternatively, you can execute the test executable directly. For example,
|
||||
@@ -212,7 +199,7 @@ The `scylla.yaml` file in the repository by default writes all database data to
|
||||
|
||||
Scylla has a number of requirements for the file-system and operating system to operate ideally and at peak performance. However, during development, these requirements can be relaxed with the `--developer-mode` flag.
|
||||
|
||||
Additionally, when running on under-powered platforms like portable laptops, the `--overprovisioned` flag is useful.
|
||||
Additionally, when running on under-powered platforms like portable laptops, the `--overprovisined` flag is useful.
|
||||
|
||||
On a development machine, one might run Scylla as
|
||||
|
||||
|
||||
16
README.md
16
README.md
@@ -15,7 +15,7 @@ For more information, please see the [ScyllaDB web site].
|
||||
## Build Prerequisites
|
||||
|
||||
Scylla is fairly fussy about its build environment, requiring very recent
|
||||
versions of the C++23 compiler and of many libraries to build. The document
|
||||
versions of the C++20 compiler and of many libraries to build. The document
|
||||
[HACKING.md](HACKING.md) includes detailed information on building and
|
||||
developing Scylla, but to get Scylla building quickly on (almost) any build
|
||||
machine, Scylla offers a [frozen toolchain](tools/toolchain/README.md),
|
||||
@@ -65,13 +65,11 @@ $ ./tools/toolchain/dbuild ./build/release/scylla --help
|
||||
|
||||
## Testing
|
||||
|
||||
[](https://github.com/scylladb/scylladb/actions/workflows/seastar.yaml) [](https://github.com/scylladb/scylladb/actions/workflows/reproducible-build.yaml) [](https://github.com/scylladb/scylladb/actions/workflows/clang-nightly.yaml)
|
||||
|
||||
See [test.py manual](docs/dev/testing.md).
|
||||
|
||||
## Scylla APIs and compatibility
|
||||
By default, Scylla is compatible with Apache Cassandra and its API - CQL.
|
||||
There is also support for the API of Amazon DynamoDB™,
|
||||
By default, Scylla is compatible with Apache Cassandra and its APIs - CQL and
|
||||
Thrift. There is also support for the API of Amazon DynamoDB™,
|
||||
which needs to be enabled and configured in order to be used. For more
|
||||
information on how to enable the DynamoDB™ API in Scylla,
|
||||
and the current compatibility of this feature as well as Scylla-specific extensions, see
|
||||
@@ -84,11 +82,11 @@ Documentation can be found [here](docs/dev/README.md).
|
||||
Seastar documentation can be found [here](http://docs.seastar.io/master/index.html).
|
||||
User documentation can be found [here](https://docs.scylladb.com/).
|
||||
|
||||
## Training
|
||||
## Training
|
||||
|
||||
Training material and online courses can be found at [Scylla University](https://university.scylladb.com/).
|
||||
The courses are free, self-paced and include hands-on examples. They cover a variety of topics including Scylla data modeling,
|
||||
administration, architecture, basic NoSQL concepts, using drivers for application development, Scylla setup, failover, compactions,
|
||||
Training material and online courses can be found at [Scylla University](https://university.scylladb.com/).
|
||||
The courses are free, self-paced and include hands-on examples. They cover a variety of topics including Scylla data modeling,
|
||||
administration, architecture, basic NoSQL concepts, using drivers for application development, Scylla setup, failover, compactions,
|
||||
multi-datacenters and how Scylla integrates with third-party applications.
|
||||
|
||||
## Contributing to Scylla
|
||||
|
||||
@@ -28,7 +28,7 @@ The files created are:
|
||||
|
||||
By default, these files are created in the 'build'
|
||||
subdirectory under the directory containing the script.
|
||||
The destination directory can be overridden by
|
||||
The destination directory can be overriden by
|
||||
using '-o PATH' option.
|
||||
END
|
||||
)
|
||||
@@ -78,7 +78,7 @@ fi
|
||||
|
||||
# Default scylla product/version tags
|
||||
PRODUCT=scylla
|
||||
VERSION=6.2.4
|
||||
VERSION=5.5.0-dev
|
||||
|
||||
if test -f version
|
||||
then
|
||||
@@ -87,14 +87,12 @@ then
|
||||
else
|
||||
SCYLLA_VERSION=$VERSION
|
||||
if [ -z "$SCYLLA_RELEASE" ]; then
|
||||
DATE=$(date --utc +%Y%m%d)
|
||||
GIT_COMMIT=$(git -C "$SCRIPT_DIR" log --pretty=format:'%h' -n 1 --abbrev=12)
|
||||
# For custom package builds, replace "0" with "counter.yourname",
|
||||
# For custom package builds, replace "0" with "counter.your_name",
|
||||
# where counter starts at 1 and increments for successive versions.
|
||||
# This ensures that the package manager will select your custom
|
||||
# package over the standard release.
|
||||
# Do not use any special characters like - or _ in the name above!
|
||||
# These characters either have special meaning or are illegal in
|
||||
# version strings.
|
||||
SCYLLA_BUILD=0
|
||||
SCYLLA_RELEASE=$SCYLLA_BUILD.$DATE.$GIT_COMMIT
|
||||
elif [ -f "$OUTPUT_DIR/SCYLLA-RELEASE-FILE" ]; then
|
||||
@@ -104,7 +102,7 @@ else
|
||||
fi
|
||||
|
||||
if [ -f "$OUTPUT_DIR/SCYLLA-RELEASE-FILE" ]; then
|
||||
GIT_COMMIT_FILE=$(cat "$OUTPUT_DIR/SCYLLA-RELEASE-FILE" | rev | cut -d . -f 1 | rev)
|
||||
GIT_COMMIT_FILE=$(cat "$OUTPUT_DIR/SCYLLA-RELEASE-FILE" |cut -d . -f 3)
|
||||
if [ "$GIT_COMMIT" = "$GIT_COMMIT_FILE" ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
1
abseil
1
abseil
Submodule abseil deleted from d7aaad83b4
@@ -27,8 +27,4 @@ target_link_libraries(alternator
|
||||
cql3
|
||||
idl
|
||||
Seastar::seastar
|
||||
xxHash::xxhash
|
||||
absl::headers)
|
||||
|
||||
check_headers(check-headers alternator
|
||||
GLOB_RECURSE ${CMAKE_CURRENT_SOURCE_DIR}/*.hh)
|
||||
xxHash::xxhash)
|
||||
|
||||
@@ -7,37 +7,37 @@
|
||||
*/
|
||||
|
||||
#include "alternator/error.hh"
|
||||
#include "auth/common.hh"
|
||||
#include "log.hh"
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include "bytes.hh"
|
||||
#include "alternator/auth.hh"
|
||||
#include <fmt/format.h>
|
||||
#include "auth/common.hh"
|
||||
#include "auth/password_authenticator.hh"
|
||||
#include "auth/roles-metadata.hh"
|
||||
#include "service/storage_proxy.hh"
|
||||
#include "alternator/executor.hh"
|
||||
#include "cql3/selection/selection.hh"
|
||||
#include "query-result-set.hh"
|
||||
#include "cql3/result_set.hh"
|
||||
#include "types/types.hh"
|
||||
#include <seastar/core/coroutine.hh>
|
||||
|
||||
namespace alternator {
|
||||
|
||||
static logging::logger alogger("alternator-auth");
|
||||
|
||||
future<std::string> get_key_from_roles(service::storage_proxy& proxy, auth::service& as, std::string username) {
|
||||
schema_ptr schema = proxy.data_dictionary().find_schema(auth::get_auth_ks_name(as.query_processor()), "roles");
|
||||
future<std::string> get_key_from_roles(service::storage_proxy& proxy, std::string username) {
|
||||
schema_ptr schema = proxy.data_dictionary().find_schema("system_auth", "roles");
|
||||
partition_key pk = partition_key::from_single_value(*schema, utf8_type->decompose(username));
|
||||
dht::partition_range_vector partition_ranges{dht::partition_range(dht::decorate_key(*schema, pk))};
|
||||
std::vector<query::clustering_range> bounds{query::clustering_range::make_open_ended_both_sides()};
|
||||
const column_definition* salted_hash_col = schema->get_column_definition(bytes("salted_hash"));
|
||||
const column_definition* can_login_col = schema->get_column_definition(bytes("can_login"));
|
||||
if (!salted_hash_col || !can_login_col) {
|
||||
co_await coroutine::return_exception(api_error::unrecognized_client(fmt::format("Credentials cannot be fetched for: {}", username)));
|
||||
if (!salted_hash_col) {
|
||||
co_await coroutine::return_exception(api_error::unrecognized_client(format("Credentials cannot be fetched for: {}", username)));
|
||||
}
|
||||
auto selection = cql3::selection::selection::for_columns(schema, {salted_hash_col, can_login_col});
|
||||
auto partition_slice = query::partition_slice(std::move(bounds), {}, query::column_id_vector{salted_hash_col->id, can_login_col->id}, selection->get_query_options());
|
||||
auto selection = cql3::selection::selection::for_columns(schema, {salted_hash_col});
|
||||
auto partition_slice = query::partition_slice(std::move(bounds), {}, query::column_id_vector{salted_hash_col->id}, selection->get_query_options());
|
||||
auto command = ::make_lw_shared<query::read_command>(schema->id(), schema->version(), partition_slice,
|
||||
proxy.get_max_result_size(partition_slice), query::tombstone_limit(proxy.get_tombstone_limit()));
|
||||
auto cl = auth::password_authenticator::consistency_for_user(username);
|
||||
@@ -51,18 +51,11 @@ future<std::string> get_key_from_roles(service::storage_proxy& proxy, auth::serv
|
||||
|
||||
auto result_set = builder.build();
|
||||
if (result_set->empty()) {
|
||||
co_await coroutine::return_exception(api_error::unrecognized_client(fmt::format("User not found: {}", username)));
|
||||
co_await coroutine::return_exception(api_error::unrecognized_client(format("User not found: {}", username)));
|
||||
}
|
||||
const auto& result = result_set->rows().front();
|
||||
bool can_login = result[1] && value_cast<bool>(boolean_type->deserialize(*result[1]));
|
||||
if (!can_login) {
|
||||
// This is a valid role name, but has "login=False" so should not be
|
||||
// usable for authentication (see #19735).
|
||||
co_await coroutine::return_exception(api_error::unrecognized_client(fmt::format("Role {} has login=false so cannot be used for login", username)));
|
||||
}
|
||||
const managed_bytes_opt& salted_hash = result.front();
|
||||
const managed_bytes_opt& salted_hash = result_set->rows().front().front(); // We only asked for 1 row and 1 column
|
||||
if (!salted_hash) {
|
||||
co_await coroutine::return_exception(api_error::unrecognized_client(fmt::format("No password found for user: {}", username)));
|
||||
co_await coroutine::return_exception(api_error::unrecognized_client(format("No password found for user: {}", username)));
|
||||
}
|
||||
co_return value_cast<sstring>(utf8_type->deserialize(*salted_hash));
|
||||
}
|
||||
|
||||
@@ -9,8 +9,10 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <array>
|
||||
#include "gc_clock.hh"
|
||||
#include "utils/loading_cache.hh"
|
||||
#include "auth/service.hh"
|
||||
|
||||
namespace service {
|
||||
class storage_proxy;
|
||||
@@ -20,6 +22,6 @@ namespace alternator {
|
||||
|
||||
using key_cache = utils::loading_cache<std::string, std::string, 1>;
|
||||
|
||||
future<std::string> get_key_from_roles(service::storage_proxy& proxy, auth::service& as, std::string username);
|
||||
future<std::string> get_key_from_roles(service::storage_proxy& proxy, std::string username);
|
||||
|
||||
}
|
||||
|
||||
@@ -6,9 +6,12 @@
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <string_view>
|
||||
#include "alternator/conditions.hh"
|
||||
#include "alternator/error.hh"
|
||||
#include "cql3/constants.hh"
|
||||
#include <unordered_map>
|
||||
#include "utils/rjson.hh"
|
||||
#include "serialization.hh"
|
||||
@@ -42,12 +45,12 @@ comparison_operator_type get_comparison_operator(const rjson::value& comparison_
|
||||
{"NOT_CONTAINS", comparison_operator_type::NOT_CONTAINS},
|
||||
};
|
||||
if (!comparison_operator.IsString()) {
|
||||
throw api_error::validation(fmt::format("Invalid comparison operator definition {}", rjson::print(comparison_operator)));
|
||||
throw api_error::validation(format("Invalid comparison operator definition {}", rjson::print(comparison_operator)));
|
||||
}
|
||||
std::string op = comparison_operator.GetString();
|
||||
auto it = ops.find(op);
|
||||
if (it == ops.end()) {
|
||||
throw api_error::validation(fmt::format("Unsupported comparison operator {}", op));
|
||||
throw api_error::validation(format("Unsupported comparison operator {}", op));
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
@@ -339,7 +342,7 @@ static bool check_NOT_NULL(const rjson::value* val) {
|
||||
}
|
||||
|
||||
// Only types S, N or B (string, number or bytes) may be compared by the
|
||||
// various comparison operators - lt, le, gt, ge, and between.
|
||||
// various comparion operators - lt, le, gt, ge, and between.
|
||||
// Note that in particular, if the value is missing (v->IsNull()), this
|
||||
// check returns false.
|
||||
static bool check_comparable_type(const rjson::value& v) {
|
||||
@@ -429,7 +432,7 @@ static bool check_BETWEEN(const T& v, const T& lb, const T& ub, bool bounds_from
|
||||
if (cmp_lt()(ub, lb)) {
|
||||
if (bounds_from_query) {
|
||||
throw api_error::validation(
|
||||
fmt::format("BETWEEN operator requires lower_bound <= upper_bound, but {} > {}", lb, ub));
|
||||
format("BETWEEN operator requires lower_bound <= upper_bound, but {} > {}", lb, ub));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
@@ -613,7 +616,7 @@ conditional_operator_type get_conditional_operator(const rjson::value& req) {
|
||||
return conditional_operator_type::OR;
|
||||
} else {
|
||||
throw api_error::validation(
|
||||
fmt::format("'ConditionalOperator' parameter must be AND, OR or missing. Found {}.", s));
|
||||
format("'ConditionalOperator' parameter must be AND, OR or missing. Found {}.", s));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cql3/restrictions/statement_restrictions.hh"
|
||||
#include "serialization.hh"
|
||||
#include "expressions_types.hh"
|
||||
|
||||
namespace alternator {
|
||||
|
||||
@@ -32,10 +32,8 @@ controller::controller(
|
||||
sharded<service::memory_limiter>& memory_limiter,
|
||||
sharded<auth::service>& auth_service,
|
||||
sharded<qos::service_level_controller>& sl_controller,
|
||||
const db::config& config,
|
||||
seastar::scheduling_group sg)
|
||||
: protocol_server(sg)
|
||||
, _gossiper(gossiper)
|
||||
const db::config& config)
|
||||
: _gossiper(gossiper)
|
||||
, _proxy(proxy)
|
||||
, _mm(mm)
|
||||
, _sys_dist_ks(sys_dist_ks)
|
||||
@@ -64,9 +62,7 @@ std::vector<socket_address> controller::listen_addresses() const {
|
||||
}
|
||||
|
||||
future<> controller::start_server() {
|
||||
seastar::thread_attributes attr;
|
||||
attr.sched_group = _sched_group;
|
||||
return seastar::async(std::move(attr), [this] {
|
||||
return seastar::async([this] {
|
||||
_listen_addresses.clear();
|
||||
|
||||
auto preferred = _config.listen_interface_prefer_ipv6() ? std::make_optional(net::inet_address::family::INET6) : std::nullopt;
|
||||
@@ -77,11 +73,11 @@ future<> controller::start_server() {
|
||||
// shards - if necessary for LWT.
|
||||
smp_service_group_config c;
|
||||
c.max_nonlocal_requests = 5000;
|
||||
_ssg = create_smp_service_group(c).get();
|
||||
_ssg = create_smp_service_group(c).get0();
|
||||
|
||||
rmw_operation::set_default_write_isolation(_config.alternator_write_isolation());
|
||||
|
||||
net::inet_address addr = utils::resolve(_config.alternator_address, family).get();
|
||||
net::inet_address addr = utils::resolve(_config.alternator_address, family).get0();
|
||||
|
||||
auto get_cdc_metadata = [] (cdc::generation_service& svc) { return std::ref(svc.get_cdc_metadata()); };
|
||||
auto get_timeout_in_ms = [] (const db::config& cfg) -> utils::updateable_value<uint32_t> {
|
||||
@@ -160,9 +156,7 @@ future<> controller::stop_server() {
|
||||
}
|
||||
|
||||
future<> controller::request_stop_server() {
|
||||
return with_scheduling_group(_sched_group, [this] {
|
||||
return stop_server();
|
||||
});
|
||||
return stop_server();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -80,8 +80,7 @@ public:
|
||||
sharded<service::memory_limiter>& memory_limiter,
|
||||
sharded<auth::service>& auth_service,
|
||||
sharded<qos::service_level_controller>& sl_controller,
|
||||
const db::config& config,
|
||||
seastar::scheduling_group sg);
|
||||
const db::config& config);
|
||||
|
||||
virtual sstring name() const override;
|
||||
virtual sstring protocol() const override;
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
|
||||
#include <seastar/http/httpd.hh>
|
||||
#include "seastarx.hh"
|
||||
#include "utils/rjson.hh"
|
||||
|
||||
namespace alternator {
|
||||
|
||||
@@ -28,16 +27,10 @@ public:
|
||||
status_type _http_code;
|
||||
std::string _type;
|
||||
std::string _msg;
|
||||
// Additional data attached to the error, null value if not set. It's wrapped in copyable_value
|
||||
// class because copy constructor is required for exception classes otherwise it won't compile
|
||||
// (despite that its use may be optimized away).
|
||||
rjson::copyable_value _extra_fields;
|
||||
api_error(std::string type, std::string msg, status_type http_code = status_type::bad_request,
|
||||
rjson::value extra_fields = rjson::null_value())
|
||||
api_error(std::string type, std::string msg, status_type http_code = status_type::bad_request)
|
||||
: _http_code(std::move(http_code))
|
||||
, _type(std::move(type))
|
||||
, _msg(std::move(msg))
|
||||
, _extra_fields(std::move(extra_fields))
|
||||
{ }
|
||||
|
||||
// Factory functions for some common types of DynamoDB API errors
|
||||
@@ -65,13 +58,8 @@ public:
|
||||
static api_error access_denied(std::string msg) {
|
||||
return api_error("AccessDeniedException", std::move(msg));
|
||||
}
|
||||
static api_error conditional_check_failed(std::string msg, rjson::value&& item) {
|
||||
if (!item.IsNull()) {
|
||||
auto tmp = rjson::empty_object();
|
||||
rjson::add(tmp, "Item", std::move(item));
|
||||
item = std::move(tmp);
|
||||
}
|
||||
return api_error("ConditionalCheckFailedException", std::move(msg), status_type::bad_request, std::move(item));
|
||||
static api_error conditional_check_failed(std::string msg) {
|
||||
return api_error("ConditionalCheckFailedException", std::move(msg));
|
||||
}
|
||||
static api_error expired_iterator(std::string msg) {
|
||||
return api_error("ExpiredIteratorException", std::move(msg));
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -9,6 +9,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <seastar/core/future.hh>
|
||||
#include <seastar/http/httpd.hh>
|
||||
#include "seastarx.hh"
|
||||
#include <seastar/json/json_elements.hh>
|
||||
#include <seastar/core/sharded.hh>
|
||||
@@ -262,9 +263,4 @@ public:
|
||||
// add more than a couple of levels in its own output construction.
|
||||
bool is_big(const rjson::value& val, int big_size = 100'000);
|
||||
|
||||
// Check CQL's Role-Based Access Control (RBAC) permission (MODIFY,
|
||||
// SELECT, DROP, etc.) on the given table. When permission is denied an
|
||||
// appropriate user-readable api_error::access_denied is thrown.
|
||||
future<> verify_permission(const service::client_state&, const schema_ptr&, auth::permission);
|
||||
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
|
||||
namespace alternator {
|
||||
|
||||
template <typename Func, typename Result = std::invoke_result_t<Func, expressionsParser&>>
|
||||
template <typename Func, typename Result = std::result_of_t<Func(expressionsParser&)>>
|
||||
static Result do_with_parser(std::string_view input, Func&& f) {
|
||||
expressionsLexer::InputStreamType input_stream{
|
||||
reinterpret_cast<const ANTLR_UINT8*>(input.data()),
|
||||
@@ -43,7 +43,7 @@ static Result do_with_parser(std::string_view input, Func&& f) {
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename Func, typename Result = std::invoke_result_t<Func, expressionsParser&>>
|
||||
template <typename Func, typename Result = std::result_of_t<Func(expressionsParser&)>>
|
||||
static Result parse(const char* input_name, std::string_view input, Func&& f) {
|
||||
if (input.length() > 4096) {
|
||||
throw expressions_syntax_error(format("{} expression size {} exceeds allowed maximum 4096.",
|
||||
@@ -57,10 +57,10 @@ static Result parse(const char* input_name, std::string_view input, Func&& f) {
|
||||
// TODO: displayRecognitionError could set a position inside the
|
||||
// expressions_syntax_error in throws, and we could use it here to
|
||||
// mark the broken position in 'input'.
|
||||
throw expressions_syntax_error(fmt::format("Failed parsing {} '{}': {}",
|
||||
throw expressions_syntax_error(format("Failed parsing {} '{}': {}",
|
||||
input_name, input, e.what()));
|
||||
} catch (...) {
|
||||
throw expressions_syntax_error(fmt::format("Failed parsing {} '{}': {}",
|
||||
throw expressions_syntax_error(format("Failed parsing {} '{}': {}",
|
||||
input_name, input, std::current_exception()));
|
||||
}
|
||||
}
|
||||
@@ -133,6 +133,21 @@ void path::check_depth_limit() {
|
||||
}
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const path& p) {
|
||||
os << p.root();
|
||||
for (const auto& op : p.operators()) {
|
||||
std::visit(overloaded_functor {
|
||||
[&] (const std::string& member) {
|
||||
os << '.' << member;
|
||||
},
|
||||
[&] (unsigned index) {
|
||||
os << '[' << index << ']';
|
||||
}
|
||||
}, op);
|
||||
}
|
||||
return os;
|
||||
}
|
||||
|
||||
} // namespace parsed
|
||||
|
||||
// The following resolve_*() functions resolve references in parsed
|
||||
@@ -160,12 +175,12 @@ static std::optional<std::string> resolve_path_component(const std::string& colu
|
||||
if (column_name.size() > 0 && column_name.front() == '#') {
|
||||
if (!expression_attribute_names) {
|
||||
throw api_error::validation(
|
||||
fmt::format("ExpressionAttributeNames missing, entry '{}' required by expression", column_name));
|
||||
format("ExpressionAttributeNames missing, entry '{}' required by expression", column_name));
|
||||
}
|
||||
const rjson::value* value = rjson::find(*expression_attribute_names, column_name);
|
||||
if (!value || !value->IsString()) {
|
||||
throw api_error::validation(
|
||||
fmt::format("ExpressionAttributeNames missing entry '{}' required by expression", column_name));
|
||||
format("ExpressionAttributeNames missing entry '{}' required by expression", column_name));
|
||||
}
|
||||
used_attribute_names.emplace(column_name);
|
||||
return std::string(rjson::to_string_view(*value));
|
||||
@@ -202,16 +217,16 @@ static void resolve_constant(parsed::constant& c,
|
||||
[&] (const std::string& valref) {
|
||||
if (!expression_attribute_values) {
|
||||
throw api_error::validation(
|
||||
fmt::format("ExpressionAttributeValues missing, entry '{}' required by expression", valref));
|
||||
format("ExpressionAttributeValues missing, entry '{}' required by expression", valref));
|
||||
}
|
||||
const rjson::value* value = rjson::find(*expression_attribute_values, valref);
|
||||
if (!value) {
|
||||
throw api_error::validation(
|
||||
fmt::format("ExpressionAttributeValues missing entry '{}' required by expression", valref));
|
||||
format("ExpressionAttributeValues missing entry '{}' required by expression", valref));
|
||||
}
|
||||
if (value->IsNull()) {
|
||||
throw api_error::validation(
|
||||
fmt::format("ExpressionAttributeValues null value for entry '{}' required by expression", valref));
|
||||
format("ExpressionAttributeValues null value for entry '{}' required by expression", valref));
|
||||
}
|
||||
validate_value(*value, "ExpressionAttributeValues");
|
||||
used_attribute_values.emplace(valref);
|
||||
@@ -708,7 +723,7 @@ rjson::value calculate_value(const parsed::value& v,
|
||||
auto function_it = function_handlers.find(std::string_view(f._function_name));
|
||||
if (function_it == function_handlers.end()) {
|
||||
throw api_error::validation(
|
||||
fmt::format("{}: unknown function '{}' called.", caller, f._function_name));
|
||||
format("{}: unknown function '{}' called.", caller, f._function_name));
|
||||
}
|
||||
return function_it->second(caller, previous_item, f);
|
||||
},
|
||||
@@ -741,20 +756,3 @@ rjson::value calculate_value(const parsed::set_rhs& rhs,
|
||||
}
|
||||
|
||||
} // namespace alternator
|
||||
|
||||
auto fmt::formatter<alternator::parsed::path>::format(const alternator::parsed::path& p, fmt::format_context& ctx) const
|
||||
-> decltype(ctx.out()) {
|
||||
auto out = ctx.out();
|
||||
out = fmt::format_to(out, "{}", p.root());
|
||||
for (const auto& op : p.operators()) {
|
||||
std::visit(overloaded_functor {
|
||||
[&] (const std::string& member) {
|
||||
out = fmt::format_to(out, ".{}", member);
|
||||
},
|
||||
[&] (unsigned index) {
|
||||
out = fmt::format_to(out, "[{}]", index);
|
||||
}
|
||||
}, op);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
@@ -60,29 +60,23 @@ enum class calculate_value_caller {
|
||||
UpdateExpression, ConditionExpression, ConditionExpressionAlone
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
template <> struct fmt::formatter<alternator::calculate_value_caller> {
|
||||
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
|
||||
auto format(alternator::calculate_value_caller caller, fmt::format_context& ctx) const {
|
||||
std::string_view name = "unknown type of expression";
|
||||
switch (caller) {
|
||||
using enum alternator::calculate_value_caller;
|
||||
case UpdateExpression:
|
||||
name = "UpdateExpression";
|
||||
break;
|
||||
case ConditionExpression:
|
||||
name = "ConditionExpression";
|
||||
break;
|
||||
case ConditionExpressionAlone:
|
||||
name = "ConditionExpression";
|
||||
break;
|
||||
}
|
||||
return fmt::format_to(ctx.out(), "{}", name);
|
||||
inline std::ostream& operator<<(std::ostream& out, calculate_value_caller caller) {
|
||||
switch (caller) {
|
||||
case calculate_value_caller::UpdateExpression:
|
||||
out << "UpdateExpression";
|
||||
break;
|
||||
case calculate_value_caller::ConditionExpression:
|
||||
out << "ConditionExpression";
|
||||
break;
|
||||
case calculate_value_caller::ConditionExpressionAlone:
|
||||
out << "ConditionExpression";
|
||||
break;
|
||||
default:
|
||||
out << "unknown type of expression";
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
namespace alternator {
|
||||
return out;
|
||||
}
|
||||
|
||||
rjson::value calculate_value(const parsed::value& v,
|
||||
calculate_value_caller caller,
|
||||
|
||||
@@ -66,6 +66,7 @@ public:
|
||||
std::vector<std::variant<std::string, unsigned>>& operators() {
|
||||
return _operators;
|
||||
}
|
||||
friend std::ostream& operator<<(std::ostream&, const path&);
|
||||
};
|
||||
|
||||
// When an expression is first parsed, all constants are references, like
|
||||
@@ -254,7 +255,3 @@ public:
|
||||
|
||||
} // namespace parsed
|
||||
} // namespace alternator
|
||||
|
||||
template <> struct fmt::formatter<alternator::parsed::path> : fmt::formatter<string_view> {
|
||||
auto format(const alternator::parsed::path&, fmt::format_context& ctx) const -> decltype(ctx.out());
|
||||
};
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace alternator {
|
||||
// operations which may involve a read of the item before the write
|
||||
// (so-called Read-Modify-Write operations). These operations include PutItem,
|
||||
// UpdateItem and DeleteItem: All of these may be conditional operations (the
|
||||
// "Expected" parameter) which require a read before the write, and UpdateItem
|
||||
// "Expected" parameter) which requir a read before the write, and UpdateItem
|
||||
// may also have an update expression which refers to the item's old value.
|
||||
//
|
||||
// The code below supports running the read and the write together as one
|
||||
@@ -69,11 +69,7 @@ protected:
|
||||
enum class returnvalues {
|
||||
NONE, ALL_OLD, UPDATED_OLD, ALL_NEW, UPDATED_NEW
|
||||
} _returnvalues;
|
||||
enum class returnvalues_on_condition_check_failure {
|
||||
NONE, ALL_OLD
|
||||
} _returnvalues_on_condition_check_failure;
|
||||
static returnvalues parse_returnvalues(const rjson::value& request);
|
||||
static returnvalues_on_condition_check_failure parse_returnvalues_on_condition_check_failure(const rjson::value& request);
|
||||
// When _returnvalues != NONE, apply() should store here, in JSON form,
|
||||
// the values which are to be returned in the "Attributes" field.
|
||||
// The default null JSON means do not return an Attributes field at all.
|
||||
@@ -81,8 +77,6 @@ protected:
|
||||
// it (see explanation below), but note that because apply() may be
|
||||
// called more than once, if apply() will sometimes set this field it
|
||||
// must set it (even if just to the default empty value) every time.
|
||||
// Additionally when _returnvalues_on_condition_check_failure is ALL_OLD
|
||||
// then condition check failure will also result in storing values here.
|
||||
mutable rjson::value _return_attributes;
|
||||
public:
|
||||
// The constructor of a rmw_operation subclass should parse the request
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "log.hh"
|
||||
#include "serialization.hh"
|
||||
#include "error.hh"
|
||||
#include "rapidjson/writer.h"
|
||||
#include "concrete_types.hh"
|
||||
#include "cql3/type_json.hh"
|
||||
#include "mutation/position_in_partition.hh"
|
||||
@@ -58,7 +59,7 @@ type_representation represent_type(alternator_type atype) {
|
||||
// calculate its magnitude and precision from its scale() and unscaled_value().
|
||||
// So in the following ugly implementation we calculate them from the string
|
||||
// representation instead. We assume the number was already parsed
|
||||
// successfully to a big_decimal to it follows its syntax rules.
|
||||
// sucessfully to a big_decimal to it follows its syntax rules.
|
||||
//
|
||||
// FIXME: rewrite this function to take a big_decimal, not a string.
|
||||
// Maybe a snippet like this can help:
|
||||
@@ -143,17 +144,17 @@ static big_decimal parse_and_validate_number(std::string_view s) {
|
||||
big_decimal ret(s);
|
||||
auto [magnitude, precision] = internal::get_magnitude_and_precision(s);
|
||||
if (magnitude > 125) {
|
||||
throw api_error::validation(fmt::format("Number overflow: {}. Attempting to store a number with magnitude larger than supported range.", s));
|
||||
throw api_error::validation(format("Number overflow: {}. Attempting to store a number with magnitude larger than supported range.", s));
|
||||
}
|
||||
if (magnitude < -130) {
|
||||
throw api_error::validation(fmt::format("Number underflow: {}. Attempting to store a number with magnitude lower than supported range.", s));
|
||||
throw api_error::validation(format("Number underflow: {}. Attempting to store a number with magnitude lower than supported range.", s));
|
||||
}
|
||||
if (precision > 38) {
|
||||
throw api_error::validation(fmt::format("Number too precise: {}. Attempting to store a number with more significant digits than supported.", s));
|
||||
throw api_error::validation(format("Number too precise: {}. Attempting to store a number with more significant digits than supported.", s));
|
||||
}
|
||||
return ret;
|
||||
} catch (const marshal_exception& e) {
|
||||
throw api_error::validation(fmt::format("The parameter cannot be converted to a numeric value: {}", s));
|
||||
throw api_error::validation(format("The parameter cannot be converted to a numeric value: {}", s));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -265,7 +266,7 @@ bytes get_key_column_value(const rjson::value& item, const column_definition& co
|
||||
std::string column_name = column.name_as_text();
|
||||
const rjson::value* key_typed_value = rjson::find(item, column_name);
|
||||
if (!key_typed_value) {
|
||||
throw api_error::validation(fmt::format("Key column {} not found", column_name));
|
||||
throw api_error::validation(format("Key column {} not found", column_name));
|
||||
}
|
||||
return get_key_from_typed_value(*key_typed_value, column);
|
||||
}
|
||||
@@ -277,26 +278,19 @@ bytes get_key_column_value(const rjson::value& item, const column_definition& co
|
||||
// mentioned in the exception message).
|
||||
// If the type does match, a reference to the encoded value is returned.
|
||||
static const rjson::value& get_typed_value(const rjson::value& key_typed_value, std::string_view type_str, std::string_view name, std::string_view value_name) {
|
||||
if (!key_typed_value.IsObject() || key_typed_value.MemberCount() != 1) {
|
||||
if (!key_typed_value.IsObject() || key_typed_value.MemberCount() != 1 ||
|
||||
!key_typed_value.MemberBegin()->value.IsString()) {
|
||||
throw api_error::validation(
|
||||
fmt::format("Malformed value object for {} {}: {}",
|
||||
format("Malformed value object for {} {}: {}",
|
||||
value_name, name, key_typed_value));
|
||||
}
|
||||
|
||||
auto it = key_typed_value.MemberBegin();
|
||||
if (rjson::to_string_view(it->name) != type_str) {
|
||||
throw api_error::validation(
|
||||
fmt::format("Type mismatch: expected type {} for {} {}, got type {}",
|
||||
format("Type mismatch: expected type {} for {} {}, got type {}",
|
||||
type_str, value_name, name, it->name));
|
||||
}
|
||||
// We assume this function is called just for key types (S, B, N), and
|
||||
// all of those always have a string value in the JSON.
|
||||
if (!it->value.IsString()) {
|
||||
throw api_error::validation(
|
||||
fmt::format("Malformed value object for {} {}: {}",
|
||||
value_name, name, key_typed_value));
|
||||
|
||||
}
|
||||
return it->value;
|
||||
}
|
||||
|
||||
@@ -402,16 +396,16 @@ position_in_partition pos_from_json(const rjson::value& item, schema_ptr schema)
|
||||
|
||||
big_decimal unwrap_number(const rjson::value& v, std::string_view diagnostic) {
|
||||
if (!v.IsObject() || v.MemberCount() != 1) {
|
||||
throw api_error::validation(fmt::format("{}: invalid number object", diagnostic));
|
||||
throw api_error::validation(format("{}: invalid number object", diagnostic));
|
||||
}
|
||||
auto it = v.MemberBegin();
|
||||
if (it->name != "N") {
|
||||
throw api_error::validation(fmt::format("{}: expected number, found type '{}'", diagnostic, it->name));
|
||||
throw api_error::validation(format("{}: expected number, found type '{}'", diagnostic, it->name));
|
||||
}
|
||||
if (!it->value.IsString()) {
|
||||
// We shouldn't reach here. Callers normally validate their input
|
||||
// earlier with validate_value().
|
||||
throw api_error::validation(fmt::format("{}: improperly formatted number constant", diagnostic));
|
||||
throw api_error::validation(format("{}: improperly formatted number constant", diagnostic));
|
||||
}
|
||||
big_decimal ret = parse_and_validate_number(rjson::to_string_view(it->value));
|
||||
return ret;
|
||||
@@ -492,7 +486,7 @@ rjson::value set_sum(const rjson::value& v1, const rjson::value& v2) {
|
||||
auto [set1_type, set1] = unwrap_set(v1);
|
||||
auto [set2_type, set2] = unwrap_set(v2);
|
||||
if (set1_type != set2_type) {
|
||||
throw api_error::validation(fmt::format("Mismatched set types: {} and {}", set1_type, set2_type));
|
||||
throw api_error::validation(format("Mismatched set types: {} and {}", set1_type, set2_type));
|
||||
}
|
||||
if (!set1 || !set2) {
|
||||
throw api_error::validation("UpdateExpression: ADD operation for sets must be given sets as arguments");
|
||||
@@ -520,7 +514,7 @@ std::optional<rjson::value> set_diff(const rjson::value& v1, const rjson::value&
|
||||
auto [set1_type, set1] = unwrap_set(v1);
|
||||
auto [set2_type, set2] = unwrap_set(v2);
|
||||
if (set1_type != set2_type) {
|
||||
throw api_error::validation(fmt::format("Set DELETE type mismatch: {} and {}", set1_type, set2_type));
|
||||
throw api_error::validation(format("Set DELETE type mismatch: {} and {}", set1_type, set2_type));
|
||||
}
|
||||
if (!set1 || !set2) {
|
||||
throw api_error::validation("UpdateExpression: DELETE operation can only be performed on a set");
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
|
||||
#include "alternator/server.hh"
|
||||
#include "log.hh"
|
||||
#include <fmt/ranges.h>
|
||||
#include <seastar/http/function_handlers.hh>
|
||||
#include <seastar/http/short_streams.hh>
|
||||
#include <seastar/core/coroutine.hh>
|
||||
@@ -17,18 +16,14 @@
|
||||
#include <seastar/util/short_streams.hh>
|
||||
#include "seastarx.hh"
|
||||
#include "error.hh"
|
||||
#include "service/client_state.hh"
|
||||
#include "service/qos/service_level_controller.hh"
|
||||
#include "utils/assert.hh"
|
||||
#include "timeout_config.hh"
|
||||
#include "utils/rjson.hh"
|
||||
#include "auth.hh"
|
||||
#include <cctype>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
#include "service/storage_proxy.hh"
|
||||
#include "gms/gossiper.hh"
|
||||
#include "utils/overloaded_functor.hh"
|
||||
#include "utils/fb_utilities.hh"
|
||||
#include "utils/aws_sigv4.hh"
|
||||
|
||||
static logging::logger slogger("alternator-server");
|
||||
@@ -39,6 +34,8 @@ using reply = http::reply;
|
||||
|
||||
namespace alternator {
|
||||
|
||||
static constexpr auto TARGET = "X-Amz-Target";
|
||||
|
||||
inline std::vector<std::string_view> split(std::string_view text, char separator) {
|
||||
std::vector<std::string_view> tokens;
|
||||
if (text == "") {
|
||||
@@ -121,7 +118,7 @@ public:
|
||||
}
|
||||
return make_ready_future<std::unique_ptr<reply>>(std::move(rep));
|
||||
}
|
||||
auto res = resf.get();
|
||||
auto res = resf.get0();
|
||||
std::visit(overloaded_functor {
|
||||
[&] (const json::json_return_type& json_return_value) {
|
||||
slogger.trace("api_handler success case");
|
||||
@@ -159,9 +156,6 @@ public:
|
||||
protected:
|
||||
void generate_error_reply(reply& rep, const api_error& err) {
|
||||
rjson::value results = rjson::empty_object();
|
||||
if (!err._extra_fields.IsNull() && err._extra_fields.IsObject()) {
|
||||
results = rjson::copy(err._extra_fields);
|
||||
}
|
||||
rjson::add(results, "__type", rjson::from_string("com.amazonaws.dynamodb.v20120810#" + err._type));
|
||||
rjson::add(results, "message", err._msg);
|
||||
rep._content = rjson::print(std::move(results));
|
||||
@@ -214,13 +208,8 @@ protected:
|
||||
sstring local_dc = topology.get_datacenter();
|
||||
std::unordered_set<gms::inet_address> local_dc_nodes = topology.get_datacenter_endpoints().at(local_dc);
|
||||
for (auto& ip : local_dc_nodes) {
|
||||
// Note that it's not enough for the node to be is_alive() - a
|
||||
// node joining the cluster is also "alive" but not responsive to
|
||||
// requests. We alive *and* normal. See #19694, #21538.
|
||||
if (_gossiper.is_alive(ip) && _gossiper.is_normal(ip)) {
|
||||
// Use the gossiped broadcast_rpc_address if available instead
|
||||
// of the internal IP address "ip". See discussion in #18711.
|
||||
rjson::push_back(results, rjson::from_string(_gossiper.get_rpc_address(ip)));
|
||||
if (_gossiper.is_alive(ip)) {
|
||||
rjson::push_back(results, rjson::from_string(ip.to_sstring()));
|
||||
}
|
||||
}
|
||||
rep->set_status(reply::status_type::ok);
|
||||
@@ -263,7 +252,7 @@ future<std::string> server::verify_signature(const request& req, const chunked_c
|
||||
std::string_view authorization_header = authorization_it->second;
|
||||
auto pos = authorization_header.find_first_of(' ');
|
||||
if (pos == std::string_view::npos || authorization_header.substr(0, pos) != "AWS4-HMAC-SHA256") {
|
||||
throw api_error::invalid_signature(fmt::format("Authorization header must use AWS4-HMAC-SHA256 algorithm: {}", authorization_header));
|
||||
throw api_error::invalid_signature(format("Authorization header must use AWS4-HMAC-SHA256 algorithm: {}", authorization_header));
|
||||
}
|
||||
authorization_header.remove_prefix(pos+1);
|
||||
std::string credential;
|
||||
@@ -298,7 +287,7 @@ future<std::string> server::verify_signature(const request& req, const chunked_c
|
||||
|
||||
std::vector<std::string_view> credential_split = split(credential, '/');
|
||||
if (credential_split.size() != 5) {
|
||||
throw api_error::validation(fmt::format("Incorrect credential information format: {}", credential));
|
||||
throw api_error::validation(format("Incorrect credential information format: {}", credential));
|
||||
}
|
||||
std::string user(credential_split[0]);
|
||||
std::string datestamp(credential_split[1]);
|
||||
@@ -319,8 +308,8 @@ future<std::string> server::verify_signature(const request& req, const chunked_c
|
||||
}
|
||||
}
|
||||
|
||||
auto cache_getter = [&proxy = _proxy, &as = _auth_service] (std::string username) {
|
||||
return get_key_from_roles(proxy, as, std::move(username));
|
||||
auto cache_getter = [&proxy = _proxy] (std::string username) {
|
||||
return get_key_from_roles(proxy, std::move(username));
|
||||
};
|
||||
return _key_cache.get_ptr(user, cache_getter).then([this, &req, &content,
|
||||
user = std::move(user),
|
||||
@@ -383,7 +372,7 @@ static tracing::trace_state_ptr maybe_trace_query(service::client_state& client_
|
||||
std::string buf;
|
||||
tracing::add_session_param(trace_state, "alternator_op", op);
|
||||
tracing::add_query(trace_state, truncated_content_view(query, buf));
|
||||
tracing::begin(trace_state, seastar::format("Alternator {}", op), client_state.get_client_address());
|
||||
tracing::begin(trace_state, format("Alternator {}", op), client_state.get_client_address());
|
||||
if (!username.empty()) {
|
||||
tracing::set_username(trace_state, auth::authenticated_user(username));
|
||||
}
|
||||
@@ -393,10 +382,10 @@ static tracing::trace_state_ptr maybe_trace_query(service::client_state& client_
|
||||
|
||||
future<executor::request_return_type> server::handle_api_request(std::unique_ptr<request> req) {
|
||||
_executor._stats.total_operations++;
|
||||
sstring target = req->get_header("X-Amz-Target");
|
||||
// target is DynamoDB API version followed by a dot '.' and operation type (e.g. CreateTable)
|
||||
auto dot = target.find('.');
|
||||
std::string_view op = (dot == sstring::npos) ? std::string_view() : std::string_view(target).substr(dot+1);
|
||||
sstring target = req->get_header(TARGET);
|
||||
std::vector<std::string_view> split_target = split(target, '.');
|
||||
//NOTICE(sarna): Target consists of Dynamo API version followed by a dot '.' and operation type (e.g. CreateTable)
|
||||
std::string op = split_target.empty() ? std::string() : std::string(split_target.back());
|
||||
// JSON parsing can allocate up to roughly 2x the size of the raw
|
||||
// document, + a couple of bytes for maintenance.
|
||||
// TODO: consider the case where req->content_length is missing. Maybe
|
||||
@@ -408,7 +397,7 @@ future<executor::request_return_type> server::handle_api_request(std::unique_ptr
|
||||
++_executor._stats.requests_blocked_memory;
|
||||
}
|
||||
auto units = co_await std::move(units_fut);
|
||||
SCYLLA_ASSERT(req->content_stream);
|
||||
assert(req->content_stream);
|
||||
chunked_content content = co_await util::read_entire_stream(*req->content_stream);
|
||||
auto username = co_await verify_signature(*req, content);
|
||||
|
||||
@@ -419,7 +408,7 @@ future<executor::request_return_type> server::handle_api_request(std::unique_ptr
|
||||
auto callback_it = _callbacks.find(op);
|
||||
if (callback_it == _callbacks.end()) {
|
||||
_executor._stats.unsupported_operations++;
|
||||
co_return api_error::unknown_operation(fmt::format("Unsupported operation {}", op));
|
||||
co_return api_error::unknown_operation(format("Unsupported operation {}", op));
|
||||
}
|
||||
if (_pending_requests.get_count() >= _max_concurrent_requests) {
|
||||
_executor._stats.requests_shed++;
|
||||
@@ -427,11 +416,11 @@ future<executor::request_return_type> server::handle_api_request(std::unique_ptr
|
||||
}
|
||||
_pending_requests.enter();
|
||||
auto leave = defer([this] () noexcept { _pending_requests.leave(); });
|
||||
executor::client_state client_state(service::client_state::external_tag(),
|
||||
_auth_service, &_sl_controller, _timeout_config.current_values(), req->get_client_address());
|
||||
if (!username.empty()) {
|
||||
client_state.set_login(auth::authenticated_user(username));
|
||||
}
|
||||
//FIXME: Client state can provide more context, e.g. client's endpoint address
|
||||
// We use unique_ptr because client_state cannot be moved or copied
|
||||
executor::client_state client_state = username.empty()
|
||||
? service::client_state{service::client_state::internal_tag()}
|
||||
: service::client_state{service::client_state::internal_tag(), _auth_service, _sl_controller, username};
|
||||
co_await client_state.maybe_update_per_service_level_params();
|
||||
|
||||
tracing::trace_state_ptr trace_state = maybe_trace_query(client_state, username, op, content);
|
||||
@@ -478,7 +467,6 @@ server::server(executor& exec, service::storage_proxy& proxy, gms::gossiper& gos
|
||||
, _enforce_authorization(false)
|
||||
, _enabled_servers{}
|
||||
, _pending_requests{}
|
||||
, _timeout_config(_proxy.data_dictionary().get_config())
|
||||
, _callbacks{
|
||||
{"CreateTable", [] (executor& e, executor::client_state& client_state, tracing::trace_state_ptr trace_state, service_permit permit, rjson::value json_request, std::unique_ptr<request> req) {
|
||||
return e.create_table(client_state, std::move(trace_state), std::move(permit), std::move(json_request));
|
||||
@@ -578,14 +566,14 @@ future<> server::init(net::inet_address addr, std::optional<uint16_t> port, std:
|
||||
set_routes(_https_server._routes);
|
||||
_https_server.set_content_length_limit(server::content_length_limit);
|
||||
_https_server.set_content_streaming(true);
|
||||
auto server_creds = creds->build_reloadable_server_credentials([](const std::unordered_set<sstring>& files, std::exception_ptr ep) {
|
||||
_https_server.set_tls_credentials(creds->build_reloadable_server_credentials([](const std::unordered_set<sstring>& files, std::exception_ptr ep) {
|
||||
if (ep) {
|
||||
slogger.warn("Exception loading {}: {}", files, ep);
|
||||
} else {
|
||||
slogger.info("Reloaded {}", files);
|
||||
}
|
||||
}).get();
|
||||
_https_server.listen(socket_address{addr, *https_port}, std::move(server_creds)).get();
|
||||
}).get0());
|
||||
_https_server.listen(socket_address{addr, *https_port}).get();
|
||||
_enabled_servers.push_back(std::ref(_https_server));
|
||||
}
|
||||
});
|
||||
@@ -643,7 +631,7 @@ future<> server::json_parser::stop() {
|
||||
|
||||
const char* api_error::what() const noexcept {
|
||||
if (_what_string.empty()) {
|
||||
_what_string = fmt::format("{} {}: {}", std::to_underlying(_http_code), _type, _msg);
|
||||
_what_string = format("{} {}: {}", static_cast<int>(_http_code), _type, _msg);
|
||||
}
|
||||
return _what_string.c_str();
|
||||
}
|
||||
|
||||
@@ -42,11 +42,6 @@ class server {
|
||||
bool _enforce_authorization;
|
||||
utils::small_vector<std::reference_wrapper<seastar::httpd::http_server>, 2> _enabled_servers;
|
||||
gate _pending_requests;
|
||||
// In some places we will need a CQL updateable_timeout_config object even
|
||||
// though it isn't really relevant for Alternator which defines its own
|
||||
// timeouts separately. We can create this object only once.
|
||||
updateable_timeout_config _timeout_config;
|
||||
|
||||
alternator_callbacks_map _callbacks;
|
||||
|
||||
semaphore* _memory_limiter;
|
||||
|
||||
@@ -21,12 +21,10 @@ stats::stats() : api_operations{} {
|
||||
_metrics.add_group("alternator", {
|
||||
#define OPERATION(name, CamelCaseName) \
|
||||
seastar::metrics::make_total_operations("operation", api_operations.name, \
|
||||
seastar::metrics::description("number of operations via Alternator API"), {op(CamelCaseName)}).set_skip_when_empty(),
|
||||
seastar::metrics::description("number of operations via Alternator API"), {op(CamelCaseName)}),
|
||||
#define OPERATION_LATENCY(name, CamelCaseName) \
|
||||
seastar::metrics::make_histogram("op_latency", \
|
||||
seastar::metrics::description("Latency histogram of an operation via Alternator API"), {op(CamelCaseName)}, [this]{return to_metrics_histogram(api_operations.name.histogram());}).aggregate({seastar::metrics::shard_label}).set_skip_when_empty(), \
|
||||
seastar::metrics::make_summary("op_latency_summary", \
|
||||
seastar::metrics::description("Latency summary of an operation via Alternator API"), [this]{return to_metrics_summary(api_operations.name.summary());})(op(CamelCaseName)).set_skip_when_empty(),
|
||||
seastar::metrics::description("Latency histogram of an operation via Alternator API"), {op(CamelCaseName)}, [this]{return to_metrics_histogram(api_operations.name);}),
|
||||
OPERATION(batch_get_item, "BatchGetItem")
|
||||
OPERATION(batch_write_item, "BatchWriteItem")
|
||||
OPERATION(create_backup, "CreateBackup")
|
||||
@@ -67,8 +65,6 @@ stats::stats() : api_operations{} {
|
||||
OPERATION_LATENCY(get_item_latency, "GetItem")
|
||||
OPERATION_LATENCY(delete_item_latency, "DeleteItem")
|
||||
OPERATION_LATENCY(update_item_latency, "UpdateItem")
|
||||
OPERATION_LATENCY(batch_write_item_latency, "BatchWriteItem")
|
||||
OPERATION_LATENCY(batch_get_item_latency, "BatchGetItem")
|
||||
OPERATION(list_streams, "ListStreams")
|
||||
OPERATION(describe_stream, "DescribeStream")
|
||||
OPERATION(get_shard_iterator, "GetShardIterator")
|
||||
@@ -96,10 +92,6 @@ stats::stats() : api_operations{} {
|
||||
seastar::metrics::description("number of rows read and matched during filtering operations")),
|
||||
seastar::metrics::make_total_operations("filtered_rows_dropped_total", [this] { return cql_stats.filtered_rows_read_total - cql_stats.filtered_rows_matched_total; },
|
||||
seastar::metrics::description("number of rows read and dropped during filtering operations")),
|
||||
seastar::metrics::make_counter("batch_item_count", seastar::metrics::description("The total number of items processed across all batches"),{op("BatchWriteItem")},
|
||||
api_operations.batch_write_item_batch_total).set_skip_when_empty(),
|
||||
seastar::metrics::make_counter("batch_item_count", seastar::metrics::description("The total number of items processed across all batches"),{op("BatchGetItem")},
|
||||
api_operations.batch_get_item_batch_total).set_skip_when_empty(),
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,8 @@
|
||||
#include <cstdint>
|
||||
|
||||
#include <seastar/core/metrics_registration.hh>
|
||||
#include "utils/histogram.hh"
|
||||
#include "seastarx.hh"
|
||||
#include "utils/estimated_histogram.hh"
|
||||
#include "cql3/stats.hh"
|
||||
|
||||
namespace alternator {
|
||||
@@ -26,8 +27,6 @@ public:
|
||||
struct {
|
||||
uint64_t batch_get_item = 0;
|
||||
uint64_t batch_write_item = 0;
|
||||
uint64_t batch_get_item_batch_total = 0;
|
||||
uint64_t batch_write_item_batch_total = 0;
|
||||
uint64_t create_backup = 0;
|
||||
uint64_t create_global_table = 0;
|
||||
uint64_t create_table = 0;
|
||||
@@ -67,13 +66,11 @@ public:
|
||||
uint64_t get_shard_iterator = 0;
|
||||
uint64_t get_records = 0;
|
||||
|
||||
utils::timed_rate_moving_average_summary_and_histogram put_item_latency;
|
||||
utils::timed_rate_moving_average_summary_and_histogram get_item_latency;
|
||||
utils::timed_rate_moving_average_summary_and_histogram delete_item_latency;
|
||||
utils::timed_rate_moving_average_summary_and_histogram update_item_latency;
|
||||
utils::timed_rate_moving_average_summary_and_histogram batch_write_item_latency;
|
||||
utils::timed_rate_moving_average_summary_and_histogram batch_get_item_latency;
|
||||
utils::timed_rate_moving_average_summary_and_histogram get_records_latency;
|
||||
utils::time_estimated_histogram put_item_latency;
|
||||
utils::time_estimated_histogram get_item_latency;
|
||||
utils::time_estimated_histogram delete_item_latency;
|
||||
utils::time_estimated_histogram update_item_latency;
|
||||
utils::time_estimated_histogram get_records_latency;
|
||||
} api_operations;
|
||||
// Miscellaneous event counters
|
||||
uint64_t total_operations = 0;
|
||||
|
||||
@@ -13,7 +13,8 @@
|
||||
|
||||
#include <seastar/json/formatter.hh>
|
||||
|
||||
#include "auth/permission.hh"
|
||||
#include "utils/base64.hh"
|
||||
#include "log.hh"
|
||||
#include "db/config.hh"
|
||||
|
||||
#include "cdc/log.hh"
|
||||
@@ -24,6 +25,7 @@
|
||||
#include "utils/UUID_gen.hh"
|
||||
#include "cql3/selection/selection.hh"
|
||||
#include "cql3/result_set.hh"
|
||||
#include "cql3/type_json.hh"
|
||||
#include "cql3/column_identifier.hh"
|
||||
#include "schema/schema_builder.hh"
|
||||
#include "service/storage_proxy.hh"
|
||||
@@ -31,6 +33,7 @@
|
||||
#include "gms/feature_service.hh"
|
||||
|
||||
#include "executor.hh"
|
||||
#include "rmw_operation.hh"
|
||||
#include "data_dictionary/data_dictionary.hh"
|
||||
|
||||
/**
|
||||
@@ -234,8 +237,11 @@ struct shard_id {
|
||||
|
||||
// dynamo specifies shardid as max 65 chars.
|
||||
friend std::ostream& operator<<(std::ostream& os, const shard_id& id) {
|
||||
fmt::print(os, "{} {:x}:{}", marker, id.time.time_since_epoch().count(), id.id.to_bytes());
|
||||
return os;
|
||||
boost::io::ios_flags_saver fs(os);
|
||||
return os << marker << std::hex
|
||||
<< id.time.time_since_epoch().count()
|
||||
<< ':' << id.id.to_bytes()
|
||||
;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -274,7 +280,7 @@ struct sequence_number {
|
||||
* Timeuuids viewed as msb<<64|lsb are _not_,
|
||||
* but they are still sorted as
|
||||
* timestamp() << 64|lsb
|
||||
* so we can simply unpack the mangled msb
|
||||
* so we can simpy unpack the mangled msb
|
||||
* and use as hi 64 in our "bignum".
|
||||
*/
|
||||
uint128_t hi = uint64_t(num.uuid.timestamp());
|
||||
@@ -413,7 +419,7 @@ using namespace std::string_literals;
|
||||
*
|
||||
* In scylla, this is sort of akin to an ID having corresponding ID/ID:s
|
||||
* that cover the token range it represents. Because ID:s are per
|
||||
* vnode shard however, this relation can be somewhat ambiguous.
|
||||
* vnode shard however, this relation can be somewhat ambigous.
|
||||
* We still provide some semblance of this by finding the ID in
|
||||
* older generation that has token start < current ID token start.
|
||||
* This will be a partial overlap, but it is the best we can do.
|
||||
@@ -520,7 +526,7 @@ future<executor::request_return_type> executor::describe_stream(client_state& cl
|
||||
// (see explanation above) since we want to find closest
|
||||
// token boundary when determining parent.
|
||||
// #7346 - we processed and searched children/parents in
|
||||
// stored order, which is not necessarily token order,
|
||||
// stored order, which is not neccesarily token order,
|
||||
// so the finding of "closest" token boundary (using upper bound)
|
||||
// could give somewhat weird results.
|
||||
static auto token_cmp = [](const cdc::stream_id& id1, const cdc::stream_id& id2) {
|
||||
@@ -777,7 +783,7 @@ struct event_id {
|
||||
cdc::stream_id stream;
|
||||
utils::UUID timestamp;
|
||||
|
||||
static constexpr auto marker = 'E';
|
||||
static const auto marker = 'E';
|
||||
|
||||
event_id(cdc::stream_id s, utils::UUID ts)
|
||||
: stream(s)
|
||||
@@ -785,8 +791,10 @@ struct event_id {
|
||||
{}
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& os, const event_id& id) {
|
||||
fmt::print(os, "{}{}:{}", marker, id.stream.to_bytes(), id.timestamp);
|
||||
return os;
|
||||
boost::io::ios_flags_saver fs(os);
|
||||
return os << marker << std::hex << id.stream.to_bytes()
|
||||
<< ':' << id.timestamp
|
||||
;
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -819,13 +827,11 @@ future<executor::request_return_type> executor::get_records(client_state& client
|
||||
}
|
||||
|
||||
if (!schema || !base || !is_alternator_keyspace(schema->ks_name())) {
|
||||
co_return api_error::resource_not_found(fmt::to_string(iter.table));
|
||||
throw api_error::resource_not_found(fmt::to_string(iter.table));
|
||||
}
|
||||
|
||||
tracing::add_table_name(trace_state, schema->ks_name(), schema->cf_name());
|
||||
|
||||
co_await verify_permission(client_state, schema, auth::permission::SELECT);
|
||||
|
||||
db::consistency_level cl = db::consistency_level::LOCAL_QUORUM;
|
||||
partition_key pk = iter.shard.id.to_partition_key(*schema);
|
||||
|
||||
@@ -890,7 +896,7 @@ future<executor::request_return_type> executor::get_records(client_state& client
|
||||
auto command = ::make_lw_shared<query::read_command>(schema->id(), schema->version(), partition_slice, _proxy.get_max_result_size(partition_slice),
|
||||
query::tombstone_limit(_proxy.get_tombstone_limit()), query::row_limit(limit * mul));
|
||||
|
||||
co_return co_await _proxy.query(schema, std::move(command), std::move(partition_ranges), cl, service::storage_proxy::coordinator_query_options(default_timeout(), std::move(permit), client_state)).then(
|
||||
return _proxy.query(schema, std::move(command), std::move(partition_ranges), cl, service::storage_proxy::coordinator_query_options(default_timeout(), std::move(permit), client_state)).then(
|
||||
[this, schema, partition_slice = std::move(partition_slice), selection = std::move(selection), start_time = std::move(start_time), limit, key_names = std::move(key_names), attr_names = std::move(attr_names), type, iter, high_ts] (service::storage_proxy::coordinator_query_result qr) mutable {
|
||||
cql3::selection::result_set_builder builder(*selection, gc_clock::now());
|
||||
query::result_view::consume(*qr.query_result, partition_slice, cql3::selection::result_set_builder::visitor(builder, *schema, *selection));
|
||||
@@ -1014,7 +1020,7 @@ future<executor::request_return_type> executor::get_records(client_state& client
|
||||
// shard did end, then the next read will have nrecords == 0 and
|
||||
// will notice end end of shard and not return NextShardIterator.
|
||||
rjson::add(ret, "NextShardIterator", next_iter);
|
||||
_stats.api_operations.get_records_latency.mark(std::chrono::steady_clock::now() - start_time);
|
||||
_stats.api_operations.get_records_latency.add(std::chrono::steady_clock::now() - start_time);
|
||||
return make_ready_future<executor::request_return_type>(make_jsonable(std::move(ret)));
|
||||
}
|
||||
|
||||
@@ -1037,7 +1043,7 @@ future<executor::request_return_type> executor::get_records(client_state& client
|
||||
shard_iterator next_iter(iter.table, iter.shard, utils::UUID_gen::min_time_UUID(high_ts.time_since_epoch()), true);
|
||||
rjson::add(ret, "NextShardIterator", iter);
|
||||
}
|
||||
_stats.api_operations.get_records_latency.mark(std::chrono::steady_clock::now() - start_time);
|
||||
_stats.api_operations.get_records_latency.add(std::chrono::steady_clock::now() - start_time);
|
||||
if (is_big(ret)) {
|
||||
return make_ready_future<executor::request_return_type>(make_streamed(std::move(ret)));
|
||||
}
|
||||
@@ -1055,6 +1061,9 @@ void executor::add_stream_options(const rjson::value& stream_specification, sche
|
||||
if (stream_enabled->GetBool()) {
|
||||
auto db = sp.data_dictionary();
|
||||
|
||||
if (!db.features().cdc) {
|
||||
throw api_error::validation("StreamSpecification: streams (CDC) feature not enabled in cluster.");
|
||||
}
|
||||
if (!db.features().alternator_streams) {
|
||||
throw api_error::validation("StreamSpecification: alternator streams feature not enabled in cluster.");
|
||||
}
|
||||
|
||||
@@ -26,19 +26,19 @@
|
||||
#include "log.hh"
|
||||
#include "gc_clock.hh"
|
||||
#include "replica/database.hh"
|
||||
#include "service/client_state.hh"
|
||||
#include "service_permit.hh"
|
||||
#include "timestamp.hh"
|
||||
#include "service/storage_proxy.hh"
|
||||
#include "service/pager/paging_state.hh"
|
||||
#include "service/pager/query_pagers.hh"
|
||||
#include "gms/feature_service.hh"
|
||||
#include "sstables/types.hh"
|
||||
#include "mutation/mutation.hh"
|
||||
#include "types/types.hh"
|
||||
#include "types/map.hh"
|
||||
#include "utils/assert.hh"
|
||||
#include "utils/rjson.hh"
|
||||
#include "utils/big_decimal.hh"
|
||||
#include "utils/fb_utilities.hh"
|
||||
#include "cql3/selection/selection.hh"
|
||||
#include "cql3/values.hh"
|
||||
#include "cql3/query_options.hh"
|
||||
@@ -81,11 +81,6 @@ future<executor::request_return_type> executor::update_time_to_live(client_state
|
||||
co_return api_error::validation("UpdateTimeToLive requires boolean Enabled");
|
||||
}
|
||||
bool enabled = v->GetBool();
|
||||
// Alternator TTL doesn't yet work when the table uses tablets (#16567)
|
||||
if (enabled && _proxy.local_db().find_keyspace(schema->ks_name()).get_replication_strategy().uses_tablets()) {
|
||||
co_return api_error::validation("TTL not yet supported on a table using tablets (issue #16567). "
|
||||
"Create a table with the tag 'experimental:initial_tablets' set to 'none' to use vnodes.");
|
||||
}
|
||||
v = rjson::find(*spec, "AttributeName");
|
||||
if (!v || !v->IsString()) {
|
||||
co_return api_error::validation("UpdateTimeToLive requires string AttributeName");
|
||||
@@ -99,7 +94,6 @@ future<executor::request_return_type> executor::update_time_to_live(client_state
|
||||
}
|
||||
sstring attribute_name(v->GetString(), v->GetStringLength());
|
||||
|
||||
co_await verify_permission(client_state, schema, auth::permission::ALTER);
|
||||
co_await db::modify_tags(_mm, schema->ks_name(), schema->cf_name(), [&](std::map<sstring, sstring>& tags_map) {
|
||||
if (enabled) {
|
||||
if (tags_map.contains(TTL_TAG_KEY)) {
|
||||
@@ -161,7 +155,7 @@ future<executor::request_return_type> executor::describe_time_to_live(client_sta
|
||||
// node owning this range as a "primary range" (the first node in the ring
|
||||
// with this range), but when this node is down, the secondary owner (the
|
||||
// second in the ring) may take over.
|
||||
// An expiration thread is responsible for all tables which need expiration
|
||||
// An expiration thread is reponsible for all tables which need expiration
|
||||
// scans. Currently, the different tables are scanned sequentially (not in
|
||||
// parallel).
|
||||
// The expiration thread scans item using CL=QUORUM to ensures that it reads
|
||||
@@ -315,7 +309,7 @@ static size_t random_offset(size_t min, size_t max) {
|
||||
// this range's primary node is down. For this we need to return not just
|
||||
// a list of this node's secondary ranges - but also the primary owner of
|
||||
// each of those ranges.
|
||||
static future<std::vector<std::pair<dht::token_range, gms::inet_address>>> get_secondary_ranges(
|
||||
static std::vector<std::pair<dht::token_range, gms::inet_address>> get_secondary_ranges(
|
||||
const locator::effective_replication_map_ptr& erm,
|
||||
gms::inet_address ep) {
|
||||
const auto& tm = *erm->get_token_metadata_ptr();
|
||||
@@ -326,7 +320,6 @@ static future<std::vector<std::pair<dht::token_range, gms::inet_address>>> get_s
|
||||
}
|
||||
auto prev_tok = sorted_tokens.back();
|
||||
for (const auto& tok : sorted_tokens) {
|
||||
co_await coroutine::maybe_yield();
|
||||
inet_address_vector_replica_set eps = erm->get_natural_endpoints(tok);
|
||||
if (eps.size() <= 1 || eps[1] != ep) {
|
||||
prev_tok = tok;
|
||||
@@ -354,7 +347,7 @@ static future<std::vector<std::pair<dht::token_range, gms::inet_address>>> get_s
|
||||
}
|
||||
prev_tok = tok;
|
||||
}
|
||||
co_return ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -387,68 +380,65 @@ static future<std::vector<std::pair<dht::token_range, gms::inet_address>>> get_s
|
||||
// the chances of covering all ranges during a scan when restarts occur.
|
||||
// A more deterministic way would be to regularly persist the scanning state,
|
||||
// but that incurs overhead that we want to avoid if not needed.
|
||||
//
|
||||
// FIXME: Check if this algorithm is safe with tablet migration.
|
||||
// https://github.com/scylladb/scylladb/issues/16567
|
||||
|
||||
// ranges_holder_primary holds just the primary ranges themselves
|
||||
class ranges_holder_primary {
|
||||
dht::token_range_vector _token_ranges;
|
||||
public:
|
||||
explicit ranges_holder_primary(dht::token_range_vector token_ranges) : _token_ranges(std::move(token_ranges)) {}
|
||||
static future<ranges_holder_primary> make(const locator::vnode_effective_replication_map_ptr& erm, gms::inet_address ep) {
|
||||
co_return ranges_holder_primary(co_await erm->get_primary_ranges(ep));
|
||||
}
|
||||
std::size_t size() const { return _token_ranges.size(); }
|
||||
const dht::token_range& operator[](std::size_t i) const {
|
||||
return _token_ranges[i];
|
||||
}
|
||||
bool should_skip(std::size_t i) const {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
// ranges_holder<secondary> holds the secondary token ranges plus each
|
||||
// range's primary owner, needed to implement should_skip().
|
||||
class ranges_holder_secondary {
|
||||
std::vector<std::pair<dht::token_range, gms::inet_address>> _token_ranges;
|
||||
const gms::gossiper& _gossiper;
|
||||
public:
|
||||
explicit ranges_holder_secondary(std::vector<std::pair<dht::token_range, gms::inet_address>> token_ranges, const gms::gossiper& g)
|
||||
: _token_ranges(std::move(token_ranges))
|
||||
, _gossiper(g) {}
|
||||
static future<ranges_holder_secondary> make(const locator::effective_replication_map_ptr& erm, gms::inet_address ep, const gms::gossiper& g) {
|
||||
co_return ranges_holder_secondary(co_await get_secondary_ranges(erm, ep), g);
|
||||
}
|
||||
std::size_t size() const { return _token_ranges.size(); }
|
||||
const dht::token_range& operator[](std::size_t i) const {
|
||||
return _token_ranges[i].first;
|
||||
}
|
||||
// range i should be skipped if its primary owner is alive.
|
||||
bool should_skip(std::size_t i) const {
|
||||
return _gossiper.is_alive(_token_ranges[i].second);
|
||||
}
|
||||
};
|
||||
|
||||
template<class primary_or_secondary_t>
|
||||
enum primary_or_secondary_t {primary, secondary};
|
||||
template<primary_or_secondary_t primary_or_secondary>
|
||||
class token_ranges_owned_by_this_shard {
|
||||
// ranges_holder_primary holds just the primary ranges themselves
|
||||
class ranges_holder_primary {
|
||||
const dht::token_range_vector _token_ranges;
|
||||
public:
|
||||
ranges_holder_primary(const locator::vnode_effective_replication_map_ptr& erm, gms::gossiper& g, gms::inet_address ep)
|
||||
: _token_ranges(erm->get_primary_ranges(ep)) {}
|
||||
std::size_t size() const { return _token_ranges.size(); }
|
||||
const dht::token_range& operator[](std::size_t i) const {
|
||||
return _token_ranges[i];
|
||||
}
|
||||
bool should_skip(std::size_t i) const {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
// ranges_holder<secondary> holds the secondary token ranges plus each
|
||||
// range's primary owner, needed to implement should_skip().
|
||||
class ranges_holder_secondary {
|
||||
std::vector<std::pair<dht::token_range, gms::inet_address>> _token_ranges;
|
||||
gms::gossiper& _gossiper;
|
||||
public:
|
||||
ranges_holder_secondary(const locator::effective_replication_map_ptr& erm, gms::gossiper& g, gms::inet_address ep)
|
||||
: _token_ranges(get_secondary_ranges(erm, ep))
|
||||
, _gossiper(g) {}
|
||||
std::size_t size() const { return _token_ranges.size(); }
|
||||
const dht::token_range& operator[](std::size_t i) const {
|
||||
return _token_ranges[i].first;
|
||||
}
|
||||
// range i should be skipped if its primary owner is alive.
|
||||
bool should_skip(std::size_t i) const {
|
||||
return _gossiper.is_alive(_token_ranges[i].second);
|
||||
}
|
||||
};
|
||||
|
||||
schema_ptr _s;
|
||||
locator::effective_replication_map_ptr _erm;
|
||||
// _token_ranges will contain a list of token ranges owned by this node.
|
||||
// We'll further need to split each such range to the pieces owned by
|
||||
// the current shard, using _intersecter.
|
||||
const primary_or_secondary_t _token_ranges;
|
||||
using ranges_holder = std::conditional_t<
|
||||
primary_or_secondary == primary_or_secondary_t::primary,
|
||||
ranges_holder_primary,
|
||||
ranges_holder_secondary>;
|
||||
const ranges_holder _token_ranges;
|
||||
// NOTICE: _range_idx is used modulo _token_ranges size when accessing
|
||||
// the data to ensure that it doesn't go out of bounds
|
||||
size_t _range_idx;
|
||||
size_t _end_idx;
|
||||
std::optional<dht::selective_token_range_sharder> _intersecter;
|
||||
locator::effective_replication_map_ptr _erm;
|
||||
public:
|
||||
token_ranges_owned_by_this_shard(schema_ptr s, primary_or_secondary_t token_ranges)
|
||||
token_ranges_owned_by_this_shard(replica::database& db, gms::gossiper& g, schema_ptr s)
|
||||
: _s(s)
|
||||
, _erm(s->table().get_effective_replication_map())
|
||||
, _token_ranges(std::move(token_ranges))
|
||||
, _token_ranges(db.find_keyspace(s->ks_name()).get_effective_replication_map(),
|
||||
g, utils::fb_utilities::get_broadcast_address())
|
||||
, _range_idx(random_offset(0, _token_ranges.size() - 1))
|
||||
, _end_idx(_range_idx + _token_ranges.size())
|
||||
, _erm(s->table().get_effective_replication_map())
|
||||
{
|
||||
tlogger.debug("Generating token ranges starting from base range {} of {}", _range_idx, _token_ranges.size());
|
||||
}
|
||||
@@ -502,7 +492,6 @@ struct scan_ranges_context {
|
||||
bytes column_name;
|
||||
std::optional<std::string> member;
|
||||
|
||||
service::client_state internal_client_state;
|
||||
::shared_ptr<cql3::selection::selection> selection;
|
||||
std::unique_ptr<service::query_state> query_state_ptr;
|
||||
std::unique_ptr<cql3::query_options> query_options;
|
||||
@@ -512,7 +501,6 @@ struct scan_ranges_context {
|
||||
: s(s)
|
||||
, column_name(column_name)
|
||||
, member(member)
|
||||
, internal_client_state(service::client_state::internal_tag())
|
||||
{
|
||||
// FIXME: don't read the entire items - read only parts of it.
|
||||
// We must read the key columns (to be able to delete) and also
|
||||
@@ -531,9 +519,10 @@ struct scan_ranges_context {
|
||||
std::vector<query::clustering_range> ck_bounds{query::clustering_range::make_open_ended_both_sides()};
|
||||
auto partition_slice = query::partition_slice(std::move(ck_bounds), {}, std::move(regular_columns), opts);
|
||||
command = ::make_lw_shared<query::read_command>(s->id(), s->version(), partition_slice, proxy.get_max_result_size(partition_slice), query::tombstone_limit(proxy.get_tombstone_limit()));
|
||||
executor::client_state client_state{executor::client_state::internal_tag()};
|
||||
tracing::trace_state_ptr trace_state;
|
||||
// NOTICE: empty_service_permit is used because the TTL service has fixed parallelism
|
||||
query_state_ptr = std::make_unique<service::query_state>(internal_client_state, trace_state, empty_service_permit());
|
||||
query_state_ptr = std::make_unique<service::query_state>(client_state, trace_state, empty_service_permit());
|
||||
// FIXME: What should we do on multi-DC? Will we run the expiration on the same ranges on all
|
||||
// DCs or only once for each range? If the latter, we need to change the CLs in the
|
||||
// scanner and deleter.
|
||||
@@ -556,7 +545,7 @@ static future<> scan_table_ranges(
|
||||
expiration_service::stats& expiration_stats)
|
||||
{
|
||||
const schema_ptr& s = scan_ctx.s;
|
||||
SCYLLA_ASSERT (partition_ranges.size() == 1); // otherwise issue #9167 will cause incorrect results.
|
||||
assert (partition_ranges.size() == 1); // otherwise issue #9167 will cause incorrect results.
|
||||
auto p = service::pager::query_pagers::pager(proxy, s, scan_ctx.selection, *scan_ctx.query_state_ptr,
|
||||
*scan_ctx.query_options, scan_ctx.command, std::move(partition_ranges), nullptr);
|
||||
while (!p->is_exhausted()) {
|
||||
@@ -729,9 +718,7 @@ static future<bool> scan_table(
|
||||
expiration_stats.scan_table++;
|
||||
// FIXME: need to pace the scan, not do it all at once.
|
||||
scan_ranges_context scan_ctx{s, proxy, std::move(column_name), std::move(member)};
|
||||
auto erm = db.real_database().find_keyspace(s->ks_name()).get_vnode_effective_replication_map();
|
||||
auto my_address = erm->get_topology().my_address();
|
||||
token_ranges_owned_by_this_shard my_ranges(s, co_await ranges_holder_primary::make(erm, my_address));
|
||||
token_ranges_owned_by_this_shard<primary> my_ranges(db.real_database(), gossiper, s);
|
||||
while (std::optional<dht::partition_range> range = my_ranges.next_partition_range()) {
|
||||
// Note that because of issue #9167 we need to run a separate
|
||||
// query on each partition range, and can't pass several of
|
||||
@@ -751,7 +738,7 @@ static future<bool> scan_table(
|
||||
// by tasking another node to take over scanning of the dead node's primary
|
||||
// ranges. What we do here is that this node will also check expiration
|
||||
// on its *secondary* ranges - but only those whose primary owner is down.
|
||||
token_ranges_owned_by_this_shard my_secondary_ranges(s, co_await ranges_holder_secondary::make(erm, my_address, gossiper));
|
||||
token_ranges_owned_by_this_shard<secondary> my_secondary_ranges(db.real_database(), gossiper, s);
|
||||
while (std::optional<dht::partition_range> range = my_secondary_ranges.next_partition_range()) {
|
||||
expiration_stats.secondary_ranges_scanned++;
|
||||
dht::partition_range_vector partition_ranges;
|
||||
|
||||
@@ -7,7 +7,6 @@ set(swagger_files
|
||||
api-doc/commitlog.json
|
||||
api-doc/compaction_manager.json
|
||||
api-doc/config.json
|
||||
api-doc/cql_server_test.json
|
||||
api-doc/endpoint_snitch_info.json
|
||||
api-doc/error_injection.json
|
||||
api-doc/failure_detector.json
|
||||
@@ -16,12 +15,10 @@ set(swagger_files
|
||||
api-doc/lsa.json
|
||||
api-doc/messaging_service.json
|
||||
api-doc/metrics.json
|
||||
api-doc/raft.json
|
||||
api-doc/storage_proxy.json
|
||||
api-doc/storage_service.json
|
||||
api-doc/stream_manager.json
|
||||
api-doc/system.json
|
||||
api-doc/tasks.json
|
||||
api-doc/task_manager.json
|
||||
api-doc/task_manager_test.json
|
||||
api-doc/utils.json)
|
||||
@@ -47,7 +44,6 @@ target_sources(api
|
||||
commitlog.cc
|
||||
compaction_manager.cc
|
||||
config.cc
|
||||
cql_server_test.cc
|
||||
endpoint_snitch.cc
|
||||
error_injection.cc
|
||||
authorization_cache.cc
|
||||
@@ -56,15 +52,12 @@ target_sources(api
|
||||
hinted_handoff.cc
|
||||
lsa.cc
|
||||
messaging_service.cc
|
||||
raft.cc
|
||||
storage_proxy.cc
|
||||
storage_service.cc
|
||||
stream_manager.cc
|
||||
system.cc
|
||||
tasks.cc
|
||||
task_manager.cc
|
||||
task_manager_test.cc
|
||||
token_metadata.cc
|
||||
${swagger_gen_files})
|
||||
target_include_directories(api
|
||||
PUBLIC
|
||||
@@ -73,9 +66,6 @@ target_include_directories(api
|
||||
target_link_libraries(api
|
||||
idl
|
||||
wasmtime_bindings
|
||||
Seastar::seastar
|
||||
xxHash::xxhash
|
||||
absl::headers)
|
||||
|
||||
check_headers(check-headers api
|
||||
GLOB_RECURSE ${CMAKE_CURRENT_SOURCE_DIR}/*.hh)
|
||||
Seastar::seastar
|
||||
xxHash::xxhash)
|
||||
|
||||
@@ -67,7 +67,7 @@
|
||||
"parameters":[
|
||||
{
|
||||
"name":"pluginid",
|
||||
"description":"The plugin ID, describe the component the metric belongs to. Examples are cache and alternator, etc'. Regex are supported.",
|
||||
"description":"The plugin ID, describe the component the metric belongs to. Examples are cache, thrift, etc'. Regex are supported.The plugin ID, describe the component the metric belong to. Examples are: cache, thrift etc'. regex are supported",
|
||||
"required":true,
|
||||
"allowMultiple":false,
|
||||
"type":"string",
|
||||
@@ -199,4 +199,4 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -84,22 +84,6 @@
|
||||
"type":"string",
|
||||
"paramType":"path"
|
||||
},
|
||||
{
|
||||
"name":"flush_memtables",
|
||||
"description":"Controls flushing of memtables before compaction (true by default). Set to \"false\" to skip automatic flushing of memtables before compaction, e.g. when the table is flushed explicitly before invoking the compaction api.",
|
||||
"required":false,
|
||||
"allowMultiple":false,
|
||||
"type":"boolean",
|
||||
"paramType":"query"
|
||||
},
|
||||
{
|
||||
"name":"consider_only_existing_data",
|
||||
"description":"Set to \"true\" to flush all memtables and force tombstone garbage collection to check only the sstables being compacted (false by default). The memtable, commitlog and other uncompacted sstables will not be checked during tombstone garbage collection.",
|
||||
"required":false,
|
||||
"allowMultiple":false,
|
||||
"type":"boolean",
|
||||
"paramType":"query"
|
||||
},
|
||||
{
|
||||
"name":"split_output",
|
||||
"description":"true if the output of the major compaction should be split in several sstables",
|
||||
@@ -219,7 +203,7 @@
|
||||
"operations":[
|
||||
{
|
||||
"method":"POST",
|
||||
"summary":"Sets the minimum and maximum number of sstables in queue before compaction kicks off",
|
||||
"summary":"Sets the minumum and maximum number of sstables in queue before compaction kicks off",
|
||||
"type":"string",
|
||||
"nickname":"set_compaction_threshold",
|
||||
"produces":[
|
||||
|
||||
@@ -144,21 +144,6 @@
|
||||
"parameters": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/commitlog/metrics/max_disk_size",
|
||||
"operations": [
|
||||
{
|
||||
"method": "GET",
|
||||
"summary": "Get max disk size",
|
||||
"type": "long",
|
||||
"nickname": "get_max_disk_size",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"parameters": []
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
{
|
||||
"apiVersion":"0.0.1",
|
||||
"swaggerVersion":"1.2",
|
||||
"basePath":"{{Protocol}}://{{Host}}",
|
||||
"resourcePath":"/cql_server_test",
|
||||
"produces":[
|
||||
"application/json"
|
||||
],
|
||||
"apis":[
|
||||
{
|
||||
"path":"/cql_server_test/connections_params",
|
||||
"operations":[
|
||||
{
|
||||
"method":"GET",
|
||||
"summary":"Get service level params of each CQL connection",
|
||||
"type":"connections_service_level_params",
|
||||
"nickname":"connections_params",
|
||||
"produces":[
|
||||
"application/json"
|
||||
],
|
||||
"parameters":[]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -63,28 +63,6 @@
|
||||
"paramType":"path"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"method":"GET",
|
||||
"summary":"Read the state of an injection from all shards",
|
||||
"type":"array",
|
||||
"items":{
|
||||
"type":"error_injection_info"
|
||||
},
|
||||
"nickname":"read_injection",
|
||||
"produces":[
|
||||
"application/json"
|
||||
],
|
||||
"parameters":[
|
||||
{
|
||||
"name":"injection",
|
||||
"description":"injection name",
|
||||
"required":true,
|
||||
"allowMultiple":false,
|
||||
"type":"string",
|
||||
"paramType":"path"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -112,30 +90,6 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"path":"/v2/error_injection/disconnect/{ip}",
|
||||
"operations":[
|
||||
{
|
||||
"method":"POST",
|
||||
"summary":"Drop connection to a given IP",
|
||||
"type":"void",
|
||||
"nickname":"inject_disconnect",
|
||||
"produces":[
|
||||
"application/json"
|
||||
],
|
||||
"parameters":[
|
||||
{
|
||||
"name":"ip",
|
||||
"description":"IP address to disconnect from",
|
||||
"required":true,
|
||||
"allowMultiple":false,
|
||||
"type":"string",
|
||||
"paramType":"path"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"path":"/v2/error_injection/injection",
|
||||
"operations":[
|
||||
@@ -174,39 +128,5 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"models":{
|
||||
"mapper":{
|
||||
"id":"mapper",
|
||||
"description":"A key value mapping",
|
||||
"properties":{
|
||||
"key":{
|
||||
"type":"string",
|
||||
"description":"The key"
|
||||
},
|
||||
"value":{
|
||||
"type":"string",
|
||||
"description":"The value"
|
||||
}
|
||||
}
|
||||
},
|
||||
"error_injection_info":{
|
||||
"id":"error_injection_info",
|
||||
"description":"Information about an error injection",
|
||||
"properties":{
|
||||
"enabled":{
|
||||
"type":"boolean",
|
||||
"description":"Is the error injection enabled"
|
||||
},
|
||||
"parameters":{
|
||||
"type":"array",
|
||||
"items":{
|
||||
"type":"mapper"
|
||||
},
|
||||
"description":"The parameter values"
|
||||
}
|
||||
},
|
||||
"required":["enabled"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
"operations":[
|
||||
{
|
||||
"method":"GET",
|
||||
"summary":"Get the addresses of the down endpoints",
|
||||
"summary":"Get the addreses of the down endpoints",
|
||||
"type":"array",
|
||||
"items":{
|
||||
"type":"string"
|
||||
@@ -31,7 +31,7 @@
|
||||
"operations":[
|
||||
{
|
||||
"method":"GET",
|
||||
"summary":"Get the addresses of live endpoints",
|
||||
"summary":"Get the addreses of live endpoints",
|
||||
"type":"array",
|
||||
"items":{
|
||||
"type":"string"
|
||||
|
||||
@@ -7,11 +7,11 @@
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "The source labels, a match is based on concatenation of the labels"
|
||||
"description": "The source labels, a match is based on concatination of the labels"
|
||||
},
|
||||
"action": {
|
||||
"type": "string",
|
||||
"description": "The action to perform on match",
|
||||
"description": "The action to perfrom on match",
|
||||
"enum": ["skip_when_empty", "report_when_empty", "replace", "keep", "drop", "drop_label"]
|
||||
},
|
||||
"target_label": {
|
||||
@@ -28,7 +28,7 @@
|
||||
},
|
||||
"separator": {
|
||||
"type": "string",
|
||||
"description": "The separator string to use when concatenating the labels"
|
||||
"description": "The separator string to use when concatinating the labels"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,99 +0,0 @@
|
||||
{
|
||||
"apiVersion":"0.0.1",
|
||||
"swaggerVersion":"1.2",
|
||||
"basePath":"{{Protocol}}://{{Host}}",
|
||||
"resourcePath":"/raft",
|
||||
"produces":[
|
||||
"application/json"
|
||||
],
|
||||
"apis":[
|
||||
{
|
||||
"path":"/raft/trigger_snapshot/{group_id}",
|
||||
"operations":[
|
||||
{
|
||||
"method":"POST",
|
||||
"summary":"Triggers snapshot creation and log truncation for the given Raft group",
|
||||
"type":"string",
|
||||
"nickname":"trigger_snapshot",
|
||||
"produces":[
|
||||
"application/json"
|
||||
],
|
||||
"parameters":[
|
||||
{
|
||||
"name":"group_id",
|
||||
"description":"The ID of the group which should get snapshotted",
|
||||
"required":true,
|
||||
"allowMultiple":false,
|
||||
"type":"string",
|
||||
"paramType":"path"
|
||||
},
|
||||
{
|
||||
"name":"timeout",
|
||||
"description":"Timeout in seconds after which the endpoint returns a failure. If not provided, 60s is used.",
|
||||
"required":false,
|
||||
"allowMultiple":false,
|
||||
"type":"long",
|
||||
"paramType":"query"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"path":"/raft/leader_host",
|
||||
"operations":[
|
||||
{
|
||||
"method":"GET",
|
||||
"summary":"Returns host ID of the current leader of the given Raft group",
|
||||
"type":"string",
|
||||
"nickname":"get_leader_host",
|
||||
"produces":[
|
||||
"application/json"
|
||||
],
|
||||
"parameters":[
|
||||
{
|
||||
"name":"group_id",
|
||||
"description":"The ID of the group. When absent, group0 is used.",
|
||||
"required":false,
|
||||
"allowMultiple":false,
|
||||
"type":"string",
|
||||
"paramType":"query"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/raft/read_barrier",
|
||||
"operations": [
|
||||
{
|
||||
"method": "POST",
|
||||
"summary": "Triggers read barrier for the given Raft group to wait for previously committed commands in this group to be applied locally. For example, can be used on group 0 to wait for the node to obtain latest schema changes.",
|
||||
"type": "string",
|
||||
"nickname": "read_barrier",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"parameters": [
|
||||
{
|
||||
"name": "group_id",
|
||||
"description": "The ID of the group. When absent, group0 is used.",
|
||||
"required": false,
|
||||
"allowMultiple": false,
|
||||
"type": "string",
|
||||
"paramType": "query"
|
||||
},
|
||||
{
|
||||
"name": "timeout",
|
||||
"description": "Timeout in seconds after which the endpoint returns a failure. If not provided, 60s is used.",
|
||||
"required": false,
|
||||
"allowMultiple": false,
|
||||
"type": "long",
|
||||
"paramType": "query"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -90,7 +90,7 @@
|
||||
"operations":[
|
||||
{
|
||||
"method":"GET",
|
||||
"summary":"Returns a list of the tokens endpoint mapping, provide keyspace and cf param to get tablet mapping",
|
||||
"summary":"Returns a list of the tokens endpoint mapping",
|
||||
"type":"array",
|
||||
"items":{
|
||||
"type":"mapper"
|
||||
@@ -100,22 +100,6 @@
|
||||
"application/json"
|
||||
],
|
||||
"parameters":[
|
||||
{
|
||||
"name":"keyspace",
|
||||
"description":"The keyspace to provide the tablet mapping for",
|
||||
"required":false,
|
||||
"allowMultiple":false,
|
||||
"type":"string",
|
||||
"paramType":"query"
|
||||
},
|
||||
{
|
||||
"name":"cf",
|
||||
"description":"The table to provide the tablet mapping for",
|
||||
"required":false,
|
||||
"allowMultiple":false,
|
||||
"type":"string",
|
||||
"paramType":"query"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -352,14 +336,6 @@
|
||||
"allowMultiple":false,
|
||||
"type":"boolean",
|
||||
"paramType":"query"
|
||||
},
|
||||
{
|
||||
"name":"cf",
|
||||
"description":"Column family name",
|
||||
"required":false,
|
||||
"allowMultiple":false,
|
||||
"type":"string",
|
||||
"paramType":"query"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -392,6 +368,25 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"path":"/storage_service/describe_ring/",
|
||||
"operations":[
|
||||
{
|
||||
"method":"GET",
|
||||
"summary":"The TokenRange for a any keyspace",
|
||||
"type":"array",
|
||||
"items":{
|
||||
"type":"token_range"
|
||||
},
|
||||
"nickname":"describe_any_ring",
|
||||
"produces":[
|
||||
"application/json"
|
||||
],
|
||||
"parameters":[
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"path":"/storage_service/describe_ring/{keyspace}",
|
||||
"operations":[
|
||||
@@ -414,14 +409,6 @@
|
||||
"allowMultiple":false,
|
||||
"type":"string",
|
||||
"paramType":"path"
|
||||
},
|
||||
{
|
||||
"name":"table",
|
||||
"description":"The name of table to fetch information about",
|
||||
"required":false,
|
||||
"allowMultiple":false,
|
||||
"type":"string",
|
||||
"paramType":"query"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -449,14 +436,6 @@
|
||||
"allowMultiple":false,
|
||||
"type":"string",
|
||||
"paramType":"path"
|
||||
},
|
||||
{
|
||||
"name":"cf",
|
||||
"description":"Column family name",
|
||||
"required":false,
|
||||
"allowMultiple":false,
|
||||
"type":"string",
|
||||
"paramType":"query"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -722,142 +701,6 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"path":"/storage_service/compact",
|
||||
"operations":[
|
||||
{
|
||||
"method":"POST",
|
||||
"summary":"Forces major compaction in all keyspaces",
|
||||
"type":"void",
|
||||
"nickname":"force_compaction",
|
||||
"produces":[
|
||||
"application/json"
|
||||
],
|
||||
"parameters":[
|
||||
{
|
||||
"name":"flush_memtables",
|
||||
"description":"Controls flushing of memtables before compaction (true by default). Set to \"false\" to skip automatic flushing of memtables before compaction, e.g. when tables were flushed explicitly before invoking the compaction api.",
|
||||
"required":false,
|
||||
"allowMultiple":false,
|
||||
"type":"boolean",
|
||||
"paramType":"query"
|
||||
},
|
||||
{
|
||||
"name":"consider_only_existing_data",
|
||||
"description":"Set to \"true\" to flush all memtables and force tombstone garbage collection to check only the sstables being compacted (false by default). The memtable, commitlog and other uncompacted sstables will not be checked during tombstone garbage collection.",
|
||||
"required":false,
|
||||
"allowMultiple":false,
|
||||
"type":"boolean",
|
||||
"paramType":"query"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"path":"/storage_service/backup",
|
||||
"operations":[
|
||||
{
|
||||
"method":"POST",
|
||||
"summary":"Starts copying SSTables from a specified keyspace to a designated bucket in object storage",
|
||||
"type":"string",
|
||||
"nickname":"start_backup",
|
||||
"produces":[
|
||||
"application/json"
|
||||
],
|
||||
"parameters":[
|
||||
{
|
||||
"name":"endpoint",
|
||||
"description":"ID of the configured object storage endpoint to copy sstables to",
|
||||
"required":true,
|
||||
"allowMultiple":false,
|
||||
"type":"string",
|
||||
"paramType":"query"
|
||||
},
|
||||
{
|
||||
"name":"bucket",
|
||||
"description":"Name of the bucket to backup sstables to",
|
||||
"required":true,
|
||||
"allowMultiple":false,
|
||||
"type":"string",
|
||||
"paramType":"query"
|
||||
},
|
||||
{
|
||||
"name":"keyspace",
|
||||
"description":"Name of a keyspace to copy sstables from",
|
||||
"required":true,
|
||||
"allowMultiple":false,
|
||||
"type":"string",
|
||||
"paramType":"query"
|
||||
},
|
||||
{
|
||||
"name":"snapshot",
|
||||
"description":"Name of a snapshot to copy sstables from",
|
||||
"required":false,
|
||||
"allowMultiple":false,
|
||||
"type":"string",
|
||||
"paramType":"query"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"path":"/storage_service/restore",
|
||||
"operations":[
|
||||
{
|
||||
"method":"POST",
|
||||
"summary":"Starts copying SSTables from a designated bucket in object storage to a specified keyspace",
|
||||
"type":"string",
|
||||
"nickname":"start_restore",
|
||||
"produces":[
|
||||
"application/json"
|
||||
],
|
||||
"parameters":[
|
||||
{
|
||||
"name":"endpoint",
|
||||
"description":"ID of the configured object storage endpoint to copy SSTables from",
|
||||
"required":true,
|
||||
"allowMultiple":false,
|
||||
"type":"string",
|
||||
"paramType":"query"
|
||||
},
|
||||
{
|
||||
"name":"bucket",
|
||||
"description":"Name of the bucket to read SSTables from",
|
||||
"required":true,
|
||||
"allowMultiple":false,
|
||||
"type":"string",
|
||||
"paramType":"query"
|
||||
},
|
||||
{
|
||||
"name":"snapshot",
|
||||
"description":"Name of a snapshot to copy SSTables from",
|
||||
"required":true,
|
||||
"allowMultiple":false,
|
||||
"type":"string",
|
||||
"paramType":"query"
|
||||
},
|
||||
{
|
||||
"name":"keyspace",
|
||||
"description":"Name of a keyspace to copy SSTables to",
|
||||
"required":true,
|
||||
"allowMultiple":false,
|
||||
"type":"string",
|
||||
"paramType":"query"
|
||||
},
|
||||
{
|
||||
"name":"table",
|
||||
"description":"Name of a table to copy SSTables to",
|
||||
"required":false,
|
||||
"allowMultiple":false,
|
||||
"type":"string",
|
||||
"paramType":"query"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"path":"/storage_service/keyspace_compaction/{keyspace}",
|
||||
"operations":[
|
||||
@@ -872,7 +715,7 @@
|
||||
"parameters":[
|
||||
{
|
||||
"name":"keyspace",
|
||||
"description":"The keyspace to compact",
|
||||
"description":"The keyspace to query about",
|
||||
"required":true,
|
||||
"allowMultiple":false,
|
||||
"type":"string",
|
||||
@@ -885,22 +728,6 @@
|
||||
"allowMultiple":false,
|
||||
"type":"string",
|
||||
"paramType":"query"
|
||||
},
|
||||
{
|
||||
"name":"flush_memtables",
|
||||
"description":"Controls flushing of memtables before compaction (true by default). Set to \"false\" to skip automatic flushing of memtables before compaction, e.g. when tables were flushed explicitly before invoking the compaction api.",
|
||||
"required":false,
|
||||
"allowMultiple":false,
|
||||
"type":"boolean",
|
||||
"paramType":"query"
|
||||
},
|
||||
{
|
||||
"name":"consider_only_existing_data",
|
||||
"description":"Set to \"true\" to flush all memtables and force tombstone garbage collection to check only the sstables being compacted (false by default). The memtable, commitlog and other uncompacted sstables will not be checked during tombstone garbage collection.",
|
||||
"required":false,
|
||||
"allowMultiple":false,
|
||||
"type":"boolean",
|
||||
"paramType":"query"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -920,7 +747,7 @@
|
||||
"parameters":[
|
||||
{
|
||||
"name":"keyspace",
|
||||
"description":"The keyspace to cleanup",
|
||||
"description":"The keyspace to query about",
|
||||
"required":true,
|
||||
"allowMultiple":false,
|
||||
"type":"string",
|
||||
@@ -938,21 +765,6 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"path":"/storage_service/cleanup_all",
|
||||
"operations":[
|
||||
{
|
||||
"method":"POST",
|
||||
"summary":"Trigger a global cleanup",
|
||||
"type":"long",
|
||||
"nickname":"cleanup_all",
|
||||
"produces":[
|
||||
"application/json"
|
||||
],
|
||||
"parameters":[]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"path":"/storage_service/keyspace_offstrategy_compaction/{keyspace}",
|
||||
"operations":[
|
||||
@@ -1100,21 +912,6 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"path":"/storage_service/flush",
|
||||
"operations":[
|
||||
{
|
||||
"method":"POST",
|
||||
"summary":"Flush all memtables in all keyspaces.",
|
||||
"type":"void",
|
||||
"nickname":"force_flush",
|
||||
"produces":[
|
||||
"application/json"
|
||||
],
|
||||
"parameters":[]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"path":"/storage_service/keyspace_flush/{keyspace}",
|
||||
"operations":[
|
||||
@@ -1325,14 +1122,6 @@
|
||||
"allowMultiple":false,
|
||||
"type":"string",
|
||||
"paramType":"query"
|
||||
},
|
||||
{
|
||||
"name":"small_table_optimization",
|
||||
"description":"If the value is the string 'true' with any capitalization, perform small table optimization. When this option is enabled, user can send the repair request to any of the nodes in the cluster. There is no need to send repair requests to multiple nodes. All token ranges for the table will be repaired automatically.",
|
||||
"required":false,
|
||||
"allowMultiple":false,
|
||||
"type":"string",
|
||||
"paramType":"query"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -1666,15 +1455,6 @@
|
||||
"type":"string",
|
||||
"enum": [ "all", "user", "non_local_strategy" ],
|
||||
"paramType":"query"
|
||||
},
|
||||
{
|
||||
"name":"replication",
|
||||
"description":"Filter keyspaces for the replication used: vnodes or tablets (default: all)",
|
||||
"required":false,
|
||||
"allowMultiple":false,
|
||||
"type":"string",
|
||||
"enum": [ "all", "vnodes", "tablets" ],
|
||||
"paramType":"query"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1809,11 +1589,33 @@
|
||||
{
|
||||
"path":"/storage_service/rpc_server",
|
||||
"operations":[
|
||||
{
|
||||
"method":"DELETE",
|
||||
"summary":"Allows a user to disable thrift",
|
||||
"type":"void",
|
||||
"nickname":"stop_rpc_server",
|
||||
"produces":[
|
||||
"application/json"
|
||||
],
|
||||
"parameters":[
|
||||
]
|
||||
},
|
||||
{
|
||||
"method":"POST",
|
||||
"summary":"allows a user to reenable thrift",
|
||||
"type":"void",
|
||||
"nickname":"start_rpc_server",
|
||||
"produces":[
|
||||
"application/json"
|
||||
],
|
||||
"parameters":[
|
||||
]
|
||||
},
|
||||
{
|
||||
"method":"GET",
|
||||
"summary":"Determine if thrift is running",
|
||||
"type":"boolean",
|
||||
"nickname":"is_thrift_server_running",
|
||||
"nickname":"is_rpc_server_running",
|
||||
"produces":[
|
||||
"application/json"
|
||||
],
|
||||
@@ -2011,14 +1813,6 @@
|
||||
"allowMultiple":false,
|
||||
"type":"string",
|
||||
"paramType":"query"
|
||||
},
|
||||
{
|
||||
"name":"force",
|
||||
"description":"Enforce the source_dc option, even if it unsafe to use for rebuild",
|
||||
"required":false,
|
||||
"allowMultiple":false,
|
||||
"type":"boolean",
|
||||
"paramType":"query"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -2176,7 +1970,7 @@
|
||||
"operations":[
|
||||
{
|
||||
"method":"POST",
|
||||
"summary":"Enables/Disables tracing for the whole system.",
|
||||
"summary":"Enables/Disables tracing for the whole system. Only thrift requests can start tracing currently",
|
||||
"type":"void",
|
||||
"nickname":"set_trace_probability",
|
||||
"produces":[
|
||||
@@ -2616,254 +2410,6 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"path":"/storage_service/tablets/move",
|
||||
"operations":[
|
||||
{
|
||||
"nickname":"move_tablet",
|
||||
"method":"POST",
|
||||
"summary":"Moves a tablet replica",
|
||||
"type":"void",
|
||||
"produces":[
|
||||
"application/json"
|
||||
],
|
||||
"parameters":[
|
||||
{
|
||||
"name":"ks",
|
||||
"description":"Keyspace name",
|
||||
"required":true,
|
||||
"allowMultiple":false,
|
||||
"type":"string",
|
||||
"paramType":"query"
|
||||
},
|
||||
{
|
||||
"name":"table",
|
||||
"description":"Table name",
|
||||
"required":true,
|
||||
"allowMultiple":false,
|
||||
"type":"string",
|
||||
"paramType":"query"
|
||||
},
|
||||
{
|
||||
"name":"token",
|
||||
"description":"Token owned by the tablet to move",
|
||||
"required":true,
|
||||
"allowMultiple":false,
|
||||
"type":"integer",
|
||||
"paramType":"query"
|
||||
},
|
||||
{
|
||||
"name":"src_host",
|
||||
"description":"Source host id",
|
||||
"required":true,
|
||||
"allowMultiple":false,
|
||||
"type":"string",
|
||||
"paramType":"query"
|
||||
},
|
||||
{
|
||||
"name":"dst_host",
|
||||
"description":"Destination host id",
|
||||
"required":true,
|
||||
"allowMultiple":false,
|
||||
"type":"string",
|
||||
"paramType":"query"
|
||||
},
|
||||
{
|
||||
"name":"src_shard",
|
||||
"description":"Source shard number",
|
||||
"required":true,
|
||||
"allowMultiple":false,
|
||||
"type":"integer",
|
||||
"paramType":"query"
|
||||
},
|
||||
{
|
||||
"name":"dst_shard",
|
||||
"description":"Destination shard number",
|
||||
"required":true,
|
||||
"allowMultiple":false,
|
||||
"type":"integer",
|
||||
"paramType":"query"
|
||||
},
|
||||
{
|
||||
"name":"force",
|
||||
"description":"When set to true, replication strategy constraints can be broken (false by default)",
|
||||
"required":false,
|
||||
"allowMultiple":false,
|
||||
"type":"boolean",
|
||||
"paramType":"query"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"path":"/storage_service/tablets/add_replica",
|
||||
"operations":[
|
||||
{
|
||||
"nickname":"add_tablet_replica",
|
||||
"method":"POST",
|
||||
"summary":"Adds replica to tablet",
|
||||
"type":"void",
|
||||
"produces":[
|
||||
"application/json"
|
||||
],
|
||||
"parameters":[
|
||||
{
|
||||
"name":"ks",
|
||||
"description":"Keyspace name",
|
||||
"required":true,
|
||||
"allowMultiple":false,
|
||||
"type":"string",
|
||||
"paramType":"query"
|
||||
},
|
||||
{
|
||||
"name":"table",
|
||||
"description":"Table name",
|
||||
"required":true,
|
||||
"allowMultiple":false,
|
||||
"type":"string",
|
||||
"paramType":"query"
|
||||
},
|
||||
{
|
||||
"name":"token",
|
||||
"description":"Token owned by the tablet to add replica to",
|
||||
"required":true,
|
||||
"allowMultiple":false,
|
||||
"type":"integer",
|
||||
"paramType":"query"
|
||||
},
|
||||
{
|
||||
"name":"dst_host",
|
||||
"description":"Destination host id",
|
||||
"required":true,
|
||||
"allowMultiple":false,
|
||||
"type":"string",
|
||||
"paramType":"query"
|
||||
},
|
||||
{
|
||||
"name":"dst_shard",
|
||||
"description":"Destination shard number",
|
||||
"required":true,
|
||||
"allowMultiple":false,
|
||||
"type":"integer",
|
||||
"paramType":"query"
|
||||
},
|
||||
{
|
||||
"name":"force",
|
||||
"description":"When set to true, replication strategy constraints can be broken (false by default)",
|
||||
"required":false,
|
||||
"allowMultiple":false,
|
||||
"type":"boolean",
|
||||
"paramType":"query"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"path":"/storage_service/tablets/del_replica",
|
||||
"operations":[
|
||||
{
|
||||
"nickname":"del_tablet_replica",
|
||||
"method":"POST",
|
||||
"summary":"Deletes replica from tablet",
|
||||
"type":"void",
|
||||
"produces":[
|
||||
"application/json"
|
||||
],
|
||||
"parameters":[
|
||||
{
|
||||
"name":"ks",
|
||||
"description":"Keyspace name",
|
||||
"required":true,
|
||||
"allowMultiple":false,
|
||||
"type":"string",
|
||||
"paramType":"query"
|
||||
},
|
||||
{
|
||||
"name":"table",
|
||||
"description":"Table name",
|
||||
"required":true,
|
||||
"allowMultiple":false,
|
||||
"type":"string",
|
||||
"paramType":"query"
|
||||
},
|
||||
{
|
||||
"name":"token",
|
||||
"description":"Token owned by the tablet to delete replica from",
|
||||
"required":true,
|
||||
"allowMultiple":false,
|
||||
"type":"integer",
|
||||
"paramType":"query"
|
||||
},
|
||||
{
|
||||
"name":"host",
|
||||
"description":"Host id to remove replica from",
|
||||
"required":true,
|
||||
"allowMultiple":false,
|
||||
"type":"string",
|
||||
"paramType":"query"
|
||||
},
|
||||
{
|
||||
"name":"shard",
|
||||
"description":"Shard number to remove replica from",
|
||||
"required":true,
|
||||
"allowMultiple":false,
|
||||
"type":"integer",
|
||||
"paramType":"query"
|
||||
},
|
||||
{
|
||||
"name":"force",
|
||||
"description":"When set to true, replication strategy constraints can be broken (false by default)",
|
||||
"required":false,
|
||||
"allowMultiple":false,
|
||||
"type":"boolean",
|
||||
"paramType":"query"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"path":"/storage_service/tablets/balancing",
|
||||
"operations":[
|
||||
{
|
||||
"nickname":"tablet_balancing_enable",
|
||||
"method":"POST",
|
||||
"summary":"Controls tablet load-balancing",
|
||||
"type":"void",
|
||||
"produces":[
|
||||
"application/json"
|
||||
],
|
||||
"parameters":[
|
||||
{
|
||||
"name":"enabled",
|
||||
"description":"When set to false, tablet load balancing is disabled",
|
||||
"required":true,
|
||||
"allowMultiple":false,
|
||||
"type":"boolean",
|
||||
"paramType":"query"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"path":"/storage_service/quiesce_topology",
|
||||
"operations":[
|
||||
{
|
||||
"nickname":"quiesce_topology",
|
||||
"method":"POST",
|
||||
"summary":"Waits until there are no ongoing topology operations. Guarantees that topology operations which started before the call are finished after the call. This doesn't consider requested but not started operations. Such operations may start after the call succeeds.",
|
||||
"type":"void",
|
||||
"produces":[
|
||||
"application/json"
|
||||
],
|
||||
"parameters":[
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"path":"/storage_service/metrics/total_hints",
|
||||
"operations":[
|
||||
@@ -2965,33 +2511,6 @@
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"path":"/storage_service/raft_topology/upgrade",
|
||||
"operations":[
|
||||
{
|
||||
"method":"POST",
|
||||
"summary":"Trigger the upgrade to topology on raft.",
|
||||
"type":"void",
|
||||
"nickname":"upgrade_to_raft_topology",
|
||||
"produces":[
|
||||
"application/json"
|
||||
],
|
||||
"parameters":[
|
||||
]
|
||||
},
|
||||
{
|
||||
"method":"GET",
|
||||
"summary":"Get information about the current upgrade status of topology on raft.",
|
||||
"type":"string",
|
||||
"nickname":"raft_topology_upgrade_status",
|
||||
"produces":[
|
||||
"application/json"
|
||||
],
|
||||
"parameters":[
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"models":{
|
||||
|
||||
@@ -179,36 +179,6 @@
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"path":"/system/dump_llvm_profile",
|
||||
"operations":[
|
||||
{
|
||||
"method":"POST",
|
||||
"summary":"Dump llvm profile data (raw profile data) that can later be used for coverage reporting or PGO (no-op if the current binary is not instrumented)",
|
||||
"type":"void",
|
||||
"nickname":"dump_profile",
|
||||
"produces":[
|
||||
"application/json"
|
||||
],
|
||||
"parameters":[]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"path":"/system/highest_supported_sstable_version",
|
||||
"operations":[
|
||||
{
|
||||
"method":"GET",
|
||||
"summary":"Get highest supported sstable version",
|
||||
"type":"string",
|
||||
"nickname":"get_highest_supported_sstable_version",
|
||||
"produces":[
|
||||
"application/json"
|
||||
],
|
||||
"parameters":[]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -115,7 +115,7 @@
|
||||
"parameters":[
|
||||
{
|
||||
"name":"task_id",
|
||||
"description":"The uuid of a task to abort; if the task is not abortable, 403 status code is returned",
|
||||
"description":"The uuid of a task to abort",
|
||||
"required":true,
|
||||
"allowMultiple":false,
|
||||
"type":"string",
|
||||
@@ -144,14 +144,6 @@
|
||||
"allowMultiple":false,
|
||||
"type":"string",
|
||||
"paramType":"path"
|
||||
},
|
||||
{
|
||||
"name":"timeout",
|
||||
"description":"Timeout for waiting; if times out, 408 status code is returned",
|
||||
"required":false,
|
||||
"allowMultiple":false,
|
||||
"type":"long",
|
||||
"paramType":"query"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -205,60 +197,11 @@
|
||||
"paramType":"query"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"method":"GET",
|
||||
"summary":"Get current ttl value",
|
||||
"type":"long",
|
||||
"nickname":"get_ttl",
|
||||
"produces":[
|
||||
"application/json"
|
||||
],
|
||||
"parameters":[
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"path":"/task_manager/drain/{module}",
|
||||
"operations":[
|
||||
{
|
||||
"method":"POST",
|
||||
"summary":"Drain finished local tasks",
|
||||
"type":"void",
|
||||
"nickname":"drain_tasks",
|
||||
"produces":[
|
||||
"application/json"
|
||||
],
|
||||
"parameters":[
|
||||
{
|
||||
"name":"module",
|
||||
"description":"The module to drain",
|
||||
"required":true,
|
||||
"allowMultiple":false,
|
||||
"type":"string",
|
||||
"paramType":"path"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"models":{
|
||||
"task_identity":{
|
||||
"id": "task_identity",
|
||||
"description":"Id and node of a task",
|
||||
"properties":{
|
||||
"task_id":{
|
||||
"type":"string",
|
||||
"description":"The uuid of a task"
|
||||
},
|
||||
"node":{
|
||||
"type":"string",
|
||||
"description":"Address of a server on which a task is created"
|
||||
}
|
||||
}
|
||||
},
|
||||
"task_stats" :{
|
||||
"id": "task_stats",
|
||||
"description":"A task statistics object",
|
||||
@@ -281,14 +224,6 @@
|
||||
"type":"string",
|
||||
"description":"The description of the task"
|
||||
},
|
||||
"kind":{
|
||||
"type":"string",
|
||||
"enum":[
|
||||
"node",
|
||||
"cluster"
|
||||
],
|
||||
"description":"The kind of a task"
|
||||
},
|
||||
"scope":{
|
||||
"type":"string",
|
||||
"description":"The scope of the task"
|
||||
@@ -323,14 +258,6 @@
|
||||
"type":"string",
|
||||
"description":"The description of the task"
|
||||
},
|
||||
"kind":{
|
||||
"type":"string",
|
||||
"enum":[
|
||||
"node",
|
||||
"cluster"
|
||||
],
|
||||
"description":"The kind of a task"
|
||||
},
|
||||
"scope":{
|
||||
"type":"string",
|
||||
"description":"The scope of the task"
|
||||
@@ -400,9 +327,9 @@
|
||||
"children_ids":{
|
||||
"type":"array",
|
||||
"items":{
|
||||
"type":"task_identity"
|
||||
"type":"string"
|
||||
},
|
||||
"description":"Task identities of children of this task"
|
||||
"description":"Task IDs of children of this task"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,230 +0,0 @@
|
||||
{
|
||||
"apiVersion":"0.0.1",
|
||||
"swaggerVersion":"1.2",
|
||||
"basePath":"{{Protocol}}://{{Host}}",
|
||||
"resourcePath":"/tasks",
|
||||
"produces":[
|
||||
"application/json"
|
||||
],
|
||||
"apis":[
|
||||
{
|
||||
"path":"/tasks/compaction/keyspace_compaction/{keyspace}",
|
||||
"operations":[
|
||||
{
|
||||
"method":"POST",
|
||||
"summary":"Forces major compaction of a single keyspace asynchronously, returns uuid which can be used to check progress with task manager",
|
||||
"type":"string",
|
||||
"nickname":"force_keyspace_compaction_async",
|
||||
"produces":[
|
||||
"application/json"
|
||||
],
|
||||
"parameters":[
|
||||
{
|
||||
"name":"keyspace",
|
||||
"description":"The keyspace to query about",
|
||||
"required":true,
|
||||
"allowMultiple":false,
|
||||
"type":"string",
|
||||
"paramType":"path"
|
||||
},
|
||||
{
|
||||
"name":"cf",
|
||||
"description":"Comma-separated table (column family) names",
|
||||
"required":false,
|
||||
"allowMultiple":false,
|
||||
"type":"string",
|
||||
"paramType":"query"
|
||||
},
|
||||
{
|
||||
"name":"flush_memtables",
|
||||
"description":"Controls flushing of memtables before compaction (true by default). Set to \"false\" to skip automatic flushing of memtables before compaction, e.g. when tables were flushed explicitly before invoking the compaction api.",
|
||||
"required":false,
|
||||
"allowMultiple":false,
|
||||
"type":"boolean",
|
||||
"paramType":"query"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"path":"/tasks/compaction/keyspace_cleanup/{keyspace}",
|
||||
"operations":[
|
||||
{
|
||||
"method":"POST",
|
||||
"summary":"Trigger a cleanup of keys on a single keyspace asynchronously, returns uuid which can be used to check progress with task manager",
|
||||
"type": "string",
|
||||
"nickname":"force_keyspace_cleanup_async",
|
||||
"produces":[
|
||||
"application/json"
|
||||
],
|
||||
"parameters":[
|
||||
{
|
||||
"name":"keyspace",
|
||||
"description":"The keyspace to query about",
|
||||
"required":true,
|
||||
"allowMultiple":false,
|
||||
"type":"string",
|
||||
"paramType":"path"
|
||||
},
|
||||
{
|
||||
"name":"cf",
|
||||
"description":"Comma-separated table (column family) names",
|
||||
"required":false,
|
||||
"allowMultiple":false,
|
||||
"type":"string",
|
||||
"paramType":"query"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"path":"/tasks/compaction/keyspace_offstrategy_compaction/{keyspace}",
|
||||
"operations":[
|
||||
{
|
||||
"method":"POST",
|
||||
"summary":"Perform offstrategy compaction, if needed, in a single keyspace asynchronously, returns uuid which can be used to check progress with task manager",
|
||||
"type":"string",
|
||||
"nickname":"perform_keyspace_offstrategy_compaction_async",
|
||||
"produces":[
|
||||
"application/json"
|
||||
],
|
||||
"parameters":[
|
||||
{
|
||||
"name":"keyspace",
|
||||
"description":"The keyspace to operate on",
|
||||
"required":true,
|
||||
"allowMultiple":false,
|
||||
"type":"string",
|
||||
"paramType":"path"
|
||||
},
|
||||
{
|
||||
"name":"cf",
|
||||
"description":"Comma-separated table (column family) names",
|
||||
"required":false,
|
||||
"allowMultiple":false,
|
||||
"type":"string",
|
||||
"paramType":"query"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"path":"/tasks/compaction/keyspace_scrub/{keyspace}",
|
||||
"operations":[
|
||||
{
|
||||
"method":"GET",
|
||||
"summary":"Scrub (deserialize + reserialize at the latest version, resolving corruptions if any) the given keyspace asynchronously, returns uuid which can be used to check progress with task manager. If columnFamilies array is empty, all CFs are scrubbed. Scrubbed CFs will be snapshotted first, if disableSnapshot is false. Scrub has the following modes: Abort (default) - abort scrub if corruption is detected; Skip (same as `skip_corrupted=true`) skip over corrupt data, omitting them from the output; Segregate - segregate data into multiple sstables if needed, such that each sstable contains data with valid order; Validate - read (no rewrite) and validate data, logging any problems found.",
|
||||
"type": "string",
|
||||
"nickname":"scrub_async",
|
||||
"produces":[
|
||||
"application/json"
|
||||
],
|
||||
"parameters":[
|
||||
{
|
||||
"name":"disable_snapshot",
|
||||
"description":"When set to true, disable snapshot",
|
||||
"required":false,
|
||||
"allowMultiple":false,
|
||||
"type":"boolean",
|
||||
"paramType":"query"
|
||||
},
|
||||
{
|
||||
"name":"skip_corrupted",
|
||||
"description":"When set to true, skip corrupted",
|
||||
"required":false,
|
||||
"allowMultiple":false,
|
||||
"type":"boolean",
|
||||
"paramType":"query"
|
||||
},
|
||||
{
|
||||
"name":"scrub_mode",
|
||||
"description":"How to handle corrupt data (overrides 'skip_corrupted'); ",
|
||||
"required":false,
|
||||
"allowMultiple":false,
|
||||
"type":"string",
|
||||
"enum":[
|
||||
"ABORT",
|
||||
"SKIP",
|
||||
"SEGREGATE",
|
||||
"VALIDATE"
|
||||
],
|
||||
"paramType":"query"
|
||||
},
|
||||
{
|
||||
"name":"quarantine_mode",
|
||||
"description":"Controls whether to scrub quarantined sstables (default INCLUDE)",
|
||||
"required":false,
|
||||
"allowMultiple":false,
|
||||
"type":"string",
|
||||
"enum":[
|
||||
"INCLUDE",
|
||||
"EXCLUDE",
|
||||
"ONLY"
|
||||
],
|
||||
"paramType":"query"
|
||||
},
|
||||
{
|
||||
"name":"keyspace",
|
||||
"description":"The keyspace to query about",
|
||||
"required":true,
|
||||
"allowMultiple":false,
|
||||
"type":"string",
|
||||
"paramType":"path"
|
||||
},
|
||||
{
|
||||
"name":"cf",
|
||||
"description":"Comma-separated table (column family) names",
|
||||
"required":false,
|
||||
"allowMultiple":false,
|
||||
"type":"string",
|
||||
"paramType":"query"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"path":"/tasks/compaction/keyspace_upgrade_sstables/{keyspace}",
|
||||
"operations":[
|
||||
{
|
||||
"method":"GET",
|
||||
"summary":"Rewrite all sstables to the latest version. Unlike scrub, it doesn't skip bad rows and do not snapshot sstables first asynchronously, returns uuid which can be used to check progress with task manager.",
|
||||
"type": "string",
|
||||
"nickname":"upgrade_sstables_async",
|
||||
"produces":[
|
||||
"application/json"
|
||||
],
|
||||
"parameters":[
|
||||
{
|
||||
"name":"keyspace",
|
||||
"description":"The keyspace",
|
||||
"required":true,
|
||||
"allowMultiple":false,
|
||||
"type":"string",
|
||||
"paramType":"path"
|
||||
},
|
||||
{
|
||||
"name":"exclude_current_version",
|
||||
"description":"When set to true exclude current version",
|
||||
"required":false,
|
||||
"allowMultiple":false,
|
||||
"type":"boolean",
|
||||
"paramType":"query"
|
||||
},
|
||||
{
|
||||
"name":"cf",
|
||||
"description":"Comma-separated table (column family) names",
|
||||
"required":false,
|
||||
"allowMultiple":false,
|
||||
"type":"string",
|
||||
"paramType":"query"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -75,7 +75,7 @@
|
||||
"items":{
|
||||
"type":"double"
|
||||
},
|
||||
"description":"One, five and fifteen minutes rates"
|
||||
"description":"One, five and fifteen mintues rates"
|
||||
},
|
||||
"mean_rate": {
|
||||
"type":"double",
|
||||
|
||||
118
api/api.cc
118
api/api.cc
@@ -10,9 +10,7 @@
|
||||
#include <seastar/http/file_handler.hh>
|
||||
#include <seastar/http/transformers.hh>
|
||||
#include <seastar/http/api_docs.hh>
|
||||
#include "cql_server_test.hh"
|
||||
#include "storage_service.hh"
|
||||
#include "token_metadata.hh"
|
||||
#include "commitlog.hh"
|
||||
#include "gossiper.hh"
|
||||
#include "failure_detector.hh"
|
||||
@@ -33,8 +31,6 @@
|
||||
#include "api/config.hh"
|
||||
#include "task_manager.hh"
|
||||
#include "task_manager_test.hh"
|
||||
#include "tasks.hh"
|
||||
#include "raft.hh"
|
||||
|
||||
logging::logger apilog("api");
|
||||
|
||||
@@ -69,13 +65,6 @@ future<> set_server_init(http_context& ctx) {
|
||||
"The system related API");
|
||||
rb02->add_definitions_file(r, "metrics");
|
||||
set_system(ctx, r);
|
||||
rb->register_function(r, "error_injection",
|
||||
"The error injection API");
|
||||
set_error_injection(ctx, r);
|
||||
rb->register_function(r, "storage_proxy",
|
||||
"The storage proxy API");
|
||||
rb->register_function(r, "storage_service",
|
||||
"The storage service API");
|
||||
});
|
||||
}
|
||||
|
||||
@@ -86,10 +75,6 @@ future<> set_server_config(http_context& ctx, const db::config& cfg) {
|
||||
});
|
||||
}
|
||||
|
||||
future<> unset_server_config(http_context& ctx) {
|
||||
return ctx.http_server.set_routes([&ctx] (routes& r) { unset_config(ctx, r); });
|
||||
}
|
||||
|
||||
static future<> register_api(http_context& ctx, const sstring& api_name,
|
||||
const sstring api_desc,
|
||||
std::function<void(http_context& ctx, routes& r)> f) {
|
||||
@@ -109,16 +94,16 @@ future<> unset_transport_controller(http_context& ctx) {
|
||||
return ctx.http_server.set_routes([&ctx] (routes& r) { unset_transport_controller(ctx, r); });
|
||||
}
|
||||
|
||||
future<> set_thrift_controller(http_context& ctx) {
|
||||
return ctx.http_server.set_routes([&ctx] (routes& r) { set_thrift_controller(ctx, r); });
|
||||
future<> set_rpc_controller(http_context& ctx, thrift_controller& ctl) {
|
||||
return ctx.http_server.set_routes([&ctx, &ctl] (routes& r) { set_rpc_controller(ctx, r, ctl); });
|
||||
}
|
||||
|
||||
future<> unset_thrift_controller(http_context& ctx) {
|
||||
return ctx.http_server.set_routes([&ctx] (routes& r) { unset_thrift_controller(ctx, r); });
|
||||
future<> unset_rpc_controller(http_context& ctx) {
|
||||
return ctx.http_server.set_routes([&ctx] (routes& r) { unset_rpc_controller(ctx, r); });
|
||||
}
|
||||
|
||||
future<> set_server_storage_service(http_context& ctx, sharded<service::storage_service>& ss, service::raft_group0_client& group0_client) {
|
||||
return ctx.http_server.set_routes([&ctx, &ss, &group0_client] (routes& r) {
|
||||
return register_api(ctx, "storage_service", "The storage service API", [&ss, &group0_client] (http_context& ctx, routes& r) {
|
||||
set_storage_service(ctx, r, ss, group0_client);
|
||||
});
|
||||
}
|
||||
@@ -127,14 +112,6 @@ future<> unset_server_storage_service(http_context& ctx) {
|
||||
return ctx.http_server.set_routes([&ctx] (routes& r) { unset_storage_service(ctx, r); });
|
||||
}
|
||||
|
||||
future<> set_load_meter(http_context& ctx, service::load_meter& lm) {
|
||||
return ctx.http_server.set_routes([&ctx, &lm] (routes& r) { set_load_meter(ctx, r, lm); });
|
||||
}
|
||||
|
||||
future<> unset_load_meter(http_context& ctx) {
|
||||
return ctx.http_server.set_routes([&ctx] (routes& r) { unset_load_meter(ctx, r); });
|
||||
}
|
||||
|
||||
future<> set_server_sstables_loader(http_context& ctx, sharded<sstables_loader>& sst_loader) {
|
||||
return ctx.http_server.set_routes([&ctx, &sst_loader] (routes& r) { set_sstables_loader(ctx, r, sst_loader); });
|
||||
}
|
||||
@@ -178,14 +155,6 @@ future<> unset_server_snapshot(http_context& ctx) {
|
||||
return ctx.http_server.set_routes([&ctx] (routes& r) { unset_snapshot(ctx, r); });
|
||||
}
|
||||
|
||||
future<> set_server_token_metadata(http_context& ctx, sharded<locator::shared_token_metadata>& tm) {
|
||||
return ctx.http_server.set_routes([&ctx, &tm] (routes& r) { set_token_metadata(ctx, r, tm); });
|
||||
}
|
||||
|
||||
future<> unset_server_token_metadata(http_context& ctx) {
|
||||
return ctx.http_server.set_routes([&ctx] (routes& r) { unset_token_metadata(ctx, r); });
|
||||
}
|
||||
|
||||
future<> set_server_snitch(http_context& ctx, sharded<locator::snitch_ptr>& snitch) {
|
||||
return register_api(ctx, "endpoint_snitch_info", "The endpoint snitch info API", [&snitch] (http_context& ctx, routes& r) {
|
||||
set_endpoint_snitch(ctx, r, snitch);
|
||||
@@ -197,31 +166,20 @@ future<> unset_server_snitch(http_context& ctx) {
|
||||
}
|
||||
|
||||
future<> set_server_gossip(http_context& ctx, sharded<gms::gossiper>& g) {
|
||||
co_await register_api(ctx, "gossiper",
|
||||
return register_api(ctx, "gossiper",
|
||||
"The gossiper API", [&g] (http_context& ctx, routes& r) {
|
||||
set_gossiper(ctx, r, g.local());
|
||||
});
|
||||
co_await register_api(ctx, "failure_detector",
|
||||
"The failure detector API", [&g] (http_context& ctx, routes& r) {
|
||||
set_failure_detector(ctx, r, g.local());
|
||||
});
|
||||
}
|
||||
|
||||
future<> unset_server_gossip(http_context& ctx) {
|
||||
return ctx.http_server.set_routes([&ctx] (routes& r) {
|
||||
unset_gossiper(ctx, r);
|
||||
unset_failure_detector(ctx, r);
|
||||
});
|
||||
}
|
||||
|
||||
future<> set_server_column_family(http_context& ctx, sharded<db::system_keyspace>& sys_ks) {
|
||||
future<> set_server_load_sstable(http_context& ctx, sharded<db::system_keyspace>& sys_ks) {
|
||||
return register_api(ctx, "column_family",
|
||||
"The column family API", [&sys_ks] (http_context& ctx, routes& r) {
|
||||
set_column_family(ctx, r, sys_ks);
|
||||
});
|
||||
}
|
||||
|
||||
future<> unset_server_column_family(http_context& ctx) {
|
||||
future<> unset_server_load_sstable(http_context& ctx) {
|
||||
return ctx.http_server.set_routes([&ctx] (routes& r) { unset_column_family(ctx, r); });
|
||||
}
|
||||
|
||||
@@ -236,7 +194,10 @@ future<> unset_server_messaging_service(http_context& ctx) {
|
||||
}
|
||||
|
||||
future<> set_server_storage_proxy(http_context& ctx, sharded<service::storage_proxy>& proxy) {
|
||||
return ctx.http_server.set_routes([&ctx, &proxy] (routes& r) { set_storage_proxy(ctx, r, proxy); });
|
||||
return register_api(ctx, "storage_proxy",
|
||||
"The storage proxy API", [&proxy] (http_context& ctx, routes& r) {
|
||||
set_storage_proxy(ctx, r, proxy);
|
||||
});
|
||||
}
|
||||
|
||||
future<> unset_server_storage_proxy(http_context& ctx) {
|
||||
@@ -259,10 +220,6 @@ future<> set_server_cache(http_context& ctx) {
|
||||
"The cache service API", set_cache_service);
|
||||
}
|
||||
|
||||
future<> unset_server_cache(http_context& ctx) {
|
||||
return ctx.http_server.set_routes([&ctx] (routes& r) { unset_cache_service(ctx, r); });
|
||||
}
|
||||
|
||||
future<> set_hinted_handoff(http_context& ctx, sharded<service::storage_proxy>& proxy) {
|
||||
return register_api(ctx, "hinted_handoff",
|
||||
"The hinted handoff API", [&proxy] (http_context& ctx, routes& r) {
|
||||
@@ -274,6 +231,16 @@ future<> unset_hinted_handoff(http_context& ctx) {
|
||||
return ctx.http_server.set_routes([&ctx] (routes& r) { unset_hinted_handoff(ctx, r); });
|
||||
}
|
||||
|
||||
future<> set_server_gossip_settle(http_context& ctx, sharded<gms::gossiper>& g) {
|
||||
auto rb = std::make_shared < api_registry_builder > (ctx.api_doc);
|
||||
|
||||
return ctx.http_server.set_routes([rb, &ctx, &g](routes& r) {
|
||||
rb->register_function(r, "failure_detector",
|
||||
"The failure detector API");
|
||||
set_failure_detector(ctx, r, g.local());
|
||||
});
|
||||
}
|
||||
|
||||
future<> set_server_compaction_manager(http_context& ctx) {
|
||||
auto rb = std::make_shared < api_registry_builder > (ctx.api_doc);
|
||||
|
||||
@@ -297,6 +264,9 @@ future<> set_server_done(http_context& ctx) {
|
||||
rb->register_function(r, "collectd",
|
||||
"The collectd API");
|
||||
set_collectd(ctx, r);
|
||||
rb->register_function(r, "error_injection",
|
||||
"The error injection API");
|
||||
set_error_injection(ctx, r);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -330,44 +300,8 @@ future<> unset_server_task_manager_test(http_context& ctx) {
|
||||
return ctx.http_server.set_routes([&ctx] (routes& r) { unset_task_manager_test(ctx, r); });
|
||||
}
|
||||
|
||||
future<> set_server_cql_server_test(http_context& ctx, cql_transport::controller& ctl) {
|
||||
return register_api(ctx, "cql_server_test", "The CQL server test API", [&ctl] (http_context& ctx, routes& r) {
|
||||
set_cql_server_test(ctx, r, ctl);
|
||||
});
|
||||
}
|
||||
|
||||
future<> unset_server_cql_server_test(http_context& ctx) {
|
||||
return ctx.http_server.set_routes([&ctx] (routes& r) { unset_cql_server_test(ctx, r); });
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
future<> set_server_tasks_compaction_module(http_context& ctx, sharded<service::storage_service>& ss, sharded<db::snapshot_ctl>& snap_ctl) {
|
||||
auto rb = std::make_shared < api_registry_builder > (ctx.api_doc);
|
||||
|
||||
return ctx.http_server.set_routes([rb, &ctx, &ss, &snap_ctl](routes& r) {
|
||||
rb->register_function(r, "tasks",
|
||||
"The tasks API");
|
||||
set_tasks_compaction_module(ctx, r, ss, snap_ctl);
|
||||
});
|
||||
}
|
||||
|
||||
future<> unset_server_tasks_compaction_module(http_context& ctx) {
|
||||
return ctx.http_server.set_routes([&ctx] (routes& r) { unset_tasks_compaction_module(ctx, r); });
|
||||
}
|
||||
|
||||
future<> set_server_raft(http_context& ctx, sharded<service::raft_group_registry>& raft_gr) {
|
||||
auto rb = std::make_shared<api_registry_builder>(ctx.api_doc);
|
||||
return ctx.http_server.set_routes([rb, &ctx, &raft_gr] (routes& r) {
|
||||
rb->register_function(r, "raft", "The Raft API");
|
||||
set_raft(ctx, r, raft_gr);
|
||||
});
|
||||
}
|
||||
|
||||
future<> unset_server_raft(http_context& ctx) {
|
||||
return ctx.http_server.set_routes([&ctx] (routes& r) { unset_raft(ctx, r); });
|
||||
}
|
||||
|
||||
void req_params::process(const request& req) {
|
||||
// Process mandatory parameters
|
||||
for (auto& [name, ent] : params) {
|
||||
@@ -375,7 +309,7 @@ void req_params::process(const request& req) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
ent.value = req.get_path_param(name);
|
||||
ent.value = req.param[name];
|
||||
} catch (std::out_of_range&) {
|
||||
throw httpd::bad_param_exception(fmt::format("Mandatory parameter '{}' was not provided", name));
|
||||
}
|
||||
|
||||
28
api/api.hh
28
api/api.hh
@@ -14,11 +14,11 @@
|
||||
#include <boost/algorithm/string/split.hpp>
|
||||
#include <boost/algorithm/string/classification.hpp>
|
||||
#include <boost/units/detail/utility.hpp>
|
||||
#include "api/api_init.hh"
|
||||
#include "api/api-doc/utils.json.hh"
|
||||
#include "utils/histogram.hh"
|
||||
#include "utils/estimated_histogram.hh"
|
||||
#include <seastar/http/exception.hh>
|
||||
#include "api_init.hh"
|
||||
#include "seastarx.hh"
|
||||
|
||||
namespace api {
|
||||
@@ -26,9 +26,7 @@ namespace api {
|
||||
template<class T>
|
||||
std::vector<sstring> container_to_vec(const T& container) {
|
||||
std::vector<sstring> res;
|
||||
res.reserve(std::size(container));
|
||||
|
||||
for (const auto& i : container) {
|
||||
for (auto i : container) {
|
||||
res.push_back(fmt::to_string(i));
|
||||
}
|
||||
return res;
|
||||
@@ -37,31 +35,27 @@ std::vector<sstring> container_to_vec(const T& container) {
|
||||
template<class T>
|
||||
std::vector<T> map_to_key_value(const std::map<sstring, sstring>& map) {
|
||||
std::vector<T> res;
|
||||
res.reserve(map.size());
|
||||
|
||||
for (const auto& [key, value] : map) {
|
||||
for (auto i : map) {
|
||||
res.push_back(T());
|
||||
res.back().key = key;
|
||||
res.back().value = value;
|
||||
res.back().key = i.first;
|
||||
res.back().value = i.second;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
template<class T, class MAP>
|
||||
std::vector<T>& map_to_key_value(const MAP& map, std::vector<T>& res) {
|
||||
res.reserve(res.size() + std::size(map));
|
||||
|
||||
for (const auto& [key, value] : map) {
|
||||
for (auto i : map) {
|
||||
T val;
|
||||
val.key = fmt::to_string(key);
|
||||
val.value = fmt::to_string(value);
|
||||
val.key = fmt::to_string(i.first);
|
||||
val.value = fmt::to_string(i.second);
|
||||
res.push_back(val);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
template <typename T, typename S = T>
|
||||
T map_sum(T&& dest, const S& src) {
|
||||
for (const auto& i : src) {
|
||||
for (auto i : src) {
|
||||
dest[i.first] += i.second;
|
||||
}
|
||||
return std::move(dest);
|
||||
@@ -70,8 +64,6 @@ T map_sum(T&& dest, const S& src) {
|
||||
template <typename MAP>
|
||||
std::vector<sstring> map_keys(const MAP& map) {
|
||||
std::vector<sstring> res;
|
||||
res.reserve(std::size(map));
|
||||
|
||||
for (const auto& i : map) {
|
||||
res.push_back(fmt::to_string(i.first));
|
||||
}
|
||||
@@ -246,7 +238,7 @@ public:
|
||||
value = T{boost::lexical_cast<Base>(param)};
|
||||
}
|
||||
} catch (boost::bad_lexical_cast&) {
|
||||
throw httpd::bad_param_exception(fmt::format("{} ({}): type error - should be {}", name, param, boost::units::detail::demangle(typeid(Base).name())));
|
||||
throw httpd::bad_param_exception(format("{} ({}): type error - should be {}", name, param, boost::units::detail::demangle(typeid(Base).name())));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,6 @@ class load_meter;
|
||||
class storage_proxy;
|
||||
class storage_service;
|
||||
class raft_group0_client;
|
||||
class raft_group_registry;
|
||||
|
||||
} // namespace service
|
||||
|
||||
@@ -33,10 +32,6 @@ namespace streaming {
|
||||
class stream_manager;
|
||||
}
|
||||
|
||||
namespace gms {
|
||||
class inet_address;
|
||||
}
|
||||
|
||||
namespace locator {
|
||||
|
||||
class token_metadata;
|
||||
@@ -46,6 +41,7 @@ class snitch_ptr;
|
||||
} // namespace locator
|
||||
|
||||
namespace cql_transport { class controller; }
|
||||
class thrift_controller;
|
||||
namespace db {
|
||||
class snapshot_ctl;
|
||||
class config;
|
||||
@@ -76,16 +72,19 @@ struct http_context {
|
||||
sstring api_doc;
|
||||
httpd::http_server_control http_server;
|
||||
distributed<replica::database>& db;
|
||||
service::load_meter& lmeter;
|
||||
const sharded<locator::shared_token_metadata>& shared_token_metadata;
|
||||
|
||||
http_context(distributed<replica::database>& _db)
|
||||
: db(_db)
|
||||
{
|
||||
http_context(distributed<replica::database>& _db,
|
||||
service::load_meter& _lm, const sharded<locator::shared_token_metadata>& _stm)
|
||||
: db(_db), lmeter(_lm), shared_token_metadata(_stm) {
|
||||
}
|
||||
|
||||
const locator::token_metadata& get_token_metadata();
|
||||
};
|
||||
|
||||
future<> set_server_init(http_context& ctx);
|
||||
future<> set_server_config(http_context& ctx, const db::config& cfg);
|
||||
future<> unset_server_config(http_context& ctx);
|
||||
future<> set_server_snitch(http_context& ctx, sharded<locator::snitch_ptr>& snitch);
|
||||
future<> unset_server_snitch(http_context& ctx);
|
||||
future<> set_server_storage_service(http_context& ctx, sharded<service::storage_service>& ss, service::raft_group0_client&);
|
||||
@@ -98,18 +97,15 @@ future<> set_server_repair(http_context& ctx, sharded<repair_service>& repair);
|
||||
future<> unset_server_repair(http_context& ctx);
|
||||
future<> set_transport_controller(http_context& ctx, cql_transport::controller& ctl);
|
||||
future<> unset_transport_controller(http_context& ctx);
|
||||
future<> set_thrift_controller(http_context& ctx);
|
||||
future<> unset_thrift_controller(http_context& ctx);
|
||||
future<> set_rpc_controller(http_context& ctx, thrift_controller& ctl);
|
||||
future<> unset_rpc_controller(http_context& ctx);
|
||||
future<> set_server_authorization_cache(http_context& ctx, sharded<auth::service> &auth_service);
|
||||
future<> unset_server_authorization_cache(http_context& ctx);
|
||||
future<> set_server_snapshot(http_context& ctx, sharded<db::snapshot_ctl>& snap_ctl);
|
||||
future<> unset_server_snapshot(http_context& ctx);
|
||||
future<> set_server_token_metadata(http_context& ctx, sharded<locator::shared_token_metadata>& tm);
|
||||
future<> unset_server_token_metadata(http_context& ctx);
|
||||
future<> set_server_gossip(http_context& ctx, sharded<gms::gossiper>& g);
|
||||
future<> unset_server_gossip(http_context& ctx);
|
||||
future<> set_server_column_family(http_context& ctx, sharded<db::system_keyspace>& sys_ks);
|
||||
future<> unset_server_column_family(http_context& ctx);
|
||||
future<> set_server_load_sstable(http_context& ctx, sharded<db::system_keyspace>& sys_ks);
|
||||
future<> unset_server_load_sstable(http_context& ctx);
|
||||
future<> set_server_messaging_service(http_context& ctx, sharded<netw::messaging_service>& ms);
|
||||
future<> unset_server_messaging_service(http_context& ctx);
|
||||
future<> set_server_storage_proxy(http_context& ctx, sharded<service::storage_proxy>& proxy);
|
||||
@@ -118,21 +114,13 @@ future<> set_server_stream_manager(http_context& ctx, sharded<streaming::stream_
|
||||
future<> unset_server_stream_manager(http_context& ctx);
|
||||
future<> set_hinted_handoff(http_context& ctx, sharded<service::storage_proxy>& p);
|
||||
future<> unset_hinted_handoff(http_context& ctx);
|
||||
future<> set_server_gossip_settle(http_context& ctx, sharded<gms::gossiper>& g);
|
||||
future<> set_server_cache(http_context& ctx);
|
||||
future<> unset_server_cache(http_context& ctx);
|
||||
future<> set_server_compaction_manager(http_context& ctx);
|
||||
future<> set_server_done(http_context& ctx);
|
||||
future<> set_server_task_manager(http_context& ctx, sharded<tasks::task_manager>& tm, lw_shared_ptr<db::config> cfg);
|
||||
future<> unset_server_task_manager(http_context& ctx);
|
||||
future<> set_server_task_manager_test(http_context& ctx, sharded<tasks::task_manager>& tm);
|
||||
future<> unset_server_task_manager_test(http_context& ctx);
|
||||
future<> set_server_tasks_compaction_module(http_context& ctx, sharded<service::storage_service>& ss, sharded<db::snapshot_ctl>& snap_ctl);
|
||||
future<> unset_server_tasks_compaction_module(http_context& ctx);
|
||||
future<> set_server_raft(http_context&, sharded<service::raft_group_registry>&);
|
||||
future<> unset_server_raft(http_context&);
|
||||
future<> set_load_meter(http_context& ctx, service::load_meter& lm);
|
||||
future<> unset_load_meter(http_context& ctx);
|
||||
future<> set_server_cql_server_test(http_context& ctx, cql_transport::controller& ctl);
|
||||
future<> unset_server_cql_server_test(http_context& ctx);
|
||||
|
||||
}
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
#include "api/api-doc/authorization_cache.json.hh"
|
||||
|
||||
#include "api/authorization_cache.hh"
|
||||
#include "api/api.hh"
|
||||
#include "auth/common.hh"
|
||||
#include "auth/service.hh"
|
||||
|
||||
namespace api {
|
||||
|
||||
@@ -8,20 +8,11 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <seastar/core/sharded.hh>
|
||||
|
||||
namespace seastar::httpd {
|
||||
class routes;
|
||||
}
|
||||
|
||||
namespace auth {
|
||||
class service;
|
||||
}
|
||||
#include "api.hh"
|
||||
|
||||
namespace api {
|
||||
|
||||
struct http_context;
|
||||
void set_authorization_cache(http_context& ctx, seastar::httpd::routes& r, seastar::sharded<auth::service> &auth_service);
|
||||
void unset_authorization_cache(http_context& ctx, seastar::httpd::routes& r);
|
||||
void set_authorization_cache(http_context& ctx, httpd::routes& r, sharded<auth::service> &auth_service);
|
||||
void unset_authorization_cache(http_context& ctx, httpd::routes& r);
|
||||
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
*/
|
||||
|
||||
#include "cache_service.hh"
|
||||
#include "api/api.hh"
|
||||
#include "api/api-doc/cache_service.json.hh"
|
||||
#include "column_family.hh"
|
||||
|
||||
@@ -196,9 +195,9 @@ void set_cache_service(http_context& ctx, routes& r) {
|
||||
return make_ready_future<json::json_return_type>(0);
|
||||
});
|
||||
|
||||
cs::get_row_capacity.set(r, [] (std::unique_ptr<http::request> req) {
|
||||
return seastar::map_reduce(smp::all_cpus(), [] (int cpu) {
|
||||
return make_ready_future<uint64_t>(memory::stats().total_memory());
|
||||
cs::get_row_capacity.set(r, [&ctx] (std::unique_ptr<http::request> req) {
|
||||
return ctx.db.map_reduce0([](replica::database& db) -> uint64_t {
|
||||
return db.row_cache_tracker().region().occupancy().used_space();
|
||||
}, uint64_t(0), std::plus<uint64_t>()).then([](const int64_t& res) {
|
||||
return make_ready_future<json::json_return_type>(res);
|
||||
});
|
||||
@@ -241,9 +240,9 @@ void set_cache_service(http_context& ctx, routes& r) {
|
||||
|
||||
cs::get_row_size.set(r, [&ctx] (std::unique_ptr<http::request> req) {
|
||||
// In origin row size is the weighted size.
|
||||
// We currently do not support weights, so we use raw size in bytes instead
|
||||
// We currently do not support weights, so we use num entries instead
|
||||
return ctx.db.map_reduce0([](replica::database& db) -> uint64_t {
|
||||
return db.row_cache_tracker().region().occupancy().used_space();
|
||||
return db.row_cache_tracker().partitions();
|
||||
}, uint64_t(0), std::plus<uint64_t>()).then([](const int64_t& res) {
|
||||
return make_ready_future<json::json_return_type>(res);
|
||||
});
|
||||
@@ -320,50 +319,5 @@ void set_cache_service(http_context& ctx, routes& r) {
|
||||
});
|
||||
}
|
||||
|
||||
void unset_cache_service(http_context& ctx, routes& r) {
|
||||
cs::get_row_cache_save_period_in_seconds.unset(r);
|
||||
cs::set_row_cache_save_period_in_seconds.unset(r);
|
||||
cs::get_key_cache_save_period_in_seconds.unset(r);
|
||||
cs::set_key_cache_save_period_in_seconds.unset(r);
|
||||
cs::get_counter_cache_save_period_in_seconds.unset(r);
|
||||
cs::set_counter_cache_save_period_in_seconds.unset(r);
|
||||
cs::get_row_cache_keys_to_save.unset(r);
|
||||
cs::set_row_cache_keys_to_save.unset(r);
|
||||
cs::get_key_cache_keys_to_save.unset(r);
|
||||
cs::set_key_cache_keys_to_save.unset(r);
|
||||
cs::get_counter_cache_keys_to_save.unset(r);
|
||||
cs::set_counter_cache_keys_to_save.unset(r);
|
||||
cs::invalidate_key_cache.unset(r);
|
||||
cs::invalidate_counter_cache.unset(r);
|
||||
cs::set_row_cache_capacity_in_mb.unset(r);
|
||||
cs::set_key_cache_capacity_in_mb.unset(r);
|
||||
cs::set_counter_cache_capacity_in_mb.unset(r);
|
||||
cs::save_caches.unset(r);
|
||||
cs::get_key_capacity.unset(r);
|
||||
cs::get_key_hits.unset(r);
|
||||
cs::get_key_requests.unset(r);
|
||||
cs::get_key_hit_rate.unset(r);
|
||||
cs::get_key_hits_moving_avrage.unset(r);
|
||||
cs::get_key_requests_moving_avrage.unset(r);
|
||||
cs::get_key_size.unset(r);
|
||||
cs::get_key_entries.unset(r);
|
||||
cs::get_row_capacity.unset(r);
|
||||
cs::get_row_hits.unset(r);
|
||||
cs::get_row_requests.unset(r);
|
||||
cs::get_row_hit_rate.unset(r);
|
||||
cs::get_row_hits_moving_avrage.unset(r);
|
||||
cs::get_row_requests_moving_avrage.unset(r);
|
||||
cs::get_row_size.unset(r);
|
||||
cs::get_row_entries.unset(r);
|
||||
cs::get_counter_capacity.unset(r);
|
||||
cs::get_counter_hits.unset(r);
|
||||
cs::get_counter_requests.unset(r);
|
||||
cs::get_counter_hit_rate.unset(r);
|
||||
cs::get_counter_hits_moving_avrage.unset(r);
|
||||
cs::get_counter_requests_moving_avrage.unset(r);
|
||||
cs::get_counter_size.unset(r);
|
||||
cs::get_counter_entries.unset(r);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -8,14 +8,10 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace seastar::httpd {
|
||||
class routes;
|
||||
}
|
||||
#include "api.hh"
|
||||
|
||||
namespace api {
|
||||
|
||||
struct http_context;
|
||||
void set_cache_service(http_context& ctx, seastar::httpd::routes& r);
|
||||
void unset_cache_service(http_context& ctx, seastar::httpd::routes& r);
|
||||
void set_cache_service(http_context& ctx, httpd::routes& r);
|
||||
|
||||
}
|
||||
|
||||
@@ -10,9 +10,9 @@
|
||||
#include "api/api-doc/collectd.json.hh"
|
||||
#include <seastar/core/scollectd.hh>
|
||||
#include <seastar/core/scollectd_api.hh>
|
||||
#include "endian.h"
|
||||
#include <boost/range/irange.hpp>
|
||||
#include <regex>
|
||||
#include "api/api_init.hh"
|
||||
|
||||
namespace api {
|
||||
|
||||
@@ -54,7 +54,7 @@ static const char* str_to_regex(const sstring& v) {
|
||||
void set_collectd(http_context& ctx, routes& r) {
|
||||
cd::get_collectd.set(r, [](std::unique_ptr<request> req) {
|
||||
|
||||
auto id = ::make_shared<scollectd::type_instance_id>(req->get_path_param("pluginid"),
|
||||
auto id = ::make_shared<scollectd::type_instance_id>(req->param["pluginid"],
|
||||
req->get_query_param("instance"), req->get_query_param("type"),
|
||||
req->get_query_param("type_instance"));
|
||||
|
||||
@@ -91,7 +91,7 @@ void set_collectd(http_context& ctx, routes& r) {
|
||||
});
|
||||
|
||||
cd::enable_collectd.set(r, [](std::unique_ptr<request> req) -> future<json::json_return_type> {
|
||||
std::regex plugin(req->get_path_param("pluginid").c_str());
|
||||
std::regex plugin(req->param["pluginid"].c_str());
|
||||
std::regex instance(str_to_regex(req->get_query_param("instance")));
|
||||
std::regex type(str_to_regex(req->get_query_param("type")));
|
||||
std::regex type_instance(str_to_regex(req->get_query_param("type_instance")));
|
||||
|
||||
@@ -8,13 +8,10 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace seastar::httpd {
|
||||
class routes;
|
||||
}
|
||||
#include "api.hh"
|
||||
|
||||
namespace api {
|
||||
|
||||
struct http_context;
|
||||
void set_collectd(http_context& ctx, seastar::httpd::routes& r);
|
||||
void set_collectd(http_context& ctx, httpd::routes& r);
|
||||
|
||||
}
|
||||
|
||||
@@ -6,16 +6,12 @@
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#include <fmt/ranges.h>
|
||||
#include "column_family.hh"
|
||||
#include "api/api.hh"
|
||||
#include "api/api-doc/column_family.json.hh"
|
||||
#include "api/api-doc/storage_service.json.hh"
|
||||
#include <vector>
|
||||
#include <seastar/http/exception.hh>
|
||||
#include "sstables/sstables.hh"
|
||||
#include "sstables/metadata_collector.hh"
|
||||
#include "utils/assert.hh"
|
||||
#include "utils/estimated_histogram.hh"
|
||||
#include <algorithm>
|
||||
#include "db/system_keyspace.hh"
|
||||
@@ -31,7 +27,6 @@ using namespace httpd;
|
||||
|
||||
using namespace json;
|
||||
namespace cf = httpd::column_family_json;
|
||||
namespace ss = httpd::storage_service_json;
|
||||
|
||||
std::tuple<sstring, sstring> parse_fully_qualified_cf_name(sstring name) {
|
||||
auto pos = name.find("%3A");
|
||||
@@ -83,65 +78,6 @@ future<json::json_return_type> get_cf_stats(http_context& ctx,
|
||||
}, std::plus<int64_t>());
|
||||
}
|
||||
|
||||
static future<json::json_return_type> set_tables(http_context& ctx, const sstring& keyspace, std::vector<sstring> tables, std::function<future<>(replica::table&)> set) {
|
||||
if (tables.empty()) {
|
||||
tables = map_keys(ctx.db.local().find_keyspace(keyspace).metadata().get()->cf_meta_data());
|
||||
}
|
||||
|
||||
return do_with(keyspace, std::move(tables), [&ctx, set] (const sstring& keyspace, const std::vector<sstring>& tables) {
|
||||
return ctx.db.invoke_on_all([&keyspace, &tables, set] (replica::database& db) {
|
||||
return parallel_for_each(tables, [&db, &keyspace, set] (const sstring& table) {
|
||||
replica::table& t = db.find_column_family(keyspace, table);
|
||||
return set(t);
|
||||
});
|
||||
});
|
||||
}).then([] {
|
||||
return make_ready_future<json::json_return_type>(json_void());
|
||||
});
|
||||
}
|
||||
|
||||
class autocompaction_toggle_guard {
|
||||
replica::database& _db;
|
||||
public:
|
||||
autocompaction_toggle_guard(replica::database& db) : _db(db) {
|
||||
SCYLLA_ASSERT(this_shard_id() == 0);
|
||||
if (!_db._enable_autocompaction_toggle) {
|
||||
throw std::runtime_error("Autocompaction toggle is busy");
|
||||
}
|
||||
_db._enable_autocompaction_toggle = false;
|
||||
}
|
||||
autocompaction_toggle_guard(const autocompaction_toggle_guard&) = delete;
|
||||
autocompaction_toggle_guard(autocompaction_toggle_guard&&) = default;
|
||||
~autocompaction_toggle_guard() {
|
||||
SCYLLA_ASSERT(this_shard_id() == 0);
|
||||
_db._enable_autocompaction_toggle = true;
|
||||
}
|
||||
};
|
||||
|
||||
static future<json::json_return_type> set_tables_autocompaction(http_context& ctx, const sstring &keyspace, std::vector<sstring> tables, bool enabled) {
|
||||
apilog.info("set_tables_autocompaction: enabled={} keyspace={} tables={}", enabled, keyspace, tables);
|
||||
|
||||
return ctx.db.invoke_on(0, [&ctx, keyspace, tables = std::move(tables), enabled] (replica::database& db) {
|
||||
auto g = autocompaction_toggle_guard(db);
|
||||
return set_tables(ctx, keyspace, tables, [enabled] (replica::table& cf) {
|
||||
if (enabled) {
|
||||
cf.enable_auto_compaction();
|
||||
} else {
|
||||
return cf.disable_auto_compaction();
|
||||
}
|
||||
return make_ready_future<>();
|
||||
}).finally([g = std::move(g)] {});
|
||||
});
|
||||
}
|
||||
|
||||
static future<json::json_return_type> set_tables_tombstone_gc(http_context& ctx, const sstring &keyspace, std::vector<sstring> tables, bool enabled) {
|
||||
apilog.info("set_tables_tombstone_gc: enabled={} keyspace={} tables={}", enabled, keyspace, tables);
|
||||
return set_tables(ctx, keyspace, std::move(tables), [enabled] (replica::table& t) {
|
||||
t.set_tombstone_gc_enabled(enabled);
|
||||
return make_ready_future<>();
|
||||
});
|
||||
}
|
||||
|
||||
static future<json::json_return_type> get_cf_stats_count(http_context& ctx, const sstring& name,
|
||||
utils::timed_rate_moving_average_summary_and_histogram replica::column_family_stats::*f) {
|
||||
return map_reduce_cf(ctx, name, int64_t(0), [f](const replica::column_family& cf) {
|
||||
@@ -367,20 +303,10 @@ ratio_holder filter_recent_false_positive_as_ratio_holder(const sstables::shared
|
||||
return ratio_holder(f + sst->filter_get_recent_true_positive(), f);
|
||||
}
|
||||
|
||||
uint64_t accumulate_on_active_memtables(replica::table& t, noncopyable_function<uint64_t(replica::memtable& mt)> action) {
|
||||
uint64_t ret = 0;
|
||||
t.for_each_active_memtable([&] (replica::memtable& mt) {
|
||||
ret += action(mt);
|
||||
});
|
||||
return ret;
|
||||
}
|
||||
|
||||
void set_column_family(http_context& ctx, routes& r, sharded<db::system_keyspace>& sys_ks) {
|
||||
cf::get_column_family_name.set(r, [&ctx] (const_req req){
|
||||
std::vector<sstring> res;
|
||||
const replica::database::tables_metadata& meta = ctx.db.local().get_tables_metadata();
|
||||
res.reserve(meta.size());
|
||||
meta.for_each_table_id([&] (const std::pair<sstring, sstring>& kscf, table_id) {
|
||||
ctx.db.local().get_tables_metadata().for_each_table_id([&] (const std::pair<sstring, sstring>& kscf, table_id) {
|
||||
res.push_back(kscf.first + ":" + kscf.second);
|
||||
});
|
||||
return res;
|
||||
@@ -400,23 +326,21 @@ void set_column_family(http_context& ctx, routes& r, sharded<db::system_keyspace
|
||||
|
||||
cf::get_column_family_name_keyspace.set(r, [&ctx] (const_req req){
|
||||
std::vector<sstring> res;
|
||||
const flat_hash_map<sstring, replica::keyspace>& keyspaces = ctx.db.local().get_keyspaces();
|
||||
res.reserve(keyspaces.size());
|
||||
for (const auto& i : keyspaces) {
|
||||
res.push_back(i.first);
|
||||
for (auto i = ctx.db.local().get_keyspaces().cbegin(); i!= ctx.db.local().get_keyspaces().cend(); i++) {
|
||||
res.push_back(i->first);
|
||||
}
|
||||
return res;
|
||||
});
|
||||
|
||||
cf::get_memtable_columns_count.set(r, [&ctx] (std::unique_ptr<http::request> req) {
|
||||
return map_reduce_cf(ctx, req->get_path_param("name"), uint64_t{0}, [](replica::column_family& cf) {
|
||||
return accumulate_on_active_memtables(cf, std::mem_fn(&replica::memtable::partition_count));
|
||||
return map_reduce_cf(ctx, req->param["name"], uint64_t{0}, [](replica::column_family& cf) {
|
||||
return boost::accumulate(cf.active_memtables() | boost::adaptors::transformed(std::mem_fn(&replica::memtable::partition_count)), uint64_t(0));
|
||||
}, std::plus<>());
|
||||
});
|
||||
|
||||
cf::get_all_memtable_columns_count.set(r, [&ctx] (std::unique_ptr<http::request> req) {
|
||||
return map_reduce_cf(ctx, uint64_t{0}, [](replica::column_family& cf) {
|
||||
return accumulate_on_active_memtables(cf, std::mem_fn(&replica::memtable::partition_count));
|
||||
return boost::accumulate(cf.active_memtables() | boost::adaptors::transformed(std::mem_fn(&replica::memtable::partition_count)), uint64_t(0));
|
||||
}, std::plus<>());
|
||||
});
|
||||
|
||||
@@ -429,34 +353,34 @@ void set_column_family(http_context& ctx, routes& r, sharded<db::system_keyspace
|
||||
});
|
||||
|
||||
cf::get_memtable_off_heap_size.set(r, [&ctx] (std::unique_ptr<http::request> req) {
|
||||
return map_reduce_cf(ctx, req->get_path_param("name"), int64_t(0), [](replica::column_family& cf) {
|
||||
return accumulate_on_active_memtables(cf, [] (replica::memtable& active_memtable) {
|
||||
return active_memtable.region().occupancy().total_space();
|
||||
});
|
||||
return map_reduce_cf(ctx, req->param["name"], int64_t(0), [](replica::column_family& cf) {
|
||||
return boost::accumulate(cf.active_memtables() | boost::adaptors::transformed([] (replica::memtable* active_memtable) {
|
||||
return active_memtable->region().occupancy().total_space();
|
||||
}), uint64_t(0));
|
||||
}, std::plus<int64_t>());
|
||||
});
|
||||
|
||||
cf::get_all_memtable_off_heap_size.set(r, [&ctx] (std::unique_ptr<http::request> req) {
|
||||
return map_reduce_cf(ctx, int64_t(0), [](replica::column_family& cf) {
|
||||
return accumulate_on_active_memtables(cf, [] (replica::memtable& active_memtable) {
|
||||
return active_memtable.region().occupancy().total_space();
|
||||
});
|
||||
return boost::accumulate(cf.active_memtables() | boost::adaptors::transformed([] (replica::memtable* active_memtable) {
|
||||
return active_memtable->region().occupancy().total_space();
|
||||
}), uint64_t(0));
|
||||
}, std::plus<int64_t>());
|
||||
});
|
||||
|
||||
cf::get_memtable_live_data_size.set(r, [&ctx] (std::unique_ptr<http::request> req) {
|
||||
return map_reduce_cf(ctx, req->get_path_param("name"), int64_t(0), [](replica::column_family& cf) {
|
||||
return accumulate_on_active_memtables(cf, [] (replica::memtable& active_memtable) {
|
||||
return active_memtable.region().occupancy().used_space();
|
||||
});
|
||||
return map_reduce_cf(ctx, req->param["name"], int64_t(0), [](replica::column_family& cf) {
|
||||
return boost::accumulate(cf.active_memtables() | boost::adaptors::transformed([] (replica::memtable* active_memtable) {
|
||||
return active_memtable->region().occupancy().used_space();
|
||||
}), uint64_t(0));
|
||||
}, std::plus<int64_t>());
|
||||
});
|
||||
|
||||
cf::get_all_memtable_live_data_size.set(r, [&ctx] (std::unique_ptr<http::request> req) {
|
||||
return map_reduce_cf(ctx, int64_t(0), [](replica::column_family& cf) {
|
||||
return accumulate_on_active_memtables(cf, [] (replica::memtable& active_memtable) {
|
||||
return active_memtable.region().occupancy().used_space();
|
||||
});
|
||||
return boost::accumulate(cf.active_memtables() | boost::adaptors::transformed([] (replica::memtable* active_memtable) {
|
||||
return active_memtable->region().occupancy().used_space();
|
||||
}), uint64_t(0));
|
||||
}, std::plus<int64_t>());
|
||||
});
|
||||
|
||||
@@ -470,7 +394,7 @@ void set_column_family(http_context& ctx, routes& r, sharded<db::system_keyspace
|
||||
|
||||
cf::get_cf_all_memtables_off_heap_size.set(r, [&ctx] (std::unique_ptr<http::request> req) {
|
||||
warn(unimplemented::cause::INDEXES);
|
||||
return map_reduce_cf(ctx, req->get_path_param("name"), int64_t(0), [](replica::column_family& cf) {
|
||||
return map_reduce_cf(ctx, req->param["name"], int64_t(0), [](replica::column_family& cf) {
|
||||
return cf.occupancy().total_space();
|
||||
}, std::plus<int64_t>());
|
||||
});
|
||||
@@ -486,7 +410,7 @@ void set_column_family(http_context& ctx, routes& r, sharded<db::system_keyspace
|
||||
|
||||
cf::get_cf_all_memtables_live_data_size.set(r, [&ctx] (std::unique_ptr<http::request> req) {
|
||||
warn(unimplemented::cause::INDEXES);
|
||||
return map_reduce_cf(ctx, req->get_path_param("name"), int64_t(0), [](replica::column_family& cf) {
|
||||
return map_reduce_cf(ctx, req->param["name"], int64_t(0), [](replica::column_family& cf) {
|
||||
return cf.occupancy().used_space();
|
||||
}, std::plus<int64_t>());
|
||||
});
|
||||
@@ -494,14 +418,14 @@ void set_column_family(http_context& ctx, routes& r, sharded<db::system_keyspace
|
||||
cf::get_all_cf_all_memtables_live_data_size.set(r, [&ctx] (std::unique_ptr<http::request> req) {
|
||||
warn(unimplemented::cause::INDEXES);
|
||||
return map_reduce_cf(ctx, int64_t(0), [](replica::column_family& cf) {
|
||||
return accumulate_on_active_memtables(cf, [] (replica::memtable& active_memtable) {
|
||||
return active_memtable.region().occupancy().used_space();
|
||||
});
|
||||
return boost::accumulate(cf.active_memtables() | boost::adaptors::transformed([] (replica::memtable* active_memtable) {
|
||||
return active_memtable->region().occupancy().used_space();
|
||||
}), uint64_t(0));
|
||||
}, std::plus<int64_t>());
|
||||
});
|
||||
|
||||
cf::get_memtable_switch_count.set(r, [&ctx] (std::unique_ptr<http::request> req) {
|
||||
return get_cf_stats(ctx,req->get_path_param("name") ,&replica::column_family_stats::memtable_switch_count);
|
||||
return get_cf_stats(ctx,req->param["name"] ,&replica::column_family_stats::memtable_switch_count);
|
||||
});
|
||||
|
||||
cf::get_all_memtable_switch_count.set(r, [&ctx] (std::unique_ptr<http::request> req) {
|
||||
@@ -510,7 +434,7 @@ void set_column_family(http_context& ctx, routes& r, sharded<db::system_keyspace
|
||||
|
||||
// FIXME: this refers to partitions, not rows.
|
||||
cf::get_estimated_row_size_histogram.set(r, [&ctx] (std::unique_ptr<http::request> req) {
|
||||
return map_reduce_cf(ctx, req->get_path_param("name"), utils::estimated_histogram(0), [](replica::column_family& cf) {
|
||||
return map_reduce_cf(ctx, req->param["name"], utils::estimated_histogram(0), [](replica::column_family& cf) {
|
||||
utils::estimated_histogram res(0);
|
||||
for (auto sstables = cf.get_sstables(); auto& i : *sstables) {
|
||||
res.merge(i->get_stats_metadata().estimated_partition_size);
|
||||
@@ -522,7 +446,7 @@ void set_column_family(http_context& ctx, routes& r, sharded<db::system_keyspace
|
||||
|
||||
// FIXME: this refers to partitions, not rows.
|
||||
cf::get_estimated_row_count.set(r, [&ctx] (std::unique_ptr<http::request> req) {
|
||||
return map_reduce_cf(ctx, req->get_path_param("name"), int64_t(0), [](replica::column_family& cf) {
|
||||
return map_reduce_cf(ctx, req->param["name"], int64_t(0), [](replica::column_family& cf) {
|
||||
uint64_t res = 0;
|
||||
for (auto sstables = cf.get_sstables(); auto& i : *sstables) {
|
||||
res += i->get_stats_metadata().estimated_partition_size.count();
|
||||
@@ -533,7 +457,7 @@ void set_column_family(http_context& ctx, routes& r, sharded<db::system_keyspace
|
||||
});
|
||||
|
||||
cf::get_estimated_column_count_histogram.set(r, [&ctx] (std::unique_ptr<http::request> req) {
|
||||
return map_reduce_cf(ctx, req->get_path_param("name"), utils::estimated_histogram(0), [](replica::column_family& cf) {
|
||||
return map_reduce_cf(ctx, req->param["name"], utils::estimated_histogram(0), [](replica::column_family& cf) {
|
||||
utils::estimated_histogram res(0);
|
||||
for (auto sstables = cf.get_sstables(); auto& i : *sstables) {
|
||||
res.merge(i->get_stats_metadata().estimated_cells_count);
|
||||
@@ -550,7 +474,7 @@ void set_column_family(http_context& ctx, routes& r, sharded<db::system_keyspace
|
||||
});
|
||||
|
||||
cf::get_pending_flushes.set(r, [&ctx] (std::unique_ptr<http::request> req) {
|
||||
return get_cf_stats(ctx,req->get_path_param("name") ,&replica::column_family_stats::pending_flushes);
|
||||
return get_cf_stats(ctx,req->param["name"] ,&replica::column_family_stats::pending_flushes);
|
||||
});
|
||||
|
||||
cf::get_all_pending_flushes.set(r, [&ctx] (std::unique_ptr<http::request> req) {
|
||||
@@ -558,7 +482,7 @@ void set_column_family(http_context& ctx, routes& r, sharded<db::system_keyspace
|
||||
});
|
||||
|
||||
cf::get_read.set(r, [&ctx] (std::unique_ptr<http::request> req) {
|
||||
return get_cf_stats_count(ctx,req->get_path_param("name") ,&replica::column_family_stats::reads);
|
||||
return get_cf_stats_count(ctx,req->param["name"] ,&replica::column_family_stats::reads);
|
||||
});
|
||||
|
||||
cf::get_all_read.set(r, [&ctx] (std::unique_ptr<http::request> req) {
|
||||
@@ -566,7 +490,7 @@ void set_column_family(http_context& ctx, routes& r, sharded<db::system_keyspace
|
||||
});
|
||||
|
||||
cf::get_write.set(r, [&ctx] (std::unique_ptr<http::request> req) {
|
||||
return get_cf_stats_count(ctx, req->get_path_param("name") ,&replica::column_family_stats::writes);
|
||||
return get_cf_stats_count(ctx, req->param["name"] ,&replica::column_family_stats::writes);
|
||||
});
|
||||
|
||||
cf::get_all_write.set(r, [&ctx] (std::unique_ptr<http::request> req) {
|
||||
@@ -574,19 +498,19 @@ void set_column_family(http_context& ctx, routes& r, sharded<db::system_keyspace
|
||||
});
|
||||
|
||||
cf::get_read_latency_histogram_depricated.set(r, [&ctx] (std::unique_ptr<http::request> req) {
|
||||
return get_cf_histogram(ctx, req->get_path_param("name"), &replica::column_family_stats::reads);
|
||||
return get_cf_histogram(ctx, req->param["name"], &replica::column_family_stats::reads);
|
||||
});
|
||||
|
||||
cf::get_read_latency_histogram.set(r, [&ctx] (std::unique_ptr<http::request> req) {
|
||||
return get_cf_rate_and_histogram(ctx, req->get_path_param("name"), &replica::column_family_stats::reads);
|
||||
return get_cf_rate_and_histogram(ctx, req->param["name"], &replica::column_family_stats::reads);
|
||||
});
|
||||
|
||||
cf::get_read_latency.set(r, [&ctx] (std::unique_ptr<http::request> req) {
|
||||
return get_cf_stats_sum(ctx,req->get_path_param("name") ,&replica::column_family_stats::reads);
|
||||
return get_cf_stats_sum(ctx,req->param["name"] ,&replica::column_family_stats::reads);
|
||||
});
|
||||
|
||||
cf::get_write_latency.set(r, [&ctx] (std::unique_ptr<http::request> req) {
|
||||
return get_cf_stats_sum(ctx, req->get_path_param("name") ,&replica::column_family_stats::writes);
|
||||
return get_cf_stats_sum(ctx, req->param["name"] ,&replica::column_family_stats::writes);
|
||||
});
|
||||
|
||||
cf::get_all_read_latency_histogram_depricated.set(r, [&ctx] (std::unique_ptr<http::request> req) {
|
||||
@@ -598,11 +522,11 @@ void set_column_family(http_context& ctx, routes& r, sharded<db::system_keyspace
|
||||
});
|
||||
|
||||
cf::get_write_latency_histogram_depricated.set(r, [&ctx] (std::unique_ptr<http::request> req) {
|
||||
return get_cf_histogram(ctx, req->get_path_param("name"), &replica::column_family_stats::writes);
|
||||
return get_cf_histogram(ctx, req->param["name"], &replica::column_family_stats::writes);
|
||||
});
|
||||
|
||||
cf::get_write_latency_histogram.set(r, [&ctx] (std::unique_ptr<http::request> req) {
|
||||
return get_cf_rate_and_histogram(ctx, req->get_path_param("name"), &replica::column_family_stats::writes);
|
||||
return get_cf_rate_and_histogram(ctx, req->param["name"], &replica::column_family_stats::writes);
|
||||
});
|
||||
|
||||
cf::get_all_write_latency_histogram_depricated.set(r, [&ctx] (std::unique_ptr<http::request> req) {
|
||||
@@ -614,7 +538,7 @@ void set_column_family(http_context& ctx, routes& r, sharded<db::system_keyspace
|
||||
});
|
||||
|
||||
cf::get_pending_compactions.set(r, [&ctx] (std::unique_ptr<http::request> req) {
|
||||
return map_reduce_cf(ctx, req->get_path_param("name"), int64_t(0), [](replica::column_family& cf) {
|
||||
return map_reduce_cf(ctx, req->param["name"], int64_t(0), [](replica::column_family& cf) {
|
||||
return cf.estimate_pending_compactions();
|
||||
}, std::plus<int64_t>());
|
||||
});
|
||||
@@ -626,7 +550,7 @@ void set_column_family(http_context& ctx, routes& r, sharded<db::system_keyspace
|
||||
});
|
||||
|
||||
cf::get_live_ss_table_count.set(r, [&ctx] (std::unique_ptr<http::request> req) {
|
||||
return get_cf_stats(ctx, req->get_path_param("name"), &replica::column_family_stats::live_sstable_count);
|
||||
return get_cf_stats(ctx, req->param["name"], &replica::column_family_stats::live_sstable_count);
|
||||
});
|
||||
|
||||
cf::get_all_live_ss_table_count.set(r, [&ctx] (std::unique_ptr<http::request> req) {
|
||||
@@ -634,11 +558,11 @@ void set_column_family(http_context& ctx, routes& r, sharded<db::system_keyspace
|
||||
});
|
||||
|
||||
cf::get_unleveled_sstables.set(r, [&ctx] (std::unique_ptr<http::request> req) {
|
||||
return get_cf_unleveled_sstables(ctx, req->get_path_param("name"));
|
||||
return get_cf_unleveled_sstables(ctx, req->param["name"]);
|
||||
});
|
||||
|
||||
cf::get_live_disk_space_used.set(r, [&ctx] (std::unique_ptr<http::request> req) {
|
||||
return sum_sstable(ctx, req->get_path_param("name"), false);
|
||||
return sum_sstable(ctx, req->param["name"], false);
|
||||
});
|
||||
|
||||
cf::get_all_live_disk_space_used.set(r, [&ctx] (std::unique_ptr<http::request> req) {
|
||||
@@ -646,7 +570,7 @@ void set_column_family(http_context& ctx, routes& r, sharded<db::system_keyspace
|
||||
});
|
||||
|
||||
cf::get_total_disk_space_used.set(r, [&ctx] (std::unique_ptr<http::request> req) {
|
||||
return sum_sstable(ctx, req->get_path_param("name"), true);
|
||||
return sum_sstable(ctx, req->param["name"], true);
|
||||
});
|
||||
|
||||
cf::get_all_total_disk_space_used.set(r, [&ctx] (std::unique_ptr<http::request> req) {
|
||||
@@ -655,7 +579,7 @@ void set_column_family(http_context& ctx, routes& r, sharded<db::system_keyspace
|
||||
|
||||
// FIXME: this refers to partitions, not rows.
|
||||
cf::get_min_row_size.set(r, [&ctx] (std::unique_ptr<http::request> req) {
|
||||
return map_reduce_cf(ctx, req->get_path_param("name"), INT64_MAX, min_partition_size, min_int64);
|
||||
return map_reduce_cf(ctx, req->param["name"], INT64_MAX, min_partition_size, min_int64);
|
||||
});
|
||||
|
||||
// FIXME: this refers to partitions, not rows.
|
||||
@@ -665,7 +589,7 @@ void set_column_family(http_context& ctx, routes& r, sharded<db::system_keyspace
|
||||
|
||||
// FIXME: this refers to partitions, not rows.
|
||||
cf::get_max_row_size.set(r, [&ctx] (std::unique_ptr<http::request> req) {
|
||||
return map_reduce_cf(ctx, req->get_path_param("name"), int64_t(0), max_partition_size, max_int64);
|
||||
return map_reduce_cf(ctx, req->param["name"], int64_t(0), max_partition_size, max_int64);
|
||||
});
|
||||
|
||||
// FIXME: this refers to partitions, not rows.
|
||||
@@ -676,7 +600,7 @@ void set_column_family(http_context& ctx, routes& r, sharded<db::system_keyspace
|
||||
// FIXME: this refers to partitions, not rows.
|
||||
cf::get_mean_row_size.set(r, [&ctx] (std::unique_ptr<http::request> req) {
|
||||
// Cassandra 3.x mean values are truncated as integrals.
|
||||
return map_reduce_cf(ctx, req->get_path_param("name"), integral_ratio_holder(), mean_partition_size, std::plus<integral_ratio_holder>());
|
||||
return map_reduce_cf(ctx, req->param["name"], integral_ratio_holder(), mean_partition_size, std::plus<integral_ratio_holder>());
|
||||
});
|
||||
|
||||
// FIXME: this refers to partitions, not rows.
|
||||
@@ -686,7 +610,7 @@ void set_column_family(http_context& ctx, routes& r, sharded<db::system_keyspace
|
||||
});
|
||||
|
||||
cf::get_bloom_filter_false_positives.set(r, [&ctx] (std::unique_ptr<http::request> req) {
|
||||
return map_reduce_cf(ctx, req->get_path_param("name"), uint64_t(0), [] (replica::column_family& cf) {
|
||||
return map_reduce_cf(ctx, req->param["name"], uint64_t(0), [] (replica::column_family& cf) {
|
||||
auto sstables = cf.get_sstables();
|
||||
return std::accumulate(sstables->begin(), sstables->end(), uint64_t(0), [](uint64_t s, auto& sst) {
|
||||
return s + sst->filter_get_false_positive();
|
||||
@@ -704,7 +628,7 @@ void set_column_family(http_context& ctx, routes& r, sharded<db::system_keyspace
|
||||
});
|
||||
|
||||
cf::get_recent_bloom_filter_false_positives.set(r, [&ctx] (std::unique_ptr<http::request> req) {
|
||||
return map_reduce_cf(ctx, req->get_path_param("name"), uint64_t(0), [] (replica::column_family& cf) {
|
||||
return map_reduce_cf(ctx, req->param["name"], uint64_t(0), [] (replica::column_family& cf) {
|
||||
auto sstables = cf.get_sstables();
|
||||
return std::accumulate(sstables->begin(), sstables->end(), uint64_t(0), [](uint64_t s, auto& sst) {
|
||||
return s + sst->filter_get_recent_false_positive();
|
||||
@@ -722,7 +646,7 @@ void set_column_family(http_context& ctx, routes& r, sharded<db::system_keyspace
|
||||
});
|
||||
|
||||
cf::get_bloom_filter_false_ratio.set(r, [&ctx] (std::unique_ptr<http::request> req) {
|
||||
return map_reduce_cf(ctx, req->get_path_param("name"), ratio_holder(), [] (replica::column_family& cf) {
|
||||
return map_reduce_cf(ctx, req->param["name"], ratio_holder(), [] (replica::column_family& cf) {
|
||||
return boost::accumulate(*cf.get_sstables() | boost::adaptors::transformed(filter_false_positive_as_ratio_holder), ratio_holder());
|
||||
}, std::plus<>());
|
||||
});
|
||||
@@ -734,7 +658,7 @@ void set_column_family(http_context& ctx, routes& r, sharded<db::system_keyspace
|
||||
});
|
||||
|
||||
cf::get_recent_bloom_filter_false_ratio.set(r, [&ctx] (std::unique_ptr<http::request> req) {
|
||||
return map_reduce_cf(ctx, req->get_path_param("name"), ratio_holder(), [] (replica::column_family& cf) {
|
||||
return map_reduce_cf(ctx, req->param["name"], ratio_holder(), [] (replica::column_family& cf) {
|
||||
return boost::accumulate(*cf.get_sstables() | boost::adaptors::transformed(filter_recent_false_positive_as_ratio_holder), ratio_holder());
|
||||
}, std::plus<>());
|
||||
});
|
||||
@@ -746,7 +670,7 @@ void set_column_family(http_context& ctx, routes& r, sharded<db::system_keyspace
|
||||
});
|
||||
|
||||
cf::get_bloom_filter_disk_space_used.set(r, [&ctx] (std::unique_ptr<http::request> req) {
|
||||
return map_reduce_cf(ctx, req->get_path_param("name"), uint64_t(0), [] (replica::column_family& cf) {
|
||||
return map_reduce_cf(ctx, req->param["name"], uint64_t(0), [] (replica::column_family& cf) {
|
||||
auto sstables = cf.get_sstables();
|
||||
return std::accumulate(sstables->begin(), sstables->end(), uint64_t(0), [](uint64_t s, auto& sst) {
|
||||
return s + sst->filter_size();
|
||||
@@ -764,7 +688,7 @@ void set_column_family(http_context& ctx, routes& r, sharded<db::system_keyspace
|
||||
});
|
||||
|
||||
cf::get_bloom_filter_off_heap_memory_used.set(r, [&ctx] (std::unique_ptr<http::request> req) {
|
||||
return map_reduce_cf(ctx, req->get_path_param("name"), uint64_t(0), [] (replica::column_family& cf) {
|
||||
return map_reduce_cf(ctx, req->param["name"], uint64_t(0), [] (replica::column_family& cf) {
|
||||
auto sstables = cf.get_sstables();
|
||||
return std::accumulate(sstables->begin(), sstables->end(), uint64_t(0), [](uint64_t s, auto& sst) {
|
||||
return s + sst->filter_memory_size();
|
||||
@@ -782,7 +706,7 @@ void set_column_family(http_context& ctx, routes& r, sharded<db::system_keyspace
|
||||
});
|
||||
|
||||
cf::get_index_summary_off_heap_memory_used.set(r, [&ctx] (std::unique_ptr<http::request> req) {
|
||||
return map_reduce_cf(ctx, req->get_path_param("name"), uint64_t(0), [] (replica::column_family& cf) {
|
||||
return map_reduce_cf(ctx, req->param["name"], uint64_t(0), [] (replica::column_family& cf) {
|
||||
auto sstables = cf.get_sstables();
|
||||
return std::accumulate(sstables->begin(), sstables->end(), uint64_t(0), [](uint64_t s, auto& sst) {
|
||||
return s + sst->get_summary().memory_footprint();
|
||||
@@ -805,7 +729,7 @@ void set_column_family(http_context& ctx, routes& r, sharded<db::system_keyspace
|
||||
// We are missing the off heap memory calculation
|
||||
// Return 0 is the wrong value. It's a work around
|
||||
// until the memory calculation will be available
|
||||
//auto id = get_uuid(req->get_path_param("name"), ctx.db.local());
|
||||
//auto id = get_uuid(req->param["name"], ctx.db.local());
|
||||
return make_ready_future<json::json_return_type>(0);
|
||||
});
|
||||
|
||||
@@ -818,7 +742,7 @@ void set_column_family(http_context& ctx, routes& r, sharded<db::system_keyspace
|
||||
cf::get_speculative_retries.set(r, [] (std::unique_ptr<http::request> req) {
|
||||
//TBD
|
||||
unimplemented();
|
||||
//auto id = get_uuid(req->get_path_param("name"), ctx.db.local());
|
||||
//auto id = get_uuid(req->param["name"], ctx.db.local());
|
||||
return make_ready_future<json::json_return_type>(0);
|
||||
});
|
||||
|
||||
@@ -831,14 +755,32 @@ void set_column_family(http_context& ctx, routes& r, sharded<db::system_keyspace
|
||||
cf::get_key_cache_hit_rate.set(r, [] (std::unique_ptr<http::request> req) {
|
||||
//TBD
|
||||
unimplemented();
|
||||
//auto id = get_uuid(req->get_path_param("name"), ctx.db.local());
|
||||
//auto id = get_uuid(req->param["name"], ctx.db.local());
|
||||
return make_ready_future<json::json_return_type>(0);
|
||||
});
|
||||
|
||||
cf::get_true_snapshots_size.set(r, [&ctx] (std::unique_ptr<http::request> req) {
|
||||
auto uuid = get_uuid(req->param["name"], ctx.db.local());
|
||||
return ctx.db.local().find_column_family(uuid).get_snapshot_details().then([](
|
||||
const std::unordered_map<sstring, replica::column_family::snapshot_details>& sd) {
|
||||
int64_t res = 0;
|
||||
for (auto i : sd) {
|
||||
res += i.second.total;
|
||||
}
|
||||
return make_ready_future<json::json_return_type>(res);
|
||||
});
|
||||
});
|
||||
|
||||
cf::get_all_true_snapshots_size.set(r, [] (std::unique_ptr<http::request> req) {
|
||||
//TBD
|
||||
unimplemented();
|
||||
return make_ready_future<json::json_return_type>(0);
|
||||
});
|
||||
|
||||
cf::get_row_cache_hit_out_of_range.set(r, [] (std::unique_ptr<http::request> req) {
|
||||
//TBD
|
||||
unimplemented();
|
||||
//auto id = get_uuid(req->get_path_param("name"), ctx.db.local());
|
||||
//auto id = get_uuid(req->param["name"], ctx.db.local());
|
||||
return make_ready_future<json::json_return_type>(0);
|
||||
});
|
||||
|
||||
@@ -849,7 +791,7 @@ void set_column_family(http_context& ctx, routes& r, sharded<db::system_keyspace
|
||||
});
|
||||
|
||||
cf::get_row_cache_hit.set(r, [&ctx] (std::unique_ptr<http::request> req) {
|
||||
return map_reduce_cf_raw(ctx, req->get_path_param("name"), utils::rate_moving_average(), [](const replica::column_family& cf) {
|
||||
return map_reduce_cf_raw(ctx, req->param["name"], utils::rate_moving_average(), [](const replica::column_family& cf) {
|
||||
return cf.get_row_cache().stats().hits.rate();
|
||||
}, std::plus<utils::rate_moving_average>()).then([](const utils::rate_moving_average& m) {
|
||||
return make_ready_future<json::json_return_type>(meter_to_json(m));
|
||||
@@ -865,7 +807,7 @@ void set_column_family(http_context& ctx, routes& r, sharded<db::system_keyspace
|
||||
});
|
||||
|
||||
cf::get_row_cache_miss.set(r, [&ctx] (std::unique_ptr<http::request> req) {
|
||||
return map_reduce_cf_raw(ctx, req->get_path_param("name"), utils::rate_moving_average(), [](const replica::column_family& cf) {
|
||||
return map_reduce_cf_raw(ctx, req->param["name"], utils::rate_moving_average(), [](const replica::column_family& cf) {
|
||||
return cf.get_row_cache().stats().misses.rate();
|
||||
}, std::plus<utils::rate_moving_average>()).then([](const utils::rate_moving_average& m) {
|
||||
return make_ready_future<json::json_return_type>(meter_to_json(m));
|
||||
@@ -882,120 +824,102 @@ void set_column_family(http_context& ctx, routes& r, sharded<db::system_keyspace
|
||||
});
|
||||
|
||||
cf::get_cas_prepare.set(r, [&ctx] (std::unique_ptr<http::request> req) {
|
||||
return map_reduce_cf_time_histogram(ctx, req->get_path_param("name"), [](const replica::column_family& cf) {
|
||||
return map_reduce_cf_time_histogram(ctx, req->param["name"], [](const replica::column_family& cf) {
|
||||
return cf.get_stats().cas_prepare.histogram();
|
||||
});
|
||||
});
|
||||
|
||||
cf::get_cas_propose.set(r, [&ctx] (std::unique_ptr<http::request> req) {
|
||||
return map_reduce_cf_time_histogram(ctx, req->get_path_param("name"), [](const replica::column_family& cf) {
|
||||
return map_reduce_cf_time_histogram(ctx, req->param["name"], [](const replica::column_family& cf) {
|
||||
return cf.get_stats().cas_accept.histogram();
|
||||
});
|
||||
});
|
||||
|
||||
cf::get_cas_commit.set(r, [&ctx] (std::unique_ptr<http::request> req) {
|
||||
return map_reduce_cf_time_histogram(ctx, req->get_path_param("name"), [](const replica::column_family& cf) {
|
||||
return map_reduce_cf_time_histogram(ctx, req->param["name"], [](const replica::column_family& cf) {
|
||||
return cf.get_stats().cas_learn.histogram();
|
||||
});
|
||||
});
|
||||
|
||||
cf::get_sstables_per_read_histogram.set(r, [&ctx] (std::unique_ptr<http::request> req) {
|
||||
return map_reduce_cf(ctx, req->get_path_param("name"), utils::estimated_histogram(0), [](replica::column_family& cf) {
|
||||
return map_reduce_cf(ctx, req->param["name"], utils::estimated_histogram(0), [](replica::column_family& cf) {
|
||||
return cf.get_stats().estimated_sstable_per_read;
|
||||
},
|
||||
utils::estimated_histogram_merge, utils_json::estimated_histogram());
|
||||
});
|
||||
|
||||
cf::get_tombstone_scanned_histogram.set(r, [&ctx] (std::unique_ptr<http::request> req) {
|
||||
return get_cf_histogram(ctx, req->get_path_param("name"), &replica::column_family_stats::tombstone_scanned);
|
||||
return get_cf_histogram(ctx, req->param["name"], &replica::column_family_stats::tombstone_scanned);
|
||||
});
|
||||
|
||||
cf::get_live_scanned_histogram.set(r, [&ctx] (std::unique_ptr<http::request> req) {
|
||||
return get_cf_histogram(ctx, req->get_path_param("name"), &replica::column_family_stats::live_scanned);
|
||||
return get_cf_histogram(ctx, req->param["name"], &replica::column_family_stats::live_scanned);
|
||||
});
|
||||
|
||||
cf::get_col_update_time_delta_histogram.set(r, [] (std::unique_ptr<http::request> req) {
|
||||
//TBD
|
||||
unimplemented();
|
||||
//auto id = get_uuid(req->get_path_param("name"), ctx.db.local());
|
||||
//auto id = get_uuid(req->param["name"], ctx.db.local());
|
||||
std::vector<double> res;
|
||||
return make_ready_future<json::json_return_type>(res);
|
||||
});
|
||||
|
||||
cf::get_auto_compaction.set(r, [&ctx] (const_req req) {
|
||||
auto uuid = get_uuid(req.get_path_param("name"), ctx.db.local());
|
||||
auto uuid = get_uuid(req.param["name"], ctx.db.local());
|
||||
replica::column_family& cf = ctx.db.local().find_column_family(uuid);
|
||||
return !cf.is_auto_compaction_disabled_by_user();
|
||||
});
|
||||
|
||||
cf::enable_auto_compaction.set(r, [&ctx](std::unique_ptr<http::request> req) {
|
||||
apilog.info("column_family/enable_auto_compaction: name={}", req->get_path_param("name"));
|
||||
auto [ks, cf] = parse_fully_qualified_cf_name(req->get_path_param("name"));
|
||||
validate_table(ctx, ks, cf);
|
||||
return set_tables_autocompaction(ctx, ks, {std::move(cf)}, true);
|
||||
apilog.info("column_family/enable_auto_compaction: name={}", req->param["name"]);
|
||||
return ctx.db.invoke_on(0, [&ctx, req = std::move(req)] (replica::database& db) {
|
||||
auto g = replica::database::autocompaction_toggle_guard(db);
|
||||
return foreach_column_family(ctx, req->param["name"], [](replica::column_family &cf) {
|
||||
cf.enable_auto_compaction();
|
||||
}).then([g = std::move(g)] {
|
||||
return make_ready_future<json::json_return_type>(json_void());
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
cf::disable_auto_compaction.set(r, [&ctx](std::unique_ptr<http::request> req) {
|
||||
apilog.info("column_family/disable_auto_compaction: name={}", req->get_path_param("name"));
|
||||
auto [ks, cf] = parse_fully_qualified_cf_name(req->get_path_param("name"));
|
||||
validate_table(ctx, ks, cf);
|
||||
return set_tables_autocompaction(ctx, ks, {std::move(cf)}, false);
|
||||
});
|
||||
|
||||
ss::enable_auto_compaction.set(r, [&ctx](std::unique_ptr<http::request> req) {
|
||||
auto keyspace = validate_keyspace(ctx, req);
|
||||
auto tables = parse_tables(keyspace, ctx, req->query_parameters, "cf");
|
||||
|
||||
apilog.info("enable_auto_compaction: keyspace={} tables={}", keyspace, tables);
|
||||
return set_tables_autocompaction(ctx, keyspace, tables, true);
|
||||
});
|
||||
|
||||
ss::disable_auto_compaction.set(r, [&ctx](std::unique_ptr<http::request> req) {
|
||||
auto keyspace = validate_keyspace(ctx, req);
|
||||
auto tables = parse_tables(keyspace, ctx, req->query_parameters, "cf");
|
||||
|
||||
apilog.info("disable_auto_compaction: keyspace={} tables={}", keyspace, tables);
|
||||
return set_tables_autocompaction(ctx, keyspace, tables, false);
|
||||
apilog.info("column_family/disable_auto_compaction: name={}", req->param["name"]);
|
||||
return ctx.db.invoke_on(0, [&ctx, req = std::move(req)] (replica::database& db) {
|
||||
auto g = replica::database::autocompaction_toggle_guard(db);
|
||||
return foreach_column_family(ctx, req->param["name"], [](replica::column_family &cf) {
|
||||
return cf.disable_auto_compaction();
|
||||
}).then([g = std::move(g)] {
|
||||
return make_ready_future<json::json_return_type>(json_void());
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
cf::get_tombstone_gc.set(r, [&ctx] (const_req req) {
|
||||
auto uuid = get_uuid(req.get_path_param("name"), ctx.db.local());
|
||||
auto uuid = get_uuid(req.param["name"], ctx.db.local());
|
||||
replica::table& t = ctx.db.local().find_column_family(uuid);
|
||||
return t.tombstone_gc_enabled();
|
||||
});
|
||||
|
||||
cf::enable_tombstone_gc.set(r, [&ctx](std::unique_ptr<http::request> req) {
|
||||
apilog.info("column_family/enable_tombstone_gc: name={}", req->get_path_param("name"));
|
||||
auto [ks, cf] = parse_fully_qualified_cf_name(req->get_path_param("name"));
|
||||
validate_table(ctx, ks, cf);
|
||||
return set_tables_tombstone_gc(ctx, ks, {std::move(cf)}, true);
|
||||
apilog.info("column_family/enable_tombstone_gc: name={}", req->param["name"]);
|
||||
return foreach_column_family(ctx, req->param["name"], [](replica::table& t) {
|
||||
t.set_tombstone_gc_enabled(true);
|
||||
}).then([] {
|
||||
return make_ready_future<json::json_return_type>(json_void());
|
||||
});
|
||||
});
|
||||
|
||||
cf::disable_tombstone_gc.set(r, [&ctx](std::unique_ptr<http::request> req) {
|
||||
apilog.info("column_family/disable_tombstone_gc: name={}", req->get_path_param("name"));
|
||||
auto [ks, cf] = parse_fully_qualified_cf_name(req->get_path_param("name"));
|
||||
validate_table(ctx, ks, cf);
|
||||
return set_tables_tombstone_gc(ctx, ks, {std::move(cf)}, false);
|
||||
});
|
||||
|
||||
ss::enable_tombstone_gc.set(r, [&ctx](std::unique_ptr<http::request> req) {
|
||||
auto keyspace = validate_keyspace(ctx, req);
|
||||
auto tables = parse_tables(keyspace, ctx, req->query_parameters, "cf");
|
||||
|
||||
apilog.info("enable_tombstone_gc: keyspace={} tables={}", keyspace, tables);
|
||||
return set_tables_tombstone_gc(ctx, keyspace, tables, true);
|
||||
});
|
||||
|
||||
ss::disable_tombstone_gc.set(r, [&ctx](std::unique_ptr<http::request> req) {
|
||||
auto keyspace = validate_keyspace(ctx, req);
|
||||
auto tables = parse_tables(keyspace, ctx, req->query_parameters, "cf");
|
||||
|
||||
apilog.info("disable_tombstone_gc: keyspace={} tables={}", keyspace, tables);
|
||||
return set_tables_tombstone_gc(ctx, keyspace, tables, false);
|
||||
apilog.info("column_family/disable_tombstone_gc: name={}", req->param["name"]);
|
||||
return foreach_column_family(ctx, req->param["name"], [](replica::table& t) {
|
||||
t.set_tombstone_gc_enabled(false);
|
||||
}).then([] {
|
||||
return make_ready_future<json::json_return_type>(json_void());
|
||||
});
|
||||
});
|
||||
|
||||
cf::get_built_indexes.set(r, [&ctx, &sys_ks](std::unique_ptr<http::request> req) {
|
||||
auto ks_cf = parse_fully_qualified_cf_name(req->get_path_param("name"));
|
||||
auto ks_cf = parse_fully_qualified_cf_name(req->param["name"]);
|
||||
auto&& ks = std::get<0>(ks_cf);
|
||||
auto&& cf_name = std::get<1>(ks_cf);
|
||||
return sys_ks.local().load_view_build_progress().then([ks, cf_name, &ctx](const std::vector<db::system_keyspace_view_build_progress>& vb) mutable {
|
||||
@@ -1033,7 +957,7 @@ void set_column_family(http_context& ctx, routes& r, sharded<db::system_keyspace
|
||||
});
|
||||
|
||||
cf::get_compression_ratio.set(r, [&ctx](std::unique_ptr<http::request> req) {
|
||||
auto uuid = get_uuid(req->get_path_param("name"), ctx.db.local());
|
||||
auto uuid = get_uuid(req->param["name"], ctx.db.local());
|
||||
|
||||
return ctx.db.map_reduce(sum_ratio<double>(), [uuid](replica::database& db) {
|
||||
replica::column_family& cf = db.find_column_family(uuid);
|
||||
@@ -1044,21 +968,21 @@ void set_column_family(http_context& ctx, routes& r, sharded<db::system_keyspace
|
||||
});
|
||||
|
||||
cf::get_read_latency_estimated_histogram.set(r, [&ctx](std::unique_ptr<http::request> req) {
|
||||
return map_reduce_cf_time_histogram(ctx, req->get_path_param("name"), [](const replica::column_family& cf) {
|
||||
return map_reduce_cf_time_histogram(ctx, req->param["name"], [](const replica::column_family& cf) {
|
||||
return cf.get_stats().reads.histogram();
|
||||
});
|
||||
});
|
||||
|
||||
cf::get_write_latency_estimated_histogram.set(r, [&ctx](std::unique_ptr<http::request> req) {
|
||||
return map_reduce_cf_time_histogram(ctx, req->get_path_param("name"), [](const replica::column_family& cf) {
|
||||
return map_reduce_cf_time_histogram(ctx, req->param["name"], [](const replica::column_family& cf) {
|
||||
return cf.get_stats().writes.histogram();
|
||||
});
|
||||
});
|
||||
|
||||
cf::set_compaction_strategy_class.set(r, [&ctx](std::unique_ptr<http::request> req) {
|
||||
sstring strategy = req->get_query_param("class_name");
|
||||
apilog.info("column_family/set_compaction_strategy_class: name={} strategy={}", req->get_path_param("name"), strategy);
|
||||
return foreach_column_family(ctx, req->get_path_param("name"), [strategy](replica::column_family& cf) {
|
||||
apilog.info("column_family/set_compaction_strategy_class: name={} strategy={}", req->param["name"], strategy);
|
||||
return foreach_column_family(ctx, req->param["name"], [strategy](replica::column_family& cf) {
|
||||
cf.set_compaction_strategy(sstables::compaction_strategy::type(strategy));
|
||||
}).then([] {
|
||||
return make_ready_future<json::json_return_type>(json_void());
|
||||
@@ -1066,7 +990,7 @@ void set_column_family(http_context& ctx, routes& r, sharded<db::system_keyspace
|
||||
});
|
||||
|
||||
cf::get_compaction_strategy_class.set(r, [&ctx](const_req req) {
|
||||
return ctx.db.local().find_column_family(get_uuid(req.get_path_param("name"), ctx.db.local())).get_compaction_strategy().name();
|
||||
return ctx.db.local().find_column_family(get_uuid(req.param["name"], ctx.db.local())).get_compaction_strategy().name();
|
||||
});
|
||||
|
||||
cf::set_compression_parameters.set(r, [](std::unique_ptr<http::request> req) {
|
||||
@@ -1082,7 +1006,7 @@ void set_column_family(http_context& ctx, routes& r, sharded<db::system_keyspace
|
||||
});
|
||||
|
||||
cf::get_sstable_count_per_level.set(r, [&ctx](std::unique_ptr<http::request> req) {
|
||||
return map_reduce_cf_raw(ctx, req->get_path_param("name"), std::vector<uint64_t>(), [](const replica::column_family& cf) {
|
||||
return map_reduce_cf_raw(ctx, req->param["name"], std::vector<uint64_t>(), [](const replica::column_family& cf) {
|
||||
return cf.sstable_count_per_level();
|
||||
}, concat_sstable_count_per_level).then([](const std::vector<uint64_t>& res) {
|
||||
return make_ready_future<json::json_return_type>(res);
|
||||
@@ -1091,7 +1015,7 @@ void set_column_family(http_context& ctx, routes& r, sharded<db::system_keyspace
|
||||
|
||||
cf::get_sstables_for_key.set(r, [&ctx](std::unique_ptr<http::request> req) {
|
||||
auto key = req->get_query_param("key");
|
||||
auto uuid = get_uuid(req->get_path_param("name"), ctx.db.local());
|
||||
auto uuid = get_uuid(req->param["name"], ctx.db.local());
|
||||
|
||||
return ctx.db.map_reduce0([key, uuid] (replica::database& db) -> future<std::unordered_set<sstring>> {
|
||||
auto sstables = co_await db.find_column_family(uuid).get_sstables_by_partition_key(key);
|
||||
@@ -1107,7 +1031,7 @@ void set_column_family(http_context& ctx, routes& r, sharded<db::system_keyspace
|
||||
|
||||
|
||||
cf::toppartitions.set(r, [&ctx] (std::unique_ptr<http::request> req) {
|
||||
auto name = req->get_path_param("name");
|
||||
auto name = req->param["name"];
|
||||
auto [ks, cf] = parse_fully_qualified_cf_name(name);
|
||||
|
||||
api::req_param<std::chrono::milliseconds, unsigned> duration{*req, "duration", 1000ms};
|
||||
@@ -1123,21 +1047,12 @@ void set_column_family(http_context& ctx, routes& r, sharded<db::system_keyspace
|
||||
});
|
||||
|
||||
cf::force_major_compaction.set(r, [&ctx](std::unique_ptr<http::request> req) -> future<json::json_return_type> {
|
||||
auto params = req_params({
|
||||
std::pair("name", mandatory::yes),
|
||||
std::pair("flush_memtables", mandatory::no),
|
||||
std::pair("consider_only_existing_data", mandatory::no),
|
||||
std::pair("split_output", mandatory::no),
|
||||
});
|
||||
params.process(*req);
|
||||
if (params.get("split_output")) {
|
||||
if (req->get_query_param("split_output") != "") {
|
||||
fail(unimplemented::cause::API);
|
||||
}
|
||||
auto [ks, cf] = parse_fully_qualified_cf_name(*params.get("name"));
|
||||
auto flush = params.get_as<bool>("flush_memtables").value_or(true);
|
||||
auto consider_only_existing_data = params.get_as<bool>("consider_only_existing_data").value_or(false);
|
||||
apilog.info("column_family/force_major_compaction: name={} flush={} consider_only_existing_data={}", req->get_path_param("name"), flush, consider_only_existing_data);
|
||||
|
||||
apilog.info("column_family/force_major_compaction: name={}", req->param["name"]);
|
||||
auto [ks, cf] = parse_fully_qualified_cf_name(req->param["name"]);
|
||||
auto keyspace = validate_keyspace(ctx, ks);
|
||||
std::vector<table_info> table_infos = {table_info{
|
||||
.name = cf,
|
||||
@@ -1145,11 +1060,7 @@ void set_column_family(http_context& ctx, routes& r, sharded<db::system_keyspace
|
||||
}};
|
||||
|
||||
auto& compaction_module = ctx.db.local().get_compaction_manager().get_task_manager_module();
|
||||
std::optional<flush_mode> fmopt;
|
||||
if (!flush && !consider_only_existing_data) {
|
||||
fmopt = flush_mode::skip;
|
||||
}
|
||||
auto task = co_await compaction_module.make_and_start_task<major_keyspace_compaction_task_impl>({}, std::move(keyspace), tasks::task_id::create_null_id(), ctx.db, std::move(table_infos), fmopt, consider_only_existing_data);
|
||||
auto task = co_await compaction_module.make_and_start_task<major_keyspace_compaction_task_impl>({}, std::move(keyspace), ctx.db, std::move(table_infos));
|
||||
co_await task->done();
|
||||
co_return json_void();
|
||||
});
|
||||
@@ -1229,6 +1140,8 @@ void unset_column_family(http_context& ctx, routes& r) {
|
||||
cf::get_speculative_retries.unset(r);
|
||||
cf::get_all_speculative_retries.unset(r);
|
||||
cf::get_key_cache_hit_rate.unset(r);
|
||||
cf::get_true_snapshots_size.unset(r);
|
||||
cf::get_all_true_snapshots_size.unset(r);
|
||||
cf::get_row_cache_hit_out_of_range.unset(r);
|
||||
cf::get_all_row_cache_hit_out_of_range.unset(r);
|
||||
cf::get_row_cache_hit.unset(r);
|
||||
@@ -1245,13 +1158,6 @@ void unset_column_family(http_context& ctx, routes& r) {
|
||||
cf::get_auto_compaction.unset(r);
|
||||
cf::enable_auto_compaction.unset(r);
|
||||
cf::disable_auto_compaction.unset(r);
|
||||
ss::enable_auto_compaction.unset(r);
|
||||
ss::disable_auto_compaction.unset(r);
|
||||
cf::get_tombstone_gc.unset(r);
|
||||
cf::enable_tombstone_gc.unset(r);
|
||||
cf::disable_tombstone_gc.unset(r);
|
||||
ss::enable_tombstone_gc.unset(r);
|
||||
ss::disable_tombstone_gc.unset(r);
|
||||
cf::get_built_indexes.unset(r);
|
||||
cf::get_compression_metadata_off_heap_memory_used.unset(r);
|
||||
cf::get_compression_parameters.unset(r);
|
||||
|
||||
@@ -8,10 +8,11 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "api.hh"
|
||||
#include "api/api-doc/column_family.json.hh"
|
||||
#include "replica/database.hh"
|
||||
#include <seastar/json/json_elements.hh>
|
||||
#include <seastar/core/future-util.hh>
|
||||
#include <any>
|
||||
#include "api/api_init.hh"
|
||||
|
||||
namespace db {
|
||||
class system_keyspace;
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
#include "commitlog.hh"
|
||||
#include "db/commitlog/commitlog.hh"
|
||||
#include "api/api-doc/commitlog.json.hh"
|
||||
#include "api/api_init.hh"
|
||||
#include "replica/database.hh"
|
||||
#include <vector>
|
||||
|
||||
@@ -17,7 +16,7 @@ namespace api {
|
||||
using namespace seastar::httpd;
|
||||
|
||||
template<typename T>
|
||||
static auto acquire_cl_metric(http_context& ctx, std::function<T (const db::commitlog*)> func) {
|
||||
static auto acquire_cl_metric(http_context& ctx, std::function<T (db::commitlog*)> func) {
|
||||
typedef T ret_type;
|
||||
|
||||
return ctx.db.map_reduce0([func = std::move(func)](replica::database& db) {
|
||||
@@ -63,9 +62,6 @@ void set_commitlog(http_context& ctx, routes& r) {
|
||||
httpd::commitlog_json::get_total_commit_log_size.set(r, [&ctx](std::unique_ptr<request> req) {
|
||||
return acquire_cl_metric<uint64_t>(ctx, std::bind(&db::commitlog::get_total_size, std::placeholders::_1));
|
||||
});
|
||||
httpd::commitlog_json::get_max_disk_size.set(r, [&ctx](std::unique_ptr<request> req) {
|
||||
return acquire_cl_metric<uint64_t>(ctx, std::bind(&db::commitlog::disk_limit, std::placeholders::_1));
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -8,12 +8,10 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace seastar::httpd {
|
||||
class routes;
|
||||
}
|
||||
#include "api.hh"
|
||||
|
||||
namespace api {
|
||||
struct http_context;
|
||||
void set_commitlog(http_context& ctx, seastar::httpd::routes& r);
|
||||
|
||||
void set_commitlog(http_context& ctx, httpd::routes& r);
|
||||
|
||||
}
|
||||
|
||||
@@ -7,11 +7,9 @@
|
||||
*/
|
||||
|
||||
#include <seastar/core/coroutine.hh>
|
||||
#include <seastar/coroutine/exception.hh>
|
||||
|
||||
#include "compaction_manager.hh"
|
||||
#include "compaction/compaction_manager.hh"
|
||||
#include "api/api.hh"
|
||||
#include "api/api-doc/compaction_manager.json.hh"
|
||||
#include "db/system_keyspace.hh"
|
||||
#include "column_family.hh"
|
||||
@@ -52,7 +50,7 @@ void set_compaction_manager(http_context& ctx, routes& r) {
|
||||
|
||||
for (const auto& c : cm.get_compactions()) {
|
||||
cm::summary s;
|
||||
s.id = fmt::to_string(c.compaction_uuid);
|
||||
s.id = c.compaction_uuid.to_sstring();
|
||||
s.ks = c.ks_name;
|
||||
s.cf = c.cf_name;
|
||||
s.unit = "keys";
|
||||
@@ -111,15 +109,15 @@ void set_compaction_manager(http_context& ctx, routes& r) {
|
||||
});
|
||||
|
||||
cm::stop_keyspace_compaction.set(r, [&ctx] (std::unique_ptr<http::request> req) -> future<json::json_return_type> {
|
||||
auto ks_name = validate_keyspace(ctx, req);
|
||||
auto ks_name = validate_keyspace(ctx, req->param);
|
||||
auto table_names = parse_tables(ks_name, ctx, req->query_parameters, "tables");
|
||||
if (table_names.empty()) {
|
||||
table_names = map_keys(ctx.db.local().find_keyspace(ks_name).metadata().get()->cf_meta_data());
|
||||
}
|
||||
auto type = req->get_query_param("type");
|
||||
co_await ctx.db.invoke_on_all([&] (replica::database& db) {
|
||||
co_await ctx.db.invoke_on_all([&ks_name, &table_names, type] (replica::database& db) {
|
||||
auto& cm = db.get_compaction_manager();
|
||||
return parallel_for_each(table_names, [&] (sstring& table_name) {
|
||||
return parallel_for_each(table_names, [&db, &cm, &ks_name, type] (sstring& table_name) {
|
||||
auto& t = db.find_column_family(ks_name, table_name);
|
||||
return t.parallel_foreach_table_state([&] (compaction::table_state& ts) {
|
||||
return cm.stop_compaction(type, &ts);
|
||||
@@ -154,15 +152,12 @@ void set_compaction_manager(http_context& ctx, routes& r) {
|
||||
});
|
||||
|
||||
cm::get_compaction_history.set(r, [&ctx] (std::unique_ptr<http::request> req) {
|
||||
std::function<future<>(output_stream<char>&&)> f = [&ctx] (output_stream<char>&& out) -> future<> {
|
||||
auto s = std::move(out);
|
||||
bool first = true;
|
||||
std::exception_ptr ex;
|
||||
try {
|
||||
co_await s.write("[");
|
||||
co_await ctx.db.local().get_compaction_manager().get_compaction_history([&s, &first](const db::compaction_history_entry& entry) mutable -> future<> {
|
||||
std::function<future<>(output_stream<char>&&)> f = [&ctx](output_stream<char>&& s) {
|
||||
return do_with(output_stream<char>(std::move(s)), true, [&ctx] (output_stream<char>& s, bool& first){
|
||||
return s.write("[").then([&ctx, &s, &first] {
|
||||
return ctx.db.local().get_compaction_manager().get_compaction_history([&s, &first](const db::compaction_history_entry& entry) mutable {
|
||||
cm::history h;
|
||||
h.id = fmt::to_string(entry.id);
|
||||
h.id = entry.id.to_sstring();
|
||||
h.ks = std::move(entry.ks);
|
||||
h.cf = std::move(entry.cf);
|
||||
h.compacted_at = entry.compacted_at;
|
||||
@@ -174,21 +169,18 @@ void set_compaction_manager(http_context& ctx, routes& r) {
|
||||
e.value = it.second;
|
||||
h.rows_merged.push(std::move(e));
|
||||
}
|
||||
if (!first) {
|
||||
co_await s.write(", ");
|
||||
}
|
||||
auto fut = first ? make_ready_future<>() : s.write(", ");
|
||||
first = false;
|
||||
co_await formatter::write(s, h);
|
||||
return fut.then([&s, h = std::move(h)] {
|
||||
return formatter::write(s, h);
|
||||
});
|
||||
}).then([&s] {
|
||||
return s.write("]").then([&s] {
|
||||
return s.close();
|
||||
});
|
||||
});
|
||||
co_await s.write("]");
|
||||
co_await s.flush();
|
||||
} catch (...) {
|
||||
ex = std::current_exception();
|
||||
}
|
||||
co_await s.close();
|
||||
if (ex) {
|
||||
co_await coroutine::return_exception_ptr(std::move(ex));
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
return make_ready_future<json::json_return_type>(std::move(f));
|
||||
});
|
||||
|
||||
@@ -8,12 +8,10 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace seastar::httpd {
|
||||
class routes;
|
||||
}
|
||||
#include "api.hh"
|
||||
|
||||
namespace api {
|
||||
struct http_context;
|
||||
void set_compaction_manager(http_context& ctx, seastar::httpd::routes& r);
|
||||
|
||||
void set_compaction_manager(http_context& ctx, httpd::routes& r);
|
||||
|
||||
}
|
||||
|
||||
115
api/config.cc
115
api/config.cc
@@ -6,21 +6,14 @@
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#include "api/api.hh"
|
||||
#include "api/config.hh"
|
||||
#include "api/api-doc/config.json.hh"
|
||||
#include "api/api-doc/storage_proxy.json.hh"
|
||||
#include "api/api-doc/storage_service.json.hh"
|
||||
#include "replica/database.hh"
|
||||
#include "db/config.hh"
|
||||
#include <sstream>
|
||||
#include <boost/algorithm/string/replace.hpp>
|
||||
#include <seastar/http/exception.hh>
|
||||
|
||||
namespace api {
|
||||
using namespace seastar::httpd;
|
||||
namespace sp = httpd::storage_proxy_json;
|
||||
namespace ss = httpd::storage_service_json;
|
||||
|
||||
template<class T>
|
||||
json::json_return_type get_json_return_type(const T& val) {
|
||||
@@ -98,7 +91,7 @@ void set_config(std::shared_ptr < api_registry_builder20 > rb, http_context& ctx
|
||||
});
|
||||
|
||||
cs::find_config_id.set(r, [&cfg] (const_req r) {
|
||||
auto id = r.get_path_param("id");
|
||||
auto id = r.param["id"];
|
||||
for (auto&& cfg_ref : cfg.values()) {
|
||||
auto&& cfg = cfg_ref.get();
|
||||
if (id == cfg.name()) {
|
||||
@@ -107,112 +100,6 @@ void set_config(std::shared_ptr < api_registry_builder20 > rb, http_context& ctx
|
||||
}
|
||||
throw bad_param_exception(sstring("No such config entry: ") + id);
|
||||
});
|
||||
|
||||
sp::get_rpc_timeout.set(r, [&cfg](const_req req) {
|
||||
return cfg.request_timeout_in_ms()/1000.0;
|
||||
});
|
||||
|
||||
sp::set_rpc_timeout.set(r, [](std::unique_ptr<http::request> req) {
|
||||
//TBD
|
||||
unimplemented();
|
||||
auto enable = req->get_query_param("timeout");
|
||||
return make_ready_future<json::json_return_type>(seastar::json::json_void());
|
||||
});
|
||||
|
||||
sp::get_read_rpc_timeout.set(r, [&cfg](const_req req) {
|
||||
return cfg.read_request_timeout_in_ms()/1000.0;
|
||||
});
|
||||
|
||||
sp::set_read_rpc_timeout.set(r, [](std::unique_ptr<http::request> req) {
|
||||
//TBD
|
||||
unimplemented();
|
||||
auto enable = req->get_query_param("timeout");
|
||||
return make_ready_future<json::json_return_type>(seastar::json::json_void());
|
||||
});
|
||||
|
||||
sp::get_write_rpc_timeout.set(r, [&cfg](const_req req) {
|
||||
return cfg.write_request_timeout_in_ms()/1000.0;
|
||||
});
|
||||
|
||||
sp::set_write_rpc_timeout.set(r, [](std::unique_ptr<http::request> req) {
|
||||
//TBD
|
||||
unimplemented();
|
||||
auto enable = req->get_query_param("timeout");
|
||||
return make_ready_future<json::json_return_type>(seastar::json::json_void());
|
||||
});
|
||||
|
||||
sp::get_counter_write_rpc_timeout.set(r, [&cfg](const_req req) {
|
||||
return cfg.counter_write_request_timeout_in_ms()/1000.0;
|
||||
});
|
||||
|
||||
sp::set_counter_write_rpc_timeout.set(r, [](std::unique_ptr<http::request> req) {
|
||||
//TBD
|
||||
unimplemented();
|
||||
auto enable = req->get_query_param("timeout");
|
||||
return make_ready_future<json::json_return_type>(seastar::json::json_void());
|
||||
});
|
||||
|
||||
sp::get_cas_contention_timeout.set(r, [&cfg](const_req req) {
|
||||
return cfg.cas_contention_timeout_in_ms()/1000.0;
|
||||
});
|
||||
|
||||
sp::set_cas_contention_timeout.set(r, [](std::unique_ptr<http::request> req) {
|
||||
//TBD
|
||||
unimplemented();
|
||||
auto enable = req->get_query_param("timeout");
|
||||
return make_ready_future<json::json_return_type>(seastar::json::json_void());
|
||||
});
|
||||
|
||||
sp::get_range_rpc_timeout.set(r, [&cfg](const_req req) {
|
||||
return cfg.range_request_timeout_in_ms()/1000.0;
|
||||
});
|
||||
|
||||
sp::set_range_rpc_timeout.set(r, [](std::unique_ptr<http::request> req) {
|
||||
//TBD
|
||||
unimplemented();
|
||||
auto enable = req->get_query_param("timeout");
|
||||
return make_ready_future<json::json_return_type>(seastar::json::json_void());
|
||||
});
|
||||
|
||||
sp::get_truncate_rpc_timeout.set(r, [&cfg](const_req req) {
|
||||
return cfg.truncate_request_timeout_in_ms()/1000.0;
|
||||
});
|
||||
|
||||
sp::set_truncate_rpc_timeout.set(r, [](std::unique_ptr<http::request> req) {
|
||||
//TBD
|
||||
unimplemented();
|
||||
auto enable = req->get_query_param("timeout");
|
||||
return make_ready_future<json::json_return_type>(seastar::json::json_void());
|
||||
});
|
||||
|
||||
ss::get_all_data_file_locations.set(r, [&cfg](const_req req) {
|
||||
return container_to_vec(cfg.data_file_directories());
|
||||
});
|
||||
|
||||
ss::get_saved_caches_location.set(r, [&cfg](const_req req) {
|
||||
return cfg.saved_caches_directory();
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
void unset_config(http_context& ctx, routes& r) {
|
||||
cs::find_config_id.unset(r);
|
||||
sp::get_rpc_timeout.unset(r);
|
||||
sp::set_rpc_timeout.unset(r);
|
||||
sp::get_read_rpc_timeout.unset(r);
|
||||
sp::set_read_rpc_timeout.unset(r);
|
||||
sp::get_write_rpc_timeout.unset(r);
|
||||
sp::set_write_rpc_timeout.unset(r);
|
||||
sp::get_counter_write_rpc_timeout.unset(r);
|
||||
sp::set_counter_write_rpc_timeout.unset(r);
|
||||
sp::get_cas_contention_timeout.unset(r);
|
||||
sp::set_cas_contention_timeout.unset(r);
|
||||
sp::get_range_rpc_timeout.unset(r);
|
||||
sp::set_range_rpc_timeout.unset(r);
|
||||
sp::get_truncate_rpc_timeout.unset(r);
|
||||
sp::set_truncate_rpc_timeout.unset(r);
|
||||
ss::get_all_data_file_locations.unset(r);
|
||||
ss::get_saved_caches_location.unset(r);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -8,11 +8,10 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "api/api_init.hh"
|
||||
#include "api.hh"
|
||||
#include <seastar/http/api_docs.hh>
|
||||
|
||||
namespace api {
|
||||
|
||||
void set_config(std::shared_ptr<httpd::api_registry_builder20> rb, http_context& ctx, httpd::routes& r, const db::config& cfg, bool first = false);
|
||||
void unset_config(http_context& ctx, httpd::routes& r);
|
||||
}
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2024-present ScyllaDB
|
||||
*/
|
||||
|
||||
/*
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef SCYLLA_BUILD_MODE_RELEASE
|
||||
|
||||
#include <seastar/core/coroutine.hh>
|
||||
#include <boost/range/algorithm/transform.hpp>
|
||||
|
||||
#include "api/api-doc/cql_server_test.json.hh"
|
||||
#include "cql_server_test.hh"
|
||||
#include "transport/controller.hh"
|
||||
#include "transport/server.hh"
|
||||
#include "service/qos/qos_common.hh"
|
||||
|
||||
namespace api {
|
||||
|
||||
namespace cst = httpd::cql_server_test_json;
|
||||
using namespace json;
|
||||
using namespace seastar::httpd;
|
||||
|
||||
struct connection_sl_params : public json::json_base {
|
||||
json::json_element<sstring> _role_name;
|
||||
json::json_element<sstring> _workload_type;
|
||||
json::json_element<sstring> _timeout;
|
||||
|
||||
connection_sl_params(const sstring& role_name, const sstring& workload_type, const sstring& timeout) {
|
||||
_role_name = role_name;
|
||||
_workload_type = workload_type;
|
||||
_timeout = timeout;
|
||||
register_params();
|
||||
}
|
||||
|
||||
connection_sl_params(const connection_sl_params& params)
|
||||
: connection_sl_params(params._role_name(), params._workload_type(), params._timeout()) {}
|
||||
|
||||
void register_params() {
|
||||
add(&_role_name, "role_name");
|
||||
add(&_workload_type, "workload_type");
|
||||
add(&_timeout, "timeout");
|
||||
}
|
||||
};
|
||||
|
||||
void set_cql_server_test(http_context& ctx, seastar::httpd::routes& r, cql_transport::controller& ctl) {
|
||||
cst::connections_params.set(r, [&ctl] (std::unique_ptr<http::request> req) -> future<json::json_return_type> {
|
||||
auto sl_params = co_await ctl.get_connections_service_level_params();
|
||||
|
||||
std::vector<connection_sl_params> result;
|
||||
boost::transform(std::move(sl_params), std::back_inserter(result), [] (const cql_transport::connection_service_level_params& params) {
|
||||
auto nanos = std::chrono::duration_cast<std::chrono::nanoseconds>(params.timeout_config.read_timeout).count();
|
||||
return connection_sl_params(
|
||||
std::move(params.role_name),
|
||||
sstring(qos::service_level_options::to_string(params.workload_type)),
|
||||
to_string(cql_duration(months_counter{0}, days_counter{0}, nanoseconds_counter{nanos})));
|
||||
});
|
||||
co_return result;
|
||||
});
|
||||
}
|
||||
|
||||
void unset_cql_server_test(http_context& ctx, seastar::httpd::routes& r) {
|
||||
cst::connections_params.unset(r);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,29 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2024-present ScyllaDB
|
||||
*/
|
||||
|
||||
/*
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef SCYLLA_BUILD_MODE_RELEASE
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace cql_transport {
|
||||
class controller;
|
||||
}
|
||||
|
||||
namespace seastar::httpd {
|
||||
class routes;
|
||||
}
|
||||
|
||||
namespace api {
|
||||
struct http_context;
|
||||
|
||||
void set_cql_server_test(http_context& ctx, seastar::httpd::routes& r, cql_transport::controller& ctl);
|
||||
void unset_cql_server_test(http_context& ctx, seastar::httpd::routes& r);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -6,15 +6,45 @@
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#include "locator/token_metadata.hh"
|
||||
#include "locator/snitch_base.hh"
|
||||
#include "locator/production_snitch_base.hh"
|
||||
#include "endpoint_snitch.hh"
|
||||
#include "api/api-doc/endpoint_snitch_info.json.hh"
|
||||
#include "api/api-doc/storage_service.json.hh"
|
||||
#include "utils/fb_utilities.hh"
|
||||
|
||||
namespace api {
|
||||
using namespace seastar::httpd;
|
||||
|
||||
void set_endpoint_snitch(http_context& ctx, routes& r, sharded<locator::snitch_ptr>& snitch) {
|
||||
static auto host_or_broadcast = [](const_req req) {
|
||||
auto host = req.get_query_param("host");
|
||||
return host.empty() ? gms::inet_address(utils::fb_utilities::get_broadcast_address()) : gms::inet_address(host);
|
||||
};
|
||||
|
||||
httpd::endpoint_snitch_info_json::get_datacenter.set(r, [&ctx](const_req req) {
|
||||
auto& topology = ctx.shared_token_metadata.local().get()->get_topology();
|
||||
auto ep = host_or_broadcast(req);
|
||||
if (!topology.has_endpoint(ep)) {
|
||||
// Cannot return error here, nodetool status can race, request
|
||||
// info about just-left node and not handle it nicely
|
||||
return locator::endpoint_dc_rack::default_location.dc;
|
||||
}
|
||||
return topology.get_datacenter(ep);
|
||||
});
|
||||
|
||||
httpd::endpoint_snitch_info_json::get_rack.set(r, [&ctx](const_req req) {
|
||||
auto& topology = ctx.shared_token_metadata.local().get()->get_topology();
|
||||
auto ep = host_or_broadcast(req);
|
||||
if (!topology.has_endpoint(ep)) {
|
||||
// Cannot return error here, nodetool status can race, request
|
||||
// info about just-left node and not handle it nicely
|
||||
return locator::endpoint_dc_rack::default_location.rack;
|
||||
}
|
||||
return topology.get_rack(ep);
|
||||
});
|
||||
|
||||
httpd::endpoint_snitch_info_json::get_snitch_name.set(r, [&snitch] (const_req req) {
|
||||
return snitch.local()->get_name();
|
||||
});
|
||||
@@ -30,6 +60,8 @@ void set_endpoint_snitch(http_context& ctx, routes& r, sharded<locator::snitch_p
|
||||
}
|
||||
|
||||
void unset_endpoint_snitch(http_context& ctx, routes& r) {
|
||||
httpd::endpoint_snitch_info_json::get_datacenter.unset(r);
|
||||
httpd::endpoint_snitch_info_json::get_rack.unset(r);
|
||||
httpd::endpoint_snitch_info_json::get_snitch_name.unset(r);
|
||||
httpd::storage_service_json::update_snitch.unset(r);
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "api/api_init.hh"
|
||||
#include "api.hh"
|
||||
|
||||
namespace locator {
|
||||
class snitch_ptr;
|
||||
|
||||
@@ -7,8 +7,10 @@
|
||||
*/
|
||||
|
||||
#include "api/api-doc/error_injection.json.hh"
|
||||
#include "api/api_init.hh"
|
||||
#include "api/api.hh"
|
||||
|
||||
#include <seastar/http/exception.hh>
|
||||
#include "log.hh"
|
||||
#include "utils/error_injection.hh"
|
||||
#include "utils/rjson.hh"
|
||||
#include <seastar/core/future-util.hh>
|
||||
@@ -22,7 +24,7 @@ namespace hf = httpd::error_injection_json;
|
||||
void set_error_injection(http_context& ctx, routes& r) {
|
||||
|
||||
hf::enable_injection.set(r, [](std::unique_ptr<request> req) {
|
||||
sstring injection = req->get_path_param("injection");
|
||||
sstring injection = req->param["injection"];
|
||||
bool one_shot = req->get_query_param("one_shot") == "True";
|
||||
auto params = req->content;
|
||||
|
||||
@@ -54,7 +56,7 @@ void set_error_injection(http_context& ctx, routes& r) {
|
||||
});
|
||||
|
||||
hf::disable_injection.set(r, [](std::unique_ptr<request> req) {
|
||||
sstring injection = req->get_path_param("injection");
|
||||
sstring injection = req->param["injection"];
|
||||
|
||||
auto& errinj = utils::get_local_injector();
|
||||
return errinj.disable_on_all(injection).then([] {
|
||||
@@ -62,32 +64,6 @@ void set_error_injection(http_context& ctx, routes& r) {
|
||||
});
|
||||
});
|
||||
|
||||
hf::read_injection.set(r, [](std::unique_ptr<request> req) -> future<json::json_return_type> {
|
||||
const sstring injection = req->get_path_param("injection");
|
||||
|
||||
std::vector<error_injection_json::error_injection_info> error_injection_infos(smp::count, error_injection_json::error_injection_info{});
|
||||
|
||||
co_await smp::invoke_on_all([&] {
|
||||
auto& info = error_injection_infos[this_shard_id()];
|
||||
auto& errinj = utils::get_local_injector();
|
||||
const auto enabled = errinj.is_enabled(injection);
|
||||
info.enabled = enabled;
|
||||
if (!enabled) {
|
||||
return;
|
||||
}
|
||||
std::vector<error_injection_json::mapper> parameters;
|
||||
for (const auto& p : errinj.get_injection_parameters(injection)) {
|
||||
error_injection_json::mapper param;
|
||||
param.key = p.first;
|
||||
param.value = p.second;
|
||||
parameters.push_back(std::move(param));
|
||||
}
|
||||
info.parameters = std::move(parameters);
|
||||
});
|
||||
|
||||
co_return json::json_return_type(error_injection_infos);
|
||||
});
|
||||
|
||||
hf::disable_on_all.set(r, [](std::unique_ptr<request> req) {
|
||||
auto& errinj = utils::get_local_injector();
|
||||
return errinj.disable_on_all().then([] {
|
||||
@@ -96,7 +72,7 @@ void set_error_injection(http_context& ctx, routes& r) {
|
||||
});
|
||||
|
||||
hf::message_injection.set(r, [](std::unique_ptr<request> req) {
|
||||
sstring injection = req->get_path_param("injection");
|
||||
sstring injection = req->param["injection"];
|
||||
auto& errinj = utils::get_local_injector();
|
||||
return errinj.receive_message_on_all(injection).then([] {
|
||||
return make_ready_future<json::json_return_type>(json::json_void());
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "api/api_init.hh"
|
||||
#include "api.hh"
|
||||
|
||||
namespace api {
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
*/
|
||||
|
||||
#include "failure_detector.hh"
|
||||
#include "api/api.hh"
|
||||
#include "api/api-doc/failure_detector.json.hh"
|
||||
#include "gms/application_state.hh"
|
||||
#include "gms/gossiper.hh"
|
||||
@@ -19,43 +18,37 @@ namespace fd = httpd::failure_detector_json;
|
||||
|
||||
void set_failure_detector(http_context& ctx, routes& r, gms::gossiper& g) {
|
||||
fd::get_all_endpoint_states.set(r, [&g](std::unique_ptr<request> req) {
|
||||
return g.container().invoke_on(0, [] (gms::gossiper& g) {
|
||||
std::vector<fd::endpoint_state> res;
|
||||
res.reserve(g.num_endpoints());
|
||||
g.for_each_endpoint_state([&] (const gms::inet_address& addr, const gms::endpoint_state& eps) {
|
||||
fd::endpoint_state val;
|
||||
val.addrs = fmt::to_string(addr);
|
||||
val.is_alive = g.is_alive(addr);
|
||||
val.generation = eps.get_heart_beat_state().get_generation().value();
|
||||
val.version = eps.get_heart_beat_state().get_heart_beat_version().value();
|
||||
val.update_time = eps.get_update_timestamp().time_since_epoch().count();
|
||||
for (const auto& [as_type, app_state] : eps.get_application_state_map()) {
|
||||
fd::version_value version_val;
|
||||
// We return the enum index and not it's name to stay compatible to origin
|
||||
// method that the state index are static but the name can be changed.
|
||||
version_val.application_state = static_cast<std::underlying_type<gms::application_state>::type>(as_type);
|
||||
version_val.value = app_state.value();
|
||||
version_val.version = app_state.version().value();
|
||||
val.application_state.push(version_val);
|
||||
}
|
||||
res.emplace_back(std::move(val));
|
||||
});
|
||||
return make_ready_future<json::json_return_type>(res);
|
||||
std::vector<fd::endpoint_state> res;
|
||||
res.reserve(g.num_endpoints());
|
||||
g.for_each_endpoint_state([&] (const gms::inet_address& addr, const gms::endpoint_state& eps) {
|
||||
fd::endpoint_state val;
|
||||
val.addrs = fmt::to_string(addr);
|
||||
val.is_alive = g.is_alive(addr);
|
||||
val.generation = eps.get_heart_beat_state().get_generation().value();
|
||||
val.version = eps.get_heart_beat_state().get_heart_beat_version().value();
|
||||
val.update_time = eps.get_update_timestamp().time_since_epoch().count();
|
||||
for (const auto& [as_type, app_state] : eps.get_application_state_map()) {
|
||||
fd::version_value version_val;
|
||||
// We return the enum index and not it's name to stay compatible to origin
|
||||
// method that the state index are static but the name can be changed.
|
||||
version_val.application_state = static_cast<std::underlying_type<gms::application_state>::type>(as_type);
|
||||
version_val.value = app_state.value();
|
||||
version_val.version = app_state.version().value();
|
||||
val.application_state.push(version_val);
|
||||
}
|
||||
res.emplace_back(std::move(val));
|
||||
});
|
||||
return make_ready_future<json::json_return_type>(res);
|
||||
});
|
||||
|
||||
fd::get_up_endpoint_count.set(r, [&g](std::unique_ptr<request> req) {
|
||||
return g.container().invoke_on(0, [] (gms::gossiper& g) {
|
||||
int res = g.get_up_endpoint_count();
|
||||
return make_ready_future<json::json_return_type>(res);
|
||||
});
|
||||
int res = g.get_up_endpoint_count();
|
||||
return make_ready_future<json::json_return_type>(res);
|
||||
});
|
||||
|
||||
fd::get_down_endpoint_count.set(r, [&g](std::unique_ptr<request> req) {
|
||||
return g.container().invoke_on(0, [] (gms::gossiper& g) {
|
||||
int res = g.get_down_endpoint_count();
|
||||
return make_ready_future<json::json_return_type>(res);
|
||||
});
|
||||
int res = g.get_down_endpoint_count();
|
||||
return make_ready_future<json::json_return_type>(res);
|
||||
});
|
||||
|
||||
fd::get_phi_convict_threshold.set(r, [] (std::unique_ptr<request> req) {
|
||||
@@ -63,13 +56,11 @@ void set_failure_detector(http_context& ctx, routes& r, gms::gossiper& g) {
|
||||
});
|
||||
|
||||
fd::get_simple_states.set(r, [&g] (std::unique_ptr<request> req) {
|
||||
return g.container().invoke_on(0, [] (gms::gossiper& g) {
|
||||
std::map<sstring, sstring> nodes_status;
|
||||
g.for_each_endpoint_state([&] (const gms::inet_address& node, const gms::endpoint_state&) {
|
||||
nodes_status.emplace(fmt::to_string(node), g.is_alive(node) ? "UP" : "DOWN");
|
||||
});
|
||||
return make_ready_future<json::json_return_type>(map_to_key_value<fd::mapper>(nodes_status));
|
||||
std::map<sstring, sstring> nodes_status;
|
||||
g.for_each_endpoint_state([&] (const gms::inet_address& node, const gms::endpoint_state&) {
|
||||
nodes_status.emplace(node.to_sstring(), g.is_alive(node) ? "UP" : "DOWN");
|
||||
});
|
||||
return make_ready_future<json::json_return_type>(map_to_key_value<fd::mapper>(nodes_status));
|
||||
});
|
||||
|
||||
fd::set_phi_convict_threshold.set(r, [](std::unique_ptr<request> req) {
|
||||
@@ -80,15 +71,13 @@ void set_failure_detector(http_context& ctx, routes& r, gms::gossiper& g) {
|
||||
});
|
||||
|
||||
fd::get_endpoint_state.set(r, [&g] (std::unique_ptr<request> req) {
|
||||
return g.container().invoke_on(0, [req = std::move(req)] (gms::gossiper& g) {
|
||||
auto state = g.get_endpoint_state_ptr(gms::inet_address(req->get_path_param("addr")));
|
||||
if (!state) {
|
||||
return make_ready_future<json::json_return_type>(format("unknown endpoint {}", req->get_path_param("addr")));
|
||||
}
|
||||
std::stringstream ss;
|
||||
g.append_endpoint_state(ss, *state);
|
||||
return make_ready_future<json::json_return_type>(sstring(ss.str()));
|
||||
});
|
||||
auto state = g.get_endpoint_state_ptr(gms::inet_address(req->param["addr"]));
|
||||
if (!state) {
|
||||
return make_ready_future<json::json_return_type>(format("unknown endpoint {}", req->param["addr"]));
|
||||
}
|
||||
std::stringstream ss;
|
||||
g.append_endpoint_state(ss, *state);
|
||||
return make_ready_future<json::json_return_type>(sstring(ss.str()));
|
||||
});
|
||||
|
||||
fd::get_endpoint_phi_values.set(r, [](std::unique_ptr<request> req) {
|
||||
@@ -99,16 +88,5 @@ void set_failure_detector(http_context& ctx, routes& r, gms::gossiper& g) {
|
||||
});
|
||||
}
|
||||
|
||||
void unset_failure_detector(http_context& ctx, routes& r) {
|
||||
fd::get_all_endpoint_states.unset(r);
|
||||
fd::get_up_endpoint_count.unset(r);
|
||||
fd::get_down_endpoint_count.unset(r);
|
||||
fd::get_phi_convict_threshold.unset(r);
|
||||
fd::get_simple_states.unset(r);
|
||||
fd::set_phi_convict_threshold.unset(r);
|
||||
fd::get_endpoint_state.unset(r);
|
||||
fd::get_endpoint_phi_values.unset(r);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "api_init.hh"
|
||||
#include "api.hh"
|
||||
|
||||
namespace gms {
|
||||
|
||||
@@ -19,6 +19,5 @@ class gossiper;
|
||||
namespace api {
|
||||
|
||||
void set_failure_detector(http_context& ctx, httpd::routes& r, gms::gossiper& g);
|
||||
void unset_failure_detector(http_context& ctx, httpd::routes& r);
|
||||
|
||||
}
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
#include "api/api-doc/gossiper.json.hh"
|
||||
#include "gms/endpoint_state.hh"
|
||||
#include "gms/gossiper.hh"
|
||||
#include "api/api.hh"
|
||||
|
||||
namespace api {
|
||||
using namespace seastar::httpd;
|
||||
@@ -32,21 +31,21 @@ void set_gossiper(http_context& ctx, routes& r, gms::gossiper& g) {
|
||||
});
|
||||
|
||||
httpd::gossiper_json::get_endpoint_downtime.set(r, [&g] (std::unique_ptr<request> req) -> future<json::json_return_type> {
|
||||
gms::inet_address ep(req->get_path_param("addr"));
|
||||
gms::inet_address ep(req->param["addr"]);
|
||||
// synchronize unreachable_members on all shards
|
||||
co_await g.get_unreachable_members_synchronized();
|
||||
co_return g.get_endpoint_downtime(ep);
|
||||
});
|
||||
|
||||
httpd::gossiper_json::get_current_generation_number.set(r, [&g] (std::unique_ptr<http::request> req) {
|
||||
gms::inet_address ep(req->get_path_param("addr"));
|
||||
gms::inet_address ep(req->param["addr"]);
|
||||
return g.get_current_generation_number(ep).then([] (gms::generation_type res) {
|
||||
return make_ready_future<json::json_return_type>(res.value());
|
||||
});
|
||||
});
|
||||
|
||||
httpd::gossiper_json::get_current_heart_beat_version.set(r, [&g] (std::unique_ptr<http::request> req) {
|
||||
gms::inet_address ep(req->get_path_param("addr"));
|
||||
gms::inet_address ep(req->param["addr"]);
|
||||
return g.get_current_heart_beat_version(ep).then([] (gms::version_type res) {
|
||||
return make_ready_future<json::json_return_type>(res.value());
|
||||
});
|
||||
@@ -54,31 +53,21 @@ void set_gossiper(http_context& ctx, routes& r, gms::gossiper& g) {
|
||||
|
||||
httpd::gossiper_json::assassinate_endpoint.set(r, [&g](std::unique_ptr<http::request> req) {
|
||||
if (req->get_query_param("unsafe") != "True") {
|
||||
return g.assassinate_endpoint(req->get_path_param("addr")).then([] {
|
||||
return g.assassinate_endpoint(req->param["addr"]).then([] {
|
||||
return make_ready_future<json::json_return_type>(json_void());
|
||||
});
|
||||
}
|
||||
return g.unsafe_assassinate_endpoint(req->get_path_param("addr")).then([] {
|
||||
return g.unsafe_assassinate_endpoint(req->param["addr"]).then([] {
|
||||
return make_ready_future<json::json_return_type>(json_void());
|
||||
});
|
||||
});
|
||||
|
||||
httpd::gossiper_json::force_remove_endpoint.set(r, [&g](std::unique_ptr<http::request> req) {
|
||||
gms::inet_address ep(req->get_path_param("addr"));
|
||||
gms::inet_address ep(req->param["addr"]);
|
||||
return g.force_remove_endpoint(ep, gms::null_permit_id).then([] {
|
||||
return make_ready_future<json::json_return_type>(json_void());
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
void unset_gossiper(http_context& ctx, routes& r) {
|
||||
httpd::gossiper_json::get_down_endpoint.unset(r);
|
||||
httpd::gossiper_json::get_live_endpoint.unset(r);
|
||||
httpd::gossiper_json::get_endpoint_downtime.unset(r);
|
||||
httpd::gossiper_json::get_current_generation_number.unset(r);
|
||||
httpd::gossiper_json::get_current_heart_beat_version.unset(r);
|
||||
httpd::gossiper_json::assassinate_endpoint.unset(r);
|
||||
httpd::gossiper_json::force_remove_endpoint.unset(r);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "api/api_init.hh"
|
||||
#include "api.hh"
|
||||
|
||||
namespace gms {
|
||||
|
||||
@@ -19,6 +19,5 @@ class gossiper;
|
||||
namespace api {
|
||||
|
||||
void set_gossiper(http_context& ctx, httpd::routes& r, gms::gossiper& g);
|
||||
void unset_gossiper(http_context& ctx, httpd::routes& r);
|
||||
|
||||
}
|
||||
|
||||
@@ -6,10 +6,10 @@
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
#include "hinted_handoff.hh"
|
||||
#include "api/api.hh"
|
||||
#include "api/api-doc/hinted_handoff.json.hh"
|
||||
|
||||
#include "gms/inet_address.hh"
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <seastar/core/sharded.hh>
|
||||
#include "api/api_init.hh"
|
||||
#include "api.hh"
|
||||
|
||||
namespace service { class storage_proxy; }
|
||||
|
||||
|
||||
@@ -8,10 +8,12 @@
|
||||
|
||||
#include "api/api-doc/lsa.json.hh"
|
||||
#include "api/lsa.hh"
|
||||
#include "api/api.hh"
|
||||
|
||||
#include <seastar/http/exception.hh>
|
||||
#include "utils/logalloc.hh"
|
||||
#include "log.hh"
|
||||
#include "replica/database.hh"
|
||||
|
||||
namespace api {
|
||||
using namespace seastar::httpd;
|
||||
@@ -19,9 +21,9 @@ using namespace seastar::httpd;
|
||||
static logging::logger alogger("lsa-api");
|
||||
|
||||
void set_lsa(http_context& ctx, routes& r) {
|
||||
httpd::lsa_json::lsa_compact.set(r, [](std::unique_ptr<request> req) {
|
||||
httpd::lsa_json::lsa_compact.set(r, [&ctx](std::unique_ptr<request> req) {
|
||||
alogger.info("Triggering compaction");
|
||||
return smp::invoke_on_all([] {
|
||||
return ctx.db.invoke_on_all([] (replica::database&) {
|
||||
logalloc::shard_tracker().reclaim(std::numeric_limits<size_t>::max());
|
||||
}).then([] {
|
||||
return json::json_return_type(json::json_void());
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "api/api_init.hh"
|
||||
#include "api.hh"
|
||||
|
||||
namespace api {
|
||||
|
||||
|
||||
@@ -10,8 +10,8 @@
|
||||
#include "message/messaging_service.hh"
|
||||
#include <seastar/rpc/rpc_types.hh>
|
||||
#include "api/api-doc/messaging_service.json.hh"
|
||||
#include "api/api-doc/error_injection.json.hh"
|
||||
#include "api/api.hh"
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
using namespace seastar::httpd;
|
||||
using namespace httpd::messaging_service_json;
|
||||
@@ -19,8 +19,6 @@ using namespace netw;
|
||||
|
||||
namespace api {
|
||||
|
||||
namespace hf = httpd::error_injection_json;
|
||||
|
||||
using shard_info = messaging_service::shard_info;
|
||||
using msg_addr = messaging_service::msg_addr;
|
||||
|
||||
@@ -114,7 +112,7 @@ void set_messaging_service(http_context& ctx, routes& r, sharded<netw::messaging
|
||||
}));
|
||||
|
||||
get_version.set(r, [&ms](const_req req) {
|
||||
return ms.local().get_raw_version(gms::inet_address(req.get_query_param("addr")));
|
||||
return ms.local().get_raw_version(req.get_query_param("addr"));
|
||||
});
|
||||
|
||||
get_dropped_messages_by_ver.set(r, [&ms](std::unique_ptr<request> req) {
|
||||
@@ -144,14 +142,6 @@ void set_messaging_service(http_context& ctx, routes& r, sharded<netw::messaging
|
||||
return make_ready_future<json::json_return_type>(res);
|
||||
});
|
||||
});
|
||||
|
||||
hf::inject_disconnect.set(r, [&ms] (std::unique_ptr<request> req) -> future<json::json_return_type> {
|
||||
auto ip = msg_addr(req->get_path_param("ip"));
|
||||
co_await ms.invoke_on_all([ip] (netw::messaging_service& ms) {
|
||||
ms.remove_rpc_client(ip);
|
||||
});
|
||||
co_return json::json_void();
|
||||
});
|
||||
}
|
||||
|
||||
void unset_messaging_service(http_context& ctx, routes& r) {
|
||||
@@ -165,7 +155,6 @@ void unset_messaging_service(http_context& ctx, routes& r) {
|
||||
get_respond_completed_messages.unset(r);
|
||||
get_version.unset(r);
|
||||
get_dropped_messages_by_ver.unset(r);
|
||||
hf::inject_disconnect.unset(r);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user