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