MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
rpl_group_set-t.cc
1 /* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
2 
3  This program is free software; you can redistribute it and/or modify
4  it under the terms of the GNU General Public License as published by
5  the Free Software Foundation; version 2 of the License.
6 
7  This program is distributed in the hope that it will be useful,
8  but WITHOUT ANY WARRANTY; without even the implied warranty of
9  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  GNU General Public License for more details.
11 
12  You should have received a copy of the GNU General Public License
13  along with this program; if not, write to the Free Software Foundation,
14  51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
15 
16 
17 #include <gtest/gtest.h>
18 #include <string.h>
19 
20 #define FRIEND_OF_GTID_SET class GroupTest_Group_containers_Test
21 #define FRIEND_OF_GROUP_CACHE class GroupTest_Group_containers_Test
22 #define FRIEND_OF_GROUP_LOG_STATE class GroupTest_Group_containers_Test
23 #define NON_DISABLED_UNITTEST_GTID
24 
25 #include "sql_class.h"
26 #include "my_pthread.h"
27 #include "binlog.h"
28 #include "rpl_gtid.h"
29 
30 #define N_SIDS 16
31 
32 #define ASSERT_OK(X) ASSERT_EQ(RETURN_STATUS_OK, X)
33 #define EXPECT_OK(X) EXPECT_EQ(RETURN_STATUS_OK, X)
34 #define EXPECT_NOK(X) EXPECT_NE(RETURN_STATUS_OK, X)
35 
36 
37 class GroupTest : public ::testing::Test
38 {
39 public:
40  static const char *uuids[16];
41  rpl_sid sids[16];
42  unsigned int seed;
43 
44 
45  void SetUp()
46  {
47  seed= (unsigned int)time(NULL);
48  printf("# seed = %u\n", seed);
49  srand(seed);
50  for (int i= 0; i < 16; i++)
51  sids[i].parse(uuids[i]);
52 
53  verbose= false;
54  errtext_stack_pos= 0;
55  errtext_stack[0]= 0;
56  append_errtext(__LINE__, "seed=%d", seed);
57  my_delete("sid-map-0", MYF(0));
58  my_delete("sid-map-1", MYF(0));
59  my_delete("sid-map-2", MYF(0));
60  }
61 
62 
63  void TearDown()
64  {
65  my_delete("sid-map-0", MYF(0));
66  my_delete("sid-map-1", MYF(0));
67  my_delete("sid-map-2", MYF(0));
68  }
69 
70 
71  /*
72  Test that different, equivalent ways to construct a Gtid_set give
73  the same resulting Gtid_set. This is used to test Gtid_set,
74  Sid_map, Group_cache, Group_log_state, and Owned_groups.
75 
76  We will generate sets of groups in *stages*. Each stage is
77  divided into a number of *sub-stages* (the number of substages is
78  taken uniformly at random from the set 1, 2, ..., 200). In each
79  sub-stage, we randomly sample one sub-group from a fixed set of
80  groups. The fixed set of groups consists of groups from 16
81  different SIDs. For the Nth SID (1 <= N <= 16), the fixed set of
82  groups contains all GNOS from the closed interval [N, N - 1 + N *
83  N]. The stage consists of the set of groups from all the
84  sub-stages.
85  */
86 
87  #define BEGIN_SUBSTAGE_LOOP(group_test, stage, do_errtext) \
88  (group_test)->push_errtext(); \
89  for (int substage_i= 0; substage_i < (stage)->n_substages; substage_i++) { \
90  Substage &substage= (stage)->substages[substage_i]; \
91  if (do_errtext) \
92  (group_test)->append_errtext(__LINE__, \
93  "sidno=%d group=%s substage_i=%d", \
94  substage.sidno, substage.gtid_str, \
95  substage_i);
96  #define END_SUBSTAGE_LOOP(group_test) } group_test->pop_errtext()
97 
101  struct Substage
102  {
103  rpl_sidno sidno;
104  rpl_gno gno;
105  const rpl_sid *sid;
106  char sid_str[rpl_sid::TEXT_LENGTH + 1];
107  char gtid_str[rpl_sid::TEXT_LENGTH + 1 + MAX_GNO_TEXT_LENGTH + 1];
108  bool is_first, is_last, is_auto;
109 #ifndef NO_DBUG
110  void print() const
111  {
112  printf("%d/%s [first=%d last=%d auto=%d]",
113  sidno, gtid_str, is_first, is_last, is_auto);
114  }
115 #endif
116  };
117 
121  struct Stage
122  {
123  class GroupTest *group_test;
124  Sid_map *sid_map;
125 
126  // List of groups added in the present stage.
127  static const int MAX_SUBSTAGES= 200;
128  Substage substages[MAX_SUBSTAGES];
129  int n_substages;
130 
131  // Set of groups added in the present stage.
132  Gtid_set set;
133  int str_len;
134  char *str;
135 
136  // The subset of groups that can be added as automatic groups.
137  Gtid_set automatic_groups;
138  // The subset of groups that cannot be added as automatic groups.
139  Gtid_set non_automatic_groups;
140 
141  Stage(class GroupTest *gt, Sid_map *sm)
142  : group_test(gt), sid_map(sm),
143  set(sm), str_len(0), str(NULL),
144  automatic_groups(sm), non_automatic_groups(sm)
145  { init(sm); }
146 
147 
148  void init(Sid_map *sm)
149  {
150  rpl_sidno max_sidno= sm->get_max_sidno();
151  ASSERT_OK(set.ensure_sidno(max_sidno));
152  ASSERT_OK(automatic_groups.ensure_sidno(max_sidno));
153  ASSERT_OK(non_automatic_groups.ensure_sidno(max_sidno));
154  }
155 
156  ~Stage() { free(str); }
157 
158  void print() const
159  {
160  printf("%d substages = {\n", n_substages);
161  for (int i= 0; i < n_substages; i++)
162  {
163  printf(" substage[%d]: ", i);
164  substages[i].print();
165  printf("\n");
166  }
167  printf("\n");
168  }
169 
177  void new_stage(const Gtid_set *done_groups, Sid_map *other_sm)
178  {
179  set.clear();
180  automatic_groups.clear();
181  non_automatic_groups.clear();
182 
183  n_substages= 1 + (rand() % MAX_SUBSTAGES);
184  BEGIN_SUBSTAGE_LOOP(group_test, this, false)
185  {
186  // generate random GTID
187  substage.sidno= 1 + (rand() % N_SIDS);
188  substage.gno=
189  1 + (rand() % (substage.sidno * substage.sidno));
190  // compute alternative forms
191  substage.sid= sid_map->sidno_to_sid(substage.sidno);
192  ASSERT_NE((rpl_sid *)NULL, substage.sid) << group_test->errtext;
193  substage.sid->to_string(substage.sid_str);
194  substage.sid->to_string(substage.gtid_str);
195  substage.gtid_str[rpl_sid::TEXT_LENGTH]= ':';
196  format_gno(substage.gtid_str + rpl_sid::TEXT_LENGTH + 1, substage.gno);
197 
198  ASSERT_LE(1, other_sm->add_permanent(substage.sid))
199  << group_test->errtext;
200 
201  // check if this group could be added as an 'automatic' group
202  Gtid_set::Const_interval_iterator ivit(done_groups, substage.sidno);
203  const Gtid_set::Interval *iv= ivit.get();
204  substage.is_auto=
205  !set.contains_group(substage.sidno, substage.gno) &&
206  ((iv == NULL || iv->start > 1) ? substage.gno == 1 :
207  substage.gno == iv->end);
208 
209  // check if this sub-group is the first in its group in this
210  // stage, and add it to the set
211  substage.is_first= !set.contains_group(substage.sidno, substage.gno);
212  if (substage.is_first)
213  ASSERT_OK(set.add(substage.gtid_str));
214  } END_SUBSTAGE_LOOP(group_test);
215 
216  // Iterate backwards so that we can detect when a subgroup is
217  // the last subgroup of its group.
218  set.clear();
219  for (int substage_i= n_substages - 1; substage_i >= 0; substage_i--)
220  {
221  Substage &substage= substages[substage_i];
222  substage.is_last= !set.contains_group(substage.sidno, substage.gno);
223  if (substage.is_last)
224  ASSERT_OK(set.add(substage.gtid_str));
225  }
226 
227  str_len= set.get_string_length();
228  str= (char *)realloc(str, str_len + 1);
229  set.to_string(str);
230  }
231  };
232 
233 
234  /*
235  We maintain a text that contains the state of the test. We print
236  this text when a test assertion fails. The text is updated each
237  iteration of each loop, so that we can easier track the exact
238  point in time when an error occurs. Since loops may be nested, we
239  maintain a stack of offsets in the error text: before a new loop
240  is entered, the position of the end of the string is pushed to the
241  stack and the text appended in each iteration is added to that
242  position.
243  */
244  char errtext[1000];
245  int errtext_stack[100];
246  int errtext_stack_pos;
247  bool verbose;
248 
249  void append_errtext(int line, const char *fmt, ...) ATTRIBUTE_FORMAT(printf, 3, 4)
250  {
251  va_list argp;
252  va_start(argp, fmt);
253  vsprintf(errtext + errtext_stack[errtext_stack_pos], fmt, argp);
254  if (verbose)
255  printf("@line %d: %s\n", line, errtext);
256  va_end(argp);
257  }
258 
259  void push_errtext()
260  {
261  int old_len= errtext_stack[errtext_stack_pos];
262  int len= old_len + strlen(errtext + old_len);
263  strcpy(errtext + len, " | ");
264  errtext_stack[++errtext_stack_pos]= len + 3;
265  }
266 
267  void pop_errtext()
268  {
269  errtext[errtext_stack[errtext_stack_pos--] - 3]= 0;
270  }
271 
272 
273  void group_subset(Gtid_set *sub, Gtid_set *super, bool outcome,
274  int line, const char *desc)
275  {
276  append_errtext(line, "%s", desc);
277  // check using is_subset
278  EXPECT_EQ(outcome, sub->is_subset(super)) << errtext;
279  // check using set subtraction
280  enum_return_status status;
281  Gtid_set sub_minus_super(sub, &status);
282  ASSERT_OK(status) << errtext;
283  ASSERT_OK(sub_minus_super.remove(super)) << errtext;
284  ASSERT_EQ(outcome, sub_minus_super.is_empty()) << errtext;
285  }
286 
287 };
288 
289 
290 const char *GroupTest::uuids[16]=
291 {
292  "00000000-0000-0000-0000-000000000000",
293  "11111111-1111-1111-1111-111111111111",
294  "22222222-2222-2222-2222-222222222222",
295  "33333333-3333-3333-3333-333333333333",
296  "44444444-4444-4444-4444-444444444444",
297  "55555555-5555-5555-5555-555555555555",
298  "66666666-6666-6666-6666-666666666666",
299  "77777777-7777-7777-7777-777777777777",
300  "88888888-8888-8888-8888-888888888888",
301  "99999999-9999-9999-9999-999999999999",
302  "aaaaAAAA-aaaa-AAAA-aaaa-aAaAaAaAaaaa",
303  "bbbbBBBB-bbbb-BBBB-bbbb-bBbBbBbBbbbb",
304  "ccccCCCC-cccc-CCCC-cccc-cCcCcCcCcccc",
305  "ddddDDDD-dddd-DDDD-dddd-dDdDdDdDdddd",
306  "eeeeEEEE-eeee-EEEE-eeee-eEeEeEeEeeee",
307  "ffffFFFF-ffff-FFFF-ffff-fFfFfFfFffff",
308 };
309 
310 
311 TEST_F(GroupTest, Uuid)
312 {
313  Uuid u;
314  char buf[100];
315 
316  // check that we get back the same UUID after parse + print
317  for (int i= 0; i < N_SIDS; i++)
318  {
319  EXPECT_OK(u.parse(uuids[i])) << "i=" << i;
320  u.to_string(buf);
321  EXPECT_STRCASEEQ(uuids[i], buf) << "i=" << i;
322  }
323  // check error cases
324  EXPECT_OK(u.parse("ffffFFFF-ffff-FFFF-ffff-ffffffffFFFFf"));
325  EXPECT_NOK(u.parse("ffffFFFF-ffff-FFFF-ffff-ffffffffFFFg"));
326  EXPECT_NOK(u.parse("ffffFFFF-ffff-FFFF-ffff-ffffffffFFF"));
327  EXPECT_NOK(u.parse("ffffFFFF-ffff-FFFF-fff-fffffffffFFFF"));
328  EXPECT_NOK(u.parse("ffffFFFF-ffff-FFFF-ffff-ffffffffFFF-"));
329  EXPECT_NOK(u.parse(" ffffFFFF-ffff-FFFF-ffff-ffffffffFFFF"));
330  EXPECT_NOK(u.parse("ffffFFFFfffff-FFFF-ffff-ffffffffFFFF"));
331 }
332 
333 
334 TEST_F(GroupTest, Sid_map)
335 {
336  Checkable_rwlock lock;
337  Sid_map sm(&lock);
338 
339  lock.rdlock();
340  ASSERT_OK(sm.open("sid-map-0"));
341 
342  // Add a random SID until we have N_SID SIDs in the map.
343  while (sm.get_max_sidno() < N_SIDS)
344  ASSERT_LE(1, sm.add_permanent(&sids[rand() % N_SIDS])) << errtext;
345 
346  // Check that all N_SID SIDs are in the map, and that
347  // get_sorted_sidno() has the correct order. This implies that no
348  // SID was added twice.
349  for (int i= 0; i < N_SIDS; i++)
350  {
351  rpl_sidno sidno= sm.get_sorted_sidno(i);
352  const rpl_sid *sid;
353  char buf[100];
354  EXPECT_NE((rpl_sid *)NULL, sid= sm.sidno_to_sid(sidno)) << errtext;
355  const int max_len= Uuid::TEXT_LENGTH;
356  EXPECT_EQ(max_len, sid->to_string(buf)) << errtext;
357  EXPECT_STRCASEEQ(uuids[i], buf) << errtext;
358  EXPECT_EQ(sidno, sm.sid_to_sidno(sid)) << errtext;
359  }
360  lock.unlock();
361  lock.assert_no_lock();
362 }
363 
364 
365 TEST_F(GroupTest, Group_containers)
366 {
367  /*
368  In this test, we maintain 298 Gtid_sets. We add groups to these
369  Gtid_sets in stages, as described above. We add the groups to
370  each of the 298 Gtid_sets in different ways, as described below.
371  At the end of each stage, we check that all the 298 resulting
372  Gtid_sets are mutually equal.
373 
374  We add groups in the two ways:
375 
376  A. Test Gtid_sets and Sid_maps. We vary two parameters:
377 
378  Parameter 1: vary the way that groups are added:
379  0. Add one group at a time, using add(sidno, gno).
380  1. Add one group at a time, using add(text).
381  2. Add all new groups at once, using add(gs_new).
382  3. add all new groups at once, using add(gs_new.to_string()).
383  4. Maintain a string that contains the concatenation of all
384  gs_new.to_string(). in each stage, we set gs[4] to a new
385  Gtid_set created from this string.
386 
387  Parameter 2: vary the Sid_map object:
388  0. Use a Sid_map that has all the SIDs in order.
389  1. Use a Sid_map where SIDs are added in the order they appear.
390 
391  We vary these parameters in all combinations; thus we construct
392  10 Gtid_sets.
393  */
394  enum enum_sets_method {
395  METHOD_SIDNO_GNO= 0, METHOD_GROUP_TEXT,
396  METHOD_GTID_SET, METHOD_GTID_SET_TEXT, METHOD_ALL_TEXTS_CONCATENATED,
397  MAX_METHOD
398  };
399  enum enum_sets_sid_map {
400  SID_MAP_0= 0, SID_MAP_1, MAX_SID_MAP
401  };
402  const int N_COMBINATIONS_SETS= MAX_METHOD * MAX_SID_MAP;
403  /*
404  B. Test Group_cache, Group_log_state, and Owned_groups. All
405  sub-groups for the stage are added to the Group_cache, the
406  Group_cache is flushed to the Group_log_state, and the
407  Gtid_set is extracted from the Group_log_state. We vary the
408  following parameters.
409 
410  Parameter 1: type of statement:
411  0. Transactional replayed statement: add all groups to the
412  transaction group cache (which is flushed to a
413  Group_log_state at the end of the stage). Set
414  GTID_NEXT_LIST to the list of all groups in the stage.
415  1. Non-transactional replayed statement: add all groups to the
416  stmt group cache (which is flushed to the Group_log_state
417  at the end of each sub-stage). Set GTID_NEXT_LIST = NULL.
418  2. Randomize: for each sub-stage, choose 0 or 1 with 50%
419  chance. Set GTID_NEXT_LIST to the list of all groups in
420  the stage.
421  3. Automatic groups: add all groups to the stmt group cache,
422  but make the group automatic if possible, i.e., if the SID
423  and GNO are unlogged and there is no smaller unlogged GNO
424  for this SID. Set GTID_NEXT_LIST = NULL.
425 
426  Parameter 2: ended or non-ended sub-groups:
427  0. All sub-groups are unended (except automatic sub-groups).
428  1. For each group, the last sub-group of the group in the
429  stage is ended. Don't add groups that are already ended in the
430  Group_log_state.
431  2. For each group in the stage, choose 0 or 1 with 50% chance.
432 
433  Parameter 3: empty or normal sub-group:
434  0. Generate only normal (and possibly automatic) sub-groups.
435  1. Generate only empty (and possibly automatic) sub-groups.
436  2. Generate only empty (and possibly automatic) sub-groups.
437  Add the sub-groups implicitly: do not call
438  add_empty_subgroup(); instead rely on
439  gtid_before_flush_trx_cache() to add empty subgroups.
440  3. Choose 0 or 1 with 33% chance.
441 
442  Parameter 4: insert anonymous sub-groups or not:
443  0. Do not generate anonymous sub-groups.
444  1. Generate an anomous sub-group before each sub-group with
445  50% chance and an anonymous group after each sub-group with
446  50% chance.
447 
448  We vary these parameters in all combinations; thus we construct
449  4*3*4*2=96 Gtid_sets.
450  */
451  enum enum_caches_type
452  {
453  TYPE_TRX= 0, TYPE_NONTRX, TYPE_RANDOMIZE, TYPE_AUTO, MAX_TYPE
454  };
455  enum enum_caches_end
456  {
457  END_OFF= 0, END_ON, END_RANDOMIZE, MAX_END
458  };
459  enum enum_caches_empty
460  {
461  EMPTY_OFF= 0, EMPTY_ON, EMPTY_IMPLICIT, EMPTY_RANDOMIZE, MAX_EMPTY
462  };
463  enum enum_caches_anon {
464  ANON_OFF= 0, ANON_ON, MAX_ANON
465  };
466  const int N_COMBINATIONS_CACHES=
467  MAX_TYPE * MAX_END * MAX_EMPTY * MAX_ANON;
468  const int N_COMBINATIONS= N_COMBINATIONS_SETS + N_COMBINATIONS_CACHES;
469 
470  // Auxiliary macros to loop through all combinations of parameters.
471 #define BEGIN_LOOP_A \
472  push_errtext(); \
473  for (int method_i= 0, combination_i= 0; method_i < MAX_METHOD; method_i++) { \
474  for (int sid_map_i= 0; sid_map_i < MAX_SID_MAP; sid_map_i++, combination_i++) { \
475  Gtid_set &gtid_set __attribute__((unused))= \
476  containers[combination_i]->gtid_set; \
477  Sid_map *&sid_map __attribute__((unused))= \
478  sid_maps[sid_map_i]; \
479  append_errtext(__LINE__, \
480  "sid_map_i=%d method_i=%d combination_i=%d", \
481  sid_map_i, method_i, combination_i);
482 
483 #define END_LOOP_A } } pop_errtext()
484 
485 #define BEGIN_LOOP_B \
486  push_errtext(); \
487  for (int type_i= 0, combination_i= N_COMBINATIONS_SETS; \
488  type_i < MAX_TYPE; type_i++) { \
489  for (int end_i= 0; end_i < MAX_END; end_i++) { \
490  for (int empty_i= 0; empty_i < MAX_EMPTY; empty_i++) { \
491  for (int anon_i= 0; anon_i < MAX_ANON; anon_i++, combination_i++) { \
492  Gtid_set &gtid_set __attribute__((unused))= \
493  containers[combination_i]->gtid_set; \
494  Group_cache &stmt_cache __attribute__((unused))= \
495  containers[combination_i]->stmt_cache; \
496  Group_cache &trx_cache __attribute__((unused))= \
497  containers[combination_i]->trx_cache; \
498  Group_log_state &group_log_state __attribute__((unused))= \
499  containers[combination_i]->group_log_state; \
500  append_errtext(__LINE__, \
501  "type_i=%d end_i=%d empty_i=%d " \
502  "anon_i=%d combination_i=%d", \
503  type_i, end_i, empty_i, \
504  anon_i, combination_i); \
505  //verbose= (combination_i == 108); /*todo*/
506 
507 #define END_LOOP_B } } } } pop_errtext()
508 
509  // Do not generate warnings (because that causes segfault when done
510  // from a unittest).
511  global_system_variables.log_warnings= 0;
512 
513  mysql_bin_log.server_uuid_sidno= 1;
514 
515  // Create Sid_maps.
516  Checkable_rwlock &lock= mysql_bin_log.sid_lock;
517  Sid_map **sid_maps= new Sid_map*[2];
518  sid_maps[0]= &mysql_bin_log.sid_map;
519  sid_maps[1]= new Sid_map(&lock);
520 
521  lock.rdlock();
522  ASSERT_OK(sid_maps[0]->open("sid-map-1"));
523  ASSERT_OK(sid_maps[1]->open("sid-map-2"));
524  /*
525  Make sid_maps[0] and sid_maps[1] different: sid_maps[0] is
526  generated in order; sid_maps[1] is generated in the order that
527  SIDS are inserted in the Gtid_set.
528  */
529  for (int i= 0; i < N_SIDS; i++)
530  ASSERT_LE(1, sid_maps[0]->add_permanent(&sids[i])) << errtext;
531 
532  // Create list of container objects. These are the objects that we
533  // test.
534  struct Containers
535  {
536  Gtid_set gtid_set;
537  Group_cache stmt_cache;
538  Group_cache trx_cache;
539  Group_log_state group_log_state;
540  Containers(Checkable_rwlock *lock, Sid_map *sm)
541  : gtid_set(sm), group_log_state(lock, sm)
542  { init(); }
543  void init() { ASSERT_OK(group_log_state.ensure_sidno()); };
544  };
545  Containers **containers= new Containers*[N_COMBINATIONS];
546  BEGIN_LOOP_A
547  {
548  containers[combination_i]= new Containers(&lock, sid_map);
549  } END_LOOP_A;
550  BEGIN_LOOP_B
551  {
552  containers[combination_i] = new Containers(&lock, sid_maps[0]);
553  } END_LOOP_B;
554 
555  /*
556  Construct a Gtid_set that contains the set of all groups from
557  which we sample.
558  */
559  static char all_groups_str[100*100];
560  char *s= all_groups_str;
561  s += sprintf(s, "%s:1", uuids[0]);
562  for (rpl_sidno sidno= 2; sidno <= N_SIDS; sidno++)
563  s += sprintf(s, ",\n%s:1-%d", uuids[sidno - 1], sidno * sidno);
564  enum_return_status status;
565  Gtid_set all_groups(sid_maps[0], all_groups_str, &status);
566  ASSERT_OK(status) << errtext;
567 
568  // The set of groups that were added in some previous stage.
569  Gtid_set done_groups(sid_maps[0]);
570  ASSERT_OK(done_groups.ensure_sidno(sid_maps[0]->get_max_sidno()));
571 
572  /*
573  Iterate through stages. In each stage, create the "stage group
574  set" by generating up to 200 subgroups. Add this stage group set
575  to each of the group sets in different ways. Stop when the union
576  of all stage group sets is equal to the full set from which we
577  took the samples.
578  */
579  char *done_str= NULL;
580  int done_str_len= 0;
581  Stage stage(this, sid_maps[0]);
582  int stage_i= 0;
583 
584  /*
585  We need a THD object only to read THD::variables.gtid_next,
586  THD::variables.gtid_end, THD::variables.gtid_next_list,
587  THD::thread_id, THD::server_status. We don't want to invoke the
588  THD constructor because that would require setting up mutexes,
589  etc. Hence we use malloc instead of new.
590  */
591  THD *thd= (THD *)malloc(sizeof(THD));
592  ASSERT_NE((THD *)NULL, thd) << errtext;
593  Gtid_specification *gtid_next= &thd->variables.gtid_next;
594  thd->thread_id= 4711;
595  gtid_next->type= Gtid_specification::AUTOMATIC;
596  my_bool &gtid_end= thd->variables.gtid_end;
597  my_bool &gtid_commit= thd->variables.gtid_commit;
598  thd->server_status= 0;
599  thd->system_thread= NON_SYSTEM_THREAD;
600  thd->variables.gtid_next_list.gtid_set= &stage.set;
601 
602  push_errtext();
603  while (!all_groups.equals(&done_groups))
604  {
605  stage_i++;
606  append_errtext(__LINE__, "stage_i=%d", stage_i);
607  stage.new_stage(&done_groups, sid_maps[1]);
608 
609  if (verbose)
610  {
611  printf("======== stage %d ========\n", stage_i);
612  stage.print();
613  }
614 
615  // Create a string that contains all previous stage.str,
616  // concatenated.
617  done_str= (char *)realloc(done_str,
618  done_str_len + 1 + stage.str_len + 1);
619  ASSERT_NE((char *)NULL, done_str) << errtext;
620  done_str_len += sprintf(done_str + done_str_len, ",%s", stage.str);
621 
622  // Add groups to Gtid_sets.
623  BEGIN_LOOP_A
624  {
625  switch (method_i)
626  {
627  case METHOD_SIDNO_GNO:
628  BEGIN_SUBSTAGE_LOOP(this, &stage, true)
629  {
630  rpl_sidno sidno_1= sid_map->sid_to_sidno(substage.sid);
631  ASSERT_LE(1, sidno_1) << errtext;
632  ASSERT_OK(gtid_set.ensure_sidno(sidno_1));
633  ASSERT_OK(gtid_set._add(sidno_1, substage.gno));
634  } END_SUBSTAGE_LOOP(this);
635  break;
636  case METHOD_GROUP_TEXT:
637  BEGIN_SUBSTAGE_LOOP(this, &stage, true)
638  {
639  ASSERT_OK(gtid_set.add(substage.gtid_str));
640  } END_SUBSTAGE_LOOP(this);
641  break;
642  case METHOD_GTID_SET:
643  ASSERT_OK(gtid_set.add(&stage.set)) << errtext;
644  break;
645  case METHOD_GTID_SET_TEXT:
646  ASSERT_OK(gtid_set.add(stage.str)) << errtext;
647  break;
648  case METHOD_ALL_TEXTS_CONCATENATED:
649  gtid_set.clear();
650  ASSERT_OK(gtid_set.add(done_str)) << errtext;
651  case MAX_METHOD:
652  break;
653  }
654  } END_LOOP_A;
655 
656  // Add groups to Group_caches.
657  BEGIN_LOOP_B
658  {
659  if (verbose)
660  {
661  printf("======== stage=%d combination=%d ========\n",
662  stage_i, combination_i);
663 #ifndef DBUG_OFF
664  printf("group log state:\n");
665  group_log_state.print();
666  printf("trx cache:\n");
667  trx_cache.print(sid_maps[0]);
668  printf("stmt cache:\n");
669  stmt_cache.print(sid_maps[0]);
670 #endif // ifdef DBUG_OFF
671  }
672 
673  Gtid_set ended_groups(sid_maps[0]);
674  bool trx_contains_logged_subgroup= false;
675  bool stmt_contains_logged_subgroup= false;
676  BEGIN_SUBSTAGE_LOOP(this, &stage, true)
677  {
678  int type_j;
679  if (type_i == TYPE_RANDOMIZE)
680  type_j= rand() % 2;
681  else if (type_i == TYPE_AUTO && !substage.is_auto)
682  type_j= TYPE_NONTRX;
683  else
684  type_j= type_i;
685  int end_j;
686  if (substage.is_first &&
687  ((end_i == END_RANDOMIZE && (rand() % 2)) ||
688  end_i == END_ON))
689  {
690  ASSERT_OK(ended_groups.ensure_sidno(substage.sidno));
691  ASSERT_OK(ended_groups._add(substage.sidno, substage.gno));
692  }
693  end_j= substage.is_last &&
694  ended_groups.contains_group(substage.sidno, substage.gno);
695 
696  /*
697  In EMPTY_RANDOMIZE mode, we have to determine once *per
698  group* (not substage) if we use EMPTY_END or not. So we
699  determine this for the first subgroup of the group, and then
700  we memoize which groups use EMPTY_END using the Gtid_set
701  empty_end.
702  */
703  int empty_j;
704  if (empty_i == EMPTY_RANDOMIZE)
705  empty_j= rand() % 3;
706  else
707  empty_j= empty_i;
708  int anon_j1, anon_j2;
709  if (type_j != TYPE_TRX || anon_i == ANON_OFF)
710  anon_j1= anon_j2= ANON_OFF;
711  else
712  {
713  anon_j1= rand() % 2;
714  anon_j2= rand() % 2;
715  }
716  if (verbose)
717  printf("type_j=%d end_j=%d empty_j=%d anon_j1=%d anon_j2=%d\n",
718  type_j, end_j, empty_j, anon_j1, anon_j2);
719 
720  thd->variables.gtid_next_list.is_non_null=
721  (type_i == TYPE_NONTRX || type_i == TYPE_AUTO) ? 0 : 1;
722  gtid_commit=
723  (substage_i == stage.n_substages - 1) ||
724  !thd->variables.gtid_next_list.is_non_null;
725 
726  if (type_j == TYPE_AUTO)
727  {
728  gtid_next->type= Gtid_specification::AUTOMATIC;
729  gtid_next->group.sidno= substage.sidno;
730  gtid_next->group.gno= 0;
731  gtid_end= false;
732  lock.unlock();
733  lock.assert_no_lock();
734  gtid_before_statement(thd, &lock, &group_log_state,
735  &stmt_cache, &trx_cache);
736  lock.rdlock();
737  stmt_cache.add_logged_subgroup(thd, 20 + rand() % 100/*binlog_len*/);
738  stmt_contains_logged_subgroup= true;
739  }
740  else
741  {
742  Group_cache &cache= type_j == TYPE_TRX ? trx_cache : stmt_cache;
743 
744  if (anon_j1)
745  {
746  gtid_next->type= Gtid_specification::ANONYMOUS;
747  gtid_next->group.sidno= 0;
748  gtid_next->group.gno= 0;
749  gtid_end= false;
750  lock.unlock();
751  lock.assert_no_lock();
752  gtid_before_statement(thd, &lock, &group_log_state,
753  &stmt_cache, &trx_cache);
754  lock.rdlock();
755  cache.add_logged_subgroup(thd, 20 + rand() % 100/*binlog_len*/);
756  trx_contains_logged_subgroup= true;
757  }
758 
759  gtid_next->type= Gtid_specification::GTID;
760  gtid_next->group.sidno= substage.sidno;
761  gtid_next->group.gno= substage.gno;
762  gtid_end= (end_j == END_ON) ? true : false;
763  lock.unlock();
764  lock.assert_no_lock();
765  gtid_before_statement(thd, &lock, &group_log_state,
766  &stmt_cache, &trx_cache);
767  lock.rdlock();
768  if (!group_log_state.is_ended(substage.sidno, substage.gno))
769  {
770  switch (empty_j)
771  {
772  case EMPTY_OFF:
773  cache.add_logged_subgroup(thd, 20 + rand() % 100/*binlog_len*/);
774  if (type_j == TYPE_TRX)
775  trx_contains_logged_subgroup= true;
776  else
777  stmt_contains_logged_subgroup= true;
778  break;
779  case EMPTY_ON:
780  cache.add_empty_subgroup(substage.sidno, substage.gno,
781  end_j ? true : false);
782  break;
783  case EMPTY_IMPLICIT:
784  break; // do nothing
785  default:
786  assert(0);
787  }
788  }
789 
790  if (anon_j2)
791  {
792  gtid_next->type= Gtid_specification::ANONYMOUS;
793  gtid_next->group.sidno= 0;
794  gtid_next->group.gno= 0;
795  gtid_end= false;
796  lock.unlock();
797  lock.assert_no_lock();
798  gtid_before_statement(thd, &lock, &group_log_state,
799  &stmt_cache, &trx_cache);
800  lock.rdlock();
801  cache.add_logged_subgroup(thd, 20 + rand() % 100/*binlog_len*/);
802  trx_contains_logged_subgroup= true;
803  }
804  }
805 
806 #ifndef DBUG_OFF
807  if (verbose)
808  {
809  printf("stmt_cache:\n");
810  stmt_cache.print(sid_maps[0]);
811  }
812 #endif // ifndef DBUG_OFF
813  if (!stmt_cache.is_empty())
814  gtid_flush_group_cache(thd, &lock,
815  &group_log_state, NULL/*group log*/,
816  &stmt_cache, &trx_cache,
817  1/*binlog_no*/, 1/*binlog_pos*/,
818  stmt_contains_logged_subgroup ?
819  20 + rand() % 99 : -1
820  /*offset_after_last_statement*/);
821  stmt_contains_logged_subgroup= false;
822  gtid_before_flush_trx_cache(thd, &lock, &group_log_state, &trx_cache);
823  if (gtid_commit)
824  {
825  // simulate gtid_after_flush_trx_cache() but don't
826  // execute a COMMIT statement
827  thd->variables.gtid_has_ongoing_super_group= 0;
828 
829 #ifndef DBUG_OFF
830  if (verbose)
831  {
832  printf("trx_cache:\n");
833  trx_cache.print(sid_maps[0]);
834  printf("trx_cache.is_empty=%d n_subgroups=%d trx_contains_logged_subgroup=%d\n",
835  trx_cache.is_empty(), trx_cache.get_n_subgroups(),
836  trx_contains_logged_subgroup);
837  }
838 #endif // ifndef DBUG_OFF
839 
840  if (!trx_cache.is_empty())
841  gtid_flush_group_cache(thd, &lock,
842  &group_log_state, NULL/*group log*/,
843  &trx_cache, &trx_cache,
844  1/*binlog_no*/, 1/*binlog_pos*/,
845  trx_contains_logged_subgroup ?
846  20 + rand() % 99 : -1
847  /*offset_after_last_statement*/);
848  trx_contains_logged_subgroup= false;
849  }
850  } END_SUBSTAGE_LOOP(this);
851 
852  gtid_set.clear();
853  ASSERT_OK(group_log_state.owned_groups.get_partial_groups(&gtid_set));
854  ASSERT_OK(gtid_set.add(&group_log_state.ended_groups));
855  } END_LOOP_B;
856 
857  // add stage.set to done_groups
858  Gtid_set old_done_groups(&done_groups, &status);
859  ASSERT_OK(status);
860  ASSERT_OK(done_groups.add(&stage.set));
861 
862  // check the Gtid_set::remove and Gtid_set::is_subset functions
863  Gtid_set diff(&done_groups, &status);
864  ASSERT_OK(status);
865  ASSERT_OK(diff.remove(&old_done_groups));
866  Gtid_set not_new(&stage.set, &status);
867  ASSERT_OK(status);
868  ASSERT_OK(not_new.remove(&diff));
869 
870 #define GROUP_SUBSET(gs1, gs2, outcome) \
871  group_subset(&gs1, &gs2, outcome, __LINE__, #gs1 " <= " #gs2);
872  push_errtext();
873  GROUP_SUBSET(not_new, not_new, true);
874  GROUP_SUBSET(not_new, diff, not_new.is_empty());
875  GROUP_SUBSET(not_new, stage.set, true);
876  GROUP_SUBSET(not_new, done_groups, true);
877  GROUP_SUBSET(not_new, old_done_groups, true);
878 
879  GROUP_SUBSET(diff, not_new, diff.is_empty());
880  GROUP_SUBSET(diff, diff, true);
881  GROUP_SUBSET(diff, stage.set, true);
882  GROUP_SUBSET(diff, done_groups, true);
883  GROUP_SUBSET(diff, old_done_groups, diff.is_empty());
884 
885  GROUP_SUBSET(stage.set, not_new, diff.is_empty());
886  GROUP_SUBSET(stage.set, diff, not_new.is_empty());
887  GROUP_SUBSET(stage.set, stage.set, true);
888  GROUP_SUBSET(stage.set, done_groups, true);
889  GROUP_SUBSET(stage.set, old_done_groups, diff.is_empty());
890 
891  //GROUP_SUBSET(done_groups, not_new, ???);
892  GROUP_SUBSET(done_groups, diff, old_done_groups.is_empty());
893  GROUP_SUBSET(done_groups, stage.set, done_groups.equals(&stage.set));
894  GROUP_SUBSET(done_groups, done_groups, true);
895  GROUP_SUBSET(done_groups, old_done_groups, diff.is_empty());
896 
897  GROUP_SUBSET(old_done_groups, not_new, old_done_groups.equals(&not_new));
898  GROUP_SUBSET(old_done_groups, diff, old_done_groups.is_empty());
899  //GROUP_SUBSET(old_done_groups, stage.set, ???);
900  GROUP_SUBSET(old_done_groups, done_groups, true);
901  GROUP_SUBSET(old_done_groups, old_done_groups, true);
902  pop_errtext();
903 
904  /*
905  Verify that all group sets are equal. We test both a.equals(b)
906  and b.equals(a) and a.equals(a), because we want to verify that
907  Gtid_set::equals is correct too. We compare both the sets
908  using Gtid_set::equals, and the output of to_string() using
909  EXPECT_STREQ.
910  */
911  BEGIN_LOOP_A
912  {
913  char *buf1= new char[gtid_set.get_string_length() + 1];
914  gtid_set.to_string(buf1);
915  for (int i= 0; i < N_COMBINATIONS_SETS; i++)
916  {
917  Gtid_set &gtid_set_2= containers[i]->gtid_set;
918  if (combination_i < i)
919  {
920  char *buf2= new char[gtid_set_2.get_string_length() + 1];
921  gtid_set_2.to_string(buf2);
922  EXPECT_STREQ(buf1, buf2) << errtext << " i=" << i;
923  delete buf2;
924  }
925  EXPECT_EQ(true, gtid_set.equals(&gtid_set_2)) << errtext << " i=" << i;
926  }
927  delete buf1;
928  } END_LOOP_A;
929  BEGIN_LOOP_B
930  {
931  EXPECT_EQ(true, containers[combination_i]->gtid_set.equals(&done_groups)) << errtext;
932  } END_LOOP_B;
933  }
934  pop_errtext();
935 
936  // Finally, verify that the string representations of
937  // done_groups is as expected
938  static char buf[100*100];
939  done_groups.to_string(buf);
940  EXPECT_STRCASEEQ(all_groups_str, buf) << errtext;
941  lock.unlock();
942  lock.assert_no_lock();
943 
944  // Clean up.
945  free(done_str);
946  for (int i= 0; i < N_COMBINATIONS; i++)
947  delete containers[i];
948  delete containers;
949  delete sid_maps[1];
950  delete sid_maps;
951  free(thd);
952 
953  mysql_bin_log.sid_lock.assert_no_lock();
954 }