schema: add fmt::formatter for schema

before this change, we rely on the default-generated fmt::formatter
created from operator<<, but fmt v10 dropped the default-generated
formatter.

in this change, we define formatters for

* column_definition
* column_mapping
* ordinal_column_id
* raw_view_info
* schema
* view_ptr

their operator<<:s are dropped. but operator<< for schema is preserved,
as we are still printing `seastar::lw_shared_ptr<const schema>` with
our homebrew generic formatter for `seastar::lw_shared_ptr<>`, which
uses operator<< to print the pointee.

Refs #13245

Signed-off-by: Kefu Chai <kefu.chai@scylladb.com>

Closes scylladb/scylladb#17768
This commit is contained in:
Kefu Chai
2024-03-12 13:15:07 +08:00
committed by Botond Dénes
parent 85c4034495
commit fb4f48b4ed
3 changed files with 132 additions and 94 deletions

View File

@@ -117,26 +117,21 @@ get_column_types(const Sequence& column_definitions) {
return result;
}
std::ostream& operator<<(std::ostream& out, const column_mapping& cm) {
auto fmt::formatter<column_mapping>::format(const column_mapping& cm, fmt::format_context& ctx) const
-> decltype(ctx.out()) {
column_id n_static = cm.n_static();
column_id n_regular = cm.columns().size() - n_static;
auto pr_entry = [] (column_id i, const column_mapping_entry& e) {
// Without schema we don't know if name is UTF8. If we had schema we could use
// s->regular_column_name_type()->to_string(e.name()).
return format("{{id={}, name=0x{}, type={}}}", i, e.name(), e.type()->name());
return fmt::format("{{id={}, name=0x{}, type={}}}", i, e.name(), e.type()->name());
};
fmt::print(out, "{{static=[{}], regular=[{}]}}",
return fmt::format_to(ctx.out(), "{{static=[{}], regular=[{}]}}",
fmt::join(boost::irange<column_id>(0, n_static) |
boost::adaptors::transformed([&] (column_id i) { return pr_entry(i, cm.static_column_at(i)); }), ", "),
fmt::join(boost::irange<column_id>(0, n_regular) |
boost::adaptors::transformed([&] (column_id i) { return pr_entry(i, cm.regular_column_at(i)); }), ", "));
return out;
}
std::ostream& operator<<(std::ostream& os, ordinal_column_id id)
{
return os << static_cast<column_count_type>(id);
}
thread_local std::map<sstring, std::unique_ptr<dht::i_partitioner>> partitioners;
@@ -655,21 +650,20 @@ column_definition::column_definition(bytes name, data_type type, column_kind kin
, kind(kind)
{}
std::ostream& operator<<(std::ostream& os, const column_definition& cd) {
os << "ColumnDefinition{";
os << "name=" << cd.name_as_text();
os << ", type=" << cd.type->name();
os << ", kind=" << to_sstring(cd.kind);
auto fmt::formatter<column_definition>::format(const column_definition& cd, fmt::format_context& ctx) const
-> decltype(ctx.out()) {
auto out = ctx.out();
out = fmt::format_to(out, "ColumnDefinition{{name={}, type={}, kind={}",
cd.name_as_text(), cd.type->name(), to_sstring(cd.kind));
if (cd.is_view_virtual()) {
os << ", view_virtual";
out = fmt::format_to(out, ", view_virtual");
}
if (cd.is_computed()) {
os << ", computed:" << cd.get_computation().serialize();
out = fmt::format_to(out, ", computed:{}", cd.get_computation().serialize());
}
os << ", componentIndex=" << (cd.has_component_index() ? std::to_string(cd.component_index()) : "null");
os << ", droppedAt=" << cd._dropped_at;
os << "}";
return os;
out = fmt::format_to(out, ", componentIndex={}", cd.has_component_index() ? std::to_string(cd.component_index()) : "null");
out = fmt::format_to(out, ", droppedAt={}", cd._dropped_at);
return fmt::format_to(out, "}}");
}
const column_definition*
@@ -695,91 +689,102 @@ schema::column_at(ordinal_column_id ordinal_id) const {
return _raw._columns.at(static_cast<column_count_type>(ordinal_id));
}
std::ostream& operator<<(std::ostream& os, const schema& s) {
os << "org.apache.cassandra.config.CFMetaData@" << &s << "[";
os << "cfId=" << s._raw._id;
os << ",ksName=" << s._raw._ks_name;
os << ",cfName=" << s._raw._cf_name;
os << ",cfType=" << cf_type_to_sstring(s._raw._type);
os << ",comparator=" << cell_comparator::to_sstring(s);
os << ",comment=" << s._raw._comment;
os << ",readRepairChance=" << s._raw._read_repair_chance;
os << ",dcLocalReadRepairChance=" << s._raw._dc_local_read_repair_chance;
os << ",tombstoneGcOptions=" << s.tombstone_gc_options().to_sstring();
os << ",gcGraceSeconds=" << s._raw._gc_grace_seconds;
os << ",keyValidator=" << s.thrift_key_validator();
os << ",minCompactionThreshold=" << s._raw._min_compaction_threshold;
os << ",maxCompactionThreshold=" << s._raw._max_compaction_threshold;
os << ",columnMetadata=[";
auto fmt::formatter<schema>::format(const schema& s, fmt::format_context& ctx) const
-> decltype(ctx.out()) {
auto out = ctx.out();
out = fmt::format_to(out, "org.apache.cassandra.config.CFMetaData@{}[", fmt::ptr(&s));
out = fmt::format_to(out, "cfId={}", s._raw._id);
out = fmt::format_to(out, ",ksName=={}", s._raw._ks_name);
out = fmt::format_to(out, ",cfName={}", s._raw._cf_name);
out = fmt::format_to(out, ",cfType={}", cf_type_to_sstring(s._raw._type));
out = fmt::format_to(out, ",comparator={}", cell_comparator::to_sstring(s));
out = fmt::format_to(out, ",comment={}", s._raw._comment);
out = fmt::format_to(out, ",readRepairChance={}", s._raw._read_repair_chance);
out = fmt::format_to(out, ",dcLocalReadRepairChance={}", s._raw._dc_local_read_repair_chance);
out = fmt::format_to(out, ",tombstoneGcOptions={}", s.tombstone_gc_options().to_sstring());
out = fmt::format_to(out, ",gcGraceSeconds={}", s._raw._gc_grace_seconds);
out = fmt::format_to(out, ",keyValidator={}", s.thrift_key_validator());
out = fmt::format_to(out, ",minCompactionThreshold={}", s._raw._min_compaction_threshold);
out = fmt::format_to(out, ",maxCompactionThreshold={}", s._raw._max_compaction_threshold);
out = fmt::format_to(out, ",columnMetadata=[");
int n = 0;
for (auto& cdef : s._raw._columns) {
if (n++ != 0) {
os << ", ";
out = fmt::format_to(out, ", ");
}
os << cdef;
out = fmt::format_to(out, "{}", cdef);
}
os << "]";
os << ",compactionStrategyClass=class org.apache.cassandra.db.compaction." << sstables::compaction_strategy::name(s._raw._compaction_strategy);
os << ",compactionStrategyOptions={";
out = fmt::format_to(out, "]");
out = fmt::format_to(out, ",compactionStrategyClass=class org.apache.cassandra.db.compaction.{}",
sstables::compaction_strategy::name(s._raw._compaction_strategy));
out = fmt::format_to(out, ",compactionStrategyOptions={{");
n = 0;
for (auto& p : s._raw._compaction_strategy_options) {
os << p.first << "=" << p.second;
os << ", ";
out = fmt::format_to(out, "{}={}", p.first, p.second);
out = fmt::format_to(out, ", ");
}
os << "enabled=" << std::boolalpha << s._raw._compaction_enabled;
os << "}";
os << ",compressionParameters={";
out = fmt::format_to(out, "enabled={}", s._raw._compaction_enabled);
out = fmt::format_to(out, "}}");
out = fmt::format_to(out, ",compressionParameters={{");
n = 0;
for (auto& p : s._raw._compressor_params.get_options() ) {
if (n++ != 0) {
os << ", ";
out = fmt::format_to(out, ", ");
}
os << p.first << "=" << p.second;
out = fmt::format_to(out, "{}={}", p.first, p.second);
}
os << "}";
os << ",bloomFilterFpChance=" << s._raw._bloom_filter_fp_chance;
os << ",memtableFlushPeriod=" << s._raw._memtable_flush_period;
os << ",caching=" << s._raw._caching_options.to_sstring();
os << ",cdc=" << s.cdc_options().to_sstring();
os << ",defaultTimeToLive=" << s._raw._default_time_to_live.count();
os << ",minIndexInterval=" << s._raw._min_index_interval;
os << ",maxIndexInterval=" << s._raw._max_index_interval;
os << ",speculativeRetry=" << s._raw._speculative_retry.to_sstring();
os << ",triggers=[]";
os << ",isDense=" << std::boolalpha << s._raw._is_dense;
os << ",version=" << s.version();
os << ",droppedColumns={";
out = fmt::format_to(out, "}}");
out = fmt::format_to(out, ",bloomFilterFpChance={}", s._raw._bloom_filter_fp_chance);
out = fmt::format_to(out, ",memtableFlushPeriod={}", s._raw._memtable_flush_period);
out = fmt::format_to(out, ",caching={}", s._raw._caching_options.to_sstring());
out = fmt::format_to(out, ",cdc={}", s.cdc_options().to_sstring());
out = fmt::format_to(out, ",defaultTimeToLive={}", s._raw._default_time_to_live.count());
out = fmt::format_to(out, ",minIndexInterval={}", s._raw._min_index_interval);
out = fmt::format_to(out, ",maxIndexInterval={}", s._raw._max_index_interval);
out = fmt::format_to(out, ",speculativeRetry={}", s._raw._speculative_retry.to_sstring());
out = fmt::format_to(out, ",triggers=[]");
out = fmt::format_to(out, ",isDense={}", s._raw._is_dense);
out = fmt::format_to(out, ",version={}", s.version());
out = fmt::format_to(out, ",droppedColumns={{");
n = 0;
for (auto& dc : s._raw._dropped_columns) {
if (n++ != 0) {
os << ", ";
out = fmt::format_to(out, ", ");
}
os << dc.first << " : { " << dc.second.type->name() << ", " << dc.second.timestamp << " }";
out = fmt::format_to(out,"{} : {{ {}, {} }}",
dc.first, dc.second.type->name(), dc.second.timestamp);
}
os << "}";
os << ",collections={";
out = fmt::format_to(out, "}}");
out = fmt::format_to(out, ",collections={{");
n = 0;
for (auto& c : s._raw._collections) {
if (n++ != 0) {
os << ", ";
out = fmt::format_to(out, ", ");
}
os << c.first << " : " << c.second->name();
out = fmt::format_to(out,"{} : {}", c.first, c.second->name());
}
os << "}";
os << ",indices={";
out = fmt::format_to(out, "}}");
out = fmt::format_to(out, ",indices={{");
n = 0;
for (auto& c : s._raw._indices_by_name) {
if (n++ != 0) {
os << ", ";
out = fmt::format_to(out, ", ");
}
os << c.first << " : " << c.second.id();
out = fmt::format_to(out,"{} : {}", c.first, c.second.id());
}
os << "}";
out = fmt::format_to(out, "}}");
if (s.is_view()) {
fmt::print(os, ", viewInfo={}", *s.view_info());
out = fmt::format_to(out, ", viewInfo={}", *s.view_info());
}
os << "]";
return os;
return fmt::format_to(out, "]");
}
static std::ostream& map_as_cql_param(std::ostream& os, const std::map<sstring, sstring>& map, bool first = true) {
@@ -795,6 +800,11 @@ static std::ostream& map_as_cql_param(std::ostream& os, const std::map<sstring,
return os;
}
std::ostream& operator<<(std::ostream& os, const schema& s) {
fmt::print(os, "{}", s);
return os;
}
static std::ostream& column_definition_as_cql_key(std::ostream& os, const column_definition & cd) {
os << cd.name_as_cql_string();
os << " " << cd.type->cql3_type_name();
@@ -2028,18 +2038,20 @@ bool operator==(const raw_view_info& x, const raw_view_info& y) {
&& x._where_clause == y._where_clause;
}
std::ostream& operator<<(std::ostream& os, const raw_view_info& view) {
os << "ViewInfo{";
os << "baseTableId=" << view._base_id;
os << ", baseTableName=" << view._base_name;
os << ", includeAllColumns=" << view._include_all_columns;
os << ", whereClause=" << view._where_clause;
os << "}";
return os;
auto fmt::formatter<raw_view_info>::format(const raw_view_info& view, fmt::format_context& ctx) const
-> decltype(ctx.out()) {
return fmt::format_to(ctx.out(),
"ViewInfo{{baseTableId={}, baseTableName={}, includeAllColumns={}, whereClause={}}}",
view._base_id, view._base_name, view._include_all_columns, view._where_clause);
}
std::ostream& operator<<(std::ostream& os, const view_ptr& view) {
return view ? os << *view : os << "null";
auto fmt::formatter<view_ptr>::format(const view_ptr& view, fmt::format_context& ctx) const
-> decltype(ctx.out()) {
if (view) {
return fmt::format_to(ctx.out(), "{}", *view);
} else {
return fmt::format_to(ctx.out(), "null");
}
}
namespace std {

View File

@@ -58,8 +58,6 @@ using column_id = column_count_type;
// mixing with column id.
enum class ordinal_column_id: column_count_type {};
std::ostream& operator<<(std::ostream& os, ordinal_column_id id);
// Maintains a set of columns used in a query. The columns are
// identified by ordinal_id.
//
@@ -353,7 +351,7 @@ public:
const sstring& name_as_text() const;
const bytes& name() const;
sstring name_as_cql_string() const;
friend std::ostream& operator<<(std::ostream& os, const column_definition& cd);
friend fmt::formatter<column_definition>;
bool has_component_index() const {
return is_primary_key();
}
@@ -440,7 +438,6 @@ public:
const column_mapping_entry& column_at(column_kind kind, column_id id) const;
const column_mapping_entry& static_column_at(column_id id) const;
const column_mapping_entry& regular_column_at(column_id id) const;
friend std::ostream& operator<<(std::ostream& out, const column_mapping& cm);
};
bool operator==(const column_mapping& lhs, const column_mapping& rhs);
@@ -474,11 +471,10 @@ public:
}
friend bool operator==(const raw_view_info&, const raw_view_info&);
friend std::ostream& operator<<(std::ostream& os, const raw_view_info& view);
friend fmt::formatter<raw_view_info>;
};
bool operator==(const raw_view_info&, const raw_view_info&);
std::ostream& operator<<(std::ostream& os, const raw_view_info& view);
class view_info;
@@ -925,7 +921,7 @@ public:
bool has_index(const sstring& index_name) const;
// Search for an existing index with same kind and options.
std::optional<index_metadata> find_index_noname(const index_metadata& target) const;
friend std::ostream& operator<<(std::ostream& os, const schema& s);
friend fmt::formatter<schema>;
virtual sstring keypace_name() const override { return ks_name(); }
virtual sstring element_name() const override { return cf_name(); }
virtual sstring element_type(replica::database& db) const override;
@@ -1020,8 +1016,6 @@ public:
explicit operator bool() const noexcept {
return bool(_schema);
}
friend std::ostream& operator<<(std::ostream& os, const view_ptr& s);
};
std::ostream& operator<<(std::ostream& os, const view_ptr& view);
@@ -1043,3 +1037,30 @@ inline void check_schema_version(table_schema_version expected, const schema& ac
throw_with_backtrace<schema_mismatch_error>(expected, access);
}
}
template <> struct fmt::formatter<ordinal_column_id> : fmt::formatter<std::string_view> {
auto format(ordinal_column_id id, fmt::format_context& ctx) const {
return fmt::format_to(ctx.out(), "{}", static_cast<column_count_type>(id));
}
};
template <> struct fmt::formatter<column_definition> : fmt::formatter<std::string_view> {
auto format(const column_definition&, fmt::format_context& ctx) const -> decltype(ctx.out());
};
template <> struct fmt::formatter<column_mapping> : fmt::formatter<std::string_view> {
auto format(const column_mapping&, fmt::format_context& ctx) const -> decltype(ctx.out());
};
template <> struct fmt::formatter<raw_view_info> : fmt::formatter<std::string_view> {
auto format(const raw_view_info&, fmt::format_context& ctx) const -> decltype(ctx.out());
};
template <> struct fmt::formatter<schema> : fmt::formatter<std::string_view> {
auto format(const schema&, fmt::format_context& ctx) const -> decltype(ctx.out());
};
std::ostream& operator<<(std::ostream& os, const schema& s);
template <> struct fmt::formatter<view_ptr> : fmt::formatter<std::string_view> {
auto format(const view_ptr& view, fmt::format_context& ctx) const -> decltype(ctx.out());
};

View File

@@ -14,6 +14,11 @@
#include "db/schema_tables.hh"
#include "transport/messages/result_message.hh"
std::ostream& boost_test_print_type(std::ostream& os, const column_mapping& cm) {
fmt::print(os, "{}", cm);
return os;
}
SEASTAR_TEST_CASE(test_column_mapping_persistence) {
return do_with_cql_env_thread([] (cql_test_env& e) {
// Check that column mapping history is empty initially