summaryrefslogtreecommitdiff
path: root/unittest
diff options
context:
space:
mode:
authorAndrei Elkin <andrei.elkin@mariadb.com>2018-07-27 22:55:18 +0300
committerAndrei Elkin <andrei.elkin@mariadb.com>2019-01-24 20:44:50 +0200
commit5d48ea7d07b481ae3930486b4b039e1454273190 (patch)
tree86e9be451b867ad4f4df061c18d0546744e45ee0 /unittest
parentf9ac7032cbc4b7b9af9c8122e6ebfd91af9fbaf9 (diff)
downloadmariadb-git-5d48ea7d07b481ae3930486b4b039e1454273190.tar.gz
MDEV-10963 Fragmented BINLOG query
The problem was originally stated in http://bugs.mysql.com/bug.php?id=82212 The size of an base64-encoded Rows_log_event exceeds its vanilla byte representation in 4/3 times. When a binlogged event size is about 1GB mysqlbinlog generates a BINLOG query that can't be send out due to its size. It is fixed with fragmenting the BINLOG argument C-string into (approximate) halves when the base64 encoded event is over 1GB size. The mysqlbinlog in such case puts out SET @binlog_fragment_0='base64-encoded-fragment_0'; SET @binlog_fragment_1='base64-encoded-fragment_1'; BINLOG @binlog_fragment_0, @binlog_fragment_1; to represent a big BINLOG. For prompt memory release BINLOG handler is made to reset the BINLOG argument user variables in the middle of processing, as if @binlog_fragment_{0,1} = NULL is assigned. Notice the 2 fragments are enough, though the client and server still may need to tweak their @@max_allowed_packet to satisfy to the fragment size (which they would have to do anyway with greater number of fragments, should that be desired). On the lower level the following changes are made: Log_event::print_base64() remains to call encoder and store the encoded data into a cache but now *without* doing any formatting. The latter is left for time when the cache is copied to an output file (e.g mysqlbinlog output). No formatting behavior is also reflected by the change in the meaning of the last argument which specifies whether to cache the encoded data. Rows_log_event::print_helper() is made to invoke a specialized fragmented cache-to-file copying function which is copy_cache_to_file_wrapped() that takes care of fragmenting also optionally wraps encoded strings (fragments) into SQL stanzas. my_b_copy_to_file() is refactored to into my_b_copy_all_to_file(). The former function is generalized to accepts more a limit argument to constraint the copying and does not reinitialize anymore the cache into reading mode. The limit does not do any effect on the fully read cache.
Diffstat (limited to 'unittest')
-rw-r--r--unittest/sql/mf_iocache-t.cc70
1 files changed, 69 insertions, 1 deletions
diff --git a/unittest/sql/mf_iocache-t.cc b/unittest/sql/mf_iocache-t.cc
index 1eef8365074..fca5ec5014d 100644
--- a/unittest/sql/mf_iocache-t.cc
+++ b/unittest/sql/mf_iocache-t.cc
@@ -370,10 +370,77 @@ void mdev17133()
}
+void mdev10963()
+{
+ int res;
+ uint n_checks= 8;
+ uchar buf[1024 * 512];
+ uint n_frag= sizeof(buf)/(2 * CACHE_SIZE);
+ FILE *file;
+ myf my_flags= MYF(MY_WME);
+ const char *file_name="cache.log";
+
+ memset(buf, FILL, sizeof(buf));
+ diag("MDEV-10963 Fragmented BINLOG query");
+
+ init_io_cache_encryption();
+ srand((uint) time(NULL));
+
+ /* copying source */
+ res= open_cached_file(&info, 0, 0, CACHE_SIZE, 0);
+ ok(res == 0, "open_cached_file" INFO_TAIL);
+ res= my_b_write(&info, buf, sizeof(buf));
+
+ ulong total_size= my_b_tell(&info);
+ ok(res == 0 && total_size == sizeof(buf), "cache is written");
+
+ /* destination */
+ file= my_fopen(file_name, O_RDWR | O_TRUNC | O_CREAT, my_flags);
+ ok(my_fileno(file) > 0, "opened file fd = %d", my_fileno(file));
+
+ /*
+ For n_checks times verify a sequence of copying with random fragment
+ size ranging from zero to about the double of the cache read buffer size.
+ */
+ for (; n_checks; n_checks--, rewind(file))
+ {
+ // copied size is an estimate can be incremeneted to greater than total_size
+ ulong copied_size= 0;
+
+ res= reinit_io_cache(&info, READ_CACHE, 0L, FALSE, FALSE);
+ ok(res == 0, "cache turned to read");
+
+ for (ulong i= 0, curr_size= 0; i < n_frag; i++, copied_size += curr_size)
+ {
+ curr_size= rand() % (2 * (total_size - copied_size) / (n_frag - i));
+
+ DBUG_ASSERT(curr_size <= total_size - copied_size || i == n_frag - 1);
+
+ res= my_b_copy_to_file(&info, file, curr_size);
+ ok(res == 0, "%lu of the cache copied to file", curr_size);
+ }
+ /*
+ Regardless of total_size <> copied_size the function succeeds:
+ when total_size < copied_size the huge overflowed value of the last
+ argument is ignored because nothing already left uncopied in the cache.
+ */
+ res= my_b_copy_to_file(&info, file, total_size - copied_size);
+ ok(res == 0, "%lu of the cache copied to file", total_size - copied_size);
+ ok(my_ftell(file, my_flags) == sizeof(buf),
+ "file written in %d fragments", n_frag+1);
+
+ res= reinit_io_cache(&info, WRITE_CACHE, total_size, 0, 0);
+ ok(res == 0 && my_b_tell(&info) == sizeof(buf), "cache turned to write");
+ }
+ close_cached_file(&info);
+ my_fclose(file, my_flags);
+ my_delete(file_name, MYF(MY_WME));
+}
+
int main(int argc __attribute__((unused)),char *argv[])
{
MY_INIT(argv[0]);
- plan(114);
+ plan(277);
/* temp files with and without encryption */
encrypt_tmp_files= 1;
@@ -391,6 +458,7 @@ int main(int argc __attribute__((unused)),char *argv[])
mdev14014();
mdev17133();
+ mdev10963();
my_end(0);
return exit_status();