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:
Calle Wilund
2017-03-29 14:22:29 +00:00
parent f9b83e299e
commit 6c8b5fc09d
18 changed files with 836 additions and 886 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -37,7 +37,7 @@ public:
}
static version current() {
static version v(2, 2, 8);
static version v(3, 0, 8);
return v;
}