Re: [Maria-developers] ad6e7b87107: introduce cache flipping
Hi, Nikita! Interesting trick. On Nov 13, Nikita Malyavin wrote:
revision-id: ad6e7b87107 (mariadb-10.5.2-477-gad6e7b87107) parent(s): 85fbd867b4c author: Nikita Malyavin committer: Nikita Malyavin timestamp: 2021-01-27 14:17:39 +1000 message:
introduce cache flipping
Could you add few lines from the Cache_flip_event_log comment here too please?
diff --git a/sql/log.h b/sql/log.h index 74c409e1ac7..1e422ae4524 100644 --- a/sql/log.h +++ b/sql/log.h @@ -424,10 +424,9 @@ class Event_log: public MYSQL_LOG
bool open( const char *log_name, - enum_log_type log_type, const char *new_name, ulong next_file_number, enum cache_type io_cache_type_arg); - IO_CACHE *get_log_file() { return &log_file; } + virtual IO_CACHE *get_log_file() { return &log_file; }
int write_description_event(enum_binlog_checksum_alg checksum_alg, bool encrypt, bool dont_set_created); @@ -435,6 +434,73 @@ class Event_log: public MYSQL_LOG bool write_event(Log_event *ev, binlog_cache_data *data, IO_CACHE *file); };
+/** + A single-reader, multiple-writer non-blocking layer for Event_log. + Provides IO_CACHE for writing and IO_CACHE for reading.\ + + Writers use an overrided get_log_file version for their writes, while readers + should use flip() to initiate reading. + flip() swaps pointers to allow non-blocking reads. + + Writers can block other writers and a reader with a mutex, but a reader only + swaps two pointers under a lock, so it won't block writers. + + TODO should be unnecessary after MDEV-24676 is done + */ +class Cache_flip_event_log: public Event_log { + IO_CACHE alt_buf; + IO_CACHE *current, *alt; +public: + + Cache_flip_event_log() : Event_log(), alt_buf{}, + current(&log_file), alt(&alt_buf) {} + bool open(enum cache_type io_cache_type_arg) + { + log_file.dir= mysql_tmpdir; + alt_buf.dir= log_file.dir; + bool res= Event_log::open(NULL, NULL, 0, io_cache_type_arg); + if (res) + return res; + + name= my_strdup(key_memory_MYSQL_LOG_name, "online-alter-binlog", + MYF(MY_WME)); + if (!name) + return false; + + res= init_io_cache(&alt_buf, -1, LOG_BIN_IO_SIZE, io_cache_type_arg, 0, 0, + MYF(MY_WME | MY_NABP | MY_WAIT_IF_FULL)) != 0; + return res; + } + + /** + Swaps current and alt_log. Can be called only from the reader thread. + @return a new IO_CACHE pointer to read from. + */ + IO_CACHE *flip() + { + IO_CACHE *tmp= current; + reinit_io_cache(alt, WRITE_CACHE, 0, 0, 0); + mysql_mutex_lock(get_log_lock()); + reinit_io_cache(current, READ_CACHE, 0, 0, 0); + current= alt; + mysql_mutex_unlock(get_log_lock()); + alt= tmp; + + return alt; + } + + IO_CACHE *get_log_file() override + { + return current;
may be mysql_mutex_assert_owner(get_log_lock()) ?
+ } + + void cleanup() + { + end_io_cache(&alt_buf); + Event_log::cleanup(); + } +}; +
Regards, Sergei VP of MariaDB Server Engineering and security@mariadb.org
Sergei, On Sat, 13 Nov 2021 at 22:44, Sergei Golubchik <serg@mariadb.org> wrote:
Hi, Nikita!
Interesting trick.
That was you who proposed it! :D
On Nov 13, Nikita Malyavin wrote:
revision-id: ad6e7b87107 (mariadb-10.5.2-477-gad6e7b87107) parent(s): 85fbd867b4c author: Nikita Malyavin committer: Nikita Malyavin timestamp: 2021-01-27 14:17:39 +1000 message:
introduce cache flipping
Could you add few lines from the Cache_flip_event_log comment here too please?
Right, thanks for pointing out.
diff --git a/sql/log.h b/sql/log.h index 74c409e1ac7..1e422ae4524 100644 --- a/sql/log.h +++ b/sql/log.h @@ -424,10 +424,9 @@ class Event_log: public MYSQL_LOG
bool open( const char *log_name, - enum_log_type log_type, const char *new_name, ulong next_file_number, enum cache_type io_cache_type_arg); - IO_CACHE *get_log_file() { return &log_file; } + virtual IO_CACHE *get_log_file() { return &log_file; }
int write_description_event(enum_binlog_checksum_alg checksum_alg, bool encrypt, bool dont_set_created); @@ -435,6 +434,73 @@ class Event_log: public MYSQL_LOG bool write_event(Log_event *ev, binlog_cache_data *data, IO_CACHE *file); };
+/** + A single-reader, multiple-writer non-blocking layer for Event_log. + Provides IO_CACHE for writing and IO_CACHE for reading.\ + + Writers use an overrided get_log_file version for their writes, while readers + should use flip() to initiate reading. + flip() swaps pointers to allow non-blocking reads. + + Writers can block other writers and a reader with a mutex, but a reader only + swaps two pointers under a lock, so it won't block writers. + + TODO should be unnecessary after MDEV-24676 is done + */ +class Cache_flip_event_log: public Event_log { + IO_CACHE alt_buf; + IO_CACHE *current, *alt; +public: + + Cache_flip_event_log() : Event_log(), alt_buf{}, + current(&log_file), alt(&alt_buf) {} + bool open(enum cache_type io_cache_type_arg) + { + log_file.dir= mysql_tmpdir; + alt_buf.dir= log_file.dir; + bool res= Event_log::open(NULL, NULL, 0, io_cache_type_arg); + if (res) + return res; + + name= my_strdup(key_memory_MYSQL_LOG_name, "online-alter-binlog", + MYF(MY_WME)); + if (!name) + return false; + + res= init_io_cache(&alt_buf, -1, LOG_BIN_IO_SIZE, io_cache_type_arg, 0, 0, + MYF(MY_WME | MY_NABP | MY_WAIT_IF_FULL)) != 0; + return res; + } + + /** + Swaps current and alt_log. Can be called only from the reader thread. + @return a new IO_CACHE pointer to read from. + */ + IO_CACHE *flip() + { + IO_CACHE *tmp= current; + reinit_io_cache(alt, WRITE_CACHE, 0, 0, 0); + mysql_mutex_lock(get_log_lock()); + reinit_io_cache(current, READ_CACHE, 0, 0, 0); + current= alt; + mysql_mutex_unlock(get_log_lock()); + alt= tmp; + + return alt; + } + + IO_CACHE *get_log_file() override + { + return current;
may be mysql_mutex_assert_owner(get_log_lock()) ?
Good point! Seems so.
+ } + + void cleanup() + { + end_io_cache(&alt_buf); + Event_log::cleanup(); + } +}; +
Regards, Sergei VP of MariaDB Server Engineering and security@mariadb.org
-- Yours truly, Nikita Malyavin
participants (2)
-
Nikita Malyavin
-
Sergei Golubchik