Merge pull request #39974 from ClickHouse/vdimir/setting-num-with-auto

Add setting type to support special 'auto' value
This commit is contained in:
Vladimir C 2022-08-11 14:25:10 +02:00 committed by GitHub
commit 1b44cb5c97
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 95 additions and 6 deletions

View File

@ -212,7 +212,7 @@ static constexpr UInt64 operator""_GiB(unsigned long long value)
\
M(Bool, insert_deduplicate, true, "For INSERT queries in the replicated table, specifies that deduplication of insertings blocks should be performed", 0) \
\
M(UInt64, insert_quorum, 0, "For INSERT queries in the replicated table, wait writing for the specified number of replicas and linearize the addition of the data. 0 - disabled.", 0) \
M(UInt64Auto, insert_quorum, 0, "For INSERT queries in the replicated table, wait writing for the specified number of replicas and linearize the addition of the data. 0 - disabled.", 0) \
M(Milliseconds, insert_quorum_timeout, 600000, "", 0) \
M(Bool, insert_quorum_parallel, true, "For quorum INSERT queries - enable to make parallel inserts without linearizability", 0) \
M(UInt64, select_sequential_consistency, 0, "For SELECT queries from the replicated table, throw an exception if the replica does not have a chunk written with the quorum; do not read the parts that have not yet been written with the quorum.", 0) \

View File

@ -153,6 +153,9 @@ template struct SettingFieldNumber<Int64>;
template struct SettingFieldNumber<float>;
template struct SettingFieldNumber<bool>;
template struct SettingAutoWrapper<SettingFieldNumber<UInt64>>;
template struct SettingAutoWrapper<SettingFieldNumber<Int64>>;
template struct SettingAutoWrapper<SettingFieldNumber<float>>;
namespace
{

View File

@ -58,11 +58,82 @@ using SettingFieldInt64 = SettingFieldNumber<Int64>;
using SettingFieldFloat = SettingFieldNumber<float>;
using SettingFieldBool = SettingFieldNumber<bool>;
/** Unlike SettingFieldUInt64, supports the value of 'auto' - the number of processor cores without taking into account SMT.
* A value of 0 is also treated as auto.
* When serializing, `auto` is written in the same way as 0.
/** Wraps any SettingField to support special value 'auto' that can be checked with `is_auto` flag.
* Note about serialization:
* The new versions with `SettingsWriteFormat::STRINGS_WITH_FLAGS` serialize values as a string.
* In legacy SettingsWriteFormat mode, functions `read/writeBinary` would serialize values as a binary, and 'is_auto' would be ignored.
* It's possible to upgrade settings from regular type to wrapped ones and keep compatibility with old versions,
* but when serializing 'auto' old version will see binary representation of the default value.
*/
template <typename Base>
struct SettingAutoWrapper
{
constexpr static auto keyword = "auto";
static bool isAuto(const Field & f) { return f.getType() == Field::Types::String && f.safeGet<const String &>() == keyword; }
static bool isAuto(const String & str) { return str == keyword; }
using Type = typename Base::Type;
Base base;
bool is_auto = false;
bool changed = false;
explicit SettingAutoWrapper() : is_auto(true) {}
explicit SettingAutoWrapper(Type val) : is_auto(false) { base = Base(val); }
explicit SettingAutoWrapper(const Field & f)
: is_auto(isAuto(f))
{
if (!is_auto)
base = Base(f);
}
SettingAutoWrapper & operator=(const Field & f)
{
changed = true;
if (is_auto = isAuto(f); !is_auto)
base = f;
return *this;
}
explicit operator Field() const { return is_auto ? Field(keyword) : Field(base); }
String toString() const { return is_auto ? keyword : base.toString(); }
void parseFromString(const String & str)
{
changed = true;
if (is_auto = isAuto(str); !is_auto)
base.parseFromString(str);
}
void writeBinary(WriteBuffer & out) const
{
if (is_auto)
Base().writeBinary(out); /// serialize default value
else
base.writeBinary(out);
}
/*
* That it is fine to reset `is_auto` here and to use default value in case `is_auto`
* because settings will be serialized only if changed.
* If they were changed they were requested to use explicit value instead of `auto`.
* And so interactions between client-server, and server-server (distributed queries), should be OK.
*/
void readBinary(ReadBuffer & in) { changed = true; is_auto = false; base.readBinary(in); }
Type valueOr(Type default_value) const { return is_auto ? default_value : base.value; }
};
using SettingFieldUInt64Auto = SettingAutoWrapper<SettingFieldUInt64>;
using SettingFieldInt64Auto = SettingAutoWrapper<SettingFieldInt64>;
using SettingFieldFloatAuto = SettingAutoWrapper<SettingFieldFloat>;
/* Similar to SettingFieldUInt64Auto with small differences to behave like regular UInt64, supported to compatibility.
* When setting to 'auto' it becomes equal to the number of processor cores without taking into account SMT.
* A value of 0 is also treated as 'auto', so 'auto' is parsed and serialized in the same way as 0.
*/
struct SettingFieldMaxThreads
{
bool is_auto;

View File

@ -4443,8 +4443,9 @@ SinkToStoragePtr StorageReplicatedMergeTree::write(const ASTPtr & /*query*/, con
bool deduplicate = storage_settings_ptr->replicated_deduplication_window != 0 && query_settings.insert_deduplicate;
// TODO: should we also somehow pass list of columns to deduplicate on to the ReplicatedMergeTreeSink?
// TODO: insert_quorum = 'auto' would be supported in https://github.com/ClickHouse/ClickHouse/pull/39970, now it's same as 0.
return std::make_shared<ReplicatedMergeTreeSink>(
*this, metadata_snapshot, query_settings.insert_quorum,
*this, metadata_snapshot, query_settings.insert_quorum.valueOr(0),
query_settings.insert_quorum_timeout.totalMilliseconds(),
query_settings.max_partitions_per_insert_block,
query_settings.insert_quorum_parallel,

View File

@ -0,0 +1,4 @@
0 0 UInt64Auto
auto 1 UInt64Auto
0 1 UInt64Auto
1 1 UInt64Auto

View File

@ -0,0 +1,10 @@
SELECT value, changed, type FROM system.settings WHERE name = 'insert_quorum';
SET insert_quorum = 'auto';
SELECT value, changed, type FROM system.settings WHERE name = 'insert_quorum';
SET insert_quorum = 0;
SELECT value, changed, type FROM system.settings WHERE name = 'insert_quorum';
SET insert_quorum = 1;
SELECT value, changed, type FROM system.settings WHERE name = 'insert_quorum';