Skip to content

Commit 2fbdd11

Browse files
committed
Bug#31020183 DUPLICATE KEYS IN PACKED CONFIG V1
Packed config v1 returned by ndb_mgmd may contain duplicate entries after upgrade to 8.0. This makes the packed config incompatible with clients using version 1. The problem occurs in backwards compatibility code for generating a packed config v1 which assumes that entries in each section is sorted while merging with the default section. Fix by sorting the entries in the section before merging them with default section. Change-Id: I151fd12991bfddb961ba711c7f98d3737a95ec0a
1 parent dea5412 commit 2fbdd11

File tree

2 files changed

+80
-41
lines changed

2 files changed

+80
-41
lines changed

storage/ndb/src/common/mgmcommon/ConfigSection.cpp

Lines changed: 40 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
2+
Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
33
44
This program is free software; you can redistribute it and/or modify
55
it under the terms of the GNU General Public License, version 2.0,
@@ -531,11 +531,28 @@ ConfigSection::get_section_type_value()
531531
return val;
532532
}
533533

534+
static bool
535+
compare_entry_key(ConfigSection::Entry *first,
536+
ConfigSection::Entry *second)
537+
{
538+
if (first == second)
539+
return false;
540+
if (first->m_key < second->m_key)
541+
return true;
542+
else if (first->m_key > second->m_key)
543+
return false;
544+
/* Two entries should never have the same key */
545+
require(false);
546+
return false;
547+
}
548+
534549
Uint32
535550
ConfigSection::get_v1_length() const
536551
{
537552
check_magic();
538-
const ConfigSection *my_section = this;
553+
// sorted entries in key key order
554+
std::vector<Entry *> sorted_entries(m_entry_array);
555+
std::sort(sorted_entries.begin(), sorted_entries.end(), compare_entry_key);
539556
ConfigSection *default_section = get_default_section();
540557
Uint32 len = 0;
541558
Uint32 my_inx = 0;
@@ -553,32 +570,28 @@ ConfigSection::get_v1_length() const
553570
* key in an appropriate manner.
554571
*/
555572
while (default_inx < default_section->m_num_entries ||
556-
my_inx < my_section->m_num_entries)
573+
my_inx < m_num_entries)
557574
{
558575
if ((default_inx >= default_section->m_num_entries) ||
559-
((my_inx < my_section->m_num_entries) &&
560-
(my_section->m_entry_array[my_inx]->m_key <
576+
((my_inx < m_num_entries) &&
577+
(sorted_entries[my_inx]->m_key <
561578
default_section->m_entry_array[default_inx]->m_key)))
562579

563580
{
564-
len += my_section->m_entry_array[my_inx]->get_v1_length();
581+
len += sorted_entries[my_inx]->get_v1_length();
565582
my_inx++;
566-
}
567-
else if ((my_inx >= my_section->m_num_entries) ||
568-
(my_section->m_entry_array[my_inx]->m_key >
569-
default_section->m_entry_array[default_inx]->m_key))
570-
{
583+
} else if ((my_inx >= m_num_entries) ||
584+
(sorted_entries[my_inx]->m_key >
585+
default_section->m_entry_array[default_inx]->m_key)) {
571586
len += default_section->m_entry_array[default_inx]->get_v1_length();
572587
default_inx++;
573-
}
574-
else
575-
{
576-
len += my_section->m_entry_array[my_inx]->get_v1_length();
588+
} else {
589+
len += sorted_entries[my_inx]->get_v1_length();
577590
my_inx++;
578591
default_inx++;
579592
}
580593
}
581-
require(my_inx == my_section->m_num_entries &&
594+
require(my_inx == m_num_entries &&
582595
default_inx == default_section->m_num_entries);
583596
/**
584597
* Add two more entries for type of section and parent.
@@ -591,7 +604,9 @@ void
591604
ConfigSection::create_v1_section(Uint32 **v1_ptr, Uint32 section_id)
592605
{
593606
check_magic();
594-
ConfigSection *my_section = this;
607+
// sorted entries in key key order
608+
std::vector<Entry*> sorted_entries(m_entry_array);
609+
std::sort(sorted_entries.begin(), sorted_entries.end(), compare_entry_key);
595610
ConfigSection *default_section = get_default_section();
596611

597612
Uint32 my_inx = 0;
@@ -604,19 +619,19 @@ ConfigSection::create_v1_section(Uint32 **v1_ptr, Uint32 section_id)
604619
* holes in the array.
605620
*/
606621
while (default_inx < default_section->m_num_entries ||
607-
my_inx < my_section->m_num_entries)
622+
my_inx < m_num_entries)
608623
{
609624
if ((default_inx >= default_section->m_num_entries) ||
610-
((my_inx < my_section->m_num_entries) &&
611-
(my_section->m_entry_array[my_inx]->m_key <
625+
((my_inx < m_num_entries) &&
626+
(sorted_entries[my_inx]->m_key <
612627
default_section->m_entry_array[default_inx]->m_key)))
613628
{
614-
Entry *my_entry = my_section->m_entry_array[my_inx];
629+
Entry *my_entry = sorted_entries[my_inx];
615630
my_entry->create_v1_entry(v1_ptr, section_id);
616631
my_inx++;
617632
}
618-
else if ((my_inx >= my_section->m_num_entries) ||
619-
(my_section->m_entry_array[my_inx]->m_key >
633+
else if ((my_inx >= m_num_entries) ||
634+
(sorted_entries[my_inx]->m_key >
620635
default_section->m_entry_array[default_inx]->m_key))
621636
{
622637
Entry *default_entry = default_section->m_entry_array[default_inx];
@@ -625,13 +640,13 @@ ConfigSection::create_v1_section(Uint32 **v1_ptr, Uint32 section_id)
625640
}
626641
else
627642
{
628-
Entry *my_entry = my_section->m_entry_array[my_inx];
643+
Entry *my_entry = sorted_entries[my_inx];
629644
my_entry->create_v1_entry(v1_ptr, section_id);
630645
my_inx++;
631646
default_inx++;
632647
}
633648
}
634-
require(my_inx == my_section->m_num_entries &&
649+
require(my_inx == m_num_entries &&
635650
default_inx == default_section->m_num_entries);
636651
{
637652
/**
@@ -1113,21 +1128,6 @@ ConfigSection::handle_default_section(ConfigSection *default_section)
11131128
sort();
11141129
}
11151130

1116-
static bool
1117-
compare_entry_key(ConfigSection::Entry *first,
1118-
ConfigSection::Entry *second)
1119-
{
1120-
if (first == second)
1121-
return false;
1122-
if (first->m_key < second->m_key)
1123-
return true;
1124-
else if (first->m_key > second->m_key)
1125-
return false;
1126-
/* Two entries should never have the same key */
1127-
require(false);
1128-
return false;
1129-
}
1130-
11311131
void
11321132
ConfigSection::sort()
11331133
{

storage/ndb/src/mgmsrv/testConfig.cpp

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
Copyright (c) 2008, 2019, Oracle and/or its affiliates. All rights reserved.
2+
Copyright (c) 2008, 2020, Oracle and/or its affiliates. All rights reserved.
33
44
55
This program is free software; you can redistribute it and/or modify
@@ -365,6 +365,44 @@ checksum_config(void)
365365
delete c2;
366366
}
367367

368+
369+
static void
370+
test_config_v1_with_dyn_ports(void)
371+
{
372+
Config* c1=
373+
create_config("[ndbd]", "[ndbd]",
374+
"[ndb_mgmd]", "HostName=localhost",
375+
"[mysqld]", NULL);
376+
CHECK(c1);
377+
378+
ndbout_c("== check config v1 ==");
379+
380+
// Set all dynamic ports
381+
ConfigIter iter(c1, CFG_SECTION_CONNECTION);
382+
for(;iter.valid();iter.next()) {
383+
Uint32 port = 0;
384+
if (iter.get(CFG_CONNECTION_SERVER_PORT, &port) != 0 ||
385+
port != 0)
386+
continue; // Not configured as dynamic port
387+
ConfigValues::Iterator i2(c1->m_configValues->m_config,
388+
iter.m_config);
389+
const Uint32 dummy_port = 37;
390+
CHECK(i2.set(CFG_CONNECTION_SERVER_PORT, dummy_port));
391+
}
392+
393+
// c1->print();
394+
395+
UtilBuffer buf;
396+
c1->pack(buf, false /* v2 */);
397+
398+
ConfigValuesFactory cvf;
399+
CHECK(cvf.unpack_v1_buf(buf));
400+
401+
delete c1;
402+
403+
ndbout_c("==================");
404+
}
405+
368406
static void
369407
test_param_values(void)
370408
{
@@ -488,6 +526,7 @@ TAPTEST(MgmConfig)
488526
test_hostname_mycnf();
489527
if (false)
490528
print_restart_info();
529+
test_config_v1_with_dyn_ports();
491530
ndb_end(0);
492531
return 1; // OK
493532
}

0 commit comments

Comments
 (0)