Skip to content

Commit ddb7e6c

Browse files
committed
speed up canonical ordering by a factor of 5, increasing the ugliness of the code by a similar amount
1 parent 326d399 commit ddb7e6c

3 files changed

Lines changed: 88 additions & 7 deletions

File tree

pdns/dnsname.cc

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,12 @@ void DNSName::prependRawLabel(const std::string& label)
182182
d_storage = prep+d_storage;
183183
}
184184

185+
bool DNSName::slowCanonCompare(const DNSName& rhs) const
186+
{
187+
auto ours=getRawLabels(), rhsLabels = rhs.getRawLabels();
188+
return std::lexicographical_compare(ours.rbegin(), ours.rend(), rhsLabels.rbegin(), rhsLabels.rend(), CIStringCompare());
189+
}
190+
185191
vector<string> DNSName::getRawLabels() const
186192
{
187193
vector<string> ret;
@@ -192,11 +198,6 @@ vector<string> DNSName::getRawLabels() const
192198
return ret;
193199
}
194200

195-
bool DNSName::canonCompare(const DNSName& rhs) const
196-
{
197-
auto ours=getRawLabels(), rhsLabels = rhs.getRawLabels();
198-
return std::lexicographical_compare(ours.rbegin(), ours.rend(), rhsLabels.rbegin(), rhsLabels.rend(), CIStringCompare());
199-
}
200201

201202
bool DNSName::chopOff()
202203
{

pdns/dnsname.hh

Lines changed: 77 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include <deque>
66
#include <strings.h>
77
#include <stdexcept>
8+
89
// #include "dns.hh"
910
// #include "logger.hh"
1011

@@ -77,11 +78,12 @@ public:
7778
ar & d_empty;
7879
}
7980

80-
bool canonCompare(const DNSName& rhs) const;
81+
inline bool canonCompare(const DNSName& rhs) const;
8182

8283
private:
8384
// typedef __gnu_cxx::__sso_string string_t;
8485
typedef std::string string_t;
86+
bool slowCanonCompare(const DNSName& rhs) const;
8587
string_t d_storage;
8688
bool d_empty;
8789
int d_recurse;
@@ -93,6 +95,80 @@ private:
9395

9496
size_t hash_value(DNSName const& d);
9597

98+
inline char dns2_tolower(char c)
99+
{
100+
if(c>='A' && c<='Z')
101+
c+='a'-'A';
102+
return c;
103+
}
104+
105+
106+
inline bool DNSName::canonCompare(const DNSName& rhs) const
107+
{
108+
// 01234567890abcd
109+
// us: 1a3www4ds9a2nl
110+
// rhs: 3www6online3com
111+
// to compare, we start at the back, is nl < com? no -> done
112+
//
113+
// 0,2,6,a
114+
// 0,4,a
115+
116+
uint8_t ourpos[64], rhspos[64];
117+
uint8_t ourcount=0, rhscount=0;
118+
//cout<<"Asked to compare "<<toString()<<" to "<<rhs.toString()<<endl;
119+
for(const char* p = d_storage.c_str(); p < d_storage.c_str() + d_storage.size() && ourcount < sizeof(ourpos); p+=*p+1)
120+
ourpos[ourcount++]=(p-d_storage.c_str());
121+
for(const char* p = rhs.d_storage.c_str(); p < rhs.d_storage.c_str() + rhs.d_storage.size() && rhscount < sizeof(rhspos); p+=*p+1)
122+
rhspos[rhscount++]=(p-rhs.d_storage.c_str());
123+
124+
if(ourcount == sizeof(ourpos) || rhscount==sizeof(rhspos)) {
125+
return slowCanonCompare(rhs);
126+
}
127+
128+
for(;;) {
129+
if(ourcount == 0 && rhscount != 0)
130+
return true;
131+
if(ourcount == 0 && rhscount == 0)
132+
return false;
133+
if(ourcount !=0 && rhscount == 0)
134+
return false;
135+
ourcount--;
136+
rhscount--;
137+
138+
/*
139+
cout<<"Going to compare: '"<<string(d_storage.c_str() + ourpos[ourcount] + 1,
140+
d_storage.c_str() + ourpos[ourcount] + 1 + *(d_storage.c_str() + ourpos[ourcount]))<<"'"<<endl;
141+
cout<<"Against: '"<<string(rhs.d_storage.c_str() + rhspos[rhscount] + 1,
142+
rhs.d_storage.c_str() + rhspos[rhscount] + 1 + *(rhs.d_storage.c_str() + rhspos[rhscount]))<<"'"<<endl;
143+
*/
144+
bool res=std::lexicographical_compare(
145+
d_storage.c_str() + ourpos[ourcount] + 1,
146+
d_storage.c_str() + ourpos[ourcount] + 1 + *(d_storage.c_str() + ourpos[ourcount]),
147+
rhs.d_storage.c_str() + rhspos[rhscount] + 1,
148+
rhs.d_storage.c_str() + rhspos[rhscount] + 1 + *(rhs.d_storage.c_str() + rhspos[rhscount]),
149+
[](const char& a, const char& b) {
150+
return dns2_tolower(a) < dns2_tolower(b);
151+
});
152+
153+
// cout<<"Forward: "<<res<<endl;
154+
if(res)
155+
return true;
156+
157+
res=std::lexicographical_compare( rhs.d_storage.c_str() + rhspos[rhscount] + 1,
158+
rhs.d_storage.c_str() + rhspos[rhscount] + 1 + *(rhs.d_storage.c_str() + rhspos[rhscount]),
159+
d_storage.c_str() + ourpos[ourcount] + 1,
160+
d_storage.c_str() + ourpos[ourcount] + 1 + *(d_storage.c_str() + ourpos[ourcount]),
161+
[](const char& a, const char& b) {
162+
return dns2_tolower(a) < dns2_tolower(b);
163+
});
164+
// cout<<"Reverse: "<<res<<endl;
165+
if(res)
166+
return false;
167+
}
168+
return false;
169+
}
170+
171+
96172
struct CanonDNSNameCompare: public std::binary_function<DNSName, DNSName, bool>
97173
{
98174
bool operator()(const DNSName&a, const DNSName& b) const

pdns/test-dnsname_cc.cc

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,9 @@ BOOST_AUTO_TEST_CASE(test_compare_canonical) {
343343
DNSName lower("bert.com."), higher("alpha.nl.");
344344
BOOST_CHECK(lower.canonCompare(higher));
345345

346+
BOOST_CHECK(DNSName("bert.com").canonCompare(DNSName("www.bert.com")));
347+
BOOST_CHECK(DNSName("BeRt.com").canonCompare(DNSName("WWW.berT.com")));
348+
BOOST_CHECK(!DNSName("www.BeRt.com").canonCompare(DNSName("WWW.berT.com")));
346349

347350
vector<DNSName> vec;
348351
for(const std::string& a : {"bert.com.", "alpha.nl.", "articles.xxx.",
@@ -352,7 +355,7 @@ BOOST_AUTO_TEST_CASE(test_compare_canonical) {
352355
}
353356
sort(vec.begin(), vec.end(), CanonDNSNameCompare());
354357
// for(const auto& v : vec)
355-
// cerr<<'"'<<v.toString()<<'"'<<endl;
358+
// cerr<<'"'<<v.toString()<<'"'<<endl;
356359

357360
vector<DNSName> right;
358361
for(const auto& a: {"bert.com.", "Aleph1.powerdns.com.",
@@ -364,6 +367,7 @@ BOOST_AUTO_TEST_CASE(test_compare_canonical) {
364367
"yyy.XXX."})
365368
right.push_back(DNSName(a));
366369

370+
367371
BOOST_CHECK(vec==right);
368372
}
369373

0 commit comments

Comments
 (0)