Skip to content

Commit

Permalink
schema: persist "view virtual" columns to a separate system table
Browse files Browse the repository at this point in the history
In the previous patch, we added a "view virtual" flag on columns. In this
patch we add persistance to this flag: I.e., writing it to the on-disk
schema table and reading it back on startup. But the implementation is
not as simple as adding a flag:

In the on-disk system tables, we have a "columns" table listing all the
columns in the database and their types. Cqlsh's "DESCRIBE MATERIALIZED
VIEW" works by reading this "columns" table, and listing all of the
requested view's columns. Therefore, we cannot add "virtual columns" -
which are columns not added by the user and not intended to be seen -
to this list.

We therefore need to create in this patch a separate list for virtual
columns, in a new table "view_virtual_columns". This table is essentially
identical to the existing "columns" table, just separate. We need to write
each column to the appropriate table (columns with the view_virtual flag to
"view_virtual_columns", columns without it to the old "columns"), read
from both on startup, and remember to delete columns from both when a table
is dropped.

Signed-off-by: Nadav Har'El <[email protected]>
  • Loading branch information
nyh committed Aug 16, 2018
1 parent 0a1d931 commit 36a657f
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 26 deletions.
93 changes: 71 additions & 22 deletions db/schema_tables.cc
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ static future<> do_merge_schema(distributed<service::storage_proxy>&, std::vecto

static std::vector<column_definition> create_columns_from_column_rows(
const query::result_set& rows, const sstring& keyspace,
const sstring& table, bool is_super);
const sstring& table, bool is_super, column_view_virtual is_view_virtual);


static std::vector<index_metadata> create_indices_from_index_rows(const query::result_set& rows,
Expand Down Expand Up @@ -304,9 +304,20 @@ schema_ptr scylla_tables() {
return schema;
}

schema_ptr columns() {
static thread_local auto schema = [] {
schema_builder builder(make_lw_shared(::schema(generate_legacy_id(NAME, COLUMNS), NAME, COLUMNS,
// The "columns" table lists the definitions of all columns in all tables
// and views. Its schema needs to be identical to the one in Cassandra because
// it is the API through which drivers inspect the list of columns in a table
// (e.g., cqlsh's "DESCRIBE TABLE" and "DESCRIBE MATERIALIZED VIEW" get their
// information from the columns table).
// The "view_virtual_columns" table is an additional table with exactly the
// same schema (both are created by columns_schema()), but has a separate
// list of "virtual" columns. Those are used in materialized views for keeping
// rows without data alive (see issue #3362). These virtual columns cannot be
// listed in the regular "columns" table, otherwise the "DESCRIBE MATERIALIZED
// VIEW" would list them - while it should only list real, selected, columns.

static schema_ptr columns_schema(const char* columns_table_name) {
schema_builder builder(make_lw_shared(::schema(generate_legacy_id(NAME, columns_table_name), NAME, columns_table_name,
// partition key
{{"keyspace_name", utf8_type}},
// clustering key
Expand All @@ -326,10 +337,16 @@ schema_ptr columns() {
// comment
"column definitions"
)));
builder.set_gc_grace_seconds(schema_gc_grace);
builder.with_version(generate_schema_version(builder.uuid()));
return builder.build();
}();
builder.set_gc_grace_seconds(schema_gc_grace);
builder.with_version(generate_schema_version(builder.uuid()));
return builder.build();
}
schema_ptr columns() {
static thread_local auto schema = columns_schema(COLUMNS);
return schema;
}
schema_ptr view_virtual_columns() {
static thread_local auto schema = columns_schema(VIEW_VIRTUAL_COLUMNS);
return schema;
}

Expand Down Expand Up @@ -1619,6 +1636,9 @@ static schema_mutations make_table_mutations(schema_ptr table, api::timestamp_ty

if (with_columns_and_triggers) {
for (auto&& column : table->v3().all_columns()) {
if (column.is_view_virtual()) {
throw std::logic_error("view_virtual column found in non-view table");
}
add_column_to_schema_mutation(table, column, timestamp, columns_mutation);
}
for (auto&& index : table->indices()) {
Expand All @@ -1631,7 +1651,8 @@ static schema_mutations make_table_mutations(schema_ptr table, api::timestamp_ty
}
}

return schema_mutations{std::move(m), std::move(columns_mutation), std::move(indices_mutation), std::move(dropped_columns_mutation),
return schema_mutations{std::move(m), std::move(columns_mutation), stdx::nullopt,
std::move(indices_mutation), std::move(dropped_columns_mutation),
std::move(scylla_tables_mutation)};
}

Expand Down Expand Up @@ -1690,6 +1711,7 @@ static void make_update_columns_mutations(schema_ptr old_table,
bool from_thrift,
std::vector<mutation>& mutations) {
mutation columns_mutation(columns(), partition_key::from_singular(*columns(), old_table->ks_name()));
mutation view_virtual_columns_mutation(view_virtual_columns(), partition_key::from_singular(*columns(), old_table->ks_name()));

auto diff = difference(old_table->v3().columns_by_name(), new_table->v3().columns_by_name());

Expand All @@ -1701,17 +1723,25 @@ static void make_update_columns_mutations(schema_ptr old_table,
if (from_thrift && !column.is_regular()) {
continue;
}

drop_column_from_schema_mutation(columns(), old_table, column.name_as_text(), timestamp, mutations);
if (column.is_view_virtual()) {
drop_column_from_schema_mutation(view_virtual_columns(), old_table, column.name_as_text(), timestamp, mutations);
} else {
drop_column_from_schema_mutation(columns(), old_table, column.name_as_text(), timestamp, mutations);
}
}

// 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->v3().columns_by_name().at(name);
add_column_to_schema_mutation(new_table, column, timestamp, columns_mutation);
if (column.is_view_virtual()) {
add_column_to_schema_mutation(new_table, column, timestamp, view_virtual_columns_mutation);
} else {
add_column_to_schema_mutation(new_table, column, timestamp, columns_mutation);
}
}

mutations.emplace_back(std::move(columns_mutation));
mutations.emplace_back(std::move(view_virtual_columns_mutation));

// dropped columns
auto dc_diff = difference(old_table->dropped_columns(), new_table->dropped_columns());
Expand Down Expand Up @@ -1761,7 +1791,11 @@ static void make_drop_table_or_view_mutations(schema_ptr schema_table,
m.partition().apply_delete(*schema_table, ckey, tombstone(timestamp, gc_clock::now()));
mutations.emplace_back(m);
for (auto& column : table_or_view->v3().all_columns()) {
drop_column_from_schema_mutation(columns(), table_or_view, column.name_as_text(), timestamp, mutations);
if (column.is_view_virtual()) {
drop_column_from_schema_mutation(view_virtual_columns(), table_or_view, column.name_as_text(), timestamp, mutations);
} else {
drop_column_from_schema_mutation(columns(), table_or_view, column.name_as_text(), timestamp, mutations);
}
}
for (auto& column : table_or_view->dropped_columns() | boost::adaptors::map_keys) {
drop_column_from_schema_mutation(dropped_columns(), table_or_view, column, timestamp, mutations);
Expand Down Expand Up @@ -1796,11 +1830,12 @@ static future<schema_mutations> read_table_mutations(distributed<service::storag
return when_all_succeed(
read_schema_partition_for_table(proxy, s, table.keyspace_name, table.table_name),
read_schema_partition_for_table(proxy, columns(), table.keyspace_name, table.table_name),
read_schema_partition_for_table(proxy, view_virtual_columns(), table.keyspace_name, table.table_name),
read_schema_partition_for_table(proxy, dropped_columns(), table.keyspace_name, table.table_name),
read_schema_partition_for_table(proxy, indexes(), table.keyspace_name, table.table_name),
read_schema_partition_for_table(proxy, scylla_tables(), table.keyspace_name, table.table_name)).then(
[] (mutation cf_m, mutation col_m, mutation dropped_m, mutation idx_m, mutation st_m) {
return schema_mutations{std::move(cf_m), std::move(col_m), std::move(idx_m), std::move(dropped_m), std::move(st_m)};
[] (mutation cf_m, mutation col_m, mutation vv_col_m, mutation dropped_m, mutation idx_m, mutation st_m) {
return schema_mutations{std::move(cf_m), std::move(col_m), std::move(vv_col_m), std::move(idx_m), std::move(dropped_m), std::move(st_m)};
});
#if 0
// FIXME:
Expand Down Expand Up @@ -2025,7 +2060,8 @@ schema_ptr create_table_from_mutations(const schema_ctxt& ctxt, schema_mutations
ks_name,
cf_name,/*,
fullRawComparator, */
cf == cf_type::super);
cf == cf_type::super,
column_view_virtual::no);


builder.set_is_dense(is_dense);
Expand Down Expand Up @@ -2187,7 +2223,8 @@ static std::vector<column_definition> create_columns_from_column_rows(const quer
const sstring& keyspace,
const sstring& table, /*,
AbstractType<?> rawComparator, */
bool is_super)
bool is_super,
column_view_virtual is_view_virtual)
{
std::vector<column_definition> columns;
for (auto&& row : rows.rows()) {
Expand All @@ -2204,7 +2241,7 @@ static std::vector<column_definition> create_columns_from_column_rows(const quer
}
}

columns.emplace_back(name_bytes, type, kind, position);
columns.emplace_back(name_bytes, type, kind, position, is_view_virtual);
}
return columns;
}
Expand Down Expand Up @@ -2247,10 +2284,16 @@ view_ptr create_view_from_mutations(const schema_ctxt& ctxt, schema_mutations sm
schema_builder builder{ks_name, cf_name, id};
prepare_builder_from_table_row(ctxt, builder, row);

auto column_defs = create_columns_from_column_rows(query::result_set(sm.columns_mutation()), ks_name, cf_name, false);
auto column_defs = create_columns_from_column_rows(query::result_set(sm.columns_mutation()), ks_name, cf_name, false, column_view_virtual::no);
for (auto&& cdef : column_defs) {
builder.with_column(cdef);
}
if (sm.view_virtual_columns_mutation()) {
column_defs = create_columns_from_column_rows(query::result_set(*sm.view_virtual_columns_mutation()), ks_name, cf_name, false, column_view_virtual::yes);
for (auto&& cdef : column_defs) {
builder.with_column(cdef);
}
}

if (version) {
builder.with_version(*version);
Expand Down Expand Up @@ -2320,12 +2363,17 @@ static schema_mutations make_view_mutations(view_ptr view, api::timestamp_type t


mutation columns_mutation(columns(), pkey);
mutation view_virtual_columns_mutation(view_virtual_columns(), pkey);
mutation dropped_columns_mutation(dropped_columns(), pkey);
mutation indices_mutation(indexes(), pkey);

if (with_columns) {
for (auto&& column : view->v3().all_columns()) {
add_column_to_schema_mutation(view, column, timestamp, columns_mutation);
if (column.is_view_virtual()) {
add_column_to_schema_mutation(view, column, timestamp, view_virtual_columns_mutation);
} else {
add_column_to_schema_mutation(view, column, timestamp, columns_mutation);
}
}

for (auto&& e : view->dropped_columns()) {
Expand All @@ -2338,7 +2386,8 @@ static schema_mutations make_view_mutations(view_ptr view, api::timestamp_type t

auto scylla_tables_mutation = make_scylla_tables_mutation(view, timestamp);

return schema_mutations{std::move(m), std::move(columns_mutation), std::move(indices_mutation), std::move(dropped_columns_mutation),
return schema_mutations{std::move(m), std::move(columns_mutation), std::move(view_virtual_columns_mutation),
std::move(indices_mutation), std::move(dropped_columns_mutation),
std::move(scylla_tables_mutation)};
}

Expand Down Expand Up @@ -2634,7 +2683,7 @@ data_type parse_type(sstring str)
std::vector<schema_ptr> all_tables() {
return {
keyspaces(), tables(), scylla_tables(), columns(), dropped_columns(), triggers(),
views(), indexes(), types(), functions(), aggregates(),
views(), indexes(), types(), functions(), aggregates(), view_virtual_columns()
};
}

Expand Down
2 changes: 2 additions & 0 deletions db/schema_tables.hh
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,10 @@ static constexpr auto TYPES = "types";
static constexpr auto FUNCTIONS = "functions";
static constexpr auto AGGREGATES = "aggregates";
static constexpr auto INDEXES = "indexes";
static constexpr auto VIEW_VIRTUAL_COLUMNS = "view_virtual_columns"; // Scylla specific

schema_ptr columns();
schema_ptr view_virtual_columns();
schema_ptr dropped_columns();
schema_ptr indexes();
schema_ptr tables();
Expand Down
1 change: 1 addition & 0 deletions idl/frozen_schema.idl.hh
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ class schema_mutations {
std::experimental::optional<canonical_mutation> indices_canonical_mutation()[[version 2.0]];
std::experimental::optional<canonical_mutation> dropped_columns_canonical_mutation()[[version 2.0]];
std::experimental::optional<canonical_mutation> scylla_tables_canonical_mutation()[[version 2.0]];
std::experimental::optional<canonical_mutation> view_virtual_columns_canonical_mutation()[[version 2.4]];
};

class schema stub [[writable]] {
Expand Down
14 changes: 12 additions & 2 deletions schema_mutations.cc
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,11 @@ schema_mutations::schema_mutations(canonical_mutation columnfamilies,
bool is_view,
stdx::optional<canonical_mutation> indices,
stdx::optional<canonical_mutation> dropped_columns,
stdx::optional<canonical_mutation> scylla_tables)
stdx::optional<canonical_mutation> scylla_tables,
stdx::optional<canonical_mutation> view_virtual_columns)
: _columnfamilies(columnfamilies.to_mutation(is_view ? db::schema_tables::views() : db::schema_tables::tables()))
, _columns(columns.to_mutation(db::schema_tables::columns()))
, _view_virtual_columns(view_virtual_columns ? mutation_opt{view_virtual_columns.value().to_mutation(db::schema_tables::view_virtual_columns())} : stdx::nullopt)
, _indices(indices ? mutation_opt{indices.value().to_mutation(db::schema_tables::indexes())} : stdx::nullopt)
, _dropped_columns(dropped_columns ? mutation_opt{dropped_columns.value().to_mutation(db::schema_tables::dropped_columns())} : stdx::nullopt)
, _scylla_tables(scylla_tables ? mutation_opt{scylla_tables.value().to_mutation(db::schema_tables::scylla_tables())} : stdx::nullopt)
Expand All @@ -40,6 +42,9 @@ schema_mutations::schema_mutations(canonical_mutation columnfamilies,
void schema_mutations::copy_to(std::vector<mutation>& dst) const {
dst.push_back(_columnfamilies);
dst.push_back(_columns);
if (_view_virtual_columns) {
dst.push_back(*_view_virtual_columns);
}
if (_indices) {
dst.push_back(*_indices);
}
Expand Down Expand Up @@ -68,6 +73,9 @@ table_schema_version schema_mutations::digest() const {
md5_hasher h;
db::schema_tables::feed_hash_for_schema_digest(h, _columnfamilies);
db::schema_tables::feed_hash_for_schema_digest(h, _columns);
if (_view_virtual_columns && !_view_virtual_columns->partition().empty()) {
db::schema_tables::feed_hash_for_schema_digest(h, *_view_virtual_columns);
}
if (_indices && !_indices->partition().empty()) {
db::schema_tables::feed_hash_for_schema_digest(h, *_indices);
}
Expand All @@ -94,6 +102,7 @@ static mutation_opt compact(const mutation& m) {
bool schema_mutations::operator==(const schema_mutations& other) const {
return compact(_columnfamilies) == compact(other._columnfamilies)
&& compact(_columns) == compact(other._columns)
&& compact(_view_virtual_columns) == compact(other._view_virtual_columns)
&& compact(_indices) == compact(other._indices)
&& compact(_dropped_columns) == compact(other._dropped_columns)
&& compact(_scylla_tables) == compact(other._scylla_tables)
Expand All @@ -105,7 +114,8 @@ bool schema_mutations::operator!=(const schema_mutations& other) const {
}

bool schema_mutations::live() const {
return _columnfamilies.live_row_count() > 0 || _columns.live_row_count() > 0;
return _columnfamilies.live_row_count() > 0 || _columns.live_row_count() > 0 ||
(_view_virtual_columns && _view_virtual_columns->live_row_count() > 0);
}

bool schema_mutations::is_view() const {
Expand Down
18 changes: 16 additions & 2 deletions schema_mutations.hh
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,16 @@
class schema_mutations {
mutation _columnfamilies;
mutation _columns;
mutation_opt _view_virtual_columns;
mutation_opt _indices;
mutation_opt _dropped_columns;
mutation_opt _scylla_tables;
public:
schema_mutations(mutation columnfamilies, mutation columns, mutation_opt indices, mutation_opt dropped_columns,
schema_mutations(mutation columnfamilies, mutation columns, mutation_opt view_virtual_columns, mutation_opt indices, mutation_opt dropped_columns,
mutation_opt scylla_tables)
: _columnfamilies(std::move(columnfamilies))
, _columns(std::move(columns))
, _view_virtual_columns(std::move(view_virtual_columns))
, _indices(std::move(indices))
, _dropped_columns(std::move(dropped_columns))
, _scylla_tables(std::move(scylla_tables))
Expand All @@ -48,7 +50,8 @@ public:
bool is_view,
stdx::optional<canonical_mutation> indices,
stdx::optional<canonical_mutation> dropped_columns,
stdx::optional<canonical_mutation> scylla_tables);
stdx::optional<canonical_mutation> scylla_tables,
stdx::optional<canonical_mutation> view_virtual_columns);

schema_mutations(schema_mutations&&) = default;
schema_mutations& operator=(schema_mutations&&) = default;
Expand All @@ -65,6 +68,10 @@ public:
return _columns;
}

const mutation_opt& view_virtual_columns_mutation() const {
return _view_virtual_columns;
}

const mutation_opt& scylla_tables() const {
return _scylla_tables;
}
Expand All @@ -88,6 +95,13 @@ public:
return canonical_mutation(_columns);
}

stdx::optional<canonical_mutation> view_virtual_columns_canonical_mutation() const {
if (_view_virtual_columns) {
return canonical_mutation(*_view_virtual_columns);
}
return {};
}

stdx::optional<canonical_mutation> indices_canonical_mutation() const {
if (_indices) {
return canonical_mutation(*_indices);
Expand Down

0 comments on commit 36a657f

Please sign in to comment.