17 #include <gtest/gtest.h>
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
25 #include "sql_class.h"
26 #include "my_pthread.h"
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)
40 static const char *uuids[16];
47 seed= (
unsigned int)time(NULL);
48 printf(
"# seed = %u\n", seed);
50 for (
int i= 0;
i < 16;
i++)
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));
65 my_delete(
"sid-map-0", MYF(0));
66 my_delete(
"sid-map-1", MYF(0));
67 my_delete(
"sid-map-2", MYF(0));
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]; \
92 (group_test)->append_errtext(__LINE__, \
93 "sidno=%d group=%s substage_i=%d", \
94 substage.sidno, substage.gtid_str, \
96 #define END_SUBSTAGE_LOOP(group_test) } group_test->pop_errtext()
108 bool is_first, is_last, is_auto;
112 printf(
"%d/%s [first=%d last=%d auto=%d]",
113 sidno, gtid_str, is_first, is_last, is_auto);
127 static const int MAX_SUBSTAGES= 200;
142 : group_test(gt), sid_map(sm),
143 set(sm), str_len(0), str(NULL),
144 automatic_groups(sm), non_automatic_groups(sm)
151 ASSERT_OK(
set.ensure_sidno(max_sidno));
153 ASSERT_OK(non_automatic_groups.
ensure_sidno(max_sidno));
156 ~
Stage() { free(str); }
160 printf(
"%d substages = {\n", n_substages);
161 for (
int i= 0;
i < n_substages;
i++)
163 printf(
" substage[%d]: ",
i);
164 substages[
i].print();
180 automatic_groups.
clear();
181 non_automatic_groups.
clear();
183 n_substages= 1 + (rand() % MAX_SUBSTAGES);
184 BEGIN_SUBSTAGE_LOOP(group_test,
this,
false)
187 substage.sidno= 1 + (rand() % N_SIDS);
189 1 + (rand() % (substage.sidno * 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);
198 ASSERT_LE(1, other_sm->add_permanent(substage.sid))
199 << group_test->errtext;
205 !
set.contains_group(substage.sidno, substage.gno) &&
206 ((iv == NULL || iv->
start > 1) ? substage.gno == 1 :
207 substage.gno == iv->
end);
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);
219 for (
int substage_i= n_substages - 1; substage_i >= 0; substage_i--)
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));
227 str_len=
set.get_string_length();
228 str= (
char *)realloc(str, str_len + 1);
245 int errtext_stack[100];
246 int errtext_stack_pos;
249 void append_errtext(
int line,
const char *
fmt, ...) ATTRIBUTE_FORMAT(printf, 3, 4)
253 vsprintf(errtext + errtext_stack[errtext_stack_pos], fmt, argp);
255 printf(
"@line %d: %s\n", line, errtext);
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;
269 errtext[errtext_stack[errtext_stack_pos--] - 3]= 0;
274 int line,
const char *desc)
276 append_errtext(line,
"%s", desc);
278 EXPECT_EQ(outcome, sub->
is_subset(super)) << errtext;
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;
290 const char *GroupTest::uuids[16]=
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",
317 for (
int i= 0;
i < N_SIDS;
i++)
319 EXPECT_OK(u.
parse(uuids[
i])) <<
"i=" << i;
321 EXPECT_STRCASEEQ(uuids[i], buf) <<
"i=" <<
i;
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"));
340 ASSERT_OK(sm.open(
"sid-map-0"));
343 while (sm.get_max_sidno() < N_SIDS)
344 ASSERT_LE(1, sm.add_permanent(&sids[rand() % N_SIDS])) << errtext;
349 for (
int i= 0; i < N_SIDS; i++)
351 rpl_sidno sidno= sm.get_sorted_sidno(i);
354 EXPECT_NE((
rpl_sid *)NULL, sid= sm.sidno_to_sid(sidno)) << errtext;
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;
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,
399 enum enum_sets_sid_map {
400 SID_MAP_0= 0, SID_MAP_1, MAX_SID_MAP
402 const int N_COMBINATIONS_SETS= MAX_METHOD * MAX_SID_MAP;
451 enum enum_caches_type
453 TYPE_TRX= 0, TYPE_NONTRX, TYPE_RANDOMIZE, TYPE_AUTO, MAX_TYPE
457 END_OFF= 0, END_ON, END_RANDOMIZE, MAX_END
459 enum enum_caches_empty
461 EMPTY_OFF= 0, EMPTY_ON, EMPTY_IMPLICIT, EMPTY_RANDOMIZE, MAX_EMPTY
463 enum enum_caches_anon {
464 ANON_OFF= 0, ANON_ON, MAX_ANON
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;
471 #define BEGIN_LOOP_A \
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 >id_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);
483 #define END_LOOP_A } } pop_errtext()
485 #define BEGIN_LOOP_B \
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 >id_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);
507 #define END_LOOP_B } } } } pop_errtext()
511 global_system_variables.log_warnings= 0;
513 mysql_bin_log.server_uuid_sidno= 1;
518 sid_maps[0]= &mysql_bin_log.sid_map;
519 sid_maps[1]=
new Sid_map(&lock);
522 ASSERT_OK(sid_maps[0]->open(
"sid-map-1"));
523 ASSERT_OK(sid_maps[1]->open(
"sid-map-2"));
529 for (
int i= 0; i < N_SIDS; i++)
530 ASSERT_LE(1, sid_maps[0]->add_permanent(&sids[i])) << errtext;
539 Group_log_state group_log_state;
541 : gtid_set(sm), group_log_state(lock, sm)
543 void init() { ASSERT_OK(group_log_state.ensure_sidno()); };
545 Containers **containers=
new Containers*[N_COMBINATIONS];
548 containers[combination_i]=
new Containers(&lock, sid_map);
552 containers[combination_i] =
new Containers(&lock, sid_maps[0]);
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;
570 ASSERT_OK(done_groups.ensure_sidno(sid_maps[0]->
get_max_sidno()));
579 char *done_str= NULL;
581 Stage stage(
this, sid_maps[0]);
591 THD *thd= (THD *)malloc(
sizeof(THD));
592 ASSERT_NE((THD *)NULL, thd) << errtext;
594 thd->thread_id= 4711;
595 gtid_next->
type= Gtid_specification::AUTOMATIC;
596 my_bool >id_end= thd->variables.gtid_end;
597 my_bool >id_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;
603 while (!all_groups.equals(&done_groups))
606 append_errtext(__LINE__,
"stage_i=%d", stage_i);
607 stage.new_stage(&done_groups, sid_maps[1]);
611 printf(
"======== stage %d ========\n", stage_i);
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);
627 case METHOD_SIDNO_GNO:
628 BEGIN_SUBSTAGE_LOOP(
this, &stage,
true)
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);
636 case METHOD_GROUP_TEXT:
637 BEGIN_SUBSTAGE_LOOP(
this, &stage,
true)
639 ASSERT_OK(gtid_set.add(substage.gtid_str));
640 } END_SUBSTAGE_LOOP(
this);
642 case METHOD_GTID_SET:
643 ASSERT_OK(gtid_set.add(&stage.set)) << errtext;
645 case METHOD_GTID_SET_TEXT:
646 ASSERT_OK(gtid_set.add(stage.str)) << errtext;
648 case METHOD_ALL_TEXTS_CONCATENATED:
650 ASSERT_OK(gtid_set.add(done_str)) << errtext;
661 printf(
"======== stage=%d combination=%d ========\n",
662 stage_i, combination_i);
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
674 bool trx_contains_logged_subgroup=
false;
675 bool stmt_contains_logged_subgroup=
false;
676 BEGIN_SUBSTAGE_LOOP(
this, &stage,
true)
679 if (type_i == TYPE_RANDOMIZE)
681 else if (type_i == TYPE_AUTO && !substage.is_auto)
686 if (substage.is_first &&
687 ((end_i == END_RANDOMIZE && (rand() % 2)) ||
690 ASSERT_OK(ended_groups.ensure_sidno(substage.sidno));
691 ASSERT_OK(ended_groups._add(substage.sidno, substage.gno));
693 end_j= substage.is_last &&
694 ended_groups.contains_group(substage.sidno, substage.gno);
704 if (empty_i == EMPTY_RANDOMIZE)
708 int anon_j1, anon_j2;
709 if (type_j != TYPE_TRX || anon_i == ANON_OFF)
710 anon_j1= anon_j2= ANON_OFF;
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);
720 thd->variables.gtid_next_list.is_non_null=
721 (type_i == TYPE_NONTRX || type_i == TYPE_AUTO) ? 0 : 1;
723 (substage_i == stage.n_substages - 1) ||
724 !thd->variables.gtid_next_list.is_non_null;
726 if (type_j == TYPE_AUTO)
728 gtid_next->
type= Gtid_specification::AUTOMATIC;
729 gtid_next->group.sidno= substage.sidno;
730 gtid_next->group.gno= 0;
734 gtid_before_statement(thd, &lock, &group_log_state,
735 &stmt_cache, &trx_cache);
737 stmt_cache.add_logged_subgroup(thd, 20 + rand() % 100);
738 stmt_contains_logged_subgroup=
true;
742 Group_cache &cache= type_j == TYPE_TRX ? trx_cache : stmt_cache;
746 gtid_next->
type= Gtid_specification::ANONYMOUS;
747 gtid_next->group.sidno= 0;
748 gtid_next->group.gno= 0;
752 gtid_before_statement(thd, &lock, &group_log_state,
753 &stmt_cache, &trx_cache);
755 cache.add_logged_subgroup(thd, 20 + rand() % 100);
756 trx_contains_logged_subgroup=
true;
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;
765 gtid_before_statement(thd, &lock, &group_log_state,
766 &stmt_cache, &trx_cache);
768 if (!group_log_state.is_ended(substage.sidno, substage.gno))
773 cache.add_logged_subgroup(thd, 20 + rand() % 100);
774 if (type_j == TYPE_TRX)
775 trx_contains_logged_subgroup=
true;
777 stmt_contains_logged_subgroup=
true;
780 cache.add_empty_subgroup(substage.sidno, substage.gno,
781 end_j ?
true :
false);
792 gtid_next->
type= Gtid_specification::ANONYMOUS;
793 gtid_next->group.sidno= 0;
794 gtid_next->group.gno= 0;
798 gtid_before_statement(thd, &lock, &group_log_state,
799 &stmt_cache, &trx_cache);
801 cache.add_logged_subgroup(thd, 20 + rand() % 100);
802 trx_contains_logged_subgroup=
true;
809 printf(
"stmt_cache:\n");
810 stmt_cache.print(sid_maps[0]);
812 #endif // ifndef DBUG_OFF
813 if (!stmt_cache.is_empty())
814 gtid_flush_group_cache(thd, &lock,
815 &group_log_state, NULL,
816 &stmt_cache, &trx_cache,
818 stmt_contains_logged_subgroup ?
819 20 + rand() % 99 : -1
821 stmt_contains_logged_subgroup=
false;
822 gtid_before_flush_trx_cache(thd, &lock, &group_log_state, &trx_cache);
827 thd->variables.gtid_has_ongoing_super_group= 0;
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);
838 #endif // ifndef DBUG_OFF
840 if (!trx_cache.is_empty())
841 gtid_flush_group_cache(thd, &lock,
842 &group_log_state, NULL,
843 &trx_cache, &trx_cache,
845 trx_contains_logged_subgroup ?
846 20 + rand() % 99 : -1
848 trx_contains_logged_subgroup=
false;
850 } END_SUBSTAGE_LOOP(
this);
853 ASSERT_OK(group_log_state.owned_groups.get_partial_groups(>id_set));
854 ASSERT_OK(gtid_set.add(&group_log_state.ended_groups));
858 Gtid_set old_done_groups(&done_groups, &status);
860 ASSERT_OK(done_groups.add(&stage.set));
863 Gtid_set diff(&done_groups, &status);
865 ASSERT_OK(diff.remove(&old_done_groups));
866 Gtid_set not_new(&stage.set, &status);
868 ASSERT_OK(not_new.remove(&diff));
870 #define GROUP_SUBSET(gs1, gs2, outcome) \
871 group_subset(&gs1, &gs2, outcome, __LINE__, #gs1 " <= " #gs2);
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);
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());
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());
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());
897 GROUP_SUBSET(old_done_groups, not_new, old_done_groups.equals(¬_new));
898 GROUP_SUBSET(old_done_groups, diff, old_done_groups.is_empty());
900 GROUP_SUBSET(old_done_groups, done_groups,
true);
901 GROUP_SUBSET(old_done_groups, old_done_groups,
true);
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++)
917 Gtid_set >id_set_2= containers[
i]->gtid_set;
918 if (combination_i < i)
922 EXPECT_STREQ(buf1, buf2) << errtext <<
" i=" <<
i;
925 EXPECT_EQ(
true, gtid_set.equals(>id_set_2)) << errtext <<
" i=" << i;
931 EXPECT_EQ(
true, containers[combination_i]->gtid_set.equals(&done_groups)) << errtext;
938 static char buf[100*100];
939 done_groups.to_string(buf);
940 EXPECT_STRCASEEQ(all_groups_str, buf) << errtext;
946 for (
int i= 0; i < N_COMBINATIONS; i++)
947 delete containers[i];
953 mysql_bin_log.sid_lock.assert_no_lock();