rpzloader.cc rpzloader.hh \
secpoll.cc \
settings/cxxsupport.cc \
- shuffle.cc shuffle.hh \
sholder.hh \
+ shuffle.cc shuffle.hh \
sillyrecords.cc \
sortlist.cc sortlist.hh \
sstuff.hh \
test-secpoll_cc.cc \
test-settings.cc \
test-sholder_hh.cc \
+ test-shuffle_cc.cc \
test-signers.cc \
test-syncres_cc.cc \
test-syncres_cc.hh \
src_dir / 'test-rpzloader_cc.cc',
src_dir / 'test-secpoll_cc.cc',
src_dir / 'test-settings.cc',
+ src_dir / 'test-shuffle_cc.cc',
src_dir / 'test-signers.cc',
src_dir / 'test-syncres_cc.cc',
src_dir / 'test-syncres_cc.hh',
}
lwr.d_records = std::move(vec);
}
- pdns::dedup(lwr.d_records);
+ if (auto count = pdns::dedup(lwr.d_records); count > 0) {
+ LOG(prefix << qname << ": Removed " << count << " duplicate records from response received from " << auth << endl);
+ }
}
void SyncRes::rememberParentSetIfNeeded(const DNSName& domain, const vector<DNSRecord>& newRecords, unsigned int depth, const string& prefix)
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef BOOST_TEST_DYN_LINK
+#define BOOST_TEST_DYN_LINK
+#endif
+
+#define BOOST_TEST_NO_MAIN
+
+#include "config.h"
+#include <boost/test/unit_test.hpp>
+
+#include "shuffle.hh"
+#include "test-common.hh"
+
+BOOST_AUTO_TEST_SUITE(shuffle_cc)
+
+BOOST_AUTO_TEST_CASE(test_simple)
+{
+ std::vector<DNSRecord> list;
+ auto* address = &list;
+ addRecordToList(list, DNSName("foo"), QType::A, "1.2.3.4");
+ addRecordToList(list, DNSName("foo2"), QType::A, "1.2.3.4");
+ auto dups = pdns::dedup(list);
+ BOOST_CHECK_EQUAL(dups, 0U);
+ BOOST_CHECK_EQUAL(list.size(), 2U);
+ addRecordToList(list, DNSName("foo"), QType::A, "1.2.3.4");
+ dups = pdns::dedup(list);
+ BOOST_CHECK_EQUAL(dups, 1U);
+ BOOST_CHECK_EQUAL(list.size(), 2U);
+ addRecordToList(list, DNSName("Foo"), QType::A, "1.2.3.4");
+ dups = pdns::dedup(list);
+ BOOST_CHECK_EQUAL(dups, 1U);
+ BOOST_CHECK_EQUAL(list.size(), 2U);
+ BOOST_CHECK_EQUAL(address, &list);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
if (auto* bval = std::get_if<bool>(&broken); bval != nullptr && *bval) {
rrc.d_signature[0] ^= 42;
}
- else if (auto *ival = std::get_if<int>(&broken)) {
+ else if (auto* ival = std::get_if<int>(&broken)) {
rrc.d_signature[0] ^= *ival; // NOLINT(*-narrowing-conversions)
}
shuffle(rrs, includingAdditionals);
}
-void pdns::dedup(vector<DNSRecord>& rrs)
+unsigned int pdns::dedup(vector<DNSRecord>& rrs)
{
// This functino tries to avoid unneccesary work
// First a vector with zero or one element does not need dedupping
if (rrs.size() <= 1) {
- return;
+ return 0;
}
// If we have a larger vector, first check if we actually have duplicates.
// We assume the most common case is: no
- std::unordered_set<std::string> seen;
- std::vector<bool> unique(rrs.size(), false);
+ std::set<std::tuple<DNSName, QType, std::string>> seen;
+ std::vector<bool> dups(rrs.size(), false);
unsigned int counter = 0;
- unsigned int numUnique = 0;
+ unsigned int numDups = 0;
for (const auto& rec : rrs) {
- // This ignores class, ttl and place
- if (seen.emplace(rec.getContent()->serialize(rec.d_name, true, true)).second) {
- unique[counter] = true;
- numUnique++;
+ // This ignores class, ttl and place by using constants for those
+ if (!seen.emplace(rec.d_name.makeLowerCase(), rec.d_type, rec.getContent()->serialize(rec.d_name, true, false)).second) {
+ dups[counter] = true;
+ numDups++;
}
++counter;
}
- if (numUnique == rrs.size()) {
+ if (numDups == 0) {
// Original is fine as-is.
- return;
+ return 0;
}
// We avoid calling erase, as it calls a lot of move constructors. This can hurt, especially if
// you call it on a large vector muliple times.
// So we just take the elements that are unique
std::vector<DNSRecord> ret;
- ret.reserve(numUnique);
+ ret.reserve(rrs.size() - numDups);
for (counter = 0; counter < rrs.size(); ++counter) {
- if (unique[counter]) {
+ if (!dups[counter]) {
ret.emplace_back(std::move(rrs[counter]));
}
}
rrs = std::move(ret);
+ return numDups;
}
{
void shuffle(std::vector<DNSZoneRecord>& rrs);
void orderAndShuffle(std::vector<DNSRecord>& rrs, bool includingAdditionals);
-void dedup(std::vector<DNSRecord>& rrs);
+unsigned int dedup(std::vector<DNSRecord>& rrs);
}