Compare commits

..

12 Commits

Author SHA1 Message Date
Pekka Enberg
d3a05737f7 release: prepare for 0.14.1 2016-01-05 15:30:47 +02:00
Shlomi Livne
21c68d3da9 dist/redhat: Increase scylla-server service start timeout to 15 min
Fixes #749

Signed-off-by: Shlomi Livne <shlomi@scylladb.com>
2016-01-05 15:30:41 +02:00
Pekka Enberg
88d544ed14 Merge "Fixes for AMI" from Shlomi
"The patch fixes a few issues caused by generalizing the ami scripts. The
 scylla_bootparam_setup requires invocation with ami flag. The
 scylla_install is missing some steps executed by the scylla-ami.sh."
2016-01-04 15:21:24 +02:00
Shlomi Livne
638c0c0ea8 Fixing missing items in move from scylla-ami.sh to scylla_install
scylla-ami.sh moved some ami specific files. This parts have been
dropped when converging scylla-ami into scylla_install. Fixing that.

Signed-off-by: Shlomi Livne <shlomi@scylladb.com>
2016-01-04 14:57:57 +02:00
Shlomi Livne
f3e96e0f0b Invoke scylla_bootparam_setup with/without ami flag
Signed-off-by: Shlomi Livne <shlomi@scylladb.com>
2016-01-04 14:57:57 +02:00
Shlomi Livne
fa15440665 Fix error: no integer expression expected in AMI creation
The script imports the /etc/sysconfig/scylla-server for configuration
settings (NR_PAGES). The /etc/sysconfig/scylla-server iincludes an AMI
param which is of string value and called as a last step in
scylla_install (after scylla_bootparam_setup has been initated).

The AMI variable is setup in scylla_install and is used in multiple
scripts. To resolve the conflict moving the import of
/etc/sysconfig/scylla-server after the AMI variable has been compared.

Fixes: #744

Signed-off-by: Shlomi Livne <shlomi@scylladb.com>
2016-01-04 14:57:33 +02:00
Takuya ASADA
c4d66a3beb dist: apply limits settings correctly on Ubuntu
Fixes #738

Signed-off-by: Takuya ASADA <syuu@scylladb.com>
2016-01-02 12:20:47 +02:00
Shlomi Livne
5023f9bbab Make sure the directory we are writting coredumps to exists
After upgrading an AMI and trying to stop and start a machine the
/var/lib/scylla/coredump is not created. Create the directory if it does
not exist prior to generating core

Signed-off-by: Shlomi Livne <shlomi@scylladb.com>
2015-12-31 13:21:54 +02:00
Pekka Enberg
3efc145562 dist: Increase NOFILE rlimit to 200k
Commit 2ba4910 ("main: verify that the NOFILE rlimit is sufficient")
added a recommendation to set NOFILE rlimit to 200k. Update our release
binaries to do the same.
2015-12-30 12:21:01 +02:00
Avi Kivity
1ad638f8bf main: verify that the NOFILE rlimit is sufficient
Require 10k files, recommend 200k.

Allow bypassing via --developer-mode.

Fixes #692.
2015-12-30 11:05:21 +02:00
Avi Kivity
43f4a8031d init: bail out if running not on an XFS filesystem
Allow an override via '--developer-mode true', and use it in
the docker setup, since that cannot be expected to use XFS.

Fixes #658.
2015-12-30 11:05:14 +02:00
Pekka Enberg
27dbbe1ca4 release: prepare for 0.14 2015-12-30 10:28:58 +02:00
191 changed files with 2064 additions and 8844 deletions

3
.gitignore vendored
View File

@@ -5,6 +5,3 @@ build
build.ninja
cscope.*
/debian/
dist/ami/files/*.rpm
dist/ami/variables.json
dist/ami/scylla_deploy.sh

View File

@@ -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
```

View File

@@ -1,6 +1,6 @@
#!/bin/sh
VERSION=0.16
VERSION=0.14.1
if test -f version
then

View File

@@ -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"
]
}
}

View File

@@ -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":{

View File

@@ -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);
}

View File

@@ -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) {

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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());
}
}
};

View File

@@ -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&);
};

View File

@@ -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());
});
});
});
}

View File

@@ -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);
};
}

View File

@@ -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;
}

View File

@@ -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;
};
}

View File

@@ -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;
}

View File

@@ -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;
};
}

View File

@@ -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();
}

View File

@@ -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&);
}

View File

@@ -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);
}

View File

@@ -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);
};
}

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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));
}
};

View File

@@ -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);
}
}
};

View File

@@ -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));
}

View File

@@ -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>;
}

View File

@@ -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

View File

@@ -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

View File

@@ -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);
}
}
};

View File

@@ -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
( '(' ')'

View File

@@ -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;

View File

@@ -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;

View File

@@ -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);
});
}
}

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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());
}
}
}

View File

@@ -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;
};
}
}

View File

@@ -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, "");
}
}
}
}

View File

@@ -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));

View File

@@ -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, ""));

View File

@@ -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;
};

View File

@@ -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);

View File

@@ -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

View File

@@ -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) {

View File

@@ -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);
}

View File

@@ -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()) {

View File

@@ -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;

View File

@@ -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] {

View File

@@ -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));

View File

@@ -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) {

View File

@@ -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));
}
}

View File

@@ -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;
};
}

View File

@@ -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;

View File

@@ -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

View File

@@ -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> ;

View File

@@ -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;
}

View File

@@ -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));
});

View File

@@ -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

View File

@@ -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
View File

@@ -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

View File

@@ -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

View File

@@ -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

30
dist/ami/scylla.json vendored
View File

@@ -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
View 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": ""
}
}

View File

@@ -1,2 +0,0 @@
#!/bin/sh
sed -i 's/Defaults requiretty/#Defaults requiretty/g' /etc/sudoers

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -1 +0,0 @@
scylla ALL=(ALL) NOPASSWD:SETENV: /usr/lib/scylla/scylla_prepare,/usr/lib/scylla/scylla_stop

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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)

View File

@@ -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)

View File

@@ -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));
}

View File

@@ -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&);
}

View File

@@ -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));
}

View File

@@ -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>;
}

View File

@@ -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

View File

@@ -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;

View File

@@ -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());
}
};

View File

@@ -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
View File

@@ -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
View File

@@ -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;
}

View File

@@ -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();

View File

@@ -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) {

View File

@@ -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);

View File

@@ -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
View File

@@ -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