@@ -14,12 +14,12 @@ int CAddrInfo::GetTriedBucket(const uint256& nKey) const
1414{
1515 CDataStream ss1 (SER_GETHASH, 0 );
1616 std::vector<unsigned char > vchKey = GetKey ();
17- ss1 << (( unsigned char ) 32 ) << nKey << vchKey;
17+ ss1 << nKey << vchKey;
1818 uint64_t hash1 = Hash (ss1.begin (), ss1.end ()).GetCheapHash ();
1919
2020 CDataStream ss2 (SER_GETHASH, 0 );
2121 std::vector<unsigned char > vchGroupKey = GetGroup ();
22- ss2 << (( unsigned char ) 32 ) << nKey << vchGroupKey << (hash1 % ADDRMAN_TRIED_BUCKETS_PER_GROUP);
22+ ss2 << nKey << vchGroupKey << (hash1 % ADDRMAN_TRIED_BUCKETS_PER_GROUP);
2323 uint64_t hash2 = Hash (ss2.begin (), ss2.end ()).GetCheapHash ();
2424 return hash2 % ADDRMAN_TRIED_BUCKET_COUNT;
2525}
@@ -29,15 +29,24 @@ int CAddrInfo::GetNewBucket(const uint256& nKey, const CNetAddr& src) const
2929 CDataStream ss1 (SER_GETHASH, 0 );
3030 std::vector<unsigned char > vchGroupKey = GetGroup ();
3131 std::vector<unsigned char > vchSourceGroupKey = src.GetGroup ();
32- ss1 << (( unsigned char ) 32 ) << nKey << vchGroupKey << vchSourceGroupKey;
32+ ss1 << nKey << vchGroupKey << vchSourceGroupKey;
3333 uint64_t hash1 = Hash (ss1.begin (), ss1.end ()).GetCheapHash ();
3434
3535 CDataStream ss2 (SER_GETHASH, 0 );
36- ss2 << (( unsigned char ) 32 ) << nKey << vchSourceGroupKey << (hash1 % ADDRMAN_NEW_BUCKETS_PER_SOURCE_GROUP);
36+ ss2 << nKey << vchSourceGroupKey << (hash1 % ADDRMAN_NEW_BUCKETS_PER_SOURCE_GROUP);
3737 uint64_t hash2 = Hash (ss2.begin (), ss2.end ()).GetCheapHash ();
3838 return hash2 % ADDRMAN_NEW_BUCKET_COUNT;
3939}
4040
41+ int CAddrInfo::GetBucketPosition (const uint256 &nKey, bool fNew , int nBucket) const
42+ {
43+ CDataStream ss1 (SER_GETHASH, 0 );
44+ std::vector<unsigned char > vchKey = GetKey ();
45+ ss1 << nKey << (fNew ? ' N' : ' K' ) << nBucket << vchKey;
46+ uint64_t hash1 = Hash (ss1.begin (), ss1.end ()).GetCheapHash ();
47+ return hash1 % ADDRMAN_BUCKET_SIZE;
48+ }
49+
4150bool CAddrInfo::IsTerrible (int64_t nNow) const
4251{
4352 if (nLastTry && nLastTry >= nNow - 60 ) // never remove things tried in the last minute
@@ -128,130 +137,81 @@ void CAddrMan::SwapRandom(unsigned int nRndPos1, unsigned int nRndPos2)
128137 vRandom[nRndPos2] = nId1;
129138}
130139
131- int CAddrMan::SelectTried (int nKBucket )
140+ void CAddrMan::Delete (int nId )
132141{
133- std::vector<int >& vTried = vvTried[nKBucket];
134-
135- // randomly shuffle the first few elements (using the entire list)
136- // find the least recently tried among them
137- int64_t nOldest = -1 ;
138- int nOldestPos = -1 ;
139- for (unsigned int i = 0 ; i < ADDRMAN_TRIED_ENTRIES_INSPECT_ON_EVICT && i < vTried.size (); i++) {
140- int nPos = GetRandInt (vTried.size () - i) + i;
141- int nTemp = vTried[nPos];
142- vTried[nPos] = vTried[i];
143- vTried[i] = nTemp;
144- assert (nOldest == -1 || mapInfo.count (nTemp) == 1 );
145- if (nOldest == -1 || mapInfo[nTemp].nLastSuccess < mapInfo[nOldest].nLastSuccess ) {
146- nOldest = nTemp;
147- nOldestPos = nPos;
148- }
149- }
142+ assert (mapInfo.count (nId) != 0 );
143+ CAddrInfo& info = mapInfo[nId];
144+ assert (!info.fInTried );
145+ assert (info.nRefCount == 0 );
150146
151- return nOldestPos;
147+ SwapRandom (info.nRandomPos , vRandom.size () - 1 );
148+ vRandom.pop_back ();
149+ mapAddr.erase (info);
150+ mapInfo.erase (nId);
151+ nNew--;
152152}
153153
154- int CAddrMan::ShrinkNew (int nUBucket)
154+ void CAddrMan::ClearNew (int nUBucket, int nUBucketPos )
155155{
156- assert (nUBucket >= 0 && (unsigned int )nUBucket < vvNew.size ());
157- std::set<int >& vNew = vvNew[nUBucket];
158-
159- // first look for deletable items
160- for (std::set<int >::iterator it = vNew.begin (); it != vNew.end (); it++) {
161- assert (mapInfo.count (*it));
162- CAddrInfo& info = mapInfo[*it];
163- if (info.IsTerrible ()) {
164- if (--info.nRefCount == 0 ) {
165- SwapRandom (info.nRandomPos , vRandom.size () - 1 );
166- vRandom.pop_back ();
167- mapAddr.erase (info);
168- mapInfo.erase (*it);
169- nNew--;
170- }
171- vNew.erase (it);
172- return 0 ;
173- }
174- }
175-
176- // otherwise, select four randomly, and pick the oldest of those to replace
177- int n[4 ] = {GetRandInt (vNew.size ()), GetRandInt (vNew.size ()), GetRandInt (vNew.size ()), GetRandInt (vNew.size ())};
178- int nI = 0 ;
179- int nOldest = -1 ;
180- for (std::set<int >::iterator it = vNew.begin (); it != vNew.end (); it++) {
181- if (nI == n[0 ] || nI == n[1 ] || nI == n[2 ] || nI == n[3 ]) {
182- assert (nOldest == -1 || mapInfo.count (*it) == 1 );
183- if (nOldest == -1 || mapInfo[*it].nTime < mapInfo[nOldest].nTime )
184- nOldest = *it;
156+ // if there is an entry in the specified bucket, delete it.
157+ if (vvNew[nUBucket][nUBucketPos] != -1 ) {
158+ int nIdDelete = vvNew[nUBucket][nUBucketPos];
159+ CAddrInfo& infoDelete = mapInfo[nIdDelete];
160+ assert (infoDelete.nRefCount > 0 );
161+ infoDelete.nRefCount --;
162+ vvNew[nUBucket][nUBucketPos] = -1 ;
163+ if (infoDelete.nRefCount == 0 ) {
164+ Delete (nIdDelete);
185165 }
186- nI++;
187- }
188- assert (mapInfo.count (nOldest) == 1 );
189- CAddrInfo& info = mapInfo[nOldest];
190- if (--info.nRefCount == 0 ) {
191- SwapRandom (info.nRandomPos , vRandom.size () - 1 );
192- vRandom.pop_back ();
193- mapAddr.erase (info);
194- mapInfo.erase (nOldest);
195- nNew--;
196166 }
197- vNew.erase (nOldest);
198-
199- return 1 ;
200167}
201168
202- void CAddrMan::MakeTried (CAddrInfo& info, int nId, int nOrigin )
169+ void CAddrMan::MakeTried (CAddrInfo& info, int nId)
203170{
204- assert (vvNew[nOrigin].count (nId) == 1 );
205-
206171 // remove the entry from all new buckets
207- for (std::vector<std::set<int > >::iterator it = vvNew.begin (); it != vvNew.end (); it++) {
208- if ((*it).erase (nId))
172+ for (int bucket = 0 ; bucket < ADDRMAN_NEW_BUCKET_COUNT; bucket++) {
173+ int pos = info.GetBucketPosition (nKey, true , bucket);
174+ if (vvNew[bucket][pos] == nId) {
175+ vvNew[bucket][pos] = -1 ;
209176 info.nRefCount --;
177+ }
210178 }
211179 nNew--;
212180
213181 assert (info.nRefCount == 0 );
214182
215183 // which tried bucket to move the entry to
216184 int nKBucket = info.GetTriedBucket (nKey);
217- std::vector<int >& vTried = vvTried[nKBucket];
218-
219- // first check whether there is place to just add it
220- if (vTried.size () < ADDRMAN_TRIED_BUCKET_SIZE) {
221- vTried.push_back (nId);
222- nTried++;
223- info.fInTried = true ;
224- return ;
225- }
226-
227- // otherwise, find an item to evict
228- int nPos = SelectTried (nKBucket);
229-
230- // find which new bucket it belongs to
231- assert (mapInfo.count (vTried[nPos]) == 1 );
232- int nUBucket = mapInfo[vTried[nPos]].GetNewBucket (nKey);
233- std::set<int >& vNew = vvNew[nUBucket];
234-
235- // remove the to-be-replaced tried entry from the tried set
236- CAddrInfo& infoOld = mapInfo[vTried[nPos]];
237- infoOld.fInTried = false ;
238- infoOld.nRefCount = 1 ;
239- // do not update nTried, as we are going to move something else there immediately
240-
241- // check whether there is place in that one,
242- if (vNew.size () < ADDRMAN_NEW_BUCKET_SIZE) {
243- // if so, move it back there
244- vNew.insert (vTried[nPos]);
245- } else {
246- // otherwise, move it to the new bucket nId came from (there is certainly place there)
247- vvNew[nOrigin].insert (vTried[nPos]);
185+ int nKBucketPos = info.GetBucketPosition (nKey, false , nKBucket);
186+
187+ // first make space to add it (the existing tried entry there is moved to new, deleting whatever is there).
188+ if (vvTried[nKBucket][nKBucketPos] != -1 ) {
189+ // find an item to evict
190+ int nIdEvict = vvTried[nKBucket][nKBucketPos];
191+ assert (mapInfo.count (nIdEvict) == 1 );
192+ CAddrInfo& infoOld = mapInfo[nIdEvict];
193+
194+ // Remove the to-be-evicted item from the tried set.
195+ infoOld.fInTried = false ;
196+ vvTried[nKBucket][nKBucketPos] = -1 ;
197+ nTried--;
198+
199+ // find which new bucket it belongs to
200+ int nUBucket = infoOld.GetNewBucket (nKey);
201+ int nUBucketPos = infoOld.GetBucketPosition (nKey, true , nUBucket);
202+ ClearNew (nUBucket, nUBucketPos);
203+ assert (vvNew[nUBucket][nUBucketPos] == -1 );
204+
205+ // Enter it into the new set again.
206+ infoOld.nRefCount = 1 ;
207+ vvNew[nUBucket][nUBucketPos] = nIdEvict;
208+ nNew++;
248209 }
249- nNew++ ;
210+ assert (vvTried[nKBucket][nKBucketPos] == - 1 ) ;
250211
251- vTried[nPos ] = nId;
252- // we just overwrote an entry in vTried; no need to update nTried
212+ vvTried[nKBucket][nKBucketPos ] = nId;
213+ nTried++;
253214 info.fInTried = true ;
254- return ;
255215}
256216
257217void CAddrMan::Good_ (const CService& addr, int64_t nTime)
@@ -281,12 +241,12 @@ void CAddrMan::Good_(const CService& addr, int64_t nTime)
281241 return ;
282242
283243 // find a bucket it is in now
284- int nRnd = GetRandInt (vvNew. size () );
244+ int nRnd = GetRandInt (ADDRMAN_NEW_BUCKET_COUNT );
285245 int nUBucket = -1 ;
286- for (unsigned int n = 0 ; n < vvNew. size () ; n++) {
287- int nB = (n + nRnd) % vvNew. size () ;
288- std::set< int >& vNew = vvNew[nB] ;
289- if (vNew. count ( nId) ) {
246+ for (unsigned int n = 0 ; n < ADDRMAN_NEW_BUCKET_COUNT ; n++) {
247+ int nB = (n + nRnd) % ADDRMAN_NEW_BUCKET_COUNT ;
248+ int nBpos = info. GetBucketPosition (nKey, true , nB) ;
249+ if (vvNew[nB][nBpos] == nId) {
290250 nUBucket = nB;
291251 break ;
292252 }
@@ -300,7 +260,7 @@ void CAddrMan::Good_(const CService& addr, int64_t nTime)
300260 LogPrint (" addrman" , " Moving %s to tried\n " , addr.ToString ());
301261
302262 // move nId to the tried tables
303- MakeTried (info, nId, nUBucket );
263+ MakeTried (info, nId);
304264}
305265
306266bool CAddrMan::Add_ (const CAddress& addr, const CNetAddr& source, int64_t nTimePenalty)
@@ -348,12 +308,25 @@ bool CAddrMan::Add_(const CAddress& addr, const CNetAddr& source, int64_t nTimeP
348308 }
349309
350310 int nUBucket = pinfo->GetNewBucket (nKey, source);
351- std::set<int >& vNew = vvNew[nUBucket];
352- if (!vNew.count (nId)) {
353- pinfo->nRefCount ++;
354- if (vNew.size () == ADDRMAN_NEW_BUCKET_SIZE)
355- ShrinkNew (nUBucket);
356- vvNew[nUBucket].insert (nId);
311+ int nUBucketPos = pinfo->GetBucketPosition (nKey, true , nUBucket);
312+ if (vvNew[nUBucket][nUBucketPos] != nId) {
313+ bool fInsert = vvNew[nUBucket][nUBucketPos] == -1 ;
314+ if (!fInsert ) {
315+ CAddrInfo& infoExisting = mapInfo[vvNew[nUBucket][nUBucketPos]];
316+ if (infoExisting.IsTerrible () || (infoExisting.nRefCount > 1 && pinfo->nRefCount == 0 )) {
317+ // Overwrite the existing new table entry.
318+ fInsert = true ;
319+ }
320+ }
321+ if (fInsert ) {
322+ ClearNew (nUBucket, nUBucketPos);
323+ pinfo->nRefCount ++;
324+ vvNew[nUBucket][nUBucketPos] = nId;
325+ } else {
326+ if (pinfo->nRefCount == 0 ) {
327+ Delete (nId);
328+ }
329+ }
357330 }
358331 return fNew ;
359332}
@@ -388,13 +361,13 @@ CAddress CAddrMan::Select_(int nUnkBias)
388361 // use a tried node
389362 double fChanceFactor = 1.0 ;
390363 while (1 ) {
391- int nKBucket = GetRandInt (vvTried. size () );
392- std::vector< int >& vTried = vvTried[nKBucket] ;
393- if (vTried. size () == 0 )
364+ int nKBucket = GetRandInt (ADDRMAN_TRIED_BUCKET_COUNT );
365+ int nKBucketPos = GetRandInt (ADDRMAN_BUCKET_SIZE) ;
366+ if (vvTried[nKBucket][nKBucketPos] == - 1 )
394367 continue ;
395- int nPos = GetRandInt (vTried. size ()) ;
396- assert (mapInfo.count (vTried[nPos] ) == 1 );
397- CAddrInfo& info = mapInfo[vTried[nPos] ];
368+ int nId = vvTried[nKBucket][nKBucketPos] ;
369+ assert (mapInfo.count (nId ) == 1 );
370+ CAddrInfo& info = mapInfo[nId ];
398371 if (GetRandInt (1 << 30 ) < fChanceFactor * info.GetChance () * (1 << 30 ))
399372 return info;
400373 fChanceFactor *= 1.2 ;
@@ -403,16 +376,13 @@ CAddress CAddrMan::Select_(int nUnkBias)
403376 // use a new node
404377 double fChanceFactor = 1.0 ;
405378 while (1 ) {
406- int nUBucket = GetRandInt (vvNew. size () );
407- std::set< int >& vNew = vvNew[nUBucket] ;
408- if (vNew. size () == 0 )
379+ int nUBucket = GetRandInt (ADDRMAN_NEW_BUCKET_COUNT );
380+ int nUBucketPos = GetRandInt (ADDRMAN_BUCKET_SIZE) ;
381+ if (vvNew[nUBucket][nUBucketPos] == - 1 )
409382 continue ;
410- int nPos = GetRandInt (vNew.size ());
411- std::set<int >::iterator it = vNew.begin ();
412- while (nPos--)
413- it++;
414- assert (mapInfo.count (*it) == 1 );
415- CAddrInfo& info = mapInfo[*it];
383+ int nId = vvNew[nUBucket][nUBucketPos];
384+ assert (mapInfo.count (nId) == 1 );
385+ CAddrInfo& info = mapInfo[nId];
416386 if (GetRandInt (1 << 30 ) < fChanceFactor * info.GetChance () * (1 << 30 ))
417387 return info;
418388 fChanceFactor *= 1.2 ;
@@ -460,22 +430,30 @@ int CAddrMan::Check_()
460430 if (mapNew.size () != nNew)
461431 return -10 ;
462432
463- for (int n = 0 ; n < vvTried.size (); n++) {
464- std::vector<int >& vTried = vvTried[n];
465- for (std::vector<int >::iterator it = vTried.begin (); it != vTried.end (); it++) {
466- if (!setTried.count (*it))
467- return -11 ;
468- setTried.erase (*it);
433+ for (int n = 0 ; n < ADDRMAN_TRIED_BUCKET_COUNT; n++) {
434+ for (int i = 0 ; i < ADDRMAN_BUCKET_SIZE; i++) {
435+ if (vvTried[n][i] != -1 ) {
436+ if (!setTried.count (vvTried[n][i]))
437+ return -11 ;
438+ if (mapInfo[vvTried[n][i]].GetTriedBucket (nKey) != n)
439+ return -17 ;
440+ if (mapInfo[vvTried[n][i]].GetBucketPosition (nKey, false , n) != i)
441+ return -18 ;
442+ setTried.erase (vvTried[n][i]);
443+ }
469444 }
470445 }
471446
472- for (int n = 0 ; n < vvNew.size (); n++) {
473- std::set<int >& vNew = vvNew[n];
474- for (std::set<int >::iterator it = vNew.begin (); it != vNew.end (); it++) {
475- if (!mapNew.count (*it))
476- return -12 ;
477- if (--mapNew[*it] == 0 )
478- mapNew.erase (*it);
447+ for (int n = 0 ; n < ADDRMAN_NEW_BUCKET_COUNT; n++) {
448+ for (int i = 0 ; i < ADDRMAN_BUCKET_SIZE; i++) {
449+ if (vvNew[n][i] != -1 ) {
450+ if (!mapNew.count (vvNew[n][i]))
451+ return -12 ;
452+ if (mapInfo[vvNew[n][i]].GetBucketPosition (nKey, true , n) != i)
453+ return -19 ;
454+ if (--mapNew[vvNew[n][i]] == 0 )
455+ mapNew.erase (vvNew[n][i]);
456+ }
479457 }
480458 }
481459
0 commit comments