mirror of
https://github.com/scylladb/scylladb.git
synced 2026-05-31 03:56:42 +00:00
This patch replaces the current row tombstone representation by a row_tombstone. The intent of the patch is thus to reify the idea of shadowable tombstones, that up until now we considered all materialized view row tombstones to be. We need to distinguish shadowable from non-shadowable row tombstones to support scenarios such as, when inserting to a table with a materialzied view: 1. insert into base (p, v1, v2) values (3, 1, 3) using timestamp 1 2. delete from base using timestamp 2 where p = 3 3. insert into base (p, v1) values (3, 1) using timestamp 3 These should yield a view row where v2 is definitely null, but with the current implementation, v2 will pop back with its value v2=3@TS=1, even though its dead in the base row. This is because the row tombstone inserted at 2) is a shadowable one. This patch only addresses the memory representation of such row_tombstones. Signed-off-by: Duarte Nunes <duarte@scylladb.com>
233 lines
8.9 KiB
C++
233 lines
8.9 KiB
C++
/*
|
|
* Copyright (C) 2015 ScyllaDB
|
|
*/
|
|
|
|
/*
|
|
* This file is part of Scylla.
|
|
*
|
|
* Scylla is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Affero General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* Scylla is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with Scylla. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include <seastar/core/simple-stream.hh>
|
|
|
|
#include "mutation_partition_view.hh"
|
|
#include "schema.hh"
|
|
#include "atomic_cell.hh"
|
|
#include "utils/data_input.hh"
|
|
#include "mutation_partition_serializer.hh"
|
|
#include "mutation_partition.hh"
|
|
#include "counters.hh"
|
|
|
|
#include "utils/UUID.hh"
|
|
#include "serializer.hh"
|
|
#include "idl/uuid.dist.hh"
|
|
#include "idl/keys.dist.hh"
|
|
#include "idl/mutation.dist.hh"
|
|
#include "serializer_impl.hh"
|
|
#include "serialization_visitors.hh"
|
|
#include "idl/uuid.dist.impl.hh"
|
|
#include "idl/keys.dist.impl.hh"
|
|
#include "idl/mutation.dist.impl.hh"
|
|
|
|
using namespace db;
|
|
|
|
namespace {
|
|
|
|
using atomic_cell_variant = boost::variant<ser::live_cell_view,
|
|
ser::expiring_cell_view,
|
|
ser::dead_cell_view,
|
|
ser::counter_cell_view,
|
|
ser::unknown_variant_type>;
|
|
|
|
atomic_cell read_atomic_cell(atomic_cell_variant cv)
|
|
{
|
|
struct atomic_cell_visitor : boost::static_visitor<atomic_cell> {
|
|
atomic_cell operator()(ser::live_cell_view& lcv) const {
|
|
return atomic_cell::make_live(lcv.created_at(), lcv.value());
|
|
}
|
|
atomic_cell operator()(ser::expiring_cell_view& ecv) const {
|
|
return atomic_cell::make_live(ecv.c().created_at(), ecv.c().value(), ecv.expiry(), ecv.ttl());
|
|
}
|
|
atomic_cell operator()(ser::dead_cell_view& dcv) const {
|
|
return atomic_cell::make_dead(dcv.tomb().timestamp(), dcv.tomb().deletion_time());
|
|
}
|
|
atomic_cell operator()(ser::counter_cell_view& ccv) const {
|
|
class counter_cell_visitor : public boost::static_visitor<atomic_cell> {
|
|
api::timestamp_type _created_at;
|
|
public:
|
|
explicit counter_cell_visitor(api::timestamp_type ts)
|
|
: _created_at(ts) { }
|
|
|
|
atomic_cell operator()(ser::counter_cell_full_view& ccv) const {
|
|
// TODO: a lot of copying for something called view
|
|
counter_cell_builder ccb; // we know the final number of shards
|
|
for (auto csv : ccv.shards()) {
|
|
ccb.add_shard(counter_shard(csv));
|
|
}
|
|
return ccb.build(_created_at);
|
|
}
|
|
atomic_cell operator()(ser::counter_cell_update_view& ccv) const {
|
|
return atomic_cell::make_live_counter_update(_created_at, ccv.delta());
|
|
}
|
|
atomic_cell operator()(ser::unknown_variant_type&) const {
|
|
throw std::runtime_error("Trying to deserialize counter cell in unknown state");
|
|
}
|
|
};
|
|
auto v = ccv.value();
|
|
return boost::apply_visitor(counter_cell_visitor(ccv.created_at()), v);
|
|
}
|
|
atomic_cell operator()(ser::unknown_variant_type&) const {
|
|
throw std::runtime_error("Trying to deserialize cell in unknown state");
|
|
}
|
|
};
|
|
return boost::apply_visitor(atomic_cell_visitor(), cv);
|
|
}
|
|
|
|
collection_mutation read_collection_cell(ser::collection_cell_view cv)
|
|
{
|
|
collection_type_impl::mutation mut;
|
|
mut.tomb = cv.tomb();
|
|
auto&& elements = cv.elements();
|
|
mut.cells.reserve(elements.size());
|
|
for (auto&& e : elements) {
|
|
mut.cells.emplace_back(e.key(), read_atomic_cell(e.value()));
|
|
}
|
|
return collection_type_impl::serialize_mutation_form(mut);
|
|
}
|
|
|
|
template<typename Visitor>
|
|
void read_and_visit_row(ser::row_view rv, const column_mapping& cm, column_kind kind, Visitor&& visitor)
|
|
{
|
|
for (auto&& cv : rv.columns()) {
|
|
auto id = cv.id();
|
|
auto& col = cm.column_at(kind, id);
|
|
|
|
class atomic_cell_or_collection_visitor : public boost::static_visitor<> {
|
|
Visitor& _visitor;
|
|
column_id _id;
|
|
const column_mapping_entry& _col;
|
|
public:
|
|
explicit atomic_cell_or_collection_visitor(Visitor& v, column_id id, const column_mapping_entry& col)
|
|
: _visitor(v), _id(id), _col(col) { }
|
|
|
|
void operator()(atomic_cell_variant& acv) const {
|
|
if (!_col.type()->is_atomic()) {
|
|
throw std::runtime_error("A collection expected, got an atomic cell");
|
|
}
|
|
// FIXME: Pass view to cell to avoid copy
|
|
auto&& outer = current_allocator();
|
|
with_allocator(standard_allocator(), [&] {
|
|
auto cell = read_atomic_cell(acv);
|
|
with_allocator(outer, [&] {
|
|
_visitor.accept_atomic_cell(_id, cell);
|
|
});
|
|
});
|
|
}
|
|
void operator()(ser::collection_cell_view& ccv) const {
|
|
if (_col.type()->is_atomic()) {
|
|
throw std::runtime_error("An atomic cell expected, got a collection");
|
|
}
|
|
// FIXME: Pass view to cell to avoid copy
|
|
auto&& outer = current_allocator();
|
|
with_allocator(standard_allocator(), [&] {
|
|
auto cell = read_collection_cell(ccv);
|
|
with_allocator(outer, [&] {
|
|
_visitor.accept_collection(_id, cell);
|
|
});
|
|
});
|
|
}
|
|
void operator()(ser::unknown_variant_type&) const {
|
|
throw std::runtime_error("Trying to deserialize unknown cell type");
|
|
}
|
|
};
|
|
auto&& cell = cv.c();
|
|
boost::apply_visitor(atomic_cell_or_collection_visitor(visitor, id, col), cell);
|
|
}
|
|
}
|
|
|
|
row_marker read_row_marker(boost::variant<ser::live_marker_view, ser::expiring_marker_view, ser::dead_marker_view, ser::no_marker_view, ser::unknown_variant_type> rmv)
|
|
{
|
|
struct row_marker_visitor : boost::static_visitor<row_marker> {
|
|
row_marker operator()(ser::live_marker_view& lmv) const {
|
|
return row_marker(lmv.created_at());
|
|
}
|
|
row_marker operator()(ser::expiring_marker_view& emv) const {
|
|
return row_marker(emv.lm().created_at(), emv.ttl(), emv.expiry());
|
|
}
|
|
row_marker operator()(ser::dead_marker_view& dmv) const {
|
|
return row_marker(dmv.tomb());
|
|
}
|
|
row_marker operator()(ser::no_marker_view&) const {
|
|
return row_marker();
|
|
}
|
|
row_marker operator()(ser::unknown_variant_type&) const {
|
|
throw std::runtime_error("Trying to deserialize unknown row marker type");
|
|
}
|
|
};
|
|
return boost::apply_visitor(row_marker_visitor(), rmv);
|
|
}
|
|
|
|
}
|
|
|
|
void
|
|
mutation_partition_view::accept(const schema& s, mutation_partition_visitor& visitor) const {
|
|
accept(s.get_column_mapping(), visitor);
|
|
}
|
|
|
|
void
|
|
mutation_partition_view::accept(const column_mapping& cm, mutation_partition_visitor& visitor) const {
|
|
auto in = _in;
|
|
auto mpv = ser::deserialize(in, boost::type<ser::mutation_partition_view>());
|
|
|
|
visitor.accept_partition_tombstone(mpv.tomb());
|
|
|
|
struct static_row_cell_visitor {
|
|
mutation_partition_visitor& _visitor;
|
|
|
|
void accept_atomic_cell(column_id id, const atomic_cell& ac) const {
|
|
_visitor.accept_static_cell(id, ac);
|
|
}
|
|
void accept_collection(column_id id, const collection_mutation& cm) const {
|
|
_visitor.accept_static_cell(id, cm);
|
|
}
|
|
};
|
|
read_and_visit_row(mpv.static_row(), cm, column_kind::static_column, static_row_cell_visitor{visitor});
|
|
|
|
for (auto&& rt : mpv.range_tombstones()) {
|
|
visitor.accept_row_tombstone(rt);
|
|
}
|
|
|
|
for (auto&& cr : mpv.rows()) {
|
|
auto t = row_tombstone(cr.deleted_at(), shadowable_tombstone(cr.shadowable_deleted_at()));
|
|
visitor.accept_row(cr.key(), t, read_row_marker(cr.marker()));
|
|
|
|
struct cell_visitor {
|
|
mutation_partition_visitor& _visitor;
|
|
|
|
void accept_atomic_cell(column_id id, const atomic_cell& ac) const {
|
|
_visitor.accept_row_cell(id, ac);
|
|
}
|
|
void accept_collection(column_id id, const collection_mutation& cm) const {
|
|
_visitor.accept_row_cell(id, cm);
|
|
}
|
|
};
|
|
read_and_visit_row(cr.cells(), cm, column_kind::regular_column, cell_visitor{visitor});
|
|
}
|
|
}
|
|
|
|
mutation_partition_view mutation_partition_view::from_view(ser::mutation_partition_view v)
|
|
{
|
|
return { v.v };
|
|
}
|