Compare commits
12 Commits
branch-0.1
...
branch-0.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d3a05737f7 | ||
|
|
21c68d3da9 | ||
|
|
88d544ed14 | ||
|
|
638c0c0ea8 | ||
|
|
f3e96e0f0b | ||
|
|
fa15440665 | ||
|
|
c4d66a3beb | ||
|
|
5023f9bbab | ||
|
|
3efc145562 | ||
|
|
1ad638f8bf | ||
|
|
43f4a8031d | ||
|
|
27dbbe1ca4 |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -5,6 +5,3 @@ build
|
||||
build.ninja
|
||||
cscope.*
|
||||
/debian/
|
||||
dist/ami/files/*.rpm
|
||||
dist/ami/variables.json
|
||||
dist/ami/scylla_deploy.sh
|
||||
|
||||
@@ -15,13 +15,13 @@ 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
|
||||
sudo yum install yaml-cpp-devel lz4-devel zlib-devel snappy-devel jsoncpp-devel thrift-devel antlr3-tool antlr3-C++-devel libasan libubsan
|
||||
```
|
||||
|
||||
* Build Scylla
|
||||
```
|
||||
./configure.py --mode=release --with=scylla --disable-xen
|
||||
ninja-build build/release/scylla -j2 # you can use more cpus if you have tons of RAM
|
||||
ninja build/release/scylla -j2 # you can use more cpus if you have tons of RAM
|
||||
|
||||
```
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/bin/sh
|
||||
|
||||
VERSION=0.16
|
||||
VERSION=0.14.1
|
||||
|
||||
if test -f version
|
||||
then
|
||||
|
||||
@@ -233,28 +233,46 @@
|
||||
"verb":{
|
||||
"type":"string",
|
||||
"enum":[
|
||||
"CLIENT_ID",
|
||||
"ECHO",
|
||||
"MUTATION",
|
||||
"MUTATION_DONE",
|
||||
"READ_DATA",
|
||||
"READ_MUTATION_DATA",
|
||||
"READ_DIGEST",
|
||||
"GOSSIP_DIGEST_SYN",
|
||||
"GOSSIP_DIGEST_ACK2",
|
||||
"GOSSIP_SHUTDOWN",
|
||||
"DEFINITIONS_UPDATE",
|
||||
"TRUNCATE",
|
||||
"REPLICATION_FINISHED",
|
||||
"MIGRATION_REQUEST",
|
||||
"STREAM_INIT_MESSAGE",
|
||||
"PREPARE_MESSAGE",
|
||||
"PREPARE_DONE_MESSAGE",
|
||||
"STREAM_MUTATION",
|
||||
"STREAM_MUTATION_DONE",
|
||||
"COMPLETE_MESSAGE",
|
||||
"REPAIR_CHECKSUM_RANGE",
|
||||
"GET_SCHEMA_VERSION"
|
||||
"MUTATION",
|
||||
"BINARY",
|
||||
"READ_REPAIR",
|
||||
"READ",
|
||||
"REQUEST_RESPONSE",
|
||||
"STREAM_INITIATE",
|
||||
"STREAM_INITIATE_DONE",
|
||||
"STREAM_REPLY",
|
||||
"STREAM_REQUEST",
|
||||
"RANGE_SLICE",
|
||||
"BOOTSTRAP_TOKEN",
|
||||
"TREE_REQUEST",
|
||||
"TREE_RESPONSE",
|
||||
"JOIN",
|
||||
"GOSSIP_DIGEST_SYN",
|
||||
"GOSSIP_DIGEST_ACK",
|
||||
"GOSSIP_DIGEST_ACK2",
|
||||
"DEFINITIONS_ANNOUNCE",
|
||||
"DEFINITIONS_UPDATE",
|
||||
"TRUNCATE",
|
||||
"SCHEMA_CHECK",
|
||||
"INDEX_SCAN",
|
||||
"REPLICATION_FINISHED",
|
||||
"INTERNAL_RESPONSE",
|
||||
"COUNTER_MUTATION",
|
||||
"STREAMING_REPAIR_REQUEST",
|
||||
"STREAMING_REPAIR_RESPONSE",
|
||||
"SNAPSHOT",
|
||||
"MIGRATION_REQUEST",
|
||||
"GOSSIP_SHUTDOWN",
|
||||
"_TRACE",
|
||||
"ECHO",
|
||||
"REPAIR_MESSAGE",
|
||||
"PAXOS_PREPARE",
|
||||
"PAXOS_PROPOSE",
|
||||
"PAXOS_COMMIT",
|
||||
"PAGED_RANGE",
|
||||
"UNUSED_1",
|
||||
"UNUSED_2",
|
||||
"UNUSED_3"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -425,7 +425,7 @@
|
||||
"summary":"load value. Keys are IP addresses",
|
||||
"type":"array",
|
||||
"items":{
|
||||
"type":"map_string_double"
|
||||
"type":"double_mapper"
|
||||
},
|
||||
"nickname":"get_load_map",
|
||||
"produces":[
|
||||
@@ -2028,8 +2028,8 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"map_string_double":{
|
||||
"id":"map_string_double",
|
||||
"double_mapper":{
|
||||
"id":"double_mapper",
|
||||
"description":"A key value mapping between a string and a double",
|
||||
"properties":{
|
||||
"key":{
|
||||
|
||||
@@ -32,9 +32,9 @@ using namespace net;
|
||||
namespace api {
|
||||
|
||||
using shard_info = messaging_service::shard_info;
|
||||
using msg_addr = messaging_service::msg_addr;
|
||||
using shard_id = messaging_service::shard_id;
|
||||
|
||||
static const int32_t num_verb = static_cast<int32_t>(messaging_verb::LAST);
|
||||
static const int32_t num_verb = static_cast<int32_t>(messaging_verb::UNUSED_3) + 1;
|
||||
|
||||
std::vector<message_counter> map_to_message_counters(
|
||||
const std::unordered_map<gms::inet_address, unsigned long>& map) {
|
||||
@@ -58,7 +58,7 @@ future_json_function get_client_getter(std::function<uint64_t(const shard_info&)
|
||||
using map_type = std::unordered_map<gms::inet_address, uint64_t>;
|
||||
auto get_shard_map = [f](messaging_service& ms) {
|
||||
std::unordered_map<gms::inet_address, unsigned long> map;
|
||||
ms.foreach_client([&map, f] (const msg_addr& id, const shard_info& info) {
|
||||
ms.foreach_client([&map, f] (const shard_id& id, const shard_info& info) {
|
||||
map[id.addr] = f(info);
|
||||
});
|
||||
return map;
|
||||
@@ -124,7 +124,7 @@ void set_messaging_service(http_context& ctx, routes& r) {
|
||||
});
|
||||
|
||||
get_dropped_messages_by_ver.set(r, [](std::unique_ptr<request> req) {
|
||||
shared_ptr<std::vector<uint64_t>> map = make_shared<std::vector<uint64_t>>(num_verb);
|
||||
shared_ptr<std::vector<uint64_t>> map = make_shared<std::vector<uint64_t>>(num_verb, 0);
|
||||
|
||||
return net::get_messaging_service().map_reduce([map](const uint64_t* local_map) mutable {
|
||||
for (auto i = 0; i < num_verb; i++) {
|
||||
@@ -137,12 +137,8 @@ void set_messaging_service(http_context& ctx, routes& r) {
|
||||
for (auto i : verb_counter::verb_wrapper::all_items()) {
|
||||
verb_counter c;
|
||||
messaging_verb v = i; // for type safety we use messaging_verb values
|
||||
auto idx = static_cast<uint32_t>(v);
|
||||
if (idx >= map->size()) {
|
||||
throw std::runtime_error(sprint("verb index out of bounds: %lu, map size: %lu", idx, map->size()));
|
||||
}
|
||||
if ((*map)[idx] > 0) {
|
||||
c.count = (*map)[idx];
|
||||
if ((*map)[static_cast<int32_t>(v)] > 0) {
|
||||
c.count = (*map)[static_cast<int32_t>(v)];
|
||||
c.verb = i;
|
||||
res.push_back(c);
|
||||
}
|
||||
|
||||
@@ -169,9 +169,9 @@ void set_storage_service(http_context& ctx, routes& r) {
|
||||
|
||||
ss::get_load_map.set(r, [] (std::unique_ptr<request> req) {
|
||||
return service::get_local_storage_service().get_load_map().then([] (auto&& load_map) {
|
||||
std::vector<ss::map_string_double> res;
|
||||
std::vector<ss::double_mapper> res;
|
||||
for (auto i : load_map) {
|
||||
ss::map_string_double val;
|
||||
ss::double_mapper val;
|
||||
val.key = i.first;
|
||||
val.value = i.second;
|
||||
res.push_back(val);
|
||||
@@ -542,9 +542,10 @@ void set_storage_service(http_context& ctx, routes& r) {
|
||||
return make_ready_future<json::json_return_type>(0);
|
||||
});
|
||||
|
||||
ss::get_compaction_throughput_mb_per_sec.set(r, [&ctx](std::unique_ptr<request> req) {
|
||||
int value = ctx.db.local().get_config().compaction_throughput_mb_per_sec();
|
||||
return make_ready_future<json::json_return_type>(value);
|
||||
ss::get_compaction_throughput_mb_per_sec.set(r, [](std::unique_ptr<request> req) {
|
||||
//TBD
|
||||
unimplemented();
|
||||
return make_ready_future<json::json_return_type>(0);
|
||||
});
|
||||
|
||||
ss::set_compaction_throughput_mb_per_sec.set(r, [](std::unique_ptr<request> req) {
|
||||
|
||||
@@ -72,12 +72,11 @@ static hs::stream_state get_state(
|
||||
si.peer = boost::lexical_cast<std::string>(info.peer);
|
||||
si.session_index = info.session_index;
|
||||
si.state = info.state;
|
||||
si.connecting = si.peer;
|
||||
si.connecting = boost::lexical_cast<std::string>(info.connecting);
|
||||
set_summaries(info.receiving_summaries, si.receiving_summaries);
|
||||
set_summaries(info.sending_summaries, si.sending_summaries);
|
||||
set_files(info.receiving_files, si.receiving_files);
|
||||
set_files(info.sending_files, si.sending_files);
|
||||
state.sessions.push(si);
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
@@ -272,6 +272,45 @@ template<typename T>
|
||||
class serializer;
|
||||
}
|
||||
|
||||
// A variant type that can hold either an atomic_cell, or a serialized collection.
|
||||
// Which type is stored is determined by the schema.
|
||||
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:
|
||||
atomic_cell_or_collection() = default;
|
||||
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_or_collection(collection_mutation cm) : _data(std::move(cm.data)) {}
|
||||
explicit operator bool() const {
|
||||
return !_data.empty();
|
||||
}
|
||||
static atomic_cell_or_collection from_collection_mutation(collection_mutation data) {
|
||||
return std::move(data.data);
|
||||
}
|
||||
collection_mutation_view as_collection_mutation() const {
|
||||
return collection_mutation_view{_data};
|
||||
}
|
||||
bytes_view serialize() const {
|
||||
return _data;
|
||||
}
|
||||
bool operator==(const atomic_cell_or_collection& other) const {
|
||||
return _data == other._data;
|
||||
}
|
||||
void linearize() {
|
||||
_data.linearize();
|
||||
}
|
||||
void unlinearize() {
|
||||
_data.scatter();
|
||||
}
|
||||
friend std::ostream& operator<<(std::ostream&, const atomic_cell_or_collection&);
|
||||
};
|
||||
|
||||
class column_definition;
|
||||
|
||||
int compare_atomic_cell_for_merge(atomic_cell_view left, atomic_cell_view right);
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Cloudius Systems, Ltd.
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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
|
||||
|
||||
// Not part of atomic_cell.hh to avoid cyclic dependency between types.hh and atomic_cell.hh
|
||||
|
||||
#include "types.hh"
|
||||
#include "atomic_cell.hh"
|
||||
#include "hashing.hh"
|
||||
|
||||
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> {
|
||||
template<typename Hasher>
|
||||
void operator()(Hasher& h, atomic_cell_view cell) const {
|
||||
feed_hash(h, cell.is_live());
|
||||
feed_hash(h, cell.timestamp());
|
||||
if (cell.is_live()) {
|
||||
if (cell.is_live_and_has_ttl()) {
|
||||
feed_hash(h, cell.expiry());
|
||||
feed_hash(h, cell.ttl());
|
||||
}
|
||||
feed_hash(h, cell.value());
|
||||
} else {
|
||||
feed_hash(h, cell.deletion_time());
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -1,73 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Cloudius Systems, Ltd.
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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 "atomic_cell.hh"
|
||||
#include "schema.hh"
|
||||
#include "hashing.hh"
|
||||
|
||||
// A variant type that can hold either an atomic_cell, or a serialized collection.
|
||||
// Which type is stored is determined by the schema.
|
||||
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:
|
||||
atomic_cell_or_collection() = default;
|
||||
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_or_collection(collection_mutation cm) : _data(std::move(cm.data)) {}
|
||||
explicit operator bool() const {
|
||||
return !_data.empty();
|
||||
}
|
||||
static atomic_cell_or_collection from_collection_mutation(collection_mutation data) {
|
||||
return std::move(data.data);
|
||||
}
|
||||
collection_mutation_view as_collection_mutation() const {
|
||||
return collection_mutation_view{_data};
|
||||
}
|
||||
bytes_view serialize() const {
|
||||
return _data;
|
||||
}
|
||||
bool operator==(const atomic_cell_or_collection& other) const {
|
||||
return _data == other._data;
|
||||
}
|
||||
template<typename Hasher>
|
||||
void feed_hash(Hasher& h, const column_definition& def) const {
|
||||
if (def.is_atomic()) {
|
||||
::feed_hash(h, as_atomic_cell());
|
||||
} else {
|
||||
::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&);
|
||||
};
|
||||
236
auth/auth.cc
236
auth/auth.cc
@@ -1,236 +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 2016 Cloudius Systems
|
||||
*
|
||||
* Modified by Cloudius Systems
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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 <seastar/core/sleep.hh>
|
||||
|
||||
#include "auth.hh"
|
||||
#include "authenticator.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"
|
||||
|
||||
const sstring auth::auth::DEFAULT_SUPERUSER_NAME("cassandra");
|
||||
const sstring auth::auth::AUTH_KS("system_auth");
|
||||
const sstring auth::auth::USERS_CF("users");
|
||||
|
||||
static const sstring USER_NAME("name");
|
||||
static const sstring SUPER("super");
|
||||
|
||||
static logging::logger logger("auth");
|
||||
|
||||
// TODO: configurable
|
||||
using namespace std::chrono_literals;
|
||||
const std::chrono::milliseconds auth::auth::SUPERUSER_SETUP_DELAY = 10000ms;
|
||||
|
||||
class auth_migration_listener : public service::migration_listener {
|
||||
void on_create_keyspace(const sstring& ks_name) override {}
|
||||
void on_create_column_family(const sstring& ks_name, const sstring& cf_name) override {}
|
||||
void on_create_user_type(const sstring& ks_name, const sstring& type_name) override {}
|
||||
void on_create_function(const sstring& ks_name, const sstring& function_name) override {}
|
||||
void on_create_aggregate(const sstring& ks_name, const sstring& aggregate_name) override {}
|
||||
|
||||
void on_update_keyspace(const sstring& ks_name) override {}
|
||||
void on_update_column_family(const sstring& ks_name, const sstring& cf_name, bool) override {}
|
||||
void on_update_user_type(const sstring& ks_name, const sstring& type_name) override {}
|
||||
void on_update_function(const sstring& ks_name, const sstring& function_name) override {}
|
||||
void on_update_aggregate(const sstring& ks_name, const sstring& aggregate_name) override {}
|
||||
|
||||
void on_drop_keyspace(const sstring& ks_name) override {
|
||||
// TODO:
|
||||
//DatabaseDescriptor.getAuthorizer().revokeAll(DataResource.keyspace(ksName));
|
||||
|
||||
}
|
||||
void on_drop_column_family(const sstring& ks_name, const sstring& cf_name) override {
|
||||
// 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 {}
|
||||
void on_drop_aggregate(const sstring& ks_name, const sstring& aggregate_name) override {}
|
||||
};
|
||||
|
||||
static auth_migration_listener auth_migration;
|
||||
|
||||
bool auth::auth::is_class_type(const sstring& type, const sstring& classname) {
|
||||
if (type == classname) {
|
||||
return true;
|
||||
}
|
||||
auto i = classname.find_last_of('.');
|
||||
return classname.compare(i + 1, sstring::npos, type) == 0;
|
||||
}
|
||||
|
||||
future<> auth::auth::setup() {
|
||||
auto& db = cql3::get_local_query_processor().db().local();
|
||||
auto& cfg = db.get_config();
|
||||
auto type = cfg.authenticator();
|
||||
|
||||
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";
|
||||
auto ksm = keyspace_metadata::new_keyspace(AUTH_KS, "org.apache.cassandra.locator.SimpleStrategy", opts, true);
|
||||
f = service::get_local_migration_manager().announce_new_keyspace(ksm, false);
|
||||
}
|
||||
|
||||
return f.then([] {
|
||||
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([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
|
||||
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) {
|
||||
auto query = sprint("INSERT INTO %s.%s (%s, %s) VALUES (?, ?) USING TIMESTAMP 0",
|
||||
AUTH_KS, USERS_CF, USER_NAME, SUPER);
|
||||
cql3::get_local_query_processor().process(query, db::consistency_level::ONE, {DEFAULT_SUPERUSER_NAME, true}).then([](auto) {
|
||||
logger.info("Created default superuser '{}'", DEFAULT_SUPERUSER_NAME);
|
||||
}).handle_exception([](auto ep) {
|
||||
try {
|
||||
std::rethrow_exception(ep);
|
||||
} catch (exceptions::request_execution_exception&) {
|
||||
logger.warn("Skipped default superuser setup: some nodes were not ready");
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
static db::consistency_level consistency_for_user(const sstring& username) {
|
||||
if (username == auth::auth::DEFAULT_SUPERUSER_NAME) {
|
||||
return db::consistency_level::QUORUM;
|
||||
}
|
||||
return db::consistency_level::LOCAL_ONE;
|
||||
}
|
||||
|
||||
static future<::shared_ptr<cql3::untyped_result_set>> select_user(const sstring& username) {
|
||||
// Here was a thread local, explicit cache of prepared statement. In normal execution this is
|
||||
// fine, but since we in testing set up and tear down system over and over, we'd start using
|
||||
// obsolete prepared statements pretty quickly.
|
||||
// Rely on query processing caching statements instead, and lets assume
|
||||
// that a map lookup string->statement is not gonna kill us much.
|
||||
return cql3::get_local_query_processor().process(
|
||||
sprint("SELECT * FROM %s.%s WHERE %s = ?",
|
||||
auth::auth::AUTH_KS, auth::auth::USERS_CF,
|
||||
USER_NAME), consistency_for_user(username),
|
||||
{ username }, true);
|
||||
}
|
||||
|
||||
future<bool> auth::auth::is_existing_user(const sstring& username) {
|
||||
return select_user(username).then(
|
||||
[](::shared_ptr<cql3::untyped_result_set> res) {
|
||||
return make_ready_future<bool>(!res->empty());
|
||||
});
|
||||
}
|
||||
|
||||
future<bool> auth::auth::is_super_user(const sstring& username) {
|
||||
return select_user(username).then(
|
||||
[](::shared_ptr<cql3::untyped_result_set> res) {
|
||||
return make_ready_future<bool>(!res->empty() && res->one().get_as<bool>(SUPER));
|
||||
});
|
||||
}
|
||||
|
||||
future<> auth::auth::insert_user(const sstring& username, bool is_super)
|
||||
throw (exceptions::request_execution_exception) {
|
||||
return cql3::get_local_query_processor().process(sprint("INSERT INTO %s.%s (%s, %s) VALUES (?, ?)",
|
||||
AUTH_KS, USERS_CF, USER_NAME, SUPER),
|
||||
consistency_for_user(username), { username, is_super }).discard_result();
|
||||
}
|
||||
|
||||
future<> auth::auth::delete_user(const sstring& username) throw(exceptions::request_execution_exception) {
|
||||
return cql3::get_local_query_processor().process(sprint("DELETE FROM %s.%s WHERE %s = ?",
|
||||
AUTH_KS, USERS_CF, USER_NAME),
|
||||
consistency_for_user(username), { username }).discard_result();
|
||||
}
|
||||
|
||||
future<> auth::auth::setup_table(const sstring& name, const sstring& cql) {
|
||||
auto& qp = cql3::get_local_query_processor();
|
||||
auto& db = qp.db().local();
|
||||
|
||||
if (db.has_schema(AUTH_KS, name)) {
|
||||
return make_ready_future();
|
||||
}
|
||||
|
||||
::shared_ptr<cql3::statements::cf_statement> parsed = static_pointer_cast<
|
||||
cql3::statements::cf_statement>(cql3::query_processor::parse_statement(cql));
|
||||
parsed->prepare_keyspace(AUTH_KS);
|
||||
::shared_ptr<cql3::statements::create_table_statement> statement =
|
||||
static_pointer_cast<cql3::statements::create_table_statement>(
|
||||
parsed->prepare(db)->statement);
|
||||
// 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) {
|
||||
auto default_user_query = sprint("SELECT * FROM %s.%s WHERE %s = ?", AUTH_KS, cfname, name_column);
|
||||
auto all_users_query = sprint("SELECT * FROM %s.%s LIMIT 1", AUTH_KS, cfname);
|
||||
|
||||
return cql3::get_local_query_processor().process(default_user_query, db::consistency_level::ONE, { def_user_name }).then([=](::shared_ptr<cql3::untyped_result_set> res) {
|
||||
if (!res->empty()) {
|
||||
return make_ready_future<bool>(true);
|
||||
}
|
||||
return cql3::get_local_query_processor().process(default_user_query, db::consistency_level::QUORUM, { def_user_name }).then([all_users_query](::shared_ptr<cql3::untyped_result_set> res) {
|
||||
if (!res->empty()) {
|
||||
return make_ready_future<bool>(true);
|
||||
}
|
||||
return cql3::get_local_query_processor().process(all_users_query, db::consistency_level::QUORUM).then([](::shared_ptr<cql3::untyped_result_set> res) {
|
||||
return make_ready_future<bool>(!res->empty());
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
116
auth/auth.hh
116
auth/auth.hh
@@ -1,116 +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 2016 Cloudius Systems
|
||||
*
|
||||
* Modified by Cloudius Systems
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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 <chrono>
|
||||
#include <seastar/core/sstring.hh>
|
||||
#include <seastar/core/future.hh>
|
||||
|
||||
#include "exceptions/exceptions.hh"
|
||||
|
||||
namespace auth {
|
||||
|
||||
class auth {
|
||||
public:
|
||||
static const sstring DEFAULT_SUPERUSER_NAME;
|
||||
static const sstring AUTH_KS;
|
||||
static const sstring USERS_CF;
|
||||
static const std::chrono::milliseconds SUPERUSER_SETUP_DELAY;
|
||||
|
||||
static bool is_class_type(const sstring& type, const sstring& classname);
|
||||
|
||||
#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.
|
||||
*
|
||||
* @param username Username to query.
|
||||
* @return whether or not Cassandra knows about the user.
|
||||
*/
|
||||
static future<bool> is_existing_user(const sstring& username);
|
||||
|
||||
/**
|
||||
* Checks if the user is a known superuser.
|
||||
*
|
||||
* @param username Username to query.
|
||||
* @return true is the user is a superuser, false if they aren't or don't exist at all.
|
||||
*/
|
||||
static future<bool> is_super_user(const sstring& username);
|
||||
|
||||
/**
|
||||
* Inserts the user into AUTH_KS.USERS_CF (or overwrites their superuser status as a result of an ALTER USER query).
|
||||
*
|
||||
* @param username Username to insert.
|
||||
* @param isSuper User's new status.
|
||||
* @throws RequestExecutionException
|
||||
*/
|
||||
static future<> insert_user(const sstring& username, bool is_super) throw(exceptions::request_execution_exception);
|
||||
|
||||
/**
|
||||
* Deletes the user from AUTH_KS.USERS_CF.
|
||||
*
|
||||
* @param username Username to delete.
|
||||
* @throws RequestExecutionException
|
||||
*/
|
||||
static future<> delete_user(const sstring& username) throw(exceptions::request_execution_exception);
|
||||
|
||||
/**
|
||||
* Sets up Authenticator and Authorizer.
|
||||
*/
|
||||
static future<> setup();
|
||||
|
||||
/**
|
||||
* Set up table from given CREATE TABLE statement under system_auth keyspace, if not already done so.
|
||||
*
|
||||
* @param name name of the table
|
||||
* @param cql CREATE TABLE statement
|
||||
*/
|
||||
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);
|
||||
};
|
||||
}
|
||||
@@ -1,61 +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 2016 Cloudius Systems
|
||||
*
|
||||
* Modified by Cloudius Systems
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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 "authenticated_user.hh"
|
||||
|
||||
const sstring auth::authenticated_user::ANONYMOUS_USERNAME("anonymous");
|
||||
|
||||
auth::authenticated_user::authenticated_user()
|
||||
: _anon(true)
|
||||
{}
|
||||
|
||||
auth::authenticated_user::authenticated_user(sstring name)
|
||||
: _name(name), _anon(false)
|
||||
{}
|
||||
|
||||
const sstring& auth::authenticated_user::name() const {
|
||||
return _anon ? ANONYMOUS_USERNAME : _name;
|
||||
}
|
||||
|
||||
bool auth::authenticated_user::operator==(const authenticated_user& v) const {
|
||||
return _anon ? v._anon : _name == v._name;
|
||||
}
|
||||
@@ -1,79 +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 2016 Cloudius Systems
|
||||
*
|
||||
* Modified by Cloudius Systems
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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/sstring.hh>
|
||||
|
||||
namespace auth {
|
||||
|
||||
class authenticated_user {
|
||||
public:
|
||||
static const sstring ANONYMOUS_USERNAME;
|
||||
|
||||
authenticated_user();
|
||||
authenticated_user(sstring name);
|
||||
|
||||
const sstring& name() const;
|
||||
|
||||
/**
|
||||
* Checks the user's superuser status.
|
||||
* Only a superuser is allowed to perform CREATE USER and DROP USER queries.
|
||||
* Im most cased, though not necessarily, a superuser will have Permission.ALL on every resource
|
||||
* (depends on IAuthorizer implementation).
|
||||
*/
|
||||
bool is_super() const;
|
||||
|
||||
/**
|
||||
* If IAuthenticator doesn't require authentication, this method may return true.
|
||||
*/
|
||||
bool is_anonymous() const {
|
||||
return _anon;
|
||||
}
|
||||
|
||||
bool operator==(const authenticated_user&) const;
|
||||
private:
|
||||
sstring _name;
|
||||
bool _anon;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -1,110 +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 2016 Cloudius Systems
|
||||
*
|
||||
* Modified by Cloudius Systems
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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 "authenticator.hh"
|
||||
#include "authenticated_user.hh"
|
||||
#include "password_authenticator.hh"
|
||||
#include "auth.hh"
|
||||
#include "db/config.hh"
|
||||
|
||||
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");
|
||||
|
||||
/**
|
||||
* 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::authenticator> global_authenticator;
|
||||
|
||||
future<>
|
||||
auth::authenticator::setup(const sstring& type) throw (exceptions::configuration_exception) {
|
||||
if (auth::auth::is_class_type(type, ALLOW_ALL_AUTHENTICATOR_NAME)) {
|
||||
class allow_all_authenticator : public authenticator {
|
||||
public:
|
||||
const sstring& class_name() const override {
|
||||
return ALLOW_ALL_AUTHENTICATOR_NAME;
|
||||
}
|
||||
bool require_authentication() const override {
|
||||
return false;
|
||||
}
|
||||
option_set supported_options() const override {
|
||||
return option_set();
|
||||
}
|
||||
option_set alterable_options() const override {
|
||||
return option_set();
|
||||
}
|
||||
future<::shared_ptr<authenticated_user>> authenticate(const credentials_map& credentials) const throw(exceptions::authentication_exception) override {
|
||||
return make_ready_future<::shared_ptr<authenticated_user>>(::make_shared<authenticated_user>());
|
||||
}
|
||||
future<> create(sstring username, const option_map& options) throw(exceptions::request_validation_exception, exceptions::request_execution_exception) override {
|
||||
return make_ready_future();
|
||||
}
|
||||
future<> alter(sstring username, const option_map& options) throw(exceptions::request_validation_exception, exceptions::request_execution_exception) override {
|
||||
return make_ready_future();
|
||||
}
|
||||
future<> drop(sstring username) throw(exceptions::request_validation_exception, exceptions::request_execution_exception) override {
|
||||
return make_ready_future();
|
||||
}
|
||||
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");
|
||||
}
|
||||
};
|
||||
global_authenticator = std::make_unique<allow_all_authenticator>();
|
||||
} else if (auth::auth::is_class_type(type, password_authenticator::PASSWORD_AUTHENTICATOR_NAME)) {
|
||||
auto pwa = std::make_unique<password_authenticator>();
|
||||
auto f = pwa->init();
|
||||
return f.then([pwa = std::move(pwa)]() mutable {
|
||||
global_authenticator = std::move(pwa);
|
||||
});
|
||||
} else {
|
||||
throw exceptions::configuration_exception("Invalid authenticator type: " + type);
|
||||
}
|
||||
return make_ready_future();
|
||||
}
|
||||
|
||||
auth::authenticator& auth::authenticator::get() {
|
||||
assert(global_authenticator);
|
||||
return *global_authenticator;
|
||||
}
|
||||
@@ -1,198 +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 2016 Cloudius Systems
|
||||
*
|
||||
* Modified by Cloudius Systems
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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 <memory>
|
||||
#include <unordered_map>
|
||||
#include <set>
|
||||
#include <stdexcept>
|
||||
#include <boost/any.hpp>
|
||||
|
||||
#include <seastar/core/sstring.hh>
|
||||
#include <seastar/core/future.hh>
|
||||
#include <seastar/core/shared_ptr.hh>
|
||||
#include <seastar/core/enum.hh>
|
||||
|
||||
#include "bytes.hh"
|
||||
#include "data_resource.hh"
|
||||
#include "enum_set.hh"
|
||||
#include "exceptions/exceptions.hh"
|
||||
|
||||
namespace db {
|
||||
class config;
|
||||
}
|
||||
|
||||
namespace auth {
|
||||
|
||||
class authenticated_user;
|
||||
|
||||
class authenticator {
|
||||
public:
|
||||
static const sstring USERNAME_KEY;
|
||||
static const sstring PASSWORD_KEY;
|
||||
static const sstring ALLOW_ALL_AUTHENTICATOR_NAME;
|
||||
|
||||
/**
|
||||
* Supported CREATE USER/ALTER USER options.
|
||||
* Currently only PASSWORD is available.
|
||||
*/
|
||||
enum class option {
|
||||
PASSWORD
|
||||
};
|
||||
|
||||
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.
|
||||
*
|
||||
* For example, use this method to create any required keyspaces/column families.
|
||||
* Note: Only call from main thread.
|
||||
*/
|
||||
static future<> setup(const sstring& type) throw(exceptions::configuration_exception);
|
||||
|
||||
/**
|
||||
* Returns the system authenticator. Must have called setup before calling this.
|
||||
*/
|
||||
static authenticator& get();
|
||||
|
||||
virtual ~authenticator()
|
||||
{}
|
||||
|
||||
virtual const sstring& class_name() const = 0;
|
||||
|
||||
/**
|
||||
* Whether or not the authenticator requires explicit login.
|
||||
* If false will instantiate user with AuthenticatedUser.ANONYMOUS_USER.
|
||||
*/
|
||||
virtual bool require_authentication() const = 0;
|
||||
|
||||
/**
|
||||
* Set of options supported by CREATE USER and ALTER USER queries.
|
||||
* Should never return null - always return an empty set instead.
|
||||
*/
|
||||
virtual option_set supported_options() const = 0;
|
||||
|
||||
/**
|
||||
* Subset of supportedOptions that users are allowed to alter when performing ALTER USER [themselves].
|
||||
* Should never return null - always return an empty set instead.
|
||||
*/
|
||||
virtual option_set alterable_options() const = 0;
|
||||
|
||||
/**
|
||||
* Authenticates a user given a Map<String, String> of credentials.
|
||||
* Should never return null - always throw AuthenticationException instead.
|
||||
* Returning AuthenticatedUser.ANONYMOUS_USER is an option as well if authentication is not required.
|
||||
*
|
||||
* @throws authentication_exception if credentials don't match any known user.
|
||||
*/
|
||||
virtual future<::shared_ptr<authenticated_user>> authenticate(const credentials_map& credentials) const throw(exceptions::authentication_exception) = 0;
|
||||
|
||||
/**
|
||||
* Called during execution of CREATE USER query (also may be called on startup, see seedSuperuserOptions method).
|
||||
* If authenticator is static then the body of the method should be left blank, but don't throw an exception.
|
||||
* options are guaranteed to be a subset of supportedOptions().
|
||||
*
|
||||
* @param username Username of the user to create.
|
||||
* @param options Options the user will be created with.
|
||||
* @throws exceptions::request_validation_exception
|
||||
* @throws exceptions::request_execution_exception
|
||||
*/
|
||||
virtual future<> create(sstring username, const option_map& options) throw(exceptions::request_validation_exception, exceptions::request_execution_exception) = 0;
|
||||
|
||||
/**
|
||||
* Called during execution of ALTER USER query.
|
||||
* options are always guaranteed to be a subset of supportedOptions(). Furthermore, if the user performing the query
|
||||
* is not a superuser and is altering himself, then options are guaranteed to be a subset of alterableOptions().
|
||||
* Keep the body of the method blank if your implementation doesn't support any options.
|
||||
*
|
||||
* @param username Username of the user that will be altered.
|
||||
* @param options Options to alter.
|
||||
* @throws exceptions::request_validation_exception
|
||||
* @throws exceptions::request_execution_exception
|
||||
*/
|
||||
virtual future<> alter(sstring username, const option_map& options) throw(exceptions::request_validation_exception, exceptions::request_execution_exception) = 0;
|
||||
|
||||
|
||||
/**
|
||||
* Called during execution of DROP USER query.
|
||||
*
|
||||
* @param username Username of the user that will be dropped.
|
||||
* @throws exceptions::request_validation_exception
|
||||
* @throws exceptions::request_execution_exception
|
||||
*/
|
||||
virtual future<> drop(sstring username) throw(exceptions::request_validation_exception, exceptions::request_execution_exception) = 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.
|
||||
* @see resource_ids
|
||||
*/
|
||||
virtual resource_ids protected_resources() const = 0;
|
||||
|
||||
class sasl_challenge {
|
||||
public:
|
||||
virtual ~sasl_challenge() {}
|
||||
virtual bytes evaluate_response(bytes_view client_response) throw(exceptions::authentication_exception) = 0;
|
||||
virtual bool is_complete() const = 0;
|
||||
virtual future<::shared_ptr<authenticated_user>> get_authenticated_user() const throw(exceptions::authentication_exception) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Provide a sasl_challenge to be used by the CQL binary protocol server. If
|
||||
* the configured authenticator requires authentication but does not implement this
|
||||
* interface we refuse to start the binary protocol server as it will have no way
|
||||
* of authenticating clients.
|
||||
* @return sasl_challenge implementation
|
||||
*/
|
||||
virtual ::shared_ptr<sasl_challenge> new_sasl_challenge() const = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -1,175 +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 2016 Cloudius Systems
|
||||
*
|
||||
* Modified by Cloudius Systems
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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 "data_resource.hh"
|
||||
|
||||
#include <regex>
|
||||
#include "service/storage_proxy.hh"
|
||||
|
||||
const sstring auth::data_resource::ROOT_NAME("data");
|
||||
|
||||
auth::data_resource::data_resource(level l, const sstring& ks, const sstring& cf)
|
||||
: _ks(ks), _cf(cf)
|
||||
{
|
||||
if (l != get_level()) {
|
||||
throw std::invalid_argument("level/keyspace/column mismatch");
|
||||
}
|
||||
}
|
||||
|
||||
auth::data_resource::data_resource()
|
||||
: data_resource(level::ROOT)
|
||||
{}
|
||||
|
||||
auth::data_resource::data_resource(const sstring& ks)
|
||||
: data_resource(level::KEYSPACE, ks)
|
||||
{}
|
||||
|
||||
auth::data_resource::data_resource(const sstring& ks, const sstring& cf)
|
||||
: data_resource(level::COLUMN_FAMILY, ks, cf)
|
||||
{}
|
||||
|
||||
auth::data_resource::level auth::data_resource::get_level() const {
|
||||
if (!_cf.empty()) {
|
||||
assert(!_ks.empty());
|
||||
return level::COLUMN_FAMILY;
|
||||
}
|
||||
if (!_ks.empty()) {
|
||||
return level::KEYSPACE;
|
||||
}
|
||||
return level::ROOT;
|
||||
}
|
||||
|
||||
auth::data_resource auth::data_resource::from_name(
|
||||
const sstring& s) {
|
||||
|
||||
static std::regex slash_regex("/");
|
||||
|
||||
auto i = std::regex_token_iterator<sstring::const_iterator>(s.begin(),
|
||||
s.end(), slash_regex, -1);
|
||||
auto e = std::regex_token_iterator<sstring::const_iterator>();
|
||||
auto n = std::distance(i, e);
|
||||
|
||||
if (n > 3 || ROOT_NAME != sstring(*i++)) {
|
||||
throw std::invalid_argument(sprint("%s is not a valid data resource name", s));
|
||||
}
|
||||
|
||||
if (n == 1) {
|
||||
return data_resource();
|
||||
}
|
||||
auto ks = *i++;
|
||||
if (n == 2) {
|
||||
return data_resource(ks.str());
|
||||
}
|
||||
auto cf = *i++;
|
||||
return data_resource(ks.str(), cf.str());
|
||||
}
|
||||
|
||||
sstring auth::data_resource::name() const {
|
||||
switch (get_level()) {
|
||||
case level::ROOT:
|
||||
return ROOT_NAME;
|
||||
case level::KEYSPACE:
|
||||
return sprint("%s/%s", ROOT_NAME, _ks);
|
||||
case level::COLUMN_FAMILY:
|
||||
default:
|
||||
return sprint("%s/%s/%s", ROOT_NAME, _ks, _cf);
|
||||
}
|
||||
}
|
||||
|
||||
auth::data_resource auth::data_resource::get_parent() const {
|
||||
switch (get_level()) {
|
||||
case level::KEYSPACE:
|
||||
return data_resource();
|
||||
case level::COLUMN_FAMILY:
|
||||
return data_resource(_ks);
|
||||
default:
|
||||
throw std::invalid_argument("Root-level resource can't have a parent");
|
||||
}
|
||||
}
|
||||
|
||||
const sstring& auth::data_resource::keyspace() const
|
||||
throw (std::invalid_argument) {
|
||||
if (is_root_level()) {
|
||||
throw std::invalid_argument("ROOT data resource has no keyspace");
|
||||
}
|
||||
return _ks;
|
||||
}
|
||||
|
||||
const sstring& auth::data_resource::column_family() const
|
||||
throw (std::invalid_argument) {
|
||||
if (!is_column_family_level()) {
|
||||
throw std::invalid_argument(sprint("%s data resource has no column family", name()));
|
||||
}
|
||||
return _cf;
|
||||
}
|
||||
|
||||
bool auth::data_resource::has_parent() const {
|
||||
return !is_root_level();
|
||||
}
|
||||
|
||||
bool auth::data_resource::exists() const {
|
||||
switch (get_level()) {
|
||||
case level::ROOT:
|
||||
return true;
|
||||
case level::KEYSPACE:
|
||||
return service::get_local_storage_proxy().get_db().local().has_keyspace(_ks);
|
||||
case level::COLUMN_FAMILY:
|
||||
default:
|
||||
return service::get_local_storage_proxy().get_db().local().has_schema(_ks, _cf);
|
||||
}
|
||||
}
|
||||
|
||||
sstring auth::data_resource::to_string() const {
|
||||
return name();
|
||||
}
|
||||
|
||||
bool auth::data_resource::operator==(const data_resource& v) const {
|
||||
return _ks == v._ks && _cf == v._cf;
|
||||
}
|
||||
|
||||
bool auth::data_resource::operator<(const data_resource& v) const {
|
||||
return _ks < v._ks ? true : (v._ks < _ks ? false : _cf < v._cf);
|
||||
}
|
||||
|
||||
std::ostream& auth::operator<<(std::ostream& os, const data_resource& r) {
|
||||
return os << r.name();
|
||||
}
|
||||
|
||||
@@ -1,146 +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 2016 Cloudius Systems
|
||||
*
|
||||
* Modified by Cloudius Systems
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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 <iosfwd>
|
||||
#include <seastar/core/sstring.hh>
|
||||
|
||||
namespace auth {
|
||||
|
||||
class data_resource {
|
||||
private:
|
||||
enum class level {
|
||||
ROOT, KEYSPACE, COLUMN_FAMILY
|
||||
};
|
||||
|
||||
static const sstring ROOT_NAME;
|
||||
|
||||
sstring _ks;
|
||||
sstring _cf;
|
||||
|
||||
data_resource(level, const sstring& ks = {}, const sstring& cf = {});
|
||||
|
||||
level get_level() const;
|
||||
public:
|
||||
/**
|
||||
* Creates a DataResource representing the root-level resource.
|
||||
* @return the root-level resource.
|
||||
*/
|
||||
data_resource();
|
||||
/**
|
||||
* Creates a DataResource representing a keyspace.
|
||||
*
|
||||
* @param keyspace Name of the keyspace.
|
||||
*/
|
||||
data_resource(const sstring& ks);
|
||||
/**
|
||||
* Creates a DataResource instance representing a column family.
|
||||
*
|
||||
* @param keyspace Name of the keyspace.
|
||||
* @param columnFamily Name of the column family.
|
||||
*/
|
||||
data_resource(const sstring& ks, const sstring& cf);
|
||||
|
||||
/**
|
||||
* Parses a data resource name into a DataResource instance.
|
||||
*
|
||||
* @param name Name of the data resource.
|
||||
* @return DataResource instance matching the name.
|
||||
*/
|
||||
static data_resource from_name(const sstring&);
|
||||
|
||||
/**
|
||||
* @return Printable name of the resource.
|
||||
*/
|
||||
sstring name() const;
|
||||
|
||||
/**
|
||||
* @return Parent of the resource, if any. Throws IllegalStateException if it's the root-level resource.
|
||||
*/
|
||||
data_resource get_parent() const;
|
||||
|
||||
bool is_root_level() const {
|
||||
return get_level() == level::ROOT;
|
||||
}
|
||||
|
||||
bool is_keyspace_level() const {
|
||||
return get_level() == level::KEYSPACE;
|
||||
}
|
||||
|
||||
bool is_column_family_level() const {
|
||||
return get_level() == level::COLUMN_FAMILY;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return keyspace of the resource.
|
||||
* @throws std::invalid_argument if it's the root-level resource.
|
||||
*/
|
||||
const sstring& keyspace() const throw(std::invalid_argument);
|
||||
|
||||
/**
|
||||
* @return column family of the resource.
|
||||
* @throws std::invalid_argument if it's not a cf-level resource.
|
||||
*/
|
||||
const sstring& column_family() const throw(std::invalid_argument);
|
||||
|
||||
/**
|
||||
* @return Whether or not the resource has a parent in the hierarchy.
|
||||
*/
|
||||
bool has_parent() const;
|
||||
|
||||
/**
|
||||
* @return Whether or not the resource exists in scylla.
|
||||
*/
|
||||
bool exists() const;
|
||||
|
||||
sstring to_string() const;
|
||||
|
||||
bool operator==(const data_resource&) const;
|
||||
bool operator<(const data_resource&) const;
|
||||
};
|
||||
|
||||
std::ostream& operator<<(std::ostream&, const data_resource&);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,357 +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 2016 Cloudius Systems
|
||||
*
|
||||
* Modified by Cloudius Systems
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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 "password_authenticator.hh"
|
||||
#include "authenticated_user.hh"
|
||||
#include "cql3/query_processor.hh"
|
||||
#include "log.hh"
|
||||
|
||||
const sstring auth::password_authenticator::PASSWORD_AUTHENTICATOR_NAME("org.apache.cassandra.auth.PasswordAuthenticator");
|
||||
|
||||
// name of the hash column.
|
||||
static const sstring SALTED_HASH = "salted_hash";
|
||||
static const sstring USER_NAME = "username";
|
||||
static const sstring DEFAULT_USER_NAME = auth::auth::DEFAULT_SUPERUSER_NAME;
|
||||
static const sstring DEFAULT_USER_PASSWORD = auth::auth::DEFAULT_SUPERUSER_NAME;
|
||||
static const sstring CREDENTIALS_CF = "credentials";
|
||||
|
||||
static logging::logger logger("password_authenticator");
|
||||
|
||||
auth::password_authenticator::~password_authenticator()
|
||||
{}
|
||||
|
||||
auth::password_authenticator::password_authenticator()
|
||||
{}
|
||||
|
||||
// TODO: blowfish
|
||||
// Origin uses Java bcrypt library, i.e. blowfish salt
|
||||
// generation and hashing, which is arguably a "better"
|
||||
// password hash than sha/md5 versions usually available in
|
||||
// crypt_r. Otoh, glibc 2.7+ uses a modified sha512 algo
|
||||
// which should be the same order of safe, so the only
|
||||
// real issue should be salted hash compatibility with
|
||||
// origin if importing system tables from there.
|
||||
//
|
||||
// Since bcrypt/blowfish is _not_ (afaict) not available
|
||||
// as a dev package/lib on most linux distros, we'd have to
|
||||
// copy and compile for example OWL crypto
|
||||
// (http://cvsweb.openwall.com/cgi/cvsweb.cgi/Owl/packages/glibc/crypt_blowfish/)
|
||||
// to be fully bit-compatible.
|
||||
//
|
||||
// Until we decide this is needed, let's just use crypt_r,
|
||||
// and some old-fashioned random salt generation.
|
||||
|
||||
static constexpr size_t rand_bytes = 16;
|
||||
|
||||
static sstring hashpw(const sstring& pass, const sstring& salt) {
|
||||
// crypt_data is huge. should this be a thread_local static?
|
||||
auto tmp = std::make_unique<crypt_data>();
|
||||
tmp->initialized = 0;
|
||||
auto res = crypt_r(pass.c_str(), salt.c_str(), tmp.get());
|
||||
if (res == nullptr) {
|
||||
throw std::system_error(errno, std::system_category());
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static bool checkpw(const sstring& pass, const sstring& salted_hash) {
|
||||
auto tmp = hashpw(pass, salted_hash);
|
||||
return tmp == salted_hash;
|
||||
}
|
||||
|
||||
static sstring gensalt() {
|
||||
static sstring prefix;
|
||||
|
||||
std::random_device rd;
|
||||
std::default_random_engine e1(rd());
|
||||
std::uniform_int_distribution<char> dist;
|
||||
|
||||
sstring valid_salt = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./";
|
||||
sstring input(rand_bytes, 0);
|
||||
|
||||
for (char&c : input) {
|
||||
c = valid_salt[dist(e1) % valid_salt.size()];
|
||||
}
|
||||
|
||||
sstring salt;
|
||||
|
||||
if (!prefix.empty()) {
|
||||
return prefix + salt;
|
||||
}
|
||||
|
||||
auto tmp = std::make_unique<crypt_data>();
|
||||
tmp->initialized = 0;
|
||||
|
||||
// Try in order:
|
||||
// blowfish 2011 fix, blowfish, sha512, sha256, md5
|
||||
for (sstring pfx : { "$2y$", "$2a$", "$6$", "$5$", "$1$" }) {
|
||||
salt = pfx + input;
|
||||
if (crypt_r("fisk", salt.c_str(), tmp.get())) {
|
||||
prefix = pfx;
|
||||
return salt;
|
||||
}
|
||||
}
|
||||
throw std::runtime_error("Could not initialize hashing algorithm");
|
||||
}
|
||||
|
||||
static sstring hashpw(const sstring& pass) {
|
||||
return hashpw(pass, gensalt());
|
||||
}
|
||||
|
||||
future<> auth::password_authenticator::init() {
|
||||
gensalt(); // do this once to determine usable hashing
|
||||
|
||||
sstring create_table = sprint(
|
||||
"CREATE TABLE %s.%s ("
|
||||
"%s text,"
|
||||
"%s text," // salt + hash + number of rounds
|
||||
"options map<text,text>,"// for future extensions
|
||||
"PRIMARY KEY(%s)"
|
||||
") WITH gc_grace_seconds=%d",
|
||||
auth::auth::AUTH_KS,
|
||||
CREDENTIALS_CF, USER_NAME, SALTED_HASH, USER_NAME,
|
||||
90 * 24 * 60 * 60); // 3 months.
|
||||
|
||||
return auth::setup_table(CREDENTIALS_CF, create_table).then([this] {
|
||||
// instead of once-timer, just schedule this later
|
||||
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,
|
||||
CREDENTIALS_CF,
|
||||
USER_NAME, SALTED_HASH
|
||||
),
|
||||
db::consistency_level::ONE, {DEFAULT_USER_NAME, hashpw(DEFAULT_USER_PASSWORD)}).then([](auto) {
|
||||
logger.info("Created default user '{}'", DEFAULT_USER_NAME);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
db::consistency_level auth::password_authenticator::consistency_for_user(const sstring& username) {
|
||||
if (username == DEFAULT_USER_NAME) {
|
||||
return db::consistency_level::QUORUM;
|
||||
}
|
||||
return db::consistency_level::LOCAL_ONE;
|
||||
}
|
||||
|
||||
const sstring& auth::password_authenticator::class_name() const {
|
||||
return PASSWORD_AUTHENTICATOR_NAME;
|
||||
}
|
||||
|
||||
bool auth::password_authenticator::require_authentication() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
auth::authenticator::option_set auth::password_authenticator::supported_options() const {
|
||||
return option_set::of<option::PASSWORD>();
|
||||
}
|
||||
|
||||
auth::authenticator::option_set auth::password_authenticator::alterable_options() const {
|
||||
return option_set::of<option::PASSWORD>();
|
||||
}
|
||||
|
||||
future<::shared_ptr<auth::authenticated_user> > auth::password_authenticator::authenticate(
|
||||
const credentials_map& credentials) const
|
||||
throw (exceptions::authentication_exception) {
|
||||
if (!credentials.count(USERNAME_KEY)) {
|
||||
throw exceptions::authentication_exception(sprint("Required key '%s' is missing", USERNAME_KEY));
|
||||
}
|
||||
if (!credentials.count(PASSWORD_KEY)) {
|
||||
throw exceptions::authentication_exception(sprint("Required key '%s' is missing", PASSWORD_KEY));
|
||||
}
|
||||
|
||||
auto& username = credentials.at(USERNAME_KEY);
|
||||
auto& password = credentials.at(PASSWORD_KEY);
|
||||
|
||||
// Here was a thread local, explicit cache of prepared statement. In normal execution this is
|
||||
// fine, but since we in testing set up and tear down system over and over, we'd start using
|
||||
// obsolete prepared statements pretty quickly.
|
||||
// Rely on query processing caching statements instead, and lets assume
|
||||
// that a map lookup string->statement is not gonna kill us much.
|
||||
auto& qp = cql3::get_local_query_processor();
|
||||
return qp.process(
|
||||
sprint("SELECT %s FROM %s.%s WHERE %s = ?", SALTED_HASH,
|
||||
auth::AUTH_KS, CREDENTIALS_CF, USER_NAME),
|
||||
consistency_for_user(username), { username }, true).then_wrapped(
|
||||
[=](future<::shared_ptr<cql3::untyped_result_set>> f) {
|
||||
try {
|
||||
auto res = f.get0();
|
||||
if (res->empty() || !checkpw(password, res->one().get_as<sstring>(SALTED_HASH))) {
|
||||
throw exceptions::authentication_exception("Username and/or password are incorrect");
|
||||
}
|
||||
return make_ready_future<::shared_ptr<authenticated_user>>(::make_shared<authenticated_user>(username));
|
||||
} catch (std::system_error &) {
|
||||
std::throw_with_nested(exceptions::authentication_exception("Could not verify password"));
|
||||
} catch (exceptions::request_execution_exception& e) {
|
||||
std::throw_with_nested(exceptions::authentication_exception(e.what()));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
future<> auth::password_authenticator::create(sstring username,
|
||||
const option_map& options)
|
||||
throw (exceptions::request_validation_exception,
|
||||
exceptions::request_execution_exception) {
|
||||
try {
|
||||
auto password = boost::any_cast<sstring>(options.at(option::PASSWORD));
|
||||
auto query = sprint("INSERT INTO %s.%s (%s, %s) VALUES (?, ?)",
|
||||
auth::AUTH_KS, CREDENTIALS_CF, USER_NAME, SALTED_HASH);
|
||||
auto& qp = cql3::get_local_query_processor();
|
||||
return qp.process(query, consistency_for_user(username), { username, hashpw(password) }).discard_result();
|
||||
} catch (std::out_of_range&) {
|
||||
throw exceptions::invalid_request_exception("PasswordAuthenticator requires PASSWORD option");
|
||||
}
|
||||
}
|
||||
|
||||
future<> auth::password_authenticator::alter(sstring username,
|
||||
const option_map& options)
|
||||
throw (exceptions::request_validation_exception,
|
||||
exceptions::request_execution_exception) {
|
||||
try {
|
||||
auto password = boost::any_cast<sstring>(options.at(option::PASSWORD));
|
||||
auto query = sprint("UPDATE %s.%s SET %s = ? WHERE %s = ?",
|
||||
auth::AUTH_KS, CREDENTIALS_CF, SALTED_HASH, USER_NAME);
|
||||
auto& qp = cql3::get_local_query_processor();
|
||||
return qp.process(query, consistency_for_user(username), { hashpw(password), username }).discard_result();
|
||||
} catch (std::out_of_range&) {
|
||||
throw exceptions::invalid_request_exception("PasswordAuthenticator requires PASSWORD option");
|
||||
}
|
||||
}
|
||||
|
||||
future<> auth::password_authenticator::drop(sstring username)
|
||||
throw (exceptions::request_validation_exception,
|
||||
exceptions::request_execution_exception) {
|
||||
try {
|
||||
auto query = sprint("DELETE FROM %s.%s WHERE %s = ?",
|
||||
auth::AUTH_KS, CREDENTIALS_CF, USER_NAME);
|
||||
auto& qp = cql3::get_local_query_processor();
|
||||
return qp.process(query, consistency_for_user(username), { username }).discard_result();
|
||||
} catch (std::out_of_range&) {
|
||||
throw exceptions::invalid_request_exception("PasswordAuthenticator requires PASSWORD option");
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
class plain_text_password_challenge: public sasl_challenge {
|
||||
public:
|
||||
plain_text_password_challenge(const password_authenticator& a)
|
||||
: _authenticator(a)
|
||||
{}
|
||||
|
||||
/**
|
||||
* SASL PLAIN mechanism specifies that credentials are encoded in a
|
||||
* sequence of UTF-8 bytes, delimited by 0 (US-ASCII NUL).
|
||||
* The form is : {code}authzId<NUL>authnId<NUL>password<NUL>{code}
|
||||
* authzId is optional, and in fact we don't care about it here as we'll
|
||||
* set the authzId to match the authnId (that is, there is no concept of
|
||||
* a user being authorized to act on behalf of another).
|
||||
*
|
||||
* @param bytes encoded credentials string sent by the client
|
||||
* @return map containing the username/password pairs in the form an IAuthenticator
|
||||
* would expect
|
||||
* @throws javax.security.sasl.SaslException
|
||||
*/
|
||||
bytes evaluate_response(bytes_view client_response)
|
||||
throw (exceptions::authentication_exception) override {
|
||||
logger.debug("Decoding credentials from client token");
|
||||
|
||||
sstring username, password;
|
||||
|
||||
auto b = client_response.crbegin();
|
||||
auto e = client_response.crend();
|
||||
auto i = b;
|
||||
|
||||
while (i != e) {
|
||||
if (*i == 0) {
|
||||
sstring tmp(i.base(), b.base());
|
||||
if (password.empty()) {
|
||||
password = std::move(tmp);
|
||||
} else if (username.empty()) {
|
||||
username = std::move(tmp);
|
||||
}
|
||||
b = ++i;
|
||||
continue;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
|
||||
if (username.empty()) {
|
||||
throw exceptions::authentication_exception("Authentication ID must not be null");
|
||||
}
|
||||
if (password.empty()) {
|
||||
throw exceptions::authentication_exception("Password must not be null");
|
||||
}
|
||||
|
||||
_credentials[USERNAME_KEY] = std::move(username);
|
||||
_credentials[PASSWORD_KEY] = std::move(password);
|
||||
_complete = true;
|
||||
return {};
|
||||
}
|
||||
bool is_complete() const override {
|
||||
return _complete;
|
||||
}
|
||||
future<::shared_ptr<authenticated_user>> get_authenticated_user() const
|
||||
throw (exceptions::authentication_exception) override {
|
||||
return _authenticator.authenticate(_credentials);
|
||||
}
|
||||
private:
|
||||
const password_authenticator& _authenticator;
|
||||
credentials_map _credentials;
|
||||
bool _complete = false;
|
||||
};
|
||||
return ::make_shared<plain_text_password_challenge>(*this);
|
||||
}
|
||||
@@ -1,73 +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 2016 Cloudius Systems
|
||||
*
|
||||
* Modified by Cloudius Systems
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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 "authenticator.hh"
|
||||
|
||||
namespace auth {
|
||||
|
||||
class password_authenticator : public authenticator {
|
||||
public:
|
||||
static const sstring PASSWORD_AUTHENTICATOR_NAME;
|
||||
|
||||
password_authenticator();
|
||||
~password_authenticator();
|
||||
|
||||
future<> init();
|
||||
|
||||
const sstring& class_name() const override;
|
||||
bool require_authentication() const override;
|
||||
option_set supported_options() const override;
|
||||
option_set alterable_options() const override;
|
||||
future<::shared_ptr<authenticated_user>> authenticate(const credentials_map& credentials) const throw(exceptions::authentication_exception) override;
|
||||
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;
|
||||
resource_ids protected_resources() const override;
|
||||
::shared_ptr<sasl_challenge> new_sasl_challenge() const override;
|
||||
|
||||
|
||||
static db::consistency_level consistency_for_user(const sstring& username);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -1,49 +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 2016 Cloudius Systems
|
||||
*
|
||||
* Modified by Cloudius Systems
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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 "permission.hh"
|
||||
|
||||
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;
|
||||
@@ -1,81 +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 2016 Cloudius Systems
|
||||
*
|
||||
* Modified by Cloudius Systems
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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 "enum_set.hh"
|
||||
|
||||
namespace auth {
|
||||
|
||||
enum class permission {
|
||||
//Deprecated
|
||||
READ,
|
||||
//Deprecated
|
||||
WRITE,
|
||||
|
||||
// schema management
|
||||
CREATE, // required for CREATE KEYSPACE and CREATE TABLE.
|
||||
ALTER, // required for ALTER KEYSPACE, ALTER TABLE, CREATE INDEX, DROP INDEX.
|
||||
DROP, // required for DROP KEYSPACE and DROP TABLE.
|
||||
|
||||
// data access
|
||||
SELECT, // required for SELECT.
|
||||
MODIFY, // required for INSERT, UPDATE, DELETE, TRUNCATE.
|
||||
|
||||
// permission management
|
||||
AUTHORIZE, // required for GRANT and REVOKE.
|
||||
};
|
||||
|
||||
typedef enum_set<super_enum<permission,
|
||||
permission::READ,
|
||||
permission::WRITE,
|
||||
permission::CREATE,
|
||||
permission::ALTER,
|
||||
permission::DROP,
|
||||
permission::SELECT,
|
||||
permission::MODIFY,
|
||||
permission::AUTHORIZE>> permission_set;
|
||||
|
||||
extern const permission_set ALL_DATA;
|
||||
extern const permission_set ALL;
|
||||
extern const permission_set NONE;
|
||||
|
||||
}
|
||||
18
bytes.hh
18
bytes.hh
@@ -22,7 +22,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "core/sstring.hh"
|
||||
#include "hashing.hh"
|
||||
#include <experimental/optional>
|
||||
#include <iosfwd>
|
||||
#include <functional>
|
||||
@@ -58,20 +57,3 @@ std::ostream& operator<<(std::ostream& os, const bytes_view& b);
|
||||
|
||||
}
|
||||
|
||||
template<>
|
||||
struct appending_hash<bytes> {
|
||||
template<typename Hasher>
|
||||
void operator()(Hasher& h, const bytes& v) const {
|
||||
feed_hash(h, v.size());
|
||||
h.update(reinterpret_cast<const char*>(v.cbegin()), v.size() * sizeof(bytes::value_type));
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct appending_hash<bytes_view> {
|
||||
template<typename Hasher>
|
||||
void operator()(Hasher& h, bytes_view v) const {
|
||||
feed_hash(h, v.size());
|
||||
h.update(reinterpret_cast<const char*>(v.begin()), v.size() * sizeof(bytes_view::value_type));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
#include "types.hh"
|
||||
#include "net/byteorder.hh"
|
||||
#include "core/unaligned.hh"
|
||||
#include "hashing.hh"
|
||||
|
||||
/**
|
||||
* Utility for writing data into a buffer when its final size is not known up front.
|
||||
@@ -333,13 +332,3 @@ public:
|
||||
_current->offset = pos._offset;
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct appending_hash<bytes_ostream> {
|
||||
template<typename Hasher>
|
||||
void operator()(Hasher& h, const bytes_ostream& b) const {
|
||||
for (auto&& frag : b.fragments()) {
|
||||
feed_hash(h, frag);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,98 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2015 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 "canonical_mutation.hh"
|
||||
#include "mutation.hh"
|
||||
#include "mutation_partition_serializer.hh"
|
||||
#include "converting_mutation_partition_applier.hh"
|
||||
#include "hashing_partition_visitor.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)
|
||||
: _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 {
|
||||
data_input in(_data);
|
||||
|
||||
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 = 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()) {
|
||||
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 = db::serializer<column_mapping>::read(in);
|
||||
converting_mutation_partition_applier v(cm, *m.schema(), m.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));
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2015 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 "bytes.hh"
|
||||
#include "schema.hh"
|
||||
#include "database_fwd.hh"
|
||||
#include "db/serializer.hh"
|
||||
#include "mutation_partition_visitor.hh"
|
||||
#include "mutation_partition_serializer.hh"
|
||||
|
||||
// Immutable mutation form which can be read using any schema version of the same table.
|
||||
// Safe to access from other shards via const&.
|
||||
// Safe to pass serialized across nodes.
|
||||
class canonical_mutation {
|
||||
bytes _data;
|
||||
canonical_mutation(bytes);
|
||||
public:
|
||||
explicit canonical_mutation(const mutation&);
|
||||
|
||||
canonical_mutation(canonical_mutation&&) = default;
|
||||
canonical_mutation(const canonical_mutation&) = default;
|
||||
canonical_mutation& operator=(const canonical_mutation&) = default;
|
||||
canonical_mutation& operator=(canonical_mutation&&) = default;
|
||||
|
||||
// Create a mutation object interpreting this canonical mutation using
|
||||
// given schema.
|
||||
//
|
||||
// Data which is not representable in the target schema is dropped. If this
|
||||
// is not intended, user should sync the schema first.
|
||||
mutation to_mutation(schema_ptr) const;
|
||||
|
||||
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>;
|
||||
|
||||
}
|
||||
@@ -169,17 +169,6 @@ rpc_address: localhost
|
||||
# port for Thrift to listen for clients on
|
||||
rpc_port: 9160
|
||||
|
||||
# port for REST API server
|
||||
api_port: 10000
|
||||
|
||||
# IP for the REST API server
|
||||
api_address: 127.0.0.1
|
||||
|
||||
# Log WARN on any batch size exceeding this value. 5kb per batch by default.
|
||||
# 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
|
||||
|
||||
|
||||
###################################################
|
||||
## Not currently supported, reserved for future use
|
||||
###################################################
|
||||
@@ -216,7 +205,7 @@ 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
|
||||
# Authentication backend, implementing IAuthenticator; used to identify users
|
||||
# Out of the box, Scylla provides org.apache.cassandra.auth.{AllowAllAuthenticator,
|
||||
# PasswordAuthenticator}.
|
||||
#
|
||||
@@ -610,6 +599,10 @@ commitlog_total_space_in_mb: -1
|
||||
# column_index_size_in_kb: 64
|
||||
|
||||
|
||||
# Log WARN on any batch size exceeding this value. 5kb per batch by default.
|
||||
# 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
|
||||
|
||||
# Number of simultaneous compactions to allow, NOT including
|
||||
# validation "compactions" for anti-entropy repair. Simultaneous
|
||||
# compactions can help preserve read performance in a mixed read/write
|
||||
|
||||
41
configure.py
41
configure.py
@@ -50,9 +50,6 @@ def apply_tristate(var, test, note, missing):
|
||||
return False
|
||||
return False
|
||||
|
||||
def have_pkg(package):
|
||||
return subprocess.call(['pkg-config', package]) == 0
|
||||
|
||||
def pkg_config(option, package):
|
||||
output = subprocess.check_output(['pkg-config', option, package])
|
||||
return output.decode('utf-8').strip()
|
||||
@@ -137,7 +134,6 @@ modes = {
|
||||
|
||||
scylla_tests = [
|
||||
'tests/mutation_test',
|
||||
'tests/canonical_mutation_test',
|
||||
'tests/range_test',
|
||||
'tests/types_test',
|
||||
'tests/keys_test',
|
||||
@@ -155,7 +151,6 @@ scylla_tests = [
|
||||
'tests/perf/perf_sstable',
|
||||
'tests/cql_query_test',
|
||||
'tests/storage_proxy_test',
|
||||
'tests/schema_change_test',
|
||||
'tests/mutation_reader_test',
|
||||
'tests/key_reader_test',
|
||||
'tests/mutation_query_test',
|
||||
@@ -189,7 +184,6 @@ scylla_tests = [
|
||||
'tests/crc_test',
|
||||
'tests/flush_queue_test',
|
||||
'tests/dynamic_bitset_test',
|
||||
'tests/auth_test',
|
||||
]
|
||||
|
||||
apps = [
|
||||
@@ -228,8 +222,6 @@ arg_parser.add_argument('--static-stdc++', dest = 'staticcxx', action = 'store_t
|
||||
help = 'Link libgcc and libstdc++ 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',
|
||||
help = 'Python3 path')
|
||||
add_tristate(arg_parser, name = 'hwloc', dest = 'hwloc', help = 'hwloc support')
|
||||
add_tristate(arg_parser, name = 'xen', dest = 'xen', help = 'Xen support')
|
||||
args = arg_parser.parse_args()
|
||||
@@ -243,15 +235,11 @@ cassandra_interface = Thrift(source = 'interface/cassandra.thrift', service = 'C
|
||||
|
||||
scylla_core = (['database.cc',
|
||||
'schema.cc',
|
||||
'frozen_schema.cc',
|
||||
'schema_registry.cc',
|
||||
'bytes.cc',
|
||||
'mutation.cc',
|
||||
'row_cache.cc',
|
||||
'canonical_mutation.cc',
|
||||
'frozen_mutation.cc',
|
||||
'memtable.cc',
|
||||
'schema_mutations.cc',
|
||||
'release.cc',
|
||||
'utils/logalloc.cc',
|
||||
'utils/large_bitset.cc',
|
||||
@@ -304,7 +292,6 @@ scylla_core = (['database.cc',
|
||||
'cql3/statements/index_target.cc',
|
||||
'cql3/statements/create_index_statement.cc',
|
||||
'cql3/statements/truncate_statement.cc',
|
||||
'cql3/statements/alter_table_statement.cc',
|
||||
'cql3/update_parameters.cc',
|
||||
'cql3/ut_name.cc',
|
||||
'thrift/handler.cc',
|
||||
@@ -387,7 +374,6 @@ scylla_core = (['database.cc',
|
||||
'locator/ec2_snitch.cc',
|
||||
'locator/ec2_multi_region_snitch.cc',
|
||||
'message/messaging_service.cc',
|
||||
'service/client_state.cc',
|
||||
'service/migration_task.cc',
|
||||
'service/storage_service.cc',
|
||||
'service/pending_range_calculator_service.cc',
|
||||
@@ -421,12 +407,6 @@ scylla_core = (['database.cc',
|
||||
'repair/repair.cc',
|
||||
'exceptions/exceptions.cc',
|
||||
'dns.cc',
|
||||
'auth/auth.cc',
|
||||
'auth/authenticated_user.cc',
|
||||
'auth/authenticator.cc',
|
||||
'auth/data_resource.cc',
|
||||
'auth/password_authenticator.cc',
|
||||
'auth/permission.cc',
|
||||
]
|
||||
+ [Antlr3Grammar('cql3/Cql.g')]
|
||||
+ [Thrift('interface/cassandra.thrift', 'Cassandra')]
|
||||
@@ -488,7 +468,6 @@ tests_not_using_seastar_test_framework = set([
|
||||
'tests/partitioner_test',
|
||||
'tests/map_difference_test',
|
||||
'tests/frozen_mutation_test',
|
||||
'tests/canonical_mutation_test',
|
||||
'tests/perf/perf_mutation',
|
||||
'tests/lsa_async_eviction_test',
|
||||
'tests/lsa_sync_eviction_test',
|
||||
@@ -550,17 +529,6 @@ else:
|
||||
args.pie = ''
|
||||
args.fpie = ''
|
||||
|
||||
optional_packages = ['libsystemd']
|
||||
pkgs = []
|
||||
|
||||
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])
|
||||
|
||||
globals().update(vars(args))
|
||||
@@ -593,7 +561,7 @@ elif args.dpdk_target:
|
||||
seastar_cflags = args.user_cflags + " -march=nehalem"
|
||||
seastar_flags += ['--compiler', args.cxx, '--cflags=%s' % (seastar_cflags)]
|
||||
|
||||
status = subprocess.call([python, './configure.py'] + seastar_flags, cwd = 'seastar')
|
||||
status = subprocess.call(['./configure.py'] + seastar_flags, cwd = 'seastar')
|
||||
|
||||
if status != 0:
|
||||
print('Seastar configuration failed')
|
||||
@@ -622,10 +590,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'
|
||||
for pkg in pkgs:
|
||||
args.user_cflags += ' ' + pkg_config('--cflags', pkg)
|
||||
libs += ' ' + pkg_config('--libs', pkg)
|
||||
libs = "-lyaml-cpp -llz4 -lz -lsnappy " + pkg_config("--libs", "jsoncpp") + ' -lboost_filesystem'
|
||||
user_cflags = args.user_cflags
|
||||
user_ldflags = args.user_ldflags
|
||||
if args.staticcxx:
|
||||
@@ -792,7 +757,7 @@ with open(buildfile, 'w') as f:
|
||||
f.write('build {}: phony\n'.format(seastar_deps))
|
||||
f.write(textwrap.dedent('''\
|
||||
rule configure
|
||||
command = {python} configure.py $configure_args
|
||||
command = python3 configure.py $configure_args
|
||||
generator = 1
|
||||
build build.ninja: configure | configure.py
|
||||
rule cscope
|
||||
|
||||
@@ -1,119 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Cloudius Systems, Ltd.
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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 "mutation_partition_view.hh"
|
||||
#include "schema.hh"
|
||||
|
||||
// Mutation partition visitor which applies visited data into
|
||||
// existing mutation_partition. The visited data may be of a different schema.
|
||||
// Data which is not representable in the new schema is dropped.
|
||||
// Weak exception guarantees.
|
||||
class converting_mutation_partition_applier : public mutation_partition_visitor {
|
||||
const schema& _p_schema;
|
||||
mutation_partition& _p;
|
||||
const column_mapping& _visited_column_mapping;
|
||||
deletable_row* _current_row;
|
||||
private:
|
||||
static bool is_compatible(const column_definition& new_def, const data_type& old_type, column_kind kind) {
|
||||
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()) {
|
||||
dst.apply(new_def, atomic_cell_or_collection(cell));
|
||||
}
|
||||
}
|
||||
void accept_cell(row& dst, column_kind kind, const column_definition& new_def, const data_type& old_type, collection_mutation_view cell) {
|
||||
if (!is_compatible(new_def, old_type, kind)) {
|
||||
return;
|
||||
}
|
||||
auto&& ctype = static_pointer_cast<const collection_type_impl>(old_type);
|
||||
auto old_view = ctype->deserialize_mutation_form(cell);
|
||||
|
||||
collection_type_impl::mutation_view new_view;
|
||||
if (old_view.tomb.timestamp > new_def.dropped_at()) {
|
||||
new_view.tomb = old_view.tomb;
|
||||
}
|
||||
for (auto& c : old_view.cells) {
|
||||
if (c.second.timestamp() > new_def.dropped_at()) {
|
||||
new_view.cells.emplace_back(std::move(c));
|
||||
}
|
||||
}
|
||||
dst.apply(new_def, ctype->serialize_mutation_form(std::move(new_view)));
|
||||
}
|
||||
public:
|
||||
converting_mutation_partition_applier(
|
||||
const column_mapping& visited_column_mapping,
|
||||
const schema& target_schema,
|
||||
mutation_partition& target)
|
||||
: _p_schema(target_schema)
|
||||
, _p(target)
|
||||
, _visited_column_mapping(visited_column_mapping)
|
||||
{ }
|
||||
|
||||
virtual void accept_partition_tombstone(tombstone t) override {
|
||||
_p.apply(t);
|
||||
}
|
||||
|
||||
virtual void accept_static_cell(column_id id, atomic_cell_view cell) override {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void accept_static_cell(column_id id, collection_mutation_view collection) override {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void accept_row_tombstone(clustering_key_prefix_view prefix, tombstone t) override {
|
||||
_p.apply_row_tombstone(_p_schema, prefix, t);
|
||||
}
|
||||
|
||||
virtual void accept_row(clustering_key_view key, tombstone deleted_at, const row_marker& rm) override {
|
||||
deletable_row& r = _p.clustered_row(_p_schema, key);
|
||||
r.apply(rm);
|
||||
r.apply(deleted_at);
|
||||
_current_row = &r;
|
||||
}
|
||||
|
||||
virtual void accept_row_cell(column_id id, atomic_cell_view cell) override {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void accept_row_cell(column_id id, collection_mutation_view collection) override {
|
||||
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);
|
||||
}
|
||||
}
|
||||
};
|
||||
42
cql3/Cql.g
42
cql3/Cql.g
@@ -31,7 +31,6 @@ options {
|
||||
|
||||
@parser::includes {
|
||||
#include "cql3/selection/writetime_or_ttl.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"
|
||||
@@ -270,9 +269,7 @@ cqlStatement returns [shared_ptr<parsed_statement> stmt]
|
||||
| st12=dropTableStatement { $stmt = st12; }
|
||||
#if 0
|
||||
| st13=dropIndexStatement { $stmt = st13; }
|
||||
#endif
|
||||
| st14=alterTableStatement { $stmt = st14; }
|
||||
#if 0
|
||||
| st15=alterKeyspaceStatement { $stmt = st15; }
|
||||
| st16=grantStatement { $stmt = st16; }
|
||||
| st17=revokeStatement { $stmt = st17; }
|
||||
@@ -771,7 +768,7 @@ alterKeyspaceStatement returns [AlterKeyspaceStatement expr]
|
||||
: K_ALTER K_KEYSPACE ks=keyspaceName
|
||||
K_WITH properties[attrs] { $expr = new AlterKeyspaceStatement(ks, attrs); }
|
||||
;
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* ALTER COLUMN FAMILY <CF> ALTER <column> TYPE <newtype>;
|
||||
@@ -780,29 +777,27 @@ alterKeyspaceStatement returns [AlterKeyspaceStatement expr]
|
||||
* ALTER COLUMN FAMILY <CF> WITH <property> = <value>;
|
||||
* ALTER COLUMN FAMILY <CF> RENAME <column> TO <column>;
|
||||
*/
|
||||
alterTableStatement returns [shared_ptr<alter_table_statement> expr]
|
||||
alterTableStatement returns [AlterTableStatement expr]
|
||||
@init {
|
||||
alter_table_statement::type type;
|
||||
auto props = make_shared<cql3::statements::cf_prop_defs>();;
|
||||
std::vector<std::pair<shared_ptr<cql3::column_identifier::raw>, shared_ptr<cql3::column_identifier::raw>>> renames;
|
||||
bool is_static = false;
|
||||
AlterTableStatement.Type type = null;
|
||||
CFPropDefs props = new CFPropDefs();
|
||||
Map<ColumnIdentifier.Raw, ColumnIdentifier.Raw> renames = new HashMap<ColumnIdentifier.Raw, ColumnIdentifier.Raw>();
|
||||
boolean isStatic = false;
|
||||
}
|
||||
: K_ALTER K_COLUMNFAMILY cf=columnFamilyName
|
||||
( K_ALTER id=cident K_TYPE v=comparatorType { type = alter_table_statement::type::alter; }
|
||||
| K_ADD id=cident v=comparatorType ({ is_static=true; } K_STATIC)? { type = alter_table_statement::type::add; }
|
||||
| K_DROP id=cident { type = alter_table_statement::type::drop; }
|
||||
| K_WITH properties[props] { type = alter_table_statement::type::opts; }
|
||||
| K_RENAME { type = alter_table_statement::type::rename; }
|
||||
id1=cident K_TO toId1=cident { renames.emplace_back(id1, toId1); }
|
||||
( K_AND idn=cident K_TO toIdn=cident { renames.emplace_back(idn, toIdn); } )*
|
||||
( K_ALTER id=cident K_TYPE v=comparatorType { type = AlterTableStatement.Type.ALTER; }
|
||||
| K_ADD id=cident v=comparatorType ({ isStatic=true; } K_STATIC)? { type = AlterTableStatement.Type.ADD; }
|
||||
| K_DROP id=cident { type = AlterTableStatement.Type.DROP; }
|
||||
| K_WITH properties[props] { type = AlterTableStatement.Type.OPTS; }
|
||||
| K_RENAME { type = AlterTableStatement.Type.RENAME; }
|
||||
id1=cident K_TO toId1=cident { renames.put(id1, toId1); }
|
||||
( K_AND idn=cident K_TO toIdn=cident { renames.put(idn, toIdn); } )*
|
||||
)
|
||||
{
|
||||
$expr = ::make_shared<alter_table_statement>(std::move(cf), type, std::move(id),
|
||||
std::move(v), std::move(props), std::move(renames), is_static);
|
||||
$expr = new AlterTableStatement(cf, type, id, v, props, renames, isStatic);
|
||||
}
|
||||
;
|
||||
|
||||
#if 0
|
||||
/**
|
||||
* ALTER TYPE <name> ALTER <field> TYPE <newtype>;
|
||||
* ALTER TYPE <name> ADD <field> <newtype>;
|
||||
@@ -1248,7 +1243,6 @@ relationType returns [const cql3::operator_type* op = nullptr]
|
||||
;
|
||||
|
||||
relation[std::vector<cql3::relation_ptr>& clauses]
|
||||
@init{ const cql3::operator_type* rt = nullptr; }
|
||||
: name=cident type=relationType t=term { $clauses.emplace_back(::make_shared<cql3::single_column_relation>(std::move(name), *type, std::move(t))); }
|
||||
|
||||
| K_TOKEN l=tupleOfIdentifiers type=relationType t=term
|
||||
@@ -1258,9 +1252,11 @@ relation[std::vector<cql3::relation_ptr>& clauses]
|
||||
{ $clauses.emplace_back(make_shared<cql3::single_column_relation>(std::move(name), cql3::operator_type::IN, std::move(marker))); }
|
||||
| name=cident K_IN in_values=singleColumnInValues
|
||||
{ $clauses.emplace_back(cql3::single_column_relation::create_in_relation(std::move(name), std::move(in_values))); }
|
||||
| name=cident K_CONTAINS { rt = &cql3::operator_type::CONTAINS; } (K_KEY { rt = &cql3::operator_type::CONTAINS_KEY; })?
|
||||
t=term { $clauses.emplace_back(make_shared<cql3::single_column_relation>(std::move(name), *rt, std::move(t))); }
|
||||
| name=cident '[' key=term ']' type=relationType t=term { $clauses.emplace_back(make_shared<cql3::single_column_relation>(std::move(name), std::move(key), *type, std::move(t))); }
|
||||
#if 0
|
||||
| name=cident K_CONTAINS { Operator rt = Operator.CONTAINS; } (K_KEY { rt = Operator.CONTAINS_KEY; })?
|
||||
t=term { $clauses.add(new SingleColumnRelation(name, rt, t)); }
|
||||
| name=cident '[' key=term ']' type=relationType t=term { $clauses.add(new SingleColumnRelation(name, key, type, t)); }
|
||||
#endif
|
||||
| ids=tupleOfIdentifiers
|
||||
( K_IN
|
||||
( '(' ')'
|
||||
|
||||
@@ -99,9 +99,9 @@ query_options::query_options(query_options&& o, std::vector<std::vector<bytes_vi
|
||||
_batch_options = std::move(tmp);
|
||||
}
|
||||
|
||||
query_options::query_options(db::consistency_level cl, std::vector<bytes_opt> values)
|
||||
query_options::query_options(std::vector<bytes_opt> values)
|
||||
: query_options(
|
||||
cl,
|
||||
db::consistency_level::ONE,
|
||||
{},
|
||||
std::move(values),
|
||||
{},
|
||||
@@ -120,11 +120,6 @@ query_options::query_options(db::consistency_level cl, std::vector<bytes_opt> va
|
||||
}
|
||||
}
|
||||
|
||||
query_options::query_options(std::vector<bytes_opt> values)
|
||||
: query_options(
|
||||
db::consistency_level::ONE, std::move(values))
|
||||
{}
|
||||
|
||||
db::consistency_level query_options::get_consistency() const
|
||||
{
|
||||
return _consistency;
|
||||
|
||||
@@ -112,7 +112,6 @@ public:
|
||||
|
||||
// forInternalUse
|
||||
explicit query_options(std::vector<bytes_opt> values);
|
||||
explicit query_options(db::consistency_level, std::vector<bytes_opt> values);
|
||||
|
||||
db::consistency_level get_consistency() const;
|
||||
bytes_view_opt get_value_at(size_t idx) const;
|
||||
|
||||
@@ -109,7 +109,6 @@ future<> query_processor::stop()
|
||||
future<::shared_ptr<result_message>>
|
||||
query_processor::process(const sstring_view& query_string, service::query_state& query_state, query_options& options)
|
||||
{
|
||||
log.trace("process: \"{}\"", query_string);
|
||||
auto p = get_statement(query_string, query_state.get_client_state());
|
||||
options.prepare(p->bound_names);
|
||||
auto cql_statement = p->statement;
|
||||
@@ -300,9 +299,8 @@ query_processor::parse_statement(const sstring_view& query)
|
||||
}
|
||||
|
||||
query_options query_processor::make_internal_options(
|
||||
::shared_ptr<statements::parsed_statement::prepared> p,
|
||||
const std::initializer_list<data_value>& values,
|
||||
db::consistency_level cl) {
|
||||
::shared_ptr<statements::parsed_statement::prepared> p,
|
||||
const std::initializer_list<data_value>& values) {
|
||||
if (p->bound_names.size() != values.size()) {
|
||||
throw std::invalid_argument(sprint("Invalid number of values. Expecting %d but got %d", p->bound_names.size(), values.size()));
|
||||
}
|
||||
@@ -318,12 +316,13 @@ query_options query_processor::make_internal_options(
|
||||
bound_values.push_back({n->type->decompose(v)});
|
||||
}
|
||||
}
|
||||
return query_options(cl, bound_values);
|
||||
return query_options(bound_values);
|
||||
}
|
||||
|
||||
::shared_ptr<statements::parsed_statement::prepared> query_processor::prepare_internal(
|
||||
const sstring& query_string) {
|
||||
auto& p = _internal_statements[query_string];
|
||||
const std::experimental::string_view& query_string) {
|
||||
|
||||
auto& p = _internal_statements[sstring(query_string.begin(), query_string.end())];
|
||||
if (p == nullptr) {
|
||||
auto np = parse_statement(query_string)->prepare(_db.local());
|
||||
np->statement->validate(_proxy, *_internal_state);
|
||||
@@ -333,54 +332,22 @@ query_options query_processor::make_internal_options(
|
||||
}
|
||||
|
||||
future<::shared_ptr<untyped_result_set>> query_processor::execute_internal(
|
||||
const sstring& query_string,
|
||||
const std::experimental::string_view& query_string,
|
||||
const std::initializer_list<data_value>& values) {
|
||||
if (log.is_enabled(logging::log_level::trace)) {
|
||||
log.trace("execute_internal: \"{}\" ({})", query_string, ::join(", ", values));
|
||||
}
|
||||
auto p = prepare_internal(query_string);
|
||||
return execute_internal(p, values);
|
||||
}
|
||||
|
||||
future<::shared_ptr<untyped_result_set>> query_processor::execute_internal(
|
||||
::shared_ptr<statements::parsed_statement::prepared> p,
|
||||
const std::initializer_list<data_value>& values) {
|
||||
auto opts = make_internal_options(p, values);
|
||||
return do_with(std::move(opts),
|
||||
[this, p = std::move(p)](query_options & opts) {
|
||||
return p->statement->execute_internal(_proxy, *_internal_state, opts).then(
|
||||
[p](::shared_ptr<transport::messages::result_message> msg) {
|
||||
[](::shared_ptr<transport::messages::result_message> msg) {
|
||||
return make_ready_future<::shared_ptr<untyped_result_set>>(::make_shared<untyped_result_set>(msg));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
future<::shared_ptr<untyped_result_set>> query_processor::process(
|
||||
const sstring& query_string,
|
||||
db::consistency_level cl, const std::initializer_list<data_value>& values, bool cache)
|
||||
{
|
||||
auto p = cache ? prepare_internal(query_string) : parse_statement(query_string)->prepare(_db.local());
|
||||
if (!cache) {
|
||||
p->statement->validate(_proxy, *_internal_state);
|
||||
}
|
||||
return process(p, cl, values);
|
||||
}
|
||||
|
||||
future<::shared_ptr<untyped_result_set>> query_processor::process(
|
||||
::shared_ptr<statements::parsed_statement::prepared> p,
|
||||
db::consistency_level cl, const std::initializer_list<data_value>& values)
|
||||
{
|
||||
auto opts = make_internal_options(p, values, cl);
|
||||
return do_with(std::move(opts),
|
||||
[this, p = std::move(p)](query_options & opts) {
|
||||
return p->statement->execute(_proxy, *_internal_state, opts).then(
|
||||
[p](::shared_ptr<transport::messages::result_message> msg) {
|
||||
return make_ready_future<::shared_ptr<untyped_result_set>>(::make_shared<untyped_result_set>(msg));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
future<::shared_ptr<transport::messages::result_message>>
|
||||
query_processor::process_batch(::shared_ptr<statements::batch_statement> batch, service::query_state& query_state, query_options& options) {
|
||||
auto& client_state = query_state.get_client_state();
|
||||
@@ -421,12 +388,8 @@ void query_processor::migration_subscriber::on_update_keyspace(const sstring& ks
|
||||
{
|
||||
}
|
||||
|
||||
void query_processor::migration_subscriber::on_update_column_family(const sstring& ks_name, const sstring& cf_name, bool columns_changed)
|
||||
void query_processor::migration_subscriber::on_update_column_family(const sstring& ks_name, const sstring& cf_name)
|
||||
{
|
||||
if (columns_changed) {
|
||||
log.info("Column definitions for {}.{} changed, invalidating related prepared statements", ks_name, cf_name);
|
||||
remove_invalid_prepared_statements(ks_name, cf_name);
|
||||
}
|
||||
}
|
||||
|
||||
void query_processor::migration_subscriber::on_update_user_type(const sstring& ks_name, const sstring& type_name)
|
||||
@@ -476,7 +439,9 @@ void query_processor::migration_subscriber::remove_invalid_prepared_statements(s
|
||||
}
|
||||
}
|
||||
for (auto& id : invalid) {
|
||||
_qp->invalidate_prepared_statement(id);
|
||||
get_query_processor().invoke_on_all([id] (auto& qp) {
|
||||
qp.invalidate_prepared_statement(id);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -322,25 +322,14 @@ public:
|
||||
}
|
||||
#endif
|
||||
private:
|
||||
query_options make_internal_options(::shared_ptr<statements::parsed_statement::prepared>, const std::initializer_list<data_value>&, db::consistency_level = db::consistency_level::ONE);
|
||||
::shared_ptr<statements::parsed_statement::prepared> prepare_internal(const std::experimental::string_view& query);
|
||||
query_options make_internal_options(::shared_ptr<statements::parsed_statement::prepared>, const std::initializer_list<data_value>&);
|
||||
|
||||
public:
|
||||
future<::shared_ptr<untyped_result_set>> execute_internal(
|
||||
const sstring& query_string,
|
||||
const std::experimental::string_view& query_string,
|
||||
const std::initializer_list<data_value>& = { });
|
||||
|
||||
::shared_ptr<statements::parsed_statement::prepared> prepare_internal(const sstring& query);
|
||||
|
||||
future<::shared_ptr<untyped_result_set>> execute_internal(
|
||||
::shared_ptr<statements::parsed_statement::prepared>,
|
||||
const std::initializer_list<data_value>& = { });
|
||||
|
||||
future<::shared_ptr<untyped_result_set>> process(
|
||||
const sstring& query_string,
|
||||
db::consistency_level, const std::initializer_list<data_value>& = { }, bool cache = false);
|
||||
future<::shared_ptr<untyped_result_set>> process(
|
||||
::shared_ptr<statements::parsed_statement::prepared>,
|
||||
db::consistency_level, const std::initializer_list<data_value>& = { });
|
||||
|
||||
/*
|
||||
* This function provides a timestamp that is guaranteed to be higher than any timestamp
|
||||
* previously used in internal queries.
|
||||
@@ -497,7 +486,7 @@ public:
|
||||
virtual void on_create_aggregate(const sstring& ks_name, const sstring& aggregate_name) override;
|
||||
|
||||
virtual void on_update_keyspace(const sstring& ks_name) override;
|
||||
virtual void on_update_column_family(const sstring& ks_name, const sstring& cf_name, bool columns_changed) override;
|
||||
virtual void on_update_column_family(const sstring& ks_name, const sstring& cf_name) override;
|
||||
virtual void on_update_user_type(const sstring& ks_name, const sstring& type_name) override;
|
||||
virtual void on_update_function(const sstring& ks_name, const sstring& function_name) override;
|
||||
virtual void on_update_aggregate(const sstring& ks_name, const sstring& aggregate_name) override;
|
||||
|
||||
@@ -134,7 +134,7 @@ public:
|
||||
* @return <code>true</code> if this selection contains a collection, <code>false</code> otherwise.
|
||||
*/
|
||||
bool contains_a_collection() const {
|
||||
if (!_schema->has_multi_cell_collections()) {
|
||||
if (!_schema->has_collections()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,278 +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 2015 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/statements/alter_table_statement.hh"
|
||||
#include "service/migration_manager.hh"
|
||||
#include "validation.hh"
|
||||
#include "db/config.hh"
|
||||
|
||||
namespace cql3 {
|
||||
|
||||
namespace statements {
|
||||
|
||||
alter_table_statement::alter_table_statement(shared_ptr<cf_name> name,
|
||||
type t,
|
||||
shared_ptr<column_identifier::raw> column_name,
|
||||
shared_ptr<cql3_type::raw> validator,
|
||||
shared_ptr<cf_prop_defs> properties,
|
||||
renames_type renames,
|
||||
bool is_static)
|
||||
: schema_altering_statement(std::move(name))
|
||||
, _type(t)
|
||||
, _raw_column_name(std::move(column_name))
|
||||
, _validator(std::move(validator))
|
||||
, _properties(std::move(properties))
|
||||
, _renames(std::move(renames))
|
||||
, _is_static(is_static)
|
||||
{
|
||||
}
|
||||
|
||||
void alter_table_statement::check_access(const service::client_state& state)
|
||||
{
|
||||
warn(unimplemented::cause::PERMISSIONS);
|
||||
#if 0
|
||||
state.hasColumnFamilyAccess(keyspace(), columnFamily(), Permission.ALTER);
|
||||
#endif
|
||||
}
|
||||
|
||||
void alter_table_statement::validate(distributed<service::storage_proxy>& proxy, const service::client_state& state)
|
||||
{
|
||||
// validated in announce_migration()
|
||||
}
|
||||
|
||||
static const sstring ALTER_TABLE_FEATURE = "ALTER TABLE";
|
||||
|
||||
future<bool> alter_table_statement::announce_migration(distributed<service::storage_proxy>& proxy, bool is_local_only)
|
||||
{
|
||||
auto& db = proxy.local().get_db().local();
|
||||
db.get_config().check_experimental(ALTER_TABLE_FEATURE);
|
||||
|
||||
auto schema = validation::validate_column_family(db, keyspace(), column_family());
|
||||
auto cfm = schema_builder(schema);
|
||||
|
||||
shared_ptr<cql3_type> validator;
|
||||
if (_validator) {
|
||||
validator = _validator->prepare(db, keyspace());
|
||||
}
|
||||
shared_ptr<column_identifier> column_name;
|
||||
const column_definition* def = nullptr;
|
||||
if (_raw_column_name) {
|
||||
column_name = _raw_column_name->prepare_column_identifier(schema);
|
||||
def = get_column_definition(schema, *column_name);
|
||||
}
|
||||
|
||||
switch (_type) {
|
||||
case alter_table_statement::type::add:
|
||||
{
|
||||
assert(column_name);
|
||||
if (schema->is_dense()) {
|
||||
throw exceptions::invalid_request_exception("Cannot add new column to a COMPACT STORAGE table");
|
||||
}
|
||||
|
||||
if (_is_static) {
|
||||
if (!schema->is_compound()) {
|
||||
throw exceptions::invalid_request_exception("Static columns are not allowed in COMPACT STORAGE tables");
|
||||
}
|
||||
if (!schema->clustering_key_size()) {
|
||||
throw exceptions::invalid_request_exception("Static columns are only useful (and thus allowed) if the table has at least one clustering column");
|
||||
}
|
||||
}
|
||||
|
||||
if (def) {
|
||||
if (def->is_partition_key()) {
|
||||
throw exceptions::invalid_request_exception(sprint("Invalid column name %s because it conflicts with a PRIMARY KEY part", column_name));
|
||||
} else {
|
||||
throw exceptions::invalid_request_exception(sprint("Invalid column name %s because it conflicts with an existing column", column_name));
|
||||
}
|
||||
}
|
||||
|
||||
// Cannot re-add a dropped counter column. See #7831.
|
||||
if (schema->is_counter() && schema->dropped_columns().count(column_name->text())) {
|
||||
throw exceptions::invalid_request_exception(sprint("Cannot re-add previously dropped counter column %s", column_name));
|
||||
}
|
||||
|
||||
auto type = validator->get_type();
|
||||
if (type->is_collection() && type->is_multi_cell()) {
|
||||
if (!schema->is_compound()) {
|
||||
throw exceptions::invalid_request_exception("Cannot use non-frozen collections with a non-composite PRIMARY KEY");
|
||||
}
|
||||
if (schema->is_super()) {
|
||||
throw exceptions::invalid_request_exception("Cannot use non-frozen collections with super column families");
|
||||
}
|
||||
}
|
||||
|
||||
cfm.with_column(column_name->name(), type, _is_static ? column_kind::static_column : column_kind::regular_column);
|
||||
break;
|
||||
}
|
||||
case alter_table_statement::type::alter:
|
||||
{
|
||||
assert(column_name);
|
||||
if (!def) {
|
||||
throw exceptions::invalid_request_exception(sprint("Column %s was not found in table %s", column_name, column_family()));
|
||||
}
|
||||
|
||||
auto type = validator->get_type();
|
||||
switch (def->kind) {
|
||||
case column_kind::partition_key:
|
||||
if (type->is_counter()) {
|
||||
throw exceptions::invalid_request_exception(sprint("counter type is not supported for PRIMARY KEY part %s", column_name));
|
||||
}
|
||||
|
||||
if (!type->is_value_compatible_with(*def->type)) {
|
||||
throw exceptions::configuration_exception(sprint("Cannot change %s from type %s to type %s: types are incompatible.",
|
||||
column_name,
|
||||
def->type->as_cql3_type(),
|
||||
validator));
|
||||
}
|
||||
break;
|
||||
|
||||
case column_kind::clustering_key:
|
||||
if (!schema->is_cql3_table()) {
|
||||
throw exceptions::invalid_request_exception(sprint("Cannot alter clustering column %s in a non-CQL3 table", column_name));
|
||||
}
|
||||
|
||||
// Note that CFMetaData.validateCompatibility already validate the change we're about to do. However, the error message it
|
||||
// sends is a bit cryptic for a CQL3 user, so validating here for a sake of returning a better error message
|
||||
// Do note that we need isCompatibleWith here, not just isValueCompatibleWith.
|
||||
if (!type->is_compatible_with(*def->type)) {
|
||||
throw exceptions::configuration_exception(sprint("Cannot change %s from type %s to type %s: types are not order-compatible.",
|
||||
column_name,
|
||||
def->type->as_cql3_type(),
|
||||
validator));
|
||||
}
|
||||
break;
|
||||
|
||||
case column_kind::compact_column:
|
||||
case column_kind::regular_column:
|
||||
case column_kind::static_column:
|
||||
// Thrift allows to change a column validator so CFMetaData.validateCompatibility will let it slide
|
||||
// if we change to an incompatible type (contrarily to the comparator case). But we don't want to
|
||||
// allow it for CQL3 (see #5882) so validating it explicitly here. We only care about value compatibility
|
||||
// though since we won't compare values (except when there is an index, but that is validated by
|
||||
// ColumnDefinition already).
|
||||
if (!type->is_value_compatible_with(*def->type)) {
|
||||
throw exceptions::configuration_exception(sprint("Cannot change %s from type %s to type %s: types are incompatible.",
|
||||
column_name,
|
||||
def->type->as_cql3_type(),
|
||||
validator));
|
||||
}
|
||||
break;
|
||||
}
|
||||
// In any case, we update the column definition
|
||||
cfm.with_altered_column_type(column_name->name(), type);
|
||||
break;
|
||||
}
|
||||
case alter_table_statement::type::drop:
|
||||
assert(column_name);
|
||||
if (!schema->is_cql3_table()) {
|
||||
throw exceptions::invalid_request_exception("Cannot drop columns from a non-CQL3 table");
|
||||
}
|
||||
if (!def) {
|
||||
throw exceptions::invalid_request_exception(sprint("Column %s was not found in table %s", column_name, column_family()));
|
||||
}
|
||||
|
||||
if (def->is_primary_key()) {
|
||||
throw exceptions::invalid_request_exception(sprint("Cannot drop PRIMARY KEY part %s", column_name));
|
||||
} else {
|
||||
for (auto&& column_def : boost::range::join(schema->static_columns(), schema->regular_columns())) { // find
|
||||
if (column_def.name() == column_name->name()) {
|
||||
cfm.without_column(column_name->name());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case alter_table_statement::type::opts:
|
||||
if (!_properties) {
|
||||
throw exceptions::invalid_request_exception("ALTER COLUMNFAMILY WITH invoked, but no parameters found");
|
||||
}
|
||||
|
||||
_properties->validate();
|
||||
|
||||
if (schema->is_counter() && _properties->get_default_time_to_live() > 0) {
|
||||
throw exceptions::invalid_request_exception("Cannot set default_time_to_live on a table with counters");
|
||||
}
|
||||
|
||||
_properties->apply_to_builder(cfm);
|
||||
break;
|
||||
|
||||
case alter_table_statement::type::rename:
|
||||
for (auto&& entry : _renames) {
|
||||
auto from = entry.first->prepare_column_identifier(schema);
|
||||
auto to = entry.second->prepare_column_identifier(schema);
|
||||
|
||||
auto def = schema->get_column_definition(from->name());
|
||||
if (!def) {
|
||||
throw exceptions::invalid_request_exception(sprint("Cannot rename unknown column %s in table %s", from, column_family()));
|
||||
}
|
||||
|
||||
if (schema->get_column_definition(to->name())) {
|
||||
throw exceptions::invalid_request_exception(sprint("Cannot rename column %s to %s in table %s; another column of that name already exist", from, to, column_family()));
|
||||
}
|
||||
|
||||
if (def->is_part_of_cell_name()) {
|
||||
throw exceptions::invalid_request_exception(sprint("Cannot rename non PRIMARY KEY part %s", from));
|
||||
}
|
||||
|
||||
if (def->is_indexed()) {
|
||||
throw exceptions::invalid_request_exception(sprint("Cannot rename column %s because it is secondary indexed", from));
|
||||
}
|
||||
|
||||
cfm.with_column_rename(from->name(), to->name());
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return service::get_local_migration_manager().announce_column_family_update(cfm.build(), false, is_local_only).then([] {
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
shared_ptr<transport::event::schema_change> alter_table_statement::change_event()
|
||||
{
|
||||
return make_shared<transport::event::schema_change>(transport::event::schema_change::change_type::UPDATED,
|
||||
transport::event::schema_change::target_type::TABLE, keyspace(), column_family());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,87 +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 2015 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 "cql3/statements/schema_altering_statement.hh"
|
||||
#include "cql3/statements/cf_prop_defs.hh"
|
||||
#include "cql3/cql3_type.hh"
|
||||
|
||||
namespace cql3 {
|
||||
|
||||
namespace statements {
|
||||
|
||||
class alter_table_statement : public schema_altering_statement {
|
||||
public:
|
||||
enum class type {
|
||||
add,
|
||||
alter,
|
||||
drop,
|
||||
opts,
|
||||
rename,
|
||||
};
|
||||
using renames_type = std::vector<std::pair<shared_ptr<column_identifier::raw>,
|
||||
shared_ptr<column_identifier::raw>>>;
|
||||
private:
|
||||
const type _type;
|
||||
const shared_ptr<column_identifier::raw> _raw_column_name;
|
||||
const shared_ptr<cql3_type::raw> _validator;
|
||||
const shared_ptr<cf_prop_defs> _properties;
|
||||
const renames_type _renames;
|
||||
const bool _is_static;
|
||||
public:
|
||||
alter_table_statement(shared_ptr<cf_name> name,
|
||||
type t,
|
||||
shared_ptr<column_identifier::raw> column_name,
|
||||
shared_ptr<cql3_type::raw> validator,
|
||||
shared_ptr<cf_prop_defs> properties,
|
||||
renames_type renames,
|
||||
bool is_static);
|
||||
|
||||
virtual void check_access(const service::client_state& state) override;
|
||||
virtual void validate(distributed<service::storage_proxy>& proxy, const service::client_state& state) override;
|
||||
virtual future<bool> announce_migration(distributed<service::storage_proxy>& proxy, bool is_local_only) override;
|
||||
virtual shared_ptr<transport::event::schema_change> change_event() override;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -38,7 +38,6 @@
|
||||
*/
|
||||
|
||||
#include "batch_statement.hh"
|
||||
#include "db/config.hh"
|
||||
|
||||
namespace cql3 {
|
||||
|
||||
@@ -56,50 +55,6 @@ bool batch_statement::depends_on_column_family(const sstring& cf_name) const
|
||||
return false;
|
||||
}
|
||||
|
||||
void batch_statement::verify_batch_size(const std::vector<mutation>& mutations) {
|
||||
size_t warn_threshold = service::get_local_storage_proxy().get_db().local().get_config().batch_size_warn_threshold_in_kb();
|
||||
|
||||
class my_partition_visitor : public mutation_partition_visitor {
|
||||
public:
|
||||
void accept_partition_tombstone(tombstone) override {}
|
||||
void accept_static_cell(column_id, atomic_cell_view v) override {
|
||||
size += v.value().size();
|
||||
}
|
||||
void accept_static_cell(column_id, collection_mutation_view v) override {
|
||||
size += v.data.size();
|
||||
}
|
||||
void accept_row_tombstone(clustering_key_prefix_view, tombstone) override {}
|
||||
void accept_row(clustering_key_view, tombstone, const row_marker&) override {}
|
||||
void accept_row_cell(column_id, atomic_cell_view v) override {
|
||||
size += v.value().size();
|
||||
}
|
||||
void accept_row_cell(column_id id, collection_mutation_view v) override {
|
||||
size += v.data.size();
|
||||
}
|
||||
|
||||
size_t size = 0;
|
||||
};
|
||||
|
||||
my_partition_visitor v;
|
||||
|
||||
for (auto&m : mutations) {
|
||||
m.partition().accept(*m.schema(), v);
|
||||
}
|
||||
|
||||
auto size = v.size / 1024;
|
||||
|
||||
if (v.size > warn_threshold) {
|
||||
std::unordered_set<sstring> ks_cf_pairs;
|
||||
for (auto&& m : mutations) {
|
||||
ks_cf_pairs.insert(m.schema()->ks_name() + "." + m.schema()->cf_name());
|
||||
}
|
||||
_logger.warn(
|
||||
"Batch of prepared statements for {} is of size {}, exceeding specified threshold of {} by {}.{}",
|
||||
join(", ", ks_cf_pairs), size, warn_threshold,
|
||||
size - warn_threshold, "");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -196,8 +196,27 @@ public:
|
||||
* Checks batch size to ensure threshold is met. If not, a warning is logged.
|
||||
* @param cfs ColumnFamilies that will store the batch's mutations.
|
||||
*/
|
||||
static void verify_batch_size(const std::vector<mutation>& mutations);
|
||||
static void verify_batch_size(const std::vector<mutation>& mutations) {
|
||||
size_t warn_threshold = 1000; // FIXME: database_descriptor::get_batch_size_warn_threshold();
|
||||
size_t fail_threshold = 2000; // FIXME: database_descriptor::get_batch_size_fail_threshold();
|
||||
|
||||
size_t size = mutations.size();
|
||||
|
||||
if (size > warn_threshold) {
|
||||
std::unordered_set<sstring> ks_cf_pairs;
|
||||
for (auto&& m : mutations) {
|
||||
ks_cf_pairs.insert(m.schema()->ks_name() + "." + m.schema()->cf_name());
|
||||
}
|
||||
const char* format = "Batch of prepared statements for {} is of size {}, exceeding specified threshold of {} by {}.{}";
|
||||
if (size > fail_threshold) {
|
||||
// FIXME: Tracing.trace(format, new Object[] {ksCfPairs, size, failThreshold, size - failThreshold, " (see batch_size_fail_threshold_in_kb)"});
|
||||
_logger.error(format, join(", ", ks_cf_pairs), size, fail_threshold, size - fail_threshold, " (see batch_size_fail_threshold_in_kb)");
|
||||
throw exceptions::invalid_request_exception("Batch too large");
|
||||
} else {
|
||||
_logger.warn(format, join(", ", ks_cf_pairs), size, warn_threshold, size - warn_threshold, "");
|
||||
}
|
||||
}
|
||||
}
|
||||
virtual future<shared_ptr<transport::messages::result_message>> execute(
|
||||
distributed<service::storage_proxy>& storage, service::query_state& state, const query_options& options) override {
|
||||
return execute(storage, state, options, false, options.get_timestamp(state));
|
||||
|
||||
@@ -139,11 +139,6 @@ std::map<sstring, sstring> cf_prop_defs::get_compression_options() const {
|
||||
return std::map<sstring, sstring>{};
|
||||
}
|
||||
|
||||
int32_t cf_prop_defs::get_default_time_to_live() const
|
||||
{
|
||||
return get_int(KW_DEFAULT_TIME_TO_LIVE, 0);
|
||||
}
|
||||
|
||||
void cf_prop_defs::apply_to_builder(schema_builder& builder) {
|
||||
if (has_property(KW_COMMENT)) {
|
||||
builder.set_comment(get_string(KW_COMMENT, ""));
|
||||
|
||||
@@ -100,8 +100,6 @@ public:
|
||||
return options;
|
||||
}
|
||||
#endif
|
||||
int32_t get_default_time_to_live() const;
|
||||
|
||||
void apply_to_builder(schema_builder& builder);
|
||||
void validate_minimum_int(const sstring& field, int32_t minimum_value, int32_t default_value) const;
|
||||
};
|
||||
|
||||
@@ -81,7 +81,7 @@ cql3::statements::create_index_statement::validate(distributed<service::storage_
|
||||
auto cd = schema->get_column_definition(target->column->name());
|
||||
|
||||
if (cd == nullptr) {
|
||||
throw exceptions::invalid_request_exception(sprint("No column definition found for column %s", *target->column));
|
||||
throw exceptions::invalid_request_exception(sprint("No column definition found for column %s", target->column->name()));
|
||||
}
|
||||
|
||||
bool is_map = dynamic_cast<const collection_type_impl *>(cd->type.get()) != nullptr
|
||||
@@ -93,7 +93,7 @@ cql3::statements::create_index_statement::validate(distributed<service::storage_
|
||||
throw exceptions::invalid_request_exception(
|
||||
sprint("Cannot create index on %s of frozen<map> column %s",
|
||||
index_target::index_option(target->type),
|
||||
*target->column));
|
||||
target->column->name()));
|
||||
}
|
||||
} else {
|
||||
// validateNotFullIndex
|
||||
@@ -107,7 +107,7 @@ cql3::statements::create_index_statement::validate(distributed<service::storage_
|
||||
sprint(
|
||||
"Cannot create index on %s of column %s; only non-frozen collections support %s indexes",
|
||||
index_target::index_option(target->type),
|
||||
*target->column,
|
||||
target->column->name(),
|
||||
index_target::index_option(target->type)));
|
||||
}
|
||||
// validateTargetColumnIsMapIfIndexInvolvesKeys
|
||||
@@ -118,7 +118,7 @@ cql3::statements::create_index_statement::validate(distributed<service::storage_
|
||||
sprint(
|
||||
"Cannot create index on %s of column %s with non-map type",
|
||||
index_target::index_option(target->type),
|
||||
*target->column));
|
||||
target->column->name()));
|
||||
|
||||
}
|
||||
}
|
||||
@@ -132,9 +132,9 @@ cql3::statements::create_index_statement::validate(distributed<service::storage_
|
||||
"Cannot create index on %s(%s): an index on %s(%s) already exists and indexing "
|
||||
"a map on more than one dimension at the same time is not currently supported",
|
||||
index_target::index_option(target->type),
|
||||
*target->column,
|
||||
target->column->name(),
|
||||
index_target::index_option(prev_type),
|
||||
*target->column));
|
||||
target->column->name()));
|
||||
}
|
||||
if (_if_not_exists) {
|
||||
return;
|
||||
@@ -164,13 +164,12 @@ cql3::statements::create_index_statement::validate(distributed<service::storage_
|
||||
throw exceptions::invalid_request_exception(
|
||||
sprint(
|
||||
"Cannot create secondary index on partition key column %s",
|
||||
*target->column));
|
||||
target->column->name()));
|
||||
}
|
||||
}
|
||||
|
||||
future<bool>
|
||||
cql3::statements::create_index_statement::announce_migration(distributed<service::storage_proxy>& proxy, bool is_local_only) {
|
||||
throw std::runtime_error("Indexes are not supported yet");
|
||||
auto schema = proxy.local().get_db().local().find_schema(keyspace(), column_family());
|
||||
auto target = _raw_target->prepare(schema);
|
||||
|
||||
|
||||
@@ -270,7 +270,7 @@ modification_statement::read_required_rows(
|
||||
for (auto&& pk : *keys) {
|
||||
pr.emplace_back(dht::global_partitioner().decorate_key(*s, pk));
|
||||
}
|
||||
query::read_command cmd(s->id(), s->version(), ps, std::numeric_limits<uint32_t>::max());
|
||||
query::read_command cmd(s->id(), ps, std::numeric_limits<uint32_t>::max());
|
||||
// FIXME: ignoring "local"
|
||||
return proxy.local().query(s, make_lw_shared(std::move(cmd)), std::move(pr), cl).then([this, ps] (auto result) {
|
||||
// FIXME: copying
|
||||
|
||||
@@ -218,8 +218,7 @@ select_statement::execute(distributed<service::storage_proxy>& proxy, service::q
|
||||
int32_t limit = get_limit(options);
|
||||
auto now = db_clock::now();
|
||||
|
||||
auto command = ::make_lw_shared<query::read_command>(_schema->id(), _schema->version(),
|
||||
make_partition_slice(options), limit, to_gc_clock(now));
|
||||
auto command = ::make_lw_shared<query::read_command>(_schema->id(), make_partition_slice(options), limit, to_gc_clock(now));
|
||||
|
||||
int32_t page_size = options.get_page_size();
|
||||
|
||||
@@ -309,8 +308,7 @@ future<::shared_ptr<transport::messages::result_message>>
|
||||
select_statement::execute_internal(distributed<service::storage_proxy>& proxy, service::query_state& state, const query_options& options) {
|
||||
int32_t limit = get_limit(options);
|
||||
auto now = db_clock::now();
|
||||
auto command = ::make_lw_shared<query::read_command>(_schema->id(), _schema->version(),
|
||||
make_partition_slice(options), limit);
|
||||
auto command = ::make_lw_shared<query::read_command>(_schema->id(), make_partition_slice(options), limit);
|
||||
auto partition_ranges = _restrictions->get_partition_key_ranges(options);
|
||||
|
||||
if (needs_post_query_ordering() && _limit) {
|
||||
|
||||
216
database.cc
216
database.cc
@@ -57,7 +57,6 @@
|
||||
#include <seastar/core/enum.hh>
|
||||
#include "utils/latency.hh"
|
||||
#include "utils/flush_queue.hh"
|
||||
#include "schema_registry.hh"
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
@@ -127,8 +126,8 @@ column_family::make_partition_presence_checker(lw_shared_ptr<sstable_list> old_s
|
||||
|
||||
mutation_source
|
||||
column_family::sstables_as_mutation_source() {
|
||||
return [this] (schema_ptr s, const query::partition_range& r) {
|
||||
return make_sstable_reader(std::move(s), r);
|
||||
return [this] (const query::partition_range& r) {
|
||||
return make_sstable_reader(r);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -207,16 +206,16 @@ public:
|
||||
};
|
||||
|
||||
mutation_reader
|
||||
column_family::make_sstable_reader(schema_ptr s, const query::partition_range& pr) const {
|
||||
column_family::make_sstable_reader(const query::partition_range& pr) const {
|
||||
if (pr.is_singular() && pr.start()->value().has_key()) {
|
||||
const dht::ring_position& pos = pr.start()->value();
|
||||
if (dht::shard_of(pos.token()) != engine().cpu_id()) {
|
||||
return make_empty_reader(); // range doesn't belong to this shard
|
||||
}
|
||||
return make_mutation_reader<single_key_sstable_reader>(std::move(s), _sstables, *pos.key());
|
||||
return make_mutation_reader<single_key_sstable_reader>(_schema, _sstables, *pos.key());
|
||||
} else {
|
||||
// range_sstable_reader is not movable so we need to wrap it
|
||||
return make_mutation_reader<range_sstable_reader>(std::move(s), _sstables, pr);
|
||||
return make_mutation_reader<range_sstable_reader>(_schema, _sstables, pr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -240,9 +239,9 @@ key_source column_family::sstables_as_key_source() const {
|
||||
|
||||
// Exposed for testing, not performance critical.
|
||||
future<column_family::const_mutation_partition_ptr>
|
||||
column_family::find_partition(schema_ptr s, const dht::decorated_key& key) const {
|
||||
return do_with(query::partition_range::make_singular(key), [s = std::move(s), this] (auto& range) {
|
||||
return do_with(this->make_reader(s, range), [] (mutation_reader& reader) {
|
||||
column_family::find_partition(const dht::decorated_key& key) const {
|
||||
return do_with(query::partition_range::make_singular(key), [this] (auto& range) {
|
||||
return do_with(this->make_reader(range), [] (mutation_reader& reader) {
|
||||
return reader().then([] (mutation_opt&& mo) -> std::unique_ptr<const mutation_partition> {
|
||||
if (!mo) {
|
||||
return {};
|
||||
@@ -254,13 +253,13 @@ column_family::find_partition(schema_ptr s, const dht::decorated_key& key) const
|
||||
}
|
||||
|
||||
future<column_family::const_mutation_partition_ptr>
|
||||
column_family::find_partition_slow(schema_ptr s, const partition_key& key) const {
|
||||
return find_partition(s, dht::global_partitioner().decorate_key(*s, key));
|
||||
column_family::find_partition_slow(const partition_key& key) const {
|
||||
return find_partition(dht::global_partitioner().decorate_key(*_schema, key));
|
||||
}
|
||||
|
||||
future<column_family::const_row_ptr>
|
||||
column_family::find_row(schema_ptr s, const dht::decorated_key& partition_key, clustering_key clustering_key) const {
|
||||
return find_partition(std::move(s), partition_key).then([clustering_key = std::move(clustering_key)] (const_mutation_partition_ptr p) {
|
||||
column_family::find_row(const dht::decorated_key& partition_key, clustering_key clustering_key) const {
|
||||
return find_partition(partition_key).then([clustering_key = std::move(clustering_key)] (const_mutation_partition_ptr p) {
|
||||
if (!p) {
|
||||
return make_ready_future<const_row_ptr>();
|
||||
}
|
||||
@@ -275,8 +274,8 @@ column_family::find_row(schema_ptr s, const dht::decorated_key& partition_key, c
|
||||
}
|
||||
|
||||
mutation_reader
|
||||
column_family::make_reader(schema_ptr s, const query::partition_range& range) const {
|
||||
if (query::is_wrap_around(range, *s)) {
|
||||
column_family::make_reader(const query::partition_range& range) const {
|
||||
if (query::is_wrap_around(range, *_schema)) {
|
||||
// make_combined_reader() can't handle streams that wrap around yet.
|
||||
fail(unimplemented::cause::WRAP_AROUND);
|
||||
}
|
||||
@@ -305,13 +304,13 @@ column_family::make_reader(schema_ptr s, const query::partition_range& range) co
|
||||
// https://github.com/scylladb/scylla/issues/185
|
||||
|
||||
for (auto&& mt : *_memtables) {
|
||||
readers.emplace_back(mt->make_reader(s, range));
|
||||
readers.emplace_back(mt->make_reader(range));
|
||||
}
|
||||
|
||||
if (_config.enable_cache) {
|
||||
readers.emplace_back(_cache.make_reader(s, range));
|
||||
readers.emplace_back(_cache.make_reader(range));
|
||||
} else {
|
||||
readers.emplace_back(make_sstable_reader(s, range));
|
||||
readers.emplace_back(make_sstable_reader(range));
|
||||
}
|
||||
|
||||
return make_combined_reader(std::move(readers));
|
||||
@@ -319,7 +318,7 @@ column_family::make_reader(schema_ptr s, const query::partition_range& range) co
|
||||
|
||||
template <typename Func>
|
||||
future<bool>
|
||||
column_family::for_all_partitions(schema_ptr s, Func&& func) const {
|
||||
column_family::for_all_partitions(Func&& func) const {
|
||||
static_assert(std::is_same<bool, std::result_of_t<Func(const dht::decorated_key&, const mutation_partition&)>>::value,
|
||||
"bad Func signature");
|
||||
|
||||
@@ -330,13 +329,13 @@ column_family::for_all_partitions(schema_ptr s, Func&& func) const {
|
||||
bool empty = false;
|
||||
public:
|
||||
bool done() const { return !ok || empty; }
|
||||
iteration_state(schema_ptr s, const column_family& cf, Func&& func)
|
||||
: reader(cf.make_reader(std::move(s)))
|
||||
iteration_state(const column_family& cf, Func&& func)
|
||||
: reader(cf.make_reader())
|
||||
, func(std::move(func))
|
||||
{ }
|
||||
};
|
||||
|
||||
return do_with(iteration_state(std::move(s), *this, std::move(func)), [] (iteration_state& is) {
|
||||
return do_with(iteration_state(*this, std::move(func)), [] (iteration_state& is) {
|
||||
return do_until([&is] { return is.done(); }, [&is] {
|
||||
return is.reader().then([&is](mutation_opt&& mo) {
|
||||
if (!mo) {
|
||||
@@ -352,39 +351,30 @@ column_family::for_all_partitions(schema_ptr s, Func&& func) const {
|
||||
}
|
||||
|
||||
future<bool>
|
||||
column_family::for_all_partitions_slow(schema_ptr s, std::function<bool (const dht::decorated_key&, const mutation_partition&)> func) const {
|
||||
return for_all_partitions(std::move(s), std::move(func));
|
||||
column_family::for_all_partitions_slow(std::function<bool (const dht::decorated_key&, const mutation_partition&)> func) const {
|
||||
return for_all_partitions(std::move(func));
|
||||
}
|
||||
|
||||
class lister {
|
||||
public:
|
||||
using dir_entry_types = std::unordered_set<directory_entry_type, enum_hash<directory_entry_type>>;
|
||||
using walker_type = std::function<future<> (directory_entry)>;
|
||||
using filter_type = std::function<bool (const sstring&)>;
|
||||
private:
|
||||
file _f;
|
||||
walker_type _walker;
|
||||
filter_type _filter;
|
||||
std::function<future<> (directory_entry de)> _walker;
|
||||
dir_entry_types _expected_type;
|
||||
subscription<directory_entry> _listing;
|
||||
sstring _dirname;
|
||||
|
||||
public:
|
||||
lister(file f, dir_entry_types type, walker_type walker, sstring dirname)
|
||||
lister(file f, dir_entry_types type, std::function<future<> (directory_entry)> walker, sstring dirname)
|
||||
: _f(std::move(f))
|
||||
, _walker(std::move(walker))
|
||||
, _filter([] (const sstring& fname) { return true; })
|
||||
, _expected_type(type)
|
||||
, _listing(_f.list_directory([this] (directory_entry de) { return _visit(de); }))
|
||||
, _dirname(dirname) {
|
||||
}
|
||||
|
||||
lister(file f, dir_entry_types type, walker_type walker, filter_type filter, sstring dirname)
|
||||
: lister(std::move(f), type, std::move(walker), dirname) {
|
||||
_filter = std::move(filter);
|
||||
}
|
||||
|
||||
static future<> scan_dir(sstring name, dir_entry_types type, walker_type walker, filter_type filter = [] (const sstring& fname) { return true; });
|
||||
static future<> scan_dir(sstring name, dir_entry_types type, std::function<future<> (directory_entry)> walker);
|
||||
protected:
|
||||
future<> _visit(directory_entry de) {
|
||||
|
||||
@@ -393,12 +383,6 @@ protected:
|
||||
if ((!_expected_type.count(*(de.type))) || (de.name[0] == '.')) {
|
||||
return make_ready_future<>();
|
||||
}
|
||||
|
||||
// apply a filter
|
||||
if (!_filter(_dirname + "/" + de.name)) {
|
||||
return make_ready_future<>();
|
||||
}
|
||||
|
||||
return _walker(de);
|
||||
});
|
||||
|
||||
@@ -419,9 +403,9 @@ private:
|
||||
};
|
||||
|
||||
|
||||
future<> lister::scan_dir(sstring name, lister::dir_entry_types type, walker_type walker, filter_type filter) {
|
||||
return engine().open_directory(name).then([type, walker = std::move(walker), filter = std::move(filter), name] (file f) {
|
||||
auto l = make_lw_shared<lister>(std::move(f), type, walker, filter, name);
|
||||
future<> lister::scan_dir(sstring name, lister::dir_entry_types type, std::function<future<> (directory_entry)> walker) {
|
||||
return engine().open_directory(name).then([type, walker = std::move(walker), name] (file f) {
|
||||
auto l = make_lw_shared<lister>(std::move(f), type, walker, name);
|
||||
return l->done().then([l] { });
|
||||
});
|
||||
}
|
||||
@@ -469,9 +453,6 @@ future<sstables::entry_descriptor> column_family::probe_file(sstring sstdir, sst
|
||||
return std::move(fut).then([this, sstdir = std::move(sstdir), comps] (range<partition_key> r) {
|
||||
// Checks whether or not sstable belongs to current shard.
|
||||
if (!belongs_to_current_shard(*_schema, std::move(r))) {
|
||||
dblog.debug("sstable {} not relevant for this shard, ignoring",
|
||||
sstables::sstable::filename(sstdir, _schema->ks_name(), _schema->cf_name(), comps.version, comps.generation, comps.format,
|
||||
sstables::sstable::component_type::Data));
|
||||
sstable::mark_sstable_for_deletion(_schema->ks_name(), _schema->cf_name(), sstdir, comps.generation, comps.version, comps.format);
|
||||
return make_ready_future<>();
|
||||
}
|
||||
@@ -691,7 +672,7 @@ column_family::reshuffle_sstables(int64_t start) {
|
||||
// Those SSTables are not known by anyone in the system. So we don't have any kind of
|
||||
// object describing them. There isn't too much of a choice.
|
||||
return work.sstables[comps.generation]->read_toc();
|
||||
}, &manifest_json_filter).then([&work] {
|
||||
}).then([&work] {
|
||||
// Note: cannot be parallel because we will be shuffling things around at this stage. Can't race.
|
||||
return do_for_each(work.sstables, [&work] (auto& pair) {
|
||||
auto&& comps = std::move(work.descriptors.at(pair.first));
|
||||
@@ -857,17 +838,6 @@ lw_shared_ptr<sstable_list> column_family::get_sstables() {
|
||||
return _sstables;
|
||||
}
|
||||
|
||||
inline bool column_family::manifest_json_filter(const sstring& fname) {
|
||||
using namespace boost::filesystem;
|
||||
|
||||
path entry_path(fname);
|
||||
if (!is_directory(status(entry_path)) && entry_path.filename() == path("manifest.json")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
future<> column_family::populate(sstring sstdir) {
|
||||
// We can catch most errors when we try to load an sstable. But if the TOC
|
||||
// file is the one missing, we won't try to load the sstable at all. This
|
||||
@@ -929,7 +899,7 @@ future<> column_family::populate(sstring sstdir) {
|
||||
futures.push_back(std::move(f));
|
||||
|
||||
return make_ready_future<>();
|
||||
}, &manifest_json_filter).then([&futures] {
|
||||
}).then([&futures] {
|
||||
return when_all(futures.begin(), futures.end()).then([] (std::vector<future<>> ret) {
|
||||
try {
|
||||
for (auto& f : ret) {
|
||||
@@ -949,7 +919,7 @@ future<> column_family::populate(sstring sstdir) {
|
||||
sstables::sstable::format_types format = descriptor->format.value();
|
||||
|
||||
if (engine().cpu_id() != 0) {
|
||||
dblog.debug("At directory: {}, partial SSTable with generation {} not relevant for this shard, ignoring", sstdir, v.first);
|
||||
dblog.info("At directory: {}, partial SSTable with generation {} not relevant for this shard, ignoring", sstdir, v.first);
|
||||
return make_ready_future<>();
|
||||
}
|
||||
// shard 0 is the responsible for removing a partial sstable.
|
||||
@@ -976,6 +946,8 @@ database::database(const db::config& cfg)
|
||||
if (!_memtable_total_space) {
|
||||
_memtable_total_space = memory::stats().total_memory() / 2;
|
||||
}
|
||||
bool durable = cfg.data_file_directories().size() > 0;
|
||||
db::system_keyspace::make(*this, durable, _cfg->volatile_system_keyspace_for_testing());
|
||||
// Start compaction manager with two tasks for handling compaction jobs.
|
||||
_compaction_manager.start(2);
|
||||
setup_collectd();
|
||||
@@ -1118,9 +1090,6 @@ future<> database::parse_system_tables(distributed<service::storage_proxy>& prox
|
||||
|
||||
future<>
|
||||
database::init_system_keyspace() {
|
||||
bool durable = _cfg->data_file_directories().size() > 0;
|
||||
db::system_keyspace::make(*this, durable, _cfg->volatile_system_keyspace_for_testing());
|
||||
|
||||
// FIXME support multiple directories
|
||||
return touch_directory(_cfg->data_file_directories()[0] + "/" + db::system_keyspace::NAME).then([this] {
|
||||
return populate_keyspace(_cfg->data_file_directories()[0], db::system_keyspace::NAME).then([this]() {
|
||||
@@ -1186,8 +1155,6 @@ void database::drop_keyspace(const sstring& name) {
|
||||
}
|
||||
|
||||
void database::add_column_family(schema_ptr schema, column_family::config cfg) {
|
||||
schema = local_schema_registry().learn(schema);
|
||||
schema->registry_entry()->mark_synced();
|
||||
auto uuid = schema->id();
|
||||
lw_shared_ptr<column_family> cf;
|
||||
if (cfg.enable_commitlog && _commitlog) {
|
||||
@@ -1213,6 +1180,17 @@ void database::add_column_family(schema_ptr schema, column_family::config cfg) {
|
||||
_ks_cf_to_uuid.emplace(std::move(kscf), uuid);
|
||||
}
|
||||
|
||||
future<> database::update_column_family(const sstring& ks_name, const sstring& cf_name) {
|
||||
auto& proxy = service::get_storage_proxy();
|
||||
auto old_cfm = find_schema(ks_name, cf_name);
|
||||
return db::schema_tables::create_table_from_name(proxy, ks_name, cf_name).then([old_cfm] (auto&& new_cfm) {
|
||||
if (old_cfm->id() != new_cfm->id()) {
|
||||
return make_exception_future<>(exceptions::configuration_exception(sprint("Column family ID mismatch (found %s; expected %s)", new_cfm->id(), old_cfm->id())));
|
||||
}
|
||||
return make_exception_future<>(std::runtime_error("update column family not implemented"));
|
||||
});
|
||||
}
|
||||
|
||||
future<> database::drop_column_family(db_clock::time_point dropped_at, const sstring& ks_name, const sstring& cf_name) {
|
||||
auto uuid = find_uuid(ks_name, cf_name);
|
||||
auto& ks = find_keyspace(ks_name);
|
||||
@@ -1476,17 +1454,13 @@ compare_atomic_cell_for_merge(atomic_cell_view left, atomic_cell_view right) {
|
||||
}
|
||||
|
||||
struct query_state {
|
||||
explicit query_state(schema_ptr s,
|
||||
const query::read_command& cmd,
|
||||
const std::vector<query::partition_range>& ranges)
|
||||
: schema(std::move(s))
|
||||
, cmd(cmd)
|
||||
explicit query_state(const query::read_command& cmd, const std::vector<query::partition_range>& ranges)
|
||||
: cmd(cmd)
|
||||
, builder(cmd.slice)
|
||||
, limit(cmd.row_limit)
|
||||
, current_partition_range(ranges.begin())
|
||||
, range_end(ranges.end()){
|
||||
}
|
||||
schema_ptr schema;
|
||||
const query::read_command& cmd;
|
||||
query::result::builder builder;
|
||||
uint32_t limit;
|
||||
@@ -1500,21 +1474,21 @@ struct query_state {
|
||||
};
|
||||
|
||||
future<lw_shared_ptr<query::result>>
|
||||
column_family::query(schema_ptr s, const query::read_command& cmd, const std::vector<query::partition_range>& partition_ranges) {
|
||||
column_family::query(const query::read_command& cmd, const std::vector<query::partition_range>& partition_ranges) {
|
||||
utils::latency_counter lc;
|
||||
_stats.reads.set_latency(lc);
|
||||
return do_with(query_state(std::move(s), cmd, partition_ranges), [this] (query_state& qs) {
|
||||
return do_with(query_state(cmd, partition_ranges), [this] (query_state& qs) {
|
||||
return do_until(std::bind(&query_state::done, &qs), [this, &qs] {
|
||||
auto&& range = *qs.current_partition_range++;
|
||||
qs.reader = make_reader(qs.schema, range);
|
||||
qs.reader = make_reader(range);
|
||||
qs.range_empty = false;
|
||||
return do_until([&qs] { return !qs.limit || qs.range_empty; }, [&qs] {
|
||||
return qs.reader().then([&qs](mutation_opt mo) {
|
||||
return do_until([&qs] { return !qs.limit || qs.range_empty; }, [this, &qs] {
|
||||
return qs.reader().then([this, &qs](mutation_opt mo) {
|
||||
if (mo) {
|
||||
auto p_builder = qs.builder.add_partition(*mo->schema(), mo->key());
|
||||
auto is_distinct = qs.cmd.slice.options.contains(query::partition_slice::option::distinct);
|
||||
auto limit = !is_distinct ? qs.limit : 1;
|
||||
mo->partition().query(p_builder, *qs.schema, qs.cmd.timestamp, limit);
|
||||
mo->partition().query(p_builder, *_schema, qs.cmd.timestamp, limit);
|
||||
qs.limit -= p_builder.row_count();
|
||||
} else {
|
||||
qs.range_empty = true;
|
||||
@@ -1535,21 +1509,21 @@ column_family::query(schema_ptr s, const query::read_command& cmd, const std::ve
|
||||
|
||||
mutation_source
|
||||
column_family::as_mutation_source() const {
|
||||
return [this] (schema_ptr s, const query::partition_range& range) {
|
||||
return this->make_reader(std::move(s), range);
|
||||
return [this] (const query::partition_range& range) {
|
||||
return this->make_reader(range);
|
||||
};
|
||||
}
|
||||
|
||||
future<lw_shared_ptr<query::result>>
|
||||
database::query(schema_ptr s, const query::read_command& cmd, const std::vector<query::partition_range>& ranges) {
|
||||
database::query(const query::read_command& cmd, const std::vector<query::partition_range>& ranges) {
|
||||
column_family& cf = find_column_family(cmd.cf_id);
|
||||
return cf.query(std::move(s), cmd, ranges);
|
||||
return cf.query(cmd, ranges);
|
||||
}
|
||||
|
||||
future<reconcilable_result>
|
||||
database::query_mutations(schema_ptr s, const query::read_command& cmd, const query::partition_range& range) {
|
||||
database::query_mutations(const query::read_command& cmd, const query::partition_range& range) {
|
||||
column_family& cf = find_column_family(cmd.cf_id);
|
||||
return mutation_query(std::move(s), cf.as_mutation_source(), range, cmd.slice, cmd.row_limit, cmd.timestamp);
|
||||
return mutation_query(cf.as_mutation_source(), range, cmd.slice, cmd.row_limit, cmd.timestamp);
|
||||
}
|
||||
|
||||
std::unordered_set<sstring> database::get_initial_tokens() {
|
||||
@@ -1613,32 +1587,28 @@ std::ostream& operator<<(std::ostream& out, const database& db) {
|
||||
return out;
|
||||
}
|
||||
|
||||
future<> database::apply_in_memory(const frozen_mutation& m, const schema_ptr& m_schema, const db::replay_position& rp) {
|
||||
future<> database::apply_in_memory(const frozen_mutation& m, const db::replay_position& rp) {
|
||||
try {
|
||||
auto& cf = find_column_family(m.column_family_id());
|
||||
cf.apply(m, m_schema, rp);
|
||||
cf.apply(m, rp);
|
||||
} catch (no_such_column_family&) {
|
||||
dblog.error("Attempting to mutate non-existent table {}", m.column_family_id());
|
||||
}
|
||||
return make_ready_future<>();
|
||||
}
|
||||
|
||||
future<> database::do_apply(schema_ptr s, const frozen_mutation& m) {
|
||||
future<> database::do_apply(const frozen_mutation& m) {
|
||||
// I'm doing a nullcheck here since the init code path for db etc
|
||||
// is a little in flux and commitlog is created only when db is
|
||||
// initied from datadir.
|
||||
auto uuid = m.column_family_id();
|
||||
auto& cf = find_column_family(uuid);
|
||||
if (!s->is_synced()) {
|
||||
throw std::runtime_error(sprint("attempted to mutate using not synced schema of %s.%s, version=%s",
|
||||
s->ks_name(), s->cf_name(), s->version()));
|
||||
}
|
||||
auto& cf = find_column_family(m.column_family_id());
|
||||
if (cf.commitlog() != nullptr) {
|
||||
auto uuid = m.column_family_id();
|
||||
bytes_view repr = m.representation();
|
||||
auto write_repr = [repr] (data_output& out) { out.write(repr.begin(), repr.end()); };
|
||||
return cf.commitlog()->add_mutation(uuid, repr.size(), write_repr).then([&m, this, s](auto rp) {
|
||||
return cf.commitlog()->add_mutation(uuid, repr.size(), write_repr).then([&m, this](auto rp) {
|
||||
try {
|
||||
return this->apply_in_memory(m, s, rp);
|
||||
return this->apply_in_memory(m, rp);
|
||||
} catch (replay_position_reordered_exception&) {
|
||||
// expensive, but we're assuming this is super rare.
|
||||
// if we failed to apply the mutation due to future re-ordering
|
||||
@@ -1646,11 +1616,11 @@ future<> database::do_apply(schema_ptr s, const frozen_mutation& m) {
|
||||
// let's just try again, add the mutation to the CL once more,
|
||||
// and assume success in inevitable eventually.
|
||||
dblog.debug("replay_position reordering detected");
|
||||
return this->apply(s, m);
|
||||
return this->apply(m);
|
||||
}
|
||||
});
|
||||
}
|
||||
return apply_in_memory(m, s, db::replay_position());
|
||||
return apply_in_memory(m, db::replay_position());
|
||||
}
|
||||
|
||||
future<> database::throttle() {
|
||||
@@ -1684,9 +1654,9 @@ void database::unthrottle() {
|
||||
}
|
||||
}
|
||||
|
||||
future<> database::apply(schema_ptr s, const frozen_mutation& m) {
|
||||
return throttle().then([this, &m, s = std::move(s)] {
|
||||
return do_apply(std::move(s), m);
|
||||
future<> database::apply(const frozen_mutation& m) {
|
||||
return throttle().then([this, &m] {
|
||||
return do_apply(m);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1828,36 +1798,6 @@ const sstring& database::get_snitch_name() const {
|
||||
return _cfg->endpoint_snitch();
|
||||
}
|
||||
|
||||
// For the filesystem operations, this code will assume that all keyspaces are visible in all shards
|
||||
// (as we have been doing for a lot of the other operations, like the snapshot itself).
|
||||
future<> database::clear_snapshot(sstring tag, std::vector<sstring> keyspace_names) {
|
||||
std::vector<std::reference_wrapper<keyspace>> keyspaces;
|
||||
|
||||
if (keyspace_names.empty()) {
|
||||
// if keyspace names are not given - apply to all existing local keyspaces
|
||||
for (auto& ks: _keyspaces) {
|
||||
keyspaces.push_back(std::reference_wrapper<keyspace>(ks.second));
|
||||
}
|
||||
} else {
|
||||
for (auto& ksname: keyspace_names) {
|
||||
try {
|
||||
keyspaces.push_back(std::reference_wrapper<keyspace>(find_keyspace(ksname)));
|
||||
} catch (no_such_keyspace& e) {
|
||||
return make_exception_future(std::current_exception());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return parallel_for_each(keyspaces, [this, tag] (auto& ks) {
|
||||
return parallel_for_each(ks.get().metadata()->cf_meta_data(), [this, tag] (auto& pair) {
|
||||
auto& cf = this->find_column_family(pair.second);
|
||||
return cf.clear_snapshot(tag);
|
||||
}).then_wrapped([] (future<> f) {
|
||||
dblog.debug("Cleared out snapshot directories");
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
future<> update_schema_version_and_announce(distributed<service::storage_proxy>& proxy)
|
||||
{
|
||||
return db::schema_tables::calculate_schema_digest(proxy).then([&proxy] (utils::UUID uuid) {
|
||||
@@ -1922,7 +1862,7 @@ seal_snapshot(sstring jsondir) {
|
||||
dblog.debug("Storing manifest {}", jsonfile);
|
||||
|
||||
return recursive_touch_directory(jsondir).then([jsonfile, json = std::move(json)] {
|
||||
return open_file_dma(jsonfile, open_flags::wo | open_flags::create | open_flags::truncate).then([json](file f) {
|
||||
return engine().open_file_dma(jsonfile, open_flags::wo | open_flags::create | open_flags::truncate).then([json](file f) {
|
||||
return do_with(make_file_output_stream(std::move(f)), [json] (output_stream<char>& out) {
|
||||
return out.write(json.c_str(), json.size()).then([&out] {
|
||||
return out.flush();
|
||||
@@ -2227,15 +2167,3 @@ std::ostream& operator<<(std::ostream& os, const keyspace_metadata& m) {
|
||||
os << "}";
|
||||
return os;
|
||||
}
|
||||
|
||||
void column_family::set_schema(schema_ptr s) {
|
||||
dblog.debug("Changing schema version of {}.{} ({}) from {} to {}",
|
||||
_schema->ks_name(), _schema->cf_name(), _schema->id(), _schema->version(), s->version());
|
||||
|
||||
for (auto& m : *_memtables) {
|
||||
m->set_schema(s);
|
||||
}
|
||||
|
||||
_cache.set_schema(s);
|
||||
_schema = std::move(s);
|
||||
}
|
||||
|
||||
46
database.hh
46
database.hh
@@ -189,8 +189,7 @@ private:
|
||||
// Creates a mutation reader which covers sstables.
|
||||
// Caller needs to ensure that column_family remains live (FIXME: relax this).
|
||||
// The 'range' parameter must be live as long as the reader is used.
|
||||
// Mutations returned by the reader will all have given schema.
|
||||
mutation_reader make_sstable_reader(schema_ptr schema, const query::partition_range& range) const;
|
||||
mutation_reader make_sstable_reader(const query::partition_range& range) const;
|
||||
|
||||
mutation_source sstables_as_mutation_source();
|
||||
key_source sstables_as_key_source() const;
|
||||
@@ -201,8 +200,7 @@ public:
|
||||
// Caller needs to ensure that column_family remains live (FIXME: relax this).
|
||||
// Note: for data queries use query() instead.
|
||||
// The 'range' parameter must be live as long as the reader is used.
|
||||
// Mutations returned by the reader will all have given schema.
|
||||
mutation_reader make_reader(schema_ptr schema, const query::partition_range& range = query::full_partition_range) const;
|
||||
mutation_reader make_reader(const query::partition_range& range = query::full_partition_range) const;
|
||||
|
||||
mutation_source as_mutation_source() const;
|
||||
|
||||
@@ -227,21 +225,16 @@ public:
|
||||
column_family(schema_ptr schema, config cfg, no_commitlog, compaction_manager&);
|
||||
column_family(column_family&&) = delete; // 'this' is being captured during construction
|
||||
~column_family();
|
||||
const schema_ptr& schema() const { return _schema; }
|
||||
void set_schema(schema_ptr);
|
||||
schema_ptr schema() const { return _schema; }
|
||||
db::commitlog* commitlog() { return _commitlog; }
|
||||
future<const_mutation_partition_ptr> find_partition(schema_ptr, const dht::decorated_key& key) const;
|
||||
future<const_mutation_partition_ptr> find_partition_slow(schema_ptr, const partition_key& key) const;
|
||||
future<const_row_ptr> find_row(schema_ptr, const dht::decorated_key& partition_key, clustering_key clustering_key) const;
|
||||
// Applies given mutation to this column family
|
||||
// The mutation is always upgraded to current schema.
|
||||
void apply(const frozen_mutation& m, const schema_ptr& m_schema, const db::replay_position& = db::replay_position());
|
||||
future<const_mutation_partition_ptr> find_partition(const dht::decorated_key& key) const;
|
||||
future<const_mutation_partition_ptr> find_partition_slow(const partition_key& key) const;
|
||||
future<const_row_ptr> find_row(const dht::decorated_key& partition_key, clustering_key clustering_key) const;
|
||||
void apply(const frozen_mutation& m, const db::replay_position& = db::replay_position());
|
||||
void apply(const mutation& m, const db::replay_position& = db::replay_position());
|
||||
|
||||
// Returns at most "cmd.limit" rows
|
||||
future<lw_shared_ptr<query::result>> query(schema_ptr,
|
||||
const query::read_command& cmd,
|
||||
const std::vector<query::partition_range>& ranges);
|
||||
future<lw_shared_ptr<query::result>> query(const query::read_command& cmd, const std::vector<query::partition_range>& ranges);
|
||||
|
||||
future<> populate(sstring datadir);
|
||||
|
||||
@@ -358,23 +351,20 @@ private:
|
||||
// one are also complete
|
||||
future<> seal_active_memtable();
|
||||
|
||||
// filter manifest.json files out
|
||||
static bool manifest_json_filter(const sstring& fname);
|
||||
|
||||
seastar::gate _in_flight_seals;
|
||||
|
||||
// Iterate over all partitions. Protocol is the same as std::all_of(),
|
||||
// so that iteration can be stopped by returning false.
|
||||
// Func signature: bool (const decorated_key& dk, const mutation_partition& mp)
|
||||
template <typename Func>
|
||||
future<bool> for_all_partitions(schema_ptr, Func&& func) const;
|
||||
future<bool> for_all_partitions(Func&& func) const;
|
||||
future<sstables::entry_descriptor> probe_file(sstring sstdir, sstring fname);
|
||||
void seal_on_overflow();
|
||||
void check_valid_rp(const db::replay_position&) const;
|
||||
public:
|
||||
// Iterate over all partitions. Protocol is the same as std::all_of(),
|
||||
// so that iteration can be stopped by returning false.
|
||||
future<bool> for_all_partitions_slow(schema_ptr, std::function<bool (const dht::decorated_key&, const mutation_partition&)> func) const;
|
||||
future<bool> for_all_partitions_slow(std::function<bool (const dht::decorated_key&, const mutation_partition&)> func) const;
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& out, const column_family& cf);
|
||||
// Testing purposes.
|
||||
@@ -548,7 +538,7 @@ class database {
|
||||
circular_buffer<promise<>> _throttled_requests;
|
||||
|
||||
future<> init_commitlog();
|
||||
future<> apply_in_memory(const frozen_mutation& m, const schema_ptr& m_schema, const db::replay_position&);
|
||||
future<> apply_in_memory(const frozen_mutation&, const db::replay_position&);
|
||||
future<> populate(sstring datadir);
|
||||
future<> populate_keyspace(sstring datadir, sstring ks_name);
|
||||
|
||||
@@ -560,7 +550,7 @@ private:
|
||||
friend void db::system_keyspace::make(database& db, bool durable, bool volatile_testing_only);
|
||||
void setup_collectd();
|
||||
future<> throttle();
|
||||
future<> do_apply(schema_ptr, const frozen_mutation&);
|
||||
future<> do_apply(const frozen_mutation&);
|
||||
void unthrottle();
|
||||
public:
|
||||
static utils::UUID empty_version;
|
||||
@@ -591,6 +581,7 @@ public:
|
||||
|
||||
void add_column_family(schema_ptr schema, column_family::config cfg);
|
||||
|
||||
future<> update_column_family(const sstring& ks_name, const sstring& cf_name);
|
||||
future<> drop_column_family(db_clock::time_point changed_at, const sstring& ks_name, const sstring& cf_name);
|
||||
|
||||
/* throws std::out_of_range if missing */
|
||||
@@ -625,12 +616,11 @@ public:
|
||||
unsigned shard_of(const dht::token& t);
|
||||
unsigned shard_of(const mutation& m);
|
||||
unsigned shard_of(const frozen_mutation& m);
|
||||
future<lw_shared_ptr<query::result>> query(schema_ptr, const query::read_command& cmd, const std::vector<query::partition_range>& ranges);
|
||||
future<reconcilable_result> query_mutations(schema_ptr, const query::read_command& cmd, const query::partition_range& range);
|
||||
future<> apply(schema_ptr, const frozen_mutation&);
|
||||
future<lw_shared_ptr<query::result>> query(const query::read_command& cmd, const std::vector<query::partition_range>& ranges);
|
||||
future<reconcilable_result> query_mutations(const query::read_command& cmd, const query::partition_range& range);
|
||||
future<> apply(const frozen_mutation&);
|
||||
keyspace::config make_keyspace_config(const keyspace_metadata& ksm);
|
||||
const sstring& get_snitch_name() const;
|
||||
future<> clear_snapshot(sstring tag, std::vector<sstring> keyspace_names);
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& out, const database& db);
|
||||
const std::unordered_map<sstring, keyspace>& get_keyspaces() const {
|
||||
@@ -710,11 +700,11 @@ column_family::check_valid_rp(const db::replay_position& rp) const {
|
||||
|
||||
inline
|
||||
void
|
||||
column_family::apply(const frozen_mutation& m, const schema_ptr& m_schema, const db::replay_position& rp) {
|
||||
column_family::apply(const frozen_mutation& m, const db::replay_position& rp) {
|
||||
utils::latency_counter lc;
|
||||
_stats.writes.set_latency(lc);
|
||||
check_valid_rp(rp);
|
||||
active_memtable().apply(m, m_schema, rp);
|
||||
active_memtable().apply(m, rp);
|
||||
seal_on_overflow();
|
||||
_stats.writes.mark(lc);
|
||||
if (lc.is_start()) {
|
||||
|
||||
@@ -31,19 +31,12 @@ class mutation_partition;
|
||||
// schema.hh
|
||||
class schema;
|
||||
class column_definition;
|
||||
class column_mapping;
|
||||
|
||||
// schema_mutations.hh
|
||||
class schema_mutations;
|
||||
|
||||
// keys.hh
|
||||
class exploded_clustering_prefix;
|
||||
class partition_key;
|
||||
class partition_key_view;
|
||||
class clustering_key_prefix;
|
||||
class clustering_key_prefix_view;
|
||||
using clustering_key = clustering_key_prefix;
|
||||
using clustering_key_view = clustering_key_prefix_view;
|
||||
|
||||
// memtable.hh
|
||||
class memtable;
|
||||
|
||||
@@ -57,7 +57,6 @@
|
||||
#include "db/config.hh"
|
||||
#include "gms/failure_detector.hh"
|
||||
#include "service/storage_service.hh"
|
||||
#include "schema_registry.hh"
|
||||
|
||||
static logging::logger logger("batchlog_manager");
|
||||
|
||||
@@ -181,9 +180,9 @@ future<> db::batchlog_manager::replay_all_failed_batches() {
|
||||
auto& fm = fms->front();
|
||||
auto mid = fm.column_family_id();
|
||||
return system_keyspace::get_truncated_at(mid).then([this, &fm, written_at, mutations](db_clock::time_point t) {
|
||||
warn(unimplemented::cause::SCHEMA_CHANGE);
|
||||
auto schema = local_schema_registry().get(fm.schema_version());
|
||||
auto schema = _qp.db().local().find_schema(fm.column_family_id());
|
||||
if (written_at > t) {
|
||||
auto schema = _qp.db().local().find_schema(fm.column_family_id());
|
||||
mutations->emplace_back(fm.unfreeze(schema));
|
||||
}
|
||||
}).then([fms] {
|
||||
|
||||
@@ -887,7 +887,7 @@ void db::commitlog::segment_manager::flush_segments(bool force) {
|
||||
|
||||
future<db::commitlog::segment_manager::sseg_ptr> db::commitlog::segment_manager::allocate_segment(bool active) {
|
||||
descriptor d(next_id());
|
||||
return open_file_dma(cfg.commit_log_location + "/" + d.filename(), open_flags::wo | open_flags::create).then([this, d, active](file f) {
|
||||
return engine().open_file_dma(cfg.commit_log_location + "/" + d.filename(), open_flags::wo | open_flags::create).then([this, d, active](file f) {
|
||||
// xfs doesn't like files extended betond eof, so enlarge the file
|
||||
return f.truncate(max_size).then([this, d, active, f] () mutable {
|
||||
auto s = make_lw_shared<segment>(this, d, std::move(f), active);
|
||||
@@ -1215,7 +1215,7 @@ const db::commitlog::config& db::commitlog::active_config() const {
|
||||
|
||||
future<std::unique_ptr<subscription<temporary_buffer<char>, db::replay_position>>>
|
||||
db::commitlog::read_log_file(const sstring& filename, commit_load_reader_func next, position_type off) {
|
||||
return open_file_dma(filename, open_flags::ro).then([next = std::move(next), off](file f) {
|
||||
return engine().open_file_dma(filename, open_flags::ro).then([next = std::move(next), off](file f) {
|
||||
return std::make_unique<subscription<temporary_buffer<char>, replay_position>>(
|
||||
read_log_file(std::move(f), std::move(next), off));
|
||||
});
|
||||
@@ -1350,17 +1350,6 @@ db::commitlog::read_log_file(file f, commit_load_reader_func next, position_type
|
||||
}
|
||||
future<> read_entry() {
|
||||
static constexpr size_t entry_header_size = segment::entry_overhead_size - sizeof(uint32_t);
|
||||
|
||||
/**
|
||||
* #598 - Must check that data left in chunk is enough to even read an entry.
|
||||
* If not, this is small slack space in the chunk end, and we should just go
|
||||
* to the next.
|
||||
*/
|
||||
assert(pos <= next);
|
||||
if ((pos + entry_header_size) >= next) {
|
||||
return skip(next - pos);
|
||||
}
|
||||
|
||||
return fin.read_exactly(entry_header_size).then([this](temporary_buffer<char> buf) {
|
||||
replay_position rp(id, position_type(pos));
|
||||
|
||||
|
||||
@@ -210,7 +210,7 @@ future<> db::commitlog_replayer::impl::process(stats* s, temporary_buffer<char>
|
||||
auto& cf = db.find_column_family(fm.column_family_id());
|
||||
|
||||
if (logger.is_enabled(logging::log_level::debug)) {
|
||||
logger.debug("replaying at {} v={} {}:{} at {}", fm.column_family_id(), fm.schema_version(),
|
||||
logger.debug("replaying at {} {}:{} at {}", fm.column_family_id(),
|
||||
cf.schema()->ks_name(), cf.schema()->cf_name(), rp);
|
||||
}
|
||||
// Removed forwarding "new" RP. Instead give none/empty.
|
||||
@@ -218,12 +218,7 @@ future<> db::commitlog_replayer::impl::process(stats* s, temporary_buffer<char>
|
||||
// The end result should be that once sstables are flushed out
|
||||
// their "replay_position" attribute will be empty, which is
|
||||
// lower than anything the new session will produce.
|
||||
if (cf.schema()->version() != fm.schema_version()) {
|
||||
// TODO: Convert fm to current schema
|
||||
fail(unimplemented::cause::SCHEMA_CHANGE);
|
||||
} else {
|
||||
cf.apply(fm, cf.schema());
|
||||
}
|
||||
cf.apply(fm);
|
||||
s->applied_mutations++;
|
||||
return make_ready_future<>();
|
||||
}).handle_exception([s](auto ep) {
|
||||
|
||||
@@ -30,7 +30,6 @@
|
||||
#include "core/shared_ptr.hh"
|
||||
#include "core/fstream.hh"
|
||||
#include "core/do_with.hh"
|
||||
#include "core/print.hh"
|
||||
#include "log.hh"
|
||||
#include <boost/any.hpp>
|
||||
|
||||
@@ -411,7 +410,7 @@ future<> db::config::read_from_file(file f) {
|
||||
}
|
||||
|
||||
future<> db::config::read_from_file(const sstring& filename) {
|
||||
return open_file_dma(filename, open_flags::ro).then([this](file f) {
|
||||
return engine().open_file_dma(filename, open_flags::ro).then([this](file f) {
|
||||
return read_from_file(std::move(f));
|
||||
});
|
||||
}
|
||||
@@ -433,9 +432,3 @@ boost::filesystem::path db::config::get_conf_dir() {
|
||||
|
||||
return confdir;
|
||||
}
|
||||
|
||||
void db::config::check_experimental(const sstring& what) const {
|
||||
if (!experimental()) {
|
||||
throw std::runtime_error(sprint("%s is currently disabled. Start Scylla with --experimental=on to enable.", what));
|
||||
}
|
||||
}
|
||||
|
||||
34
db/config.hh
34
db/config.hh
@@ -102,9 +102,6 @@ public:
|
||||
|
||||
config();
|
||||
|
||||
// Throws exception if experimental feature is disabled.
|
||||
void check_experimental(const sstring& what) const;
|
||||
|
||||
boost::program_options::options_description
|
||||
get_options_description();
|
||||
|
||||
@@ -386,7 +383,7 @@ public:
|
||||
"This setting has been removed from default configuration. It makes new (non-seed) nodes automatically migrate the right data to themselves. When initializing a fresh cluster with no data, add auto_bootstrap: false.\n" \
|
||||
"Related information: Initializing a multiple node cluster (single data center) and Initializing a multiple node cluster (multiple data centers)." \
|
||||
) \
|
||||
val(batch_size_warn_threshold_in_kb, uint32_t, 5, Used, \
|
||||
val(batch_size_warn_threshold_in_kb, uint32_t, 5, Unused, \
|
||||
"Log WARN on any batch size exceeding this value in kilobytes. Caution should be taken on increasing the size of this threshold as it can lead to node instability." \
|
||||
) \
|
||||
val(broadcast_address, sstring, /* listen_address */, Used, \
|
||||
@@ -641,8 +638,8 @@ public:
|
||||
) \
|
||||
/* Security properties */ \
|
||||
/* Server and client security settings. */ \
|
||||
val(authenticator, sstring, "org.apache.cassandra.auth.AllowAllAuthenticator", Used, \
|
||||
"The authentication backend, used to identify users. The available authenticators are:\n" \
|
||||
val(authenticator, sstring, "org.apache.cassandra.auth.AllowAllAuthenticator", Unused, \
|
||||
"The authentication backend. It implements IAuthenticator, which is used to identify users. The available authenticators are:\n" \
|
||||
"\n" \
|
||||
"\torg.apache.cassandra.auth.AllowAllAuthenticator : Disables authentication; no checks are performed.\n" \
|
||||
"\torg.apache.cassandra.auth.PasswordAuthenticator : Authenticates users with user names and hashed passwords stored in the system_auth.credentials table. If you use the default, 1, and the node with the lone replica goes down, you will not be able to log into the cluster because the system_auth keyspace was not replicated.\n" \
|
||||
@@ -682,18 +679,28 @@ public:
|
||||
"truststore : (Default: <system truststore> ) Location of the truststore containing the trusted certificate for authenticating remote servers.\n" \
|
||||
"Related information: Node-to-node encryption" \
|
||||
) \
|
||||
val(client_encryption_options, string_map, /*none*/, Used, \
|
||||
"Enable or disable client-to-node encryption. You must also generate keys and provide the appropriate key and certificate. No custom encryption options are currently enabled. The available options are:\n" \
|
||||
val(client_encryption_options, string_map, /*none*/, Unused, \
|
||||
"Enable or disable client-to-node encryption. You must also generate keys and provide the appropriate key and trust store locations and passwords. No custom encryption options are currently enabled. The available options are:\n" \
|
||||
"\n" \
|
||||
"\tenabled : (Default: false ) To enable, set to true.\n" \
|
||||
"\tcertificate: (Default: conf/scylla.crt) The location of a PEM-encoded x509 certificate used to identify and encrypt the client/server communication.\n" \
|
||||
"\tkeyfile: (Default: conf/scylla.key) PEM Key file associated with certificate.\n" \
|
||||
"\tkeystore : (Default: conf/.keystore ) The location of a Java keystore (JKS) suitable for use with Java Secure Socket Extension (JSSE), which is the Java version of the Secure Sockets Layer (SSL), and Transport Layer Security (TLS) protocols. The keystore contains the private key used to encrypt outgoing messages.\n" \
|
||||
"\tkeystore_password : (Default: cassandra ) Password for the keystore. This must match the password used when generating the keystore and truststore.\n" \
|
||||
"\trequire_client_auth : (Default: false ) Enables or disables certificate authentication. (Available starting with Cassandra 1.2.3.)\n" \
|
||||
"\ttruststore : (Default: conf/.truststore ) Set if require_client_auth is true.\n" \
|
||||
"\ttruststore_password : <truststore_password> Set if require_client_auth is true.\n" \
|
||||
"\n" \
|
||||
"The advanced settings are:\n" \
|
||||
"\n" \
|
||||
"\tprotocol : (Default: TLS )\n" \
|
||||
"\talgorithm : (Default: SunX509 )\n" \
|
||||
"\tstore_type : (Default: JKS )\n" \
|
||||
"\tcipher_suites : (Default: TLS_RSA_WITH_AES_128_CBC_SHA , TLS_RSA_WITH_AES_256_CBC_SHA )\n" \
|
||||
"Related information: Client-to-node encryption" \
|
||||
) \
|
||||
val(ssl_storage_port, uint32_t, 7001, Used, \
|
||||
val(ssl_storage_port, uint32_t, 7001, Unused, \
|
||||
"The SSL port for encrypted communication. Unused unless enabled in encryption_options." \
|
||||
) \
|
||||
val(default_log_level, sstring, "info", Used, \
|
||||
val(default_log_level, sstring, "warn", Used, \
|
||||
"Default log level for log messages. Valid values are trace, debug, info, warn, error.") \
|
||||
val(logger_log_level, string_map, /* none */, Used,\
|
||||
"map of logger name to log level. Valid values are trace, debug, info, warn, error. " \
|
||||
@@ -719,8 +726,6 @@ public:
|
||||
val(override_decommission, bool, false, Used, "Set true to force a decommissioned node to join the cluster") \
|
||||
val(ring_delay_ms, uint32_t, 30 * 1000, Used, "Time a node waits to hear from other nodes before joining the ring in milliseconds. Same as -Dcassandra.ring_delay_ms in cassandra.") \
|
||||
val(developer_mode, bool, false, Used, "Relax environement checks. Setting to true can reduce performance and reliability significantly.") \
|
||||
val(skip_wait_for_gossip_to_settle, int32_t, -1, Used, "An integer to configure the wait for gossip to settle. -1: wait normally, 0: do not wait at all, n: wait for at most n polls. Same as -Dcassandra.skip_wait_for_gossip_to_settle in cassandra.") \
|
||||
val(experimental, bool, false, Used, "Set to true to unlock experimental features.") \
|
||||
/* done! */
|
||||
|
||||
#define _make_value_member(name, type, deflt, status, desc, ...) \
|
||||
@@ -737,4 +742,5 @@ private:
|
||||
int _dummy;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -46,7 +46,6 @@
|
||||
#include "system_keyspace.hh"
|
||||
#include "query_context.hh"
|
||||
#include "query-result-set.hh"
|
||||
#include "query-result-writer.hh"
|
||||
#include "schema_builder.hh"
|
||||
#include "map_difference.hh"
|
||||
#include "utils/UUID_gen.hh"
|
||||
@@ -54,12 +53,9 @@
|
||||
#include "core/thread.hh"
|
||||
#include "json.hh"
|
||||
#include "log.hh"
|
||||
#include "frozen_schema.hh"
|
||||
#include "schema_registry.hh"
|
||||
|
||||
#include "db/marshal/type_parser.hh"
|
||||
#include "db/config.hh"
|
||||
#include "md5_hasher.hh"
|
||||
|
||||
#include <boost/range/algorithm/copy.hpp>
|
||||
#include <boost/range/adaptor/map.hpp>
|
||||
@@ -74,36 +70,6 @@ namespace schema_tables {
|
||||
|
||||
logging::logger logger("schema_tables");
|
||||
|
||||
struct qualified_name {
|
||||
sstring keyspace_name;
|
||||
sstring table_name;
|
||||
|
||||
qualified_name(sstring keyspace_name, sstring table_name)
|
||||
: keyspace_name(std::move(keyspace_name))
|
||||
, table_name(std::move(table_name))
|
||||
{ }
|
||||
|
||||
qualified_name(const schema_ptr& s)
|
||||
: keyspace_name(s->ks_name())
|
||||
, table_name(s->cf_name())
|
||||
{ }
|
||||
|
||||
bool operator<(const qualified_name& o) const {
|
||||
return keyspace_name < o.keyspace_name
|
||||
|| (keyspace_name == o.keyspace_name && table_name < o.table_name);
|
||||
}
|
||||
|
||||
bool operator==(const qualified_name& o) const {
|
||||
return keyspace_name == o.keyspace_name && table_name == o.table_name;
|
||||
}
|
||||
};
|
||||
|
||||
static future<schema_mutations> read_table_mutations(distributed<service::storage_proxy>& proxy, const qualified_name& table);
|
||||
|
||||
static void merge_tables(distributed<service::storage_proxy>& proxy,
|
||||
std::map<qualified_name, schema_mutations>&& before,
|
||||
std::map<qualified_name, schema_mutations>&& after);
|
||||
|
||||
std::vector<const char*> ALL { KEYSPACES, COLUMNFAMILIES, COLUMNS, TRIGGERS, USERTYPES, /* not present in 2.1.8: FUNCTIONS, AGGREGATES */ };
|
||||
|
||||
using days = std::chrono::duration<int, std::ratio<24 * 3600>>;
|
||||
@@ -129,9 +95,7 @@ using days = std::chrono::duration<int, std::ratio<24 * 3600>>;
|
||||
"keyspace definitions"
|
||||
)));
|
||||
builder.set_gc_grace_seconds(std::chrono::duration_cast<std::chrono::seconds>(days(7)).count());
|
||||
builder.with(schema_builder::compact_storage::yes);
|
||||
builder.with_version(generate_schema_version(builder.uuid()));
|
||||
return builder.build();
|
||||
return builder.build(schema_builder::compact_storage::yes);
|
||||
}();
|
||||
return keyspaces;
|
||||
}
|
||||
@@ -183,9 +147,7 @@ using days = std::chrono::duration<int, std::ratio<24 * 3600>>;
|
||||
"table definitions"
|
||||
)));
|
||||
builder.set_gc_grace_seconds(std::chrono::duration_cast<std::chrono::seconds>(days(7)).count());
|
||||
builder.with(schema_builder::compact_storage::no);
|
||||
builder.with_version(generate_schema_version(builder.uuid()));
|
||||
return builder.build();
|
||||
return builder.build(schema_builder::compact_storage::no);
|
||||
}();
|
||||
return columnfamilies;
|
||||
}
|
||||
@@ -214,9 +176,7 @@ using days = std::chrono::duration<int, std::ratio<24 * 3600>>;
|
||||
"column definitions"
|
||||
)));
|
||||
builder.set_gc_grace_seconds(std::chrono::duration_cast<std::chrono::seconds>(days(7)).count());
|
||||
builder.with(schema_builder::compact_storage::no);
|
||||
builder.with_version(generate_schema_version(builder.uuid()));
|
||||
return builder.build();
|
||||
return builder.build(schema_builder::compact_storage::no);
|
||||
}();
|
||||
return columns;
|
||||
}
|
||||
@@ -240,9 +200,7 @@ using days = std::chrono::duration<int, std::ratio<24 * 3600>>;
|
||||
"trigger definitions"
|
||||
)));
|
||||
builder.set_gc_grace_seconds(std::chrono::duration_cast<std::chrono::seconds>(days(7)).count());
|
||||
builder.with(schema_builder::compact_storage::no);
|
||||
builder.with_version(generate_schema_version(builder.uuid()));
|
||||
return builder.build();
|
||||
return builder.build(schema_builder::compact_storage::no);
|
||||
}();
|
||||
return triggers;
|
||||
}
|
||||
@@ -267,9 +225,7 @@ using days = std::chrono::duration<int, std::ratio<24 * 3600>>;
|
||||
"user defined type definitions"
|
||||
)));
|
||||
builder.set_gc_grace_seconds(std::chrono::duration_cast<std::chrono::seconds>(days(7)).count());
|
||||
builder.with(schema_builder::compact_storage::no);
|
||||
builder.with_version(generate_schema_version(builder.uuid()));
|
||||
return builder.build();
|
||||
return builder.build(schema_builder::compact_storage::no);
|
||||
}();
|
||||
return usertypes;
|
||||
}
|
||||
@@ -298,9 +254,7 @@ using days = std::chrono::duration<int, std::ratio<24 * 3600>>;
|
||||
"user defined type definitions"
|
||||
)));
|
||||
builder.set_gc_grace_seconds(std::chrono::duration_cast<std::chrono::seconds>(days(7)).count());
|
||||
builder.with(schema_builder::compact_storage::no);
|
||||
builder.with_version(generate_schema_version(builder.uuid()));
|
||||
return builder.build();
|
||||
return builder.build(schema_builder::compact_storage::no);
|
||||
}();
|
||||
return functions;
|
||||
}
|
||||
@@ -329,9 +283,7 @@ using days = std::chrono::duration<int, std::ratio<24 * 3600>>;
|
||||
"user defined aggregate definitions"
|
||||
)));
|
||||
builder.set_gc_grace_seconds(std::chrono::duration_cast<std::chrono::seconds>(days(7)).count());
|
||||
builder.with(schema_builder::compact_storage::no);
|
||||
builder.with_version(generate_schema_version(builder.uuid()));
|
||||
return builder.build();
|
||||
return builder.build(schema_builder::compact_storage::no);
|
||||
}();
|
||||
return aggregates;
|
||||
}
|
||||
@@ -343,11 +295,10 @@ future<> save_system_keyspace_schema() {
|
||||
|
||||
// delete old, possibly obsolete entries in schema tables
|
||||
return parallel_for_each(ALL, [ksm] (sstring cf) {
|
||||
auto deletion_timestamp = schema_creation_timestamp() - 1;
|
||||
return db::execute_cql(sprint("DELETE FROM system.%%s USING TIMESTAMP %s WHERE keyspace_name = ?",
|
||||
deletion_timestamp), cf, ksm->name()).discard_result();
|
||||
return db::execute_cql("DELETE FROM system.%s WHERE keyspace_name = ?", cf, ksm->name()).discard_result();
|
||||
}).then([ksm] {
|
||||
auto mvec = make_create_keyspace_mutations(ksm, schema_creation_timestamp(), true);
|
||||
// (+1 to timestamp to make sure we don't get shadowed by the tombstones we just added)
|
||||
auto mvec = make_create_keyspace_mutations(ksm, qctx->next_timestamp(), true);
|
||||
return qctx->proxy().mutate_locally(std::move(mvec));
|
||||
});
|
||||
}
|
||||
@@ -375,30 +326,36 @@ future<utils::UUID> calculate_schema_digest(distributed<service::storage_proxy>&
|
||||
auto map = [&proxy] (sstring table) {
|
||||
return db::system_keyspace::query_mutations(proxy, table).then([&proxy, table] (auto rs) {
|
||||
auto s = proxy.local().get_db().local().find_schema(system_keyspace::NAME, table);
|
||||
std::vector<mutation> mutations;
|
||||
std::vector<query::result> results;
|
||||
for (auto&& p : rs->partitions()) {
|
||||
auto mut = p.mut().unfreeze(s);
|
||||
auto partition_key = value_cast<sstring>(utf8_type->deserialize(mut.key().get_component(*s, 0)));
|
||||
if (partition_key == system_keyspace::NAME) {
|
||||
continue;
|
||||
}
|
||||
mutations.emplace_back(std::move(mut));
|
||||
auto slice = partition_slice_builder(*s).build();
|
||||
results.emplace_back(mut.query(slice));
|
||||
}
|
||||
return mutations;
|
||||
return results;
|
||||
});
|
||||
};
|
||||
auto reduce = [] (auto& hash, auto&& mutations) {
|
||||
for (const mutation& m : mutations) {
|
||||
feed_hash_for_schema_digest(hash, m);
|
||||
auto reduce = [] (auto& hash, auto&& results) {
|
||||
for (auto&& rs : results) {
|
||||
for (auto&& f : rs.buf().fragments()) {
|
||||
hash.Update(reinterpret_cast<const unsigned char*>(f.begin()), f.size());
|
||||
}
|
||||
}
|
||||
return make_ready_future<>();
|
||||
};
|
||||
return do_with(md5_hasher(), [map, reduce] (auto& hash) {
|
||||
return do_with(CryptoPP::Weak::MD5{}, [map, reduce] (auto& hash) {
|
||||
return do_for_each(ALL.begin(), ALL.end(), [&hash, map, reduce] (auto& table) {
|
||||
return map(table).then([&hash, reduce] (auto&& mutations) {
|
||||
reduce(hash, mutations);
|
||||
return map(table).then([&hash, reduce] (auto&& results) {
|
||||
return reduce(hash, results);
|
||||
});
|
||||
}).then([&hash] {
|
||||
return make_ready_future<utils::UUID>(utils::UUID_gen::get_name_UUID(hash.finalize()));
|
||||
bytes digest{bytes::initialized_later(), CryptoPP::Weak::MD5::DIGESTSIZE};
|
||||
hash.Final(reinterpret_cast<unsigned char*>(digest.begin()));
|
||||
return make_ready_future<utils::UUID>(utils::UUID_gen::get_name_UUID(digest));
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -441,28 +398,6 @@ read_schema_for_keyspaces(distributed<service::storage_proxy>& proxy, const sstr
|
||||
return map_reduce(keyspace_names.begin(), keyspace_names.end(), map, schema_result{}, insert);
|
||||
}
|
||||
|
||||
static
|
||||
future<mutation> query_partition_mutation(service::storage_proxy& proxy,
|
||||
schema_ptr s,
|
||||
lw_shared_ptr<query::read_command> cmd,
|
||||
partition_key pkey)
|
||||
{
|
||||
auto dk = dht::global_partitioner().decorate_key(*s, pkey);
|
||||
return do_with(query::partition_range::make_singular(dk), [&proxy, dk, s = std::move(s), cmd = std::move(cmd)] (auto& range) {
|
||||
return proxy.query_mutations_locally(s, std::move(cmd), range)
|
||||
.then([dk = std::move(dk), s](foreign_ptr<lw_shared_ptr<reconcilable_result>> res) {
|
||||
auto&& partitions = res->partitions();
|
||||
if (partitions.size() == 0) {
|
||||
return mutation(std::move(dk), s);
|
||||
} else if (partitions.size() == 1) {
|
||||
return partitions[0].mut().unfreeze(s);
|
||||
} else {
|
||||
assert(false && "Results must have at most one partition");
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
future<schema_result_value_type>
|
||||
read_schema_partition_for_keyspace(distributed<service::storage_proxy>& proxy, const sstring& schema_table_name, const sstring& keyspace_name)
|
||||
{
|
||||
@@ -474,18 +409,16 @@ read_schema_partition_for_keyspace(distributed<service::storage_proxy>& proxy, c
|
||||
});
|
||||
}
|
||||
|
||||
future<mutation>
|
||||
future<schema_result_value_type>
|
||||
read_schema_partition_for_table(distributed<service::storage_proxy>& proxy, const sstring& schema_table_name, const sstring& keyspace_name, const sstring& table_name)
|
||||
{
|
||||
auto schema = proxy.local().get_db().local().find_schema(system_keyspace::NAME, schema_table_name);
|
||||
auto keyspace_key = partition_key::from_singular(*schema, keyspace_name);
|
||||
auto clustering_range = query::clustering_range(clustering_key_prefix::from_clustering_prefix(
|
||||
*schema, exploded_clustering_prefix({utf8_type->decompose(table_name)})));
|
||||
auto slice = partition_slice_builder(*schema)
|
||||
.with_range(std::move(clustering_range))
|
||||
.build();
|
||||
auto cmd = make_lw_shared<query::read_command>(schema->id(), schema->version(), std::move(slice), query::max_rows);
|
||||
return query_partition_mutation(proxy.local(), std::move(schema), std::move(cmd), std::move(keyspace_key));
|
||||
auto keyspace_key = dht::global_partitioner().decorate_key(*schema,
|
||||
partition_key::from_singular(*schema, keyspace_name));
|
||||
auto clustering_range = query::clustering_range(clustering_key_prefix::from_clustering_prefix(*schema, exploded_clustering_prefix({utf8_type->decompose(table_name)})));
|
||||
return db::system_keyspace::query(proxy, schema_table_name, keyspace_key, clustering_range).then([keyspace_name] (auto&& rs) {
|
||||
return schema_result_value_type{keyspace_name, std::move(rs)};
|
||||
});
|
||||
}
|
||||
|
||||
static semaphore the_merge_lock;
|
||||
@@ -519,7 +452,7 @@ future<> merge_schema(distributed<service::storage_proxy>& proxy, std::vector<mu
|
||||
}
|
||||
|
||||
future<> merge_schema(distributed<service::storage_proxy>& proxy, std::vector<mutation> mutations, bool do_flush)
|
||||
{
|
||||
{
|
||||
return merge_lock().then([&proxy, mutations = std::move(mutations), do_flush] () mutable {
|
||||
return do_merge_schema(proxy, std::move(mutations), do_flush);
|
||||
}).finally([] {
|
||||
@@ -527,35 +460,6 @@ future<> merge_schema(distributed<service::storage_proxy>& proxy, std::vector<mu
|
||||
});
|
||||
}
|
||||
|
||||
// Returns names of live table definitions of given keyspace
|
||||
future<std::vector<sstring>>
|
||||
static read_table_names_of_keyspace(distributed<service::storage_proxy>& proxy, const sstring& keyspace_name) {
|
||||
auto s = columnfamilies();
|
||||
auto pkey = dht::global_partitioner().decorate_key(*s, partition_key::from_singular(*s, keyspace_name));
|
||||
return db::system_keyspace::query(proxy, COLUMNFAMILIES, pkey).then([] (auto&& rs) {
|
||||
std::vector<sstring> result;
|
||||
for (const query::result_set_row& row : rs->rows()) {
|
||||
result.emplace_back(row.get_nonnull<sstring>("columnfamily_name"));
|
||||
}
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
// Call inside a seastar thread
|
||||
static
|
||||
std::map<qualified_name, schema_mutations>
|
||||
read_tables_for_keyspaces(distributed<service::storage_proxy>& proxy, const std::set<sstring>& keyspace_names)
|
||||
{
|
||||
std::map<qualified_name, schema_mutations> result;
|
||||
for (auto&& keyspace_name : keyspace_names) {
|
||||
for (auto&& table_name : read_table_names_of_keyspace(proxy, keyspace_name).get0()) {
|
||||
auto qn = qualified_name(keyspace_name, table_name);
|
||||
result.emplace(qn, read_table_mutations(proxy, qn).get0());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
future<> do_merge_schema(distributed<service::storage_proxy>& proxy, std::vector<mutation> mutations, bool do_flush)
|
||||
{
|
||||
return seastar::async([&proxy, mutations = std::move(mutations), do_flush] () mutable {
|
||||
@@ -570,7 +474,7 @@ future<> do_merge_schema(distributed<service::storage_proxy>& proxy, std::vector
|
||||
|
||||
// current state of the schema
|
||||
auto&& old_keyspaces = read_schema_for_keyspaces(proxy, KEYSPACES, keyspaces).get0();
|
||||
auto&& old_column_families = read_tables_for_keyspaces(proxy, keyspaces);
|
||||
auto&& old_column_families = read_schema_for_keyspaces(proxy, COLUMNFAMILIES, keyspaces).get0();
|
||||
/*auto& old_types = */read_schema_for_keyspaces(proxy, USERTYPES, keyspaces).get0();
|
||||
#if 0 // not in 2.1.8
|
||||
/*auto& old_functions = */read_schema_for_keyspaces(proxy, FUNCTIONS, keyspaces).get0();
|
||||
@@ -590,7 +494,7 @@ future<> do_merge_schema(distributed<service::storage_proxy>& proxy, std::vector
|
||||
|
||||
// with new data applied
|
||||
auto&& new_keyspaces = read_schema_for_keyspaces(proxy, KEYSPACES, keyspaces).get0();
|
||||
auto&& new_column_families = read_tables_for_keyspaces(proxy, keyspaces);
|
||||
auto&& new_column_families = read_schema_for_keyspaces(proxy, COLUMNFAMILIES, keyspaces).get0();
|
||||
/*auto& new_types = */read_schema_for_keyspaces(proxy, USERTYPES, keyspaces).get0();
|
||||
#if 0 // not in 2.1.8
|
||||
/*auto& new_functions = */read_schema_for_keyspaces(proxy, FUNCTIONS, keyspaces).get0();
|
||||
@@ -598,7 +502,7 @@ future<> do_merge_schema(distributed<service::storage_proxy>& proxy, std::vector
|
||||
#endif
|
||||
|
||||
std::set<sstring> keyspaces_to_drop = merge_keyspaces(proxy, std::move(old_keyspaces), std::move(new_keyspaces)).get0();
|
||||
merge_tables(proxy, std::move(old_column_families), std::move(new_column_families));
|
||||
merge_tables(proxy, std::move(old_column_families), std::move(new_column_families)).get0();
|
||||
#if 0
|
||||
mergeTypes(oldTypes, newTypes);
|
||||
mergeFunctions(oldFunctions, newFunctions);
|
||||
@@ -608,7 +512,15 @@ future<> do_merge_schema(distributed<service::storage_proxy>& proxy, std::vector
|
||||
// it is safe to drop a keyspace only when all nested ColumnFamilies where deleted
|
||||
for (auto&& keyspace_to_drop : keyspaces_to_drop) {
|
||||
db.drop_keyspace(keyspace_to_drop);
|
||||
service::get_local_migration_manager().notify_drop_keyspace(keyspace_to_drop);
|
||||
}
|
||||
// FIXME: clean this up by reorganizing the code
|
||||
// Send CQL events only once, not once per shard.
|
||||
if (engine().cpu_id() == 0) {
|
||||
return do_for_each(keyspaces_to_drop, [] (auto& ks_name) {
|
||||
return service::migration_manager::notify_drop_keyspace(ks_name);
|
||||
});
|
||||
} else {
|
||||
return make_ready_future<>();
|
||||
}
|
||||
}).get0();
|
||||
});
|
||||
@@ -639,84 +551,138 @@ future<std::set<sstring>> merge_keyspaces(distributed<service::storage_proxy>& p
|
||||
}
|
||||
for (auto&& key : diff.entries_only_on_right) {
|
||||
auto&& value = after[key];
|
||||
created.emplace_back(schema_result_value_type{key, std::move(value)});
|
||||
if (!value->empty()) {
|
||||
created.emplace_back(schema_result_value_type{key, std::move(value)});
|
||||
}
|
||||
}
|
||||
for (auto&& key : diff.entries_differing) {
|
||||
altered.emplace_back(key);
|
||||
sstring keyspace_name = key;
|
||||
|
||||
auto&& pre = before[key];
|
||||
auto&& post = after[key];
|
||||
|
||||
if (!pre->empty() && !post->empty()) {
|
||||
altered.emplace_back(keyspace_name);
|
||||
} else if (!pre->empty()) {
|
||||
dropped.emplace(keyspace_name);
|
||||
} else if (!post->empty()) { // a (re)created keyspace
|
||||
created.emplace_back(schema_result_value_type{key, std::move(post)});
|
||||
}
|
||||
}
|
||||
return do_with(std::move(created), [&proxy, altered = std::move(altered)] (auto& created) {
|
||||
return proxy.local().get_db().invoke_on_all([&created, altered = std::move(altered)] (database& db) {
|
||||
return do_for_each(created, [&db](auto&& val) {
|
||||
return do_for_each(created, [&db] (auto&& val) {
|
||||
auto ksm = create_keyspace_from_schema_partition(val);
|
||||
return db.create_keyspace(ksm).then([ksm] {
|
||||
service::get_local_migration_manager().notify_create_keyspace(ksm);
|
||||
});
|
||||
return db.create_keyspace(std::move(ksm));
|
||||
}).then([&altered, &db] () mutable {
|
||||
for (auto&& name : altered) {
|
||||
db.update_keyspace(name);
|
||||
}
|
||||
|
||||
return make_ready_future<>();
|
||||
});
|
||||
}).then([&created] {
|
||||
// FIXME: clean this up by reorganizing the code
|
||||
// Send CQL events only once, not once per shard.
|
||||
if (engine().cpu_id() == 0) {
|
||||
return do_for_each(created, [] (auto&& partition) {
|
||||
auto ksm = create_keyspace_from_schema_partition(partition);
|
||||
return service::migration_manager::notify_create_keyspace(ksm);
|
||||
});
|
||||
} else {
|
||||
return make_ready_future<>();
|
||||
}
|
||||
});
|
||||
}).then([dropped = std::move(dropped)] () {
|
||||
return make_ready_future<std::set<sstring>>(dropped);
|
||||
});
|
||||
}
|
||||
|
||||
static void update_column_family(database& db, schema_ptr new_schema) {
|
||||
column_family& cfm = db.find_column_family(new_schema->id());
|
||||
|
||||
bool columns_changed = !cfm.schema()->equal_columns(*new_schema);
|
||||
|
||||
auto s = local_schema_registry().learn(new_schema);
|
||||
s->registry_entry()->mark_synced();
|
||||
cfm.set_schema(std::move(s));
|
||||
|
||||
service::get_local_migration_manager().notify_update_column_family(cfm.schema(), columns_changed);
|
||||
}
|
||||
|
||||
// see the comments for merge_keyspaces()
|
||||
static void merge_tables(distributed<service::storage_proxy>& proxy,
|
||||
std::map<qualified_name, schema_mutations>&& before,
|
||||
std::map<qualified_name, schema_mutations>&& after)
|
||||
future<> merge_tables(distributed<service::storage_proxy>& proxy, schema_result&& before, schema_result&& after)
|
||||
{
|
||||
auto changed_at = db_clock::now();
|
||||
std::vector<global_schema_ptr> created;
|
||||
std::vector<global_schema_ptr> altered;
|
||||
std::vector<global_schema_ptr> dropped;
|
||||
|
||||
auto diff = difference(before, after);
|
||||
for (auto&& key : diff.entries_only_on_left) {
|
||||
auto&& s = proxy.local().get_db().local().find_schema(key.keyspace_name, key.table_name);
|
||||
dropped.emplace_back(s);
|
||||
}
|
||||
for (auto&& key : diff.entries_only_on_right) {
|
||||
created.emplace_back(create_table_from_mutations(after.at(key)));
|
||||
}
|
||||
for (auto&& key : diff.entries_differing) {
|
||||
altered.emplace_back(create_table_from_mutations(after.at(key)));
|
||||
}
|
||||
|
||||
proxy.local().get_db().invoke_on_all([&created, &dropped, &altered, changed_at] (database& db) {
|
||||
return seastar::async([&] {
|
||||
for (auto&& gs : created) {
|
||||
schema_ptr s = gs.get();
|
||||
auto& ks = db.find_keyspace(s->ks_name());
|
||||
auto cfg = ks.make_column_family_config(*s);
|
||||
db.add_column_family(s, cfg);
|
||||
ks.make_directory_for_column_family(s->cf_name(), s->id()).get();
|
||||
service::get_local_migration_manager().notify_create_column_family(s);
|
||||
}
|
||||
for (auto&& gs : altered) {
|
||||
update_column_family(db, gs.get());
|
||||
}
|
||||
parallel_for_each(dropped.begin(), dropped.end(), [changed_at, &db](auto&& gs) {
|
||||
schema_ptr s = gs.get();
|
||||
return db.drop_column_family(changed_at, s->ks_name(), s->cf_name()).then([s] {
|
||||
service::get_local_migration_manager().notify_drop_column_family(s);
|
||||
return do_with(std::make_pair(std::move(after), std::move(before)), [&proxy] (auto& pair) {
|
||||
auto& after = pair.first;
|
||||
auto& before = pair.second;
|
||||
auto changed_at = db_clock::now();
|
||||
return proxy.local().get_db().invoke_on_all([changed_at, &proxy, &before, &after] (database& db) {
|
||||
return seastar::async([changed_at, &proxy, &db, &before, &after] {
|
||||
std::vector<schema_ptr> created;
|
||||
std::vector<schema_ptr> altered;
|
||||
std::vector<schema_ptr> dropped;
|
||||
auto diff = difference(before, after, [](const auto& x, const auto& y) -> bool {
|
||||
return *x == *y;
|
||||
});
|
||||
}).get();
|
||||
for (auto&& key : diff.entries_only_on_left) {
|
||||
auto&& rs = before[key];
|
||||
for (const query::result_set_row& row : rs->rows()) {
|
||||
auto ks_name = row.get_nonnull<sstring>("keyspace_name");
|
||||
auto cf_name = row.get_nonnull<sstring>("columnfamily_name");
|
||||
dropped.emplace_back(db.find_schema(ks_name, cf_name));
|
||||
}
|
||||
}
|
||||
for (auto&& key : diff.entries_only_on_right) {
|
||||
auto&& value = after[key];
|
||||
if (!value->empty()) {
|
||||
auto&& tables = create_tables_from_tables_partition(proxy, value).get0();
|
||||
boost::copy(tables | boost::adaptors::map_values, std::back_inserter(created));
|
||||
}
|
||||
}
|
||||
for (auto&& key : diff.entries_differing) {
|
||||
sstring keyspace_name = key;
|
||||
|
||||
auto&& pre = before[key];
|
||||
auto&& post = after[key];
|
||||
|
||||
if (!pre->empty() && !post->empty()) {
|
||||
auto before = db.find_keyspace(keyspace_name).metadata()->cf_meta_data();
|
||||
auto after = create_tables_from_tables_partition(proxy, post).get0();
|
||||
auto delta = difference(std::map<sstring, schema_ptr>{before.begin(), before.end()}, after, [](const schema_ptr& x, const schema_ptr& y) -> bool {
|
||||
return *x == *y;
|
||||
});
|
||||
for (auto&& key : delta.entries_only_on_left) {
|
||||
dropped.emplace_back(before[key]);
|
||||
}
|
||||
for (auto&& key : delta.entries_only_on_right) {
|
||||
created.emplace_back(after[key]);
|
||||
}
|
||||
for (auto&& key : delta.entries_differing) {
|
||||
altered.emplace_back(after[key]);
|
||||
}
|
||||
} else if (!pre->empty()) {
|
||||
auto before = db.find_keyspace(keyspace_name).metadata()->cf_meta_data();
|
||||
boost::copy(before | boost::adaptors::map_values, std::back_inserter(dropped));
|
||||
} else if (!post->empty()) {
|
||||
auto tables = create_tables_from_tables_partition(proxy, post).get0();
|
||||
boost::copy(tables | boost::adaptors::map_values, std::back_inserter(created));
|
||||
}
|
||||
}
|
||||
for (auto&& cfm : created) {
|
||||
auto& ks = db.find_keyspace(cfm->ks_name());
|
||||
auto cfg = ks.make_column_family_config(*cfm);
|
||||
db.add_column_family(cfm, cfg);
|
||||
}
|
||||
parallel_for_each(altered.begin(), altered.end(), [&db] (auto&& cfm) {
|
||||
return db.update_column_family(cfm->ks_name(), cfm->cf_name());
|
||||
}).get();
|
||||
parallel_for_each(dropped.begin(), dropped.end(), [changed_at, &db] (auto&& cfm) {
|
||||
return db.drop_column_family(changed_at, cfm->ks_name(), cfm->cf_name());
|
||||
}).get();
|
||||
// FIXME: clean this up by reorganizing the code
|
||||
// Send CQL events only once, not once per shard.
|
||||
if (engine().cpu_id() == 0) {
|
||||
for (auto&& cfm : created) {
|
||||
service::migration_manager::notify_create_column_family(cfm).get0();
|
||||
auto& ks = db.find_keyspace(cfm->ks_name());
|
||||
ks.make_directory_for_column_family(cfm->cf_name(), cfm->id());
|
||||
}
|
||||
for (auto&& cfm : dropped) {
|
||||
service::migration_manager::notify_drop_column_family(cfm).get0();
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}).get();
|
||||
});
|
||||
}
|
||||
|
||||
#if 0
|
||||
@@ -905,7 +871,7 @@ std::vector<mutation> make_create_keyspace_mutations(lw_shared_ptr<keyspace_meta
|
||||
addTypeToSchemaMutation(type, timestamp, mutation);
|
||||
#endif
|
||||
for (auto&& kv : keyspace->cf_meta_data()) {
|
||||
add_table_to_schema_mutation(kv.second, timestamp, true, mutations);
|
||||
add_table_to_schema_mutation(kv.second, timestamp, true, pkey, mutations);
|
||||
}
|
||||
}
|
||||
return mutations;
|
||||
@@ -1031,19 +997,17 @@ std::vector<mutation> make_create_table_mutations(lw_shared_ptr<keyspace_metadat
|
||||
{
|
||||
// Include the serialized keyspace in case the target node missed a CREATE KEYSPACE migration (see CASSANDRA-5631).
|
||||
auto mutations = make_create_keyspace_mutations(keyspace, timestamp, false);
|
||||
add_table_to_schema_mutation(table, timestamp, true, mutations);
|
||||
schema_ptr s = keyspaces();
|
||||
auto pkey = partition_key::from_singular(*s, keyspace->name());
|
||||
add_table_to_schema_mutation(table, timestamp, true, pkey, mutations);
|
||||
return mutations;
|
||||
}
|
||||
|
||||
schema_mutations make_table_mutations(schema_ptr table, api::timestamp_type timestamp, bool with_columns_and_triggers)
|
||||
void add_table_to_schema_mutation(schema_ptr table, api::timestamp_type timestamp, bool with_columns_and_triggers, const partition_key& pkey, std::vector<mutation>& mutations)
|
||||
{
|
||||
// When adding new schema properties, don't set cells for default values so that
|
||||
// both old and new nodes will see the same version during rolling upgrades.
|
||||
|
||||
// For property that can be null (and can be changed), we insert tombstones, to make sure
|
||||
// we don't keep a property the user has removed
|
||||
schema_ptr s = columnfamilies();
|
||||
auto pkey = partition_key::from_singular(*s, table->ks_name());
|
||||
mutation m{pkey, s};
|
||||
auto ckey = clustering_key::from_singular(*s, table->cf_name());
|
||||
m.set_clustered_cell(ckey, "cf_id", table->id(), timestamp);
|
||||
@@ -1102,24 +1066,16 @@ schema_mutations make_table_mutations(schema_ptr table, api::timestamp_type time
|
||||
if (table->compact_columns_count() == 1) {
|
||||
m.set_clustered_cell(ckey, "value_alias", table->compact_column().name_as_text(), timestamp);
|
||||
} // null if none
|
||||
|
||||
map_type_impl::mutation dropped_columns;
|
||||
auto dropped_columns_column = s->get_column_definition("dropped_columns");
|
||||
assert(dropped_columns_column);
|
||||
auto dropped_columns_type = static_pointer_cast<const map_type_impl>(dropped_columns_column->type);
|
||||
for (auto&& entry : table->dropped_columns()) {
|
||||
dropped_columns.cells.emplace_back(dropped_columns_type->get_keys_type()->decompose(data_value(entry.first)),
|
||||
atomic_cell::make_live(timestamp, dropped_columns_type->get_values_type()->decompose(entry.second)));
|
||||
}
|
||||
m.set_clustered_cell(ckey, *dropped_columns_column,
|
||||
atomic_cell_or_collection::from_collection_mutation(dropped_columns_type->serialize_mutation_form(std::move(dropped_columns))));
|
||||
#if 0
|
||||
for (Map.Entry<ColumnIdentifier, Long> entry : table.getDroppedColumns().entrySet())
|
||||
adder.addMapEntry("dropped_columns", entry.getKey().toString(), entry.getValue());
|
||||
#endif
|
||||
|
||||
m.set_clustered_cell(ckey, "is_dense", table->is_dense(), timestamp);
|
||||
|
||||
mutation columns_mutation(pkey, columns());
|
||||
if (with_columns_and_triggers) {
|
||||
for (auto&& column : table->all_columns_in_select_order()) {
|
||||
add_column_to_schema_mutation(table, column, timestamp, columns_mutation);
|
||||
add_column_to_schema_mutation(table, column, timestamp, pkey, mutations);
|
||||
}
|
||||
|
||||
#if 0
|
||||
@@ -1127,51 +1083,42 @@ schema_mutations make_table_mutations(schema_ptr table, api::timestamp_type time
|
||||
addTriggerToSchemaMutation(table, trigger, timestamp, mutation);
|
||||
#endif
|
||||
}
|
||||
return schema_mutations{std::move(m), std::move(columns_mutation)};
|
||||
mutations.emplace_back(std::move(m));
|
||||
}
|
||||
|
||||
void add_table_to_schema_mutation(schema_ptr table, api::timestamp_type timestamp, bool with_columns_and_triggers, std::vector<mutation>& mutations)
|
||||
{
|
||||
make_table_mutations(table, timestamp, with_columns_and_triggers).copy_to(mutations);
|
||||
}
|
||||
#if 0
|
||||
public static Mutation makeUpdateTableMutation(KSMetaData keyspace,
|
||||
CFMetaData oldTable,
|
||||
CFMetaData newTable,
|
||||
long timestamp,
|
||||
boolean fromThrift)
|
||||
{
|
||||
Mutation mutation = makeCreateKeyspaceMutation(keyspace, timestamp, false);
|
||||
|
||||
std::vector<mutation> make_update_table_mutations(lw_shared_ptr<keyspace_metadata> keyspace,
|
||||
schema_ptr old_table,
|
||||
schema_ptr new_table,
|
||||
api::timestamp_type timestamp,
|
||||
bool from_thrift)
|
||||
{
|
||||
// Include the serialized keyspace in case the target node missed a CREATE KEYSPACE migration (see CASSANDRA-5631).
|
||||
auto mutations = make_create_keyspace_mutations(keyspace, timestamp, false);
|
||||
addTableToSchemaMutation(newTable, timestamp, false, mutation);
|
||||
|
||||
add_table_to_schema_mutation(new_table, timestamp, false, mutations);
|
||||
MapDifference<ByteBuffer, ColumnDefinition> columnDiff = Maps.difference(oldTable.getColumnMetadata(),
|
||||
newTable.getColumnMetadata());
|
||||
|
||||
mutation columns_mutation(partition_key::from_singular(*columns(), old_table->ks_name()), columns());
|
||||
// columns that are no longer needed
|
||||
for (ColumnDefinition column : columnDiff.entriesOnlyOnLeft().values())
|
||||
{
|
||||
// Thrift only knows about the REGULAR ColumnDefinition type, so don't consider other type
|
||||
// are being deleted just because they are not here.
|
||||
if (fromThrift && column.kind != ColumnDefinition.Kind.REGULAR)
|
||||
continue;
|
||||
|
||||
auto diff = difference(old_table->all_columns(), new_table->all_columns());
|
||||
|
||||
// columns that are no longer needed
|
||||
for (auto&& name : diff.entries_only_on_left) {
|
||||
// Thrift only knows about the REGULAR ColumnDefinition type, so don't consider other type
|
||||
// are being deleted just because they are not here.
|
||||
const column_definition& column = *old_table->all_columns().at(name);
|
||||
if (from_thrift && !column.is_regular()) {
|
||||
continue;
|
||||
dropColumnFromSchemaMutation(oldTable, column, timestamp, mutation);
|
||||
}
|
||||
|
||||
drop_column_from_schema_mutation(old_table, column, timestamp, mutations);
|
||||
}
|
||||
// newly added columns
|
||||
for (ColumnDefinition column : columnDiff.entriesOnlyOnRight().values())
|
||||
addColumnToSchemaMutation(newTable, column, timestamp, mutation);
|
||||
|
||||
// newly added columns and old columns with updated attributes
|
||||
for (auto&& name : boost::range::join(diff.entries_differing, diff.entries_only_on_right)) {
|
||||
const column_definition& column = *new_table->all_columns().at(name);
|
||||
add_column_to_schema_mutation(new_table, column, timestamp, columns_mutation);
|
||||
}
|
||||
// old columns with updated attributes
|
||||
for (ByteBuffer name : columnDiff.entriesDiffering().keySet())
|
||||
addColumnToSchemaMutation(newTable, newTable.getColumnDefinition(name), timestamp, mutation);
|
||||
|
||||
mutations.emplace_back(std::move(columns_mutation));
|
||||
|
||||
warn(unimplemented::cause::TRIGGERS);
|
||||
#if 0
|
||||
MapDifference<String, TriggerDefinition> triggerDiff = Maps.difference(oldTable.getTriggers(), newTable.getTriggers());
|
||||
|
||||
// dropped triggers
|
||||
@@ -1182,9 +1129,9 @@ std::vector<mutation> make_update_table_mutations(lw_shared_ptr<keyspace_metadat
|
||||
for (TriggerDefinition trigger : triggerDiff.entriesOnlyOnRight().values())
|
||||
addTriggerToSchemaMutation(newTable, trigger, timestamp, mutation);
|
||||
|
||||
return mutation;
|
||||
}
|
||||
#endif
|
||||
return mutations;
|
||||
}
|
||||
|
||||
std::vector<mutation> make_drop_table_mutations(lw_shared_ptr<keyspace_metadata> keyspace, schema_ptr table, api::timestamp_type timestamp)
|
||||
{
|
||||
@@ -1212,39 +1159,13 @@ std::vector<mutation> make_drop_table_mutations(lw_shared_ptr<keyspace_metadata>
|
||||
return mutations;
|
||||
}
|
||||
|
||||
static future<schema_mutations> read_table_mutations(distributed<service::storage_proxy>& proxy, const qualified_name& table)
|
||||
{
|
||||
return read_schema_partition_for_table(proxy, COLUMNFAMILIES, table.keyspace_name, table.table_name)
|
||||
.then([&proxy, table] (mutation cf_m) {
|
||||
return read_schema_partition_for_table(proxy, COLUMNS, table.keyspace_name, table.table_name)
|
||||
.then([cf_m = std::move(cf_m)] (mutation col_m) {
|
||||
return schema_mutations{std::move(cf_m), std::move(col_m)};
|
||||
});
|
||||
#if 0
|
||||
// FIXME:
|
||||
Row serializedTriggers = readSchemaPartitionForTable(TRIGGERS, ksName, cfName);
|
||||
try
|
||||
{
|
||||
for (TriggerDefinition trigger : createTriggersFromTriggersPartition(serializedTriggers))
|
||||
cfm.addTriggerDefinition(trigger);
|
||||
}
|
||||
catch (InvalidRequestException e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
#endif
|
||||
});
|
||||
}
|
||||
|
||||
future<schema_ptr> create_table_from_name(distributed<service::storage_proxy>& proxy, const sstring& keyspace, const sstring& table)
|
||||
{
|
||||
return do_with(qualified_name(keyspace, table), [&proxy] (auto&& qn) {
|
||||
return read_table_mutations(proxy, qn).then([qn] (schema_mutations sm) {
|
||||
if (!sm.live()) {
|
||||
throw std::runtime_error(sprint("%s:%s not found in the schema definitions keyspace.", qn.keyspace_name, qn.table_name));
|
||||
}
|
||||
return create_table_from_mutations(std::move(sm));
|
||||
});
|
||||
return read_schema_partition_for_table(proxy, COLUMNFAMILIES, keyspace, table).then([&proxy, keyspace, table] (auto partition) {
|
||||
if (partition.second->empty()) {
|
||||
throw std::runtime_error(sprint("%s:%s not found in the schema definitions keyspace.", keyspace, table));
|
||||
}
|
||||
return create_table_from_table_partition(proxy, std::move(partition.second));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1273,6 +1194,18 @@ future<std::map<sstring, schema_ptr>> create_tables_from_tables_partition(distri
|
||||
}
|
||||
#endif
|
||||
|
||||
void create_table_from_table_row_and_columns_partition(schema_builder& builder, const query::result_set_row& table_row, const schema_result::value_type& serialized_columns)
|
||||
{
|
||||
create_table_from_table_row_and_column_rows(builder, table_row, serialized_columns.second);
|
||||
}
|
||||
|
||||
future<schema_ptr> create_table_from_table_partition(distributed<service::storage_proxy>& proxy, lw_shared_ptr<query::result_set>&& partition)
|
||||
{
|
||||
return do_with(std::move(partition), [&proxy] (auto& partition) {
|
||||
return create_table_from_table_row(proxy, partition->row(0));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Deserialize table metadata from low-level representation
|
||||
*
|
||||
@@ -1282,18 +1215,31 @@ future<schema_ptr> create_table_from_table_row(distributed<service::storage_prox
|
||||
{
|
||||
auto ks_name = row.get_nonnull<sstring>("keyspace_name");
|
||||
auto cf_name = row.get_nonnull<sstring>("columnfamily_name");
|
||||
return create_table_from_name(proxy, ks_name, cf_name);
|
||||
auto id = row.get_nonnull<utils::UUID>("cf_id");
|
||||
return read_schema_partition_for_table(proxy, COLUMNS, ks_name, cf_name).then([&row, ks_name, cf_name, id] (auto serialized_columns) {
|
||||
schema_builder builder{ks_name, cf_name, id};
|
||||
create_table_from_table_row_and_columns_partition(builder, row, serialized_columns);
|
||||
return builder.build();
|
||||
});
|
||||
#if 0
|
||||
// FIXME:
|
||||
Row serializedTriggers = readSchemaPartitionForTable(TRIGGERS, ksName, cfName);
|
||||
try
|
||||
{
|
||||
for (TriggerDefinition trigger : createTriggersFromTriggersPartition(serializedTriggers))
|
||||
cfm.addTriggerDefinition(trigger);
|
||||
}
|
||||
catch (InvalidRequestException e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
schema_ptr create_table_from_mutations(schema_mutations sm, std::experimental::optional<table_schema_version> version)
|
||||
void create_table_from_table_row_and_column_rows(schema_builder& builder, const query::result_set_row& table_row, const schema_result::mapped_type& serialized_column_definitions)
|
||||
{
|
||||
auto table_rs = query::result_set(sm.columnfamilies_mutation());
|
||||
query::result_set_row table_row = table_rs.row(0);
|
||||
|
||||
auto ks_name = table_row.get_nonnull<sstring>("keyspace_name");
|
||||
auto cf_name = table_row.get_nonnull<sstring>("columnfamily_name");
|
||||
auto id = table_row.get_nonnull<utils::UUID>("cf_id");
|
||||
schema_builder builder{ks_name, cf_name, id};
|
||||
|
||||
#if 0
|
||||
AbstractType<?> rawComparator = TypeParser.parse(result.getString("comparator"));
|
||||
@@ -1311,12 +1257,11 @@ schema_ptr create_table_from_mutations(schema_mutations sm, std::experimental::o
|
||||
AbstractType<?> fullRawComparator = CFMetaData.makeRawAbstractType(rawComparator, subComparator);
|
||||
#endif
|
||||
|
||||
std::vector<column_definition> column_defs = create_columns_from_column_rows(
|
||||
query::result_set(sm.columns_mutation()),
|
||||
ks_name,
|
||||
cf_name,/*,
|
||||
fullRawComparator, */
|
||||
cf == cf_type::super);
|
||||
std::vector<column_definition> column_defs = create_columns_from_column_rows(serialized_column_definitions,
|
||||
ks_name,
|
||||
cf_name,/*,
|
||||
fullRawComparator, */
|
||||
cf == cf_type::super);
|
||||
|
||||
bool is_dense;
|
||||
if (table_row.has("is_dense")) {
|
||||
@@ -1420,22 +1365,13 @@ schema_ptr create_table_from_mutations(schema_mutations sm, std::experimental::o
|
||||
builder.set_bloom_filter_fp_chance(builder.get_bloom_filter_fp_chance());
|
||||
}
|
||||
|
||||
if (table_row.has("dropped_columns")) {
|
||||
auto map = table_row.get_nonnull<map_type_impl::native_type>("dropped_columns");
|
||||
for (auto&& entry : map) {
|
||||
builder.without_column(value_cast<sstring>(entry.first), value_cast<api::timestamp_type>(entry.second));
|
||||
};
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (result.has("dropped_columns"))
|
||||
cfm.droppedColumns(convertDroppedColumns(result.getMap("dropped_columns", UTF8Type.instance, LongType.instance)));
|
||||
#endif
|
||||
for (auto&& cdef : column_defs) {
|
||||
builder.with_column(cdef);
|
||||
}
|
||||
if (version) {
|
||||
builder.with_version(*version);
|
||||
} else {
|
||||
builder.with_version(sm.digest());
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
#if 0
|
||||
@@ -1455,9 +1391,12 @@ schema_ptr create_table_from_mutations(schema_mutations sm, std::experimental::o
|
||||
void add_column_to_schema_mutation(schema_ptr table,
|
||||
const column_definition& column,
|
||||
api::timestamp_type timestamp,
|
||||
mutation& m)
|
||||
const partition_key& pkey,
|
||||
std::vector<mutation>& mutations)
|
||||
{
|
||||
auto ckey = clustering_key::from_exploded(*m.schema(), {utf8_type->decompose(table->cf_name()), column.name()});
|
||||
schema_ptr s = columns();
|
||||
mutation m{pkey, s};
|
||||
auto ckey = clustering_key::from_exploded(*s, {utf8_type->decompose(table->cf_name()), column.name()});
|
||||
m.set_clustered_cell(ckey, "validator", column.type->name(), timestamp);
|
||||
m.set_clustered_cell(ckey, "type", serialize_kind(column.kind), timestamp);
|
||||
if (!column.is_on_all_components()) {
|
||||
@@ -1468,6 +1407,7 @@ void add_column_to_schema_mutation(schema_ptr table,
|
||||
adder.add("index_type", column.getIndexType() == null ? null : column.getIndexType().toString());
|
||||
adder.add("index_options", json(column.getIndexOptions()));
|
||||
#endif
|
||||
mutations.emplace_back(std::move(m));
|
||||
}
|
||||
|
||||
sstring serialize_kind(column_kind kind)
|
||||
@@ -1508,14 +1448,14 @@ void drop_column_from_schema_mutation(schema_ptr table, const column_definition&
|
||||
mutations.emplace_back(m);
|
||||
}
|
||||
|
||||
std::vector<column_definition> create_columns_from_column_rows(const query::result_set& rows,
|
||||
std::vector<column_definition> create_columns_from_column_rows(const schema_result::mapped_type& rows,
|
||||
const sstring& keyspace,
|
||||
const sstring& table, /*,
|
||||
AbstractType<?> rawComparator, */
|
||||
bool is_super)
|
||||
{
|
||||
std::vector<column_definition> columns;
|
||||
for (auto&& row : rows.rows()) {
|
||||
for (auto&& row : rows->rows()) {
|
||||
columns.emplace_back(std::move(create_column_from_column_row(row, keyspace, table, /*, rawComparator, */ is_super)));
|
||||
}
|
||||
return columns;
|
||||
|
||||
@@ -43,8 +43,6 @@
|
||||
#include "service/storage_proxy.hh"
|
||||
#include "mutation.hh"
|
||||
#include "schema.hh"
|
||||
#include "hashing.hh"
|
||||
#include "schema_mutations.hh"
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
@@ -94,24 +92,17 @@ std::vector<mutation> make_drop_keyspace_mutations(lw_shared_ptr<keyspace_metada
|
||||
|
||||
lw_shared_ptr<keyspace_metadata> create_keyspace_from_schema_partition(const schema_result_value_type& partition);
|
||||
|
||||
future<> merge_tables(distributed<service::storage_proxy>& proxy, schema_result&& before, schema_result&& after);
|
||||
|
||||
lw_shared_ptr<keyspace_metadata> create_keyspace_from_schema_partition(const schema_result_value_type& partition);
|
||||
|
||||
mutation make_create_keyspace_mutation(lw_shared_ptr<keyspace_metadata> keyspace, api::timestamp_type timestamp, bool with_tables_and_types_and_functions = true);
|
||||
|
||||
std::vector<mutation> make_create_table_mutations(lw_shared_ptr<keyspace_metadata> keyspace, schema_ptr table, api::timestamp_type timestamp);
|
||||
|
||||
std::vector<mutation> make_update_table_mutations(
|
||||
lw_shared_ptr<keyspace_metadata> keyspace,
|
||||
schema_ptr old_table,
|
||||
schema_ptr new_table,
|
||||
api::timestamp_type timestamp,
|
||||
bool from_thrift);
|
||||
|
||||
schema_mutations make_table_mutations(schema_ptr table, api::timestamp_type timestamp, bool with_columns_and_triggers = true);
|
||||
|
||||
future<std::map<sstring, schema_ptr>> create_tables_from_tables_partition(distributed<service::storage_proxy>& proxy, const schema_result::mapped_type& result);
|
||||
|
||||
void add_table_to_schema_mutation(schema_ptr table, api::timestamp_type timestamp, bool with_columns_and_triggers, std::vector<mutation>& mutations);
|
||||
void add_table_to_schema_mutation(schema_ptr table, api::timestamp_type timestamp, bool with_columns_and_triggers, const partition_key& pkey, std::vector<mutation>& mutations);
|
||||
|
||||
std::vector<mutation> make_drop_table_mutations(lw_shared_ptr<keyspace_metadata> keyspace, schema_ptr table, api::timestamp_type timestamp);
|
||||
|
||||
@@ -119,11 +110,13 @@ future<schema_ptr> create_table_from_name(distributed<service::storage_proxy>& p
|
||||
|
||||
future<schema_ptr> create_table_from_table_row(distributed<service::storage_proxy>& proxy, const query::result_set_row& row);
|
||||
|
||||
schema_ptr create_table_from_mutations(schema_mutations, std::experimental::optional<table_schema_version> version = {});
|
||||
void create_table_from_table_row_and_column_rows(schema_builder& builder, const query::result_set_row& table_row, const schema_result::mapped_type& serialized_columns);
|
||||
|
||||
future<schema_ptr> create_table_from_table_partition(distributed<service::storage_proxy>& proxy, lw_shared_ptr<query::result_set>&& partition);
|
||||
|
||||
void drop_column_from_schema_mutation(schema_ptr table, const column_definition& column, long timestamp, std::vector<mutation>& mutations);
|
||||
|
||||
std::vector<column_definition> create_columns_from_column_rows(const query::result_set& rows,
|
||||
std::vector<column_definition> create_columns_from_column_rows(const schema_result::mapped_type& rows,
|
||||
const sstring& keyspace,
|
||||
const sstring& table,/*,
|
||||
AbstractType<?> rawComparator, */
|
||||
@@ -136,25 +129,11 @@ column_definition create_column_from_column_row(const query::result_set_row& row
|
||||
bool is_super);
|
||||
|
||||
|
||||
void add_column_to_schema_mutation(schema_ptr table, const column_definition& column, api::timestamp_type timestamp, mutation& mutation);
|
||||
void add_column_to_schema_mutation(schema_ptr table, const column_definition& column, api::timestamp_type timestamp, const partition_key& pkey, std::vector<mutation>& mutations);
|
||||
|
||||
sstring serialize_kind(column_kind kind);
|
||||
column_kind deserialize_kind(sstring kind);
|
||||
data_type parse_type(sstring str);
|
||||
|
||||
schema_ptr columns();
|
||||
schema_ptr columnfamilies();
|
||||
|
||||
template<typename Hasher>
|
||||
void feed_hash_for_schema_digest(Hasher& h, const mutation& m) {
|
||||
// Cassandra is skipping tombstones from digest calculation
|
||||
// to avoid disagreements due to tombstone GC.
|
||||
// See https://issues.apache.org/jira/browse/CASSANDRA-6862.
|
||||
// We achieve similar effect with compact_for_compaction().
|
||||
mutation m_compacted(m);
|
||||
m_compacted.partition().compact_for_compaction(*m.schema(), api::max_timestamp, gc_clock::time_point::max());
|
||||
feed_hash(h, m_compacted);
|
||||
}
|
||||
|
||||
} // namespace schema_tables
|
||||
} // namespace db
|
||||
|
||||
@@ -69,11 +69,6 @@ void db::serializer<bytes>::read(bytes& b, input& in) {
|
||||
b = in.read<bytes>();
|
||||
}
|
||||
|
||||
template<>
|
||||
void db::serializer<bytes>::skip(input& in) {
|
||||
in.read<bytes>(); // FIXME: Avoid reading
|
||||
}
|
||||
|
||||
template<>
|
||||
db::serializer<bytes_view>::serializer(const bytes_view& v)
|
||||
: _item(v), _size(output::serialized_size(v)) {
|
||||
@@ -109,11 +104,6 @@ void db::serializer<sstring>::read(sstring& s, input& in) {
|
||||
s = in.read<sstring>();
|
||||
}
|
||||
|
||||
template<>
|
||||
void db::serializer<sstring>::skip(input& in) {
|
||||
in.read<sstring>(); // FIXME: avoid reading
|
||||
}
|
||||
|
||||
template<>
|
||||
db::serializer<tombstone>::serializer(const tombstone& t)
|
||||
: _item(t), _size(sizeof(t.timestamp) + sizeof(decltype(t.deletion_time.time_since_epoch().count()))) {
|
||||
@@ -167,6 +157,81 @@ void db::serializer<collection_mutation_view>::read(collection_mutation_view& c,
|
||||
c = collection_mutation_view::from_bytes(bytes_view_serializer::read(in));
|
||||
}
|
||||
|
||||
template<>
|
||||
db::serializer<partition_key_view>::serializer(const partition_key_view& key)
|
||||
: _item(key), _size(sizeof(uint16_t) /* size */ + key.representation().size()) {
|
||||
}
|
||||
|
||||
template<>
|
||||
void db::serializer<partition_key_view>::write(output& out, const partition_key_view& key) {
|
||||
bytes_view v = key.representation();
|
||||
out.write<uint16_t>(v.size());
|
||||
out.write(v.begin(), v.end());
|
||||
}
|
||||
|
||||
template<>
|
||||
void db::serializer<partition_key_view>::read(partition_key_view& b, input& in) {
|
||||
auto len = in.read<uint16_t>();
|
||||
b = partition_key_view::from_bytes(in.read_view(len));
|
||||
}
|
||||
|
||||
template<>
|
||||
partition_key_view db::serializer<partition_key_view>::read(input& in) {
|
||||
auto len = in.read<uint16_t>();
|
||||
return partition_key_view::from_bytes(in.read_view(len));
|
||||
}
|
||||
|
||||
template<>
|
||||
void db::serializer<partition_key_view>::skip(input& in) {
|
||||
auto len = in.read<uint16_t>();
|
||||
in.skip(len);
|
||||
}
|
||||
|
||||
template<>
|
||||
db::serializer<clustering_key_prefix_view>::serializer(const clustering_key_prefix_view& key)
|
||||
: _item(key), _size(sizeof(uint16_t) /* size */ + key.representation().size()) {
|
||||
}
|
||||
|
||||
template<>
|
||||
void db::serializer<clustering_key_prefix_view>::write(output& out, const clustering_key_prefix_view& key) {
|
||||
bytes_view v = key.representation();
|
||||
out.write<uint16_t>(v.size());
|
||||
out.write(v.begin(), v.end());
|
||||
}
|
||||
|
||||
template<>
|
||||
void db::serializer<clustering_key_prefix_view>::read(clustering_key_prefix_view& b, input& in) {
|
||||
auto len = in.read<uint16_t>();
|
||||
b = clustering_key_prefix_view::from_bytes(in.read_view(len));
|
||||
}
|
||||
|
||||
template<>
|
||||
clustering_key_prefix_view db::serializer<clustering_key_prefix_view>::read(input& in) {
|
||||
auto len = in.read<uint16_t>();
|
||||
return clustering_key_prefix_view::from_bytes(in.read_view(len));
|
||||
}
|
||||
|
||||
template<>
|
||||
db::serializer<frozen_mutation>::serializer(const frozen_mutation& mutation)
|
||||
: _item(mutation), _size(sizeof(uint32_t) /* size */ + mutation.representation().size()) {
|
||||
}
|
||||
|
||||
template<>
|
||||
void db::serializer<frozen_mutation>::write(output& out, const frozen_mutation& mutation) {
|
||||
bytes_view v = mutation.representation();
|
||||
out.write(v);
|
||||
}
|
||||
|
||||
template<>
|
||||
void db::serializer<frozen_mutation>::read(frozen_mutation& m, input& in) {
|
||||
m = read(in);
|
||||
}
|
||||
|
||||
template<>
|
||||
frozen_mutation db::serializer<frozen_mutation>::read(input& in) {
|
||||
return frozen_mutation(bytes_serializer::read(in));
|
||||
}
|
||||
|
||||
template<>
|
||||
db::serializer<db::replay_position>::serializer(const db::replay_position& rp)
|
||||
: _item(rp), _size(sizeof(uint64_t) * 2) {
|
||||
@@ -191,4 +256,7 @@ template class db::serializer<sstring> ;
|
||||
template class db::serializer<atomic_cell_view> ;
|
||||
template class db::serializer<collection_mutation_view> ;
|
||||
template class db::serializer<utils::UUID> ;
|
||||
template class db::serializer<partition_key_view> ;
|
||||
template class db::serializer<clustering_key_prefix_view> ;
|
||||
template class db::serializer<frozen_mutation> ;
|
||||
template class db::serializer<db::replay_position> ;
|
||||
|
||||
@@ -28,7 +28,9 @@
|
||||
#include "utils/data_output.hh"
|
||||
#include "bytes_ostream.hh"
|
||||
#include "bytes.hh"
|
||||
#include "keys.hh"
|
||||
#include "database_fwd.hh"
|
||||
#include "frozen_mutation.hh"
|
||||
#include "db/commitlog/replay_position.hh"
|
||||
|
||||
namespace db {
|
||||
@@ -178,7 +180,6 @@ template<> utils::UUID serializer<utils::UUID>::read(input&);
|
||||
template<> serializer<bytes>::serializer(const bytes &);
|
||||
template<> void serializer<bytes>::write(output&, const type&);
|
||||
template<> void serializer<bytes>::read(bytes&, input&);
|
||||
template<> void serializer<bytes>::skip(input&);
|
||||
|
||||
template<> serializer<bytes_view>::serializer(const bytes_view&);
|
||||
template<> void serializer<bytes_view>::write(output&, const type&);
|
||||
@@ -188,7 +189,6 @@ template<> bytes_view serializer<bytes_view>::read(input&);
|
||||
template<> serializer<sstring>::serializer(const sstring&);
|
||||
template<> void serializer<sstring>::write(output&, const type&);
|
||||
template<> void serializer<sstring>::read(sstring&, input&);
|
||||
template<> void serializer<sstring>::skip(input&);
|
||||
|
||||
template<> serializer<tombstone>::serializer(const tombstone &);
|
||||
template<> void serializer<tombstone>::write(output&, const type&);
|
||||
@@ -203,6 +203,22 @@ template<> serializer<collection_mutation_view>::serializer(const collection_mut
|
||||
template<> void serializer<collection_mutation_view>::write(output&, const type&);
|
||||
template<> void serializer<collection_mutation_view>::read(collection_mutation_view&, input&);
|
||||
|
||||
template<> serializer<frozen_mutation>::serializer(const frozen_mutation &);
|
||||
template<> void serializer<frozen_mutation>::write(output&, const type&);
|
||||
template<> void serializer<frozen_mutation>::read(frozen_mutation&, input&);
|
||||
template<> frozen_mutation serializer<frozen_mutation>::read(input&);
|
||||
|
||||
template<> serializer<partition_key_view>::serializer(const partition_key_view &);
|
||||
template<> void serializer<partition_key_view>::write(output&, const partition_key_view&);
|
||||
template<> void serializer<partition_key_view>::read(partition_key_view&, input&);
|
||||
template<> partition_key_view serializer<partition_key_view>::read(input&);
|
||||
template<> void serializer<partition_key_view>::skip(input&);
|
||||
|
||||
template<> serializer<clustering_key_prefix_view>::serializer(const clustering_key_prefix_view &);
|
||||
template<> void serializer<clustering_key_prefix_view>::write(output&, const clustering_key_prefix_view&);
|
||||
template<> void serializer<clustering_key_prefix_view>::read(clustering_key_prefix_view&, input&);
|
||||
template<> clustering_key_prefix_view serializer<clustering_key_prefix_view>::read(input&);
|
||||
|
||||
template<> serializer<db::replay_position>::serializer(const db::replay_position&);
|
||||
template<> void serializer<db::replay_position>::write(output&, const db::replay_position&);
|
||||
template<> void serializer<db::replay_position>::read(db::replay_position&, input&);
|
||||
@@ -219,6 +235,9 @@ extern template class serializer<bytes>;
|
||||
extern template class serializer<bytes_view>;
|
||||
extern template class serializer<sstring>;
|
||||
extern template class serializer<utils::UUID>;
|
||||
extern template class serializer<partition_key_view>;
|
||||
extern template class serializer<clustering_key_view>;
|
||||
extern template class serializer<clustering_key_prefix_view>;
|
||||
extern template class serializer<db::replay_position>;
|
||||
|
||||
typedef serializer<tombstone> tombstone_serializer;
|
||||
@@ -228,6 +247,10 @@ typedef serializer<sstring> sstring_serializer;
|
||||
typedef serializer<atomic_cell_view> atomic_cell_view_serializer;
|
||||
typedef serializer<collection_mutation_view> collection_mutation_view_serializer;
|
||||
typedef serializer<utils::UUID> uuid_serializer;
|
||||
typedef serializer<partition_key_view> partition_key_view_serializer;
|
||||
typedef serializer<clustering_key_view> clustering_key_view_serializer;
|
||||
typedef serializer<clustering_key_prefix_view> clustering_key_prefix_view_serializer;
|
||||
typedef serializer<frozen_mutation> frozen_mutation_serializer;
|
||||
typedef serializer<db::replay_position> replay_position_serializer;
|
||||
|
||||
}
|
||||
|
||||
@@ -63,8 +63,6 @@
|
||||
#include "partition_slice_builder.hh"
|
||||
#include "db/config.hh"
|
||||
#include "schema_builder.hh"
|
||||
#include "md5_hasher.hh"
|
||||
#include "release.hh"
|
||||
#include <core/enum.hh>
|
||||
|
||||
using days = std::chrono::duration<int, std::ratio<24 * 3600>>;
|
||||
@@ -75,23 +73,6 @@ std::unique_ptr<query_context> qctx = {};
|
||||
|
||||
namespace system_keyspace {
|
||||
|
||||
static const api::timestamp_type creation_timestamp = api::new_timestamp();
|
||||
|
||||
api::timestamp_type schema_creation_timestamp() {
|
||||
return creation_timestamp;
|
||||
}
|
||||
|
||||
// Increase whenever changing schema of any system table.
|
||||
// FIXME: Make automatic by calculating from schema structure.
|
||||
static const uint16_t version_sequence_number = 1;
|
||||
|
||||
table_schema_version generate_schema_version(utils::UUID table_id) {
|
||||
md5_hasher h;
|
||||
feed_hash(h, table_id);
|
||||
feed_hash(h, version_sequence_number);
|
||||
return utils::UUID_gen::get_name_UUID(h.finalize());
|
||||
}
|
||||
|
||||
// Currently, the type variables (uuid_type, etc.) are thread-local reference-
|
||||
// counted shared pointers. This forces us to also make the built in schemas
|
||||
// below thread-local as well.
|
||||
@@ -120,7 +101,6 @@ schema_ptr hints() {
|
||||
)));
|
||||
builder.set_gc_grace_seconds(0);
|
||||
builder.set_compaction_strategy_options({{ "enabled", "false" }});
|
||||
builder.with_version(generate_schema_version(builder.uuid()));
|
||||
return builder.build(schema_builder::compact_storage::yes);
|
||||
}();
|
||||
return hints;
|
||||
@@ -146,7 +126,6 @@ schema_ptr batchlog() {
|
||||
// .compactionStrategyOptions(Collections.singletonMap("min_threshold", "2"))
|
||||
)));
|
||||
builder.set_gc_grace_seconds(0);
|
||||
builder.with_version(generate_schema_version(builder.uuid()));
|
||||
return builder.build(schema_builder::compact_storage::no);
|
||||
}();
|
||||
return batchlog;
|
||||
@@ -171,7 +150,6 @@ schema_ptr batchlog() {
|
||||
// operations on resulting CFMetaData:
|
||||
// .compactionStrategyClass(LeveledCompactionStrategy.class);
|
||||
)));
|
||||
builder.with_version(generate_schema_version(builder.uuid()));
|
||||
return builder.build(schema_builder::compact_storage::no);
|
||||
}();
|
||||
return paxos;
|
||||
@@ -193,7 +171,6 @@ schema_ptr built_indexes() {
|
||||
// comment
|
||||
"built column indexes"
|
||||
)));
|
||||
builder.with_version(generate_schema_version(builder.uuid()));
|
||||
return builder.build(schema_builder::compact_storage::yes);
|
||||
}();
|
||||
return built_indexes;
|
||||
@@ -235,7 +212,6 @@ schema_ptr built_indexes() {
|
||||
// comment
|
||||
"information about the local node"
|
||||
)));
|
||||
builder.with_version(generate_schema_version(builder.uuid()));
|
||||
return builder.build(schema_builder::compact_storage::no);
|
||||
}();
|
||||
return local;
|
||||
@@ -266,7 +242,6 @@ schema_ptr built_indexes() {
|
||||
// comment
|
||||
"information about known peers in the cluster"
|
||||
)));
|
||||
builder.with_version(generate_schema_version(builder.uuid()));
|
||||
return builder.build(schema_builder::compact_storage::no);
|
||||
}();
|
||||
return peers;
|
||||
@@ -290,7 +265,6 @@ schema_ptr built_indexes() {
|
||||
// comment
|
||||
"events related to peers"
|
||||
)));
|
||||
builder.with_version(generate_schema_version(builder.uuid()));
|
||||
return builder.build(schema_builder::compact_storage::no);
|
||||
}();
|
||||
return peer_events;
|
||||
@@ -312,7 +286,6 @@ schema_ptr built_indexes() {
|
||||
// comment
|
||||
"ranges requested for transfer"
|
||||
)));
|
||||
builder.with_version(generate_schema_version(builder.uuid()));
|
||||
return builder.build(schema_builder::compact_storage::no);
|
||||
}();
|
||||
return range_xfers;
|
||||
@@ -338,7 +311,6 @@ schema_ptr built_indexes() {
|
||||
// comment
|
||||
"unfinished compactions"
|
||||
)));
|
||||
builder.with_version(generate_schema_version(builder.uuid()));
|
||||
return builder.build(schema_builder::compact_storage::no);
|
||||
}();
|
||||
return compactions_in_progress;
|
||||
@@ -368,7 +340,6 @@ schema_ptr built_indexes() {
|
||||
"week-long compaction history"
|
||||
)));
|
||||
builder.set_default_time_to_live(std::chrono::duration_cast<std::chrono::seconds>(days(7)));
|
||||
builder.with_version(generate_schema_version(builder.uuid()));
|
||||
return builder.build(schema_builder::compact_storage::no);
|
||||
}();
|
||||
return compaction_history;
|
||||
@@ -397,7 +368,6 @@ schema_ptr built_indexes() {
|
||||
// comment
|
||||
"historic sstable read rates"
|
||||
)));
|
||||
builder.with_version(generate_schema_version(builder.uuid()));
|
||||
return builder.build(schema_builder::compact_storage::no);
|
||||
}();
|
||||
return sstable_activity;
|
||||
@@ -423,7 +393,6 @@ schema_ptr size_estimates() {
|
||||
"per-table primary range size estimates"
|
||||
)));
|
||||
builder.set_gc_grace_seconds(0);
|
||||
builder.with_version(generate_schema_version(builder.uuid()));
|
||||
return builder.build(schema_builder::compact_storage::no);
|
||||
}();
|
||||
return size_estimates;
|
||||
@@ -517,10 +486,6 @@ future<> init_local_cache() {
|
||||
});
|
||||
}
|
||||
|
||||
future<> deinit_local_cache() {
|
||||
return _local_cache.stop();
|
||||
}
|
||||
|
||||
void minimal_setup(distributed<database>& db, distributed<cql3::query_processor>& qp) {
|
||||
qctx = std::make_unique<query_context>(db, qp);
|
||||
}
|
||||
@@ -544,6 +509,7 @@ future<> setup(distributed<database>& db, distributed<cql3::query_processor>& qp
|
||||
return ms.init_local_preferred_ip_cache();
|
||||
});
|
||||
});
|
||||
return make_ready_future<>();
|
||||
}
|
||||
|
||||
typedef std::pair<replay_positions, db_clock::time_point> truncation_entry;
|
||||
@@ -1015,9 +981,8 @@ query_mutations(distributed<service::storage_proxy>& proxy, const sstring& cf_na
|
||||
database& db = proxy.local().get_db().local();
|
||||
schema_ptr schema = db.find_schema(db::system_keyspace::NAME, cf_name);
|
||||
auto slice = partition_slice_builder(*schema).build();
|
||||
auto cmd = make_lw_shared<query::read_command>(schema->id(), schema->version(),
|
||||
std::move(slice), std::numeric_limits<uint32_t>::max());
|
||||
return proxy.local().query_mutations_locally(std::move(schema), std::move(cmd), query::full_partition_range);
|
||||
auto cmd = make_lw_shared<query::read_command>(schema->id(), std::move(slice), std::numeric_limits<uint32_t>::max());
|
||||
return proxy.local().query_mutations_locally(cmd, query::full_partition_range);
|
||||
}
|
||||
|
||||
future<lw_shared_ptr<query::result_set>>
|
||||
@@ -1025,8 +990,7 @@ query(distributed<service::storage_proxy>& proxy, const sstring& cf_name) {
|
||||
database& db = proxy.local().get_db().local();
|
||||
schema_ptr schema = db.find_schema(db::system_keyspace::NAME, cf_name);
|
||||
auto slice = partition_slice_builder(*schema).build();
|
||||
auto cmd = make_lw_shared<query::read_command>(schema->id(), schema->version(),
|
||||
std::move(slice), std::numeric_limits<uint32_t>::max());
|
||||
auto cmd = make_lw_shared<query::read_command>(schema->id(), std::move(slice), std::numeric_limits<uint32_t>::max());
|
||||
return proxy.local().query(schema, cmd, {query::full_partition_range}, db::consistency_level::ONE).then([schema, cmd] (auto&& result) {
|
||||
return make_lw_shared(query::result_set::from_raw_result(schema, cmd->slice, *result));
|
||||
});
|
||||
@@ -1040,7 +1004,7 @@ query(distributed<service::storage_proxy>& proxy, const sstring& cf_name, const
|
||||
auto slice = partition_slice_builder(*schema)
|
||||
.with_range(std::move(row_range))
|
||||
.build();
|
||||
auto cmd = make_lw_shared<query::read_command>(schema->id(), schema->version(), std::move(slice), query::max_rows);
|
||||
auto cmd = make_lw_shared<query::read_command>(schema->id(), std::move(slice), query::max_rows);
|
||||
return proxy.local().query(schema, cmd, {query::partition_range::make_singular(key)}, db::consistency_level::ONE).then([schema, cmd] (auto&& result) {
|
||||
return make_lw_shared(query::result_set::from_raw_result(schema, cmd->slice, *result));
|
||||
});
|
||||
|
||||
@@ -84,13 +84,10 @@ extern schema_ptr hints();
|
||||
extern schema_ptr batchlog();
|
||||
extern schema_ptr built_indexes(); // TODO (from Cassandra): make private
|
||||
|
||||
table_schema_version generate_schema_version(utils::UUID table_id);
|
||||
|
||||
// Only for testing.
|
||||
void minimal_setup(distributed<database>& db, distributed<cql3::query_processor>& qp);
|
||||
|
||||
future<> init_local_cache();
|
||||
future<> deinit_local_cache();
|
||||
future<> setup(distributed<database>& db, distributed<cql3::query_processor>& qp);
|
||||
future<> update_schema_version(utils::UUID version);
|
||||
future<> update_tokens(std::unordered_set<dht::token> tokens);
|
||||
@@ -675,7 +672,5 @@ future<> set_bootstrap_state(bootstrap_state state);
|
||||
executeInternal(String.format(cql, SSTABLE_ACTIVITY), keyspace, table, generation);
|
||||
}
|
||||
#endif
|
||||
|
||||
api::timestamp_type schema_creation_timestamp();
|
||||
} // namespace system_keyspace
|
||||
} // namespace db
|
||||
|
||||
@@ -241,11 +241,12 @@ future<streaming::stream_state> range_streamer::fetch_async() {
|
||||
for (auto& x : fetch.second) {
|
||||
auto& source = x.first;
|
||||
auto& ranges = x.second;
|
||||
auto preferred = net::get_local_messaging_service().get_preferred_ip(source);
|
||||
/* Send messages to respective folks to stream data over to me */
|
||||
if (logger.is_enabled(logging::log_level::debug)) {
|
||||
logger.debug("{}ing from {} ranges {}", _description, source, ranges);
|
||||
}
|
||||
_stream_plan.request_ranges(source, keyspace, ranges);
|
||||
_stream_plan.request_ranges(source, preferred, keyspace, ranges);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
33
dist/ami/build_ami.sh
vendored
33
dist/ami/build_ami.sh
vendored
@@ -5,22 +5,15 @@ if [ ! -e dist/ami/build_ami.sh ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
print_usage() {
|
||||
echo "build_ami.sh -l"
|
||||
echo " -l deploy locally built rpms"
|
||||
TARGET_JSON=scylla.json
|
||||
if [ "$1" != "" ]; then
|
||||
TARGET_JSON=$1
|
||||
fi
|
||||
|
||||
if [ ! -f dist/ami/$TARGET_JSON ]; then
|
||||
echo "dist/ami/$TARGET_JSON does not found"
|
||||
exit 1
|
||||
}
|
||||
LOCALRPM=0
|
||||
while getopts lh OPT; do
|
||||
case "$OPT" in
|
||||
"l")
|
||||
LOCALRPM=1
|
||||
;;
|
||||
"h")
|
||||
print_usage
|
||||
;;
|
||||
esac
|
||||
done
|
||||
fi
|
||||
|
||||
cd dist/ami
|
||||
|
||||
@@ -37,12 +30,4 @@ if [ ! -d packer ]; then
|
||||
cd -
|
||||
fi
|
||||
|
||||
if [ $LOCALRPM = 0 ]; then
|
||||
echo "sudo sh -x -e /home/centos/scylla_install_pkg; sudo sh -x -e /usr/lib/scylla/scylla_setup -a" > scylla_deploy.sh
|
||||
else
|
||||
echo "sudo sh -x -e /home/centos/scylla_install_pkg -l /home/centos; sudo sh -x -e /usr/lib/scylla/scylla_setup -a" > scylla_deploy.sh
|
||||
|
||||
fi
|
||||
|
||||
chmod a+rx scylla_deploy.sh
|
||||
packer/packer build -var-file=variables.json scylla.json
|
||||
packer/packer build -var-file=variables.json $TARGET_JSON
|
||||
|
||||
17
dist/ami/build_ami_local.sh
vendored
17
dist/ami/build_ami_local.sh
vendored
@@ -5,27 +5,26 @@ if [ ! -e dist/ami/build_ami_local.sh ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
rm -rf build/*
|
||||
sudo yum -y install git
|
||||
if [ ! -f dist/ami/files/scylla-server.x86_64.rpm ]; then
|
||||
if [ ! -f dist/ami/scylla-server.x86_64.rpm ]; then
|
||||
dist/redhat/build_rpm.sh
|
||||
cp build/rpmbuild/RPMS/x86_64/scylla-server-`cat build/SCYLLA-VERSION-FILE`-`cat build/SCYLLA-RELEASE-FILE`.*.x86_64.rpm dist/ami/files/scylla-server.x86_64.rpm
|
||||
cp build/rpms/scylla-server-`cat build/SCYLLA-VERSION-FILE`-`cat build/SCYLLA-RELEASE-FILE`.*.x86_64.rpm dist/ami/scylla-server.x86_64.rpm
|
||||
fi
|
||||
if [ ! -f dist/ami/files/scylla-jmx.noarch.rpm ]; then
|
||||
if [ ! -f dist/ami/scylla-jmx.noarch.rpm ]; then
|
||||
cd build
|
||||
git clone --depth 1 https://github.com/scylladb/scylla-jmx.git
|
||||
cd scylla-jmx
|
||||
sh -x -e dist/redhat/build_rpm.sh $*
|
||||
sh -x -e dist/redhat/build_rpm.sh
|
||||
cd ../..
|
||||
cp build/scylla-jmx/build/rpmbuild/RPMS/noarch/scylla-jmx-`cat build/scylla-jmx/build/SCYLLA-VERSION-FILE`-`cat build/scylla-jmx/build/SCYLLA-RELEASE-FILE`.*.noarch.rpm dist/ami/files/scylla-jmx.noarch.rpm
|
||||
cp build/scylla-jmx/build/rpms/scylla-jmx-`cat build/scylla-jmx/build/SCYLLA-VERSION-FILE`-`cat build/scylla-jmx/build/SCYLLA-RELEASE-FILE`.*.noarch.rpm dist/ami/scylla-jmx.noarch.rpm
|
||||
fi
|
||||
if [ ! -f dist/ami/files/scylla-tools.noarch.rpm ]; then
|
||||
if [ ! -f dist/ami/scylla-tools.noarch.rpm ]; then
|
||||
cd build
|
||||
git clone --depth 1 https://github.com/scylladb/scylla-tools-java.git
|
||||
cd scylla-tools-java
|
||||
sh -x -e dist/redhat/build_rpm.sh
|
||||
cd ../..
|
||||
cp build/scylla-tools-java/build/rpmbuild/RPMS/noarch/scylla-tools-`cat build/scylla-tools-java/build/SCYLLA-VERSION-FILE`-`cat build/scylla-tools-java/build/SCYLLA-RELEASE-FILE`.*.noarch.rpm dist/ami/files/scylla-tools.noarch.rpm
|
||||
cp build/scylla-tools-java/build/rpms/scylla-tools-`cat build/scylla-tools-java/build/SCYLLA-VERSION-FILE`-`cat build/scylla-tools-java/build/SCYLLA-RELEASE-FILE`.*.noarch.rpm dist/ami/scylla-tools.noarch.rpm
|
||||
fi
|
||||
|
||||
exec dist/ami/build_ami.sh -l
|
||||
exec dist/ami/build_ami.sh scylla_local.json
|
||||
|
||||
4
dist/ami/files/.bash_profile
vendored
4
dist/ami/files/.bash_profile
vendored
@@ -23,7 +23,7 @@ echo ' |___/ '
|
||||
echo ''
|
||||
echo ''
|
||||
echo 'Nodetool:'
|
||||
echo ' nodetool help'
|
||||
echo ' nodetool --help'
|
||||
echo 'CQL Shell:'
|
||||
echo ' cqlsh'
|
||||
echo 'More documentation available at: '
|
||||
@@ -35,7 +35,6 @@ if [ "`systemctl is-active scylla-server`" = "active" ]; then
|
||||
tput bold
|
||||
echo " ScyllaDB is active."
|
||||
tput sgr0
|
||||
echo
|
||||
else
|
||||
tput setaf 1
|
||||
tput bold
|
||||
@@ -43,5 +42,4 @@ else
|
||||
tput sgr0
|
||||
echo "Please wait for startup. To see status of ScyllaDB, run "
|
||||
echo " 'systemctl status scylla-server'"
|
||||
echo
|
||||
fi
|
||||
|
||||
2
dist/ami/files/scylla-ami
vendored
2
dist/ami/files/scylla-ami
vendored
Submodule dist/ami/files/scylla-ami updated: eb1fdd4f41...07b71180d3
30
dist/ami/scylla.json
vendored
30
dist/ami/scylla.json
vendored
@@ -8,34 +8,34 @@
|
||||
"security_group_id": "{{user `security_group_id`}}",
|
||||
"region": "{{user `region`}}",
|
||||
"associate_public_ip_address": "{{user `associate_public_ip_address`}}",
|
||||
"source_ami": "ami-8ef1d6e4",
|
||||
"user_data_file": "user_data.txt",
|
||||
"source_ami": "ami-a51564c0",
|
||||
"instance_type": "{{user `instance_type`}}",
|
||||
"ssh_username": "centos",
|
||||
"ssh_username": "fedora",
|
||||
"ssh_timeout": "5m",
|
||||
"ami_name": "scylla_{{isotime | clean_ami_name}}",
|
||||
"launch_block_device_mappings": [
|
||||
{
|
||||
"device_name": "/dev/sda1",
|
||||
"volume_size": 10
|
||||
}
|
||||
]
|
||||
"ami_name": "scylla_{{isotime | clean_ami_name}}"
|
||||
}
|
||||
],
|
||||
"provisioners": [
|
||||
{
|
||||
"type": "file",
|
||||
"source": "files/",
|
||||
"destination": "/home/centos/"
|
||||
"source": "files/scylla-ami",
|
||||
"destination": "/home/fedora/scylla-ami"
|
||||
},
|
||||
{
|
||||
"type": "file",
|
||||
"source": "../../scripts/scylla_install_pkg",
|
||||
"destination": "/home/centos/scylla_install_pkg"
|
||||
"source": "files/.bash_profile",
|
||||
"destination": "/home/fedora/.bash_profile"
|
||||
},
|
||||
{
|
||||
"type": "file",
|
||||
"source": "../../scripts/scylla_install",
|
||||
"destination": "/home/fedora/scylla_install"
|
||||
},
|
||||
{
|
||||
"type": "shell",
|
||||
"script": "scylla_deploy.sh"
|
||||
"inline": [
|
||||
"sudo sh -x -e /home/fedora/scylla_install -a"
|
||||
]
|
||||
}
|
||||
],
|
||||
"variables": {
|
||||
|
||||
67
dist/ami/scylla_local.json
vendored
Normal file
67
dist/ami/scylla_local.json
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
{
|
||||
"builders": [
|
||||
{
|
||||
"type": "amazon-ebs",
|
||||
"access_key": "{{user `access_key`}}",
|
||||
"secret_key": "{{user `secret_key`}}",
|
||||
"subnet_id": "{{user `subnet_id`}}",
|
||||
"security_group_id": "{{user `security_group_id`}}",
|
||||
"region": "{{user `region`}}",
|
||||
"associate_public_ip_address": "{{user `associate_public_ip_address`}}",
|
||||
"source_ami": "ami-a51564c0",
|
||||
"instance_type": "{{user `instance_type`}}",
|
||||
"ssh_username": "fedora",
|
||||
"ssh_timeout": "5m",
|
||||
"ami_name": "scylla_{{isotime | clean_ami_name}}"
|
||||
}
|
||||
],
|
||||
"provisioners": [
|
||||
{
|
||||
"type": "file",
|
||||
"source": "files/scylla-ami",
|
||||
"destination": "/home/fedora/scylla-ami"
|
||||
},
|
||||
{
|
||||
"type": "file",
|
||||
"source": "files/.bash_profile",
|
||||
"destination": "/home/fedora/.bash_profile"
|
||||
},
|
||||
{
|
||||
"type": "file",
|
||||
"source": "../../scripts/scylla_install",
|
||||
"destination": "/home/fedora/scylla_install"
|
||||
},
|
||||
{
|
||||
"type": "file",
|
||||
"source": "scylla-server.x86_64.rpm",
|
||||
"destination": "/home/fedora/scylla-server.x86_64.rpm"
|
||||
},
|
||||
{
|
||||
"type": "file",
|
||||
"source": "scylla-jmx.noarch.rpm",
|
||||
"destination": "/home/fedora/scylla-jmx.noarch.rpm"
|
||||
},
|
||||
{
|
||||
"type": "file",
|
||||
"source": "scylla-tools.noarch.rpm",
|
||||
"destination": "/home/fedora/scylla-tools.noarch.rpm"
|
||||
},
|
||||
{
|
||||
"type": "shell",
|
||||
"inline": [
|
||||
"sudo yum install -y /home/fedora/scylla-server.x86_64.rpm /home/fedora/scylla-jmx.noarch.rpm /home/fedora/scylla-tools.noarch.rpm",
|
||||
"sudo mv /home/fedora/scylla-ami /usr/lib/scylla/scylla-ami",
|
||||
"sudo sh -x -e /home/fedora/scylla_install -a -l /home/fedora"
|
||||
]
|
||||
}
|
||||
],
|
||||
"variables": {
|
||||
"access_key": "",
|
||||
"secret_key": "",
|
||||
"subnet_id": "",
|
||||
"security_group_id": "",
|
||||
"region": "",
|
||||
"associate_public_ip_address": "",
|
||||
"instance_type": ""
|
||||
}
|
||||
}
|
||||
2
dist/ami/user_data.txt
vendored
2
dist/ami/user_data.txt
vendored
@@ -1,2 +0,0 @@
|
||||
#!/bin/sh
|
||||
sed -i 's/Defaults requiretty/#Defaults requiretty/g' /etc/sudoers
|
||||
56
dist/common/scripts/scylla_bootparam_setup
vendored
56
dist/common/scripts/scylla_bootparam_setup
vendored
@@ -2,23 +2,47 @@
|
||||
#
|
||||
# Copyright (C) 2015 ScyllaDB
|
||||
|
||||
print_usage() {
|
||||
echo "scylla_bootparam_setup -a"
|
||||
echo " -a AMI instance mode"
|
||||
exit 1
|
||||
}
|
||||
|
||||
AMI=0
|
||||
while getopts a OPT; do
|
||||
case "$OPT" in
|
||||
"a")
|
||||
AMI=1
|
||||
;;
|
||||
"h")
|
||||
print_usage
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
. /etc/os-release
|
||||
|
||||
. /etc/sysconfig/scylla-server
|
||||
if [ ! -f /etc/default/grub ]; then
|
||||
echo "Unsupported bootloader"
|
||||
exit 1
|
||||
fi
|
||||
if [ "`grep hugepagesz /etc/default/grub`" != "" ] || [ "`grep hugepages /etc/default/grub`" != "" ]; then
|
||||
sed -e "s#hugepagesz=2M ##" /etc/default/grub > /tmp/grub
|
||||
mv /tmp/grub /etc/default/grub
|
||||
sed -e "s#hugepages=[0-9]* ##" /etc/default/grub > /tmp/grub
|
||||
mv /tmp/grub /etc/default/grub
|
||||
fi
|
||||
sed -e "s#^GRUB_CMDLINE_LINUX=\"#GRUB_CMDLINE_LINUX=\"hugepagesz=2M hugepages=$NR_HUGEPAGES #" /etc/default/grub > /tmp/grub
|
||||
mv /tmp/grub /etc/default/grub
|
||||
if [ "$ID" = "ubuntu" ]; then
|
||||
grub2-mkconfig -o /boot/grub/grub.cfg
|
||||
if [ $AMI -eq 1 ]; then
|
||||
. /etc/sysconfig/scylla-server
|
||||
sed -e "s#append #append clocksource=tsc tsc=reliable hugepagesz=2M hugepages=$NR_HUGEPAGES #" /boot/extlinux/extlinux.conf > /tmp/extlinux.conf
|
||||
mv /tmp/extlinux.conf /boot/extlinux/extlinux.conf
|
||||
else
|
||||
grub2-mkconfig -o /boot/grub2/grub.cfg
|
||||
. /etc/sysconfig/scylla-server
|
||||
if [ ! -f /etc/default/grub ]; then
|
||||
echo "Unsupported bootloader"
|
||||
exit 1
|
||||
fi
|
||||
if [ "`grep hugepagesz /etc/default/grub`" != "" ] || [ "`grep hugepages /etc/default/grub`" != "" ]; then
|
||||
sed -e "s#hugepagesz=2M ##" /etc/default/grub > /tmp/grub
|
||||
mv /tmp/grub /etc/default/grub
|
||||
sed -e "s#hugepages=[0-9]* ##" /etc/default/grub > /tmp/grub
|
||||
mv /tmp/grub /etc/default/grub
|
||||
fi
|
||||
sed -e "s#^GRUB_CMDLINE_LINUX=\"#GRUB_CMDLINE_LINUX=\"hugepagesz=2M hugepages=$NR_HUGEPAGES #" /etc/default/grub > /tmp/grub
|
||||
mv /tmp/grub /etc/default/grub
|
||||
if [ "$ID" = "ubuntu" ]; then
|
||||
grub2-mkconfig -o /boot/grub/grub.cfg
|
||||
else
|
||||
grub2-mkconfig -o /boot/grub2/grub.cfg
|
||||
fi
|
||||
fi
|
||||
|
||||
38
dist/common/scripts/scylla_coredump_setup
vendored
38
dist/common/scripts/scylla_coredump_setup
vendored
@@ -2,43 +2,15 @@
|
||||
#
|
||||
# Copyright (C) 2015 ScyllaDB
|
||||
|
||||
print_usage() {
|
||||
echo "scylla_coredump_setup -s"
|
||||
echo " -s store coredump to /var/lib/scylla"
|
||||
exit 1
|
||||
}
|
||||
|
||||
SYMLINK=0
|
||||
while getopts sh OPT; do
|
||||
case "$OPT" in
|
||||
"s")
|
||||
SYMLINK=1
|
||||
;;
|
||||
"h")
|
||||
print_usage
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
|
||||
. /etc/os-release
|
||||
|
||||
if [ "$ID" = "ubuntu" ]; then
|
||||
apt-get remove -y apport-noui
|
||||
sysctl -p /etc/sysctl.d/99-scylla.conf
|
||||
else
|
||||
cat << EOS > /etc/systemd/coredump.conf
|
||||
[Coredump]
|
||||
Storage=external
|
||||
Compress=yes
|
||||
ProcessSizeMax=1024G
|
||||
ExternalSizeMax=1024G
|
||||
EOS
|
||||
if [ $SYMLINK = 1 ]; then
|
||||
rm -rf /var/lib/systemd/coredump
|
||||
ln -sf /var/lib/scylla/coredump /var/lib/systemd/coredump
|
||||
if [ -f /etc/systemd/coredump.conf ]; then
|
||||
mv /etc/systemd/coredump.conf /etc/systemd/coredump.conf.save
|
||||
systemctl daemon-reload
|
||||
fi
|
||||
systemctl daemon-reload
|
||||
echo "kernel.core_pattern=|/usr/lib/systemd/systemd-coredump %p %u %g %s %t %e" > /etc/sysctl.d/99-coredump.conf
|
||||
sysctl -p /etc/sysctl.d/99-coredump.conf
|
||||
fi
|
||||
|
||||
sysctl -p /etc/sysctl.d/99-scylla.conf
|
||||
|
||||
5
dist/common/scripts/scylla_ntp_setup
vendored
5
dist/common/scripts/scylla_ntp_setup
vendored
@@ -32,10 +32,7 @@ else
|
||||
sed -e s#fedora.pool.ntp.org#amazon.pool.ntp.org# /etc/ntp.conf > /tmp/ntp.conf
|
||||
mv /tmp/ntp.conf /etc/ntp.conf
|
||||
fi
|
||||
if [ "`systemctl is-active ntpd`" = "active" ]; then
|
||||
systemctl stop ntpd.service
|
||||
fi
|
||||
ntpdate `cat /etc/ntp.conf |grep "^server"|head -n1|awk '{print $2}'`
|
||||
systemctl enable ntpd.service
|
||||
ntpdate `cat /etc/ntp.conf |grep "^server"|head -n1|awk '{print $2}'`
|
||||
systemctl start ntpd.service
|
||||
fi
|
||||
|
||||
2
dist/common/scripts/scylla_prepare
vendored
2
dist/common/scripts/scylla_prepare
vendored
@@ -30,6 +30,8 @@ if [ "$AMI" = "yes" ]; then
|
||||
|
||||
if [ "$DISKS" != "" ]; then
|
||||
/usr/lib/scylla/scylla_raid_setup -d $DISKS
|
||||
else
|
||||
echo "WARN: Scylla is not using XFS to store data. Perforamnce will suffer." > /home/fedora/WARN_PLEASE_READ.TXT
|
||||
fi
|
||||
|
||||
/usr/lib/scylla/scylla-ami/ds2_configure.py
|
||||
|
||||
@@ -7,4 +7,4 @@ TIME=`date --date @$2 +%F-%T`
|
||||
PID=$3
|
||||
|
||||
mkdir -p /var/lib/scylla/coredump
|
||||
cat - > /var/lib/scylla/coredump/core.$FILE-$TIME-$PID
|
||||
/usr/bin/gzip -c > /var/lib/scylla/coredump/core.$FILE-$TIME-$PID.gz
|
||||
76
dist/common/scripts/scylla_setup
vendored
76
dist/common/scripts/scylla_setup
vendored
@@ -1,76 +0,0 @@
|
||||
#!/bin/sh -e
|
||||
#
|
||||
# Copyright (C) 2015 ScyllaDB
|
||||
|
||||
if [ "`id -u`" -ne 0 ]; then
|
||||
echo "Requires root permission."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
print_usage() {
|
||||
echo "scylla_setup -d /dev/hda,/dev/hdb... -n eth0 -a"
|
||||
echo " -d specify disks for RAID"
|
||||
echo " -n specify NIC"
|
||||
echo " -a setup AMI instance"
|
||||
exit 1
|
||||
}
|
||||
|
||||
NIC=eth0
|
||||
RAID=/dev/md0
|
||||
AMI=0
|
||||
while getopts d:n:al:h OPT; do
|
||||
case "$OPT" in
|
||||
"n")
|
||||
NIC=$OPTARG
|
||||
;;
|
||||
"d")
|
||||
DISKS=$OPTARG
|
||||
;;
|
||||
"a")
|
||||
AMI=1
|
||||
;;
|
||||
"h")
|
||||
print_usage
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
SYSCONFIG_SETUP_ARGS="-n $NIC"
|
||||
. /etc/os-release
|
||||
|
||||
if [ "$ID" != "ubuntu" ]; then
|
||||
if [ "`sestatus | awk '{print $3}'`" != "disabled" ]; then
|
||||
setenforce 0
|
||||
sed -e "s/enforcing/disabled/" /etc/sysconfig/selinux > /tmp/selinux
|
||||
mv /tmp/selinux /etc/sysconfig/
|
||||
fi
|
||||
if [ $AMI -eq 1 ]; then
|
||||
SYSCONFIG_SETUP_ARGS="$SYSCONFIG_SETUP_ARGS -N -a"
|
||||
if [ "$LOCAL_PKG" = "" ]; then
|
||||
yum update -y
|
||||
else
|
||||
SYSCONFIG_SETUP_ARGS="$SYSCONFIG_SETUP_ARGS -k"
|
||||
fi
|
||||
grep -v ' - mounts' /etc/cloud/cloud.cfg > /tmp/cloud.cfg
|
||||
mv /tmp/cloud.cfg /etc/cloud/cloud.cfg
|
||||
mv /home/centos/scylla-ami /usr/lib/scylla/scylla-ami
|
||||
chmod a+rx /usr/lib/scylla/scylla-ami/ds2_configure.py
|
||||
fi
|
||||
systemctl enable scylla-server.service
|
||||
systemctl enable scylla-jmx.service
|
||||
fi
|
||||
if [ $AMI -eq 0 ]; then
|
||||
/usr/lib/scylla/scylla_ntp_setup
|
||||
/usr/lib/scylla/scylla_bootparam_setup
|
||||
if [ $DISKS != "" ]; then
|
||||
/usr/lib/scylla/scylla_raid_setup -d $DISKS -u
|
||||
/usr/lib/scylla/scylla_coredump_setup -s
|
||||
else
|
||||
/usr/lib/scylla/scylla_coredump_setup
|
||||
fi
|
||||
else
|
||||
/usr/lib/scylla/scylla_coredump_setup -s
|
||||
/usr/lib/scylla/scylla_ntp_setup -a
|
||||
/usr/lib/scylla/scylla_bootparam_setup -a
|
||||
fi
|
||||
/usr/lib/scylla/scylla_sysconfig_setup $SYSCONFIG_SETUP_ARGS
|
||||
1
dist/common/sudoers.d/scylla
vendored
1
dist/common/sudoers.d/scylla
vendored
@@ -1 +0,0 @@
|
||||
scylla ALL=(ALL) NOPASSWD:SETENV: /usr/lib/scylla/scylla_prepare,/usr/lib/scylla/scylla_stop
|
||||
10
dist/docker/Dockerfile
vendored
10
dist/docker/Dockerfile
vendored
@@ -1,13 +1,11 @@
|
||||
FROM centos:7
|
||||
FROM fedora:22
|
||||
|
||||
MAINTAINER Avi Kivity <avi@cloudius-systems.com>
|
||||
|
||||
RUN yum -y install epel-release
|
||||
ADD scylla.repo /etc/yum.repos.d/
|
||||
RUN yum -y update
|
||||
RUN yum -y remove boost-thread boost-system
|
||||
RUN yum -y install scylla-server hostname
|
||||
RUN yum clean all
|
||||
RUN dnf -y update
|
||||
RUN dnf -y install scylla-server hostname
|
||||
RUN dnf clean all
|
||||
ADD start-scylla /start-scylla
|
||||
RUN chown scylla /start-scylla
|
||||
|
||||
|
||||
20
dist/docker/scylla.repo
vendored
20
dist/docker/scylla.repo
vendored
@@ -1,23 +1,11 @@
|
||||
[scylla]
|
||||
name=Scylla for Centos $releasever - $basearch
|
||||
baseurl=https://s3.amazonaws.com/downloads.scylladb.com/rpm/centos/$releasever/$basearch/
|
||||
name=Scylla for Fedora $releasever - $basearch
|
||||
baseurl=https://s3.amazonaws.com/downloads.scylladb.com/rpm/fedora/$releasever/$basearch/
|
||||
enabled=1
|
||||
gpgcheck=0
|
||||
|
||||
[scylla-generic]
|
||||
name=Scylla for centos $releasever
|
||||
baseurl=https://s3.amazonaws.com/downloads.scylladb.com/rpm/centos/$releasever/noarch/
|
||||
enabled=1
|
||||
gpgcheck=0
|
||||
|
||||
[scylla-3rdparty]
|
||||
name=Scylla 3rdParty for Centos $releasever - $basearch
|
||||
baseurl=https://s3.amazonaws.com/downloads.scylladb.com/rpm/3rdparty/centos/$releasever/$basearch/
|
||||
enabled=1
|
||||
gpgcheck=0
|
||||
|
||||
[scylla-3rdparty-generic]
|
||||
name=Scylla 3rdParty for Centos $releasever
|
||||
baseurl=https://s3.amazonaws.com/downloads.scylladb.com/rpm/3rdparty/centos/$releasever/noarch/
|
||||
name=Scylla for Fedora $releasever
|
||||
baseurl=https://s3.amazonaws.com/downloads.scylladb.com/rpm/fedora/$releasever/noarch/
|
||||
enabled=1
|
||||
gpgcheck=0
|
||||
|
||||
26
dist/redhat/build_rpm.sh
vendored
26
dist/redhat/build_rpm.sh
vendored
@@ -1,22 +1,5 @@
|
||||
#!/bin/sh -e
|
||||
|
||||
print_usage() {
|
||||
echo "build_rpm.sh -R"
|
||||
echo " -R rebuild dependency packages (CentOS)"
|
||||
exit 1
|
||||
}
|
||||
REBUILD=0
|
||||
while getopts Rh OPT; do
|
||||
case "$OPT" in
|
||||
"R")
|
||||
REBUILD=1
|
||||
;;
|
||||
"h")
|
||||
print_usage
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
RPMBUILD=`pwd`/build/rpmbuild
|
||||
|
||||
if [ ! -e dist/redhat/build_rpm.sh ]; then
|
||||
@@ -39,12 +22,7 @@ if [ ! -f /usr/bin/git ]; then
|
||||
fi
|
||||
mkdir -p $RPMBUILD/{BUILD,BUILDROOT,RPMS,SOURCES,SPECS,SRPMS}
|
||||
if [ "$ID" = "centos" ]; then
|
||||
sudo yum install -y epel-release
|
||||
if [ $REBUILD = 1 ]; then
|
||||
./dist/redhat/centos_dep/build_dependency.sh
|
||||
else
|
||||
sudo curl https://s3.amazonaws.com/downloads.scylladb.com/rpm/centos/scylla.repo -o /etc/yum.repos.d/scylla.repo
|
||||
fi
|
||||
./dist/redhat/centos_dep/build_dependency.sh
|
||||
fi
|
||||
VERSION=$(./SCYLLA-VERSION-GEN)
|
||||
SCYLLA_VERSION=$(cat build/SCYLLA-VERSION-FILE)
|
||||
@@ -59,7 +37,7 @@ if [ "$ID" = "fedora" ]; then
|
||||
rpmbuild -bs --define "_topdir $RPMBUILD" $RPMBUILD/SPECS/scylla-server.spec
|
||||
mock rebuild --resultdir=`pwd`/build/rpms $RPMBUILD/SRPMS/scylla-server-$VERSION*.src.rpm
|
||||
else
|
||||
sudo yum-builddep -y $RPMBUILD/SPECS/scylla-server.spec
|
||||
. /etc/profile.d/scylla.sh
|
||||
sudo yum-builddep -y $RPMBUILD/SPECS/scylla-server.spec
|
||||
rpmbuild -ba --define "_topdir $RPMBUILD" $RPMBUILD/SPECS/scylla-server.spec
|
||||
fi
|
||||
|
||||
1
dist/redhat/centos_dep/build_dependency.sh
vendored
1
dist/redhat/centos_dep/build_dependency.sh
vendored
@@ -38,6 +38,7 @@ fi
|
||||
|
||||
cd -
|
||||
|
||||
sudo yum install -y epel-release
|
||||
sudo yum install -y cryptopp cryptopp-devel jsoncpp jsoncpp-devel lz4 lz4-devel yaml-cpp yaml-cpp-devel thrift thrift-devel scons gtest gtest-devel python34
|
||||
sudo ln -sf /usr/bin/python3.4 /usr/bin/python3
|
||||
|
||||
|
||||
2
dist/redhat/scripts/scylla_run
vendored
2
dist/redhat/scripts/scylla_run
vendored
@@ -11,4 +11,4 @@ elif [ "$NETWORK_MODE" = "dpdk" ]; then
|
||||
fi
|
||||
|
||||
export HOME=/var/lib/scylla
|
||||
exec /usr/bin/scylla $args
|
||||
exec sudo -E -u $USER /usr/bin/scylla $args
|
||||
|
||||
16
dist/redhat/scylla-server.spec.in
vendored
16
dist/redhat/scylla-server.spec.in
vendored
@@ -8,9 +8,9 @@ License: AGPLv3
|
||||
URL: http://www.scylladb.com/
|
||||
Source0: %{name}-@@VERSION@@-@@RELEASE@@.tar
|
||||
|
||||
BuildRequires: libaio-devel libstdc++-devel cryptopp-devel hwloc-devel numactl-devel libpciaccess-devel libxml2-devel zlib-devel thrift-devel yaml-cpp-devel lz4-devel snappy-devel jsoncpp-devel systemd-devel xz-devel openssl-devel libcap-devel libselinux-devel libgcrypt-devel libgpg-error-devel elfutils-devel krb5-devel libcom_err-devel libattr-devel pcre-devel elfutils-libelf-devel bzip2-devel keyutils-libs-devel xfsprogs-devel make gnutls-devel systemd-devel
|
||||
%{?fedora:BuildRequires: boost-devel ninja-build ragel antlr3-tool antlr3-C++-devel python3 gcc-c++ libasan libubsan}
|
||||
%{?rhel:BuildRequires: scylla-libstdc++-static scylla-boost-devel scylla-ninja-build scylla-ragel scylla-antlr3-tool scylla-antlr3-C++-devel python34 scylla-gcc-c++ >= 5.1.1}
|
||||
BuildRequires: libaio-devel boost-devel libstdc++-devel cryptopp-devel hwloc-devel numactl-devel libpciaccess-devel libxml2-devel zlib-devel thrift-devel yaml-cpp-devel lz4-devel snappy-devel jsoncpp-devel systemd-devel xz-devel openssl-devel libcap-devel libselinux-devel libgcrypt-devel libgpg-error-devel elfutils-devel krb5-devel libcom_err-devel libattr-devel pcre-devel elfutils-libelf-devel bzip2-devel keyutils-libs-devel xfsprogs-devel make gnutls-devel
|
||||
%{?fedora:BuildRequires: ninja-build ragel antlr3-tool antlr3-C++-devel python3 gcc-c++ libasan libubsan}
|
||||
%{?rhel:BuildRequires: scylla-ninja-build scylla-ragel scylla-antlr3-tool scylla-antlr3-C++-devel python34 scylla-gcc-c++ >= 5.1.1}
|
||||
Requires: systemd-libs xfsprogs mdadm hwloc
|
||||
|
||||
%description
|
||||
@@ -28,24 +28,24 @@ Requires: systemd-libs xfsprogs mdadm hwloc
|
||||
./configure.py --with scylla --disable-xen --enable-dpdk --mode=release
|
||||
%endif
|
||||
%if 0%{?rhel}
|
||||
python3.4 ./configure.py --with scylla --disable-xen --enable-dpdk --mode=release --static-stdc++ --compiler=/opt/scylladb/bin/g++ --python python3.4
|
||||
./configure.py --with scylla --disable-xen --enable-dpdk --mode=release --static-stdc++ --compiler=/opt/scylladb/bin/g++
|
||||
%endif
|
||||
ninja-build -j2
|
||||
|
||||
%install
|
||||
rm -rf $RPM_BUILD_ROOT
|
||||
mkdir -p $RPM_BUILD_ROOT%{_bindir}
|
||||
mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/sysctl.d/
|
||||
mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/sysconfig/
|
||||
mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/security/limits.d/
|
||||
mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/sudoers.d/
|
||||
mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/scylla/
|
||||
mkdir -p $RPM_BUILD_ROOT%{_docdir}/scylla/
|
||||
mkdir -p $RPM_BUILD_ROOT%{_unitdir}
|
||||
mkdir -p $RPM_BUILD_ROOT%{_prefix}/lib/scylla/
|
||||
|
||||
install -m644 dist/common/sysctl.d/99-scylla.conf $RPM_BUILD_ROOT%{_sysconfdir}/sysctl.d/
|
||||
install -m644 dist/common/sysconfig/scylla-server $RPM_BUILD_ROOT%{_sysconfdir}/sysconfig/
|
||||
install -m644 dist/common/limits.d/scylla.conf $RPM_BUILD_ROOT%{_sysconfdir}/security/limits.d/
|
||||
install -m644 dist/common/sudoers.d/scylla $RPM_BUILD_ROOT%{_sysconfdir}/sudoers.d/
|
||||
install -d -m755 $RPM_BUILD_ROOT%{_sysconfdir}/scylla
|
||||
install -m644 conf/scylla.yaml $RPM_BUILD_ROOT%{_sysconfdir}/scylla/
|
||||
install -m644 conf/cassandra-rackdc.properties $RPM_BUILD_ROOT%{_sysconfdir}/scylla/
|
||||
@@ -128,7 +128,7 @@ rm -rf $RPM_BUILD_ROOT
|
||||
|
||||
%config(noreplace) %{_sysconfdir}/sysconfig/scylla-server
|
||||
%{_sysconfdir}/security/limits.d/scylla.conf
|
||||
%{_sysconfdir}/sudoers.d/scylla
|
||||
%{_sysconfdir}/sysctl.d/99-scylla.conf
|
||||
%attr(0755,root,root) %dir %{_sysconfdir}/scylla
|
||||
%config(noreplace) %{_sysconfdir}/scylla/scylla.yaml
|
||||
%config(noreplace) %{_sysconfdir}/scylla/cassandra-rackdc.properties
|
||||
@@ -142,7 +142,7 @@ rm -rf $RPM_BUILD_ROOT
|
||||
%{_prefix}/lib/scylla/scylla_prepare
|
||||
%{_prefix}/lib/scylla/scylla_run
|
||||
%{_prefix}/lib/scylla/scylla_stop
|
||||
%{_prefix}/lib/scylla/scylla_setup
|
||||
%{_prefix}/lib/scylla/scylla_save_coredump
|
||||
%{_prefix}/lib/scylla/scylla_coredump_setup
|
||||
%{_prefix}/lib/scylla/scylla_raid_setup
|
||||
%{_prefix}/lib/scylla/scylla_sysconfig_setup
|
||||
|
||||
7
dist/redhat/systemd/scylla-server.service
vendored
7
dist/redhat/systemd/scylla-server.service
vendored
@@ -3,19 +3,18 @@ Description=Scylla Server
|
||||
After=network.target libvirtd.service
|
||||
|
||||
[Service]
|
||||
Type=notify
|
||||
Type=simple
|
||||
LimitMEMLOCK=infinity
|
||||
LimitNOFILE=200000
|
||||
LimitAS=infinity
|
||||
LimitNPROC=8096
|
||||
EnvironmentFile=/etc/sysconfig/scylla-server
|
||||
ExecStartPre=/usr/bin/sudo -E /usr/lib/scylla/scylla_prepare
|
||||
ExecStartPre=/usr/lib/scylla/scylla_prepare
|
||||
ExecStart=/usr/lib/scylla/scylla_run
|
||||
ExecStopPost=/usr/bin/sudo -E /usr/lib/scylla/scylla_stop
|
||||
ExecStopPost=/usr/lib/scylla/scylla_stop
|
||||
TimeoutStartSec=900
|
||||
KillMode=process
|
||||
Restart=no
|
||||
User=scylla
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
|
||||
3
dist/ubuntu/build_deb.sh
vendored
3
dist/ubuntu/build_deb.sh
vendored
@@ -21,6 +21,9 @@ fi
|
||||
VERSION=$(./SCYLLA-VERSION-GEN)
|
||||
SCYLLA_VERSION=$(cat build/SCYLLA-VERSION-FILE)
|
||||
SCYLLA_RELEASE=$(cat build/SCYLLA-RELEASE-FILE)
|
||||
if [ "$SCYLLA_VERSION" = "development" ]; then
|
||||
SCYLLA_VERSION=0development
|
||||
fi
|
||||
echo $VERSION > version
|
||||
./scripts/git-archive-all --extra version --force-submodules --prefix scylla-server ../scylla-server_$SCYLLA_VERSION-$SCYLLA_RELEASE.orig.tar.gz
|
||||
|
||||
|
||||
2
dist/ubuntu/debian/rules
vendored
2
dist/ubuntu/debian/rules
vendored
@@ -23,7 +23,7 @@ override_dh_auto_install:
|
||||
cp $(CURDIR)/dist/common/limits.d/scylla.conf $(LIMITS)
|
||||
|
||||
mkdir -p $(SYSCTL) && \
|
||||
cp $(CURDIR)/dist/ubuntu/sysctl.d/99-scylla.conf $(SYSCTL)
|
||||
cp $(CURDIR)/dist/common/sysctl.d/99-scylla.conf $(SYSCTL)
|
||||
|
||||
mkdir -p $(CONF) && \
|
||||
cp $(CURDIR)/conf/scylla.yaml $(CONF)
|
||||
|
||||
@@ -162,22 +162,6 @@ public:
|
||||
using cassandra_exception::cassandra_exception;
|
||||
};
|
||||
|
||||
class unauthorized_exception: public request_validation_exception {
|
||||
public:
|
||||
unauthorized_exception(sstring msg)
|
||||
: request_validation_exception(exception_code::UNAUTHORIZED,
|
||||
std::move(msg)) {
|
||||
}
|
||||
};
|
||||
|
||||
class authentication_exception: public request_validation_exception {
|
||||
public:
|
||||
authentication_exception(sstring msg)
|
||||
: request_validation_exception(exception_code::BAD_CREDENTIALS,
|
||||
std::move(msg)) {
|
||||
}
|
||||
};
|
||||
|
||||
class invalid_request_exception : public request_validation_exception {
|
||||
public:
|
||||
invalid_request_exception(sstring cause)
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
//
|
||||
// Representation layout:
|
||||
//
|
||||
// <mutation> ::= <column-family-id> <schema-version> <partition-key> <partition>
|
||||
// <mutation> ::= <column-family-id> <partition-key> <partition>
|
||||
//
|
||||
|
||||
using namespace db;
|
||||
@@ -43,18 +43,10 @@ frozen_mutation::column_family_id() const {
|
||||
return uuid_serializer::read(in);
|
||||
}
|
||||
|
||||
utils::UUID
|
||||
frozen_mutation::schema_version() const {
|
||||
data_input in(_bytes);
|
||||
uuid_serializer::skip(in); // cf_id
|
||||
return uuid_serializer::read(in);
|
||||
}
|
||||
|
||||
partition_key_view
|
||||
frozen_mutation::key(const schema& s) const {
|
||||
data_input in(_bytes);
|
||||
uuid_serializer::skip(in); // cf_id
|
||||
uuid_serializer::skip(in); // schema_version
|
||||
uuid_serializer::skip(in);
|
||||
return partition_key_view_serializer::read(in);
|
||||
}
|
||||
|
||||
@@ -70,21 +62,14 @@ frozen_mutation::frozen_mutation(bytes&& b)
|
||||
frozen_mutation::frozen_mutation(const mutation& m) {
|
||||
auto&& id = m.schema()->id();
|
||||
partition_key_view key_view = m.key();
|
||||
auto version = m.schema()->version();
|
||||
|
||||
uuid_serializer id_ser(id);
|
||||
uuid_serializer schema_version_ser(version);
|
||||
partition_key_view_serializer key_ser(key_view);
|
||||
mutation_partition_serializer part_ser(*m.schema(), m.partition());
|
||||
|
||||
bytes buf(bytes::initialized_later(),
|
||||
id_ser.size()
|
||||
+ schema_version_ser.size()
|
||||
+ key_ser.size()
|
||||
+ part_ser.size_without_framing());
|
||||
bytes buf(bytes::initialized_later(), id_ser.size() + key_ser.size() + part_ser.size_without_framing());
|
||||
data_output out(buf);
|
||||
id_ser.write(out);
|
||||
schema_version_ser.write(out);
|
||||
key_ser.write(out);
|
||||
part_ser.write_without_framing(out);
|
||||
|
||||
@@ -105,8 +90,7 @@ frozen_mutation freeze(const mutation& m) {
|
||||
|
||||
mutation_partition_view frozen_mutation::partition() const {
|
||||
data_input in(_bytes);
|
||||
uuid_serializer::skip(in); // cf_id
|
||||
uuid_serializer::skip(in); // schema_version
|
||||
uuid_serializer::skip(in);
|
||||
partition_key_view_serializer::skip(in);
|
||||
return mutation_partition_view::from_bytes(in.read_view(in.avail()));
|
||||
}
|
||||
@@ -118,26 +102,3 @@ std::ostream& operator<<(std::ostream& out, const frozen_mutation::printer& pr)
|
||||
frozen_mutation::printer frozen_mutation::pretty_printer(schema_ptr s) const {
|
||||
return { *this, std::move(s) };
|
||||
}
|
||||
|
||||
template class db::serializer<frozen_mutation>;
|
||||
|
||||
template<>
|
||||
db::serializer<frozen_mutation>::serializer(const frozen_mutation& mutation)
|
||||
: _item(mutation), _size(sizeof(uint32_t) /* size */ + mutation.representation().size()) {
|
||||
}
|
||||
|
||||
template<>
|
||||
void db::serializer<frozen_mutation>::write(output& out, const frozen_mutation& mutation) {
|
||||
bytes_view v = mutation.representation();
|
||||
out.write(v);
|
||||
}
|
||||
|
||||
template<>
|
||||
void db::serializer<frozen_mutation>::read(frozen_mutation& m, input& in) {
|
||||
m = read(in);
|
||||
}
|
||||
|
||||
template<>
|
||||
frozen_mutation db::serializer<frozen_mutation>::read(input& in) {
|
||||
return frozen_mutation(bytes_serializer::read(in));
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
|
||||
#include "dht/i_partitioner.hh"
|
||||
#include "atomic_cell.hh"
|
||||
#include "database_fwd.hh"
|
||||
#include "keys.hh"
|
||||
#include "mutation_partition_view.hh"
|
||||
|
||||
class mutation;
|
||||
@@ -51,7 +51,6 @@ public:
|
||||
|
||||
bytes_view representation() const { return _bytes; }
|
||||
utils::UUID column_family_id() const;
|
||||
utils::UUID schema_version() const; // FIXME: Should replace column_family_id()
|
||||
partition_key_view key(const schema& s) const;
|
||||
dht::decorated_key decorated_key(const schema& s) const;
|
||||
mutation_partition_view partition() const;
|
||||
@@ -67,14 +66,3 @@ public:
|
||||
};
|
||||
|
||||
frozen_mutation freeze(const mutation& m);
|
||||
|
||||
namespace db {
|
||||
|
||||
typedef serializer<frozen_mutation> frozen_mutation_serializer;
|
||||
|
||||
template<> serializer<frozen_mutation>::serializer(const frozen_mutation &);
|
||||
template<> void serializer<frozen_mutation>::write(output&, const type&);
|
||||
template<> void serializer<frozen_mutation>::read(frozen_mutation&, input&);
|
||||
template<> frozen_mutation serializer<frozen_mutation>::read(input&);
|
||||
|
||||
}
|
||||
|
||||
@@ -1,64 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015 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 "frozen_schema.hh"
|
||||
#include "db/schema_tables.hh"
|
||||
#include "schema_mutations.hh"
|
||||
|
||||
template class db::serializer<frozen_schema>;
|
||||
|
||||
frozen_schema::frozen_schema(const schema_ptr& s)
|
||||
: _data([&s] {
|
||||
bytes_ostream out;
|
||||
db::serializer<table_schema_version>(s->version()).write(out);
|
||||
schema_mutations sm = db::schema_tables::make_table_mutations(s, api::new_timestamp());
|
||||
db::serializer<schema_mutations>(sm).write(out);
|
||||
return to_bytes(out.linearize());
|
||||
}())
|
||||
{ }
|
||||
|
||||
schema_ptr frozen_schema::unfreeze() const {
|
||||
data_input in(_data);
|
||||
auto version = db::serializer<table_schema_version>::read(in);
|
||||
auto mutations = db::serializer<schema_mutations>::read(in);
|
||||
return db::schema_tables::create_table_from_mutations(mutations, version);
|
||||
}
|
||||
|
||||
frozen_schema::frozen_schema(bytes b)
|
||||
: _data(std::move(b))
|
||||
{ }
|
||||
|
||||
template<>
|
||||
db::serializer<frozen_schema>::serializer(const frozen_schema& v)
|
||||
: _item(v)
|
||||
, _size(db::serializer<bytes>(v._data).size())
|
||||
{ }
|
||||
|
||||
template<>
|
||||
void
|
||||
db::serializer<frozen_schema>::write(output& out, const frozen_schema& v) {
|
||||
db::serializer<bytes>(v._data).write(out);
|
||||
}
|
||||
|
||||
template<>
|
||||
frozen_schema db::serializer<frozen_schema>::read(input& in) {
|
||||
return frozen_schema(db::serializer<bytes>::read(in));
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015 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 "query-result.hh"
|
||||
#include "schema.hh"
|
||||
#include "db/serializer.hh"
|
||||
#include "frozen_mutation.hh"
|
||||
|
||||
// Transport for schema_ptr across shards/nodes.
|
||||
// It's safe to access from another shard by const&.
|
||||
class frozen_schema {
|
||||
bytes _data;
|
||||
private:
|
||||
frozen_schema(bytes);
|
||||
public:
|
||||
frozen_schema(const schema_ptr&);
|
||||
frozen_schema(frozen_schema&&) = default;
|
||||
frozen_schema(const frozen_schema&) = default;
|
||||
frozen_schema& operator=(const frozen_schema&) = default;
|
||||
frozen_schema& operator=(frozen_schema&&) = default;
|
||||
schema_ptr unfreeze() const;
|
||||
friend class db::serializer<frozen_schema>;
|
||||
};
|
||||
|
||||
namespace db {
|
||||
|
||||
template<> serializer<frozen_schema>::serializer(const frozen_schema&);
|
||||
template<> void serializer<frozen_schema>::write(output&, const frozen_schema&);
|
||||
template<> frozen_schema serializer<frozen_schema>::read(input&);
|
||||
|
||||
extern template class serializer<frozen_schema>;
|
||||
|
||||
}
|
||||
@@ -187,7 +187,7 @@ future<gossip_digest_ack> gossiper::handle_syn_msg(gossip_digest_syn syn_msg) {
|
||||
return make_ready_future<gossip_digest_ack>(std::move(ack_msg));
|
||||
}
|
||||
|
||||
future<> gossiper::handle_ack_msg(msg_addr id, gossip_digest_ack ack_msg) {
|
||||
future<> gossiper::handle_ack_msg(shard_id id, gossip_digest_ack ack_msg) {
|
||||
this->set_last_processed_message_at();
|
||||
if (!this->is_enabled() && !this->is_in_shadow_round()) {
|
||||
return make_ready_future<>();
|
||||
@@ -295,7 +295,7 @@ future<bool> gossiper::send_gossip(gossip_digest_syn message, std::set<inet_addr
|
||||
std::uniform_int_distribution<int> dist(0, size - 1);
|
||||
int index = dist(_random);
|
||||
inet_address to = __live_endpoints[index];
|
||||
auto id = get_msg_addr(to);
|
||||
auto id = get_shard_id(to);
|
||||
logger.trace("Sending a GossipDigestSyn to {} ...", id);
|
||||
return ms().send_gossip_digest_syn(id, std::move(message)).then_wrapped([this, id] (auto&& f) {
|
||||
try {
|
||||
@@ -577,7 +577,6 @@ void gossiper::run() {
|
||||
}).then_wrapped([this] (auto&& f) {
|
||||
try {
|
||||
f.get();
|
||||
_nr_run++;
|
||||
logger.trace("=== Gossip round OK");
|
||||
} catch (...) {
|
||||
logger.trace("=== Gossip round FAIL");
|
||||
@@ -1046,7 +1045,7 @@ void gossiper::mark_alive(inet_address addr, endpoint_state& local_state) {
|
||||
// }
|
||||
|
||||
local_state.mark_dead();
|
||||
msg_addr id = get_msg_addr(addr);
|
||||
shard_id id = get_shard_id(addr);
|
||||
logger.trace("Sending a EchoMessage to {}", id);
|
||||
auto ok = make_shared<bool>(false);
|
||||
ms().send_echo(id).then_wrapped([this, id, ok] (auto&& f) mutable {
|
||||
@@ -1305,7 +1304,6 @@ future<> gossiper::start_gossiping(int generation_nbr, std::map<application_stat
|
||||
return locator::i_endpoint_snitch::get_local_snitch_ptr()->gossiper_starting().then([this, &local_state] {
|
||||
logger.trace("gossip started with generation {}", local_state.get_heart_beat_state().get_generation());
|
||||
_enabled = true;
|
||||
_nr_run = 0;
|
||||
_scheduled_gossip_task.arm(INTERVAL);
|
||||
return make_ready_future<>();
|
||||
});
|
||||
@@ -1322,7 +1320,7 @@ future<> gossiper::do_shadow_round() {
|
||||
for (inet_address seed : _seeds) {
|
||||
std::vector<gossip_digest> digests;
|
||||
gossip_digest_syn message(get_cluster_name(), get_partitioner_name(), digests);
|
||||
auto id = get_msg_addr(seed);
|
||||
auto id = get_shard_id(seed);
|
||||
logger.trace("Sending a GossipDigestSyn (ShadowRound) to {} ...", id);
|
||||
ms().send_gossip_digest_syn(id, std::move(message)).then_wrapped([this, id] (auto&& f) {
|
||||
try {
|
||||
@@ -1418,7 +1416,7 @@ future<> gossiper::do_stop_gossiping() {
|
||||
logger.info("Announcing shutdown");
|
||||
add_local_application_state(application_state::STATUS, storage_service_value_factory().shutdown(true)).get();
|
||||
for (inet_address addr : _live_endpoints) {
|
||||
msg_addr id = get_msg_addr(addr);
|
||||
shard_id id = get_shard_id(addr);
|
||||
logger.trace("Sending a GossipShutdown to {}", id);
|
||||
ms().send_gossip_shutdown(id, get_broadcast_address()).then_wrapped([id] (auto&&f) {
|
||||
try {
|
||||
@@ -1558,64 +1556,4 @@ sstring gossiper::get_gossip_status(const inet_address& endpoint) const {
|
||||
return get_gossip_status(*ep_state);
|
||||
}
|
||||
|
||||
future<> gossiper::wait_for_gossip_to_settle() {
|
||||
return seastar::async([this] {
|
||||
auto& cfg = service::get_local_storage_service().db().local().get_config();
|
||||
auto force_after = cfg.skip_wait_for_gossip_to_settle();
|
||||
if (force_after == 0) {
|
||||
return;
|
||||
}
|
||||
static constexpr std::chrono::milliseconds GOSSIP_SETTLE_MIN_WAIT_MS{5000};
|
||||
static constexpr std::chrono::milliseconds GOSSIP_SETTLE_POLL_INTERVAL_MS{1000};
|
||||
static constexpr int32_t GOSSIP_SETTLE_POLL_SUCCESSES_REQUIRED = 3;
|
||||
int32_t total_polls = 0;
|
||||
int32_t num_okay = 0;
|
||||
logger.info("Waiting for gossip to settle before accepting client requests...");
|
||||
sleep(GOSSIP_SETTLE_MIN_WAIT_MS).get();
|
||||
while (num_okay < GOSSIP_SETTLE_POLL_SUCCESSES_REQUIRED) {
|
||||
sleep(GOSSIP_SETTLE_POLL_INTERVAL_MS).get();
|
||||
total_polls++;
|
||||
// Make sure 5 gossip rounds are completed sucessfully
|
||||
if (_nr_run > 5) {
|
||||
logger.debug("Gossip looks settled. {} gossip round completed: {}", _nr_run);
|
||||
num_okay++;
|
||||
} else {
|
||||
logger.info("Gossip not settled after {} polls.", total_polls);
|
||||
num_okay = 0;
|
||||
}
|
||||
if (force_after > 0 && total_polls > force_after) {
|
||||
logger.warn("Gossip not settled but startup forced by cassandra.skip_wait_for_gossip_to_settle.", total_polls);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (total_polls > GOSSIP_SETTLE_POLL_SUCCESSES_REQUIRED) {
|
||||
logger.info("Gossip settled after {} extra polls; proceeding", total_polls - GOSSIP_SETTLE_POLL_SUCCESSES_REQUIRED);
|
||||
} else {
|
||||
logger.info("No gossip backlog; proceeding");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
bool gossiper::is_safe_for_bootstrap(inet_address endpoint) {
|
||||
auto eps = get_endpoint_state_for_endpoint(endpoint);
|
||||
|
||||
// if there's no previous state, or the node was previously removed from the cluster, we're good
|
||||
if (!eps || is_dead_state(*eps)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
sstring status = get_gossip_status(*eps);
|
||||
|
||||
logger.debug("is_safe_for_bootstrap: node {} status {}", endpoint, status);
|
||||
|
||||
// these states are not allowed to join the cluster as it would not be safe
|
||||
std::unordered_set<sstring> unsafe_statuses{
|
||||
sstring(""), // failed bootstrap but we did start gossiping
|
||||
sstring(versioned_value::STATUS_NORMAL), // node is legit in the cluster or it was stopped with kill -9
|
||||
sstring(versioned_value::SHUTDOWN) // node was shutdown
|
||||
};
|
||||
|
||||
return !unsafe_statuses.count(status);
|
||||
}
|
||||
|
||||
} // namespace gms
|
||||
|
||||
@@ -82,17 +82,17 @@ public:
|
||||
private:
|
||||
using messaging_verb = net::messaging_verb;
|
||||
using messaging_service = net::messaging_service;
|
||||
using msg_addr = net::messaging_service::msg_addr;
|
||||
using shard_id = net::messaging_service::shard_id;
|
||||
net::messaging_service& ms() {
|
||||
return net::get_local_messaging_service();
|
||||
}
|
||||
void init_messaging_service_handler();
|
||||
void uninit_messaging_service_handler();
|
||||
future<gossip_digest_ack> handle_syn_msg(gossip_digest_syn syn_msg);
|
||||
future<> handle_ack_msg(msg_addr id, gossip_digest_ack ack_msg);
|
||||
future<> handle_ack_msg(shard_id id, gossip_digest_ack ack_msg);
|
||||
static constexpr uint32_t _default_cpuid = 0;
|
||||
msg_addr get_msg_addr(inet_address to) {
|
||||
return msg_addr{to, _default_cpuid};
|
||||
shard_id get_shard_id(inet_address to) {
|
||||
return shard_id{to, _default_cpuid};
|
||||
}
|
||||
void do_sort(std::vector<gossip_digest>& g_digest_list);
|
||||
timer<clk> _scheduled_gossip_task;
|
||||
@@ -347,7 +347,6 @@ public:
|
||||
future<int> get_current_heart_beat_version(inet_address endpoint);
|
||||
|
||||
bool is_gossip_only_member(inet_address endpoint);
|
||||
bool is_safe_for_bootstrap(inet_address endpoint);
|
||||
private:
|
||||
/**
|
||||
* Returns true if the chosen target was also a seed. False otherwise
|
||||
@@ -501,10 +500,6 @@ public:
|
||||
private:
|
||||
sstring get_gossip_status(const endpoint_state& ep_state) const;
|
||||
sstring get_gossip_status(const inet_address& endpoint) const;
|
||||
public:
|
||||
future<> wait_for_gossip_to_settle();
|
||||
private:
|
||||
uint64_t _nr_run = 0;
|
||||
};
|
||||
|
||||
extern distributed<gossiper> _the_gossiper;
|
||||
|
||||
159
hashing.hh
159
hashing.hh
@@ -1,159 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2015 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 <chrono>
|
||||
#include <map>
|
||||
#include <experimental/optional>
|
||||
#include <seastar/core/byteorder.hh>
|
||||
#include <seastar/core/sstring.hh>
|
||||
|
||||
//
|
||||
// This hashing differs from std::hash<> in that it decouples knowledge about
|
||||
// type structure from the way the hash value is calculated:
|
||||
// * appending_hash<T> instantiation knows about what data should be included in the hash for type T.
|
||||
// * Hasher object knows how to combine the data into the final hash.
|
||||
//
|
||||
// The appending_hash<T> should always feed some data into the hasher, regardless of the state the object is in,
|
||||
// in order for the hash to be highly sensitive for value changes. For example, vector<optional<T>> should
|
||||
// ideally feed different values for empty vector and a vector with a single empty optional.
|
||||
//
|
||||
// appending_hash<T> is machine-independent.
|
||||
//
|
||||
|
||||
// The Hasher concept
|
||||
struct Hasher {
|
||||
void update(const char* ptr, size_t size);
|
||||
};
|
||||
|
||||
template<typename T, typename Enable = void>
|
||||
struct appending_hash;
|
||||
|
||||
template<typename Hasher, typename T>
|
||||
inline
|
||||
void feed_hash(Hasher& h, const T& value) {
|
||||
appending_hash<T>()(h, value);
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct appending_hash<T, std::enable_if_t<std::is_arithmetic<T>::value>> {
|
||||
template<typename Hasher>
|
||||
void operator()(Hasher& h, T value) const {
|
||||
auto value_le = cpu_to_le(value);
|
||||
h.update(reinterpret_cast<const char*>(&value_le), sizeof(T));
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct appending_hash<bool> {
|
||||
template<typename Hasher>
|
||||
void operator()(Hasher& h, bool value) const {
|
||||
feed_hash(h, static_cast<uint8_t>(value));
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct appending_hash<T, std::enable_if_t<std::is_enum<T>::value>> {
|
||||
template<typename Hasher>
|
||||
void operator()(Hasher& h, const T& value) const {
|
||||
feed_hash(h, static_cast<std::underlying_type_t<T>>(value));
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct appending_hash<std::experimental::optional<T>> {
|
||||
template<typename Hasher>
|
||||
void operator()(Hasher& h, const std::experimental::optional<T>& value) const {
|
||||
if (value) {
|
||||
feed_hash(h, true);
|
||||
feed_hash(h, *value);
|
||||
} else {
|
||||
feed_hash(h, false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<size_t N>
|
||||
struct appending_hash<char[N]> {
|
||||
template<typename Hasher>
|
||||
void operator()(Hasher& h, const char (&value) [N]) const {
|
||||
feed_hash(h, N);
|
||||
h.update(value, N);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct appending_hash<std::vector<T>> {
|
||||
template<typename Hasher>
|
||||
void operator()(Hasher& h, const std::vector<T>& value) const {
|
||||
feed_hash(h, value.size());
|
||||
for (auto&& v : value) {
|
||||
appending_hash<T>()(h, v);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<typename K, typename V>
|
||||
struct appending_hash<std::map<K, V>> {
|
||||
template<typename Hasher>
|
||||
void operator()(Hasher& h, const std::map<K, V>& value) const {
|
||||
feed_hash(h, value.size());
|
||||
for (auto&& e : value) {
|
||||
appending_hash<K>()(h, e.first);
|
||||
appending_hash<V>()(h, e.second);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct appending_hash<sstring> {
|
||||
template<typename Hasher>
|
||||
void operator()(Hasher& h, const sstring& v) const {
|
||||
feed_hash(h, v.size());
|
||||
h.update(reinterpret_cast<const char*>(v.cbegin()), v.size() * sizeof(sstring::value_type));
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct appending_hash<std::string> {
|
||||
template<typename Hasher>
|
||||
void operator()(Hasher& h, const std::string& v) const {
|
||||
feed_hash(h, v.size());
|
||||
h.update(reinterpret_cast<const char*>(v.data()), v.size() * sizeof(std::string::value_type));
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T, typename R>
|
||||
struct appending_hash<std::chrono::duration<T, R>> {
|
||||
template<typename Hasher>
|
||||
void operator()(Hasher& h, std::chrono::duration<T, R> v) const {
|
||||
feed_hash(h, v.count());
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Clock, typename Duration>
|
||||
struct appending_hash<std::chrono::time_point<Clock, Duration>> {
|
||||
template<typename Hasher>
|
||||
void operator()(Hasher& h, std::chrono::time_point<Clock, Duration> v) const {
|
||||
feed_hash(h, v.time_since_epoch().count());
|
||||
}
|
||||
};
|
||||
@@ -1,85 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2015 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 "mutation_partition_visitor.hh"
|
||||
#include "hashing.hh"
|
||||
#include "schema.hh"
|
||||
#include "atomic_cell_hash.hh"
|
||||
#include "keys.hh"
|
||||
|
||||
// Calculates a hash of a mutation_partition which is consistent with
|
||||
// mutation equality. For any equal mutations, no matter which schema
|
||||
// version they were generated under, the hash fed will be the same for both of them.
|
||||
template<typename Hasher>
|
||||
class hashing_partition_visitor : public mutation_partition_visitor {
|
||||
Hasher& _h;
|
||||
const schema& _s;
|
||||
public:
|
||||
hashing_partition_visitor(Hasher& h, const schema& s)
|
||||
: _h(h)
|
||||
, _s(s)
|
||||
{ }
|
||||
|
||||
virtual void accept_partition_tombstone(tombstone t) {
|
||||
feed_hash(_h, t);
|
||||
}
|
||||
|
||||
virtual void accept_static_cell(column_id id, atomic_cell_view cell) {
|
||||
auto&& col = _s.static_column_at(id);
|
||||
feed_hash(_h, col.name());
|
||||
feed_hash(_h, col.type->name());
|
||||
feed_hash(_h, cell);
|
||||
}
|
||||
|
||||
virtual void accept_static_cell(column_id id, collection_mutation_view cell) {
|
||||
auto&& col = _s.static_column_at(id);
|
||||
feed_hash(_h, col.name());
|
||||
feed_hash(_h, col.type->name());
|
||||
feed_hash(cell, _h, col.type);
|
||||
}
|
||||
|
||||
virtual void accept_row_tombstone(clustering_key_prefix_view prefix, tombstone t) {
|
||||
prefix.feed_hash(_h, _s);
|
||||
feed_hash(_h, t);
|
||||
}
|
||||
|
||||
virtual void accept_row(clustering_key_view key, tombstone deleted_at, const row_marker& rm) {
|
||||
key.feed_hash(_h, _s);
|
||||
feed_hash(_h, deleted_at);
|
||||
feed_hash(_h, rm);
|
||||
}
|
||||
|
||||
virtual void accept_row_cell(column_id id, atomic_cell_view cell) {
|
||||
auto&& col = _s.regular_column_at(id);
|
||||
feed_hash(_h, col.name());
|
||||
feed_hash(_h, col.type->name());
|
||||
feed_hash(_h, cell);
|
||||
}
|
||||
|
||||
virtual void accept_row_cell(column_id id, collection_mutation_view cell) {
|
||||
auto&& col = _s.regular_column_at(id);
|
||||
feed_hash(_h, col.name());
|
||||
feed_hash(_h, col.type->name());
|
||||
feed_hash(cell, _h, col.type);
|
||||
}
|
||||
};
|
||||
57
keys.cc
57
keys.cc
@@ -52,60 +52,3 @@ partition_key_view::ring_order_tri_compare(const schema& s, partition_key_view k
|
||||
}
|
||||
return legacy_tri_compare(s, k2);
|
||||
}
|
||||
|
||||
template class db::serializer<partition_key_view>;
|
||||
template class db::serializer<clustering_key_prefix_view>;
|
||||
|
||||
template<>
|
||||
db::serializer<partition_key_view>::serializer(const partition_key_view& key)
|
||||
: _item(key), _size(sizeof(uint16_t) /* size */ + key.representation().size()) {
|
||||
}
|
||||
|
||||
template<>
|
||||
void db::serializer<partition_key_view>::write(output& out, const partition_key_view& key) {
|
||||
bytes_view v = key.representation();
|
||||
out.write<uint16_t>(v.size());
|
||||
out.write(v.begin(), v.end());
|
||||
}
|
||||
|
||||
template<>
|
||||
void db::serializer<partition_key_view>::read(partition_key_view& b, input& in) {
|
||||
auto len = in.read<uint16_t>();
|
||||
b = partition_key_view::from_bytes(in.read_view(len));
|
||||
}
|
||||
|
||||
template<>
|
||||
partition_key_view db::serializer<partition_key_view>::read(input& in) {
|
||||
auto len = in.read<uint16_t>();
|
||||
return partition_key_view::from_bytes(in.read_view(len));
|
||||
}
|
||||
|
||||
template<>
|
||||
void db::serializer<partition_key_view>::skip(input& in) {
|
||||
auto len = in.read<uint16_t>();
|
||||
in.skip(len);
|
||||
}
|
||||
|
||||
template<>
|
||||
db::serializer<clustering_key_prefix_view>::serializer(const clustering_key_prefix_view& key)
|
||||
: _item(key), _size(sizeof(uint16_t) /* size */ + key.representation().size()) {
|
||||
}
|
||||
|
||||
template<>
|
||||
void db::serializer<clustering_key_prefix_view>::write(output& out, const clustering_key_prefix_view& key) {
|
||||
bytes_view v = key.representation();
|
||||
out.write<uint16_t>(v.size());
|
||||
out.write(v.begin(), v.end());
|
||||
}
|
||||
|
||||
template<>
|
||||
void db::serializer<clustering_key_prefix_view>::read(clustering_key_prefix_view& b, input& in) {
|
||||
auto len = in.read<uint16_t>();
|
||||
b = clustering_key_prefix_view::from_bytes(in.read_view(len));
|
||||
}
|
||||
|
||||
template<>
|
||||
clustering_key_prefix_view db::serializer<clustering_key_prefix_view>::read(input& in) {
|
||||
auto len = in.read<uint16_t>();
|
||||
return clustering_key_prefix_view::from_bytes(in.read_view(len));
|
||||
}
|
||||
|
||||
43
keys.hh
43
keys.hh
@@ -26,7 +26,6 @@
|
||||
#include "types.hh"
|
||||
#include "compound_compat.hh"
|
||||
#include "utils/managed_bytes.hh"
|
||||
#include "hashing.hh"
|
||||
|
||||
//
|
||||
// This header defines type system for primary key holders.
|
||||
@@ -123,18 +122,6 @@ public:
|
||||
std::advance(it, idx);
|
||||
return *it;
|
||||
}
|
||||
|
||||
// Returns a range of bytes_view
|
||||
auto components(const schema& s) const {
|
||||
return boost::make_iterator_range(begin(s), end(s));
|
||||
}
|
||||
|
||||
template<typename Hasher>
|
||||
void feed_hash(Hasher& h, const schema& s) const {
|
||||
for (bytes_view v : components(s)) {
|
||||
::feed_hash(h, v);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename TopLevel, typename TopLevelView>
|
||||
@@ -265,11 +252,6 @@ public:
|
||||
std::advance(it, idx);
|
||||
return *it;
|
||||
}
|
||||
|
||||
template<typename Hasher>
|
||||
void feed_hash(Hasher& h, const schema& s) const {
|
||||
view().feed_hash(h, s);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename TopLevel, typename PrefixTopLevel>
|
||||
@@ -604,12 +586,6 @@ public:
|
||||
static clustering_key_prefix_view from_bytes(bytes_view v) {
|
||||
return { v };
|
||||
}
|
||||
|
||||
using compound = lw_shared_ptr<compound_type<allow_prefixes::yes>>;
|
||||
|
||||
static const compound& get_compound_type(const schema& s) {
|
||||
return s.clustering_key_prefix_type();
|
||||
}
|
||||
};
|
||||
|
||||
class clustering_key_prefix : public prefix_compound_wrapper<clustering_key_prefix, clustering_key_prefix_view, clustering_key> {
|
||||
@@ -637,22 +613,3 @@ public:
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& out, const clustering_key_prefix& ckp);
|
||||
};
|
||||
|
||||
namespace db {
|
||||
|
||||
template<> serializer<partition_key_view>::serializer(const partition_key_view &);
|
||||
template<> void serializer<partition_key_view>::write(output&, const partition_key_view&);
|
||||
template<> void serializer<partition_key_view>::read(partition_key_view&, input&);
|
||||
template<> partition_key_view serializer<partition_key_view>::read(input&);
|
||||
template<> void serializer<partition_key_view>::skip(input&);
|
||||
|
||||
template<> serializer<clustering_key_prefix_view>::serializer(const clustering_key_prefix_view &);
|
||||
template<> void serializer<clustering_key_prefix_view>::write(output&, const clustering_key_prefix_view&);
|
||||
template<> void serializer<clustering_key_prefix_view>::read(clustering_key_prefix_view&, input&);
|
||||
template<> clustering_key_prefix_view serializer<clustering_key_prefix_view>::read(input&);
|
||||
|
||||
typedef serializer<partition_key_view> partition_key_view_serializer;
|
||||
typedef serializer<clustering_key_view> clustering_key_view_serializer;
|
||||
typedef serializer<clustering_key_prefix_view> clustering_key_prefix_view_serializer;
|
||||
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
|
||||
namespace locator {
|
||||
future<bool> gossiping_property_file_snitch::property_file_was_modified() {
|
||||
return open_file_dma(_prop_file_name, open_flags::ro)
|
||||
return engine().open_file_dma(_prop_file_name, open_flags::ro)
|
||||
.then([this](file f) {
|
||||
return do_with(std::move(f), [] (file& f) {
|
||||
return f.stat();
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace locator {
|
||||
future<> production_snitch_base::load_property_file() {
|
||||
return open_file_dma(_prop_file_name, open_flags::ro)
|
||||
return engine().open_file_dma(_prop_file_name, open_flags::ro)
|
||||
.then([this] (file f) {
|
||||
return do_with(std::move(f), [this] (file& f) {
|
||||
return f.size().then([this, &f] (size_t s) {
|
||||
|
||||
@@ -79,7 +79,7 @@ private:
|
||||
net::get_messaging_service().invoke_on_all([public_address, local_address] (auto& local_ms) {
|
||||
local_ms.cache_preferred_ip(public_address, local_address);
|
||||
|
||||
net::msg_addr id = {
|
||||
net::shard_id id = {
|
||||
.addr = public_address
|
||||
};
|
||||
local_ms.remove_rpc_client(id);
|
||||
|
||||
@@ -149,10 +149,9 @@ public:
|
||||
virtual void set_local_private_addr(const sstring& addr_str) {};
|
||||
|
||||
static distributed<snitch_ptr>& snitch_instance() {
|
||||
// FIXME: leaked intentionally to avoid shutdown problems, see #293
|
||||
static distributed<snitch_ptr>* snitch_inst = new distributed<snitch_ptr>();
|
||||
static distributed<snitch_ptr> snitch_inst;
|
||||
|
||||
return *snitch_inst;
|
||||
return snitch_inst;
|
||||
}
|
||||
|
||||
static snitch_ptr& get_local_snitch_ptr() {
|
||||
|
||||
2
log.hh
2
log.hh
@@ -62,7 +62,7 @@ class registry;
|
||||
|
||||
class logger {
|
||||
sstring _name;
|
||||
std::atomic<log_level> _level = { log_level::info };
|
||||
std::atomic<log_level> _level = { log_level::warn };
|
||||
static std::atomic<bool> _stdout;
|
||||
static std::atomic<bool> _syslog;
|
||||
private:
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user