schema_tables: Use v3 schema tables and formats
Switches system/schema_* for system_schema/*, updates schema/schema builder and uses to hold/expect v3 style info (i.e. types & dropped).
This commit is contained in:
@@ -39,6 +39,8 @@
|
||||
* along with Scylla. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <boost/range/adaptor/transformed.hpp>
|
||||
|
||||
#include "cql3/selection/selection.hh"
|
||||
#include "cql3/selection/selector_factories.hh"
|
||||
#include "cql3/result_set.hh"
|
||||
@@ -203,14 +205,10 @@ protected:
|
||||
};
|
||||
|
||||
::shared_ptr<selection> selection::wildcard(schema_ptr schema) {
|
||||
std::vector<const column_definition*> cds;
|
||||
auto& columns = schema->all_columns_in_select_order();
|
||||
cds.reserve(columns.size());
|
||||
for (auto& c : columns) {
|
||||
if (!schema->is_dense() || !c.is_regular() || !c.name().empty()) {
|
||||
cds.emplace_back(&c);
|
||||
}
|
||||
}
|
||||
auto columns = schema->all_columns_in_select_order();
|
||||
auto cds = boost::copy_range<std::vector<const column_definition*>>(columns | boost::adaptors::transformed([](const column_definition& c) {
|
||||
return &c;
|
||||
}));
|
||||
return simple_selection::make(schema, std::move(cds), true);
|
||||
}
|
||||
|
||||
|
||||
@@ -229,8 +229,13 @@ future<shared_ptr<transport::event::schema_change>> alter_table_statement::annou
|
||||
throw exceptions::invalid_request_exception("Cannot use non-frozen collections with super column families");
|
||||
}
|
||||
|
||||
auto it = schema->collections().find(column_name->name());
|
||||
if (it != schema->collections().end() && !type->is_compatible_with(*it->second)) {
|
||||
|
||||
// If there used to be a non-frozen collection column with the same name (that has been dropped),
|
||||
// we could still have some data using the old type, and so we can't allow adding a collection
|
||||
// with the same name unless the types are compatible (see #6276).
|
||||
auto& dropped = schema->dropped_columns();
|
||||
auto i = dropped.find(column_name->text());
|
||||
if (i != dropped.end() && !type->is_compatible_with(*i->second.type)) {
|
||||
throw exceptions::invalid_request_exception(sprint("Cannot add a collection with the name %s "
|
||||
"because a collection with the same name and a different type has already been used in the past", column_name));
|
||||
}
|
||||
|
||||
@@ -79,6 +79,57 @@ void drop_type_statement::validate(distributed<service::storage_proxy>& proxy, c
|
||||
throw exceptions::invalid_request_exception(sprint("No user type named %s exists.", _name.to_string()));
|
||||
}
|
||||
}
|
||||
|
||||
// We don't want to drop a type unless it's not used anymore (mainly because
|
||||
// if someone drops a type and recreates one with the same name but different
|
||||
// definition with the previous name still in use, things can get messy).
|
||||
// We have two places to check: 1) other user type that can nest the one
|
||||
// we drop and 2) existing tables referencing the type (maybe in a nested
|
||||
// way).
|
||||
|
||||
// This code is moved from schema_keyspace (akin to origin) because we cannot
|
||||
// delay this check to until after we've applied the mutations. If a type or
|
||||
// table references the type we're dropping, we will a.) get exceptions parsing
|
||||
// (can be translated to invalid_request, but...) and more importantly b.)
|
||||
// we will leave those types/tables in a broken state.
|
||||
// We managed to get through this before because we neither enforced hard
|
||||
// cross reference between types when loading them, nor did we in fact
|
||||
// probably ever run the scenario of dropping a referenced type and then
|
||||
// actually using the referee.
|
||||
//
|
||||
// Now, this has a giant flaw. We are succeptible to race conditions here,
|
||||
// since we could have a drop at the same time as a create type that references
|
||||
// the dropped one, but we complete the check before the create is done,
|
||||
// yet apply the drop mutations after -> inconsistent data!
|
||||
// This problem is the same in origin, and I see no good way around it
|
||||
// as long as the atomicity of schema modifications are based on
|
||||
// actual appy of mutations, because unlike other drops, this one isn't
|
||||
// benevolent.
|
||||
// I guess this is one case where user need beware, and don't mess with types
|
||||
// concurrently!
|
||||
|
||||
auto&& type = old->second;
|
||||
auto&& keyspace = type->_keyspace;
|
||||
auto&& name = type->_name;
|
||||
|
||||
for (auto&& ut : all_types | boost::adaptors::map_values) {
|
||||
if (ut->_keyspace == keyspace && ut->_name == name) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ut->references_user_type(keyspace, name)) {
|
||||
throw exceptions::invalid_request_exception(sprint("Cannot drop user type %s.%s as it is still used by user type %s", keyspace, type->get_name_as_string(), ut->get_name_as_string()));
|
||||
}
|
||||
}
|
||||
|
||||
for (auto&& cfm : ks.metadata()->cf_meta_data() | boost::adaptors::map_values) {
|
||||
for (auto&& col : cfm->all_columns()) {
|
||||
if (col.type->references_user_type(keyspace, name)) {
|
||||
throw exceptions::invalid_request_exception(sprint("Cannot drop user type %s.%s as it is still used by table %s.%s", keyspace, type->get_name_as_string(), cfm->ks_name(), cfm->cf_name()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} catch (no_such_keyspace& e) {
|
||||
throw exceptions::invalid_request_exception(sprint("Cannot drop type in unknown keyspace %s", keyspace()));
|
||||
}
|
||||
|
||||
@@ -70,7 +70,9 @@ void update_statement::add_update_for_key(mutation& m, const query::clustering_r
|
||||
}
|
||||
// An empty name for the value is what we use to recognize the case where there is not column
|
||||
// outside the PK, see CreateStatement.
|
||||
if (s->regular_begin()->name().empty()) {
|
||||
// Since v3 schema we use empty_type instead, see schema.cc.
|
||||
auto rb = s->regular_begin();
|
||||
if (rb->name().empty() || rb->type == empty_type) {
|
||||
// There is no column outside the PK. So no operation could have passed through validation
|
||||
assert(_column_operations.empty());
|
||||
constants::setter(*s->regular_begin(), make_shared(constants::value(cql3::raw_value::make_value(bytes())))).execute(m, prefix, params);
|
||||
|
||||
@@ -2189,7 +2189,7 @@ future<> database::parse_system_tables(distributed<service::storage_proxy>& prox
|
||||
auto ksm = create_keyspace_from_schema_partition(v);
|
||||
return create_keyspace(ksm);
|
||||
}).then([&proxy, this] {
|
||||
return do_parse_schema_tables(proxy, db::schema_tables::USERTYPES, [this, &proxy] (schema_result_value_type &v) {
|
||||
return do_parse_schema_tables(proxy, db::schema_tables::TYPES, [this, &proxy] (schema_result_value_type &v) {
|
||||
auto&& user_types = create_types_from_schema_partition(v);
|
||||
auto& ks = this->find_keyspace(v.first);
|
||||
for (auto&& type : user_types) {
|
||||
@@ -2206,7 +2206,7 @@ future<> database::parse_system_tables(distributed<service::storage_proxy>& prox
|
||||
});
|
||||
});
|
||||
}).then([&proxy, this] {
|
||||
return do_parse_schema_tables(proxy, db::schema_tables::COLUMNFAMILIES, [this, &proxy] (schema_result_value_type &v) {
|
||||
return do_parse_schema_tables(proxy, db::schema_tables::TABLES, [this, &proxy] (schema_result_value_type &v) {
|
||||
return create_tables_from_tables_partition(proxy, v.second).then([this] (std::map<sstring, schema_ptr> tables) {
|
||||
return parallel_for_each(tables.begin(), tables.end(), [this] (auto& t) {
|
||||
return this->add_column_family_and_make_directory(t.second);
|
||||
|
||||
1262
db/schema_tables.cc
1262
db/schema_tables.cc
File diff suppressed because it is too large
Load Diff
@@ -59,18 +59,6 @@ namespace schema_tables {
|
||||
using schema_result = std::map<sstring, lw_shared_ptr<query::result_set>>;
|
||||
using schema_result_value_type = std::pair<sstring, lw_shared_ptr<query::result_set>>;
|
||||
|
||||
extern const sstring NAME;
|
||||
|
||||
static constexpr auto KEYSPACES = "schema_keyspaces";
|
||||
static constexpr auto COLUMNFAMILIES = "schema_columnfamilies";
|
||||
static constexpr auto COLUMNS = "schema_columns";
|
||||
static constexpr auto TRIGGERS = "schema_triggers";
|
||||
static constexpr auto USERTYPES = "schema_usertypes";
|
||||
static constexpr auto FUNCTIONS = "schema_functions";
|
||||
static constexpr auto AGGREGATES = "schema_aggregates";
|
||||
static constexpr auto VIEWS = "views";
|
||||
static constexpr auto INDEXES = "indexes";
|
||||
|
||||
namespace v3 {
|
||||
|
||||
static constexpr auto NAME = "system_schema";
|
||||
@@ -85,8 +73,16 @@ static constexpr auto FUNCTIONS = "functions";
|
||||
static constexpr auto AGGREGATES = "aggregates";
|
||||
static constexpr auto INDEXES = "indexes";
|
||||
|
||||
schema_ptr columns();
|
||||
schema_ptr dropped_columns();
|
||||
schema_ptr indexes();
|
||||
schema_ptr tables();
|
||||
schema_ptr views();
|
||||
|
||||
}
|
||||
|
||||
using namespace v3;
|
||||
|
||||
extern std::vector<const char*> ALL;
|
||||
|
||||
std::vector<schema_ptr> all_tables();
|
||||
@@ -105,8 +101,6 @@ 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);
|
||||
|
||||
future<> do_merge_schema(distributed<service::storage_proxy>& proxy, std::vector<mutation> mutations, bool do_flush);
|
||||
|
||||
future<std::set<sstring>> merge_keyspaces(distributed<service::storage_proxy>& proxy, schema_result&& before, schema_result&& after);
|
||||
|
||||
std::vector<mutation> make_create_keyspace_mutations(lw_shared_ptr<keyspace_metadata> keyspace, api::timestamp_type timestamp, bool with_tables_and_types_and_functions = true);
|
||||
@@ -136,42 +130,9 @@ future<std::map<sstring, schema_ptr>> create_tables_from_tables_partition(distri
|
||||
|
||||
future<std::vector<mutation>> make_drop_table_mutations(lw_shared_ptr<keyspace_metadata> keyspace, schema_ptr table, api::timestamp_type timestamp);
|
||||
|
||||
future<schema_ptr> create_table_from_name(distributed<service::storage_proxy>& proxy, const sstring& keyspace, const sstring& table);
|
||||
|
||||
future<schema_ptr> create_table_from_table_row(distributed<service::storage_proxy>& proxy, const query::result_set_row& row);
|
||||
|
||||
void prepare_builder_from_table_row(schema_builder& builder, const query::result_set_row& table_row);
|
||||
|
||||
schema_ptr create_table_from_mutations(schema_mutations, std::experimental::optional<table_schema_version> version = {});
|
||||
|
||||
void drop_column_from_schema_mutation(schema_ptr table, const column_definition& column, long timestamp, std::vector<mutation>& mutations);
|
||||
void drop_index_from_schema_mutation(schema_ptr table, const index_metadata& column, long timestamp, std::vector<mutation>& mutations);
|
||||
|
||||
std::vector<column_definition> create_columns_from_column_rows(const query::result_set& rows,
|
||||
const sstring& keyspace,
|
||||
const sstring& table,/*,
|
||||
AbstractType<?> rawComparator, */
|
||||
bool is_super);
|
||||
|
||||
column_definition create_column_from_column_row(const query::result_set_row& row,
|
||||
sstring keyspace,
|
||||
sstring table, /*,
|
||||
AbstractType<?> rawComparator, */
|
||||
bool is_super);
|
||||
|
||||
std::vector<index_metadata> create_indices_from_index_rows(const query::result_set& rows,
|
||||
const sstring& keyspace,
|
||||
const sstring& table);
|
||||
|
||||
index_metadata create_index_from_index_row(const query::result_set_row& row,
|
||||
sstring keyspace,
|
||||
sstring table);
|
||||
|
||||
void add_column_to_schema_mutation(schema_ptr table, const column_definition& column, api::timestamp_type timestamp, mutation& mutation);
|
||||
|
||||
void add_index_to_schema_mutation(schema_ptr table, const index_metadata& index, api::timestamp_type timestamp, mutation& mutation);
|
||||
|
||||
view_ptr create_view_from_mutations(schema_mutations sm, std::experimental::optional<table_schema_version> version = {});
|
||||
view_ptr create_view_from_mutations(schema_mutations, std::experimental::optional<table_schema_version> version = {});
|
||||
|
||||
future<std::vector<view_ptr>> create_views_from_schema_partition(distributed<service::storage_proxy>& proxy, const schema_result::mapped_type& result);
|
||||
|
||||
@@ -192,11 +153,6 @@ data_type parse_type(sstring str);
|
||||
sstring serialize_index_kind(index_metadata_kind kind);
|
||||
index_metadata_kind deserialize_index_kind(sstring kind);
|
||||
|
||||
schema_ptr columns();
|
||||
schema_ptr columnfamilies();
|
||||
schema_ptr views();
|
||||
schema_ptr indexes();
|
||||
|
||||
template<typename Hasher>
|
||||
void feed_hash_for_schema_digest(Hasher& h, const mutation& m) {
|
||||
// Cassandra is skipping tombstones from digest calculation
|
||||
|
||||
@@ -1525,20 +1525,21 @@ set_index_removed(const sstring& ks_name, const sstring& index_name) {
|
||||
|
||||
std::vector<schema_ptr> all_tables() {
|
||||
std::vector<schema_ptr> r;
|
||||
auto legacy_tables = db::schema_tables::all_tables();
|
||||
std::copy(legacy_tables.begin(), legacy_tables.end(), std::back_inserter(r));
|
||||
r.push_back(built_indexes());
|
||||
r.push_back(hints());
|
||||
r.push_back(batchlog());
|
||||
r.push_back(paxos());
|
||||
r.push_back(local());
|
||||
r.push_back(peers());
|
||||
r.push_back(peer_events());
|
||||
r.push_back(range_xfers());
|
||||
r.push_back(compactions_in_progress());
|
||||
r.push_back(compaction_history());
|
||||
r.push_back(sstable_activity());
|
||||
r.push_back(size_estimates());
|
||||
auto schema_tables = db::schema_tables::all_tables();
|
||||
std::copy(schema_tables.begin(), schema_tables.end(), std::back_inserter(r));
|
||||
r.insert(r.end(), { built_indexes(), hints(), batchlog(), paxos(), local(),
|
||||
peers(), peer_events(), range_xfers(),
|
||||
compactions_in_progress(), compaction_history(),
|
||||
sstable_activity(), size_estimates(),
|
||||
});
|
||||
// legacy schema
|
||||
r.insert(r.end(), {
|
||||
// TODO: once we migrate hints/batchlog and add convertor
|
||||
// legacy::hints(), legacy::batchlog(),
|
||||
legacy::keyspaces(), legacy::column_families(),
|
||||
legacy::columns(), legacy::triggers(), legacy::usertypes(),
|
||||
legacy::functions(), legacy::aggregates(), });
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ class schema_mutations {
|
||||
canonical_mutation columns_canonical_mutation();
|
||||
bool is_view()[[version 1.6]];
|
||||
std::experimental::optional<canonical_mutation> indices_canonical_mutation()[[version 1.9]];
|
||||
std::experimental::optional<canonical_mutation> dropped_columns_canonical_mutation()[[version 1.9]];
|
||||
};
|
||||
|
||||
class schema stub [[writable]] {
|
||||
|
||||
144
schema.cc
144
schema.cc
@@ -141,7 +141,7 @@ void schema::rebuild() {
|
||||
thrift()._compound = is_compound();
|
||||
thrift()._is_dynamic = clustering_key_size() > 0;
|
||||
|
||||
if (default_validator()->is_counter()) {
|
||||
if (is_counter()) {
|
||||
for (auto&& cdef : boost::range::join(static_columns(), regular_columns())) {
|
||||
if (!cdef.type->is_counter()) {
|
||||
throw exceptions::configuration_exception(sprint("Cannot add a non counter column (%s) in a counter column family", cdef.name_as_text()));
|
||||
@@ -190,7 +190,6 @@ schema::schema(const raw_schema& raw, stdx::optional<raw_view_info> raw_view_inf
|
||||
};
|
||||
}())
|
||||
, _regular_columns_by_name(serialized_compare(_raw._regular_column_name_type))
|
||||
, _is_counter(_raw._default_validator->is_counter())
|
||||
{
|
||||
struct name_compare {
|
||||
data_type type;
|
||||
@@ -226,7 +225,7 @@ schema::schema(const raw_schema& raw, stdx::optional<raw_view_info> raw_view_inf
|
||||
|
||||
auto dropped_at_it = _raw._dropped_columns.find(def.name_as_text());
|
||||
if (dropped_at_it != _raw._dropped_columns.end()) {
|
||||
def._dropped_at = std::max(def._dropped_at, dropped_at_it->second);
|
||||
def._dropped_at = std::max(def._dropped_at, dropped_at_it->second.timestamp);
|
||||
}
|
||||
|
||||
def._thrift_bits = column_definition::thrift_bits();
|
||||
@@ -302,7 +301,6 @@ schema::schema(const schema& o)
|
||||
: _raw(o._raw)
|
||||
, _offsets(o._offsets)
|
||||
, _regular_columns_by_name(serialized_compare(_raw._regular_column_name_type))
|
||||
, _is_counter(o._is_counter)
|
||||
{
|
||||
rebuild();
|
||||
if (o.is_view()) {
|
||||
@@ -368,7 +366,9 @@ bool operator==(const schema& x, const schema& y)
|
||||
&& x._raw._dropped_columns == y._raw._dropped_columns
|
||||
&& x._raw._collections == y._raw._collections
|
||||
&& indirect_equal_to<std::unique_ptr<::view_info>>()(x._view_info, y._view_info)
|
||||
&& x._raw._indices_by_name == y._raw._indices_by_name;
|
||||
&& x._raw._indices_by_name == y._raw._indices_by_name
|
||||
&& x._raw._is_counter == y._raw._is_counter
|
||||
;
|
||||
#if 0
|
||||
&& Objects.equal(triggers, other.triggers)
|
||||
#endif
|
||||
@@ -464,7 +464,6 @@ std::ostream& operator<<(std::ostream& os, const schema& s) {
|
||||
os << ",readRepairChance=" << s._raw._read_repair_chance;
|
||||
os << ",dcLocalReadRepairChance=" << s._raw._dc_local_read_repair_chance;
|
||||
os << ",gcGraceSeconds=" << s._raw._gc_grace_seconds;
|
||||
os << ",defaultValidator=" << s._raw._default_validator->name();
|
||||
os << ",keyValidator=" << s.thrift_key_validator();
|
||||
os << ",minCompactionThreshold=" << s._raw._min_compaction_threshold;
|
||||
os << ",maxCompactionThreshold=" << s._raw._max_compaction_threshold;
|
||||
@@ -513,7 +512,7 @@ std::ostream& operator<<(std::ostream& os, const schema& s) {
|
||||
if (n++ != 0) {
|
||||
os << ", ";
|
||||
}
|
||||
os << dc.first << " : " << dc.second;
|
||||
os << dc.first << " : { " << dc.second.type->name() << ", " << dc.second.timestamp << " }";
|
||||
}
|
||||
os << "}";
|
||||
os << ",collections={";
|
||||
@@ -648,8 +647,8 @@ schema_builder& schema_builder::with_column(bytes name, data_type type, column_k
|
||||
if (type->is_multi_cell()) {
|
||||
with_collection(name, type);
|
||||
} else if (type->is_counter()) {
|
||||
set_default_validator(counter_type);
|
||||
}
|
||||
set_is_counter(true);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -660,19 +659,23 @@ schema_builder& schema_builder::without_column(bytes name)
|
||||
});
|
||||
assert(it != _raw._columns.end());
|
||||
auto now = api::new_timestamp();
|
||||
auto ret = _raw._dropped_columns.emplace(it->name_as_text(), now);
|
||||
auto ret = _raw._dropped_columns.emplace(it->name_as_text(), schema::dropped_column{it->type, now});
|
||||
if (!ret.second) {
|
||||
ret.first->second = std::max(ret.first->second, now);
|
||||
ret.first->second.timestamp = std::max(ret.first->second.timestamp, now);
|
||||
}
|
||||
_raw._columns.erase(it);
|
||||
return *this;
|
||||
}
|
||||
|
||||
schema_builder& schema_builder::without_column(sstring name, api::timestamp_type timestamp)
|
||||
schema_builder& schema_builder::without_column(sstring name, api::timestamp_type timestamp) {
|
||||
return without_column(std::move(name), bytes_type, timestamp);
|
||||
}
|
||||
|
||||
schema_builder& schema_builder::without_column(sstring name, data_type type, api::timestamp_type timestamp)
|
||||
{
|
||||
auto ret = _raw._dropped_columns.emplace(name, timestamp);
|
||||
auto ret = _raw._dropped_columns.emplace(name, schema::dropped_column{type, timestamp});
|
||||
if (!ret.second) {
|
||||
ret.first->second = std::max(ret.first->second, timestamp);
|
||||
ret.first->second.timestamp = std::max(ret.first->second.timestamp, timestamp);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
@@ -762,15 +765,64 @@ sstring schema_builder::default_names::compact_value_name() {
|
||||
}
|
||||
|
||||
void schema_builder::prepare_dense_schema(schema::raw_schema& raw) {
|
||||
if (raw._is_dense) {
|
||||
auto regular_cols = std::count_if(raw._columns.begin(), raw._columns.end(), [](auto&& col) {
|
||||
return col.kind == column_kind::regular_column;
|
||||
});
|
||||
// In Origin, dense CFs always have at least one regular column
|
||||
if (regular_cols == 0) {
|
||||
raw._columns.emplace_back(bytes(""), raw._regular_column_name_type, column_kind::regular_column, 0);
|
||||
} else if (regular_cols > 1) {
|
||||
throw exceptions::configuration_exception(sprint("Expecting exactly one regular column. Found %d", regular_cols));
|
||||
auto is_dense = raw._is_dense;
|
||||
auto is_compound = raw._is_compound;
|
||||
auto is_static_compact = !is_dense && !is_compound;
|
||||
auto is_compact_table = is_dense || !is_compound;
|
||||
|
||||
|
||||
if (is_compact_table) {
|
||||
auto count_kind = [&raw](column_kind kind) {
|
||||
return std::count_if(raw._columns.begin(), raw._columns.end(), [kind](const column_definition& c) {
|
||||
return c.kind == kind;
|
||||
});
|
||||
};
|
||||
|
||||
default_names names(raw);
|
||||
|
||||
if (is_static_compact) {
|
||||
/**
|
||||
* In origin v3 the general cql-ification of the "storage engine" means
|
||||
* that "static compact" tables are expressed as all defined columns static,
|
||||
* but with synthetic clustering + regular columns.
|
||||
* We unfortunately need to play along with this, both because we want
|
||||
* schema tables on disk to be compatible (and they are explicit).
|
||||
* More to the point, we are, at least until we upgrade to version "m"
|
||||
* sstables, stuck with having origins java tools reading our schema tables
|
||||
* for table schemas (this btw applies to db drivers too, though maybe a little
|
||||
* less), and it asserts badly if we don't uphold the origin table tweaks.
|
||||
*
|
||||
* So transform away...
|
||||
*
|
||||
*/
|
||||
if (!count_kind(column_kind::static_column)) {
|
||||
assert(!count_kind(column_kind::clustering_key));
|
||||
for (auto& c : raw._columns) {
|
||||
// Note that for "static" no-clustering compact storage we use static for the defined columns
|
||||
if (c.kind == column_kind::regular_column) {
|
||||
c.kind = column_kind::static_column;
|
||||
}
|
||||
}
|
||||
// Compact tables always have a clustering and a single regular value.
|
||||
raw._columns.emplace_back(to_bytes(names.clustering_name()),
|
||||
utf8_type, column_kind::clustering_key, 0);
|
||||
raw._columns.emplace_back(to_bytes(names.compact_value_name()),
|
||||
raw._is_counter ? counter_type : bytes_type,
|
||||
column_kind::regular_column, 0);
|
||||
}
|
||||
} else if (is_dense) {
|
||||
auto regular_cols = count_kind(column_kind::regular_column);
|
||||
// In Origin, dense CFs always have at least one regular column
|
||||
if (regular_cols == 0) {
|
||||
raw._columns.emplace_back(to_bytes(names.compact_value_name()),
|
||||
empty_type,
|
||||
column_kind::regular_column, 0);
|
||||
} else if (regular_cols > 1) {
|
||||
throw exceptions::configuration_exception(
|
||||
sprint(
|
||||
"Expecting exactly one regular column. Found %d",
|
||||
regular_cols));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -872,7 +924,7 @@ sstring to_sstring(const schema& s) {
|
||||
if (s.is_compound()) {
|
||||
return compound_name(s);
|
||||
} else if (s.clustering_key_size() == 1) {
|
||||
assert(s.is_dense());
|
||||
assert(s.is_dense() || s.is_static_compact_table());
|
||||
return s.clustering_key_columns().front().type->name();
|
||||
} else {
|
||||
return s.regular_column_name_type()->name();
|
||||
@@ -1069,9 +1121,27 @@ schema::regular_columns() const {
|
||||
, _raw._columns.end());
|
||||
}
|
||||
|
||||
const schema::columns_type&
|
||||
schema::all_columns_in_select_order() const {
|
||||
return _raw._columns;
|
||||
schema::select_order_range schema::all_columns_in_select_order() const {
|
||||
auto is_static_compact_table = this->is_static_compact_table();
|
||||
auto no_non_pk_columns = is_compact_table()
|
||||
// Origin: && CompactTables.hasEmptyCompactValue(this);
|
||||
&& regular_columns_count() == 1
|
||||
&& [](const column_definition& c) {
|
||||
// We use empty_type now to match origin, but earlier incarnations
|
||||
// set name empty instead. check either.
|
||||
return c.type == empty_type || c.name().empty();
|
||||
}(regular_column_at(0));
|
||||
auto pk_range = const_iterator_range_type(_raw._columns.begin(),
|
||||
_raw._columns.begin() + (is_static_compact_table ?
|
||||
column_offset(column_kind::clustering_key) :
|
||||
column_offset(column_kind::static_column)));
|
||||
auto ck_v_range =
|
||||
(is_static_compact_table || no_non_pk_columns) ?
|
||||
static_columns() :
|
||||
const_iterator_range_type(
|
||||
static_columns().begin(),
|
||||
all_columns().end());
|
||||
return boost::range::join(pk_range, ck_v_range);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
@@ -1108,6 +1178,26 @@ std::vector<sstring> schema::index_names() const {
|
||||
return boost::copy_range<std::vector<sstring>>(_raw._indices_by_name | boost::adaptors::map_keys);
|
||||
}
|
||||
|
||||
data_type schema::make_legacy_default_validator() const {
|
||||
if (is_counter()) {
|
||||
return counter_type;
|
||||
}
|
||||
if (is_compact_table()) {
|
||||
// See CFMetaData.
|
||||
if (is_super()) {
|
||||
for (auto& c : regular_columns()) {
|
||||
if (c.name().empty()) {
|
||||
return c.type;
|
||||
}
|
||||
}
|
||||
assert("Invalid super column table definition, no 'dynamic' map column");
|
||||
} else {
|
||||
return regular_columns().begin()->type;
|
||||
}
|
||||
}
|
||||
return bytes_type;
|
||||
}
|
||||
|
||||
bool schema::is_synced() const {
|
||||
return _registry_entry && _registry_entry->is_synced();
|
||||
}
|
||||
|
||||
31
schema.hh
31
schema.hh
@@ -387,6 +387,14 @@ class view_info;
|
||||
* Use global_schema_ptr for safe across-shard access.
|
||||
*/
|
||||
class schema final : public enable_lw_shared_from_this<schema> {
|
||||
public:
|
||||
struct dropped_column {
|
||||
data_type type;
|
||||
api::timestamp_type timestamp;
|
||||
bool operator==(const dropped_column& rhs) const {
|
||||
return type == rhs.type && timestamp == rhs.timestamp;
|
||||
}
|
||||
};
|
||||
private:
|
||||
// More complex fields are derived from these inside rebuild().
|
||||
// Contains only fields which can be safely default-copied.
|
||||
@@ -400,16 +408,17 @@ private:
|
||||
std::vector<column_definition> _columns;
|
||||
sstring _comment;
|
||||
gc_clock::duration _default_time_to_live = gc_clock::duration::zero();
|
||||
data_type _default_validator = bytes_type;
|
||||
data_type _regular_column_name_type;
|
||||
double _bloom_filter_fp_chance = 0.01;
|
||||
compression_parameters _compressor_params;
|
||||
bool _is_dense = false;
|
||||
bool _is_compound = true;
|
||||
bool _is_counter = false;
|
||||
cf_type _type = cf_type::standard;
|
||||
int32_t _gc_grace_seconds = DEFAULT_GC_GRACE_SECONDS;
|
||||
double _dc_local_read_repair_chance = 0.1;
|
||||
double _read_repair_chance = 0.0;
|
||||
double _crc_check_chance = 1;
|
||||
int32_t _min_compaction_threshold = DEFAULT_MIN_COMPACTION_THRESHOLD;
|
||||
int32_t _max_compaction_threshold = DEFAULT_MAX_COMPACTION_THRESHOLD;
|
||||
int32_t _min_index_interval = DEFAULT_MIN_INDEX_INTERVAL;
|
||||
@@ -422,7 +431,7 @@ private:
|
||||
std::map<sstring, sstring> _compaction_strategy_options;
|
||||
caching_options _caching_options;
|
||||
table_schema_version _version;
|
||||
std::unordered_map<sstring, api::timestamp_type> _dropped_columns;
|
||||
std::unordered_map<sstring, dropped_column> _dropped_columns;
|
||||
std::map<bytes, data_type> _collections;
|
||||
std::unordered_map<sstring, index_metadata> _indices_by_name;
|
||||
};
|
||||
@@ -442,7 +451,6 @@ private:
|
||||
lw_shared_ptr<compound_type<allow_prefixes::no>> _partition_key_type;
|
||||
lw_shared_ptr<compound_type<allow_prefixes::yes>> _clustering_key_type;
|
||||
column_mapping _column_mapping;
|
||||
bool _is_counter = false;
|
||||
friend class schema_builder;
|
||||
public:
|
||||
using row_column_ids_are_ordered_by_name = std::true_type;
|
||||
@@ -518,7 +526,7 @@ public:
|
||||
return _raw._comment;
|
||||
}
|
||||
bool is_counter() const {
|
||||
return _is_counter;
|
||||
return _raw._is_counter;
|
||||
}
|
||||
|
||||
const cf_type type() const {
|
||||
@@ -541,6 +549,9 @@ public:
|
||||
double read_repair_chance() const {
|
||||
return _raw._read_repair_chance;
|
||||
}
|
||||
double crc_check_chance() const {
|
||||
return _raw._crc_check_chance;
|
||||
}
|
||||
|
||||
int32_t min_compaction_threshold() const {
|
||||
return _raw._min_compaction_threshold;
|
||||
@@ -607,7 +618,11 @@ public:
|
||||
// Returns a range of column definitions
|
||||
const_iterator_range_type regular_columns() const;
|
||||
// Returns a range of column definitions
|
||||
const columns_type& all_columns_in_select_order() const;
|
||||
|
||||
typedef boost::range::joined_range<const_iterator_range_type, const_iterator_range_type>
|
||||
select_order_range;
|
||||
|
||||
select_order_range all_columns_in_select_order() const;
|
||||
uint32_t position(const column_definition& column) const;
|
||||
|
||||
const columns_type& all_columns() const {
|
||||
@@ -629,9 +644,9 @@ public:
|
||||
gc_clock::duration default_time_to_live() const {
|
||||
return _raw._default_time_to_live;
|
||||
}
|
||||
const data_type& default_validator() const {
|
||||
return _raw._default_validator;
|
||||
}
|
||||
|
||||
data_type make_legacy_default_validator() const;
|
||||
|
||||
const sstring& ks_name() const {
|
||||
return _raw._ks_name;
|
||||
}
|
||||
|
||||
@@ -74,17 +74,12 @@ public:
|
||||
return _raw._default_time_to_live;
|
||||
}
|
||||
|
||||
schema_builder& set_default_validator(const data_type& validator) {
|
||||
_raw._default_validator = validator;
|
||||
return *this;
|
||||
}
|
||||
|
||||
schema_builder& set_gc_grace_seconds(int32_t gc_grace_seconds) {
|
||||
_raw._gc_grace_seconds = gc_grace_seconds;
|
||||
return *this;
|
||||
}
|
||||
|
||||
int32_t get_gc_grace_seconds() {
|
||||
int32_t get_gc_grace_seconds() const {
|
||||
return _raw._gc_grace_seconds;
|
||||
}
|
||||
|
||||
@@ -93,7 +88,7 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
double get_dc_local_read_repair_chance() {
|
||||
double get_dc_local_read_repair_chance() const {
|
||||
return _raw._dc_local_read_repair_chance;
|
||||
}
|
||||
|
||||
@@ -102,16 +97,25 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
double get_read_repair_chance() {
|
||||
double get_read_repair_chance() const {
|
||||
return _raw._read_repair_chance;
|
||||
}
|
||||
|
||||
schema_builder& set_crc_check_chance(double chance) {
|
||||
_raw._crc_check_chance = chance;
|
||||
return *this;
|
||||
}
|
||||
|
||||
double get_crc_check_chance() const {
|
||||
return _raw._crc_check_chance;
|
||||
}
|
||||
|
||||
schema_builder& set_min_compaction_threshold(int32_t t) {
|
||||
_raw._min_compaction_threshold = t;
|
||||
return *this;
|
||||
}
|
||||
|
||||
int32_t get_min_compaction_threshold() {
|
||||
int32_t get_min_compaction_threshold() const {
|
||||
return _raw._min_compaction_threshold;
|
||||
}
|
||||
|
||||
@@ -120,7 +124,7 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
int32_t get_max_compaction_threshold() {
|
||||
int32_t get_max_compaction_threshold() const {
|
||||
return _raw._max_compaction_threshold;
|
||||
}
|
||||
|
||||
@@ -129,7 +133,7 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
int32_t get_min_index_interval() {
|
||||
int32_t get_min_index_interval() const {
|
||||
return _raw._min_index_interval;
|
||||
}
|
||||
|
||||
@@ -138,7 +142,7 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
int32_t get_max_index_interval() {
|
||||
int32_t get_max_index_interval() const {
|
||||
return _raw._max_index_interval;
|
||||
}
|
||||
|
||||
@@ -156,7 +160,7 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
const speculative_retry& get_speculative_retry() {
|
||||
const speculative_retry& get_speculative_retry() const {
|
||||
return _raw._speculative_retry;
|
||||
}
|
||||
|
||||
@@ -197,6 +201,11 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
schema_builder& set_is_counter(bool is_counter) {
|
||||
_raw._is_counter = is_counter;
|
||||
return *this;
|
||||
}
|
||||
|
||||
class default_names {
|
||||
public:
|
||||
default_names(const schema_builder&);
|
||||
@@ -217,6 +226,7 @@ public:
|
||||
schema_builder& with_column(bytes name, data_type type, column_kind kind, column_id component_index);
|
||||
schema_builder& without_column(bytes name);
|
||||
schema_builder& without_column(sstring name, api::timestamp_type timestamp);
|
||||
schema_builder& without_column(sstring name, data_type, api::timestamp_type timestamp);
|
||||
schema_builder& with_column_rename(bytes from, bytes to);
|
||||
schema_builder& with_altered_column_type(bytes name, data_type new_type);
|
||||
|
||||
|
||||
@@ -27,12 +27,13 @@
|
||||
schema_mutations::schema_mutations(canonical_mutation columnfamilies,
|
||||
canonical_mutation columns,
|
||||
bool is_view,
|
||||
stdx::optional<canonical_mutation> indices)
|
||||
: _columnfamilies(columnfamilies.to_mutation(is_view ? db::schema_tables::views() : db::schema_tables::columnfamilies()))
|
||||
stdx::optional<canonical_mutation> indices,
|
||||
stdx::optional<canonical_mutation> dropped_columns)
|
||||
: _columnfamilies(columnfamilies.to_mutation(is_view ? db::schema_tables::views() : db::schema_tables::tables()))
|
||||
, _columns(columns.to_mutation(db::schema_tables::columns()))
|
||||
, _indices(indices ? stdx::optional<mutation>{indices.value().to_mutation(db::schema_tables::indexes())} : stdx::nullopt)
|
||||
{
|
||||
}
|
||||
, _dropped_columns(dropped_columns ? stdx::optional<mutation>{dropped_columns.value().to_mutation(db::schema_tables::dropped_columns())} : stdx::nullopt)
|
||||
{}
|
||||
|
||||
void schema_mutations::copy_to(std::vector<mutation>& dst) const {
|
||||
dst.push_back(_columnfamilies);
|
||||
@@ -40,6 +41,9 @@ void schema_mutations::copy_to(std::vector<mutation>& dst) const {
|
||||
if (_indices) {
|
||||
dst.push_back(_indices.value());
|
||||
}
|
||||
if (_dropped_columns) {
|
||||
dst.push_back(_dropped_columns.value());
|
||||
}
|
||||
}
|
||||
|
||||
table_schema_version schema_mutations::digest() const {
|
||||
@@ -49,13 +53,18 @@ table_schema_version schema_mutations::digest() const {
|
||||
if (_indices && !_indices.value().partition().empty()) {
|
||||
db::schema_tables::feed_hash_for_schema_digest(h, _indices.value());
|
||||
}
|
||||
if (_dropped_columns && !_dropped_columns.value().partition().empty()) {
|
||||
db::schema_tables::feed_hash_for_schema_digest(h, _dropped_columns.value());
|
||||
}
|
||||
return utils::UUID_gen::get_name_UUID(h.finalize());
|
||||
}
|
||||
|
||||
bool schema_mutations::operator==(const schema_mutations& other) const {
|
||||
return _columnfamilies == other._columnfamilies
|
||||
&& _columns == other._columns
|
||||
&& _indices == other._indices;
|
||||
&& _indices == other._indices
|
||||
&& _dropped_columns == other._dropped_columns
|
||||
;
|
||||
}
|
||||
|
||||
bool schema_mutations::operator!=(const schema_mutations& other) const {
|
||||
@@ -68,4 +77,4 @@ bool schema_mutations::live() const {
|
||||
|
||||
bool schema_mutations::is_view() const {
|
||||
return _columnfamilies.schema() == db::schema_tables::views();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,16 +31,19 @@ class schema_mutations {
|
||||
mutation _columnfamilies;
|
||||
mutation _columns;
|
||||
stdx::optional<mutation> _indices;
|
||||
stdx::optional<mutation> _dropped_columns;
|
||||
public:
|
||||
schema_mutations(mutation columnfamilies, mutation columns, stdx::optional<mutation> indices)
|
||||
schema_mutations(mutation columnfamilies, mutation columns, stdx::optional<mutation> indices, stdx::optional<mutation> dropped_columns)
|
||||
: _columnfamilies(std::move(columnfamilies))
|
||||
, _columns(std::move(columns))
|
||||
, _indices(std::move(indices))
|
||||
, _dropped_columns(std::move(dropped_columns))
|
||||
{ }
|
||||
schema_mutations(canonical_mutation columnfamilies,
|
||||
canonical_mutation columns,
|
||||
bool is_view,
|
||||
stdx::optional<canonical_mutation> indices);
|
||||
stdx::optional<canonical_mutation> indices,
|
||||
stdx::optional<canonical_mutation> dropped_columns);
|
||||
|
||||
schema_mutations(schema_mutations&&) = default;
|
||||
schema_mutations& operator=(schema_mutations&&) = default;
|
||||
@@ -60,6 +63,9 @@ public:
|
||||
const stdx::optional<mutation>& indices_mutation() const {
|
||||
return _indices;
|
||||
}
|
||||
const stdx::optional<mutation>& dropped_columns_mutation() const {
|
||||
return _dropped_columns;
|
||||
}
|
||||
|
||||
canonical_mutation columnfamilies_canonical_mutation() const {
|
||||
return canonical_mutation(_columnfamilies);
|
||||
@@ -75,6 +81,12 @@ public:
|
||||
}
|
||||
return {};
|
||||
}
|
||||
stdx::optional<canonical_mutation> dropped_columns_canonical_mutation() const {
|
||||
if (_dropped_columns) {
|
||||
return canonical_mutation(_dropped_columns.value());
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
bool is_view() const;
|
||||
|
||||
|
||||
@@ -169,7 +169,12 @@ public:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// See schema::prepare_dense_schema. We can, using v3 schemas, have columns we consider "static" without
|
||||
// the table being compound, i.e. no clustering. We can ignore prefixes, but we still need to produce
|
||||
// static for mutations.
|
||||
if (cdef && !is_static && cdef->is_static() && schema.is_static_compact_table()) {
|
||||
is_static = true;
|
||||
}
|
||||
if (is_present && is_static != cdef->is_static()) {
|
||||
throw malformed_sstable_exception(seastar::format("Mismatch between {} cell and {} column definition",
|
||||
is_static ? "static" : "non-static", cdef->is_static() ? "static" : "non-static"));
|
||||
|
||||
@@ -1617,10 +1617,17 @@ void sstable::write_static_row(file_writer& out, const schema& schema, const row
|
||||
return;
|
||||
}
|
||||
assert(column_definition.is_static());
|
||||
const auto& column_name = column_definition.name();
|
||||
if (schema.is_compound()) {
|
||||
auto sp = composite::static_prefix(schema);
|
||||
maybe_flush_pi_block(out, sp, { bytes_view(column_name) });
|
||||
write_column_name(out, sp, { bytes_view(column_name) });
|
||||
} else {
|
||||
assert(!schema.is_dense());
|
||||
maybe_flush_pi_block(out, composite(), { bytes_view(column_name) });
|
||||
write_column_name(out, bytes_view(column_name));
|
||||
}
|
||||
atomic_cell_view cell = c.as_atomic_cell();
|
||||
auto sp = composite::static_prefix(schema);
|
||||
maybe_flush_pi_block(out, sp, { bytes_view(column_definition.name()) });
|
||||
write_column_name(out, sp, { bytes_view(column_definition.name()) });
|
||||
write_cell(out, cell, column_definition);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1141,7 +1141,7 @@ private:
|
||||
}
|
||||
cf_def.__set_column_metadata(columns);
|
||||
cf_def.__set_gc_grace_seconds(s->gc_grace_seconds().count());
|
||||
cf_def.__set_default_validation_class(s->default_validator()->name());
|
||||
cf_def.__set_default_validation_class(s->make_legacy_default_validator()->name());
|
||||
cf_def.__set_min_compaction_threshold(s->min_compaction_threshold());
|
||||
cf_def.__set_max_compaction_threshold(s->max_compaction_threshold());
|
||||
cf_def.__set_key_validation_class(class_from_compound_type(*s->partition_key_type()));
|
||||
@@ -1189,6 +1189,7 @@ private:
|
||||
static schema_ptr schema_from_thrift(const CfDef& cf_def, const sstring ks_name, std::experimental::optional<utils::UUID> id = { }) {
|
||||
thrift_validation::validate_cf_def(cf_def);
|
||||
schema_builder builder(ks_name, cf_def.name, id);
|
||||
schema_builder::default_names names(builder);
|
||||
|
||||
if (cf_def.__isset.key_validation_class) {
|
||||
auto pk_types = std::move(get_types(cf_def.key_validation_class).first);
|
||||
@@ -1196,11 +1197,11 @@ private:
|
||||
builder.with_column(to_bytes(cf_def.key_alias), std::move(pk_types.back()), column_kind::partition_key);
|
||||
} else {
|
||||
for (uint32_t i = 0; i < pk_types.size(); ++i) {
|
||||
builder.with_column(to_bytes(sprint("key%d", i + 1)), std::move(pk_types[i]), column_kind::partition_key);
|
||||
builder.with_column(to_bytes(names.partition_key_name()), std::move(pk_types[i]), column_kind::partition_key);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
builder.with_column(to_bytes("key"), bytes_type, column_kind::partition_key);
|
||||
builder.with_column(to_bytes(names.partition_key_name()), bytes_type, column_kind::partition_key);
|
||||
}
|
||||
|
||||
data_type regular_column_name_type;
|
||||
@@ -1212,13 +1213,12 @@ private:
|
||||
auto ck_types = std::move(p.first);
|
||||
builder.set_is_compound(p.second);
|
||||
for (uint32_t i = 0; i < ck_types.size(); ++i) {
|
||||
builder.with_column(to_bytes(sprint("column%d", i + 1)), std::move(ck_types[i]), column_kind::clustering_key);
|
||||
builder.with_column(to_bytes(names.clustering_name()), std::move(ck_types[i]), column_kind::clustering_key);
|
||||
}
|
||||
auto&& vtype = cf_def.__isset.default_validation_class
|
||||
? db::marshal::type_parser::parse(to_sstring(cf_def.default_validation_class))
|
||||
: bytes_type;
|
||||
builder.set_default_validator(vtype);
|
||||
builder.with_column(to_bytes("value"), std::move(vtype));
|
||||
builder.with_column(to_bytes(names.compact_value_name()), std::move(vtype));
|
||||
} else {
|
||||
// Static CF
|
||||
builder.set_is_compound(false);
|
||||
@@ -1233,6 +1233,10 @@ private:
|
||||
builder.with_index(index.value());
|
||||
}
|
||||
}
|
||||
// CMH composite? Origin seemingly allows composite comparator_type.
|
||||
builder.with_column(to_bytes(names.clustering_name()), regular_column_name_type, column_kind::clustering_key);
|
||||
builder.with_column(to_bytes(names.compact_value_name()), db::marshal::type_parser::parse(to_sstring(cf_def.default_validation_class)));
|
||||
|
||||
}
|
||||
builder.set_regular_column_name_type(regular_column_name_type);
|
||||
if (cf_def.__isset.comment) {
|
||||
|
||||
@@ -37,7 +37,7 @@ public:
|
||||
}
|
||||
|
||||
static version current() {
|
||||
static version v(2, 2, 8);
|
||||
static version v(3, 0, 8);
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user