-
Notifications
You must be signed in to change notification settings - Fork 921
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
rec: store authority recs and signatures as shared pointers to const data #14985
rec: store authority recs and signatures as shared pointers to const data #14985
Conversation
…c of shared pointers to DNSRecs
This shows a modest increase in speed: 'null test' 0.11 seconds: 3222473473.3 runs/s, 0.00 us/run 'AuthRecordsTest' 0.10 seconds: 66.8 runs/s, 14977.88 us/run to 'null test' 0.10 seconds: 3223627246.4 runs/s, 0.00 us/run 'AuthRecordsTest' 0.11 seconds: 72.1 runs/s, 13868.26 us/run The test is: generate 100 records into the cache (each with an authRecord), retrieve each record 100 times.
Pull Request Test Coverage Report for Build 12631365029Warning: This coverage report may be inaccurate.This pull request's base commit is no longer the HEAD commit of its target branch. This means it includes changes from outside the original pull request, including, potentially, unrelated coverage changes.
Details
💛 - Coveralls |
pdns/recursordist/recursor_cache.cc
Outdated
*signatures = std::make_shared<SigRecsVec>(vec); | ||
} | ||
else { | ||
assert(*signatures == nullptr || (*signatures)->empty()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This feels wrong. If the condition above is not correct, we could get here with some entries in *signatures
as long as entry->d_signatures
doesn't contain any, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, the assert seems too strict.
pdns/recursordist/recursor_cache.cc
Outdated
// Return a new vec if we need to append to a non-empty vector | ||
SigRecsVec vec(**signatures); | ||
vec.insert(vec.end(), entry->d_signatures->cbegin(), entry->d_signatures->cend()); | ||
*signatures = std::make_shared<SigRecsVec>(vec); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it make sense to create the shared pointer right away and insert into it? Or at least to move vec
?
pdns/recursordist/recursor_cache.hh
Outdated
// pointer gets copied, while earlier code would copy all shared pointer in the vector. | ||
// | ||
// In the current SyncRes code, AuthRecs never get appended to a non-empty vector while SigRecs do | ||
// get appended in some cases; the handleHit() code will take measures. In the futrue we might |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// get appended in some cases; the handleHit() code will take measures. In the futrue we might | |
// get appended in some cases; the handleHit() code will take measures. In the future we might |
pdns/recursordist/recursor_cache.hh
Outdated
// | ||
// In the current SyncRes code, AuthRecs never get appended to a non-empty vector while SigRecs do | ||
// get appended in some cases; the handleHit() code will take measures. In the futrue we might | ||
// want a more specialized datastructure than a vector, it would require another level of |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// want a more specialized datastructure than a vector, it would require another level of | |
// want a more specialized data structure than a vector, it would require another level of |
pdns/recursordist/recursor_cache.cc
Outdated
@@ -1016,18 +1042,18 @@ void MemRecursorCache::getRecordSet(T& message, U recordSet) | |||
for (const auto& record : recordSet->d_records) { | |||
message.add_bytes(PBCacheEntry::repeated_bytes_record, record->serialize(recordSet->d_qname, true)); | |||
} | |||
for (const auto& record : recordSet->d_signatures) { | |||
for (const auto& record : *recordSet->d_signatures) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we need to check that d_signatures
is not nullptr
first.
pdns/recursordist/recursor_cache.cc
Outdated
message.add_bytes(PBCacheEntry::repeated_bytes_sig, record->serialize(recordSet->d_qname, true)); | ||
} | ||
for (const auto& authRec : recordSet->d_authorityRecs) { | ||
for (const auto& authRec : *recordSet->d_authorityRecs) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same.
pdns/recursordist/recursor_cache.cc
Outdated
if (!cacheEntry.d_signatures) { | ||
cacheEntry.d_signatures = std::make_shared<SigRecsVec>(); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this can go?
pdns/recursordist/recursor_cache.cc
Outdated
if (!cacheEntry.d_authorityRecs) { | ||
cacheEntry.d_authorityRecs = std::make_shared<AuthRecsVec>(); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same?
// store a shared pointer to the copied data. The shared pointer will be returned by get(). There | ||
// are optimizations: an empty vector will be stored as a nullptr, but get() will return a pointer | ||
// to an already existing empty vector in that case, this is more convenient for the caller, since | ||
// it avoid checking for nullptr, just iterate as for the non-empty case. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder how the optimization holds when we have a lot of threads: we avoid allocating memory which is good (but could be done in a thread-specific pool without any contention) at the cost of having (in some cases, which may be rare?) several threads atomically accessing and updating the same memory location (the shared reference counter). I guess the optimization is worth it if we do not cross NUMA-boundaries, and perhaps a bit less if we do?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point, when I was writing this I was wondering this as well. Many new/delete implementation use some form of locking as several threads share the same memory pool, so I was guessing it would be beneficial in the typical case. I do not have hard data, though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm OK with ignoring this unless/until it shows up in a performance profile :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
…be passed a nullptr
rec: followup to #14985: init shared pointers as get() might be passed a nullptr
Short description
Currently, we stored and return vectors, change this to store and return a shared pointer to const vectors. This allows us to return a single shared pointer on get(), avoiding to copy all vector elements.
This approach does not work for the answer records, as modified (e.g. TTL)
DNSRecord
s are returned.Speedup of get() of about 10% in a totally artificial test case of a single insert and many gets(). Should also save a bit on memory. We store
nullptr
for empty vectors and make sureget()
rerurns a ready-made empty vector in that case.This not only needs review on the detail level, but also on the general approach!
Checklist
I have: