-
-
Notifications
You must be signed in to change notification settings - Fork 1.9k
MDEV-28302 Configurable DEFAULTs for CHANGE MASTER
#4430
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
These iterable tuples build towards refactoring Master & Relay Log info with DRY loops – their persistence for MDEV-37530, and possibly SHOW REPLICA STATUS and even CHANGE MASTER in the future.
Link `MasterInfoFile` & `RelayLogInfoFile` structs by making corresponding `Master_info` & `Relay_log_info` properties references to the fields. Properties are not moved for now due to the large number of changes. Also adjust usages affected by the addition of fields with `DEFAULT`s in preparation for MDEV-28302 “CHANGE MASTER TO …=DEFAULT”, except for persistence code that will be separately adjusted for MDEV-37362.
This commit finishes expanding MDEV-28302 (WIP)’s `DEFAULT`-capable, loop-based implementation of Master & Relay Log info file persistence. This conclusion realizes MDEV-37530’s goal. This involves moving – and improving, while here – the string and ID array parsers to `InfoFile::Persistent::load_from()` implementations. They and the other overrides supercede the `init_*var_from_file()` helpers and are will not overflow `int`s as reported by MDEV-38020. Also while here, fix MDEV-38010 “trailing garbage does not error”, as the MDEV-37530 refactors will disconnect them from the patch for prior versions. On the topic of transitioning to iterable fields interface, this commit also removes these functions: * `Domain_id_filter::init_ids()`: unused starting from this commit * `Domain_id_filter::store_ids(THD *)` & `prot_store_ids()`: unused since the Information Schema reimplemented SHOW REPLICA STATUS. This commit also has a few minor adjustments and fixes for the previous two commits.
I don’t mind highlighting them; but for records’ sake, TODO: squash
DEFAULTs for CHANGE MASTER
ParadoxV5
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Large projects come with large discussions, like power and responsibility.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would this .hh extension be suitable for distinguishing “single-header libraries” (and C++20 modules) from our traditional h-cc pairs?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We already have single-header libraries that still use the regular .h (e.g. sql_sort.h, was just the first I found). I think it is ok to keep just .h, otherwise we'd have differing conventions.
| /// Relay_Master_Log_File (of the event *group*) | ||
| StringField<> read_master_log_file; | ||
| /// Exec_Master_Log_Pos (of the event *group*) | ||
| IntField<my_off_t> read_master_log_pos; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If (hypothetically) we add the IO thread’s Relay Log position (i.e., Gtid_IO_Pos but for file-position mode) to CM/SSS, what would we name it?
|
|
||
|
|
||
| /// Persistence interface for an unspecified item | ||
| struct Persistent |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought about what CHANGE MASTER would look like as a table that supports SQL, such as SELECT and INSERT.
I decided that these new structs are alright, since a system table does not permit DDL (e.g., ALTER TABLE).
I am mainly concerned about an “unnecessary performance tax” for using a full-blown storage engine such as Aria, MyISAM or Memory, particularly their ACID compliance mechanisms.
Speaking of system tables, perhaps some of them can utilize a “system” storage engine, too, where storage is C++-first and DDL is not supported.
SHOW REPLICA STATUS could use a virtual method in this class, too; I am not sure.
After all, we still need to write out info files, at least on demand, if we support downgrades.
What’s the point of their forward compatibility, after all?
| /// }@ | ||
|
|
||
|
|
||
| struct MasterInfoFile: InfoFile |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Name conflict, I know.
But, Master_info & Relay_log_info also appear to contain runtime data for IO and SQL threads, respectively.
This inadequacy in organization makes maintenance difficult to know what belongs to whom, not to mention one of the 0b10 hardest problems in software development.
|
|
||
| if (init_intvar_from_file(&master_log_pos, &mi->file, 4) || | ||
| init_strvar_from_file(mi->host, sizeof(mi->host), &mi->file, 0) || | ||
| init_strvar_from_file(mi->user, sizeof(mi->user), &mi->file, "test") || |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Test Who?
| if (c == my_b_EOF) | ||
| return true; | ||
| buf[i]= c; | ||
| if (c == /* End of Count */ ' ' || c == /* End of Line */ '\n') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TODO: extend my_b_gets() to accept multiple delimiters
| ../sql/filesort_utils.cc ../sql/sql_digest.cc | ||
| ../sql/filesort.cc ../sql/grant.cc | ||
| ../sql/gstream.cc ../sql/slave.cc | ||
| ../sql/gstream.cc |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
when moving these functions to mysys, don't forget to remove slave.cc from libmysqld/CMakeLists.txt
⸺init_intvar_from_file()’s code documentation
| gtid_supported ? | ||
| enum_master_use_gtid::SLAVE_POS : enum_master_use_gtid::NO |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From the code, it looks like if the primary is before MariaDB 10 (back when GTIDs were not available), the replica sets its master_use_gtid to NO and remembers this as its new default for RESET REPLICA.
IMO, it would be nice if the replica would automatically default back to Slave_Pos if the connection changes to a MariaDB 10+ primary.
- Here, this “remember
NOas its newDEFAULT” does not override the option-configured default, since the primary’s version is not known until the replica (re)connects to it.
Should it? - Or, maybe we should silently fall back to
NOwithout affecting this config.- Currently, if the primary is MariaDB 10+,
RESET REPLICAalso warns about changingUsing_Gtid(sic) ifmaster_use_gtidisn’t alreadySlave_Pos.
- Currently, if the primary is MariaDB 10+,
- In fact, how old a MariaDB/MySQL version do we maintain the backward compatibility for anyway?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Look, @DaveGosselin-MariaDB, C++17!
| m_row.ssl_allowed= mi->master_ssl ? | ||
| #ifdef HAVE_OPENSSL | ||
| PS_SSL_ALLOWED_YES | ||
| #else | ||
| PS_SSL_ALLOWED_IGNORED | ||
| #endif | ||
| : PS_SSL_ALLOWED_NO; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The PerfSchema has its own copies of enum_rpl_yes_no, enum_ssl_allowed and enum_using_gtid, but with each value one more than the corresponding Master_info enum.
It could be that the enums in the PerfSchema storage engine start from 1 instead of 0.
What should we do about them?
Not to mention the rest of the Replica Status fields duplicated between the InfoSchema and the PerfSchema.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am gonna take a short break from this project.
Known issues with master_heartbeat_period in the draft so far
- It was reset not with RESET REPLICA but with CHANGE MASTER.
And now I removed this unintuitive CHANGE MASTER reset, but forgot to add it to RESET REPLICA. - MDEV-35879 Slave_heartbeat_period is imprecise:
I am getting4294967.040. (We might actually make this a blocker.)
| #ifdef __clang__ | ||
| // FIXME: floating-point variants of `std::from_chars()` not supported |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
According to this Stack Overflow answer, libc++ (Clang) doesn’t support floating-point variants of std::from_chars().
How did it pass our (relatively recent) C++17 requirement, then?
bnestere
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @ParadoxV5 !
I gave the patch a read-through. Not super in-depth b/c it is still a draft (thanks for the early publish!), but enough to get the idea, and I think it is good so far. I left some notes.
A general concern I have is that it is effectively un-loop-unrolling and adding in additional function calls, and I'd worry it would make MDEV-37684 worse. So I think we should run some benchmarks with this to make sure it isn't incurring any additional overhead.
| [C++20 modules](https://en.cppreference.com/w/cpp/language/modules.html) | ||
| can supercede headers and their `#include` guards. | ||
| */ | ||
| struct InfoFile |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The naming conventions don't follow the replication general pattern of Uppercase_lowercase_underscore_splits. We should try to be consistent.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Acknowledged.
Though, what do you mean by a replication general pattern? Are replication patterns diverted from the rest of the server?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, our official MariaDB guidelines say:
New types should be named in Capital_snake_case. You can consider using UPPER_SNAKE_CASE rarely, when consistency with old code base is stylistically important.
Older st_prefixed_snake_case should be never used in the new code.
But I've noticed other parts of the code sometimes have their own styles. The general rule is that new code in an existing file should follow the conventions already established in that file (so the file itself is consistent), and then new files should adhere to our official standards.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, our official MariaDB guidelines say:
Ah, CODING_STANDARDS.md.
I totally forgot about it with my first new classes for MariaDB 😅.
But I've noticed other parts of the code sometimes have their own styles.
Either them or that standard needs to explain the histories…
| #include "rpl_info_file.hh" | ||
| #include <unordered_map> // Type of @ref MasterInfoFile::FIELDS_MAP | ||
| #include <string_view> // Key type of @ref MasterInfoFile::FIELDS_MAP | ||
| #include <unordered_set> // Parameter type of ChangeMaster::set_defaults() //? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this needed? I only saw seen of that type, and I'm not certain is is effectively used anymore (perhaps it was needed in an earlier version?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Aye, that comment was a leftover from an earlier MDEV-28302 design that I expect to replace.
| bool load_from(IO_CACHE *file) override | ||
| { | ||
| buf[1]= false; // not default | ||
| return StringField<>::load_from(file); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This overwrites buf, yet you use buf to track "defaultness". That can make things hard to debug, I'd suggest to just have a variable to track default.
| calculated as an unsigned integer milliseconds field. | ||
| It has a `DEFAULT` value of @ref ::master_heartbeat_period, | ||
| which in turn has a `DEFAULT` value of `@@slave_net_timeout / 2` seconds. | ||
| */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Where you define the struct body of a variable at the same time as its declaration, it'd be good to make it clear in the comment what the following definition is before, so one doesn't have to go down a bunch of lines to find it (applies to everywhere you have this pattern).
| static constexpr const char END_MARKER[]= "END_MARKER"; | ||
| /// An iterable for the `key=value` section of `@@master_info_file` | ||
| // C++ default allocator to match that `mysql_execute_command()` uses `new` | ||
| inline static const std::unordered_map<std::string_view, mem_fn> FIELDS_MAP= { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why unordered? As the FIELDS_MAP is iterated over when saving the KV pairs, wouldn't that make it non-deterministic? The fields should be written in the same order as pre-MDEV-37530 so users can downgrade without breaking anything.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The pre-MDEV-37530 code checks keys, too, so the order is not important.
I can see that the predecessor who added this key-value section in the first place had order independence in mind.
(That code is a chain of if (got_eq && !seen_X && !strcmp(buf, "X")), however, which will look ridiculous under my (backward-compatible!) plan of stuffing the DEFAULT choices in that section, not to mention performance comparisons with hash lookups.)
| MariaDB 10.0 does not have the `END_MARKER` before any left-overs at | ||
| the end of the file, so ignore any non-first occurrences of a key. | ||
| */ | ||
| auto seen= std::unordered_set<const char *>(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is this used for? I see it is inserted into, but never used after that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
else if (seen.insert(key).second) // if no previous insertionThe second member of the return of std::unordered_set::insert(value_type&&) is true if and only if the set doesn’t already have the element.
I’ll expand the comment to describe this API.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah right, my blunder 🤦. Though with that said, we should prefer MariaDB data types (when available) to promote a standard way of doing things. Here, you should be able to just use HASH (and it should be used in the same way as sql_hset.h's Hash_set, though I'm not sure if you can just use Hash_set because you're just using const char *.).
And another question - do we need to track seen? Would it otherwise just overwrite the last value seen (where there shouldn't be duplicates anyway)? That's how config options in my.cnf work, and I'd think we can keep that same behavior.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here, you should be able to just use
HASH(and it should be used in the same way assql_hset.h'sHash_set, though I'm not sure if you can just useHash_setbecause you're just usingconst char *.).
Indeed, though I prefer the C++ standard library to roll fewer things of my own.
Here, I can use Hash_set, but I would either have to specify a charset (for comparing contents) or a comparator of (constant) pointers by their face values.
I am actually looking forward to a future where we use PSI_memory_key-configured C++ allocators with the best C++ standard library implementation.
Would it otherwise just overwrite the last value seen (where there shouldn't be duplicates anyway)? That's how config options in
my.cnfwork, and I'd think we can keep that same behavior.
I asked this question too.
The “code document” of seen is slightly edited from the comment at the corresponding section in rpl_mi.cc, which was:
10.0 does not have the END_MARKER before any left-overs at the end
of the file. So ignore any but the first occurrence of a key.
That is, a file from 10.0 could have two entries of a key by chance and intend the first to be the real one.
(Of course, you could also argue that 10.0 is long EOL, nobody should have them around, and we can get rid of code that holds those compatibilities together.)
| key[i]= c; | ||
| } | ||
| } | ||
| break_for:; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
labels shouldn't be indented
| /// }@ | ||
|
|
||
|
|
||
| inline static const std::initializer_list<mem_fn> FIELDS_LIST= { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can this be combined with FIELDS_MAP?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought about that once.
But nearly all of the MDEV-28302 fields are in the line-by-line section (FIELDS_LIST), and I want to write those fields both in this old-style section to preserve the defaulted values for downgrades, and in the key-value section to indicate the DEFAULT state.
The differences in the two sections encouraged me to simply “unwind this loop”.
Developing forward compatibility for a feature in older versions (where only the Enterprise Server receive features) sure is a task.
Description
An amazing description should answer some questions like:
1. MDEV-37530 Refactor Master & Relay Log info to iterable tuples
As this refactor will disconnect it from fixes for some open bugs in prior versions, this commit also:
Slave_heartbeat_periodis imprecisemaster_retry_count64-bit on LLP64 (e.g., Windows) to match LP64 (e.g., Linux)Release Notes
TODO: What should the release notes say about this change?
Include any changed system variables, status variables or behaviour. Optionally list any https://mariadb.com/kb/ pages that need changing.
How can this PR be tested?
TODO: modify the automated test suite to verify that the PR causes MariaDB to behave as intended.
Consult the documentation on "Writing good test cases".
If the changes are not amenable to automated testing, please explain why not and carefully describe how to test manually.
PR quality check
orand a refactoring, and the PR is based against themainbranch.This is a bug fix, and the PR is based against the earliest maintained branch in which the bug can be reproduced.