mirror of
https://github.com/scylladb/scylladb.git
synced 2026-05-01 21:55:50 +00:00
Compare commits
12 Commits
branch-1.2
...
branch-0.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e10588e37a | ||
|
|
bb0aeb9bb2 | ||
|
|
d2c97d9620 | ||
|
|
ddbe20f65c | ||
|
|
88bf12aa0b | ||
|
|
87fdf2ee0d | ||
|
|
d6992189ed | ||
|
|
5bf1afa059 | ||
|
|
b013ed6357 | ||
|
|
d4d0dd9cda | ||
|
|
5865a43400 | ||
|
|
b81292d5d2 |
9
.github/ISSUE_TEMPLATE.md
vendored
9
.github/ISSUE_TEMPLATE.md
vendored
@@ -1,9 +0,0 @@
|
||||
## Installation details
|
||||
Scylla version (or git commit hash):
|
||||
Cluster size:
|
||||
OS (RHEL/CentOS/Ubuntu/AWS AMI):
|
||||
|
||||
## Hardware details (for performance issues)
|
||||
Platform (physical/VM/cloud instance type/docker):
|
||||
Hardware: sockets= cores= hyperthreading= memory=
|
||||
Disks: (SSD/HDD, count)
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -8,4 +8,3 @@ cscope.*
|
||||
dist/ami/files/*.rpm
|
||||
dist/ami/variables.json
|
||||
dist/ami/scylla_deploy.sh
|
||||
*.pyc
|
||||
|
||||
2
.gitmodules
vendored
2
.gitmodules
vendored
@@ -1,6 +1,6 @@
|
||||
[submodule "seastar"]
|
||||
path = seastar
|
||||
url = ../scylla-seastar
|
||||
url = ../seastar
|
||||
ignore = dirty
|
||||
[submodule "swagger-ui"]
|
||||
path = swagger-ui
|
||||
|
||||
103
IDL.md
103
IDL.md
@@ -1,103 +0,0 @@
|
||||
#IDL definition
|
||||
The schema we use similar to c++ schema.
|
||||
Use class or struct similar to the object you need the serializer for.
|
||||
Use namespace when applicable.
|
||||
|
||||
##keywords
|
||||
* class/struct - a class or a struct like C++
|
||||
class/struct can have final or stub marker
|
||||
* namespace - has the same C++ meaning
|
||||
* enum class - has the same C++ meaning
|
||||
* final modifier for class - when a class mark as final it will not contain a size parameter. Note that final class cannot be extended by future version, so use with care
|
||||
* stub class - when a class is mark as stub, it means that no code will be generated for this class and it is only there as a documentation.
|
||||
* version attributes - mark with [[version id ]] mark that a field is available from a specific version
|
||||
* template - A template class definition like C++
|
||||
##Syntax
|
||||
|
||||
###Namespace
|
||||
```
|
||||
namespace ns_name { namespace-body }
|
||||
```
|
||||
* ns_name: either a previously unused identifier, in which case this is original-namespace-definition or the name of a namespace, in which case this is extension-namespace-definition
|
||||
* namespace-body: possibly empty sequence of declarations of any kind (including class and struct definitions as well as nested namespaces)
|
||||
|
||||
###class/struct
|
||||
`
|
||||
class-key class-name final(optional) stub(optional) { member-specification } ;(optional)
|
||||
`
|
||||
* class-key: one of class or struct.
|
||||
* class-name: the name of the class that's being defined. optionally followed by keyword final, optionally followed by keyword stub
|
||||
* final: when a class mark as final, it means it can not be extended and there is no need to serialize its size, use with care.
|
||||
* stub: when a class is mark as stub, it means no code will generate for it and it is added for documentation only.
|
||||
* member-specification: list of access specifiers, and public member accessor see class member below.
|
||||
* to be compatible with C++ a class definition can be followed by a semicolon.
|
||||
###enum
|
||||
`enum-key identifier enum-base { enumerator-list(optional) }`
|
||||
* enum-key: only enum class is supported
|
||||
* identifier: the name of the enumeration that's being declared.
|
||||
* enum-base: colon (:), followed by a type-specifier-seq that names an integral type (see the C++ standard for the full list of all possible integral types).
|
||||
* enumerator-list: comma-separated list of enumerator definitions, each of which is either simply an identifier, which becomes the name of the enumerator, or an identifier with an initializer: identifier = integral value.
|
||||
Note that though C++ allows constexpr as an initialize value, it makes the documentation less readable, hence is not permitted.
|
||||
|
||||
###class member
|
||||
`type member-access attributes(optional) default-value(optional);`
|
||||
* type: Any valid C++ type, following the C++ notation. note that there should be a serializer for the type, but deceleration order is not mandatory
|
||||
* member-access: is the way the member can be access. If the member is public it can be the name itself. if not it could be a getter function that should be followed by braces. Note that getter can (and probably should) be const methods.
|
||||
* attributes: Attributes define by square brackets. Currently are use to mark a version in which a specific member was added [ [ version version-number] ] would mark that the specific member was added in the given version number.
|
||||
|
||||
###template
|
||||
`template < parameter-list > class-declaration`
|
||||
* parameter-list - a non-empty comma-separated list of the template parameters.
|
||||
* class-decleration - (See class section) The class name declared become a template name.
|
||||
|
||||
##IDL example
|
||||
Forward slashes comments are ignored until the end of the line.
|
||||
```
|
||||
namespace utils {
|
||||
// An example of a stub class
|
||||
class UUID stub {
|
||||
int64_t most_sig_bits;
|
||||
int64_t least_sig_bits;
|
||||
}
|
||||
}
|
||||
|
||||
namespace gms {
|
||||
//an enum example
|
||||
enum class application_state:int {STATUS = 0,
|
||||
LOAD,
|
||||
SCHEMA,
|
||||
DC};
|
||||
|
||||
// example of final class
|
||||
class versioned_value final {
|
||||
// getter and setter as public member
|
||||
int version;
|
||||
sstring value;
|
||||
}
|
||||
|
||||
class heart_beat_state {
|
||||
//getter as function
|
||||
int32_t get_generation();
|
||||
//default value example
|
||||
int32_t get_heart_beat_version() = 1;
|
||||
}
|
||||
|
||||
class endpoint_state {
|
||||
heart_beat_state get_heart_beat_state();
|
||||
std::map<application_state, versioned_value> get_application_state_map();
|
||||
}
|
||||
|
||||
class gossip_digest {
|
||||
inet_address get_endpoint();
|
||||
int32_t get_generation();
|
||||
//mark that a field was added on a specific version
|
||||
int32_t get_max_version() [ [version 0.14.2] ];
|
||||
}
|
||||
|
||||
class gossip_digest_ack {
|
||||
std::vector<gossip_digest> digests();
|
||||
std::map<inet_address, gms::endpoint_state> get_endpoint_state_map();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -15,7 +15,7 @@ git submodule update --recursive
|
||||
* Installing required packages:
|
||||
|
||||
```
|
||||
sudo yum install yaml-cpp-devel lz4-devel zlib-devel snappy-devel jsoncpp-devel thrift-devel antlr3-tool antlr3-C++-devel libasan libubsan gcc-c++ gnutls-devel ninja-build ragel libaio-devel cryptopp-devel xfsprogs-devel numactl-devel hwloc-devel libpciaccess-devel libxml2-devel python3-pyparsing lksctp-tools-devel
|
||||
sudo yum install yaml-cpp-devel lz4-devel zlib-devel snappy-devel jsoncpp-devel thrift-devel antlr3-tool antlr3-C++-devel libasan libubsan gcc-c++ gnutls-devel ninja-build ragel libaio-devel cryptopp-devel xfsprogs-devel
|
||||
```
|
||||
|
||||
* Build Scylla
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/bin/sh
|
||||
|
||||
VERSION=1.2.6
|
||||
VERSION=0.16
|
||||
|
||||
if test -f version
|
||||
then
|
||||
|
||||
@@ -487,36 +487,6 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/cache_service/metrics/row/hits_moving_avrage",
|
||||
"operations": [
|
||||
{
|
||||
"method": "GET",
|
||||
"summary": "Get row hits moving avrage",
|
||||
"type": "#/utils/rate_moving_average",
|
||||
"nickname": "get_row_hits_moving_avrage",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"parameters": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/cache_service/metrics/row/requests_moving_avrage",
|
||||
"operations": [
|
||||
{
|
||||
"method": "GET",
|
||||
"summary": "Get row requests moving avrage",
|
||||
"type": "#/utils/rate_moving_average",
|
||||
"nickname": "get_row_requests_moving_avrage",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"parameters": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/cache_service/metrics/row/size",
|
||||
"operations": [
|
||||
|
||||
@@ -1094,7 +1094,7 @@
|
||||
"method":"GET",
|
||||
"summary":"Get read latency histogram",
|
||||
"$ref": "#/utils/histogram",
|
||||
"nickname":"get_read_latency_histogram_depricated",
|
||||
"nickname":"get_read_latency_histogram",
|
||||
"produces":[
|
||||
"application/json"
|
||||
],
|
||||
@@ -1121,49 +1121,6 @@
|
||||
"items":{
|
||||
"$ref": "#/utils/histogram"
|
||||
},
|
||||
"nickname":"get_all_read_latency_histogram_depricated",
|
||||
"produces":[
|
||||
"application/json"
|
||||
],
|
||||
"parameters":[
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"path":"/column_family/metrics/read_latency/moving_average_histogram/{name}",
|
||||
"operations":[
|
||||
{
|
||||
"method":"GET",
|
||||
"summary":"Get read latency moving avrage histogram",
|
||||
"$ref": "#/utils/rate_moving_average_and_histogram",
|
||||
"nickname":"get_read_latency_histogram",
|
||||
"produces":[
|
||||
"application/json"
|
||||
],
|
||||
"parameters":[
|
||||
{
|
||||
"name":"name",
|
||||
"description":"The column family name in keysspace:name format",
|
||||
"required":true,
|
||||
"allowMultiple":false,
|
||||
"type":"string",
|
||||
"paramType":"path"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"path":"/column_family/metrics/read_latency/moving_average_histogram/",
|
||||
"operations":[
|
||||
{
|
||||
"method":"GET",
|
||||
"summary":"Get read latency moving avrage histogram from all column family",
|
||||
"type":"array",
|
||||
"items":{
|
||||
"$ref": "#/utils/rate_moving_average_and_histogram"
|
||||
},
|
||||
"nickname":"get_all_read_latency_histogram",
|
||||
"produces":[
|
||||
"application/json"
|
||||
@@ -1303,7 +1260,7 @@
|
||||
"method":"GET",
|
||||
"summary":"Get write latency histogram",
|
||||
"$ref": "#/utils/histogram",
|
||||
"nickname":"get_write_latency_histogram_depricated",
|
||||
"nickname":"get_write_latency_histogram",
|
||||
"produces":[
|
||||
"application/json"
|
||||
],
|
||||
@@ -1330,49 +1287,6 @@
|
||||
"items":{
|
||||
"$ref": "#/utils/histogram"
|
||||
},
|
||||
"nickname":"get_all_write_latency_histogram_depricated",
|
||||
"produces":[
|
||||
"application/json"
|
||||
],
|
||||
"parameters":[
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"path":"/column_family/metrics/write_latency/moving_average_histogram/{name}",
|
||||
"operations":[
|
||||
{
|
||||
"method":"GET",
|
||||
"summary":"Get write latency moving average histogram",
|
||||
"$ref": "#/utils/rate_moving_average_and_histogram",
|
||||
"nickname":"get_write_latency_histogram",
|
||||
"produces":[
|
||||
"application/json"
|
||||
],
|
||||
"parameters":[
|
||||
{
|
||||
"name":"name",
|
||||
"description":"The column family name in keysspace:name format",
|
||||
"required":true,
|
||||
"allowMultiple":false,
|
||||
"type":"string",
|
||||
"paramType":"path"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"path":"/column_family/metrics/write_latency/moving_average_histogram/",
|
||||
"operations":[
|
||||
{
|
||||
"method":"GET",
|
||||
"summary":"Get write latency moving average histogram of all column family",
|
||||
"type":"array",
|
||||
"items":{
|
||||
"$ref": "#/utils/rate_moving_average_and_histogram"
|
||||
},
|
||||
"nickname":"get_all_write_latency_histogram",
|
||||
"produces":[
|
||||
"application/json"
|
||||
|
||||
@@ -106,7 +106,7 @@
|
||||
"required":true,
|
||||
"allowMultiple":false,
|
||||
"type":"string",
|
||||
"paramType":"query"
|
||||
"paramType":"string"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -196,10 +196,6 @@
|
||||
"value": {
|
||||
"type": "string",
|
||||
"description": "The version value"
|
||||
},
|
||||
"version": {
|
||||
"type": "int",
|
||||
"description": "The application state version"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -234,12 +234,12 @@
|
||||
"type":"string",
|
||||
"enum":[
|
||||
"CLIENT_ID",
|
||||
"ECHO",
|
||||
"MUTATION",
|
||||
"MUTATION_DONE",
|
||||
"READ_DATA",
|
||||
"READ_MUTATION_DATA",
|
||||
"READ_DIGEST",
|
||||
"GOSSIP_ECHO",
|
||||
"GOSSIP_DIGEST_SYN",
|
||||
"GOSSIP_DIGEST_ACK2",
|
||||
"GOSSIP_SHUTDOWN",
|
||||
@@ -247,6 +247,7 @@
|
||||
"TRUNCATE",
|
||||
"REPLICATION_FINISHED",
|
||||
"MIGRATION_REQUEST",
|
||||
"STREAM_INIT_MESSAGE",
|
||||
"PREPARE_MESSAGE",
|
||||
"PREPARE_DONE_MESSAGE",
|
||||
"STREAM_MUTATION",
|
||||
|
||||
@@ -716,36 +716,6 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/storage_proxy/metrics/read/timeouts_rates",
|
||||
"operations": [
|
||||
{
|
||||
"method": "GET",
|
||||
"summary": "Get read metrics rates",
|
||||
"type": "#/utils/rate_moving_average",
|
||||
"nickname": "get_read_metrics_timeouts_rates",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"parameters": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/storage_proxy/metrics/read/unavailables_rates",
|
||||
"operations": [
|
||||
{
|
||||
"method": "GET",
|
||||
"summary": "Get read metrics rates",
|
||||
"type": "#/utils/rate_moving_average",
|
||||
"nickname": "get_read_metrics_unavailables_rates",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"parameters": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/storage_proxy/metrics/read/histogram",
|
||||
"operations": [
|
||||
@@ -753,7 +723,7 @@
|
||||
"method": "GET",
|
||||
"summary": "Get read metrics",
|
||||
"$ref": "#/utils/histogram",
|
||||
"nickname": "get_read_metrics_latency_histogram_depricated",
|
||||
"nickname": "get_read_metrics_latency_histogram",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
@@ -768,36 +738,6 @@
|
||||
"method": "GET",
|
||||
"summary": "Get range metrics",
|
||||
"$ref": "#/utils/histogram",
|
||||
"nickname": "get_range_metrics_latency_histogram_depricated",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"parameters": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/storage_proxy/metrics/read/moving_avrage_histogram",
|
||||
"operations": [
|
||||
{
|
||||
"method": "GET",
|
||||
"summary": "Get read metrics",
|
||||
"$ref": "#/utils/rate_moving_average_and_histogram",
|
||||
"nickname": "get_read_metrics_latency_histogram",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"parameters": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/storage_proxy/metrics/range/moving_avrage_histogram",
|
||||
"operations": [
|
||||
{
|
||||
"method": "GET",
|
||||
"summary": "Get range metrics rate and histogram",
|
||||
"$ref": "#/utils/rate_moving_average_and_histogram",
|
||||
"nickname": "get_range_metrics_latency_histogram",
|
||||
"produces": [
|
||||
"application/json"
|
||||
@@ -836,36 +776,6 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/storage_proxy/metrics/range/timeouts_rates",
|
||||
"operations": [
|
||||
{
|
||||
"method": "GET",
|
||||
"summary": "Get range metrics rates",
|
||||
"type": "#/utils/rate_moving_average",
|
||||
"nickname": "get_range_metrics_timeouts_rates",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"parameters": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/storage_proxy/metrics/range/unavailables_rates",
|
||||
"operations": [
|
||||
{
|
||||
"method": "GET",
|
||||
"summary": "Get range metrics rates",
|
||||
"type": "#/utils/rate_moving_average",
|
||||
"nickname": "get_range_metrics_unavailables_rates",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"parameters": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/storage_proxy/metrics/write/timeouts",
|
||||
"operations": [
|
||||
@@ -896,36 +806,6 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/storage_proxy/metrics/write/timeouts_rates",
|
||||
"operations": [
|
||||
{
|
||||
"method": "GET",
|
||||
"summary": "Get write metrics rates",
|
||||
"type": "#/utils/rate_moving_average",
|
||||
"nickname": "get_write_metrics_timeouts_rates",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"parameters": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/storage_proxy/metrics/write/unavailables_rates",
|
||||
"operations": [
|
||||
{
|
||||
"method": "GET",
|
||||
"summary": "Get write metrics rates",
|
||||
"type": "#/utils/rate_moving_average",
|
||||
"nickname": "get_write_metrics_unavailables_rates",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"parameters": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/storage_proxy/metrics/write/histogram",
|
||||
"operations": [
|
||||
@@ -933,21 +813,6 @@
|
||||
"method": "GET",
|
||||
"summary": "Get write metrics",
|
||||
"$ref": "#/utils/histogram",
|
||||
"nickname": "get_write_metrics_latency_histogram_depricated",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"parameters": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/storage_proxy/metrics/write/moving_avrage_histogram",
|
||||
"operations": [
|
||||
{
|
||||
"method": "GET",
|
||||
"summary": "Get write metrics",
|
||||
"$ref": "#/utils/rate_moving_average_and_histogram",
|
||||
"nickname": "get_write_metrics_latency_histogram",
|
||||
"produces": [
|
||||
"application/json"
|
||||
|
||||
@@ -836,22 +836,6 @@
|
||||
"type":"string",
|
||||
"paramType":"query"
|
||||
},
|
||||
{
|
||||
"name":"startToken",
|
||||
"description":"Token on which to begin repair",
|
||||
"required":false,
|
||||
"allowMultiple":false,
|
||||
"type":"string",
|
||||
"paramType":"query"
|
||||
},
|
||||
{
|
||||
"name":"endToken",
|
||||
"description":"Token on which to end repair",
|
||||
"required":false,
|
||||
"allowMultiple":false,
|
||||
"type":"string",
|
||||
"paramType":"query"
|
||||
},
|
||||
{
|
||||
"name":"columnFamilies",
|
||||
"description":"Which column families to repair in the given keyspace. Multiple columns families can be named separated by commas. If this option is missing, all column families in the keyspace are repaired.",
|
||||
|
||||
@@ -65,41 +65,6 @@
|
||||
"description":"The series of values to which the counts in `buckets` correspond"
|
||||
}
|
||||
}
|
||||
},
|
||||
"rate_moving_average": {
|
||||
"id":"rate_moving_average",
|
||||
"description":"A meter metric which measures mean throughput and one, five, and fifteen-minute exponentially-weighted moving average throughputs",
|
||||
"properties":{
|
||||
"rates": {
|
||||
"type":"array",
|
||||
"items":{
|
||||
"type":"double"
|
||||
},
|
||||
"description":"One, five and fifteen mintues rates"
|
||||
},
|
||||
"mean_rate": {
|
||||
"type":"double",
|
||||
"description":"The mean rate from startup"
|
||||
},
|
||||
"count": {
|
||||
"type":"long",
|
||||
"description":"Total number of events from startup"
|
||||
}
|
||||
}
|
||||
},
|
||||
"rate_moving_average_and_histogram": {
|
||||
"id":"rate_moving_average_and_histogram",
|
||||
"description":"A timer metric which aggregates timing durations and provides duration statistics, plus throughput statistics",
|
||||
"properties":{
|
||||
"meter": {
|
||||
"type":"rate_moving_average",
|
||||
"description":"The metric rate moving average"
|
||||
},
|
||||
"hist": {
|
||||
"type":"histogram",
|
||||
"description":"The metric histogram"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
127
api/api.cc
127
api/api.cc
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2015 ScyllaDB
|
||||
* Copyright 2015 Cloudius Systems
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -52,98 +52,67 @@ static std::unique_ptr<reply> exception_reply(std::exception_ptr eptr) {
|
||||
return std::make_unique<reply>();
|
||||
}
|
||||
|
||||
future<> set_server_init(http_context& ctx) {
|
||||
future<> set_server(http_context& ctx) {
|
||||
auto rb = std::make_shared < api_registry_builder > (ctx.api_doc);
|
||||
|
||||
return ctx.http_server.set_routes([rb, &ctx](routes& r) {
|
||||
r.register_exeption_handler(exception_reply);
|
||||
httpd::directory_handler* dir = new httpd::directory_handler(ctx.api_dir,
|
||||
new content_replace("html"));
|
||||
r.put(GET, "/ui", new httpd::file_handler(ctx.api_dir + "/index.html",
|
||||
new content_replace("html")));
|
||||
r.add(GET, url("/ui").remainder("path"), new httpd::directory_handler(ctx.api_dir,
|
||||
new content_replace("html")));
|
||||
r.add(GET, url("/ui").remainder("path"), dir);
|
||||
|
||||
rb->set_api_doc(r);
|
||||
rb->register_function(r, "system",
|
||||
"The system related API");
|
||||
set_system(ctx, r);
|
||||
});
|
||||
}
|
||||
rb->register_function(r, "storage_service",
|
||||
"The storage service API");
|
||||
set_storage_service(ctx,r);
|
||||
rb->register_function(r, "commitlog",
|
||||
"The commit log API");
|
||||
set_commitlog(ctx,r);
|
||||
rb->register_function(r, "gossiper",
|
||||
"The gossiper API");
|
||||
set_gossiper(ctx,r);
|
||||
rb->register_function(r, "column_family",
|
||||
"The column family API");
|
||||
set_column_family(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) {
|
||||
auto rb = std::make_shared < api_registry_builder > (ctx.api_doc);
|
||||
|
||||
return ctx.http_server.set_routes([rb, &ctx, api_name, api_desc, f](routes& r) {
|
||||
rb->register_function(r, api_name, api_desc);
|
||||
f(ctx,r);
|
||||
});
|
||||
}
|
||||
|
||||
future<> set_server_storage_service(http_context& ctx) {
|
||||
return register_api(ctx, "storage_service", "The storage service API", set_storage_service);
|
||||
}
|
||||
|
||||
future<> set_server_snitch(http_context& ctx) {
|
||||
return register_api(ctx, "endpoint_snitch_info", "The endpoint snitch info API", set_endpoint_snitch);
|
||||
}
|
||||
|
||||
future<> set_server_gossip(http_context& ctx) {
|
||||
return register_api(ctx, "gossiper",
|
||||
"The gossiper API", set_gossiper);
|
||||
}
|
||||
|
||||
future<> set_server_load_sstable(http_context& ctx) {
|
||||
return register_api(ctx, "column_family",
|
||||
"The column family API", set_column_family);
|
||||
}
|
||||
|
||||
future<> set_server_messaging_service(http_context& ctx) {
|
||||
return register_api(ctx, "messaging_service",
|
||||
"The messaging service API", set_messaging_service);
|
||||
}
|
||||
|
||||
future<> set_server_storage_proxy(http_context& ctx) {
|
||||
return register_api(ctx, "storage_proxy",
|
||||
"The storage proxy API", set_storage_proxy);
|
||||
}
|
||||
|
||||
future<> set_server_stream_manager(http_context& ctx) {
|
||||
return register_api(ctx, "stream_manager",
|
||||
"The stream manager API", set_stream_manager);
|
||||
}
|
||||
|
||||
future<> set_server_gossip_settle(http_context& ctx) {
|
||||
auto rb = std::make_shared < api_registry_builder > (ctx.api_doc);
|
||||
|
||||
return ctx.http_server.set_routes([rb, &ctx](routes& r) {
|
||||
rb->register_function(r, "failure_detector",
|
||||
"The failure detector API");
|
||||
set_failure_detector(ctx,r);
|
||||
rb->register_function(r, "cache_service",
|
||||
"The cache service API");
|
||||
set_cache_service(ctx,r);
|
||||
});
|
||||
}
|
||||
|
||||
future<> set_server_done(http_context& ctx) {
|
||||
auto rb = std::make_shared < api_registry_builder > (ctx.api_doc);
|
||||
|
||||
return ctx.http_server.set_routes([rb, &ctx](routes& r) {
|
||||
rb->register_function(r, "compaction_manager",
|
||||
"The Compaction manager API");
|
||||
set_compaction_manager(ctx, r);
|
||||
rb->register_function(r, "lsa", "Log-structured allocator API");
|
||||
set_lsa(ctx, r);
|
||||
|
||||
rb->register_function(r, "commitlog",
|
||||
"The commit log API");
|
||||
set_commitlog(ctx,r);
|
||||
rb->register_function(r, "hinted_handoff",
|
||||
"The hinted handoff API");
|
||||
set_hinted_handoff(ctx, r);
|
||||
rb->register_function(r, "failure_detector",
|
||||
"The failure detector API");
|
||||
set_failure_detector(ctx,r);
|
||||
|
||||
rb->register_function(r, "messaging_service",
|
||||
"The messaging service API");
|
||||
set_messaging_service(ctx, r);
|
||||
rb->register_function(r, "storage_proxy",
|
||||
"The storage proxy API");
|
||||
set_storage_proxy(ctx, r);
|
||||
|
||||
rb->register_function(r, "cache_service",
|
||||
"The cache service API");
|
||||
set_cache_service(ctx,r);
|
||||
rb->register_function(r, "collectd",
|
||||
"The collectd API");
|
||||
set_collectd(ctx, r);
|
||||
rb->register_function(r, "endpoint_snitch_info",
|
||||
"The endpoint snitch info API");
|
||||
set_endpoint_snitch(ctx, r);
|
||||
rb->register_function(r, "compaction_manager",
|
||||
"The Compaction manager API");
|
||||
set_compaction_manager(ctx, r);
|
||||
rb->register_function(r, "hinted_handoff",
|
||||
"The hinted handoff API");
|
||||
set_hinted_handoff(ctx, r);
|
||||
rb->register_function(r, "stream_manager",
|
||||
"The stream manager API");
|
||||
set_stream_manager(ctx, r);
|
||||
rb->register_function(r, "system",
|
||||
"The system related API");
|
||||
set_system(ctx, r);
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
85
api/api.hh
85
api/api.hh
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2015 ScyllaDB
|
||||
* Copyright 2015 Cloudius Systems
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -21,17 +21,31 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "http/httpd.hh"
|
||||
#include "json/json_elements.hh"
|
||||
#include "database.hh"
|
||||
#include "service/storage_proxy.hh"
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/algorithm/string/split.hpp>
|
||||
#include <boost/algorithm/string/classification.hpp>
|
||||
#include "api/api-doc/utils.json.hh"
|
||||
#include "utils/histogram.hh"
|
||||
#include "http/exception.hh"
|
||||
#include "api_init.hh"
|
||||
|
||||
namespace api {
|
||||
|
||||
struct http_context {
|
||||
sstring api_dir;
|
||||
sstring api_doc;
|
||||
httpd::http_server_control http_server;
|
||||
distributed<database>& db;
|
||||
distributed<service::storage_proxy>& sp;
|
||||
http_context(distributed<database>& _db, distributed<service::storage_proxy>&
|
||||
_sp) : db(_db), sp(_sp) {}
|
||||
};
|
||||
|
||||
future<> set_server(http_context& ctx);
|
||||
|
||||
template<class T>
|
||||
std::vector<sstring> container_to_vec(const T& container) {
|
||||
std::vector<sstring> res;
|
||||
@@ -110,7 +124,44 @@ future<json::json_return_type> sum_stats(distributed<T>& d, V F::*f) {
|
||||
});
|
||||
}
|
||||
|
||||
inline double pow2(double a) {
|
||||
return a * a;
|
||||
}
|
||||
|
||||
// FIXME: Move to utils::ihistogram::operator+=()
|
||||
inline utils::ihistogram add_histogram(utils::ihistogram res,
|
||||
const utils::ihistogram& val) {
|
||||
if (res.count == 0) {
|
||||
return val;
|
||||
}
|
||||
if (val.count == 0) {
|
||||
return std::move(res);
|
||||
}
|
||||
if (res.min > val.min) {
|
||||
res.min = val.min;
|
||||
}
|
||||
if (res.max < val.max) {
|
||||
res.max = val.max;
|
||||
}
|
||||
double ncount = res.count + val.count;
|
||||
// To get an estimated sum we take the estimated mean
|
||||
// and multiply it by the true count
|
||||
res.sum = res.sum + val.mean * val.count;
|
||||
double a = res.count/ncount;
|
||||
double b = val.count/ncount;
|
||||
|
||||
double mean = a * res.mean + b * val.mean;
|
||||
|
||||
res.variance = (res.variance + pow2(res.mean - mean) )* a +
|
||||
(val.variance + pow2(val.mean -mean))* b;
|
||||
|
||||
res.mean = mean;
|
||||
res.count = res.count + val.count;
|
||||
for (auto i : val.sample) {
|
||||
res.sample.push_back(i);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
inline
|
||||
httpd::utils_json::histogram to_json(const utils::ihistogram& val) {
|
||||
@@ -119,39 +170,15 @@ httpd::utils_json::histogram to_json(const utils::ihistogram& val) {
|
||||
return h;
|
||||
}
|
||||
|
||||
inline
|
||||
httpd::utils_json::rate_moving_average meter_to_json(const utils::rate_moving_average& val) {
|
||||
httpd::utils_json::rate_moving_average m;
|
||||
m = val;
|
||||
return m;
|
||||
}
|
||||
|
||||
inline
|
||||
httpd::utils_json::rate_moving_average_and_histogram timer_to_json(const utils::rate_moving_average_and_histogram& val) {
|
||||
httpd::utils_json::rate_moving_average_and_histogram h;
|
||||
h.hist = val.hist;
|
||||
h.meter = meter_to_json(val.rate);
|
||||
return h;
|
||||
}
|
||||
|
||||
template<class T, class F>
|
||||
future<json::json_return_type> sum_histogram_stats(distributed<T>& d, utils::timed_rate_moving_average_and_histogram F::*f) {
|
||||
future<json::json_return_type> sum_histogram_stats(distributed<T>& d, utils::ihistogram F::*f) {
|
||||
|
||||
return d.map_reduce0([f](const T& p) {return (p.get_stats().*f).hist;}, utils::ihistogram(),
|
||||
std::plus<utils::ihistogram>()).then([](const utils::ihistogram& val) {
|
||||
return d.map_reduce0([f](const T& p) {return p.get_stats().*f;}, utils::ihistogram(),
|
||||
add_histogram).then([](const utils::ihistogram& val) {
|
||||
return make_ready_future<json::json_return_type>(to_json(val));
|
||||
});
|
||||
}
|
||||
|
||||
template<class T, class F>
|
||||
future<json::json_return_type> sum_timer_stats(distributed<T>& d, utils::timed_rate_moving_average_and_histogram F::*f) {
|
||||
|
||||
return d.map_reduce0([f](const T& p) {return (p.get_stats().*f).rate();}, utils::rate_moving_average_and_histogram(),
|
||||
std::plus<utils::rate_moving_average_and_histogram>()).then([](const utils::rate_moving_average_and_histogram& val) {
|
||||
return make_ready_future<json::json_return_type>(timer_to_json(val));
|
||||
});
|
||||
}
|
||||
|
||||
inline int64_t min_int64(int64_t a, int64_t b) {
|
||||
return std::min(a,b);
|
||||
}
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
/*
|
||||
* Copyright 2016 ScylaDB
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is part of Scylla.
|
||||
*
|
||||
* Scylla is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Scylla is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Scylla. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include "database.hh"
|
||||
#include "service/storage_proxy.hh"
|
||||
#include "http/httpd.hh"
|
||||
|
||||
namespace api {
|
||||
|
||||
struct http_context {
|
||||
sstring api_dir;
|
||||
sstring api_doc;
|
||||
httpd::http_server_control http_server;
|
||||
distributed<database>& db;
|
||||
distributed<service::storage_proxy>& sp;
|
||||
http_context(distributed<database>& _db,
|
||||
distributed<service::storage_proxy>& _sp)
|
||||
: db(_db), sp(_sp) {
|
||||
}
|
||||
};
|
||||
|
||||
future<> set_server_init(http_context& ctx);
|
||||
future<> set_server_snitch(http_context& ctx);
|
||||
future<> set_server_storage_service(http_context& ctx);
|
||||
future<> set_server_gossip(http_context& ctx);
|
||||
future<> set_server_load_sstable(http_context& ctx);
|
||||
future<> set_server_messaging_service(http_context& ctx);
|
||||
future<> set_server_storage_proxy(http_context& ctx);
|
||||
future<> set_server_stream_manager(http_context& ctx);
|
||||
future<> set_server_gossip_settle(http_context& ctx);
|
||||
future<> set_server_done(http_context& ctx);
|
||||
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2015 ScyllaDB
|
||||
* Copyright 2015 Cloudius Systems
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -200,40 +200,24 @@ void set_cache_service(http_context& ctx, routes& r) {
|
||||
});
|
||||
|
||||
cs::get_row_hits.set(r, [&ctx] (std::unique_ptr<request> req) {
|
||||
return map_reduce_cf(ctx, uint64_t(0), [](const column_family& cf) {
|
||||
return cf.get_row_cache().stats().hits.count();
|
||||
}, std::plus<uint64_t>());
|
||||
return map_reduce_cf(ctx, 0, [](const column_family& cf) {
|
||||
return cf.get_row_cache().stats().hits;
|
||||
}, std::plus<int64_t>());
|
||||
});
|
||||
|
||||
cs::get_row_requests.set(r, [&ctx] (std::unique_ptr<request> req) {
|
||||
return map_reduce_cf(ctx, uint64_t(0), [](const column_family& cf) {
|
||||
return cf.get_row_cache().stats().hits.count() + cf.get_row_cache().stats().misses.count();
|
||||
}, std::plus<uint64_t>());
|
||||
return map_reduce_cf(ctx, 0, [](const column_family& cf) {
|
||||
return cf.get_row_cache().stats().hits + cf.get_row_cache().stats().misses;
|
||||
}, std::plus<int64_t>());
|
||||
});
|
||||
|
||||
cs::get_row_hit_rate.set(r, [&ctx] (std::unique_ptr<request> req) {
|
||||
return map_reduce_cf(ctx, ratio_holder(), [](const column_family& cf) {
|
||||
return ratio_holder(cf.get_row_cache().stats().hits.count() + cf.get_row_cache().stats().misses.count(),
|
||||
cf.get_row_cache().stats().hits.count());
|
||||
return ratio_holder(cf.get_row_cache().stats().hits + cf.get_row_cache().stats().misses,
|
||||
cf.get_row_cache().stats().hits);
|
||||
}, std::plus<ratio_holder>());
|
||||
});
|
||||
|
||||
cs::get_row_hits_moving_avrage.set(r, [&ctx] (std::unique_ptr<request> req) {
|
||||
return map_reduce_cf_raw(ctx, utils::rate_moving_average(), [](const 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));
|
||||
});
|
||||
});
|
||||
|
||||
cs::get_row_requests_moving_avrage.set(r, [&ctx] (std::unique_ptr<request> req) {
|
||||
return map_reduce_cf_raw(ctx, utils::rate_moving_average(), [](const column_family& cf) {
|
||||
return cf.get_row_cache().stats().hits.rate() + 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));
|
||||
});
|
||||
});
|
||||
|
||||
cs::get_row_size.set(r, [&ctx] (std::unique_ptr<request> req) {
|
||||
// In origin row size is the weighted size.
|
||||
// We currently do not support weights, so we use num entries instead
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2015 ScyllaDB
|
||||
* Copyright 2015 Cloudius Systems
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2015 ScyllaDB
|
||||
* Copyright 2015 Cloudius Systems
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2015 ScyllaDB
|
||||
* Copyright 2015 Cloudius Systems
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2015 ScyllaDB
|
||||
* Copyright 2015 Cloudius Systems
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -40,7 +40,7 @@ const utils::UUID& get_uuid(const sstring& name, const database& db) {
|
||||
if (pos == sstring::npos) {
|
||||
pos = name.find(":");
|
||||
if (pos == sstring::npos) {
|
||||
throw bad_param_exception("Column family name should be in keyspace:column_family format");
|
||||
throw bad_param_exception("Column family name should be in keyspace::column_family format");
|
||||
}
|
||||
end = pos + 1;
|
||||
} else {
|
||||
@@ -77,14 +77,14 @@ future<json::json_return_type> get_cf_stats(http_context& ctx,
|
||||
}
|
||||
|
||||
static future<json::json_return_type> get_cf_stats_count(http_context& ctx, const sstring& name,
|
||||
utils::timed_rate_moving_average_and_histogram column_family::stats::*f) {
|
||||
utils::ihistogram column_family::stats::*f) {
|
||||
return map_reduce_cf(ctx, name, int64_t(0), [f](const column_family& cf) {
|
||||
return (cf.get_stats().*f).hist.count;
|
||||
return (cf.get_stats().*f).count;
|
||||
}, std::plus<int64_t>());
|
||||
}
|
||||
|
||||
static future<json::json_return_type> get_cf_stats_sum(http_context& ctx, const sstring& name,
|
||||
utils::timed_rate_moving_average_and_histogram column_family::stats::*f) {
|
||||
utils::ihistogram column_family::stats::*f) {
|
||||
auto uuid = get_uuid(name, ctx.db.local());
|
||||
return ctx.db.map_reduce0([uuid, f](database& db) {
|
||||
// Histograms information is sample of the actual load
|
||||
@@ -92,7 +92,7 @@ static future<json::json_return_type> get_cf_stats_sum(http_context& ctx, const
|
||||
// with count. The information is gather in nano second,
|
||||
// but reported in micro
|
||||
column_family& cf = db.find_column_family(uuid);
|
||||
return ((cf.get_stats().*f).hist.count/1000.0) * (cf.get_stats().*f).hist.mean;
|
||||
return ((cf.get_stats().*f).count/1000.0) * (cf.get_stats().*f).mean;
|
||||
}, 0.0, std::plus<double>()).then([](double res) {
|
||||
return make_ready_future<json::json_return_type>((int64_t)res);
|
||||
});
|
||||
@@ -100,29 +100,28 @@ static future<json::json_return_type> get_cf_stats_sum(http_context& ctx, const
|
||||
|
||||
|
||||
static future<json::json_return_type> get_cf_stats_count(http_context& ctx,
|
||||
utils::timed_rate_moving_average_and_histogram column_family::stats::*f) {
|
||||
utils::ihistogram column_family::stats::*f) {
|
||||
return map_reduce_cf(ctx, int64_t(0), [f](const column_family& cf) {
|
||||
return (cf.get_stats().*f).hist.count;
|
||||
return (cf.get_stats().*f).count;
|
||||
}, std::plus<int64_t>());
|
||||
}
|
||||
|
||||
static future<json::json_return_type> get_cf_histogram(http_context& ctx, const sstring& name,
|
||||
utils::timed_rate_moving_average_and_histogram column_family::stats::*f) {
|
||||
utils::ihistogram column_family::stats::*f) {
|
||||
utils::UUID uuid = get_uuid(name, ctx.db.local());
|
||||
return ctx.db.map_reduce0([f, uuid](const database& p) {
|
||||
return (p.find_column_family(uuid).get_stats().*f).hist;},
|
||||
return ctx.db.map_reduce0([f, uuid](const database& p) {return p.find_column_family(uuid).get_stats().*f;},
|
||||
utils::ihistogram(),
|
||||
std::plus<utils::ihistogram>())
|
||||
add_histogram)
|
||||
.then([](const utils::ihistogram& val) {
|
||||
return make_ready_future<json::json_return_type>(to_json(val));
|
||||
});
|
||||
}
|
||||
|
||||
static future<json::json_return_type> get_cf_histogram(http_context& ctx, utils::timed_rate_moving_average_and_histogram column_family::stats::*f) {
|
||||
static future<json::json_return_type> get_cf_histogram(http_context& ctx, utils::ihistogram column_family::stats::*f) {
|
||||
std::function<utils::ihistogram(const database&)> fun = [f] (const database& db) {
|
||||
utils::ihistogram res;
|
||||
for (auto i : db.get_column_families()) {
|
||||
res += (i.second->get_stats().*f).hist;
|
||||
res = add_histogram(res, i.second->get_stats().*f);
|
||||
}
|
||||
return res;
|
||||
};
|
||||
@@ -133,33 +132,6 @@ static future<json::json_return_type> get_cf_histogram(http_context& ctx, utils:
|
||||
});
|
||||
}
|
||||
|
||||
static future<json::json_return_type> get_cf_rate_and_histogram(http_context& ctx, const sstring& name,
|
||||
utils::timed_rate_moving_average_and_histogram column_family::stats::*f) {
|
||||
utils::UUID uuid = get_uuid(name, ctx.db.local());
|
||||
return ctx.db.map_reduce0([f, uuid](const database& p) {
|
||||
return (p.find_column_family(uuid).get_stats().*f).rate();},
|
||||
utils::rate_moving_average_and_histogram(),
|
||||
std::plus<utils::rate_moving_average_and_histogram>())
|
||||
.then([](const utils::rate_moving_average_and_histogram& val) {
|
||||
return make_ready_future<json::json_return_type>(timer_to_json(val));
|
||||
});
|
||||
}
|
||||
|
||||
static future<json::json_return_type> get_cf_rate_and_histogram(http_context& ctx, utils::timed_rate_moving_average_and_histogram column_family::stats::*f) {
|
||||
std::function<utils::rate_moving_average_and_histogram(const database&)> fun = [f] (const database& db) {
|
||||
utils::rate_moving_average_and_histogram res;
|
||||
for (auto i : db.get_column_families()) {
|
||||
res += (i.second->get_stats().*f).rate();
|
||||
}
|
||||
return res;
|
||||
};
|
||||
return ctx.db.map(fun).then([](const std::vector<utils::rate_moving_average_and_histogram> &res) {
|
||||
std::vector<httpd::utils_json::rate_moving_average_and_histogram> r;
|
||||
boost::copy(res | boost::adaptors::transformed(timer_to_json), std::back_inserter(r));
|
||||
return make_ready_future<json::json_return_type>(r);
|
||||
});
|
||||
}
|
||||
|
||||
static future<json::json_return_type> get_cf_unleveled_sstables(http_context& ctx, const sstring& name) {
|
||||
return map_reduce_cf(ctx, name, int64_t(0), [](const column_family& cf) {
|
||||
return cf.get_unleveled_sstables();
|
||||
@@ -201,80 +173,6 @@ static ratio_holder mean_row_size(column_family& cf) {
|
||||
return res;
|
||||
}
|
||||
|
||||
static std::unordered_map<sstring, uint64_t> merge_maps(std::unordered_map<sstring, uint64_t> a,
|
||||
const std::unordered_map<sstring, uint64_t>& b) {
|
||||
a.insert(b.begin(), b.end());
|
||||
return a;
|
||||
}
|
||||
|
||||
static json::json_return_type sum_map(const std::unordered_map<sstring, uint64_t>& val) {
|
||||
uint64_t res = 0;
|
||||
for (auto i : val) {
|
||||
res += i.second;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static future<json::json_return_type> sum_sstable(http_context& ctx, const sstring name, bool total) {
|
||||
auto uuid = get_uuid(name, ctx.db.local());
|
||||
return ctx.db.map_reduce0([uuid, total](database& db) {
|
||||
std::unordered_map<sstring, uint64_t> m;
|
||||
auto sstables = (total) ? db.find_column_family(uuid).get_sstables_including_compacted_undeleted() :
|
||||
db.find_column_family(uuid).get_sstables();
|
||||
for (auto t : *sstables) {
|
||||
m[t.second->get_filename()] = t.second->bytes_on_disk();
|
||||
}
|
||||
return m;
|
||||
}, std::unordered_map<sstring, uint64_t>(), merge_maps).
|
||||
then([](const std::unordered_map<sstring, uint64_t>& val) {
|
||||
return sum_map(val);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
static future<json::json_return_type> sum_sstable(http_context& ctx, bool total) {
|
||||
return map_reduce_cf_raw(ctx, std::unordered_map<sstring, uint64_t>(), [total](column_family& cf) {
|
||||
std::unordered_map<sstring, uint64_t> m;
|
||||
auto sstables = (total) ? cf.get_sstables_including_compacted_undeleted() :
|
||||
cf.get_sstables();
|
||||
for (auto t : *sstables) {
|
||||
m[t.second->get_filename()] = t.second->bytes_on_disk();
|
||||
}
|
||||
return m;
|
||||
},merge_maps).then([](const std::unordered_map<sstring, uint64_t>& val) {
|
||||
return sum_map(val);
|
||||
});
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
class sum_ratio {
|
||||
uint64_t _n = 0;
|
||||
T _total = 0;
|
||||
public:
|
||||
future<> operator()(T value) {
|
||||
if (value > 0) {
|
||||
_total += value;
|
||||
_n++;
|
||||
}
|
||||
return make_ready_future<>();
|
||||
}
|
||||
// Returns average value of all registered ratios.
|
||||
T get() && {
|
||||
return _n ? (_total / _n) : T(0);
|
||||
}
|
||||
};
|
||||
|
||||
static double get_compression_ratio(column_family& cf) {
|
||||
sum_ratio<double> result;
|
||||
for (auto i : *cf.get_sstables()) {
|
||||
auto compression_ratio = i.second->get_compression_ratio();
|
||||
if (compression_ratio != sstables::metadata_collector::NO_COMPRESSION_RATIO) {
|
||||
result(compression_ratio);
|
||||
}
|
||||
}
|
||||
return std::move(result).get();
|
||||
}
|
||||
|
||||
void set_column_family(http_context& ctx, routes& r) {
|
||||
cf::get_column_family_name.set(r, [&ctx] (const_req req){
|
||||
vector<sstring> res;
|
||||
@@ -457,12 +355,8 @@ void set_column_family(http_context& ctx, routes& r) {
|
||||
return get_cf_stats_count(ctx, &column_family::stats::writes);
|
||||
});
|
||||
|
||||
cf::get_read_latency_histogram_depricated.set(r, [&ctx] (std::unique_ptr<request> req) {
|
||||
return get_cf_histogram(ctx, req->param["name"], &column_family::stats::reads);
|
||||
});
|
||||
|
||||
cf::get_read_latency_histogram.set(r, [&ctx] (std::unique_ptr<request> req) {
|
||||
return get_cf_rate_and_histogram(ctx, req->param["name"], &column_family::stats::reads);
|
||||
return get_cf_histogram(ctx, req->param["name"], &column_family::stats::reads);
|
||||
});
|
||||
|
||||
cf::get_read_latency.set(r, [&ctx] (std::unique_ptr<request> req) {
|
||||
@@ -473,28 +367,16 @@ void set_column_family(http_context& ctx, routes& r) {
|
||||
return get_cf_stats_sum(ctx, req->param["name"] ,&column_family::stats::writes);
|
||||
});
|
||||
|
||||
cf::get_all_read_latency_histogram_depricated.set(r, [&ctx] (std::unique_ptr<request> req) {
|
||||
return get_cf_histogram(ctx, &column_family::stats::writes);
|
||||
});
|
||||
|
||||
cf::get_all_read_latency_histogram.set(r, [&ctx] (std::unique_ptr<request> req) {
|
||||
return get_cf_rate_and_histogram(ctx, &column_family::stats::writes);
|
||||
});
|
||||
|
||||
cf::get_write_latency_histogram_depricated.set(r, [&ctx] (std::unique_ptr<request> req) {
|
||||
return get_cf_histogram(ctx, req->param["name"], &column_family::stats::writes);
|
||||
return get_cf_histogram(ctx, &column_family::stats::writes);
|
||||
});
|
||||
|
||||
cf::get_write_latency_histogram.set(r, [&ctx] (std::unique_ptr<request> req) {
|
||||
return get_cf_rate_and_histogram(ctx, req->param["name"], &column_family::stats::writes);
|
||||
});
|
||||
|
||||
cf::get_all_write_latency_histogram_depricated.set(r, [&ctx] (std::unique_ptr<request> req) {
|
||||
return get_cf_histogram(ctx, &column_family::stats::writes);
|
||||
return get_cf_histogram(ctx, req->param["name"], &column_family::stats::writes);
|
||||
});
|
||||
|
||||
cf::get_all_write_latency_histogram.set(r, [&ctx] (std::unique_ptr<request> req) {
|
||||
return get_cf_rate_and_histogram(ctx, &column_family::stats::writes);
|
||||
return get_cf_histogram(ctx, &column_family::stats::writes);
|
||||
});
|
||||
|
||||
cf::get_pending_compactions.set(r, [&ctx] (std::unique_ptr<request> req) {
|
||||
@@ -518,19 +400,19 @@ void set_column_family(http_context& ctx, routes& r) {
|
||||
});
|
||||
|
||||
cf::get_live_disk_space_used.set(r, [&ctx] (std::unique_ptr<request> req) {
|
||||
return sum_sstable(ctx, req->param["name"], false);
|
||||
return get_cf_stats(ctx, req->param["name"], &column_family::stats::live_disk_space_used);
|
||||
});
|
||||
|
||||
cf::get_all_live_disk_space_used.set(r, [&ctx] (std::unique_ptr<request> req) {
|
||||
return sum_sstable(ctx, false);
|
||||
return get_cf_stats(ctx, &column_family::stats::live_disk_space_used);
|
||||
});
|
||||
|
||||
cf::get_total_disk_space_used.set(r, [&ctx] (std::unique_ptr<request> req) {
|
||||
return sum_sstable(ctx, req->param["name"], true);
|
||||
return get_cf_stats(ctx, req->param["name"], &column_family::stats::total_disk_space_used);
|
||||
});
|
||||
|
||||
cf::get_all_total_disk_space_used.set(r, [&ctx] (std::unique_ptr<request> req) {
|
||||
return sum_sstable(ctx, true);
|
||||
return get_cf_stats(ctx, &column_family::stats::total_disk_space_used);
|
||||
});
|
||||
|
||||
cf::get_min_row_size.set(r, [&ctx] (std::unique_ptr<request> req) {
|
||||
@@ -741,35 +623,27 @@ void set_column_family(http_context& ctx, routes& r) {
|
||||
});
|
||||
|
||||
cf::get_row_cache_hit.set(r, [&ctx] (std::unique_ptr<request> req) {
|
||||
return map_reduce_cf_raw(ctx, req->param["name"], utils::rate_moving_average(), [](const 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));
|
||||
});
|
||||
return map_reduce_cf(ctx, req->param["name"], int64_t(0), [](const column_family& cf) {
|
||||
return cf.get_row_cache().stats().hits;
|
||||
}, std::plus<int64_t>());
|
||||
});
|
||||
|
||||
cf::get_all_row_cache_hit.set(r, [&ctx] (std::unique_ptr<request> req) {
|
||||
return map_reduce_cf_raw(ctx, utils::rate_moving_average(), [](const 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));
|
||||
});
|
||||
return map_reduce_cf(ctx, int64_t(0), [](const column_family& cf) {
|
||||
return cf.get_row_cache().stats().hits;
|
||||
}, std::plus<int64_t>());
|
||||
});
|
||||
|
||||
cf::get_row_cache_miss.set(r, [&ctx] (std::unique_ptr<request> req) {
|
||||
return map_reduce_cf_raw(ctx, req->param["name"], utils::rate_moving_average(), [](const 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));
|
||||
});
|
||||
return map_reduce_cf(ctx, req->param["name"], int64_t(0), [](const column_family& cf) {
|
||||
return cf.get_row_cache().stats().misses;
|
||||
}, std::plus<int64_t>());
|
||||
});
|
||||
|
||||
cf::get_all_row_cache_miss.set(r, [&ctx] (std::unique_ptr<request> req) {
|
||||
return map_reduce_cf_raw(ctx, utils::rate_moving_average(), [](const 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));
|
||||
});
|
||||
return map_reduce_cf(ctx, int64_t(0), [](const column_family& cf) {
|
||||
return cf.get_row_cache().stats().misses;
|
||||
}, std::plus<int64_t>());
|
||||
|
||||
});
|
||||
|
||||
@@ -845,15 +719,11 @@ void set_column_family(http_context& ctx, routes& r) {
|
||||
return std::vector<sstring>();
|
||||
});
|
||||
|
||||
cf::get_compression_ratio.set(r, [&ctx](std::unique_ptr<request> req) {
|
||||
auto uuid = get_uuid(req->param["name"], ctx.db.local());
|
||||
|
||||
return ctx.db.map_reduce(sum_ratio<double>(), [uuid](database& db) {
|
||||
column_family& cf = db.find_column_family(uuid);
|
||||
return make_ready_future<double>(get_compression_ratio(cf));
|
||||
}).then([] (const double& result) {
|
||||
return make_ready_future<json::json_return_type>(result);
|
||||
});
|
||||
cf::get_compression_ratio.set(r, [](const_req) {
|
||||
// FIXME
|
||||
// Currently there are no compression information
|
||||
// so we return 0 as the ratio
|
||||
return 0;
|
||||
});
|
||||
|
||||
cf::get_read_latency_estimated_histogram.set(r, [&ctx](std::unique_ptr<request> req) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2015 ScyllaDB
|
||||
* Copyright 2015 Cloudius Systems
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -34,44 +34,31 @@ future<> foreach_column_family(http_context& ctx, const sstring& name, std::func
|
||||
|
||||
|
||||
template<class Mapper, class I, class Reducer>
|
||||
future<I> map_reduce_cf_raw(http_context& ctx, const sstring& name, I init,
|
||||
future<json::json_return_type> map_reduce_cf(http_context& ctx, const sstring& name, I init,
|
||||
Mapper mapper, Reducer reducer) {
|
||||
auto uuid = get_uuid(name, ctx.db.local());
|
||||
return ctx.db.map_reduce0([mapper, uuid](database& db) {
|
||||
return mapper(db.find_column_family(uuid));
|
||||
}, init, reducer);
|
||||
}
|
||||
|
||||
|
||||
template<class Mapper, class I, class Reducer>
|
||||
future<json::json_return_type> map_reduce_cf(http_context& ctx, const sstring& name, I init,
|
||||
Mapper mapper, Reducer reducer) {
|
||||
return map_reduce_cf_raw(ctx, name, init, mapper, reducer).then([](const I& res) {
|
||||
}, init, reducer).then([](const I& res) {
|
||||
return make_ready_future<json::json_return_type>(res);
|
||||
});
|
||||
}
|
||||
|
||||
template<class Mapper, class I, class Reducer, class Result>
|
||||
future<I> map_reduce_cf_raw(http_context& ctx, const sstring& name, I init,
|
||||
future<json::json_return_type> map_reduce_cf(http_context& ctx, const sstring& name, I init,
|
||||
Mapper mapper, Reducer reducer, Result result) {
|
||||
auto uuid = get_uuid(name, ctx.db.local());
|
||||
return ctx.db.map_reduce0([mapper, uuid](database& db) {
|
||||
return mapper(db.find_column_family(uuid));
|
||||
}, init, reducer);
|
||||
}
|
||||
|
||||
|
||||
template<class Mapper, class I, class Reducer, class Result>
|
||||
future<json::json_return_type> map_reduce_cf(http_context& ctx, const sstring& name, I init,
|
||||
Mapper mapper, Reducer reducer, Result result) {
|
||||
return map_reduce_cf_raw(ctx, name, init, mapper, reducer, result).then([result](const I& res) mutable {
|
||||
}, init, reducer).then([result](const I& res) mutable {
|
||||
result = res;
|
||||
return make_ready_future<json::json_return_type>(result);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
template<class Mapper, class I, class Reducer>
|
||||
future<I> map_reduce_cf_raw(http_context& ctx, I init,
|
||||
future<json::json_return_type> map_reduce_cf(http_context& ctx, I init,
|
||||
Mapper mapper, Reducer reducer) {
|
||||
return ctx.db.map_reduce0([mapper, init, reducer](database& db) {
|
||||
auto res = init;
|
||||
@@ -79,18 +66,10 @@ future<I> map_reduce_cf_raw(http_context& ctx, I init,
|
||||
res = reducer(res, mapper(*i.second.get()));
|
||||
}
|
||||
return res;
|
||||
}, init, reducer);
|
||||
}
|
||||
|
||||
|
||||
template<class Mapper, class I, class Reducer>
|
||||
future<json::json_return_type> map_reduce_cf(http_context& ctx, I init,
|
||||
Mapper mapper, Reducer reducer) {
|
||||
return map_reduce_cf_raw(ctx, init, mapper, reducer).then([](const I& res) {
|
||||
}, init, reducer).then([](const I& res) {
|
||||
return make_ready_future<json::json_return_type>(res);
|
||||
});
|
||||
}
|
||||
|
||||
future<json::json_return_type> get_cf_stats(http_context& ctx, const sstring& name,
|
||||
int64_t column_family::stats::*f);
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2015 ScyllaDB
|
||||
* Copyright 2015 Cloudius Systems
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2015 ScyllaDB
|
||||
* Copyright 2015 Cloudius Systems
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2015 ScyllaDB
|
||||
* Copyright 2015 Cloudius Systems
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -49,7 +49,7 @@ void set_compaction_manager(http_context& ctx, routes& r) {
|
||||
s.ks = c->ks;
|
||||
s.cf = c->cf;
|
||||
s.unit = "keys";
|
||||
s.task_type = sstables::compaction_name(c->type);
|
||||
s.task_type = "compaction";
|
||||
s.completed = c->total_keys_written;
|
||||
s.total = c->total_partitions;
|
||||
summaries.push_back(std::move(s));
|
||||
@@ -67,14 +67,11 @@ void set_compaction_manager(http_context& ctx, routes& r) {
|
||||
return make_ready_future<json::json_return_type>(json_void());
|
||||
});
|
||||
|
||||
cm::stop_compaction.set(r, [&ctx] (std::unique_ptr<request> req) {
|
||||
auto type = req->get_query_param("type");
|
||||
return ctx.db.invoke_on_all([type] (database& db) {
|
||||
auto& cm = db.get_compaction_manager();
|
||||
cm.stop_compaction(type);
|
||||
}).then([] {
|
||||
return make_ready_future<json::json_return_type>(json_void());
|
||||
});
|
||||
cm::stop_compaction.set(r, [] (std::unique_ptr<request> req) {
|
||||
//TBD
|
||||
// FIXME
|
||||
warn(unimplemented::cause::API);
|
||||
return make_ready_future<json::json_return_type>("");
|
||||
});
|
||||
|
||||
cm::get_pending_tasks.set(r, [&ctx] (std::unique_ptr<request> req) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2015 ScyllaDB
|
||||
* Copyright 2015 Cloudius Systems
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2015 ScyllaDB
|
||||
* Copyright 2015 Cloudius Systems
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2015 ScyllaDB
|
||||
* Copyright 2015 Cloudius Systems
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2015 ScyllaDB
|
||||
* Copyright 2015 Cloudius Systems
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -44,7 +44,6 @@ void set_failure_detector(http_context& ctx, routes& r) {
|
||||
// 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>(a.first);
|
||||
version_val.value = a.second.value;
|
||||
version_val.version = a.second.version;
|
||||
val.application_state.push(version_val);
|
||||
}
|
||||
res.push_back(val);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2015 ScyllaDB
|
||||
* Copyright 2015 Cloudius Systems
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2015 ScyllaDB
|
||||
* Copyright 2015 Cloudius Systems
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2015 ScyllaDB
|
||||
* Copyright 2015 Cloudius Systems
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2015 ScyllaDB
|
||||
* Copyright 2015 Cloudius Systems
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2015 ScyllaDB
|
||||
* Copyright 2015 Cloudius Systems
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2015 ScyllaDB
|
||||
* Copyright 2015 Cloudius Systems
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2015 ScyllaDB
|
||||
* Copyright 2015 Cloudius Systems
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2015 ScyllaDB
|
||||
* Copyright 2015 Cloudius Systems
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2015 ScyllaDB
|
||||
* Copyright 2015 Cloudius Systems
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2015 ScyllaDB
|
||||
* Copyright 2015 Cloudius Systems
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -33,25 +33,6 @@ namespace sp = httpd::storage_proxy_json;
|
||||
using proxy = service::storage_proxy;
|
||||
using namespace json;
|
||||
|
||||
static future<utils::rate_moving_average> sum_timed_rate(distributed<proxy>& d, utils::timed_rate_moving_average proxy::stats::*f) {
|
||||
return d.map_reduce0([f](const proxy& p) {return (p.get_stats().*f).rate();}, utils::rate_moving_average(),
|
||||
std::plus<utils::rate_moving_average>());
|
||||
}
|
||||
|
||||
static future<json::json_return_type> sum_timed_rate_as_obj(distributed<proxy>& d, utils::timed_rate_moving_average proxy::stats::*f) {
|
||||
return sum_timed_rate(d, f).then([](const utils::rate_moving_average& val) {
|
||||
httpd::utils_json::rate_moving_average m;
|
||||
m = val;
|
||||
return make_ready_future<json::json_return_type>(m);
|
||||
});
|
||||
}
|
||||
|
||||
static future<json::json_return_type> sum_timed_rate_as_long(distributed<proxy>& d, utils::timed_rate_moving_average proxy::stats::*f) {
|
||||
return sum_timed_rate(d, f).then([](const utils::rate_moving_average& val) {
|
||||
return make_ready_future<json::json_return_type>(val.count);
|
||||
});
|
||||
}
|
||||
|
||||
static future<json::json_return_type> sum_estimated_histogram(http_context& ctx, sstables::estimated_histogram proxy::stats::*f) {
|
||||
return ctx.sp.map_reduce0([f](const proxy& p) {return p.get_stats().*f;}, sstables::estimated_histogram(),
|
||||
sstables::merge).then([](const sstables::estimated_histogram& val) {
|
||||
@@ -61,8 +42,8 @@ static future<json::json_return_type> sum_estimated_histogram(http_context& ctx
|
||||
});
|
||||
}
|
||||
|
||||
static future<json::json_return_type> total_latency(http_context& ctx, utils::timed_rate_moving_average_and_histogram proxy::stats::*f) {
|
||||
return ctx.sp.map_reduce0([f](const proxy& p) {return (p.get_stats().*f).hist.mean * (p.get_stats().*f).hist.count;}, 0.0,
|
||||
static future<json::json_return_type> total_latency(http_context& ctx, utils::ihistogram proxy::stats::*f) {
|
||||
return ctx.sp.map_reduce0([f](const proxy& p) {return (p.get_stats().*f).mean * (p.get_stats().*f).count;}, 0.0,
|
||||
std::plus<double>()).then([](double val) {
|
||||
int64_t res = val;
|
||||
return make_ready_future<json::json_return_type>(res);
|
||||
@@ -233,16 +214,16 @@ void set_storage_proxy(http_context& ctx, routes& r) {
|
||||
});
|
||||
|
||||
sp::get_schema_versions.set(r, [](std::unique_ptr<request> req) {
|
||||
return service::get_local_storage_service().describe_schema_versions().then([] (auto result) {
|
||||
std::vector<sp::mapper_list> res;
|
||||
for (auto e : result) {
|
||||
sp::mapper_list entry;
|
||||
entry.key = std::move(e.first);
|
||||
entry.value = std::move(e.second);
|
||||
res.emplace_back(std::move(entry));
|
||||
}
|
||||
return make_ready_future<json::json_return_type>(std::move(res));
|
||||
});
|
||||
//TBD
|
||||
// FIXME
|
||||
// describe_schema_versions is not implemented yet
|
||||
// this is a work around
|
||||
std::vector<sp::mapper_list> res;
|
||||
sp::mapper_list entry;
|
||||
entry.key = boost::lexical_cast<std::string>(utils::fb_utilities::get_broadcast_address());
|
||||
entry.value.push(service::get_local_storage_service().get_schema_version());
|
||||
res.push_back(entry);
|
||||
return make_ready_future<json::json_return_type>(res);
|
||||
});
|
||||
|
||||
sp::get_cas_read_timeouts.set(r, [](std::unique_ptr<request> req) {
|
||||
@@ -310,75 +291,39 @@ void set_storage_proxy(http_context& ctx, routes& r) {
|
||||
});
|
||||
|
||||
sp::get_read_metrics_timeouts.set(r, [&ctx](std::unique_ptr<request> req) {
|
||||
return sum_timed_rate_as_long(ctx.sp, &proxy::stats::read_timeouts);
|
||||
return sum_stats(ctx.sp, &proxy::stats::read_timeouts);
|
||||
});
|
||||
|
||||
sp::get_read_metrics_unavailables.set(r, [&ctx](std::unique_ptr<request> req) {
|
||||
return sum_timed_rate_as_long(ctx.sp, &proxy::stats::read_unavailables);
|
||||
return sum_stats(ctx.sp, &proxy::stats::read_unavailables);
|
||||
});
|
||||
|
||||
sp::get_range_metrics_timeouts.set(r, [&ctx](std::unique_ptr<request> req) {
|
||||
return sum_timed_rate_as_long(ctx.sp, &proxy::stats::range_slice_timeouts);
|
||||
return sum_stats(ctx.sp, &proxy::stats::range_slice_timeouts);
|
||||
});
|
||||
|
||||
sp::get_range_metrics_unavailables.set(r, [&ctx](std::unique_ptr<request> req) {
|
||||
return sum_timed_rate_as_long(ctx.sp, &proxy::stats::range_slice_unavailables);
|
||||
return sum_stats(ctx.sp, &proxy::stats::range_slice_unavailables);
|
||||
});
|
||||
|
||||
sp::get_write_metrics_timeouts.set(r, [&ctx](std::unique_ptr<request> req) {
|
||||
return sum_timed_rate_as_long(ctx.sp, &proxy::stats::write_timeouts);
|
||||
return sum_stats(ctx.sp, &proxy::stats::write_timeouts);
|
||||
});
|
||||
|
||||
sp::get_write_metrics_unavailables.set(r, [&ctx](std::unique_ptr<request> req) {
|
||||
return sum_timed_rate_as_long(ctx.sp, &proxy::stats::write_unavailables);
|
||||
});
|
||||
|
||||
sp::get_read_metrics_timeouts_rates.set(r, [&ctx](std::unique_ptr<request> req) {
|
||||
return sum_timed_rate_as_obj(ctx.sp, &proxy::stats::read_timeouts);
|
||||
});
|
||||
|
||||
sp::get_read_metrics_unavailables_rates.set(r, [&ctx](std::unique_ptr<request> req) {
|
||||
return sum_timed_rate_as_obj(ctx.sp, &proxy::stats::read_unavailables);
|
||||
});
|
||||
|
||||
sp::get_range_metrics_timeouts_rates.set(r, [&ctx](std::unique_ptr<request> req) {
|
||||
return sum_timed_rate_as_obj(ctx.sp, &proxy::stats::range_slice_timeouts);
|
||||
});
|
||||
|
||||
sp::get_range_metrics_unavailables_rates.set(r, [&ctx](std::unique_ptr<request> req) {
|
||||
return sum_timed_rate_as_obj(ctx.sp, &proxy::stats::range_slice_unavailables);
|
||||
});
|
||||
|
||||
sp::get_write_metrics_timeouts_rates.set(r, [&ctx](std::unique_ptr<request> req) {
|
||||
return sum_timed_rate_as_obj(ctx.sp, &proxy::stats::write_timeouts);
|
||||
});
|
||||
|
||||
sp::get_write_metrics_unavailables_rates.set(r, [&ctx](std::unique_ptr<request> req) {
|
||||
return sum_timed_rate_as_obj(ctx.sp, &proxy::stats::write_unavailables);
|
||||
});
|
||||
|
||||
sp::get_range_metrics_latency_histogram_depricated.set(r, [&ctx](std::unique_ptr<request> req) {
|
||||
return sum_histogram_stats(ctx.sp, &proxy::stats::range);
|
||||
});
|
||||
|
||||
sp::get_write_metrics_latency_histogram_depricated.set(r, [&ctx](std::unique_ptr<request> req) {
|
||||
return sum_histogram_stats(ctx.sp, &proxy::stats::write);
|
||||
});
|
||||
|
||||
sp::get_read_metrics_latency_histogram_depricated.set(r, [&ctx](std::unique_ptr<request> req) {
|
||||
return sum_histogram_stats(ctx.sp, &proxy::stats::read);
|
||||
return sum_stats(ctx.sp, &proxy::stats::write_unavailables);
|
||||
});
|
||||
|
||||
sp::get_range_metrics_latency_histogram.set(r, [&ctx](std::unique_ptr<request> req) {
|
||||
return sum_timer_stats(ctx.sp, &proxy::stats::range);
|
||||
return sum_histogram_stats(ctx.sp, &proxy::stats::range);
|
||||
});
|
||||
|
||||
sp::get_write_metrics_latency_histogram.set(r, [&ctx](std::unique_ptr<request> req) {
|
||||
return sum_timer_stats(ctx.sp, &proxy::stats::write);
|
||||
return sum_histogram_stats(ctx.sp, &proxy::stats::write);
|
||||
});
|
||||
|
||||
sp::get_read_metrics_latency_histogram.set(r, [&ctx](std::unique_ptr<request> req) {
|
||||
return sum_timer_stats(ctx.sp, &proxy::stats::read);
|
||||
return sum_histogram_stats(ctx.sp, &proxy::stats::read);
|
||||
});
|
||||
|
||||
sp::get_read_estimated_histogram.set(r, [&ctx](std::unique_ptr<request> req) {
|
||||
@@ -397,7 +342,7 @@ void set_storage_proxy(http_context& ctx, routes& r) {
|
||||
});
|
||||
|
||||
sp::get_range_estimated_histogram.set(r, [&ctx](std::unique_ptr<request> req) {
|
||||
return sum_timer_stats(ctx.sp, &proxy::stats::read);
|
||||
return sum_histogram_stats(ctx.sp, &proxy::stats::read);
|
||||
});
|
||||
|
||||
sp::get_range_latency.set(r, [&ctx](std::unique_ptr<request> req) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2015 ScyllaDB
|
||||
* Copyright 2015 Cloudius Systems
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2015 ScyllaDB
|
||||
* Copyright 2015 Cloudius Systems
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -30,7 +30,6 @@
|
||||
#include "repair/repair.hh"
|
||||
#include "locator/snitch_base.hh"
|
||||
#include "column_family.hh"
|
||||
#include "log.hh"
|
||||
|
||||
namespace api {
|
||||
|
||||
@@ -272,23 +271,15 @@ void set_storage_service(http_context& ctx, routes& r) {
|
||||
});
|
||||
|
||||
ss::force_keyspace_cleanup.set(r, [&ctx](std::unique_ptr<request> req) {
|
||||
//TBD
|
||||
// FIXME
|
||||
// the nodetool clean up is used in many tests
|
||||
// this workaround willl let it work until
|
||||
// a cleanup is implemented
|
||||
warn(unimplemented::cause::API);
|
||||
auto keyspace = validate_keyspace(ctx, req->param);
|
||||
auto column_families = split_cf(req->get_query_param("cf"));
|
||||
if (column_families.empty()) {
|
||||
column_families = map_keys(ctx.db.local().find_keyspace(keyspace).metadata().get()->cf_meta_data());
|
||||
}
|
||||
return ctx.db.invoke_on_all([keyspace, column_families] (database& db) {
|
||||
std::vector<column_family*> column_families_vec;
|
||||
auto& cm = db.get_compaction_manager();
|
||||
for (auto cf : column_families) {
|
||||
column_families_vec.push_back(&db.find_column_family(keyspace, cf));
|
||||
}
|
||||
return parallel_for_each(column_families_vec, [&cm] (column_family* cf) {
|
||||
return cm.perform_cleanup(cf);
|
||||
});
|
||||
}).then([]{
|
||||
return make_ready_future<json::json_return_type>(0);
|
||||
});
|
||||
auto column_family = req->get_query_param("cf");
|
||||
return make_ready_future<json::json_return_type>(0);
|
||||
});
|
||||
|
||||
ss::scrub.set(r, [&ctx](std::unique_ptr<request> req) {
|
||||
@@ -328,8 +319,7 @@ void set_storage_service(http_context& ctx, routes& r) {
|
||||
|
||||
ss::repair_async.set(r, [&ctx](std::unique_ptr<request> req) {
|
||||
static std::vector<sstring> options = {"primaryRange", "parallelism", "incremental",
|
||||
"jobThreads", "ranges", "columnFamilies", "dataCenters", "hosts", "trace",
|
||||
"startToken", "endToken" };
|
||||
"jobThreads", "ranges", "columnFamilies", "dataCenters", "hosts", "trace"};
|
||||
std::unordered_map<sstring, sstring> options_map;
|
||||
for (auto o : options) {
|
||||
auto s = req->get_query_param(o);
|
||||
@@ -382,21 +372,21 @@ void set_storage_service(http_context& ctx, routes& r) {
|
||||
|
||||
ss::remove_node.set(r, [](std::unique_ptr<request> req) {
|
||||
auto host_id = req->get_query_param("host_id");
|
||||
return service::get_local_storage_service().removenode(host_id).then([] {
|
||||
return service::get_local_storage_service().remove_node(host_id).then([] {
|
||||
return make_ready_future<json::json_return_type>(json_void());
|
||||
});
|
||||
});
|
||||
|
||||
ss::get_removal_status.set(r, [](std::unique_ptr<request> req) {
|
||||
return service::get_local_storage_service().get_removal_status().then([] (auto status) {
|
||||
return make_ready_future<json::json_return_type>(status);
|
||||
});
|
||||
//TBD
|
||||
unimplemented();
|
||||
return make_ready_future<json::json_return_type>("");
|
||||
});
|
||||
|
||||
ss::force_remove_completion.set(r, [](std::unique_ptr<request> req) {
|
||||
return service::get_local_storage_service().force_remove_completion().then([] {
|
||||
return make_ready_future<json::json_return_type>(json_void());
|
||||
});
|
||||
//TBD
|
||||
unimplemented();
|
||||
return make_ready_future<json::json_return_type>(json_void());
|
||||
});
|
||||
|
||||
ss::set_logging_level.set(r, [](std::unique_ptr<request> req) {
|
||||
@@ -408,13 +398,9 @@ void set_storage_service(http_context& ctx, routes& r) {
|
||||
});
|
||||
|
||||
ss::get_logging_levels.set(r, [](std::unique_ptr<request> req) {
|
||||
//TBD
|
||||
unimplemented();
|
||||
std::vector<ss::mapper> res;
|
||||
for (auto i : logging::logger_registry().get_all_logger_names()) {
|
||||
ss::mapper log;
|
||||
log.key = i;
|
||||
log.value = logging::level_name(logging::logger_registry().get_logger_level(i));
|
||||
res.push_back(log);
|
||||
}
|
||||
return make_ready_future<json::json_return_type>(res);
|
||||
});
|
||||
|
||||
@@ -588,8 +574,6 @@ void set_storage_service(http_context& ctx, routes& r) {
|
||||
auto val_str = req->get_query_param("value");
|
||||
bool value = (val_str == "True") || (val_str == "true") || (val_str == "1");
|
||||
return service::get_local_storage_service().db().invoke_on_all([value] (database& db) {
|
||||
db.set_enable_incremental_backups(value);
|
||||
|
||||
// Change both KS and CF, so they are in sync
|
||||
for (auto& pair: db.get_keyspaces()) {
|
||||
auto& ks = pair.second;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2015 ScyllaDB
|
||||
* Copyright 2015 Cloudius Systems
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2015 ScyllaDB
|
||||
* Copyright 2015 Cloudius Systems
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -32,16 +32,11 @@ namespace hs = httpd::stream_manager_json;
|
||||
|
||||
static void set_summaries(const std::vector<streaming::stream_summary>& from,
|
||||
json::json_list<hs::stream_summary>& to) {
|
||||
if (!from.empty()) {
|
||||
for (auto sum : from) {
|
||||
hs::stream_summary res;
|
||||
res.cf_id = boost::lexical_cast<std::string>(from.front().cf_id);
|
||||
// For each stream_session, we pretend we are sending/receiving one
|
||||
// file, to make it compatible with nodetool.
|
||||
res.files = 1;
|
||||
// We can not estimate total number of bytes the stream_session will
|
||||
// send or recvieve since we don't know the size of the frozen_mutation
|
||||
// until we read it.
|
||||
res.total_size = 0;
|
||||
res.cf_id = boost::lexical_cast<std::string>(sum.cf_id);
|
||||
res.files = sum.files;
|
||||
res.total_size = sum.total_size;
|
||||
to.push(res);
|
||||
}
|
||||
}
|
||||
@@ -52,7 +47,7 @@ static hs::progress_info get_progress_info(const streaming::progress_info& info)
|
||||
res.direction = info.dir;
|
||||
res.file_name = info.file_name;
|
||||
res.peer = boost::lexical_cast<std::string>(info.peer);
|
||||
res.session_index = 0;
|
||||
res.session_index = info.session_index;
|
||||
res.total_bytes = info.total_bytes;
|
||||
return res;
|
||||
}
|
||||
@@ -75,7 +70,7 @@ static hs::stream_state get_state(
|
||||
for (auto info : result_future.get_coordinator().get()->get_all_session_info()) {
|
||||
hs::stream_info si;
|
||||
si.peer = boost::lexical_cast<std::string>(info.peer);
|
||||
si.session_index = 0;
|
||||
si.session_index = info.session_index;
|
||||
si.state = info.state;
|
||||
si.connecting = si.peer;
|
||||
set_summaries(info.receiving_summaries, si.receiving_summaries);
|
||||
@@ -90,22 +85,18 @@ static hs::stream_state get_state(
|
||||
void set_stream_manager(http_context& ctx, routes& r) {
|
||||
hs::get_current_streams.set(r,
|
||||
[] (std::unique_ptr<request> req) {
|
||||
return streaming::get_stream_manager().invoke_on_all([] (auto& sm) {
|
||||
return sm.update_all_progress_info();
|
||||
}).then([] {
|
||||
return streaming::get_stream_manager().map_reduce0([](streaming::stream_manager& stream) {
|
||||
std::vector<hs::stream_state> res;
|
||||
for (auto i : stream.get_initiated_streams()) {
|
||||
res.push_back(get_state(*i.second.get()));
|
||||
}
|
||||
for (auto i : stream.get_receiving_streams()) {
|
||||
res.push_back(get_state(*i.second.get()));
|
||||
}
|
||||
return res;
|
||||
}, std::vector<hs::stream_state>(),concat<hs::stream_state>).
|
||||
then([](const std::vector<hs::stream_state>& res) {
|
||||
return make_ready_future<json::json_return_type>(res);
|
||||
});
|
||||
return streaming::get_stream_manager().map_reduce0([](streaming::stream_manager& stream) {
|
||||
std::vector<hs::stream_state> res;
|
||||
for (auto i : stream.get_initiated_streams()) {
|
||||
res.push_back(get_state(*i.second.get()));
|
||||
}
|
||||
for (auto i : stream.get_receiving_streams()) {
|
||||
res.push_back(get_state(*i.second.get()));
|
||||
}
|
||||
return res;
|
||||
}, std::vector<hs::stream_state>(),concat<hs::stream_state>).
|
||||
then([](const std::vector<hs::stream_state>& res) {
|
||||
return make_ready_future<json::json_return_type>(res);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -118,42 +109,66 @@ void set_stream_manager(http_context& ctx, routes& r) {
|
||||
});
|
||||
|
||||
hs::get_total_incoming_bytes.set(r, [](std::unique_ptr<request> req) {
|
||||
gms::inet_address peer(req->param["peer"]);
|
||||
return streaming::get_stream_manager().map_reduce0([peer](streaming::stream_manager& sm) {
|
||||
return sm.get_progress_on_all_shards(peer).then([] (auto sbytes) {
|
||||
return sbytes.bytes_received;
|
||||
});
|
||||
gms::inet_address ep(req->param["peer"]);
|
||||
utils::UUID plan_id = gms::get_local_gossiper().get_host_id(ep);
|
||||
return streaming::get_stream_manager().map_reduce0([plan_id](streaming::stream_manager& stream) {
|
||||
int64_t res = 0;
|
||||
streaming::stream_result_future* s = stream.get_receiving_stream(plan_id).get();
|
||||
if (s != nullptr) {
|
||||
for (auto si: s->get_coordinator()->get_all_session_info()) {
|
||||
res += si.get_total_size_received();
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}, 0, std::plus<int64_t>()).then([](int64_t res) {
|
||||
return make_ready_future<json::json_return_type>(res);
|
||||
});
|
||||
});
|
||||
|
||||
hs::get_all_total_incoming_bytes.set(r, [](std::unique_ptr<request> req) {
|
||||
return streaming::get_stream_manager().map_reduce0([](streaming::stream_manager& sm) {
|
||||
return sm.get_progress_on_all_shards().then([] (auto sbytes) {
|
||||
return sbytes.bytes_received;
|
||||
});
|
||||
return streaming::get_stream_manager().map_reduce0([](streaming::stream_manager& stream) {
|
||||
int64_t res = 0;
|
||||
for (auto s : stream.get_receiving_streams()) {
|
||||
if (s.second.get() != nullptr) {
|
||||
for (auto si: s.second.get()->get_coordinator()->get_all_session_info()) {
|
||||
res += si.get_total_size_received();
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}, 0, std::plus<int64_t>()).then([](int64_t res) {
|
||||
return make_ready_future<json::json_return_type>(res);
|
||||
});
|
||||
});
|
||||
|
||||
hs::get_total_outgoing_bytes.set(r, [](std::unique_ptr<request> req) {
|
||||
gms::inet_address peer(req->param["peer"]);
|
||||
return streaming::get_stream_manager().map_reduce0([peer] (streaming::stream_manager& sm) {
|
||||
return sm.get_progress_on_all_shards(peer).then([] (auto sbytes) {
|
||||
return sbytes.bytes_sent;
|
||||
});
|
||||
gms::inet_address ep(req->param["peer"]);
|
||||
utils::UUID plan_id = gms::get_local_gossiper().get_host_id(ep);
|
||||
return streaming::get_stream_manager().map_reduce0([plan_id](streaming::stream_manager& stream) {
|
||||
int64_t res = 0;
|
||||
streaming::stream_result_future* s = stream.get_sending_stream(plan_id).get();
|
||||
if (s != nullptr) {
|
||||
for (auto si: s->get_coordinator()->get_all_session_info()) {
|
||||
res += si.get_total_size_received();
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}, 0, std::plus<int64_t>()).then([](int64_t res) {
|
||||
return make_ready_future<json::json_return_type>(res);
|
||||
});
|
||||
});
|
||||
|
||||
hs::get_all_total_outgoing_bytes.set(r, [](std::unique_ptr<request> req) {
|
||||
return streaming::get_stream_manager().map_reduce0([](streaming::stream_manager& sm) {
|
||||
return sm.get_progress_on_all_shards().then([] (auto sbytes) {
|
||||
return sbytes.bytes_sent;
|
||||
});
|
||||
return streaming::get_stream_manager().map_reduce0([](streaming::stream_manager& stream) {
|
||||
int64_t res = 0;
|
||||
for (auto s : stream.get_initiated_streams()) {
|
||||
if (s.second.get() != nullptr) {
|
||||
for (auto si: s.second.get()->get_coordinator()->get_all_session_info()) {
|
||||
res += si.get_total_size_received();
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}, 0, std::plus<int64_t>()).then([](int64_t res) {
|
||||
return make_ready_future<json::json_return_type>(res);
|
||||
});
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2015 ScyllaDB
|
||||
* Copyright 2015 Cloudius Systems
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2015 ScyllaDB
|
||||
* Copyright 2015 Cloudius Systems
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2015 ScyllaDB
|
||||
* Copyright 2015 Cloudius Systems
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2015 ScyllaDB
|
||||
* Copyright (C) 2015 Cloudius Systems, Ltd.
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -54,9 +54,9 @@ class atomic_cell_or_collection;
|
||||
*/
|
||||
class atomic_cell_type final {
|
||||
private:
|
||||
static constexpr int8_t DEAD_FLAGS = 0;
|
||||
static constexpr int8_t LIVE_FLAG = 0x01;
|
||||
static constexpr int8_t EXPIRY_FLAG = 0x02; // When present, expiry field is present. Set only for live cells
|
||||
static constexpr int8_t REVERT_FLAG = 0x04; // transient flag used to efficiently implement ReversiblyMergeable for atomic cells.
|
||||
static constexpr unsigned flags_size = 1;
|
||||
static constexpr unsigned timestamp_offset = flags_size;
|
||||
static constexpr unsigned timestamp_size = 8;
|
||||
@@ -67,21 +67,14 @@ private:
|
||||
static constexpr unsigned ttl_offset = expiry_offset + expiry_size;
|
||||
static constexpr unsigned ttl_size = 4;
|
||||
private:
|
||||
static bool is_revert_set(bytes_view cell) {
|
||||
return cell[0] & REVERT_FLAG;
|
||||
}
|
||||
template<typename BytesContainer>
|
||||
static void set_revert(BytesContainer& cell, bool revert) {
|
||||
cell[0] = (cell[0] & ~REVERT_FLAG) | (revert * REVERT_FLAG);
|
||||
}
|
||||
static bool is_live(const bytes_view& cell) {
|
||||
return cell[0] & LIVE_FLAG;
|
||||
return cell[0] != DEAD_FLAGS;
|
||||
}
|
||||
static bool is_live_and_has_ttl(const bytes_view& cell) {
|
||||
return cell[0] & EXPIRY_FLAG;
|
||||
}
|
||||
static bool is_dead(const bytes_view& cell) {
|
||||
return !is_live(cell);
|
||||
return cell[0] == DEAD_FLAGS;
|
||||
}
|
||||
// Can be called on live and dead cells
|
||||
static api::timestamp_type timestamp(const bytes_view& cell) {
|
||||
@@ -113,7 +106,7 @@ private:
|
||||
}
|
||||
static managed_bytes make_dead(api::timestamp_type timestamp, gc_clock::time_point deletion_time) {
|
||||
managed_bytes b(managed_bytes::initialized_later(), flags_size + timestamp_size + deletion_time_size);
|
||||
b[0] = 0;
|
||||
b[0] = DEAD_FLAGS;
|
||||
set_field(b, timestamp_offset, timestamp);
|
||||
set_field(b, deletion_time_offset, deletion_time.time_since_epoch().count());
|
||||
return b;
|
||||
@@ -147,11 +140,8 @@ protected:
|
||||
ByteContainer _data;
|
||||
protected:
|
||||
atomic_cell_base(ByteContainer&& data) : _data(std::forward<ByteContainer>(data)) { }
|
||||
friend class atomic_cell_or_collection;
|
||||
atomic_cell_base(const ByteContainer& data) : _data(data) { }
|
||||
public:
|
||||
bool is_revert_set() const {
|
||||
return atomic_cell_type::is_revert_set(_data);
|
||||
}
|
||||
bool is_live() const {
|
||||
return atomic_cell_type::is_live(_data);
|
||||
}
|
||||
@@ -197,13 +187,10 @@ public:
|
||||
bytes_view serialize() const {
|
||||
return _data;
|
||||
}
|
||||
void set_revert(bool revert) {
|
||||
atomic_cell_type::set_revert(_data, revert);
|
||||
}
|
||||
};
|
||||
|
||||
class atomic_cell_view final : public atomic_cell_base<bytes_view> {
|
||||
atomic_cell_view(bytes_view data) : atomic_cell_base(std::move(data)) {}
|
||||
atomic_cell_view(bytes_view data) : atomic_cell_base(data) {}
|
||||
public:
|
||||
static atomic_cell_view from_bytes(bytes_view data) { return atomic_cell_view(data); }
|
||||
|
||||
@@ -211,11 +198,6 @@ public:
|
||||
friend std::ostream& operator<<(std::ostream& os, const atomic_cell_view& acv);
|
||||
};
|
||||
|
||||
class atomic_cell_ref final : public atomic_cell_base<managed_bytes&> {
|
||||
public:
|
||||
atomic_cell_ref(managed_bytes& buf) : atomic_cell_base(buf) {}
|
||||
};
|
||||
|
||||
class atomic_cell final : public atomic_cell_base<managed_bytes> {
|
||||
atomic_cell(managed_bytes b) : atomic_cell_base(std::move(b)) {}
|
||||
public:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2015 ScyllaDB
|
||||
* Copyright (C) 2015 Cloudius Systems, Ltd.
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -27,18 +27,16 @@
|
||||
#include "atomic_cell.hh"
|
||||
#include "hashing.hh"
|
||||
|
||||
template<>
|
||||
struct appending_hash<collection_mutation_view> {
|
||||
template<typename Hasher>
|
||||
void operator()(Hasher& h, collection_mutation_view cell) const {
|
||||
auto m_view = collection_type_impl::deserialize_mutation_form(cell);
|
||||
::feed_hash(h, m_view.tomb);
|
||||
for (auto&& key_and_value : m_view.cells) {
|
||||
::feed_hash(h, key_and_value.first);
|
||||
::feed_hash(h, key_and_value.second);
|
||||
}
|
||||
template<typename Hasher>
|
||||
void feed_hash(collection_mutation_view cell, Hasher& h, const data_type& type) {
|
||||
auto&& ctype = static_pointer_cast<const collection_type_impl>(type);
|
||||
auto m_view = ctype->deserialize_mutation_form(cell);
|
||||
::feed_hash(h, m_view.tomb);
|
||||
for (auto&& key_and_value : m_view.cells) {
|
||||
::feed_hash(h, key_and_value.first);
|
||||
::feed_hash(h, key_and_value.second);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
template<>
|
||||
struct appending_hash<atomic_cell_view> {
|
||||
@@ -57,19 +55,3 @@ struct appending_hash<atomic_cell_view> {
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct appending_hash<atomic_cell> {
|
||||
template<typename Hasher>
|
||||
void operator()(Hasher& h, const atomic_cell& cell) const {
|
||||
feed_hash(h, static_cast<atomic_cell_view>(cell));
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct appending_hash<collection_mutation> {
|
||||
template<typename Hasher>
|
||||
void operator()(Hasher& h, const collection_mutation& cm) const {
|
||||
feed_hash(h, static_cast<collection_mutation_view>(cm));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2015 ScyllaDB
|
||||
* Copyright (C) 2015 Cloudius Systems, Ltd.
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -27,10 +27,11 @@
|
||||
|
||||
// A variant type that can hold either an atomic_cell, or a serialized collection.
|
||||
// Which type is stored is determined by the schema.
|
||||
// Has an "empty" state.
|
||||
// Objects moved-from are left in an empty state.
|
||||
class atomic_cell_or_collection final {
|
||||
managed_bytes _data;
|
||||
|
||||
template<typename T>
|
||||
friend class db::serializer;
|
||||
private:
|
||||
atomic_cell_or_collection(managed_bytes&& data) : _data(std::move(data)) {}
|
||||
public:
|
||||
@@ -38,7 +39,6 @@ public:
|
||||
atomic_cell_or_collection(atomic_cell ac) : _data(std::move(ac._data)) {}
|
||||
static atomic_cell_or_collection from_atomic_cell(atomic_cell data) { return { std::move(data._data) }; }
|
||||
atomic_cell_view as_atomic_cell() const { return atomic_cell_view::from_bytes(_data); }
|
||||
atomic_cell_ref as_atomic_cell_ref() { return { _data }; }
|
||||
atomic_cell_or_collection(collection_mutation cm) : _data(std::move(cm.data)) {}
|
||||
explicit operator bool() const {
|
||||
return !_data.empty();
|
||||
@@ -63,5 +63,11 @@ public:
|
||||
::feed_hash(as_collection_mutation(), h, def.type);
|
||||
}
|
||||
}
|
||||
void linearize() {
|
||||
_data.linearize();
|
||||
}
|
||||
void unlinearize() {
|
||||
_data.scatter();
|
||||
}
|
||||
friend std::ostream& operator<<(std::ostream&, const atomic_cell_or_collection&);
|
||||
};
|
||||
|
||||
187
auth/auth.cc
187
auth/auth.cc
@@ -17,9 +17,9 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2016 ScyllaDB
|
||||
* Copyright 2016 Cloudius Systems
|
||||
*
|
||||
* Modified by ScyllaDB
|
||||
* Modified by Cloudius Systems
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -40,19 +40,14 @@
|
||||
*/
|
||||
#include <seastar/core/sleep.hh>
|
||||
|
||||
#include <seastar/core/distributed.hh>
|
||||
|
||||
#include "auth.hh"
|
||||
#include "authenticator.hh"
|
||||
#include "authorizer.hh"
|
||||
#include "database.hh"
|
||||
#include "cql3/query_processor.hh"
|
||||
#include "cql3/statements/cf_statement.hh"
|
||||
#include "cql3/statements/create_table_statement.hh"
|
||||
#include "db/config.hh"
|
||||
#include "service/migration_manager.hh"
|
||||
#include "utils/loading_cache.hh"
|
||||
#include "utils/hash.hh"
|
||||
|
||||
const sstring auth::auth::DEFAULT_SUPERUSER_NAME("cassandra");
|
||||
const sstring auth::auth::AUTH_KS("system_auth");
|
||||
@@ -81,10 +76,13 @@ class auth_migration_listener : public service::migration_listener {
|
||||
void on_update_aggregate(const sstring& ks_name, const sstring& aggregate_name) override {}
|
||||
|
||||
void on_drop_keyspace(const sstring& ks_name) override {
|
||||
auth::authorizer::get().revoke_all(auth::data_resource(ks_name));
|
||||
// TODO:
|
||||
//DatabaseDescriptor.getAuthorizer().revokeAll(DataResource.keyspace(ksName));
|
||||
|
||||
}
|
||||
void on_drop_column_family(const sstring& ks_name, const sstring& cf_name) override {
|
||||
auth::authorizer::get().revoke_all(auth::data_resource(ks_name, cf_name));
|
||||
// TODO:
|
||||
//DatabaseDescriptor.getAuthorizer().revokeAll(DataResource.columnFamily(ksName, cfName));
|
||||
}
|
||||
void on_drop_user_type(const sstring& ks_name, const sstring& type_name) override {}
|
||||
void on_drop_function(const sstring& ks_name, const sstring& function_name) override {}
|
||||
@@ -93,125 +91,6 @@ class auth_migration_listener : public service::migration_listener {
|
||||
|
||||
static auth_migration_listener auth_migration;
|
||||
|
||||
namespace std {
|
||||
template <>
|
||||
struct hash<auth::data_resource> {
|
||||
size_t operator()(const auth::data_resource & v) const {
|
||||
return v.hash_value();
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct hash<auth::authenticated_user> {
|
||||
size_t operator()(const auth::authenticated_user & v) const {
|
||||
return utils::tuple_hash()(v.name(), v.is_anonymous());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
class auth::auth::permissions_cache {
|
||||
public:
|
||||
typedef utils::loading_cache<std::pair<authenticated_user, data_resource>, permission_set, utils::tuple_hash> cache_type;
|
||||
typedef typename cache_type::key_type key_type;
|
||||
|
||||
permissions_cache()
|
||||
: permissions_cache(
|
||||
cql3::get_local_query_processor().db().local().get_config()) {
|
||||
}
|
||||
|
||||
permissions_cache(const db::config& cfg)
|
||||
: _cache(cfg.permissions_cache_max_entries(), expiry(cfg),
|
||||
std::chrono::milliseconds(
|
||||
cfg.permissions_validity_in_ms()),
|
||||
[](const key_type& k) {
|
||||
logger.debug("Refreshing permissions for {}", k.first.name());
|
||||
return authorizer::get().authorize(::make_shared<authenticated_user>(k.first), k.second);
|
||||
}) {
|
||||
}
|
||||
|
||||
static std::chrono::milliseconds expiry(const db::config& cfg) {
|
||||
auto exp = cfg.permissions_update_interval_in_ms();
|
||||
if (exp == 0 || exp == std::numeric_limits<uint32_t>::max()) {
|
||||
exp = cfg.permissions_validity_in_ms();
|
||||
}
|
||||
return std::chrono::milliseconds(exp);
|
||||
}
|
||||
|
||||
future<> stop() {
|
||||
return make_ready_future<>();
|
||||
}
|
||||
|
||||
future<permission_set> get(::shared_ptr<authenticated_user> user, data_resource resource) {
|
||||
return _cache.get(key_type(*user, std::move(resource)));
|
||||
}
|
||||
|
||||
private:
|
||||
cache_type _cache;
|
||||
};
|
||||
|
||||
static distributed<auth::auth::permissions_cache> perm_cache;
|
||||
|
||||
/**
|
||||
* Poor mans job schedule. For maximum 2 jobs. Sic.
|
||||
* Still does nothing more clever than waiting 10 seconds
|
||||
* like origin, then runs the submitted tasks.
|
||||
*
|
||||
* Only difference compared to sleep (from which this
|
||||
* borrows _heavily_) is that if tasks have not run by the time
|
||||
* we exit (and do static clean up) we delete the promise + cont
|
||||
*
|
||||
* Should be abstracted to some sort of global server function
|
||||
* probably.
|
||||
*/
|
||||
struct waiter {
|
||||
promise<> done;
|
||||
timer<> tmr;
|
||||
waiter() : tmr([this] {done.set_value();})
|
||||
{
|
||||
tmr.arm(auth::auth::SUPERUSER_SETUP_DELAY);
|
||||
}
|
||||
~waiter() {
|
||||
if (tmr.armed()) {
|
||||
tmr.cancel();
|
||||
done.set_exception(std::runtime_error("shutting down"));
|
||||
}
|
||||
logger.trace("Deleting scheduled task");
|
||||
}
|
||||
void kill() {
|
||||
}
|
||||
};
|
||||
|
||||
typedef std::unique_ptr<waiter> waiter_ptr;
|
||||
|
||||
static std::vector<waiter_ptr> & thread_waiters() {
|
||||
static thread_local std::vector<waiter_ptr> the_waiters;
|
||||
return the_waiters;
|
||||
}
|
||||
|
||||
void auth::auth::schedule_when_up(scheduled_func f) {
|
||||
logger.trace("Adding scheduled task");
|
||||
|
||||
auto & waiters = thread_waiters();
|
||||
|
||||
waiters.emplace_back(std::make_unique<waiter>());
|
||||
auto* w = waiters.back().get();
|
||||
|
||||
w->done.get_future().finally([w] {
|
||||
auto & waiters = thread_waiters();
|
||||
auto i = std::find_if(waiters.begin(), waiters.end(), [w](const waiter_ptr& p) {
|
||||
return p.get() == w;
|
||||
});
|
||||
if (i != waiters.end()) {
|
||||
waiters.erase(i);
|
||||
}
|
||||
}).then([f = std::move(f)] {
|
||||
logger.trace("Running scheduled task");
|
||||
return f();
|
||||
}).handle_exception([](auto ep) {
|
||||
return make_ready_future();
|
||||
});
|
||||
}
|
||||
|
||||
bool auth::auth::is_class_type(const sstring& type, const sstring& classname) {
|
||||
if (type == classname) {
|
||||
return true;
|
||||
@@ -223,22 +102,14 @@ bool auth::auth::is_class_type(const sstring& type, const sstring& classname) {
|
||||
future<> auth::auth::setup() {
|
||||
auto& db = cql3::get_local_query_processor().db().local();
|
||||
auto& cfg = db.get_config();
|
||||
auto type = cfg.authenticator();
|
||||
|
||||
future<> f = perm_cache.start();
|
||||
|
||||
if (is_class_type(cfg.authenticator(),
|
||||
authenticator::ALLOW_ALL_AUTHENTICATOR_NAME)
|
||||
&& is_class_type(cfg.authorizer(),
|
||||
authorizer::ALLOW_ALL_AUTHORIZER_NAME)
|
||||
) {
|
||||
// just create the objects
|
||||
return f.then([&cfg] {
|
||||
return authenticator::setup(cfg.authenticator());
|
||||
}).then([&cfg] {
|
||||
return authorizer::setup(cfg.authorizer());
|
||||
});
|
||||
if (is_class_type(type, authenticator::ALLOW_ALL_AUTHENTICATOR_NAME)) {
|
||||
return authenticator::setup(type).discard_result(); // just create the object
|
||||
}
|
||||
|
||||
future<> f = make_ready_future();
|
||||
|
||||
if (!db.has_keyspace(AUTH_KS)) {
|
||||
std::map<sstring, sstring> opts;
|
||||
opts["replication_factor"] = "1";
|
||||
@@ -250,14 +121,14 @@ future<> auth::auth::setup() {
|
||||
return setup_table(USERS_CF, sprint("CREATE TABLE %s.%s (%s text, %s boolean, PRIMARY KEY(%s)) WITH gc_grace_seconds=%d",
|
||||
AUTH_KS, USERS_CF, USER_NAME, SUPER, USER_NAME,
|
||||
90 * 24 * 60 * 60)); // 3 months.
|
||||
}).then([&cfg] {
|
||||
return authenticator::setup(cfg.authenticator());
|
||||
}).then([&cfg] {
|
||||
return authorizer::setup(cfg.authorizer());
|
||||
}).then([type] {
|
||||
return authenticator::setup(type).discard_result();
|
||||
}).then([] {
|
||||
// TODO authorizer
|
||||
}).then([] {
|
||||
service::get_local_migration_manager().register_listener(&auth_migration); // again, only one shard...
|
||||
// instead of once-timer, just schedule this later
|
||||
schedule_when_up([] {
|
||||
sleep(SUPERUSER_SETUP_DELAY).then([] {
|
||||
// setup default super user
|
||||
return has_existing_users(USERS_CF, DEFAULT_SUPERUSER_NAME, USER_NAME).then([](bool exists) {
|
||||
if (!exists) {
|
||||
@@ -278,21 +149,6 @@ future<> auth::auth::setup() {
|
||||
});
|
||||
}
|
||||
|
||||
future<> auth::auth::shutdown() {
|
||||
// just make sure we don't have pending tasks.
|
||||
// this is mostly relevant for test cases where
|
||||
// db-env-shutdown != process shutdown
|
||||
return smp::invoke_on_all([] {
|
||||
thread_waiters().clear();
|
||||
}).then([] {
|
||||
return perm_cache.stop();
|
||||
});
|
||||
}
|
||||
|
||||
future<auth::permission_set> auth::auth::get_permissions(::shared_ptr<authenticated_user> user, data_resource resource) {
|
||||
return perm_cache.local().get(std::move(user), std::move(resource));
|
||||
}
|
||||
|
||||
static db::consistency_level consistency_for_user(const sstring& username) {
|
||||
if (username == auth::auth::DEFAULT_SUPERUSER_NAME) {
|
||||
return db::consistency_level::QUORUM;
|
||||
@@ -354,12 +210,9 @@ future<> auth::auth::setup_table(const sstring& name, const sstring& cql) {
|
||||
::shared_ptr<cql3::statements::create_table_statement> statement =
|
||||
static_pointer_cast<cql3::statements::create_table_statement>(
|
||||
parsed->prepare(db)->statement);
|
||||
auto schema = statement->get_cf_meta_data();
|
||||
auto uuid = generate_legacy_id(schema->ks_name(), schema->cf_name());
|
||||
|
||||
schema_builder b(schema);
|
||||
b.set_uuid(uuid);
|
||||
return service::get_local_migration_manager().announce_new_column_family(b.build(), false);
|
||||
// Origin sets "Legacy Cf Id" for the new table. We have no need to be
|
||||
// pre-2.1 compatible (afaik), so lets skip a whole lotta hoolaballo
|
||||
return statement->announce_migration(qp.proxy(), false).then([statement](bool) {});
|
||||
}
|
||||
|
||||
future<bool> auth::auth::has_existing_users(const sstring& cfname, const sstring& def_user_name, const sstring& name_column) {
|
||||
|
||||
24
auth/auth.hh
24
auth/auth.hh
@@ -17,9 +17,9 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2016 ScyllaDB
|
||||
* Copyright 2016 Cloudius Systems
|
||||
*
|
||||
* Modified by ScyllaDB
|
||||
* Modified by Cloudius Systems
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -44,21 +44,13 @@
|
||||
#include <chrono>
|
||||
#include <seastar/core/sstring.hh>
|
||||
#include <seastar/core/future.hh>
|
||||
#include <seastar/core/shared_ptr.hh>
|
||||
|
||||
|
||||
#include "exceptions/exceptions.hh"
|
||||
#include "permission.hh"
|
||||
#include "data_resource.hh"
|
||||
|
||||
namespace auth {
|
||||
|
||||
class authenticated_user;
|
||||
|
||||
class auth {
|
||||
public:
|
||||
class permissions_cache;
|
||||
|
||||
static const sstring DEFAULT_SUPERUSER_NAME;
|
||||
static const sstring AUTH_KS;
|
||||
static const sstring USERS_CF;
|
||||
@@ -66,7 +58,12 @@ public:
|
||||
|
||||
static bool is_class_type(const sstring& type, const sstring& classname);
|
||||
|
||||
static future<permission_set> get_permissions(::shared_ptr<authenticated_user>, data_resource);
|
||||
#if 0
|
||||
public static Set<Permission> getPermissions(AuthenticatedUser user, IResource resource)
|
||||
{
|
||||
return permissionsCache.getPermissions(user, resource);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Checks if the username is stored in AUTH_KS.USERS_CF.
|
||||
@@ -105,7 +102,6 @@ public:
|
||||
* Sets up Authenticator and Authorizer.
|
||||
*/
|
||||
static future<> setup();
|
||||
static future<> shutdown();
|
||||
|
||||
/**
|
||||
* Set up table from given CREATE TABLE statement under system_auth keyspace, if not already done so.
|
||||
@@ -116,9 +112,5 @@ public:
|
||||
static future<> setup_table(const sstring& name, const sstring& cql);
|
||||
|
||||
static future<bool> has_existing_users(const sstring& cfname, const sstring& def_user_name, const sstring& name_column_name);
|
||||
|
||||
// For internal use. Run function "when system is up".
|
||||
typedef std::function<future<>()> scheduled_func;
|
||||
static void schedule_when_up(scheduled_func);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -17,9 +17,9 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2016 ScyllaDB
|
||||
* Copyright 2016 Cloudius Systems
|
||||
*
|
||||
* Modified by ScyllaDB
|
||||
* Modified by Cloudius Systems
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -41,7 +41,6 @@
|
||||
|
||||
|
||||
#include "authenticated_user.hh"
|
||||
#include "auth.hh"
|
||||
|
||||
const sstring auth::authenticated_user::ANONYMOUS_USERNAME("anonymous");
|
||||
|
||||
@@ -53,20 +52,10 @@ auth::authenticated_user::authenticated_user(sstring name)
|
||||
: _name(name), _anon(false)
|
||||
{}
|
||||
|
||||
auth::authenticated_user::authenticated_user(authenticated_user&&) = default;
|
||||
auth::authenticated_user::authenticated_user(const authenticated_user&) = default;
|
||||
|
||||
const sstring& auth::authenticated_user::name() const {
|
||||
return _anon ? ANONYMOUS_USERNAME : _name;
|
||||
}
|
||||
|
||||
future<bool> auth::authenticated_user::is_super() const {
|
||||
if (is_anonymous()) {
|
||||
return make_ready_future<bool>(false);
|
||||
}
|
||||
return auth::auth::is_super_user(_name);
|
||||
}
|
||||
|
||||
bool auth::authenticated_user::operator==(const authenticated_user& v) const {
|
||||
return _anon ? v._anon : _name == v._name;
|
||||
}
|
||||
|
||||
@@ -17,9 +17,9 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2016 ScyllaDB
|
||||
* Copyright 2016 Cloudius Systems
|
||||
*
|
||||
* Modified by ScyllaDB
|
||||
* Modified by Cloudius Systems
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -42,7 +42,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <seastar/core/sstring.hh>
|
||||
#include <seastar/core/future.hh>
|
||||
|
||||
namespace auth {
|
||||
|
||||
@@ -52,8 +51,6 @@ public:
|
||||
|
||||
authenticated_user();
|
||||
authenticated_user(sstring name);
|
||||
authenticated_user(authenticated_user&&);
|
||||
authenticated_user(const authenticated_user&);
|
||||
|
||||
const sstring& name() const;
|
||||
|
||||
@@ -63,7 +60,7 @@ public:
|
||||
* Im most cased, though not necessarily, a superuser will have Permission.ALL on every resource
|
||||
* (depends on IAuthorizer implementation).
|
||||
*/
|
||||
future<bool> is_super() const;
|
||||
bool is_super() const;
|
||||
|
||||
/**
|
||||
* If IAuthenticator doesn't require authentication, this method may return true.
|
||||
|
||||
@@ -17,9 +17,9 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2016 ScyllaDB
|
||||
* Copyright 2016 Cloudius Systems
|
||||
*
|
||||
* Modified by ScyllaDB
|
||||
* Modified by Cloudius Systems
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -49,22 +49,6 @@ const sstring auth::authenticator::USERNAME_KEY("username");
|
||||
const sstring auth::authenticator::PASSWORD_KEY("password");
|
||||
const sstring auth::authenticator::ALLOW_ALL_AUTHENTICATOR_NAME("org.apache.cassandra.auth.AllowAllAuthenticator");
|
||||
|
||||
auth::authenticator::option auth::authenticator::string_to_option(const sstring& name) {
|
||||
if (strcasecmp(name.c_str(), "password") == 0) {
|
||||
return option::PASSWORD;
|
||||
}
|
||||
throw std::invalid_argument(name);
|
||||
}
|
||||
|
||||
sstring auth::authenticator::option_to_string(option opt) {
|
||||
switch (opt) {
|
||||
case option::PASSWORD:
|
||||
return "PASSWORD";
|
||||
default:
|
||||
throw std::invalid_argument(sprint("Unknown option {}", opt));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Authenticator is assumed to be a fully state-less immutable object (note all the const).
|
||||
* We thus store a single instance globally, since it should be safe/ok.
|
||||
@@ -100,9 +84,8 @@ auth::authenticator::setup(const sstring& type) throw (exceptions::configuration
|
||||
future<> drop(sstring username) throw(exceptions::request_validation_exception, exceptions::request_execution_exception) override {
|
||||
return make_ready_future();
|
||||
}
|
||||
const resource_ids& protected_resources() const override {
|
||||
static const resource_ids ids;
|
||||
return ids;
|
||||
resource_ids protected_resources() const override {
|
||||
return resource_ids();
|
||||
}
|
||||
::shared_ptr<sasl_challenge> new_sasl_challenge() const override {
|
||||
throw std::runtime_error("Should not reach");
|
||||
|
||||
@@ -17,9 +17,9 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2016 ScyllaDB
|
||||
* Copyright 2016 Cloudius Systems
|
||||
*
|
||||
* Modified by ScyllaDB
|
||||
* Modified by Cloudius Systems
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -79,13 +79,15 @@ public:
|
||||
PASSWORD
|
||||
};
|
||||
|
||||
static option string_to_option(const sstring&);
|
||||
static sstring option_to_string(option);
|
||||
|
||||
using option_set = enum_set<super_enum<option, option::PASSWORD>>;
|
||||
using option_map = std::unordered_map<option, boost::any, enum_hash<option>>;
|
||||
using credentials_map = std::unordered_map<sstring, sstring>;
|
||||
|
||||
/**
|
||||
* Resource id mappings, i.e. keyspace and/or column families.
|
||||
*/
|
||||
using resource_ids = std::set<data_resource>;
|
||||
|
||||
/**
|
||||
* Setup is called once upon system startup to initialize the IAuthenticator.
|
||||
*
|
||||
@@ -172,7 +174,7 @@ public:
|
||||
* @return Keyspaces, column families that will be unmodifiable by users; other resources.
|
||||
* @see resource_ids
|
||||
*/
|
||||
virtual const resource_ids& protected_resources() const = 0;
|
||||
virtual resource_ids protected_resources() const = 0;
|
||||
|
||||
class sasl_challenge {
|
||||
public:
|
||||
@@ -192,9 +194,5 @@ public:
|
||||
virtual ::shared_ptr<sasl_challenge> new_sasl_challenge() const = 0;
|
||||
};
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& os, authenticator::option opt) {
|
||||
return os << authenticator::option_to_string(opt);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,104 +0,0 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2016 ScyllaDB
|
||||
*
|
||||
* Modified by ScyllaDB
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is part of Scylla.
|
||||
*
|
||||
* Scylla is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Scylla is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Scylla. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "authorizer.hh"
|
||||
#include "authenticated_user.hh"
|
||||
#include "default_authorizer.hh"
|
||||
#include "auth.hh"
|
||||
#include "db/config.hh"
|
||||
|
||||
const sstring auth::authorizer::ALLOW_ALL_AUTHORIZER_NAME("org.apache.cassandra.auth.AllowAllAuthorizer");
|
||||
|
||||
/**
|
||||
* Authenticator is assumed to be a fully state-less immutable object (note all the const).
|
||||
* We thus store a single instance globally, since it should be safe/ok.
|
||||
*/
|
||||
static std::unique_ptr<auth::authorizer> global_authorizer;
|
||||
|
||||
future<>
|
||||
auth::authorizer::setup(const sstring& type) {
|
||||
if (auth::auth::is_class_type(type, ALLOW_ALL_AUTHORIZER_NAME)) {
|
||||
class allow_all_authorizer : public authorizer {
|
||||
public:
|
||||
future<permission_set> authorize(::shared_ptr<authenticated_user>, data_resource) const override {
|
||||
return make_ready_future<permission_set>(permissions::ALL);
|
||||
}
|
||||
future<> grant(::shared_ptr<authenticated_user>, permission_set, data_resource, sstring) override {
|
||||
throw exceptions::invalid_request_exception("GRANT operation is not supported by AllowAllAuthorizer");
|
||||
}
|
||||
future<> revoke(::shared_ptr<authenticated_user>, permission_set, data_resource, sstring) override {
|
||||
throw exceptions::invalid_request_exception("REVOKE operation is not supported by AllowAllAuthorizer");
|
||||
}
|
||||
future<std::vector<permission_details>> list(::shared_ptr<authenticated_user> performer, permission_set, optional<data_resource>, optional<sstring>) const override {
|
||||
throw exceptions::invalid_request_exception("LIST PERMISSIONS operation is not supported by AllowAllAuthorizer");
|
||||
}
|
||||
future<> revoke_all(sstring dropped_user) override {
|
||||
return make_ready_future();
|
||||
}
|
||||
future<> revoke_all(data_resource) override {
|
||||
return make_ready_future();
|
||||
}
|
||||
const resource_ids& protected_resources() override {
|
||||
static const resource_ids ids;
|
||||
return ids;
|
||||
}
|
||||
future<> validate_configuration() const override {
|
||||
return make_ready_future();
|
||||
}
|
||||
};
|
||||
|
||||
global_authorizer = std::make_unique<allow_all_authorizer>();
|
||||
} else if (auth::auth::is_class_type(type, default_authorizer::DEFAULT_AUTHORIZER_NAME)) {
|
||||
auto da = std::make_unique<default_authorizer>();
|
||||
auto f = da->init();
|
||||
return f.then([da = std::move(da)]() mutable {
|
||||
global_authorizer = std::move(da);
|
||||
});
|
||||
} else {
|
||||
throw exceptions::configuration_exception("Invalid authorizer type: " + type);
|
||||
}
|
||||
return make_ready_future();
|
||||
}
|
||||
|
||||
auth::authorizer& auth::authorizer::get() {
|
||||
assert(global_authorizer);
|
||||
return *global_authorizer;
|
||||
}
|
||||
@@ -1,171 +0,0 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2016 ScyllaDB
|
||||
*
|
||||
* Modified by ScyllaDB
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is part of Scylla.
|
||||
*
|
||||
* Scylla is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Scylla is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Scylla. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <tuple>
|
||||
|
||||
#include <experimental/optional>
|
||||
#include <seastar/core/future.hh>
|
||||
#include <seastar/core/shared_ptr.hh>
|
||||
|
||||
#include "permission.hh"
|
||||
#include "data_resource.hh"
|
||||
|
||||
namespace auth {
|
||||
|
||||
class authenticated_user;
|
||||
|
||||
struct permission_details {
|
||||
sstring user;
|
||||
data_resource resource;
|
||||
permission_set permissions;
|
||||
|
||||
bool operator<(const permission_details& v) const {
|
||||
return std::tie(user, resource, permissions) < std::tie(v.user, v.resource, v.permissions);
|
||||
}
|
||||
};
|
||||
|
||||
using std::experimental::optional;
|
||||
|
||||
class authorizer {
|
||||
public:
|
||||
static const sstring ALLOW_ALL_AUTHORIZER_NAME;
|
||||
|
||||
virtual ~authorizer() {}
|
||||
|
||||
/**
|
||||
* The primary Authorizer method. Returns a set of permissions of a user on a resource.
|
||||
*
|
||||
* @param user Authenticated user requesting authorization.
|
||||
* @param resource Resource for which the authorization is being requested. @see DataResource.
|
||||
* @return Set of permissions of the user on the resource. Should never return empty. Use permission.NONE instead.
|
||||
*/
|
||||
virtual future<permission_set> authorize(::shared_ptr<authenticated_user>, data_resource) const = 0;
|
||||
|
||||
/**
|
||||
* Grants a set of permissions on a resource to a user.
|
||||
* The opposite of revoke().
|
||||
*
|
||||
* @param performer User who grants the permissions.
|
||||
* @param permissions Set of permissions to grant.
|
||||
* @param to Grantee of the permissions.
|
||||
* @param resource Resource on which to grant the permissions.
|
||||
*
|
||||
* @throws RequestValidationException
|
||||
* @throws RequestExecutionException
|
||||
*/
|
||||
virtual future<> grant(::shared_ptr<authenticated_user> performer, permission_set, data_resource, sstring to) = 0;
|
||||
|
||||
/**
|
||||
* Revokes a set of permissions on a resource from a user.
|
||||
* The opposite of grant().
|
||||
*
|
||||
* @param performer User who revokes the permissions.
|
||||
* @param permissions Set of permissions to revoke.
|
||||
* @param from Revokee of the permissions.
|
||||
* @param resource Resource on which to revoke the permissions.
|
||||
*
|
||||
* @throws RequestValidationException
|
||||
* @throws RequestExecutionException
|
||||
*/
|
||||
virtual future<> revoke(::shared_ptr<authenticated_user> performer, permission_set, data_resource, sstring from) = 0;
|
||||
|
||||
/**
|
||||
* Returns a list of permissions on a resource of a user.
|
||||
*
|
||||
* @param performer User who wants to see the permissions.
|
||||
* @param permissions Set of Permission values the user is interested in. The result should only include the matching ones.
|
||||
* @param resource The resource on which permissions are requested. Can be null, in which case permissions on all resources
|
||||
* should be returned.
|
||||
* @param of The user whose permissions are requested. Can be null, in which case permissions of every user should be returned.
|
||||
*
|
||||
* @return All of the matching permission that the requesting user is authorized to know about.
|
||||
*
|
||||
* @throws RequestValidationException
|
||||
* @throws RequestExecutionException
|
||||
*/
|
||||
virtual future<std::vector<permission_details>> list(::shared_ptr<authenticated_user> performer, permission_set, optional<data_resource>, optional<sstring>) const = 0;
|
||||
|
||||
/**
|
||||
* This method is called before deleting a user with DROP USER query so that a new user with the same
|
||||
* name wouldn't inherit permissions of the deleted user in the future.
|
||||
*
|
||||
* @param droppedUser The user to revoke all permissions from.
|
||||
*/
|
||||
virtual future<> revoke_all(sstring dropped_user) = 0;
|
||||
|
||||
/**
|
||||
* This method is called after a resource is removed (i.e. keyspace or a table is dropped).
|
||||
*
|
||||
* @param droppedResource The resource to revoke all permissions on.
|
||||
*/
|
||||
virtual future<> revoke_all(data_resource) = 0;
|
||||
|
||||
/**
|
||||
* Set of resources that should be made inaccessible to users and only accessible internally.
|
||||
*
|
||||
* @return Keyspaces, column families that will be unmodifiable by users; other resources.
|
||||
*/
|
||||
virtual const resource_ids& protected_resources() = 0;
|
||||
|
||||
/**
|
||||
* Validates configuration of IAuthorizer implementation (if configurable).
|
||||
*
|
||||
* @throws ConfigurationException when there is a configuration error.
|
||||
*/
|
||||
virtual future<> validate_configuration() const = 0;
|
||||
|
||||
/**
|
||||
* Setup is called once upon system startup to initialize the IAuthorizer.
|
||||
*
|
||||
* For example, use this method to create any required keyspaces/column families.
|
||||
*/
|
||||
static future<> setup(const sstring& type);
|
||||
|
||||
/**
|
||||
* Returns the system authorizer. Must have called setup before calling this.
|
||||
*/
|
||||
static authorizer& get();
|
||||
};
|
||||
|
||||
}
|
||||
@@ -17,9 +17,9 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2016 ScyllaDB
|
||||
* Copyright 2016 Cloudius Systems
|
||||
*
|
||||
* Modified by ScyllaDB
|
||||
* Modified by Cloudius Systems
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -158,15 +158,7 @@ bool auth::data_resource::exists() const {
|
||||
}
|
||||
|
||||
sstring auth::data_resource::to_string() const {
|
||||
switch (get_level()) {
|
||||
case level::ROOT:
|
||||
return "<all keyspaces>";
|
||||
case level::KEYSPACE:
|
||||
return sprint("<keyspace %s>", _ks);
|
||||
case level::COLUMN_FAMILY:
|
||||
default:
|
||||
return sprint("<table %s.%s>", _ks, _cf);
|
||||
}
|
||||
return name();
|
||||
}
|
||||
|
||||
bool auth::data_resource::operator==(const data_resource& v) const {
|
||||
@@ -178,6 +170,6 @@ bool auth::data_resource::operator<(const data_resource& v) const {
|
||||
}
|
||||
|
||||
std::ostream& auth::operator<<(std::ostream& os, const data_resource& r) {
|
||||
return os << r.to_string();
|
||||
return os << r.name();
|
||||
}
|
||||
|
||||
|
||||
@@ -17,9 +17,9 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2016 ScyllaDB
|
||||
* Copyright 2016 Cloudius Systems
|
||||
*
|
||||
* Modified by ScyllaDB
|
||||
* Modified by Cloudius Systems
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -41,9 +41,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "utils/hash.hh"
|
||||
#include <iosfwd>
|
||||
#include <set>
|
||||
#include <seastar/core/sstring.hh>
|
||||
|
||||
namespace auth {
|
||||
@@ -138,17 +136,8 @@ public:
|
||||
|
||||
bool operator==(const data_resource&) const;
|
||||
bool operator<(const data_resource&) const;
|
||||
|
||||
size_t hash_value() const {
|
||||
return utils::tuple_hash()(_ks, _cf);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Resource id mappings, i.e. keyspace and/or column families.
|
||||
*/
|
||||
using resource_ids = std::set<data_resource>;
|
||||
|
||||
std::ostream& operator<<(std::ostream&, const data_resource&);
|
||||
|
||||
}
|
||||
|
||||
@@ -1,240 +0,0 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2016 ScyllaDB
|
||||
*
|
||||
* Modified by ScyllaDB
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is part of Scylla.
|
||||
*
|
||||
* Scylla is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Scylla is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Scylla. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <crypt.h>
|
||||
#include <random>
|
||||
#include <chrono>
|
||||
|
||||
#include <seastar/core/reactor.hh>
|
||||
|
||||
#include "auth.hh"
|
||||
#include "default_authorizer.hh"
|
||||
#include "authenticated_user.hh"
|
||||
#include "permission.hh"
|
||||
#include "cql3/query_processor.hh"
|
||||
#include "exceptions/exceptions.hh"
|
||||
#include "log.hh"
|
||||
|
||||
const sstring auth::default_authorizer::DEFAULT_AUTHORIZER_NAME(
|
||||
"org.apache.cassandra.auth.CassandraAuthorizer");
|
||||
|
||||
static const sstring USER_NAME = "username";
|
||||
static const sstring RESOURCE_NAME = "resource";
|
||||
static const sstring PERMISSIONS_NAME = "permissions";
|
||||
static const sstring PERMISSIONS_CF = "permissions";
|
||||
|
||||
static logging::logger logger("default_authorizer");
|
||||
|
||||
auth::default_authorizer::default_authorizer() {
|
||||
}
|
||||
auth::default_authorizer::~default_authorizer() {
|
||||
}
|
||||
|
||||
future<> auth::default_authorizer::init() {
|
||||
sstring create_table = sprint("CREATE TABLE %s.%s ("
|
||||
"%s text,"
|
||||
"%s text,"
|
||||
"%s set<text>,"
|
||||
"PRIMARY KEY(%s, %s)"
|
||||
") WITH gc_grace_seconds=%d", auth::auth::AUTH_KS,
|
||||
PERMISSIONS_CF, USER_NAME, RESOURCE_NAME, PERMISSIONS_NAME,
|
||||
USER_NAME, RESOURCE_NAME, 90 * 24 * 60 * 60); // 3 months.
|
||||
|
||||
return auth::setup_table(PERMISSIONS_CF, create_table);
|
||||
}
|
||||
|
||||
|
||||
future<auth::permission_set> auth::default_authorizer::authorize(
|
||||
::shared_ptr<authenticated_user> user, data_resource resource) const {
|
||||
return user->is_super().then([this, user, resource = std::move(resource)](bool is_super) {
|
||||
if (is_super) {
|
||||
return make_ready_future<permission_set>(permissions::ALL);
|
||||
}
|
||||
|
||||
/**
|
||||
* TOOD: could create actual data type for permission (translating string<->perm),
|
||||
* but this seems overkill right now. We still must store strings so...
|
||||
*/
|
||||
auto& qp = cql3::get_local_query_processor();
|
||||
auto query = sprint("SELECT %s FROM %s.%s WHERE %s = ? AND %s = ?"
|
||||
, PERMISSIONS_NAME, auth::AUTH_KS, PERMISSIONS_CF, USER_NAME, RESOURCE_NAME);
|
||||
return qp.process(query, db::consistency_level::LOCAL_ONE, {user->name(), resource.name() })
|
||||
.then_wrapped([=](future<::shared_ptr<cql3::untyped_result_set>> f) {
|
||||
try {
|
||||
auto res = f.get0();
|
||||
|
||||
if (res->empty() || !res->one().has(PERMISSIONS_NAME)) {
|
||||
return make_ready_future<permission_set>(permissions::NONE);
|
||||
}
|
||||
return make_ready_future<permission_set>(permissions::from_strings(res->one().get_set<sstring>(PERMISSIONS_NAME)));
|
||||
} catch (exceptions::request_execution_exception& e) {
|
||||
logger.warn("CassandraAuthorizer failed to authorize {} for {}", user->name(), resource);
|
||||
return make_ready_future<permission_set>(permissions::NONE);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
#include <boost/range.hpp>
|
||||
|
||||
future<> auth::default_authorizer::modify(
|
||||
::shared_ptr<authenticated_user> performer, permission_set set,
|
||||
data_resource resource, sstring user, sstring op) {
|
||||
// TODO: why does this not check super user?
|
||||
auto& qp = cql3::get_local_query_processor();
|
||||
auto query = sprint("UPDATE %s.%s SET %s = %s %s ? WHERE %s = ? AND %s = ?",
|
||||
auth::AUTH_KS, PERMISSIONS_CF, PERMISSIONS_NAME,
|
||||
PERMISSIONS_NAME, op, USER_NAME, RESOURCE_NAME);
|
||||
return qp.process(query, db::consistency_level::ONE, {
|
||||
permissions::to_strings(set), user, resource.name() }).discard_result();
|
||||
}
|
||||
|
||||
|
||||
future<> auth::default_authorizer::grant(
|
||||
::shared_ptr<authenticated_user> performer, permission_set set,
|
||||
data_resource resource, sstring to) {
|
||||
return modify(std::move(performer), std::move(set), std::move(resource), std::move(to), "+");
|
||||
}
|
||||
|
||||
future<> auth::default_authorizer::revoke(
|
||||
::shared_ptr<authenticated_user> performer, permission_set set,
|
||||
data_resource resource, sstring from) {
|
||||
return modify(std::move(performer), std::move(set), std::move(resource), std::move(from), "-");
|
||||
}
|
||||
|
||||
future<std::vector<auth::permission_details>> auth::default_authorizer::list(
|
||||
::shared_ptr<authenticated_user> performer, permission_set set,
|
||||
optional<data_resource> resource, optional<sstring> user) const {
|
||||
return performer->is_super().then([this, performer, set = std::move(set), resource = std::move(resource), user = std::move(user)](bool is_super) {
|
||||
if (!is_super && (!user || performer->name() != *user)) {
|
||||
throw exceptions::unauthorized_exception(sprint("You are not authorized to view %s's permissions", user ? *user : "everyone"));
|
||||
}
|
||||
|
||||
auto query = sprint("SELECT %s, %s, %s FROM %s.%s", USER_NAME, RESOURCE_NAME, PERMISSIONS_NAME, auth::AUTH_KS, PERMISSIONS_CF);
|
||||
auto& qp = cql3::get_local_query_processor();
|
||||
|
||||
// Oh, look, it is a case where it does not pay off to have
|
||||
// parameters to process in an initializer list.
|
||||
future<::shared_ptr<cql3::untyped_result_set>> f = make_ready_future<::shared_ptr<cql3::untyped_result_set>>();
|
||||
|
||||
if (resource && user) {
|
||||
query += sprint(" WHERE %s = ? AND %s = ?", USER_NAME, RESOURCE_NAME);
|
||||
f = qp.process(query, db::consistency_level::ONE, {*user, resource->name()});
|
||||
} else if (resource) {
|
||||
query += sprint(" WHERE %s = ? ALLOW FILTERING", RESOURCE_NAME);
|
||||
f = qp.process(query, db::consistency_level::ONE, {resource->name()});
|
||||
} else if (user) {
|
||||
query += sprint(" WHERE %s = ?", USER_NAME);
|
||||
f = qp.process(query, db::consistency_level::ONE, {*user});
|
||||
} else {
|
||||
f = qp.process(query, db::consistency_level::ONE, {});
|
||||
}
|
||||
|
||||
return f.then([set](::shared_ptr<cql3::untyped_result_set> res) {
|
||||
std::vector<permission_details> result;
|
||||
|
||||
for (auto& row : *res) {
|
||||
if (row.has(PERMISSIONS_NAME)) {
|
||||
auto username = row.get_as<sstring>(USER_NAME);
|
||||
auto resource = data_resource::from_name(row.get_as<sstring>(RESOURCE_NAME));
|
||||
auto ps = permissions::from_strings(row.get_set<sstring>(PERMISSIONS_NAME));
|
||||
ps = permission_set::from_mask(ps.mask() & set.mask());
|
||||
|
||||
result.emplace_back(permission_details {username, resource, ps});
|
||||
}
|
||||
}
|
||||
return make_ready_future<std::vector<permission_details>>(std::move(result));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
future<> auth::default_authorizer::revoke_all(sstring dropped_user) {
|
||||
auto& qp = cql3::get_local_query_processor();
|
||||
auto query = sprint("DELETE FROM %s.%s WHERE %s = ?", auth::AUTH_KS,
|
||||
PERMISSIONS_CF, USER_NAME);
|
||||
return qp.process(query, db::consistency_level::ONE, { dropped_user }).discard_result().handle_exception(
|
||||
[dropped_user](auto ep) {
|
||||
try {
|
||||
std::rethrow_exception(ep);
|
||||
} catch (exceptions::request_execution_exception& e) {
|
||||
logger.warn("CassandraAuthorizer failed to revoke all permissions of {}: {}", dropped_user, e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
future<> auth::default_authorizer::revoke_all(data_resource resource) {
|
||||
auto& qp = cql3::get_local_query_processor();
|
||||
auto query = sprint("SELECT %s FROM %s.%s WHERE %s = ? ALLOW FILTERING",
|
||||
USER_NAME, auth::AUTH_KS, PERMISSIONS_CF, RESOURCE_NAME);
|
||||
return qp.process(query, db::consistency_level::LOCAL_ONE, { resource.name() })
|
||||
.then_wrapped([resource, &qp](future<::shared_ptr<cql3::untyped_result_set>> f) {
|
||||
try {
|
||||
auto res = f.get0();
|
||||
return parallel_for_each(res->begin(), res->end(), [&qp, res, resource](const cql3::untyped_result_set::row& r) {
|
||||
auto query = sprint("DELETE FROM %s.%s WHERE %s = ? AND %s = ?"
|
||||
, auth::AUTH_KS, PERMISSIONS_CF, USER_NAME, RESOURCE_NAME);
|
||||
return qp.process(query, db::consistency_level::LOCAL_ONE, { r.get_as<sstring>(USER_NAME), resource.name() })
|
||||
.discard_result().handle_exception([resource](auto ep) {
|
||||
try {
|
||||
std::rethrow_exception(ep);
|
||||
} catch (exceptions::request_execution_exception& e) {
|
||||
logger.warn("CassandraAuthorizer failed to revoke all permissions on {}: {}", resource, e);
|
||||
}
|
||||
|
||||
});
|
||||
});
|
||||
} catch (exceptions::request_execution_exception& e) {
|
||||
logger.warn("CassandraAuthorizer failed to revoke all permissions on {}: {}", resource, e);
|
||||
return make_ready_future();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
const auth::resource_ids& auth::default_authorizer::protected_resources() {
|
||||
static const resource_ids ids({ data_resource(auth::AUTH_KS, PERMISSIONS_CF) });
|
||||
return ids;
|
||||
}
|
||||
|
||||
future<> auth::default_authorizer::validate_configuration() const {
|
||||
return make_ready_future();
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2016 ScyllaDB
|
||||
*
|
||||
* Modified by ScyllaDB
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is part of Scylla.
|
||||
*
|
||||
* Scylla is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Scylla is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Scylla. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "authorizer.hh"
|
||||
|
||||
namespace auth {
|
||||
|
||||
class default_authorizer : public authorizer {
|
||||
public:
|
||||
static const sstring DEFAULT_AUTHORIZER_NAME;
|
||||
|
||||
default_authorizer();
|
||||
~default_authorizer();
|
||||
|
||||
future<> init();
|
||||
|
||||
future<permission_set> authorize(::shared_ptr<authenticated_user>, data_resource) const override;
|
||||
|
||||
future<> grant(::shared_ptr<authenticated_user>, permission_set, data_resource, sstring) override;
|
||||
|
||||
future<> revoke(::shared_ptr<authenticated_user>, permission_set, data_resource, sstring) override;
|
||||
|
||||
future<std::vector<permission_details>> list(::shared_ptr<authenticated_user>, permission_set, optional<data_resource>, optional<sstring>) const override;
|
||||
|
||||
future<> revoke_all(sstring) override;
|
||||
|
||||
future<> revoke_all(data_resource) override;
|
||||
|
||||
const resource_ids& protected_resources() override;
|
||||
|
||||
future<> validate_configuration() const override;
|
||||
|
||||
private:
|
||||
future<> modify(::shared_ptr<authenticated_user>, permission_set, data_resource, sstring, sstring);
|
||||
};
|
||||
|
||||
} /* namespace auth */
|
||||
|
||||
@@ -17,9 +17,9 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2016 ScyllaDB
|
||||
* Copyright 2016 Cloudius Systems
|
||||
*
|
||||
* Modified by ScyllaDB
|
||||
* Modified by Cloudius Systems
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -160,8 +160,8 @@ future<> auth::password_authenticator::init() {
|
||||
|
||||
return auth::setup_table(CREDENTIALS_CF, create_table).then([this] {
|
||||
// instead of once-timer, just schedule this later
|
||||
auth::schedule_when_up([] {
|
||||
return auth::has_existing_users(CREDENTIALS_CF, DEFAULT_USER_NAME, USER_NAME).then([](bool exists) {
|
||||
sleep(auth::SUPERUSER_SETUP_DELAY).then([] {
|
||||
auth::has_existing_users(CREDENTIALS_CF, DEFAULT_USER_NAME, USER_NAME).then([](bool exists) {
|
||||
if (!exists) {
|
||||
cql3::get_local_query_processor().process(sprint("INSERT INTO %s.%s (%s, %s) VALUES (?, ?) USING TIMESTAMP 0",
|
||||
auth::AUTH_KS,
|
||||
@@ -281,9 +281,8 @@ future<> auth::password_authenticator::drop(sstring username)
|
||||
}
|
||||
}
|
||||
|
||||
const auth::resource_ids& auth::password_authenticator::protected_resources() const {
|
||||
static const resource_ids ids({ data_resource(auth::AUTH_KS, CREDENTIALS_CF) });
|
||||
return ids;
|
||||
auth::authenticator::resource_ids auth::password_authenticator::protected_resources() const {
|
||||
return { data_resource(auth::AUTH_KS, CREDENTIALS_CF) };
|
||||
}
|
||||
|
||||
::shared_ptr<auth::authenticator::sasl_challenge> auth::password_authenticator::new_sasl_challenge() const {
|
||||
|
||||
@@ -17,9 +17,9 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2016 ScyllaDB
|
||||
* Copyright 2016 Cloudius Systems
|
||||
*
|
||||
* Modified by ScyllaDB
|
||||
* Modified by Cloudius Systems
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -62,7 +62,7 @@ public:
|
||||
future<> create(sstring username, const option_map& options) throw(exceptions::request_validation_exception, exceptions::request_execution_exception) override;
|
||||
future<> alter(sstring username, const option_map& options) throw(exceptions::request_validation_exception, exceptions::request_execution_exception) override;
|
||||
future<> drop(sstring username) throw(exceptions::request_validation_exception, exceptions::request_execution_exception) override;
|
||||
const resource_ids& protected_resources() const override;
|
||||
resource_ids protected_resources() const override;
|
||||
::shared_ptr<sasl_challenge> new_sasl_challenge() const override;
|
||||
|
||||
|
||||
|
||||
@@ -17,9 +17,9 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2016 ScyllaDB
|
||||
* Copyright 2016 Cloudius Systems
|
||||
*
|
||||
* Modified by ScyllaDB
|
||||
* Modified by Cloudius Systems
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -39,63 +39,11 @@
|
||||
* along with Scylla. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <unordered_map>
|
||||
#include "permission.hh"
|
||||
|
||||
const auth::permission_set auth::permissions::ALL_DATA =
|
||||
auth::permission_set::of<auth::permission::CREATE,
|
||||
auth::permission::ALTER, auth::permission::DROP,
|
||||
auth::permission::SELECT,
|
||||
auth::permission::MODIFY,
|
||||
auth::permission::AUTHORIZE>();
|
||||
const auth::permission_set auth::permissions::ALL = auth::permissions::ALL_DATA;
|
||||
const auth::permission_set auth::permissions::NONE;
|
||||
const auth::permission_set auth::permissions::ALTERATIONS =
|
||||
auth::permission_set::of<auth::permission::CREATE,
|
||||
auth::permission::ALTER, auth::permission::DROP>();
|
||||
|
||||
static const std::unordered_map<sstring, auth::permission> permission_names({
|
||||
{ "READ", auth::permission::READ },
|
||||
{ "WRITE", auth::permission::WRITE },
|
||||
{ "CREATE", auth::permission::CREATE },
|
||||
{ "ALTER", auth::permission::ALTER },
|
||||
{ "DROP", auth::permission::DROP },
|
||||
{ "SELECT", auth::permission::SELECT },
|
||||
{ "MODIFY", auth::permission::MODIFY },
|
||||
{ "AUTHORIZE", auth::permission::AUTHORIZE },
|
||||
});
|
||||
|
||||
const sstring& auth::permissions::to_string(permission p) {
|
||||
for (auto& v : permission_names) {
|
||||
if (v.second == p) {
|
||||
return v.first;
|
||||
}
|
||||
}
|
||||
throw std::out_of_range("unknown permission");
|
||||
}
|
||||
|
||||
auth::permission auth::permissions::from_string(const sstring& s) {
|
||||
return permission_names.at(s);
|
||||
}
|
||||
|
||||
std::unordered_set<sstring> auth::permissions::to_strings(const permission_set& set) {
|
||||
std::unordered_set<sstring> res;
|
||||
for (auto& v : permission_names) {
|
||||
if (set.contains(v.second)) {
|
||||
res.emplace(v.first);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
auth::permission_set auth::permissions::from_strings(const std::unordered_set<sstring>& set) {
|
||||
permission_set res = auth::permissions::NONE;
|
||||
for (auto& s : set) {
|
||||
res.set(from_string(s));
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
bool auth::operator<(const permission_set& p1, const permission_set& p2) {
|
||||
return p1.mask() < p2.mask();
|
||||
}
|
||||
const auth::permission_set auth::ALL_DATA = auth::permission_set::of
|
||||
< auth::permission::CREATE, auth::permission::ALTER,
|
||||
auth::permission::DROP, auth::permission::SELECT,
|
||||
auth::permission::MODIFY, auth::permission::AUTHORIZE>();
|
||||
const auth::permission_set auth::ALL = auth::ALL_DATA;
|
||||
const auth::permission_set auth::NONE;
|
||||
|
||||
@@ -17,9 +17,9 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2016 ScyllaDB
|
||||
* Copyright 2016 Cloudius Systems
|
||||
*
|
||||
* Modified by ScyllaDB
|
||||
* Modified by Cloudius Systems
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -41,9 +41,6 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <unordered_set>
|
||||
#include <seastar/core/sstring.hh>
|
||||
|
||||
#include "enum_set.hh"
|
||||
|
||||
namespace auth {
|
||||
@@ -77,22 +74,8 @@ typedef enum_set<super_enum<permission,
|
||||
permission::MODIFY,
|
||||
permission::AUTHORIZE>> permission_set;
|
||||
|
||||
bool operator<(const permission_set&, const permission_set&);
|
||||
|
||||
namespace permissions {
|
||||
|
||||
extern const permission_set ALL_DATA;
|
||||
extern const permission_set ALL;
|
||||
extern const permission_set NONE;
|
||||
extern const permission_set ALTERATIONS;
|
||||
|
||||
const sstring& to_string(permission);
|
||||
permission from_string(const sstring&);
|
||||
|
||||
std::unordered_set<sstring> to_strings(const permission_set&);
|
||||
permission_set from_strings(const std::unordered_set<sstring>&);
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
2
bytes.cc
2
bytes.cc
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014 ScyllaDB
|
||||
* Copyright (C) 2014 Cloudius Systems, Ltd.
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
2
bytes.hh
2
bytes.hh
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2015 ScyllaDB
|
||||
* Copyright (C) 2015 Cloudius Systems, Ltd.
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2015 ScyllaDB
|
||||
* Copyright 2015 Cloudius Systems
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -21,12 +21,11 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <boost/range/iterator_range.hpp>
|
||||
|
||||
#include "bytes.hh"
|
||||
#include "types.hh"
|
||||
#include "net/byteorder.hh"
|
||||
#include "core/unaligned.hh"
|
||||
#include "hashing.hh"
|
||||
#include "seastar/core/simple-stream.hh"
|
||||
|
||||
/**
|
||||
* Utility for writing data into a buffer when its final size is not known up front.
|
||||
*
|
||||
@@ -43,14 +42,6 @@ private:
|
||||
struct chunk {
|
||||
// FIXME: group fragment pointers to reduce pointer chasing when packetizing
|
||||
std::unique_ptr<chunk> next;
|
||||
~chunk() {
|
||||
auto p = std::move(next);
|
||||
while (p) {
|
||||
// Avoid recursion when freeing chunks
|
||||
auto p_next = std::move(p->next);
|
||||
p = std::move(p_next);
|
||||
}
|
||||
}
|
||||
size_type offset; // Also means "size" after chunk is closed
|
||||
size_type size;
|
||||
value_type data[0];
|
||||
@@ -172,12 +163,16 @@ public:
|
||||
template <typename T>
|
||||
struct place_holder {
|
||||
value_type* ptr;
|
||||
// makes the place_holder looks like a stream
|
||||
seastar::simple_output_stream get_stream() {
|
||||
return seastar::simple_output_stream{reinterpret_cast<char*>(ptr)};
|
||||
}
|
||||
};
|
||||
|
||||
// Writes given values in big-endian format
|
||||
template <typename T>
|
||||
inline
|
||||
std::enable_if_t<std::is_fundamental<T>::value, void>
|
||||
write(T val) {
|
||||
*reinterpret_cast<unaligned<T>*>(alloc(sizeof(T))) = net::hton(val);
|
||||
}
|
||||
|
||||
// Returns a place holder for a value to be written later.
|
||||
template <typename T>
|
||||
inline
|
||||
@@ -211,8 +206,17 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void write(const char* ptr, size_t size) {
|
||||
write(bytes_view(reinterpret_cast<const signed char*>(ptr), size));
|
||||
// Writes given sequence of bytes with a preceding length component encoded in big-endian format
|
||||
inline void write_blob(bytes_view v) {
|
||||
assert((size_type)v.size() == v.size());
|
||||
write<size_type>(v.size());
|
||||
write(v);
|
||||
}
|
||||
|
||||
// Writes given value into the place holder in big-endian format
|
||||
template <typename T>
|
||||
inline void set(place_holder<T> ph, T val) {
|
||||
*reinterpret_cast<unaligned<T>*>(ph.ptr) = net::hton(val);
|
||||
}
|
||||
|
||||
bool is_linearized() const {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2015 ScyllaDB
|
||||
* Copyright (C) 2015 Cloudius Systems, Ltd.
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
@@ -24,66 +24,75 @@
|
||||
#include "mutation_partition_serializer.hh"
|
||||
#include "converting_mutation_partition_applier.hh"
|
||||
#include "hashing_partition_visitor.hh"
|
||||
#include "utils/UUID.hh"
|
||||
#include "serializer.hh"
|
||||
#include "idl/uuid.dist.hh"
|
||||
#include "idl/keys.dist.hh"
|
||||
#include "idl/mutation.dist.hh"
|
||||
#include "serializer_impl.hh"
|
||||
#include "serialization_visitors.hh"
|
||||
#include "idl/uuid.dist.impl.hh"
|
||||
#include "idl/keys.dist.impl.hh"
|
||||
#include "idl/mutation.dist.impl.hh"
|
||||
|
||||
template class db::serializer<canonical_mutation>;
|
||||
|
||||
//
|
||||
// Representation layout:
|
||||
//
|
||||
// <canonical_mutation> ::= <column_family_id> <table_schema_version> <partition_key> <column-mapping> <partition>
|
||||
//
|
||||
// For <partition> see mutation_partition_serializer.cc
|
||||
// For <column-mapping> see db::serializer<column_mapping>
|
||||
//
|
||||
|
||||
canonical_mutation::canonical_mutation(bytes data)
|
||||
: _data(std::move(data))
|
||||
{ }
|
||||
|
||||
canonical_mutation::canonical_mutation(const mutation& m)
|
||||
{
|
||||
mutation_partition_serializer part_ser(*m.schema(), m.partition());
|
||||
|
||||
bytes_ostream out;
|
||||
ser::writer_of_canonical_mutation wr(out);
|
||||
std::move(wr).write_table_id(m.schema()->id())
|
||||
.write_schema_version(m.schema()->version())
|
||||
.write_key(m.key())
|
||||
.write_mapping(m.schema()->get_column_mapping())
|
||||
.partition([&] (auto wr) {
|
||||
part_ser.write(std::move(wr));
|
||||
}).end_canonical_mutation();
|
||||
_data = to_bytes(out.linearize());
|
||||
}
|
||||
|
||||
utils::UUID canonical_mutation::column_family_id() const {
|
||||
auto in = ser::as_input_stream(_data);
|
||||
auto mv = ser::deserialize(in, boost::type<ser::canonical_mutation_view>());
|
||||
return mv.table_id();
|
||||
}
|
||||
: _data([&m] {
|
||||
bytes_ostream out;
|
||||
db::serializer<utils::UUID>(m.column_family_id()).write(out);
|
||||
db::serializer<table_schema_version>(m.schema()->version()).write(out);
|
||||
db::serializer<partition_key_view>(m.key()).write(out);
|
||||
db::serializer<column_mapping>(m.schema()->get_column_mapping()).write(out);
|
||||
mutation_partition_serializer ser(*m.schema(), m.partition());
|
||||
ser.write(out);
|
||||
return to_bytes(out.linearize());
|
||||
}())
|
||||
{ }
|
||||
|
||||
mutation canonical_mutation::to_mutation(schema_ptr s) const {
|
||||
auto in = ser::as_input_stream(_data);
|
||||
auto mv = ser::deserialize(in, boost::type<ser::canonical_mutation_view>());
|
||||
data_input in(_data);
|
||||
|
||||
auto cf_id = mv.table_id();
|
||||
auto cf_id = db::serializer<utils::UUID>::read(in);
|
||||
if (s->id() != cf_id) {
|
||||
throw std::runtime_error(sprint("Attempted to deserialize canonical_mutation of table %s with schema of table %s (%s.%s)",
|
||||
cf_id, s->id(), s->ks_name(), s->cf_name()));
|
||||
}
|
||||
|
||||
auto version = mv.schema_version();
|
||||
auto pk = mv.key();
|
||||
auto version = db::serializer<table_schema_version>::read(in);
|
||||
auto pk = partition_key(db::serializer<partition_key_view>::read(in));
|
||||
|
||||
mutation m(std::move(pk), std::move(s));
|
||||
|
||||
if (version == m.schema()->version()) {
|
||||
auto partition_view = mutation_partition_view::from_view(mv.partition());
|
||||
db::serializer<column_mapping>::skip(in);
|
||||
auto partition_view = mutation_partition_serializer::read_as_view(in);
|
||||
m.partition().apply(*m.schema(), partition_view, *m.schema());
|
||||
} else {
|
||||
column_mapping cm = mv.mapping();
|
||||
column_mapping cm = db::serializer<column_mapping>::read(in);
|
||||
converting_mutation_partition_applier v(cm, *m.schema(), m.partition());
|
||||
auto partition_view = mutation_partition_view::from_view(mv.partition());
|
||||
auto partition_view = mutation_partition_serializer::read_as_view(in);
|
||||
partition_view.accept(cm, v);
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
template<>
|
||||
db::serializer<canonical_mutation>::serializer(const canonical_mutation& v)
|
||||
: _item(v)
|
||||
, _size(db::serializer<bytes>(v._data).size())
|
||||
{ }
|
||||
|
||||
template<>
|
||||
void
|
||||
db::serializer<canonical_mutation>::write(output& out, const canonical_mutation& v) {
|
||||
db::serializer<bytes>(v._data).write(out);
|
||||
}
|
||||
|
||||
template<>
|
||||
canonical_mutation db::serializer<canonical_mutation>::read(input& in) {
|
||||
return canonical_mutation(db::serializer<bytes>::read(in));
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "bytes.hh"
|
||||
#include "schema.hh"
|
||||
#include "database_fwd.hh"
|
||||
#include "db/serializer.hh"
|
||||
#include "mutation_partition_visitor.hh"
|
||||
#include "mutation_partition_serializer.hh"
|
||||
|
||||
@@ -32,8 +33,8 @@
|
||||
// Safe to pass serialized across nodes.
|
||||
class canonical_mutation {
|
||||
bytes _data;
|
||||
canonical_mutation(bytes);
|
||||
public:
|
||||
explicit canonical_mutation(bytes);
|
||||
explicit canonical_mutation(const mutation&);
|
||||
|
||||
canonical_mutation(canonical_mutation&&) = default;
|
||||
@@ -48,8 +49,23 @@ public:
|
||||
// is not intended, user should sync the schema first.
|
||||
mutation to_mutation(schema_ptr) const;
|
||||
|
||||
utils::UUID column_family_id() const;
|
||||
|
||||
const bytes& representation() const { return _data; }
|
||||
|
||||
friend class db::serializer<canonical_mutation>;
|
||||
};
|
||||
//
|
||||
//template<>
|
||||
//struct hash<canonical_mutation> {
|
||||
// template<typename Hasher>
|
||||
// void operator()(Hasher& h, const canonical_mutation& m) const {
|
||||
// m.feed_hash(h);
|
||||
// }
|
||||
//};
|
||||
|
||||
namespace db {
|
||||
|
||||
template<> serializer<canonical_mutation>::serializer(const canonical_mutation&);
|
||||
template<> void serializer<canonical_mutation>::write(output&, const canonical_mutation&);
|
||||
template<> canonical_mutation serializer<canonical_mutation>::read(input&);
|
||||
|
||||
extern template class serializer<canonical_mutation>;
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2015 ScyllaDB
|
||||
* Copyright 2015 Cloudius Systems
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,151 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016 ScyllaDB
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is part of Scylla.
|
||||
*
|
||||
* Scylla is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Scylla is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Scylla. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "seastar/core/file.hh"
|
||||
#include "disk-error-handler.hh"
|
||||
|
||||
class checked_file_impl : public file_impl {
|
||||
public:
|
||||
|
||||
checked_file_impl(disk_error_signal_type& s, file f)
|
||||
: _signal(s) , _file(f) {
|
||||
_memory_dma_alignment = f.memory_dma_alignment();
|
||||
_disk_read_dma_alignment = f.disk_read_dma_alignment();
|
||||
_disk_write_dma_alignment = f.disk_write_dma_alignment();
|
||||
}
|
||||
|
||||
virtual future<size_t> write_dma(uint64_t pos, const void* buffer, size_t len, const io_priority_class& pc) override {
|
||||
return do_io_check(_signal, [&] {
|
||||
return get_file_impl(_file)->write_dma(pos, buffer, len, pc);
|
||||
});
|
||||
}
|
||||
|
||||
virtual future<size_t> write_dma(uint64_t pos, std::vector<iovec> iov, const io_priority_class& pc) override {
|
||||
return do_io_check(_signal, [&] {
|
||||
return get_file_impl(_file)->write_dma(pos, iov, pc);
|
||||
});
|
||||
}
|
||||
|
||||
virtual future<size_t> read_dma(uint64_t pos, void* buffer, size_t len, const io_priority_class& pc) override {
|
||||
return do_io_check(_signal, [&] {
|
||||
return get_file_impl(_file)->read_dma(pos, buffer, len, pc);
|
||||
});
|
||||
}
|
||||
|
||||
virtual future<size_t> read_dma(uint64_t pos, std::vector<iovec> iov, const io_priority_class& pc) override {
|
||||
return do_io_check(_signal, [&] {
|
||||
return get_file_impl(_file)->read_dma(pos, iov, pc);
|
||||
});
|
||||
}
|
||||
|
||||
virtual future<> flush(void) override {
|
||||
return do_io_check(_signal, [&] {
|
||||
return get_file_impl(_file)->flush();
|
||||
});
|
||||
}
|
||||
|
||||
virtual future<struct stat> stat(void) override {
|
||||
return do_io_check(_signal, [&] {
|
||||
return get_file_impl(_file)->stat();
|
||||
});
|
||||
}
|
||||
|
||||
virtual future<> truncate(uint64_t length) override {
|
||||
return do_io_check(_signal, [&] {
|
||||
return get_file_impl(_file)->truncate(length);
|
||||
});
|
||||
}
|
||||
|
||||
virtual future<> discard(uint64_t offset, uint64_t length) override {
|
||||
return do_io_check(_signal, [&] {
|
||||
return get_file_impl(_file)->discard(offset, length);
|
||||
});
|
||||
}
|
||||
|
||||
virtual future<> allocate(uint64_t position, uint64_t length) override {
|
||||
return do_io_check(_signal, [&] {
|
||||
return get_file_impl(_file)->allocate(position, length);
|
||||
});
|
||||
}
|
||||
|
||||
virtual future<uint64_t> size(void) override {
|
||||
return do_io_check(_signal, [&] {
|
||||
return get_file_impl(_file)->size();
|
||||
});
|
||||
}
|
||||
|
||||
virtual future<> close() override {
|
||||
return do_io_check(_signal, [&] {
|
||||
return get_file_impl(_file)->close();
|
||||
});
|
||||
}
|
||||
|
||||
virtual subscription<directory_entry> list_directory(std::function<future<> (directory_entry de)> next) override {
|
||||
return do_io_check(_signal, [&] {
|
||||
return get_file_impl(_file)->list_directory(next);
|
||||
});
|
||||
}
|
||||
|
||||
private:
|
||||
disk_error_signal_type &_signal;
|
||||
file _file;
|
||||
};
|
||||
|
||||
inline file make_checked_file(disk_error_signal_type& signal, file& f)
|
||||
{
|
||||
return file(::make_shared<checked_file_impl>(signal, f));
|
||||
}
|
||||
|
||||
future<file>
|
||||
inline open_checked_file_dma(disk_error_signal_type& signal,
|
||||
sstring name, open_flags flags,
|
||||
file_open_options options)
|
||||
{
|
||||
return do_io_check(signal, [&] {
|
||||
return open_file_dma(name, flags, options).then([&] (file f) {
|
||||
return make_ready_future<file>(make_checked_file(signal, f));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
future<file>
|
||||
inline open_checked_file_dma(disk_error_signal_type& signal,
|
||||
sstring name, open_flags flags)
|
||||
{
|
||||
return do_io_check(signal, [&] {
|
||||
return open_file_dma(name, flags).then([&] (file f) {
|
||||
return make_ready_future<file>(make_checked_file(signal, f));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
future<file>
|
||||
inline open_checked_directory(disk_error_signal_type& signal,
|
||||
sstring name)
|
||||
{
|
||||
return do_io_check(signal, [&] {
|
||||
return engine().open_directory(name).then([&] (file f) {
|
||||
return make_ready_future<file>(make_checked_file(signal, f));
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -1,127 +0,0 @@
|
||||
|
||||
/*
|
||||
* Copyright (C) 2016 ScyllaDB
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is part of Scylla.
|
||||
*
|
||||
* Scylla is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Scylla is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Scylla. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "keys.hh"
|
||||
#include "schema.hh"
|
||||
#include "range.hh"
|
||||
|
||||
/**
|
||||
* Represents the kind of bound in a range tombstone.
|
||||
*/
|
||||
enum class bound_kind : uint8_t {
|
||||
excl_end = 0,
|
||||
incl_start = 1,
|
||||
// values 2 to 5 are reserved for forward Origin compatibility
|
||||
incl_end = 6,
|
||||
excl_start = 7,
|
||||
};
|
||||
|
||||
std::ostream& operator<<(std::ostream& out, const bound_kind k);
|
||||
|
||||
bound_kind invert_kind(bound_kind k);
|
||||
int32_t weight(bound_kind k);
|
||||
|
||||
static inline bound_kind flip_bound_kind(bound_kind bk)
|
||||
{
|
||||
switch (bk) {
|
||||
case bound_kind::excl_end: return bound_kind::excl_start;
|
||||
case bound_kind::incl_end: return bound_kind::incl_start;
|
||||
case bound_kind::excl_start: return bound_kind::excl_end;
|
||||
case bound_kind::incl_start: return bound_kind::incl_end;
|
||||
}
|
||||
abort();
|
||||
}
|
||||
|
||||
class bound_view {
|
||||
const static thread_local clustering_key empty_prefix;
|
||||
public:
|
||||
const clustering_key_prefix& prefix;
|
||||
bound_kind kind;
|
||||
bound_view(const clustering_key_prefix& prefix, bound_kind kind)
|
||||
: prefix(prefix)
|
||||
, kind(kind)
|
||||
{ }
|
||||
struct compare {
|
||||
// To make it assignable and to avoid taking a schema_ptr, we
|
||||
// wrap the schema reference.
|
||||
std::reference_wrapper<const schema> _s;
|
||||
compare(const schema& s) : _s(s)
|
||||
{ }
|
||||
bool operator()(const clustering_key_prefix& p1, int32_t w1, const clustering_key_prefix& p2, int32_t w2) const {
|
||||
auto type = _s.get().clustering_key_prefix_type();
|
||||
auto res = prefix_equality_tri_compare(type->types().begin(),
|
||||
type->begin(p1), type->end(p1),
|
||||
type->begin(p2), type->end(p2),
|
||||
tri_compare);
|
||||
if (res) {
|
||||
return res < 0;
|
||||
}
|
||||
auto d1 = p1.size(_s);
|
||||
auto d2 = p2.size(_s);
|
||||
if (d1 == d2) {
|
||||
return w1 < w2;
|
||||
}
|
||||
return d1 < d2 ? w1 <= 0 : w2 > 0;
|
||||
}
|
||||
bool operator()(const bound_view b, const clustering_key_prefix& p) const {
|
||||
return operator()(b.prefix, weight(b.kind), p, 0);
|
||||
}
|
||||
bool operator()(const clustering_key_prefix& p, const bound_view b) const {
|
||||
return operator()(p, 0, b.prefix, weight(b.kind));
|
||||
}
|
||||
bool operator()(const bound_view b1, const bound_view b2) const {
|
||||
return operator()(b1.prefix, weight(b1.kind), b2.prefix, weight(b2.kind));
|
||||
}
|
||||
};
|
||||
bool equal(const schema& s, const bound_view other) const {
|
||||
return kind == other.kind && prefix.equal(s, other.prefix);
|
||||
}
|
||||
bool adjacent(const schema& s, const bound_view other) const {
|
||||
return invert_kind(other.kind) == kind && prefix.equal(s, other.prefix);
|
||||
}
|
||||
static bound_view bottom(const schema& s) {
|
||||
return {empty_prefix, bound_kind::incl_start};
|
||||
}
|
||||
static bound_view top(const schema& s) {
|
||||
return {empty_prefix, bound_kind::incl_end};
|
||||
}
|
||||
/*
|
||||
template<template<typename> typename T, typename U>
|
||||
concept bool Range() {
|
||||
return requires (T<U> range) {
|
||||
{ range.start() } -> stdx::optional<U>;
|
||||
{ range.end() } -> stdx::optional<U>;
|
||||
};
|
||||
};*/
|
||||
template<template<typename> typename Range>
|
||||
static std::pair<bound_view, bound_view> from_range(const schema& s, const Range<clustering_key_prefix>& range) {
|
||||
return {
|
||||
range.start() ? bound_view(range.start()->value(), range.start()->is_inclusive() ? bound_kind::incl_start : bound_kind::excl_start) : bottom(s),
|
||||
range.end() ? bound_view(range.end()->value(), range.end()->is_inclusive() ? bound_kind::incl_end : bound_kind::excl_end) : top(s),
|
||||
};
|
||||
}
|
||||
friend std::ostream& operator<<(std::ostream& out, const bound_view& b) {
|
||||
return out << "{bound: prefix=" << b.prefix << ", kind=" << b.kind << "}";
|
||||
}
|
||||
};
|
||||
@@ -1,124 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016 ScyllaDB
|
||||
*
|
||||
* Modified by ScyllaDB
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is part of Scylla.
|
||||
*
|
||||
* Scylla is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Scylla is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Scylla. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "clustering_key_filter.hh"
|
||||
#include "keys.hh"
|
||||
#include "query-request.hh"
|
||||
#include "range.hh"
|
||||
|
||||
namespace query {
|
||||
|
||||
const std::vector<range<clustering_key_prefix>>&
|
||||
clustering_key_filtering_context::get_ranges(const partition_key& key) const {
|
||||
static thread_local std::vector<range<clustering_key_prefix>> full_range = {{}};
|
||||
return _factory ? _factory->get_ranges(key) : full_range;
|
||||
}
|
||||
|
||||
clustering_key_filtering_context clustering_key_filtering_context::create_no_filtering() {
|
||||
return clustering_key_filtering_context{};
|
||||
}
|
||||
|
||||
const clustering_key_filtering_context no_clustering_key_filtering =
|
||||
clustering_key_filtering_context::create_no_filtering();
|
||||
|
||||
class stateless_clustering_key_filter_factory : public clustering_key_filter_factory {
|
||||
clustering_key_filter _filter;
|
||||
std::vector<range<clustering_key_prefix>> _ranges;
|
||||
public:
|
||||
stateless_clustering_key_filter_factory(std::vector<range<clustering_key_prefix>>&& ranges,
|
||||
clustering_key_filter&& filter)
|
||||
: _filter(std::move(filter)), _ranges(std::move(ranges)) {}
|
||||
|
||||
virtual clustering_key_filter get_filter(const partition_key& key) override {
|
||||
return _filter;
|
||||
}
|
||||
|
||||
virtual clustering_key_filter get_filter_for_sorted(const partition_key& key) override {
|
||||
return _filter;
|
||||
}
|
||||
|
||||
virtual const std::vector<range<clustering_key_prefix>>& get_ranges(const partition_key& key) override {
|
||||
return _ranges;
|
||||
}
|
||||
};
|
||||
|
||||
class partition_slice_clustering_key_filter_factory : public clustering_key_filter_factory {
|
||||
schema_ptr _schema;
|
||||
const partition_slice& _slice;
|
||||
clustering_key_prefix::prefix_equal_tri_compare _cmp;
|
||||
public:
|
||||
partition_slice_clustering_key_filter_factory(schema_ptr s, const partition_slice& slice)
|
||||
: _schema(std::move(s)), _slice(slice), _cmp(*_schema) {}
|
||||
|
||||
virtual clustering_key_filter get_filter(const partition_key& key) override {
|
||||
const clustering_row_ranges& ranges = _slice.row_ranges(*_schema, key);
|
||||
return [this, &ranges] (const clustering_key& key) {
|
||||
return std::any_of(std::begin(ranges), std::end(ranges),
|
||||
[this, &key] (const range<clustering_key_prefix>& r) { return r.contains(key, _cmp); });
|
||||
};
|
||||
}
|
||||
|
||||
virtual clustering_key_filter get_filter_for_sorted(const partition_key& key) override {
|
||||
const clustering_row_ranges& ranges = _slice.row_ranges(*_schema, key);
|
||||
return [this, &ranges] (const clustering_key& key) {
|
||||
return std::any_of(std::begin(ranges), std::end(ranges),
|
||||
[this, &key] (const range<clustering_key_prefix>& r) { return r.contains(key, _cmp); });
|
||||
};
|
||||
}
|
||||
|
||||
virtual const std::vector<range<clustering_key_prefix>>& get_ranges(const partition_key& key) override {
|
||||
return _slice.row_ranges(*_schema, key);
|
||||
}
|
||||
};
|
||||
|
||||
static const shared_ptr<clustering_key_filter_factory>
|
||||
create_partition_slice_filter(schema_ptr s, const partition_slice& slice) {
|
||||
return ::make_shared<partition_slice_clustering_key_filter_factory>(std::move(s), slice);
|
||||
}
|
||||
|
||||
const clustering_key_filtering_context
|
||||
clustering_key_filtering_context::create(schema_ptr schema, const partition_slice& slice) {
|
||||
static thread_local clustering_key_filtering_context accept_all = clustering_key_filtering_context(
|
||||
::make_shared<stateless_clustering_key_filter_factory>(std::vector<range<clustering_key_prefix>>{{}},
|
||||
[](const clustering_key&) { return true; }));
|
||||
static thread_local clustering_key_filtering_context reject_all = clustering_key_filtering_context(
|
||||
::make_shared<stateless_clustering_key_filter_factory>(std::vector<range<clustering_key_prefix>>{},
|
||||
[](const clustering_key&) { return false; }));
|
||||
|
||||
if (slice.get_specific_ranges()) {
|
||||
return clustering_key_filtering_context(create_partition_slice_filter(schema, slice));
|
||||
}
|
||||
|
||||
const clustering_row_ranges& ranges = slice.default_row_ranges();
|
||||
|
||||
if (ranges.empty()) {
|
||||
return reject_all;
|
||||
}
|
||||
|
||||
if (ranges.size() == 1 && ranges[0].is_full()) {
|
||||
return accept_all;
|
||||
}
|
||||
return clustering_key_filtering_context(create_partition_slice_filter(schema, slice));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016 ScyllaDB
|
||||
*
|
||||
* Modified by ScyllaDB
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is part of Scylla.
|
||||
*
|
||||
* Scylla is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Scylla is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Scylla. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
|
||||
#include "core/shared_ptr.hh"
|
||||
#include "database_fwd.hh"
|
||||
#include "schema.hh"
|
||||
|
||||
template<typename T> class range;
|
||||
|
||||
namespace query {
|
||||
|
||||
class partition_slice;
|
||||
|
||||
// A predicate that tells if a clustering key should be accepted.
|
||||
using clustering_key_filter = std::function<bool(const clustering_key&)>;
|
||||
|
||||
// A factory for clustering key filter which can be reused for multiple clustering keys.
|
||||
class clustering_key_filter_factory {
|
||||
public:
|
||||
// Create a clustering key filter that can be used for multiple clustering keys with no restrictions.
|
||||
virtual clustering_key_filter get_filter(const partition_key&) = 0;
|
||||
// Create a clustering key filter that can be used for multiple clustering keys but they have to be sorted.
|
||||
virtual clustering_key_filter get_filter_for_sorted(const partition_key&) = 0;
|
||||
virtual const std::vector<range<clustering_key_prefix>>& get_ranges(const partition_key&) = 0;
|
||||
virtual ~clustering_key_filter_factory() = default;
|
||||
};
|
||||
|
||||
class clustering_key_filtering_context {
|
||||
private:
|
||||
shared_ptr<clustering_key_filter_factory> _factory;
|
||||
clustering_key_filtering_context() {};
|
||||
clustering_key_filtering_context(shared_ptr<clustering_key_filter_factory> factory) : _factory(factory) {}
|
||||
public:
|
||||
// Create a clustering key filter that can be used for multiple clustering keys with no restrictions.
|
||||
clustering_key_filter get_filter(const partition_key& key) const {
|
||||
return _factory ? _factory->get_filter(key) : [] (const clustering_key&) { return true; };
|
||||
}
|
||||
// Create a clustering key filter that can be used for multiple clustering keys but they have to be sorted.
|
||||
clustering_key_filter get_filter_for_sorted(const partition_key& key) const {
|
||||
return _factory ? _factory->get_filter_for_sorted(key) : [] (const clustering_key&) { return true; };
|
||||
}
|
||||
const std::vector<range<clustering_key_prefix>>& get_ranges(const partition_key& key) const;
|
||||
|
||||
static const clustering_key_filtering_context create(schema_ptr, const partition_slice&);
|
||||
|
||||
static clustering_key_filtering_context create_no_filtering();
|
||||
};
|
||||
|
||||
extern const clustering_key_filtering_context no_clustering_key_filtering;
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2015 ScyllaDB
|
||||
* Copyright (C) 2015 Cloudius Systems, Ltd.
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2015 ScyllaDB
|
||||
* Copyright 2015 Cloudius Systems
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -34,8 +34,6 @@ enum class compaction_strategy_type {
|
||||
};
|
||||
|
||||
class compaction_strategy_impl;
|
||||
class sstable;
|
||||
struct compaction_descriptor;
|
||||
|
||||
class compaction_strategy {
|
||||
::shared_ptr<compaction_strategy_impl> _compaction_strategy_impl;
|
||||
@@ -48,12 +46,7 @@ public:
|
||||
compaction_strategy(compaction_strategy&&);
|
||||
compaction_strategy& operator=(compaction_strategy&&);
|
||||
|
||||
// Return a list of sstables to be compacted after applying the strategy.
|
||||
compaction_descriptor get_sstables_for_compaction(column_family& cfs, std::vector<lw_shared_ptr<sstable>> candidates);
|
||||
|
||||
// Return if parallel compaction is allowed by strategy.
|
||||
bool parallel_compaction() const;
|
||||
|
||||
future<> compact(column_family& cfs);
|
||||
static sstring name(compaction_strategy_type type) {
|
||||
switch (type) {
|
||||
case compaction_strategy_type::null:
|
||||
|
||||
172
compound.hh
172
compound.hh
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2015 ScyllaDB
|
||||
* Copyright (C) 2015 Cloudius Systems, Ltd.
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -26,10 +26,29 @@
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
#include <boost/range/iterator_range.hpp>
|
||||
#include <boost/range/adaptor/transformed.hpp>
|
||||
#include "utils/serialization.hh"
|
||||
#include "unimplemented.hh"
|
||||
|
||||
// value_traits is meant to abstract away whether we are working on 'bytes'
|
||||
// elements or 'bytes_opt' elements. We don't support optional values, but
|
||||
// there are some generic layers which use this code which provide us with
|
||||
// data in that format. In order to avoid allocation and rewriting that data
|
||||
// into a new vector just to throw it away soon after that, we accept that
|
||||
// format too.
|
||||
|
||||
template <typename T>
|
||||
struct value_traits {
|
||||
static const T& unwrap(const T& t) { return t; }
|
||||
};
|
||||
|
||||
template<>
|
||||
struct value_traits<bytes_opt> {
|
||||
static const bytes& unwrap(const bytes_opt& t) {
|
||||
assert(t);
|
||||
return *t;
|
||||
}
|
||||
};
|
||||
|
||||
enum class allow_prefixes { no, yes };
|
||||
|
||||
template<allow_prefixes AllowPrefixes = allow_prefixes::no>
|
||||
@@ -43,14 +62,13 @@ public:
|
||||
static constexpr bool is_prefixable = AllowPrefixes == allow_prefixes::yes;
|
||||
using prefix_type = compound_type<allow_prefixes::yes>;
|
||||
using value_type = std::vector<bytes>;
|
||||
using size_type = uint16_t;
|
||||
|
||||
compound_type(std::vector<data_type> types)
|
||||
: _types(std::move(types))
|
||||
, _byte_order_equal(std::all_of(_types.begin(), _types.end(), [] (auto t) {
|
||||
return t->is_byte_order_equal();
|
||||
}))
|
||||
, _byte_order_comparable(false)
|
||||
, _byte_order_comparable(!is_prefixable && _types.size() == 1 && _types[0]->is_byte_order_comparable())
|
||||
, _is_reversed(_types.size() == 1 && _types[0]->is_reversed())
|
||||
{ }
|
||||
|
||||
@@ -67,54 +85,79 @@ public:
|
||||
prefix_type as_prefix() {
|
||||
return prefix_type(_types);
|
||||
}
|
||||
private:
|
||||
|
||||
/*
|
||||
* Format:
|
||||
* <len(value1)><value1><len(value2)><value2>...<len(value_n)><value_n>
|
||||
* <len(value1)><value1><len(value2)><value2>...<len(value_n-1)><value_n-1>(len(value_n))?<value_n>
|
||||
*
|
||||
* For non-prefixable compounds, the value corresponding to the last component of types doesn't
|
||||
* have its length encoded, its length is deduced from the input range.
|
||||
*
|
||||
* serialize_value() and serialize_optionals() for single element rely on the fact that for a single-element
|
||||
* compounds their serialized form is equal to the serialized form of the component.
|
||||
*/
|
||||
template<typename RangeOfSerializedComponents>
|
||||
static void serialize_value(RangeOfSerializedComponents&& values, bytes::iterator& out) {
|
||||
for (auto&& val : values) {
|
||||
assert(val.size() <= std::numeric_limits<size_type>::max());
|
||||
write<size_type>(out, size_type(val.size()));
|
||||
template<typename Wrapped>
|
||||
void serialize_value(const std::vector<Wrapped>& values, bytes::iterator& out) {
|
||||
if (AllowPrefixes == allow_prefixes::yes) {
|
||||
assert(values.size() <= _types.size());
|
||||
} else {
|
||||
assert(values.size() == _types.size());
|
||||
}
|
||||
|
||||
size_t n_left = _types.size();
|
||||
for (auto&& wrapped : values) {
|
||||
auto&& val = value_traits<Wrapped>::unwrap(wrapped);
|
||||
assert(val.size() <= std::numeric_limits<uint16_t>::max());
|
||||
if (--n_left || AllowPrefixes == allow_prefixes::yes) {
|
||||
write<uint16_t>(out, uint16_t(val.size()));
|
||||
}
|
||||
out = std::copy(val.begin(), val.end(), out);
|
||||
}
|
||||
}
|
||||
template <typename RangeOfSerializedComponents>
|
||||
static size_t serialized_size(RangeOfSerializedComponents&& values) {
|
||||
template <typename Wrapped>
|
||||
size_t serialized_size(const std::vector<Wrapped>& values) {
|
||||
size_t len = 0;
|
||||
for (auto&& val : values) {
|
||||
len += sizeof(size_type) + val.size();
|
||||
size_t n_left = _types.size();
|
||||
for (auto&& wrapped : values) {
|
||||
auto&& val = value_traits<Wrapped>::unwrap(wrapped);
|
||||
assert(val.size() <= std::numeric_limits<uint16_t>::max());
|
||||
if (--n_left || AllowPrefixes == allow_prefixes::yes) {
|
||||
len += sizeof(uint16_t);
|
||||
}
|
||||
len += val.size();
|
||||
}
|
||||
return len;
|
||||
}
|
||||
public:
|
||||
bytes serialize_single(bytes&& v) {
|
||||
return serialize_value({std::move(v)});
|
||||
}
|
||||
template<typename RangeOfSerializedComponents>
|
||||
static bytes serialize_value(RangeOfSerializedComponents&& values) {
|
||||
auto size = serialized_size(values);
|
||||
if (size > std::numeric_limits<size_type>::max()) {
|
||||
throw std::runtime_error(sprint("Key size too large: %d > %d", size, std::numeric_limits<size_type>::max()));
|
||||
if (AllowPrefixes == allow_prefixes::no) {
|
||||
assert(_types.size() == 1);
|
||||
return std::move(v);
|
||||
} else {
|
||||
// FIXME: Optimize
|
||||
std::vector<bytes> vec;
|
||||
vec.reserve(1);
|
||||
vec.emplace_back(std::move(v));
|
||||
return ::serialize_value(*this, vec);
|
||||
}
|
||||
bytes b(bytes::initialized_later(), size);
|
||||
auto i = b.begin();
|
||||
serialize_value(values, i);
|
||||
return b;
|
||||
}
|
||||
template<typename T>
|
||||
static bytes serialize_value(std::initializer_list<T> values) {
|
||||
return serialize_value(boost::make_iterator_range(values.begin(), values.end()));
|
||||
bytes serialize_value(const std::vector<bytes>& values) {
|
||||
return ::serialize_value(*this, values);
|
||||
}
|
||||
bytes serialize_value(std::vector<bytes>&& values) {
|
||||
if (AllowPrefixes == allow_prefixes::no && _types.size() == 1 && values.size() == 1) {
|
||||
return std::move(values[0]);
|
||||
}
|
||||
return ::serialize_value(*this, values);
|
||||
}
|
||||
bytes serialize_optionals(const std::vector<bytes_opt>& values) {
|
||||
return serialize_value(values | boost::adaptors::transformed([] (const bytes_opt& bo) -> bytes_view {
|
||||
if (!bo) {
|
||||
throw std::logic_error("attempted to create key component from empty optional");
|
||||
}
|
||||
return *bo;
|
||||
}));
|
||||
return ::serialize_value(*this, values);
|
||||
}
|
||||
bytes serialize_optionals(std::vector<bytes_opt>&& values) {
|
||||
if (AllowPrefixes == allow_prefixes::no && _types.size() == 1 && values.size() == 1) {
|
||||
assert(values[0]);
|
||||
return std::move(*values[0]);
|
||||
}
|
||||
return ::serialize_value(*this, values);
|
||||
}
|
||||
bytes serialize_value_deep(const std::vector<data_value>& values) {
|
||||
// TODO: Optimize
|
||||
@@ -128,21 +171,37 @@ public:
|
||||
return serialize_value(partial);
|
||||
}
|
||||
bytes decompose_value(const value_type& values) {
|
||||
return serialize_value(values);
|
||||
return ::serialize_value(*this, values);
|
||||
}
|
||||
class iterator : public std::iterator<std::input_iterator_tag, bytes_view> {
|
||||
private:
|
||||
ssize_t _types_left;
|
||||
bytes_view _v;
|
||||
value_type _current;
|
||||
private:
|
||||
void read_current() {
|
||||
size_type len;
|
||||
{
|
||||
if (_v.empty()) {
|
||||
_v = bytes_view(nullptr, 0);
|
||||
return;
|
||||
if (_types_left == 0) {
|
||||
if (!_v.empty()) {
|
||||
throw marshal_exception();
|
||||
}
|
||||
len = read_simple<size_type>(_v);
|
||||
_v = bytes_view(nullptr, 0);
|
||||
return;
|
||||
}
|
||||
--_types_left;
|
||||
uint16_t len;
|
||||
if (_types_left == 0 && AllowPrefixes == allow_prefixes::no) {
|
||||
len = _v.size();
|
||||
} else {
|
||||
if (_v.empty()) {
|
||||
if (AllowPrefixes == allow_prefixes::yes) {
|
||||
_types_left = 0;
|
||||
_v = bytes_view(nullptr, 0);
|
||||
return;
|
||||
} else {
|
||||
throw marshal_exception();
|
||||
}
|
||||
}
|
||||
len = read_simple<uint16_t>(_v);
|
||||
if (_v.size() < len) {
|
||||
throw marshal_exception();
|
||||
}
|
||||
@@ -152,10 +211,10 @@ public:
|
||||
}
|
||||
public:
|
||||
struct end_iterator_tag {};
|
||||
iterator(const bytes_view& v) : _v(v) {
|
||||
iterator(const compound_type& t, const bytes_view& v) : _types_left(t._types.size()), _v(v) {
|
||||
read_current();
|
||||
}
|
||||
iterator(end_iterator_tag, const bytes_view& v) : _v(nullptr, 0) {}
|
||||
iterator(end_iterator_tag, const bytes_view& v) : _types_left(0), _v(nullptr, 0) {}
|
||||
iterator& operator++() {
|
||||
read_current();
|
||||
return *this;
|
||||
@@ -167,18 +226,21 @@ public:
|
||||
}
|
||||
const value_type& operator*() const { return _current; }
|
||||
const value_type* operator->() const { return &_current; }
|
||||
bool operator!=(const iterator& i) const { return _v.begin() != i._v.begin(); }
|
||||
bool operator==(const iterator& i) const { return _v.begin() == i._v.begin(); }
|
||||
bool operator!=(const iterator& i) const { return _v.begin() != i._v.begin() || _types_left != i._types_left; }
|
||||
bool operator==(const iterator& i) const { return _v.begin() == i._v.begin() && _types_left == i._types_left; }
|
||||
};
|
||||
static iterator begin(const bytes_view& v) {
|
||||
return iterator(v);
|
||||
iterator begin(const bytes_view& v) const {
|
||||
return iterator(*this, v);
|
||||
}
|
||||
static iterator end(const bytes_view& v) {
|
||||
iterator end(const bytes_view& v) const {
|
||||
return iterator(typename iterator::end_iterator_tag(), v);
|
||||
}
|
||||
static boost::iterator_range<iterator> components(const bytes_view& v) {
|
||||
boost::iterator_range<iterator> components(const bytes_view& v) const {
|
||||
return { begin(v), end(v) };
|
||||
}
|
||||
auto iter_items(const bytes_view& v) {
|
||||
return boost::iterator_range<iterator>(begin(v), end(v));
|
||||
}
|
||||
value_type deserialize_value(bytes_view v) {
|
||||
std::vector<bytes> result;
|
||||
result.reserve(_types.size());
|
||||
@@ -196,7 +258,7 @@ public:
|
||||
}
|
||||
auto t = _types.begin();
|
||||
size_t h = 0;
|
||||
for (auto&& value : components(v)) {
|
||||
for (auto&& value : iter_items(v)) {
|
||||
h ^= (*t)->hash(value);
|
||||
++t;
|
||||
}
|
||||
@@ -215,6 +277,12 @@ public:
|
||||
return type->compare(v1, v2);
|
||||
});
|
||||
}
|
||||
bytes from_string(sstring_view s) {
|
||||
throw std::runtime_error(sprint("%s not implemented", __PRETTY_FUNCTION__));
|
||||
}
|
||||
sstring to_string(const bytes& b) {
|
||||
throw std::runtime_error(sprint("%s not implemented", __PRETTY_FUNCTION__));
|
||||
}
|
||||
// Retruns true iff given prefix has no missing components
|
||||
bool is_full(bytes_view v) const {
|
||||
assert(AllowPrefixes == allow_prefixes::yes);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2015 ScyllaDB
|
||||
* Copyright 2015 Cloudius Systems
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2015 ScyllaDB
|
||||
* Copyright (C) 2015 Cloudius Systems, Ltd.
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
110
conf/scylla.yaml
110
conf/scylla.yaml
@@ -106,19 +106,6 @@ write_request_timeout_in_ms: 2000
|
||||
# most users should never need to adjust this.
|
||||
# phi_convict_threshold: 8
|
||||
|
||||
# IEndpointSnitch. The snitch has two functions:
|
||||
# - it teaches Scylla enough about your network topology to route
|
||||
# requests efficiently
|
||||
# - it allows Scylla to spread replicas around your cluster to avoid
|
||||
# correlated failures. It does this by grouping machines into
|
||||
# "datacenters" and "racks." Scylla will do its best not to have
|
||||
# more than one replica on the same "rack" (which may not actually
|
||||
# be a physical location)
|
||||
#
|
||||
# IF YOU CHANGE THE SNITCH AFTER DATA IS INSERTED INTO THE CLUSTER,
|
||||
# YOU MUST RUN A FULL REPAIR, SINCE THE SNITCH AFFECTS WHERE REPLICAS
|
||||
# ARE PLACED.
|
||||
#
|
||||
# Out of the box, Scylla provides
|
||||
# - SimpleSnitch:
|
||||
# Treats Strategy order as proximity. This can improve cache
|
||||
@@ -192,24 +179,6 @@ api_address: 127.0.0.1
|
||||
# Caution should be taken on increasing the size of this threshold as it can lead to node instability.
|
||||
batch_size_warn_threshold_in_kb: 5
|
||||
|
||||
# Authentication backend, identifying users
|
||||
# Out of the box, Scylla provides org.apache.cassandra.auth.{AllowAllAuthenticator,
|
||||
# PasswordAuthenticator}.
|
||||
#
|
||||
# - AllowAllAuthenticator performs no checks - set it to disable authentication.
|
||||
# - PasswordAuthenticator relies on username/password pairs to authenticate
|
||||
# users. It keeps usernames and hashed passwords in system_auth.credentials table.
|
||||
# Please increase system_auth keyspace replication factor if you use this authenticator.
|
||||
# authenticator: AllowAllAuthenticator
|
||||
|
||||
# Authorization backend, implementing IAuthorizer; used to limit access/provide permissions
|
||||
# Out of the box, Scylla provides org.apache.cassandra.auth.{AllowAllAuthorizer,
|
||||
# CassandraAuthorizer}.
|
||||
#
|
||||
# - AllowAllAuthorizer allows any action to any user - set it to disable authorization.
|
||||
# - CassandraAuthorizer stores permissions in system_auth.permissions table. Please
|
||||
# increase system_auth keyspace replication factor if you use this authorizer.
|
||||
# authorizer: AllowAllAuthorizer
|
||||
|
||||
###################################################
|
||||
## Not currently supported, reserved for future use
|
||||
@@ -247,6 +216,25 @@ batch_size_warn_threshold_in_kb: 5
|
||||
# reduced proportionally to the number of nodes in the cluster.
|
||||
# batchlog_replay_throttle_in_kb: 1024
|
||||
|
||||
# Authentication backend, identifying users
|
||||
# Out of the box, Scylla provides org.apache.cassandra.auth.{AllowAllAuthenticator,
|
||||
# PasswordAuthenticator}.
|
||||
#
|
||||
# - AllowAllAuthenticator performs no checks - set it to disable authentication.
|
||||
# - PasswordAuthenticator relies on username/password pairs to authenticate
|
||||
# users. It keeps usernames and hashed passwords in system_auth.credentials table.
|
||||
# Please increase system_auth keyspace replication factor if you use this authenticator.
|
||||
# authenticator: AllowAllAuthenticator
|
||||
|
||||
# Authorization backend, implementing IAuthorizer; used to limit access/provide permissions
|
||||
# Out of the box, Scylla provides org.apache.cassandra.auth.{AllowAllAuthorizer,
|
||||
# CassandraAuthorizer}.
|
||||
#
|
||||
# - AllowAllAuthorizer allows any action to any user - set it to disable authorization.
|
||||
# - CassandraAuthorizer stores permissions in system_auth.permissions table. Please
|
||||
# increase system_auth keyspace replication factor if you use this authorizer.
|
||||
# authorizer: AllowAllAuthorizer
|
||||
|
||||
# Validity period for permissions cache (fetching permissions can be an
|
||||
# expensive operation depending on the authorizer, CassandraAuthorizer is
|
||||
# one example). Defaults to 2000, set to 0 to disable.
|
||||
@@ -692,6 +680,58 @@ commitlog_total_space_in_mb: -1
|
||||
# Default value is 0, which never timeout streams.
|
||||
# streaming_socket_timeout_in_ms: 0
|
||||
|
||||
|
||||
# endpoint_snitch -- Set this to a class that implements
|
||||
# IEndpointSnitch. The snitch has two functions:
|
||||
# - it teaches Scylla enough about your network topology to route
|
||||
# requests efficiently
|
||||
# - it allows Scylla to spread replicas around your cluster to avoid
|
||||
# correlated failures. It does this by grouping machines into
|
||||
# "datacenters" and "racks." Scylla will do its best not to have
|
||||
# more than one replica on the same "rack" (which may not actually
|
||||
# be a physical location)
|
||||
#
|
||||
# IF YOU CHANGE THE SNITCH AFTER DATA IS INSERTED INTO THE CLUSTER,
|
||||
# YOU MUST RUN A FULL REPAIR, SINCE THE SNITCH AFFECTS WHERE REPLICAS
|
||||
# ARE PLACED.
|
||||
#
|
||||
# Out of the box, Scylla provides
|
||||
# - SimpleSnitch:
|
||||
# Treats Strategy order as proximity. This can improve cache
|
||||
# locality when disabling read repair. Only appropriate for
|
||||
# single-datacenter deployments.
|
||||
# - GossipingPropertyFileSnitch
|
||||
# This should be your go-to snitch for production use. The rack
|
||||
# and datacenter for the local node are defined in
|
||||
# cassandra-rackdc.properties and propagated to other nodes via
|
||||
# gossip. If cassandra-topology.properties exists, it is used as a
|
||||
# fallback, allowing migration from the PropertyFileSnitch.
|
||||
# - PropertyFileSnitch:
|
||||
# Proximity is determined by rack and data center, which are
|
||||
# explicitly configured in cassandra-topology.properties.
|
||||
# - Ec2Snitch:
|
||||
# Appropriate for EC2 deployments in a single Region. Loads Region
|
||||
# and Availability Zone information from the EC2 API. The Region is
|
||||
# treated as the datacenter, and the Availability Zone as the rack.
|
||||
# Only private IPs are used, so this will not work across multiple
|
||||
# Regions.
|
||||
# - Ec2MultiRegionSnitch:
|
||||
# Uses public IPs as broadcast_address to allow cross-region
|
||||
# connectivity. (Thus, you should set seed addresses to the public
|
||||
# IP as well.) You will need to open the storage_port or
|
||||
# ssl_storage_port on the public IP firewall. (For intra-Region
|
||||
# traffic, Scylla will switch to the private IP after
|
||||
# establishing a connection.)
|
||||
# - RackInferringSnitch:
|
||||
# Proximity is determined by rack and data center, which are
|
||||
# assumed to correspond to the 3rd and 2nd octet of each node's IP
|
||||
# address, respectively. Unless this happens to match your
|
||||
# deployment conventions, this is best used as an example of
|
||||
# writing a custom Snitch class and is provided in that spirit.
|
||||
#
|
||||
# You can use a custom Snitch by setting this to the full class name
|
||||
# of the snitch, which will be assumed to be on your classpath.
|
||||
|
||||
# controls how often to perform the more expensive part of host score
|
||||
# calculation
|
||||
# dynamic_snitch_update_interval_in_ms: 100
|
||||
@@ -805,11 +845,3 @@ commitlog_total_space_in_mb: -1
|
||||
# true: relaxed environment checks; performance and reliability may degraade.
|
||||
#
|
||||
# developer_mode: false
|
||||
|
||||
|
||||
# Idle-time background processing
|
||||
#
|
||||
# Scylla can perform certain jobs in the background while the system is otherwise idle,
|
||||
# freeing processor resources when there is other work to be done.
|
||||
#
|
||||
# defragment_memory_on_idle: true
|
||||
|
||||
194
configure.py
194
configure.py
@@ -1,6 +1,6 @@
|
||||
#!/usr/bin/python3
|
||||
#
|
||||
# Copyright (C) 2015 ScyllaDB
|
||||
# Copyright 2015 Cloudius Systems
|
||||
#
|
||||
|
||||
#
|
||||
@@ -25,31 +25,6 @@ from distutils.spawn import find_executable
|
||||
|
||||
configure_args = str.join(' ', [shlex.quote(x) for x in sys.argv[1:]])
|
||||
|
||||
for line in open('/etc/os-release'):
|
||||
key, _, value = line.partition('=')
|
||||
value = value.strip().strip('"')
|
||||
if key == 'ID':
|
||||
os_ids = [value]
|
||||
if key == 'ID_LIKE':
|
||||
os_ids += value.split(' ')
|
||||
|
||||
# distribution "internationalization", converting package names.
|
||||
# Fedora name is key, values is distro -> package name dict.
|
||||
i18n_xlat = {
|
||||
'boost-devel': {
|
||||
'debian': 'libboost-dev',
|
||||
'ubuntu': 'libboost-dev (libboost1.55-dev on 14.04)',
|
||||
},
|
||||
}
|
||||
|
||||
def pkgname(name):
|
||||
if name in i18n_xlat:
|
||||
dict = i18n_xlat[name]
|
||||
for id in os_ids:
|
||||
if id in dict:
|
||||
return dict[id]
|
||||
return name
|
||||
|
||||
def get_flags():
|
||||
with open('/proc/cpuinfo') as f:
|
||||
for line in f:
|
||||
@@ -162,7 +137,6 @@ modes = {
|
||||
|
||||
scylla_tests = [
|
||||
'tests/mutation_test',
|
||||
'tests/schema_registry_test',
|
||||
'tests/canonical_mutation_test',
|
||||
'tests/range_test',
|
||||
'tests/types_test',
|
||||
@@ -193,6 +167,7 @@ scylla_tests = [
|
||||
'tests/commitlog_test',
|
||||
'tests/cartesian_product_test',
|
||||
'tests/hash_test',
|
||||
'tests/serializer_test',
|
||||
'tests/map_difference_test',
|
||||
'tests/message',
|
||||
'tests/gossip',
|
||||
@@ -215,7 +190,6 @@ scylla_tests = [
|
||||
'tests/flush_queue_test',
|
||||
'tests/dynamic_bitset_test',
|
||||
'tests/auth_test',
|
||||
'tests/idl_test',
|
||||
]
|
||||
|
||||
apps = [
|
||||
@@ -224,11 +198,7 @@ apps = [
|
||||
|
||||
tests = scylla_tests
|
||||
|
||||
other = [
|
||||
'iotune',
|
||||
]
|
||||
|
||||
all_artifacts = apps + tests + other
|
||||
all_artifacts = apps + tests
|
||||
|
||||
arg_parser = argparse.ArgumentParser('Configure scylla')
|
||||
arg_parser.add_argument('--static', dest = 'static', action = 'store_const', default = '',
|
||||
@@ -256,8 +226,6 @@ arg_parser.add_argument('--debuginfo', action = 'store', dest = 'debuginfo', typ
|
||||
help = 'Enable(1)/disable(0)compiler debug information generation')
|
||||
arg_parser.add_argument('--static-stdc++', dest = 'staticcxx', action = 'store_true',
|
||||
help = 'Link libgcc and libstdc++ statically')
|
||||
arg_parser.add_argument('--static-thrift', dest = 'staticthrift', action = 'store_true',
|
||||
help = 'Link libthrift statically')
|
||||
arg_parser.add_argument('--tests-debuginfo', action = 'store', dest = 'tests_debuginfo', type = int, default = 0,
|
||||
help = 'Enable(1)/disable(0)compiler debug information generation for tests')
|
||||
arg_parser.add_argument('--python', action = 'store', dest = 'python', default = 'python3',
|
||||
@@ -267,6 +235,7 @@ add_tristate(arg_parser, name = 'xen', dest = 'xen', help = 'Xen support')
|
||||
args = arg_parser.parse_args()
|
||||
|
||||
defines = []
|
||||
scylla_libs = '-llz4 -lsnappy -lz -lboost_thread -lcryptopp -lrt -lyaml-cpp -lboost_date_time'
|
||||
|
||||
extra_cxxflags = {}
|
||||
|
||||
@@ -293,7 +262,6 @@ scylla_core = (['database.cc',
|
||||
'mutation_query.cc',
|
||||
'key_reader.cc',
|
||||
'keys.cc',
|
||||
'clustering_key_filter.cc',
|
||||
'sstables/sstables.cc',
|
||||
'sstables/compress.cc',
|
||||
'sstables/row.cc',
|
||||
@@ -301,8 +269,6 @@ scylla_core = (['database.cc',
|
||||
'sstables/partition.cc',
|
||||
'sstables/filter.cc',
|
||||
'sstables/compaction.cc',
|
||||
'sstables/compaction_strategy.cc',
|
||||
'sstables/compaction_manager.cc',
|
||||
'log.cc',
|
||||
'transport/event.cc',
|
||||
'transport/event_notifier.cc',
|
||||
@@ -320,14 +286,10 @@ scylla_core = (['database.cc',
|
||||
'cql3/functions/functions.cc',
|
||||
'cql3/statements/cf_prop_defs.cc',
|
||||
'cql3/statements/cf_statement.cc',
|
||||
'cql3/statements/authentication_statement.cc',
|
||||
'cql3/statements/create_keyspace_statement.cc',
|
||||
'cql3/statements/create_table_statement.cc',
|
||||
'cql3/statements/create_type_statement.cc',
|
||||
'cql3/statements/create_user_statement.cc',
|
||||
'cql3/statements/drop_keyspace_statement.cc',
|
||||
'cql3/statements/drop_table_statement.cc',
|
||||
'cql3/statements/drop_type_statement.cc',
|
||||
'cql3/statements/schema_altering_statement.cc',
|
||||
'cql3/statements/ks_prop_defs.cc',
|
||||
'cql3/statements/modification_statement.cc',
|
||||
@@ -343,19 +305,8 @@ scylla_core = (['database.cc',
|
||||
'cql3/statements/create_index_statement.cc',
|
||||
'cql3/statements/truncate_statement.cc',
|
||||
'cql3/statements/alter_table_statement.cc',
|
||||
'cql3/statements/alter_user_statement.cc',
|
||||
'cql3/statements/drop_user_statement.cc',
|
||||
'cql3/statements/list_users_statement.cc',
|
||||
'cql3/statements/authorization_statement.cc',
|
||||
'cql3/statements/permission_altering_statement.cc',
|
||||
'cql3/statements/list_permissions_statement.cc',
|
||||
'cql3/statements/grant_statement.cc',
|
||||
'cql3/statements/revoke_statement.cc',
|
||||
'cql3/statements/alter_type_statement.cc',
|
||||
'cql3/statements/alter_keyspace_statement.cc',
|
||||
'cql3/update_parameters.cc',
|
||||
'cql3/ut_name.cc',
|
||||
'cql3/user_options.cc',
|
||||
'thrift/handler.cc',
|
||||
'thrift/server.cc',
|
||||
'thrift/thrift_validation.cc',
|
||||
@@ -365,13 +316,11 @@ scylla_core = (['database.cc',
|
||||
'utils/big_decimal.cc',
|
||||
'types.cc',
|
||||
'validation.cc',
|
||||
'service/priority_manager.cc',
|
||||
'service/migration_manager.cc',
|
||||
'service/storage_proxy.cc',
|
||||
'cql3/operator.cc',
|
||||
'cql3/relation.cc',
|
||||
'cql3/column_identifier.cc',
|
||||
'cql3/column_specification.cc',
|
||||
'cql3/constants.cc',
|
||||
'cql3/query_processor.cc',
|
||||
'cql3/query_options.cc',
|
||||
@@ -387,13 +336,12 @@ scylla_core = (['database.cc',
|
||||
'cql3/selection/selection.cc',
|
||||
'cql3/selection/selector.cc',
|
||||
'cql3/restrictions/statement_restrictions.cc',
|
||||
'cql3/result_set.cc',
|
||||
'db/consistency_level.cc',
|
||||
'db/system_keyspace.cc',
|
||||
'db/schema_tables.cc',
|
||||
'db/commitlog/commitlog.cc',
|
||||
'db/commitlog/commitlog_replayer.cc',
|
||||
'db/commitlog/commitlog_entry.cc',
|
||||
'db/serializer.cc',
|
||||
'db/config.cc',
|
||||
'db/index/secondary_index.cc',
|
||||
'db/marshal/type_parser.cc',
|
||||
@@ -405,10 +353,9 @@ scylla_core = (['database.cc',
|
||||
'utils/bloom_filter.cc',
|
||||
'utils/bloom_calculations.cc',
|
||||
'utils/rate_limiter.cc',
|
||||
'utils/compaction_manager.cc',
|
||||
'utils/file_lock.cc',
|
||||
'utils/dynamic_bitset.cc',
|
||||
'utils/managed_bytes.cc',
|
||||
'utils/exceptions.cc',
|
||||
'gms/version_generator.cc',
|
||||
'gms/versioned_value.cc',
|
||||
'gms/gossiper.cc',
|
||||
@@ -430,7 +377,6 @@ scylla_core = (['database.cc',
|
||||
'locator/simple_strategy.cc',
|
||||
'locator/local_strategy.cc',
|
||||
'locator/network_topology_strategy.cc',
|
||||
'locator/everywhere_replication_strategy.cc',
|
||||
'locator/token_metadata.cc',
|
||||
'locator/locator.cc',
|
||||
'locator/snitch_base.cc',
|
||||
@@ -444,9 +390,11 @@ scylla_core = (['database.cc',
|
||||
'service/client_state.cc',
|
||||
'service/migration_task.cc',
|
||||
'service/storage_service.cc',
|
||||
'service/pending_range_calculator_service.cc',
|
||||
'service/load_broadcaster.cc',
|
||||
'service/pager/paging_state.cc',
|
||||
'service/pager/query_pagers.cc',
|
||||
'streaming/streaming.cc',
|
||||
'streaming/stream_task.cc',
|
||||
'streaming/stream_session.cc',
|
||||
'streaming/stream_request.cc',
|
||||
@@ -459,6 +407,13 @@ scylla_core = (['database.cc',
|
||||
'streaming/stream_coordinator.cc',
|
||||
'streaming/stream_manager.cc',
|
||||
'streaming/stream_result_future.cc',
|
||||
'streaming/messages/stream_init_message.cc',
|
||||
'streaming/messages/retry_message.cc',
|
||||
'streaming/messages/received_message.cc',
|
||||
'streaming/messages/prepare_message.cc',
|
||||
'streaming/messages/file_message_header.cc',
|
||||
'streaming/messages/outgoing_file_message.cc',
|
||||
'streaming/messages/incoming_file_message.cc',
|
||||
'streaming/stream_session_state.cc',
|
||||
'gc_clock.cc',
|
||||
'partition_slice_builder.cc',
|
||||
@@ -469,8 +424,6 @@ scylla_core = (['database.cc',
|
||||
'auth/auth.cc',
|
||||
'auth/authenticated_user.cc',
|
||||
'auth/authenticator.cc',
|
||||
'auth/authorizer.cc',
|
||||
'auth/default_authorizer.cc',
|
||||
'auth/data_resource.cc',
|
||||
'auth/password_authenticator.cc',
|
||||
'auth/permission.cc',
|
||||
@@ -513,29 +466,7 @@ api = ['api/api.cc',
|
||||
'api/system.cc'
|
||||
]
|
||||
|
||||
idls = ['idl/gossip_digest.idl.hh',
|
||||
'idl/uuid.idl.hh',
|
||||
'idl/range.idl.hh',
|
||||
'idl/keys.idl.hh',
|
||||
'idl/read_command.idl.hh',
|
||||
'idl/token.idl.hh',
|
||||
'idl/ring_position.idl.hh',
|
||||
'idl/result.idl.hh',
|
||||
'idl/frozen_mutation.idl.hh',
|
||||
'idl/reconcilable_result.idl.hh',
|
||||
'idl/streaming.idl.hh',
|
||||
'idl/paging_state.idl.hh',
|
||||
'idl/frozen_schema.idl.hh',
|
||||
'idl/partition_checksum.idl.hh',
|
||||
'idl/replay_position.idl.hh',
|
||||
'idl/truncation_record.idl.hh',
|
||||
'idl/mutation.idl.hh',
|
||||
'idl/query.idl.hh',
|
||||
'idl/idl_test.idl.hh',
|
||||
'idl/commitlog.idl.hh',
|
||||
]
|
||||
|
||||
scylla_tests_dependencies = scylla_core + api + idls + [
|
||||
scylla_tests_dependencies = scylla_core + [
|
||||
'tests/cql_test_env.cc',
|
||||
'tests/cql_assertions.cc',
|
||||
'tests/result_set_assertions.cc',
|
||||
@@ -548,10 +479,11 @@ scylla_tests_seastar_deps = [
|
||||
]
|
||||
|
||||
deps = {
|
||||
'scylla': idls + ['main.cc'] + scylla_core + api,
|
||||
'scylla': ['main.cc'] + scylla_core + api,
|
||||
}
|
||||
|
||||
tests_not_using_seastar_test_framework = set([
|
||||
'tests/types_test',
|
||||
'tests/keys_test',
|
||||
'tests/partitioner_test',
|
||||
'tests/map_difference_test',
|
||||
@@ -576,7 +508,6 @@ tests_not_using_seastar_test_framework = set([
|
||||
'tests/perf/perf_sstable',
|
||||
'tests/managed_vector_test',
|
||||
'tests/dynamic_bitset_test',
|
||||
'tests/idl_test',
|
||||
])
|
||||
|
||||
for t in tests_not_using_seastar_test_framework:
|
||||
@@ -619,44 +550,16 @@ else:
|
||||
args.pie = ''
|
||||
args.fpie = ''
|
||||
|
||||
# a list element means a list of alternative packages to consider
|
||||
# the first element becomes the HAVE_pkg define
|
||||
# a string element is a package name with no alternatives
|
||||
optional_packages = [['libsystemd', 'libsystemd-daemon']]
|
||||
optional_packages = ['libsystemd']
|
||||
pkgs = []
|
||||
|
||||
def setup_first_pkg_of_list(pkglist):
|
||||
# The HAVE_pkg symbol is taken from the first alternative
|
||||
upkg = pkglist[0].upper().replace('-', '_')
|
||||
for pkg in pkglist:
|
||||
if have_pkg(pkg):
|
||||
pkgs.append(pkg)
|
||||
defines.append('HAVE_{}=1'.format(upkg))
|
||||
return True
|
||||
return False
|
||||
|
||||
for pkglist in optional_packages:
|
||||
if isinstance(pkglist, str):
|
||||
pkglist = [pkglist]
|
||||
if not setup_first_pkg_of_list(pkglist):
|
||||
if len(pkglist) == 1:
|
||||
print('Missing optional package {pkglist[0]}'.format(**locals()))
|
||||
else:
|
||||
alternatives = ':'.join(pkglist[1:])
|
||||
print('Missing optional package {pkglist[0]} (or alteratives {alternatives})'.format(**locals()))
|
||||
|
||||
if not try_compile(compiler=args.cxx, source='#include <boost/version.hpp>'):
|
||||
print('Boost not installed. Please install {}.'.format(pkgname("boost-devel")))
|
||||
sys.exit(1)
|
||||
|
||||
if not try_compile(compiler=args.cxx, source='''\
|
||||
#include <boost/version.hpp>
|
||||
#if BOOST_VERSION < 105500
|
||||
#error Boost version too low
|
||||
#endif
|
||||
'''):
|
||||
print('Installed boost version too old. Please update {}.'.format(pkgname("boost-devel")))
|
||||
sys.exit(1)
|
||||
for pkg in optional_packages:
|
||||
if have_pkg(pkg):
|
||||
pkgs.append(pkg)
|
||||
upkg = pkg.upper().replace('-', '_')
|
||||
defines.append('HAVE_{}=1'.format(upkg))
|
||||
else:
|
||||
print('Missing optional package {pkg}'.format(**locals()))
|
||||
|
||||
defines = ' '.join(['-D' + d for d in defines])
|
||||
|
||||
@@ -686,8 +589,6 @@ if args.dpdk:
|
||||
seastar_flags += ['--enable-dpdk']
|
||||
elif args.dpdk_target:
|
||||
seastar_flags += ['--dpdk-target', args.dpdk_target]
|
||||
if args.staticcxx:
|
||||
seastar_flags += ['--static-stdc++']
|
||||
|
||||
seastar_cflags = args.user_cflags + " -march=nehalem"
|
||||
seastar_flags += ['--compiler', args.cxx, '--cflags=%s' % (seastar_cflags)]
|
||||
@@ -721,7 +622,7 @@ for mode in build_modes:
|
||||
seastar_deps = 'practically_anything_can_change_so_lets_run_it_every_time_and_restat.'
|
||||
|
||||
args.user_cflags += " " + pkg_config("--cflags", "jsoncpp")
|
||||
libs = "-lyaml-cpp -llz4 -lz -lsnappy " + pkg_config("--libs", "jsoncpp") + ' -lboost_filesystem' + ' -lcrypt' + ' -lboost_date_time'
|
||||
libs = "-lyaml-cpp -llz4 -lz -lsnappy " + pkg_config("--libs", "jsoncpp") + ' -lboost_filesystem' + ' -lcrypt'
|
||||
for pkg in pkgs:
|
||||
args.user_cflags += ' ' + pkg_config('--cflags', pkg)
|
||||
libs += ' ' + pkg_config('--libs', pkg)
|
||||
@@ -729,10 +630,6 @@ user_cflags = args.user_cflags
|
||||
user_ldflags = args.user_ldflags
|
||||
if args.staticcxx:
|
||||
user_ldflags += " -static-libgcc -static-libstdc++"
|
||||
if args.staticthrift:
|
||||
thrift_libs = "-Wl,-Bstatic -lthrift -Wl,-Bdynamic"
|
||||
else:
|
||||
thrift_libs = "-lthrift"
|
||||
|
||||
outdir = 'build'
|
||||
buildfile = 'build.ninja'
|
||||
@@ -760,16 +657,10 @@ with open(buildfile, 'w') as f:
|
||||
rule swagger
|
||||
command = seastar/json/json2code.py -f $in -o $out
|
||||
description = SWAGGER $out
|
||||
rule serializer
|
||||
command = {python} ./idl-compiler.py --ns ser -f $in -o $out
|
||||
description = IDL compiler $out
|
||||
rule ninja
|
||||
command = {ninja} -C $subdir $target
|
||||
restat = 1
|
||||
description = NINJA $out
|
||||
rule copy
|
||||
command = cp $in $out
|
||||
description = COPY $out
|
||||
''').format(**globals()))
|
||||
for mode in build_modes:
|
||||
modeval = modes[mode]
|
||||
@@ -802,12 +693,9 @@ with open(buildfile, 'w') as f:
|
||||
compiles = {}
|
||||
ragels = {}
|
||||
swaggers = {}
|
||||
serializers = {}
|
||||
thrifts = set()
|
||||
antlr3_grammars = set()
|
||||
for binary in build_artifacts:
|
||||
if binary in other:
|
||||
continue
|
||||
srcs = deps[binary]
|
||||
objs = ['$builddir/' + mode + '/' + src.replace('.cc', '.o')
|
||||
for src in srcs
|
||||
@@ -843,14 +731,14 @@ with open(buildfile, 'w') as f:
|
||||
f.write('build $builddir/{}/{}: {}.{} {} {}\n'.format(mode, binary, tests_link_rule, mode, str.join(' ', objs),
|
||||
'seastar/build/{}/libseastar.a'.format(mode)))
|
||||
if has_thrift:
|
||||
f.write(' libs = {} -lboost_system $libs\n'.format(thrift_libs))
|
||||
f.write(' libs = -lthrift -lboost_system $libs\n')
|
||||
f.write('build $builddir/{}/{}_g: link.{} {} {}\n'.format(mode, binary, mode, str.join(' ', objs),
|
||||
'seastar/build/{}/libseastar.a'.format(mode)))
|
||||
else:
|
||||
f.write('build $builddir/{}/{}: link.{} {} {}\n'.format(mode, binary, mode, str.join(' ', objs),
|
||||
'seastar/build/{}/libseastar.a'.format(mode)))
|
||||
if has_thrift:
|
||||
f.write(' libs = {} -lboost_system $libs\n'.format(thrift_libs))
|
||||
f.write(' libs = -lthrift -lboost_system $libs\n')
|
||||
for src in srcs:
|
||||
if src.endswith('.cc'):
|
||||
obj = '$builddir/' + mode + '/' + src.replace('.cc', '.o')
|
||||
@@ -858,9 +746,6 @@ with open(buildfile, 'w') as f:
|
||||
elif src.endswith('.rl'):
|
||||
hh = '$builddir/' + mode + '/gen/' + src.replace('.rl', '.hh')
|
||||
ragels[hh] = src
|
||||
elif src.endswith('.idl.hh'):
|
||||
hh = '$builddir/' + mode + '/gen/' + src.replace('.idl.hh', '.dist.hh')
|
||||
serializers[hh] = src
|
||||
elif src.endswith('.json'):
|
||||
hh = '$builddir/' + mode + '/gen/' + src + '.hh'
|
||||
swaggers[hh] = src
|
||||
@@ -873,14 +758,12 @@ with open(buildfile, 'w') as f:
|
||||
for obj in compiles:
|
||||
src = compiles[obj]
|
||||
gen_headers = list(ragels.keys())
|
||||
gen_headers += ['seastar/build/{}/gen/http/request_parser.hh'.format(mode)]
|
||||
gen_headers += ['seastar/build/{}/gen/http/http_response_parser.hh'.format(mode)]
|
||||
gen_headers += ['seastar/build/{}/http/request_parser.hh'.format(mode)]
|
||||
for th in thrifts:
|
||||
gen_headers += th.headers('$builddir/{}/gen'.format(mode))
|
||||
for g in antlr3_grammars:
|
||||
gen_headers += g.headers('$builddir/{}/gen'.format(mode))
|
||||
gen_headers += list(swaggers.keys())
|
||||
gen_headers += list(serializers.keys())
|
||||
f.write('build {}: cxx.{} {} || {} \n'.format(obj, mode, src, ' '.join(gen_headers)))
|
||||
if src in extra_cxxflags:
|
||||
f.write(' cxxflags = {seastar_cflags} $cxxflags $cxxflags_{mode} {extra_cxxflags}\n'.format(mode = mode, extra_cxxflags = extra_cxxflags[src], **modeval))
|
||||
@@ -890,9 +773,6 @@ with open(buildfile, 'w') as f:
|
||||
for hh in swaggers:
|
||||
src = swaggers[hh]
|
||||
f.write('build {}: swagger {}\n'.format(hh,src))
|
||||
for hh in serializers:
|
||||
src = serializers[hh]
|
||||
f.write('build {}: serializer {} | idl-compiler.py\n'.format(hh,src))
|
||||
for thrift in thrifts:
|
||||
outs = ' '.join(thrift.generated('$builddir/{}/gen'.format(mode)))
|
||||
f.write('build {}: thrift.{} {}\n'.format(outs, mode, thrift.source))
|
||||
@@ -905,14 +785,10 @@ with open(buildfile, 'w') as f:
|
||||
grammar.source.rsplit('.', 1)[0]))
|
||||
for cc in grammar.sources('$builddir/{}/gen'.format(mode)):
|
||||
obj = cc.replace('.cpp', '.o')
|
||||
f.write('build {}: cxx.{} {} || {}\n'.format(obj, mode, cc, ' '.join(serializers)))
|
||||
f.write('build seastar/build/{mode}/libseastar.a seastar/build/{mode}/apps/iotune/iotune seastar/build/{mode}/gen/http/request_parser.hh seastar/build/{mode}/gen/http/http_response_parser.hh: ninja {seastar_deps}\n'
|
||||
.format(**locals()))
|
||||
f.write('build {}: cxx.{} {}\n'.format(obj, mode, cc))
|
||||
f.write('build seastar/build/{}/libseastar.a: ninja {}\n'.format(mode, seastar_deps))
|
||||
f.write(' subdir = seastar\n')
|
||||
f.write(' target = build/{mode}/libseastar.a build/{mode}/apps/iotune/iotune build/{mode}/gen/http/request_parser.hh build/{mode}/gen/http/http_response_parser.hh\n'.format(**locals()))
|
||||
f.write(textwrap.dedent('''\
|
||||
build build/{mode}/iotune: copy seastar/build/{mode}/apps/iotune/iotune
|
||||
''').format(**locals()))
|
||||
f.write(' target = build/{}/libseastar.a\n'.format(mode))
|
||||
f.write('build {}: phony\n'.format(seastar_deps))
|
||||
f.write(textwrap.dedent('''\
|
||||
rule configure
|
||||
@@ -923,6 +799,10 @@ with open(buildfile, 'w') as f:
|
||||
command = find -name '*.[chS]' -o -name "*.cc" -o -name "*.hh" | cscope -bq -i-
|
||||
description = CSCOPE
|
||||
build cscope: cscope
|
||||
rule request_parser_hh
|
||||
command = {ninja} -C seastar build/release/gen/http/request_parser.hh build/debug/gen/http/request_parser.hh
|
||||
description = GEN seastar/http/request_parser.hh
|
||||
build seastar/build/release/http/request_parser.hh seastar/build/debug/http/request_parser.hh: request_parser_hh
|
||||
rule clean
|
||||
command = rm -rf build
|
||||
description = CLEAN
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2015 ScyllaDB
|
||||
* Copyright (C) 2015 Cloudius Systems, Ltd.
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -35,7 +35,7 @@ class converting_mutation_partition_applier : public mutation_partition_visitor
|
||||
deletable_row* _current_row;
|
||||
private:
|
||||
static bool is_compatible(const column_definition& new_def, const data_type& old_type, column_kind kind) {
|
||||
return ::is_compatible(new_def.kind, kind) && new_def.type->is_value_compatible_with(*old_type);
|
||||
return new_def.kind == kind && new_def.type->is_value_compatible_with(*old_type);
|
||||
}
|
||||
void accept_cell(row& dst, column_kind kind, const column_definition& new_def, const data_type& old_type, atomic_cell_view cell) {
|
||||
if (is_compatible(new_def, old_type, kind) && cell.timestamp() > new_def.dropped_at()) {
|
||||
@@ -75,7 +75,7 @@ public:
|
||||
}
|
||||
|
||||
virtual void accept_static_cell(column_id id, atomic_cell_view cell) override {
|
||||
const column_mapping_entry& col = _visited_column_mapping.static_column_at(id);
|
||||
const column_mapping::column& col = _visited_column_mapping.static_column_at(id);
|
||||
const column_definition* def = _p_schema.get_column_definition(col.name());
|
||||
if (def) {
|
||||
accept_cell(_p._static_row, column_kind::static_column, *def, col.type(), cell);
|
||||
@@ -83,7 +83,7 @@ public:
|
||||
}
|
||||
|
||||
virtual void accept_static_cell(column_id id, collection_mutation_view collection) override {
|
||||
const column_mapping_entry& col = _visited_column_mapping.static_column_at(id);
|
||||
const column_mapping::column& col = _visited_column_mapping.static_column_at(id);
|
||||
const column_definition* def = _p_schema.get_column_definition(col.name());
|
||||
if (def) {
|
||||
accept_cell(_p._static_row, column_kind::static_column, *def, col.type(), collection);
|
||||
@@ -102,7 +102,7 @@ public:
|
||||
}
|
||||
|
||||
virtual void accept_row_cell(column_id id, atomic_cell_view cell) override {
|
||||
const column_mapping_entry& col = _visited_column_mapping.regular_column_at(id);
|
||||
const column_mapping::column& col = _visited_column_mapping.regular_column_at(id);
|
||||
const column_definition* def = _p_schema.get_column_definition(col.name());
|
||||
if (def) {
|
||||
accept_cell(_current_row->cells(), column_kind::regular_column, *def, col.type(), cell);
|
||||
@@ -110,7 +110,7 @@ public:
|
||||
}
|
||||
|
||||
virtual void accept_row_cell(column_id id, collection_mutation_view collection) override {
|
||||
const column_mapping_entry& col = _visited_column_mapping.regular_column_at(id);
|
||||
const column_mapping::column& col = _visited_column_mapping.regular_column_at(id);
|
||||
const column_definition* def = _p_schema.get_column_definition(col.name());
|
||||
if (def) {
|
||||
accept_cell(_current_row->cells(), column_kind::regular_column, *def, col.type(), collection);
|
||||
|
||||
222
cql3/Cql.g
222
cql3/Cql.g
@@ -26,21 +26,16 @@ options {
|
||||
@parser::namespace{cql3_parser}
|
||||
|
||||
@lexer::includes {
|
||||
#include "cql3/error_collector.hh"
|
||||
#include "cql3/error_listener.hh"
|
||||
}
|
||||
|
||||
@parser::includes {
|
||||
#include "cql3/selection/writetime_or_ttl.hh"
|
||||
#include "cql3/statements/alter_keyspace_statement.hh"
|
||||
#include "cql3/statements/alter_table_statement.hh"
|
||||
#include "cql3/statements/create_keyspace_statement.hh"
|
||||
#include "cql3/statements/drop_keyspace_statement.hh"
|
||||
#include "cql3/statements/create_index_statement.hh"
|
||||
#include "cql3/statements/create_table_statement.hh"
|
||||
#include "cql3/statements/create_type_statement.hh"
|
||||
#include "cql3/statements/drop_type_statement.hh"
|
||||
#include "cql3/statements/alter_type_statement.hh"
|
||||
#include "cql3/statements/property_definitions.hh"
|
||||
#include "cql3/statements/drop_table_statement.hh"
|
||||
#include "cql3/statements/truncate_statement.hh"
|
||||
@@ -50,13 +45,6 @@ options {
|
||||
#include "cql3/statements/index_prop_defs.hh"
|
||||
#include "cql3/statements/use_statement.hh"
|
||||
#include "cql3/statements/batch_statement.hh"
|
||||
#include "cql3/statements/create_user_statement.hh"
|
||||
#include "cql3/statements/alter_user_statement.hh"
|
||||
#include "cql3/statements/drop_user_statement.hh"
|
||||
#include "cql3/statements/list_users_statement.hh"
|
||||
#include "cql3/statements/grant_statement.hh"
|
||||
#include "cql3/statements/revoke_statement.hh"
|
||||
#include "cql3/statements/list_permissions_statement.hh"
|
||||
#include "cql3/statements/index_target.hh"
|
||||
#include "cql3/statements/ks_prop_defs.hh"
|
||||
#include "cql3/selection/raw_selector.hh"
|
||||
@@ -119,13 +107,10 @@ struct uninitialized {
|
||||
}
|
||||
|
||||
@context {
|
||||
using collector_type = cql3::error_collector<ComponentType, ExceptionBaseType::TokenType, ExceptionBaseType>;
|
||||
using listener_type = cql3::error_listener<ComponentType, ExceptionBaseType>;
|
||||
|
||||
using listener_type = cql3::error_listener<RecognizerType>;
|
||||
listener_type* listener;
|
||||
|
||||
std::vector<::shared_ptr<cql3::column_identifier>> _bind_variables;
|
||||
std::vector<std::unique_ptr<TokenType>> _missing_tokens;
|
||||
|
||||
// Can't use static variable, since it needs to be defined out-of-line
|
||||
static const std::unordered_set<sstring>& _reserved_type_names() {
|
||||
@@ -175,26 +160,15 @@ struct uninitialized {
|
||||
|
||||
void displayRecognitionError(ANTLR_UINT8** token_names, ExceptionBaseType* ex)
|
||||
{
|
||||
listener->syntax_error(*this, token_names, ex);
|
||||
std::stringstream msg;
|
||||
ex->displayRecognitionError(token_names, msg);
|
||||
listener->syntax_error(*this, msg.str());
|
||||
}
|
||||
|
||||
void add_recognition_error(const sstring& msg) {
|
||||
listener->syntax_error(*this, msg);
|
||||
}
|
||||
|
||||
bool is_eof_token(CommonTokenType token) const
|
||||
{
|
||||
return token == CommonTokenType::TOKEN_EOF;
|
||||
}
|
||||
|
||||
std::string token_text(const TokenType* token)
|
||||
{
|
||||
if (!token) {
|
||||
return "";
|
||||
}
|
||||
return token->getText();
|
||||
}
|
||||
|
||||
std::map<sstring, sstring> convert_property_map(shared_ptr<cql3::maps::literal> map) {
|
||||
if (!map || map->entries.empty()) {
|
||||
return std::map<sstring, sstring>{};
|
||||
@@ -241,13 +215,6 @@ struct uninitialized {
|
||||
}
|
||||
operations.emplace_back(std::move(key), std::move(update));
|
||||
}
|
||||
|
||||
TokenType* getMissingSymbol(IntStreamType* istream, ExceptionBaseType* e,
|
||||
ANTLR_UINT32 expectedTokenType, BitsetListType* follow) {
|
||||
auto token = BaseType::getMissingSymbol(istream, e, expectedTokenType, follow);
|
||||
_missing_tokens.emplace_back(token);
|
||||
return token;
|
||||
}
|
||||
}
|
||||
|
||||
@lexer::namespace{cql3_parser}
|
||||
@@ -265,8 +232,7 @@ struct uninitialized {
|
||||
}
|
||||
|
||||
@lexer::context {
|
||||
using collector_type = cql3::error_collector<ComponentType, ExceptionBaseType::TokenType, ExceptionBaseType>;
|
||||
using listener_type = cql3::error_listener<ComponentType, ExceptionBaseType>;
|
||||
using listener_type = cql3::error_listener<RecognizerType>;
|
||||
|
||||
listener_type* listener;
|
||||
|
||||
@@ -276,20 +242,9 @@ struct uninitialized {
|
||||
|
||||
void displayRecognitionError(ANTLR_UINT8** token_names, ExceptionBaseType* ex)
|
||||
{
|
||||
listener->syntax_error(*this, token_names, ex);
|
||||
}
|
||||
|
||||
bool is_eof_token(CommonTokenType token) const
|
||||
{
|
||||
return token == CommonTokenType::TOKEN_EOF;
|
||||
}
|
||||
|
||||
std::string token_text(const TokenType* token) const
|
||||
{
|
||||
if (!token) {
|
||||
return "";
|
||||
}
|
||||
return std::to_string(int(*token));
|
||||
std::stringstream msg;
|
||||
ex->displayRecognitionError(token_names, msg);
|
||||
listener->syntax_error(*this, msg.str());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -317,6 +272,7 @@ cqlStatement returns [shared_ptr<parsed_statement> stmt]
|
||||
| st13=dropIndexStatement { $stmt = st13; }
|
||||
#endif
|
||||
| st14=alterTableStatement { $stmt = st14; }
|
||||
#if 0
|
||||
| st15=alterKeyspaceStatement { $stmt = st15; }
|
||||
| st16=grantStatement { $stmt = st16; }
|
||||
| st17=revokeStatement { $stmt = st17; }
|
||||
@@ -325,14 +281,11 @@ cqlStatement returns [shared_ptr<parsed_statement> stmt]
|
||||
| st20=alterUserStatement { $stmt = st20; }
|
||||
| st21=dropUserStatement { $stmt = st21; }
|
||||
| st22=listUsersStatement { $stmt = st22; }
|
||||
#if 0
|
||||
| st23=createTriggerStatement { $stmt = st23; }
|
||||
| st24=dropTriggerStatement { $stmt = st24; }
|
||||
#endif
|
||||
| st25=createTypeStatement { $stmt = st25; }
|
||||
| st26=alterTypeStatement { $stmt = st26; }
|
||||
| st27=dropTypeStatement { $stmt = st27; }
|
||||
#if 0
|
||||
| st28=createFunctionStatement { $stmt = st28; }
|
||||
| st29=dropFunctionStatement { $stmt = st29; }
|
||||
| st30=createAggregateStatement { $stmt = st30; }
|
||||
@@ -742,6 +695,7 @@ cfamOrdering[shared_ptr<cql3::statements::create_table_statement::raw_statement>
|
||||
;
|
||||
|
||||
|
||||
#if 0
|
||||
/**
|
||||
* CREATE TYPE foo (
|
||||
* <name1> <type1>,
|
||||
@@ -749,16 +703,17 @@ cfamOrdering[shared_ptr<cql3::statements::create_table_statement::raw_statement>
|
||||
* ....
|
||||
* )
|
||||
*/
|
||||
createTypeStatement returns [::shared_ptr<create_type_statement> expr]
|
||||
@init { bool if_not_exists = false; }
|
||||
: K_CREATE K_TYPE (K_IF K_NOT K_EXISTS { if_not_exists = true; } )?
|
||||
tn=userTypeName { $expr = ::make_shared<create_type_statement>(tn, if_not_exists); }
|
||||
createTypeStatement returns [CreateTypeStatement expr]
|
||||
@init { boolean ifNotExists = false; }
|
||||
: K_CREATE K_TYPE (K_IF K_NOT K_EXISTS { ifNotExists = true; } )?
|
||||
tn=userTypeName { $expr = new CreateTypeStatement(tn, ifNotExists); }
|
||||
'(' typeColumns[expr] ( ',' typeColumns[expr]? )* ')'
|
||||
;
|
||||
|
||||
typeColumns[::shared_ptr<create_type_statement> expr]
|
||||
: k=ident v=comparatorType { $expr->add_definition(k, v); }
|
||||
typeColumns[CreateTypeStatement expr]
|
||||
: k=ident v=comparatorType { $expr.addDefinition(k, v); }
|
||||
;
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
@@ -808,18 +763,15 @@ dropTriggerStatement returns [DropTriggerStatement expr]
|
||||
{ $expr = new DropTriggerStatement(cf, name.toString(), ifExists); }
|
||||
;
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* ALTER KEYSPACE <KS> WITH <property> = <value>;
|
||||
*/
|
||||
alterKeyspaceStatement returns [shared_ptr<cql3::statements::alter_keyspace_statement> expr]
|
||||
@init {
|
||||
auto attrs = make_shared<cql3::statements::ks_prop_defs>();
|
||||
}
|
||||
alterKeyspaceStatement returns [AlterKeyspaceStatement expr]
|
||||
@init { KSPropDefs attrs = new KSPropDefs(); }
|
||||
: K_ALTER K_KEYSPACE ks=keyspaceName
|
||||
K_WITH properties[attrs] { $expr = make_shared<cql3::statements::alter_keyspace_statement>(ks, attrs); }
|
||||
K_WITH properties[attrs] { $expr = new AlterKeyspaceStatement(ks, attrs); }
|
||||
;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* ALTER COLUMN FAMILY <CF> ALTER <column> TYPE <newtype>;
|
||||
@@ -850,27 +802,26 @@ alterTableStatement returns [shared_ptr<alter_table_statement> expr]
|
||||
}
|
||||
;
|
||||
|
||||
#if 0
|
||||
/**
|
||||
* ALTER TYPE <name> ALTER <field> TYPE <newtype>;
|
||||
* ALTER TYPE <name> ADD <field> <newtype>;
|
||||
* ALTER TYPE <name> RENAME <field> TO <newtype> AND ...;
|
||||
*/
|
||||
alterTypeStatement returns [::shared_ptr<alter_type_statement> expr]
|
||||
alterTypeStatement returns [AlterTypeStatement expr]
|
||||
: K_ALTER K_TYPE name=userTypeName
|
||||
( K_ALTER f=ident K_TYPE v=comparatorType { $expr = ::make_shared<alter_type_statement::add_or_alter>(name, false, f, v); }
|
||||
| K_ADD f=ident v=comparatorType { $expr = ::make_shared<alter_type_statement::add_or_alter>(name, true, f, v); }
|
||||
( K_ALTER f=ident K_TYPE v=comparatorType { $expr = AlterTypeStatement.alter(name, f, v); }
|
||||
| K_ADD f=ident v=comparatorType { $expr = AlterTypeStatement.addition(name, f, v); }
|
||||
| K_RENAME
|
||||
{ $expr = ::make_shared<alter_type_statement::renames>(name); }
|
||||
renames[{ static_pointer_cast<alter_type_statement::renames>($expr) }]
|
||||
{ Map<ColumnIdentifier, ColumnIdentifier> renames = new HashMap<ColumnIdentifier, ColumnIdentifier>(); }
|
||||
id1=ident K_TO toId1=ident { renames.put(id1, toId1); }
|
||||
( K_AND idn=ident K_TO toIdn=ident { renames.put(idn, toIdn); } )*
|
||||
{ $expr = AlterTypeStatement.renames(name, renames); }
|
||||
)
|
||||
;
|
||||
#endif
|
||||
|
||||
|
||||
renames[::shared_ptr<alter_type_statement::renames> expr]
|
||||
: fromId=ident K_TO toId=ident { $expr->add_rename(fromId, toId); }
|
||||
( K_AND renames[$expr] )?
|
||||
;
|
||||
|
||||
/**
|
||||
* DROP KEYSPACE [IF EXISTS] <KSP>;
|
||||
*/
|
||||
@@ -887,15 +838,15 @@ dropTableStatement returns [::shared_ptr<drop_table_statement> stmt]
|
||||
: K_DROP K_COLUMNFAMILY (K_IF K_EXISTS { if_exists = true; } )? cf=columnFamilyName { $stmt = ::make_shared<drop_table_statement>(cf, if_exists); }
|
||||
;
|
||||
|
||||
#if 0
|
||||
/**
|
||||
* DROP TYPE <name>;
|
||||
*/
|
||||
dropTypeStatement returns [::shared_ptr<drop_type_statement> stmt]
|
||||
@init { bool if_exists = false; }
|
||||
: K_DROP K_TYPE (K_IF K_EXISTS { if_exists = true; } )? name=userTypeName { $stmt = ::make_shared<drop_type_statement>(name, if_exists); }
|
||||
dropTypeStatement returns [DropTypeStatement stmt]
|
||||
@init { boolean ifExists = false; }
|
||||
: K_DROP K_TYPE (K_IF K_EXISTS { ifExists = true; } )? name=userTypeName { $stmt = new DropTypeStatement(name, ifExists); }
|
||||
;
|
||||
|
||||
#if 0
|
||||
/**
|
||||
* DROP INDEX [IF EXISTS] <INDEX_NAME>
|
||||
*/
|
||||
@@ -913,118 +864,120 @@ truncateStatement returns [::shared_ptr<truncate_statement> stmt]
|
||||
: K_TRUNCATE (K_COLUMNFAMILY)? cf=columnFamilyName { $stmt = ::make_shared<truncate_statement>(cf); }
|
||||
;
|
||||
|
||||
#if 0
|
||||
/**
|
||||
* GRANT <permission> ON <resource> TO <username>
|
||||
*/
|
||||
grantStatement returns [::shared_ptr<grant_statement> stmt]
|
||||
grantStatement returns [GrantStatement stmt]
|
||||
: K_GRANT
|
||||
permissionOrAll
|
||||
K_ON
|
||||
resource
|
||||
K_TO
|
||||
username
|
||||
{ $stmt = ::make_shared<grant_statement>($permissionOrAll.perms, $resource.res, $username.text); }
|
||||
{ $stmt = new GrantStatement($permissionOrAll.perms, $resource.res, $username.text); }
|
||||
;
|
||||
|
||||
/**
|
||||
* REVOKE <permission> ON <resource> FROM <username>
|
||||
*/
|
||||
revokeStatement returns [::shared_ptr<revoke_statement> stmt]
|
||||
revokeStatement returns [RevokeStatement stmt]
|
||||
: K_REVOKE
|
||||
permissionOrAll
|
||||
K_ON
|
||||
resource
|
||||
K_FROM
|
||||
username
|
||||
{ $stmt = ::make_shared<revoke_statement>($permissionOrAll.perms, $resource.res, $username.text); }
|
||||
{ $stmt = new RevokeStatement($permissionOrAll.perms, $resource.res, $username.text); }
|
||||
;
|
||||
|
||||
listPermissionsStatement returns [::shared_ptr<list_permissions_statement> stmt]
|
||||
listPermissionsStatement returns [ListPermissionsStatement stmt]
|
||||
@init {
|
||||
std::experimental::optional<auth::data_resource> r;
|
||||
std::experimental::optional<sstring> u;
|
||||
bool recursive = true;
|
||||
IResource resource = null;
|
||||
String username = null;
|
||||
boolean recursive = true;
|
||||
}
|
||||
: K_LIST
|
||||
permissionOrAll
|
||||
( K_ON resource { r = $resource.res; } )?
|
||||
( K_OF username { u = sstring($username.text); } )?
|
||||
( K_ON resource { resource = $resource.res; } )?
|
||||
( K_OF username { username = $username.text; } )?
|
||||
( K_NORECURSIVE { recursive = false; } )?
|
||||
{ $stmt = ::make_shared<list_permissions_statement>($permissionOrAll.perms, std::move(r), std::move(u), recursive); }
|
||||
{ $stmt = new ListPermissionsStatement($permissionOrAll.perms, resource, username, recursive); }
|
||||
;
|
||||
|
||||
permission returns [auth::permission perm]
|
||||
permission returns [Permission perm]
|
||||
: p=(K_CREATE | K_ALTER | K_DROP | K_SELECT | K_MODIFY | K_AUTHORIZE)
|
||||
{ $perm = auth::permissions::from_string($p.text); }
|
||||
{ $perm = Permission.valueOf($p.text.toUpperCase()); }
|
||||
;
|
||||
|
||||
permissionOrAll returns [auth::permission_set perms]
|
||||
: K_ALL ( K_PERMISSIONS )? { $perms = auth::permissions::ALL_DATA; }
|
||||
| p=permission ( K_PERMISSION )? { $perms = auth::permission_set::from_mask(auth::permission_set::mask_for($p.perm)); }
|
||||
permissionOrAll returns [Set<Permission> perms]
|
||||
: K_ALL ( K_PERMISSIONS )? { $perms = Permission.ALL_DATA; }
|
||||
| p=permission ( K_PERMISSION )? { $perms = EnumSet.of($p.perm); }
|
||||
;
|
||||
|
||||
resource returns [auth::data_resource res]
|
||||
resource returns [IResource res]
|
||||
: r=dataResource { $res = $r.res; }
|
||||
;
|
||||
|
||||
dataResource returns [auth::data_resource res]
|
||||
: K_ALL K_KEYSPACES { $res = auth::data_resource(); }
|
||||
| K_KEYSPACE ks = keyspaceName { $res = auth::data_resource($ks.id); }
|
||||
dataResource returns [DataResource res]
|
||||
: K_ALL K_KEYSPACES { $res = DataResource.root(); }
|
||||
| K_KEYSPACE ks = keyspaceName { $res = DataResource.keyspace($ks.id); }
|
||||
| ( K_COLUMNFAMILY )? cf = columnFamilyName
|
||||
{ $res = auth::data_resource($cf.name->get_keyspace(), $cf.name->get_column_family()); }
|
||||
{ $res = DataResource.columnFamily($cf.name.getKeyspace(), $cf.name.getColumnFamily()); }
|
||||
;
|
||||
|
||||
/**
|
||||
* CREATE USER [IF NOT EXISTS] <username> [WITH PASSWORD <password>] [SUPERUSER|NOSUPERUSER]
|
||||
*/
|
||||
createUserStatement returns [::shared_ptr<create_user_statement> stmt]
|
||||
createUserStatement returns [CreateUserStatement stmt]
|
||||
@init {
|
||||
auto opts = ::make_shared<cql3::user_options>();
|
||||
bool superuser = false;
|
||||
bool ifNotExists = false;
|
||||
UserOptions opts = new UserOptions();
|
||||
boolean superuser = false;
|
||||
boolean ifNotExists = false;
|
||||
}
|
||||
: K_CREATE K_USER (K_IF K_NOT K_EXISTS { ifNotExists = true; })? username
|
||||
( K_WITH userOptions[opts] )?
|
||||
( K_SUPERUSER { superuser = true; } | K_NOSUPERUSER { superuser = false; } )?
|
||||
{ $stmt = ::make_shared<create_user_statement>($username.text, std::move(opts), superuser, ifNotExists); }
|
||||
{ $stmt = new CreateUserStatement($username.text, opts, superuser, ifNotExists); }
|
||||
;
|
||||
|
||||
/**
|
||||
* ALTER USER <username> [WITH PASSWORD <password>] [SUPERUSER|NOSUPERUSER]
|
||||
*/
|
||||
alterUserStatement returns [::shared_ptr<alter_user_statement> stmt]
|
||||
alterUserStatement returns [AlterUserStatement stmt]
|
||||
@init {
|
||||
auto opts = ::make_shared<cql3::user_options>();
|
||||
std::experimental::optional<bool> superuser;
|
||||
UserOptions opts = new UserOptions();
|
||||
Boolean superuser = null;
|
||||
}
|
||||
: K_ALTER K_USER username
|
||||
( K_WITH userOptions[opts] )?
|
||||
( K_SUPERUSER { superuser = true; } | K_NOSUPERUSER { superuser = false; } )?
|
||||
{ $stmt = ::make_shared<alter_user_statement>($username.text, std::move(opts), std::move(superuser)); }
|
||||
{ $stmt = new AlterUserStatement($username.text, opts, superuser); }
|
||||
;
|
||||
|
||||
/**
|
||||
* DROP USER [IF EXISTS] <username>
|
||||
*/
|
||||
dropUserStatement returns [::shared_ptr<drop_user_statement> stmt]
|
||||
@init { bool ifExists = false; }
|
||||
: K_DROP K_USER (K_IF K_EXISTS { ifExists = true; })? username { $stmt = ::make_shared<drop_user_statement>($username.text, ifExists); }
|
||||
dropUserStatement returns [DropUserStatement stmt]
|
||||
@init { boolean ifExists = false; }
|
||||
: K_DROP K_USER (K_IF K_EXISTS { ifExists = true; })? username { $stmt = new DropUserStatement($username.text, ifExists); }
|
||||
;
|
||||
|
||||
/**
|
||||
* LIST USERS
|
||||
*/
|
||||
listUsersStatement returns [::shared_ptr<list_users_statement> stmt]
|
||||
: K_LIST K_USERS { $stmt = ::make_shared<list_users_statement>(); }
|
||||
listUsersStatement returns [ListUsersStatement stmt]
|
||||
: K_LIST K_USERS { $stmt = new ListUsersStatement(); }
|
||||
;
|
||||
|
||||
userOptions[::shared_ptr<cql3::user_options> opts]
|
||||
userOptions[UserOptions opts]
|
||||
: userOption[opts]
|
||||
;
|
||||
|
||||
userOption[::shared_ptr<cql3::user_options> opts]
|
||||
: k=K_PASSWORD v=STRING_LITERAL { opts->put($k.text, $v.text); }
|
||||
userOption[UserOptions opts]
|
||||
: k=K_PASSWORD v=STRING_LITERAL { opts.put($k.text, $v.text); }
|
||||
;
|
||||
#endif
|
||||
|
||||
/** DEFINITIONS **/
|
||||
|
||||
@@ -1203,8 +1156,7 @@ columnOperation[operations_type& operations]
|
||||
|
||||
columnOperationDifferentiator[operations_type& operations, ::shared_ptr<cql3::column_identifier::raw> key]
|
||||
: '=' normalColumnOperation[operations, key]
|
||||
| '[' k=term ']' specializedColumnOperation[operations, key, k, false]
|
||||
| '[' K_SCYLLA_TIMEUUID_LIST_INDEX '(' k=term ')' ']' specializedColumnOperation[operations, key, k, true]
|
||||
| '[' k=term ']' specializedColumnOperation[operations, key, k]
|
||||
;
|
||||
|
||||
normalColumnOperation[operations_type& operations, ::shared_ptr<cql3::column_identifier::raw> key]
|
||||
@@ -1246,12 +1198,11 @@ normalColumnOperation[operations_type& operations, ::shared_ptr<cql3::column_ide
|
||||
specializedColumnOperation[std::vector<std::pair<shared_ptr<cql3::column_identifier::raw>,
|
||||
shared_ptr<cql3::operation::raw_update>>>& operations,
|
||||
shared_ptr<cql3::column_identifier::raw> key,
|
||||
shared_ptr<cql3::term::raw> k,
|
||||
bool by_uuid]
|
||||
shared_ptr<cql3::term::raw> k]
|
||||
|
||||
: '=' t=term
|
||||
{
|
||||
add_raw_update(operations, key, make_shared<cql3::operation::set_element>(k, t, by_uuid));
|
||||
add_raw_update(operations, key, make_shared<cql3::operation::set_element>(k, t));
|
||||
}
|
||||
;
|
||||
|
||||
@@ -1431,10 +1382,12 @@ tuple_type returns [shared_ptr<cql3::cql3_type::raw> t]
|
||||
'>' { $t = cql3::cql3_type::raw::tuple(std::move(types)); }
|
||||
;
|
||||
|
||||
#if 0
|
||||
username
|
||||
: IDENT
|
||||
| STRING_LITERAL
|
||||
;
|
||||
#endif
|
||||
|
||||
// Basically the same as cident, but we need to exlude existing CQL3 types
|
||||
// (which for some reason are not reserved otherwise)
|
||||
@@ -1613,8 +1566,6 @@ K_OR: O R;
|
||||
K_REPLACE: R E P L A C E;
|
||||
K_DETERMINISTIC: D E T E R M I N I S T I C;
|
||||
|
||||
K_SCYLLA_TIMEUUID_LIST_INDEX: S C Y L L A '_' T I M E U U I D '_' L I S T '_' I N D E X;
|
||||
|
||||
// Case-insensitive alpha characters
|
||||
fragment A: ('a'|'A');
|
||||
fragment B: ('b'|'B');
|
||||
@@ -1660,17 +1611,20 @@ STRING_LITERAL
|
||||
setText(txt);
|
||||
}
|
||||
:
|
||||
// FIXME:
|
||||
#if 0
|
||||
/* pg-style string literal */
|
||||
(
|
||||
'$' '$'
|
||||
(
|
||||
(c=~('$') { txt.push_back(c); })
|
||||
|
|
||||
('$' (c=~('$') { txt.push_back('$'); txt.push_back(c); }))
|
||||
'\$' '\$'
|
||||
( /* collect all input until '$$' is reached again */
|
||||
{ (input.size() - input.index() > 1)
|
||||
&& !"$$".equals(input.substring(input.index(), input.index() + 1)) }?
|
||||
=> c=. { txt.appendCodePoint(c); }
|
||||
)*
|
||||
'$' '$'
|
||||
'\$' '\$'
|
||||
)
|
||||
|
|
||||
#endif
|
||||
/* conventional quoted string literal */
|
||||
(
|
||||
'\'' (c=~('\'') { txt.push_back(c);} | '\'' '\'' { txt.push_back('\''); })* '\''
|
||||
|
||||
@@ -17,9 +17,9 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2015 ScyllaDB
|
||||
* Copyright 2015 Cloudius Systems
|
||||
*
|
||||
* Modified by ScyllaDB
|
||||
* Modified by Cloudius Systems
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
@@ -17,9 +17,9 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2015 ScyllaDB
|
||||
* Copyright 2015 Cloudius Systems
|
||||
*
|
||||
* Modified by ScyllaDB
|
||||
* Modified by Cloudius Systems
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
@@ -17,9 +17,9 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2014 ScyllaDB
|
||||
* Copyright 2014 Cloudius Systems
|
||||
*
|
||||
* Modified by ScyllaDB
|
||||
* Modified by Cloudius Systems
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
@@ -17,9 +17,9 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2015 ScyllaDB
|
||||
* Copyright 2015 Cloudius Systems
|
||||
*
|
||||
* Modified by ScyllaDB
|
||||
* Modified by Cloudius Systems
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
@@ -17,9 +17,9 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2015 ScyllaDB
|
||||
* Copyright 2015 Cloudius Systems
|
||||
*
|
||||
* Modified by ScyllaDB
|
||||
* Modified by Cloudius Systems
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
@@ -17,9 +17,9 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2015 ScyllaDB
|
||||
* Copyright 2015 Cloudius Systems
|
||||
*
|
||||
* Modified by ScyllaDB
|
||||
* Modified by Cloudius Systems
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
@@ -17,9 +17,9 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2015 ScyllaDB
|
||||
* Copyright 2015 Cloudius Systems
|
||||
*
|
||||
* Modified by ScyllaDB
|
||||
* Modified by Cloudius Systems
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
@@ -17,9 +17,9 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2015 ScyllaDB
|
||||
* Copyright 2015 Cloudius Systems
|
||||
*
|
||||
* Modified by ScyllaDB
|
||||
* Modified by Cloudius Systems
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
@@ -17,9 +17,9 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2015 ScyllaDB
|
||||
* Copyright 2015 Cloudius Systems
|
||||
*
|
||||
* Modified by ScyllaDB
|
||||
* Modified by Cloudius Systems
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -737,7 +737,7 @@ public:
|
||||
/** A condition on a collection element. For example: "IF col['key'] = 'foo'" */
|
||||
static ::shared_ptr<raw> collection_condition(::shared_ptr<term::raw> value, ::shared_ptr<term::raw> collection_element,
|
||||
const operator_type& op) {
|
||||
return ::make_shared<raw>(std::move(value), std::vector<::shared_ptr<term::raw>>{}, ::shared_ptr<abstract_marker::in_raw>{}, std::move(collection_element), op);
|
||||
return ::make_shared<raw>(std::move(value), std::vector<::shared_ptr<term::raw>>{}, ::shared_ptr<abstract_marker::in_raw>{}, std::move(collection_element), operator_type::IN);
|
||||
}
|
||||
|
||||
/** An IN condition on a collection element. For example: "IF col['key'] IN ('foo', 'bar', ...)" */
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2015 ScyllaDB
|
||||
* Copyright 2015 Cloudius Systems
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -121,7 +121,3 @@ column_identifier::new_selector_factory(database& db, schema_ptr schema, std::ve
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool cql3::column_identifier::text_comparator::operator()(const cql3::column_identifier& c1, const cql3::column_identifier& c2) const {
|
||||
return c1.text() < c2.text();
|
||||
}
|
||||
|
||||
@@ -17,9 +17,9 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2015 ScyllaDB
|
||||
* Copyright 2015 Cloudius Systems
|
||||
*
|
||||
* Modified by ScyllaDB
|
||||
* Modified by Cloudius Systems
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -61,11 +61,6 @@ public:
|
||||
private:
|
||||
sstring _text;
|
||||
public:
|
||||
// less comparator sorting by text
|
||||
struct text_comparator {
|
||||
bool operator()(const column_identifier& c1, const column_identifier& c2) const;
|
||||
};
|
||||
|
||||
column_identifier(sstring raw_text, bool keep_case);
|
||||
|
||||
column_identifier(bytes bytes_, data_type type);
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2016 ScyllaDB
|
||||
*
|
||||
* Modified by ScyllaDB
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is part of Scylla.
|
||||
*
|
||||
* Scylla is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Scylla is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Scylla. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "cql3/column_specification.hh"
|
||||
|
||||
namespace cql3 {
|
||||
|
||||
bool column_specification::all_in_same_table(const std::vector<::shared_ptr<column_specification>>& names)
|
||||
{
|
||||
assert(!names.empty());
|
||||
|
||||
auto first = names.front();
|
||||
return std::all_of(std::next(names.begin()), names.end(), [first] (auto&& spec) {
|
||||
return spec->ks_name == first->ks_name && spec->cf_name == first->cf_name;
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -17,9 +17,9 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2015 ScyllaDB
|
||||
* Copyright 2015 Cloudius Systems
|
||||
*
|
||||
* Modified by ScyllaDB
|
||||
* Modified by Cloudius Systems
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -75,8 +75,6 @@ public:
|
||||
bool is_reversed_type() const {
|
||||
return ::dynamic_pointer_cast<const reversed_type_impl>(type) != nullptr;
|
||||
}
|
||||
|
||||
static bool all_in_same_table(const std::vector<::shared_ptr<column_specification>>& names);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -17,9 +17,9 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2015 ScyllaDB
|
||||
* Copyright 2015 Cloudius Systems
|
||||
*
|
||||
* Modified by ScyllaDB
|
||||
* Modified by Cloudius Systems
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user