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