File indexing completed on 2025-01-05 04:37:23
0001 /* 0002 SPDX-FileCopyrightText: 2010 Joris Guisson <joris.guisson@gmail.com> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "superseeder.h" 0008 #include "chunkcounter.h" 0009 0010 #include <QRandomGenerator> 0011 0012 #include <interfaces/peerinterface.h> 0013 #include <util/log.h> 0014 0015 namespace bt 0016 { 0017 SuperSeeder::SuperSeeder(Uint32 num_chunks) 0018 : chunk_counter(new ChunkCounter(num_chunks)) 0019 , num_seeders(0) 0020 { 0021 } 0022 0023 SuperSeeder::~SuperSeeder() 0024 { 0025 } 0026 0027 void SuperSeeder::have(PeerInterface *peer, Uint32 chunk) 0028 { 0029 chunk_counter->inc(chunk); 0030 if (peer->getBitSet().allOn()) // it is possible the peer has become a seeder 0031 num_seeders++; 0032 0033 QList<PeerInterface *> peers; 0034 0035 ActiveChunkItr i = active_chunks.find(chunk); 0036 while (i != active_chunks.end() && i.key() == chunk) { 0037 // Somebody else has an active chunk we sent to p2 0038 PeerInterface *p2 = i.value(); 0039 if (peer != p2) { 0040 active_peers.remove(p2); 0041 i = active_chunks.erase(i); 0042 // p2 has probably been a good boy, he can download another chunk from us 0043 peers.append(p2); 0044 } else 0045 ++i; 0046 } 0047 0048 for (PeerInterface *p : std::as_const(peers)) { 0049 sendChunk(p); 0050 } 0051 } 0052 0053 void SuperSeeder::haveAll(PeerInterface *peer) 0054 { 0055 // Lets just ignore seeders 0056 if (active_peers.contains(peer)) { 0057 Uint32 chunk = active_peers[peer]; 0058 active_chunks.remove(chunk, peer); 0059 active_peers.remove(peer); 0060 } 0061 0062 num_seeders++; 0063 } 0064 0065 void SuperSeeder::bitset(PeerInterface *peer, const bt::BitSet &bs) 0066 { 0067 if (bs.allOn()) { 0068 haveAll(peer); 0069 return; 0070 } 0071 0072 // Call have for each chunk the peer has 0073 for (Uint32 i = 0; i < bs.getNumBits(); i++) { 0074 if (bs.get(i)) 0075 have(peer, i); 0076 } 0077 } 0078 0079 void SuperSeeder::peerAdded(PeerInterface *peer) 0080 { 0081 if (peer->getBitSet().allOn()) { 0082 num_seeders++; 0083 } else { 0084 chunk_counter->incBitSet(peer->getBitSet()); 0085 sendChunk(peer); 0086 } 0087 } 0088 0089 void SuperSeeder::peerRemoved(PeerInterface *peer) 0090 { 0091 // remove the peer 0092 if (active_peers.contains(peer)) { 0093 Uint32 chunk = active_peers[peer]; 0094 active_chunks.remove(chunk, peer); 0095 active_peers.remove(peer); 0096 } 0097 0098 // decrease num_seeders if the peer is a seeder 0099 if (peer->getBitSet().allOn() && num_seeders > 0) 0100 num_seeders--; 0101 0102 chunk_counter->decBitSet(peer->getBitSet()); 0103 } 0104 0105 void SuperSeeder::sendChunk(PeerInterface *peer) 0106 { 0107 if (active_peers.contains(peer)) 0108 return; 0109 0110 const BitSet &bs = peer->getBitSet(); 0111 if (bs.allOn()) 0112 return; 0113 0114 // Use random chunk to start searching for a potential chunk we can send 0115 Uint32 num_chunks = chunk_counter->getNumChunks(); 0116 Uint32 start = QRandomGenerator::global()->bounded(num_chunks); 0117 Uint32 chunk = (start + 1) % num_chunks; 0118 Uint32 alternative = num_chunks; 0119 while (chunk != start) { 0120 chunk = (chunk + 1) % num_chunks; 0121 if (bs.get(chunk)) 0122 continue; 0123 0124 // If we can find a chunk which nobody has, use that 0125 // keep track of alternatives, if none is found 0126 if (chunk_counter->get(chunk) - num_seeders == 0) { 0127 peer->chunkAllowed(chunk); 0128 active_chunks.insert(chunk, peer); 0129 active_peers[peer] = chunk; 0130 return; 0131 } else if (alternative == num_chunks) { 0132 alternative = chunk; 0133 } 0134 } 0135 0136 if (alternative < num_chunks) { 0137 peer->chunkAllowed(chunk); 0138 active_chunks.insert(chunk, peer); 0139 active_peers[peer] = chunk; 0140 } 0141 } 0142 0143 void SuperSeeder::dump() 0144 { 0145 Out(SYS_GEN | LOG_DEBUG) << "Active chunks: " << endl; 0146 ActiveChunkItr i = active_chunks.begin(); 0147 while (i != active_chunks.end()) { 0148 Out(SYS_GEN | LOG_DEBUG) << "Chunk " << i.key() << " : " << i.value()->getPeerID().toString() << endl; 0149 ++i; 0150 } 0151 0152 Out(SYS_GEN | LOG_DEBUG) << "Active peers: " << endl; 0153 ActivePeerItr j = active_peers.begin(); 0154 while (j != active_peers.end()) { 0155 Out(SYS_GEN | LOG_DEBUG) << "Peer " << j.key()->getPeerID().toString() << " : " << j.value() << endl; 0156 ++j; 0157 } 0158 } 0159 0160 }