Skip to content

Commit fb203ca

Browse files
committed
Merge pull request #4508
b069750 Break up CAddrMan's IMPLEMENT_SERIALIZE (Pieter Wuille)
2 parents c4f11ca + b069750 commit fb203ca

File tree

2 files changed

+160
-129
lines changed

2 files changed

+160
-129
lines changed

src/addrman.h

Lines changed: 131 additions & 129 deletions
Original file line numberDiff line numberDiff line change
@@ -245,140 +245,142 @@ class CAddrMan
245245
void Connected_(const CService &addr, int64_t nTime);
246246

247247
public:
248+
// serialized format:
249+
// * version byte (currently 0)
250+
// * nKey
251+
// * nNew
252+
// * nTried
253+
// * number of "new" buckets
254+
// * all nNew addrinfos in vvNew
255+
// * all nTried addrinfos in vvTried
256+
// * for each bucket:
257+
// * number of elements
258+
// * for each element: index
259+
//
260+
// Notice that vvTried, mapAddr and vVector are never encoded explicitly;
261+
// they are instead reconstructed from the other information.
262+
//
263+
// vvNew is serialized, but only used if ADDRMAN_UNKOWN_BUCKET_COUNT didn't change,
264+
// otherwise it is reconstructed as well.
265+
//
266+
// This format is more complex, but significantly smaller (at most 1.5 MiB), and supports
267+
// changes to the ADDRMAN_ parameters without breaking the on-disk structure.
268+
//
269+
// We don't use IMPLEMENT_SERIALIZE since the serialization and deserialization code has
270+
// very little in common.
271+
template<typename Stream>
272+
void Serialize(Stream &s, int nType, int nVersionDummy) const
273+
{
274+
LOCK(cs);
275+
276+
unsigned char nVersion = 0;
277+
s << nVersion;
278+
s << nKey;
279+
s << nNew;
280+
s << nTried;
281+
282+
int nUBuckets = ADDRMAN_NEW_BUCKET_COUNT;
283+
s << nUBuckets;
284+
std::map<int, int> mapUnkIds;
285+
int nIds = 0;
286+
for (std::map<int, CAddrInfo>::const_iterator it = mapInfo.begin(); it != mapInfo.end(); it++) {
287+
if (nIds == nNew) break; // this means nNew was wrong, oh ow
288+
mapUnkIds[(*it).first] = nIds;
289+
const CAddrInfo &info = (*it).second;
290+
if (info.nRefCount) {
291+
s << info;
292+
nIds++;
293+
}
294+
}
295+
nIds = 0;
296+
for (std::map<int, CAddrInfo>::const_iterator it = mapInfo.begin(); it != mapInfo.end(); it++) {
297+
if (nIds == nTried) break; // this means nTried was wrong, oh ow
298+
const CAddrInfo &info = (*it).second;
299+
if (info.fInTried) {
300+
s << info;
301+
nIds++;
302+
}
303+
}
304+
for (std::vector<std::set<int> >::const_iterator it = vvNew.begin(); it != vvNew.end(); it++) {
305+
const std::set<int> &vNew = (*it);
306+
int nSize = vNew.size();
307+
s << nSize;
308+
for (std::set<int>::const_iterator it2 = vNew.begin(); it2 != vNew.end(); it2++) {
309+
int nIndex = mapUnkIds[*it2];
310+
s << nIndex;
311+
}
312+
}
313+
}
248314

249-
IMPLEMENT_SERIALIZE
250-
(({
251-
// serialized format:
252-
// * version byte (currently 0)
253-
// * nKey
254-
// * nNew
255-
// * nTried
256-
// * number of "new" buckets
257-
// * all nNew addrinfos in vvNew
258-
// * all nTried addrinfos in vvTried
259-
// * for each bucket:
260-
// * number of elements
261-
// * for each element: index
262-
//
263-
// Notice that vvTried, mapAddr and vVector are never encoded explicitly;
264-
// they are instead reconstructed from the other information.
265-
//
266-
// vvNew is serialized, but only used if ADDRMAN_UNKOWN_BUCKET_COUNT didn't change,
267-
// otherwise it is reconstructed as well.
268-
//
269-
// This format is more complex, but significantly smaller (at most 1.5 MiB), and supports
270-
// changes to the ADDRMAN_ parameters without breaking the on-disk structure.
271-
{
272-
LOCK(cs);
273-
unsigned char nVersion = 0;
274-
READWRITE(nVersion);
275-
READWRITE(nKey);
276-
READWRITE(nNew);
277-
READWRITE(nTried);
278-
279-
CAddrMan *am = const_cast<CAddrMan*>(this);
280-
if (fWrite)
281-
{
282-
int nUBuckets = ADDRMAN_NEW_BUCKET_COUNT;
283-
READWRITE(nUBuckets);
284-
std::map<int, int> mapUnkIds;
285-
int nIds = 0;
286-
for (std::map<int, CAddrInfo>::iterator it = am->mapInfo.begin(); it != am->mapInfo.end(); it++)
287-
{
288-
if (nIds == nNew) break; // this means nNew was wrong, oh ow
289-
mapUnkIds[(*it).first] = nIds;
290-
CAddrInfo &info = (*it).second;
291-
if (info.nRefCount)
292-
{
293-
READWRITE(info);
294-
nIds++;
295-
}
296-
}
297-
nIds = 0;
298-
for (std::map<int, CAddrInfo>::iterator it = am->mapInfo.begin(); it != am->mapInfo.end(); it++)
299-
{
300-
if (nIds == nTried) break; // this means nTried was wrong, oh ow
301-
CAddrInfo &info = (*it).second;
302-
if (info.fInTried)
303-
{
304-
READWRITE(info);
305-
nIds++;
306-
}
307-
}
308-
for (std::vector<std::set<int> >::iterator it = am->vvNew.begin(); it != am->vvNew.end(); it++)
309-
{
310-
const std::set<int> &vNew = (*it);
311-
int nSize = vNew.size();
312-
READWRITE(nSize);
313-
for (std::set<int>::iterator it2 = vNew.begin(); it2 != vNew.end(); it2++)
314-
{
315-
int nIndex = mapUnkIds[*it2];
316-
READWRITE(nIndex);
317-
}
318-
}
315+
template<typename Stream>
316+
void Unserialize(Stream& s, int nType, int nVersionDummy)
317+
{
318+
LOCK(cs);
319+
320+
unsigned char nVersion;
321+
s >> nVersion;
322+
s >> nKey;
323+
s >> nNew;
324+
s >> nTried;
325+
326+
int nUBuckets = 0;
327+
s >> nUBuckets;
328+
nIdCount = 0;
329+
mapInfo.clear();
330+
mapAddr.clear();
331+
vRandom.clear();
332+
vvTried = std::vector<std::vector<int> >(ADDRMAN_TRIED_BUCKET_COUNT, std::vector<int>(0));
333+
vvNew = std::vector<std::set<int> >(ADDRMAN_NEW_BUCKET_COUNT, std::set<int>());
334+
for (int n = 0; n < nNew; n++) {
335+
CAddrInfo &info = mapInfo[n];
336+
s >> info;
337+
mapAddr[info] = n;
338+
info.nRandomPos = vRandom.size();
339+
vRandom.push_back(n);
340+
if (nUBuckets != ADDRMAN_NEW_BUCKET_COUNT) {
341+
vvNew[info.GetNewBucket(nKey)].insert(n);
342+
info.nRefCount++;
343+
}
344+
}
345+
nIdCount = nNew;
346+
int nLost = 0;
347+
for (int n = 0; n < nTried; n++) {
348+
CAddrInfo info;
349+
s >> info;
350+
std::vector<int> &vTried = vvTried[info.GetTriedBucket(nKey)];
351+
if (vTried.size() < ADDRMAN_TRIED_BUCKET_SIZE) {
352+
info.nRandomPos = vRandom.size();
353+
info.fInTried = true;
354+
vRandom.push_back(nIdCount);
355+
mapInfo[nIdCount] = info;
356+
mapAddr[info] = nIdCount;
357+
vTried.push_back(nIdCount);
358+
nIdCount++;
319359
} else {
320-
int nUBuckets = 0;
321-
READWRITE(nUBuckets);
322-
am->nIdCount = 0;
323-
am->mapInfo.clear();
324-
am->mapAddr.clear();
325-
am->vRandom.clear();
326-
am->vvTried = std::vector<std::vector<int> >(ADDRMAN_TRIED_BUCKET_COUNT, std::vector<int>(0));
327-
am->vvNew = std::vector<std::set<int> >(ADDRMAN_NEW_BUCKET_COUNT, std::set<int>());
328-
for (int n = 0; n < am->nNew; n++)
329-
{
330-
CAddrInfo &info = am->mapInfo[n];
331-
READWRITE(info);
332-
am->mapAddr[info] = n;
333-
info.nRandomPos = vRandom.size();
334-
am->vRandom.push_back(n);
335-
if (nUBuckets != ADDRMAN_NEW_BUCKET_COUNT)
336-
{
337-
am->vvNew[info.GetNewBucket(am->nKey)].insert(n);
338-
info.nRefCount++;
339-
}
340-
}
341-
am->nIdCount = am->nNew;
342-
int nLost = 0;
343-
for (int n = 0; n < am->nTried; n++)
344-
{
345-
CAddrInfo info;
346-
READWRITE(info);
347-
std::vector<int> &vTried = am->vvTried[info.GetTriedBucket(am->nKey)];
348-
if (vTried.size() < ADDRMAN_TRIED_BUCKET_SIZE)
349-
{
350-
info.nRandomPos = vRandom.size();
351-
info.fInTried = true;
352-
am->vRandom.push_back(am->nIdCount);
353-
am->mapInfo[am->nIdCount] = info;
354-
am->mapAddr[info] = am->nIdCount;
355-
vTried.push_back(am->nIdCount);
356-
am->nIdCount++;
357-
} else {
358-
nLost++;
359-
}
360-
}
361-
am->nTried -= nLost;
362-
for (int b = 0; b < nUBuckets; b++)
363-
{
364-
std::set<int> &vNew = am->vvNew[b];
365-
int nSize = 0;
366-
READWRITE(nSize);
367-
for (int n = 0; n < nSize; n++)
368-
{
369-
int nIndex = 0;
370-
READWRITE(nIndex);
371-
CAddrInfo &info = am->mapInfo[nIndex];
372-
if (nUBuckets == ADDRMAN_NEW_BUCKET_COUNT && info.nRefCount < ADDRMAN_NEW_BUCKETS_PER_ADDRESS)
373-
{
374-
info.nRefCount++;
375-
vNew.insert(nIndex);
376-
}
377-
}
360+
nLost++;
361+
}
362+
}
363+
nTried -= nLost;
364+
for (int b = 0; b < nUBuckets; b++) {
365+
std::set<int> &vNew = vvNew[b];
366+
int nSize = 0;
367+
s >> nSize;
368+
for (int n = 0; n < nSize; n++) {
369+
int nIndex = 0;
370+
s >> nIndex;
371+
CAddrInfo &info = mapInfo[nIndex];
372+
if (nUBuckets == ADDRMAN_NEW_BUCKET_COUNT && info.nRefCount < ADDRMAN_NEW_BUCKETS_PER_ADDRESS) {
373+
info.nRefCount++;
374+
vNew.insert(nIndex);
378375
}
379376
}
380377
}
381-
});)
378+
}
379+
380+
unsigned int GetSerializeSize(int nType, int nVersion) const
381+
{
382+
return (CSizeComputer(nType, nVersion) << *this).size();
383+
}
382384

383385
CAddrMan() : vRandom(0), vvTried(ADDRMAN_TRIED_BUCKET_COUNT, std::vector<int>(0)), vvNew(ADDRMAN_NEW_BUCKET_COUNT, std::set<int>())
384386
{

src/serialize.h

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -830,6 +830,35 @@ struct ser_streamplaceholder
830830

831831
typedef std::vector<char, zero_after_free_allocator<char> > CSerializeData;
832832

833+
class CSizeComputer
834+
{
835+
protected:
836+
size_t nSize;
837+
838+
public:
839+
int nType;
840+
int nVersion;
841+
842+
CSizeComputer(int nTypeIn, int nVersionIn) : nSize(0), nType(nTypeIn), nVersion(nVersionIn) {}
843+
844+
CSizeComputer& write(const char *psz, int nSize)
845+
{
846+
this->nSize += nSize;
847+
return *this;
848+
}
849+
850+
template<typename T>
851+
CSizeComputer& operator<<(const T& obj)
852+
{
853+
::Serialize(*this, obj, nType, nVersion);
854+
return (*this);
855+
}
856+
857+
size_t size() const {
858+
return nSize;
859+
}
860+
};
861+
833862
/** Double ended buffer combining vector and stream-like interfaces.
834863
*
835864
* >> and << read and write unformatted data using the above serialization templates.

0 commit comments

Comments
 (0)