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 }