SlotAllocator.cpp

Go to the documentation of this file.
00001 /*
00002 
00003 Copyright (C) 2006-2007 by Peter Dimov.
00004 
00005 This file is part of Calitko (http://www.calitko.org).
00006 
00007 Calitko is free software; you can redistribute it and/or modify
00008 it under the terms of the GNU General Public License as published by
00009 the Free Software Foundation; either version 2 of the License, or
00010 (at your option) any later version.
00011 
00012 Calitko is distributed in the hope that it will be useful,
00013 but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 GNU General Public License for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with Calitko; if not, write to the Free Software
00019 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00020 
00021 */
00022 
00023 #include "Qt.h"
00024 #include "SlotAllocator.h"
00025 #include "HandshakeSession.h"
00026 #include "Imports.cpp"
00027 
00028 using namespace Gnutella::Handshaking;
00029 
00030 namespace Gnutella {
00031 namespace Handshaking {
00032 
00033 enum Constants
00034 {
00035     TotalHandshakingSlots       = 5,
00036     TotalUltrapeerSlots         = 2,
00037     TotalPeerSlots              = 32,
00038     TotalLeafSlots              = 0,
00039     BootstrappingThreshold      = 4,
00040     WellConnectedThreshold      = 24
00041 };
00042 
00043 class SlotAllocatorPrivate
00044 {
00045     REFERENCE_OBJECT (SlotAllocatorPrivate)
00046 
00047 public:
00048     LocalPeer       *localPeer;
00049     uint            freeHandshakingSlots;
00050     uint            freeUltrapeerSlots;
00051     uint            freePeerSlots;
00052     uint            freeLeafSlots;
00053     QSignalMapper   destroyedMapper;
00054 
00055     SlotAllocatorPrivate (LocalPeer *localPeer_)
00056      :  localPeer (localPeer_),
00057         freeHandshakingSlots (TotalHandshakingSlots),
00058         freeUltrapeerSlots (TotalUltrapeerSlots),
00059         freePeerSlots (TotalPeerSlots),
00060         freeLeafSlots (TotalLeafSlots),
00061         destroyedMapper()
00062     {}
00063 };
00064 
00065 enum SlotType
00066 {
00067     HandshakingSlot,
00068     UltrapeerSlot,
00069     PeerSlot,
00070     LeafSlot
00071 };
00072 
00073 struct Slot
00074 {
00075     SlotType type;
00076 };
00077 
00078 } // namespace Handshaking;
00079 } // namespace Gnutella;
00080 
00081 uint SlotAllocator::freeHandshakingSlots() const
00082 {
00083     return (p->freeHandshakingSlots > 0) ? p->freeHandshakingSlots : 0;
00084 }
00085 
00086 uint SlotAllocator::freeUltrapeerSlots() const
00087 {
00088     return p->freeUltrapeerSlots;
00089 }
00090 
00091 uint SlotAllocator::freePeerSlots() const
00092 {
00093     return p->freePeerSlots;
00094 }
00095 
00096 uint SlotAllocator::freeLeafSlots() const
00097 {
00098     return p->freeLeafSlots;
00099 }
00100 
00101 /*
00102 uint SlotAllocator::usedHandshakingSlots() const
00103 {
00104     return TotalHandshakingSlots - p->freeHandshakingSlots;
00105 }
00106 
00107 uint SlotAllocator::usedUltrapeerSlots() const
00108 {
00109     return TotalUltrapeerSlots - p->freeUltrapeerSlots;
00110 }
00111 
00112 uint SlotAllocator::usedPeerSlots() const
00113 {
00114     return TotalPeerSlots - p->freePeerSlots;
00115 }
00116 
00117 uint SlotAllocator::usedLeafSlots() const
00118 {
00119     return TotalLeafSlots - p->freeLeafSlots;
00120 }
00121 */
00122 
00123 bool SlotAllocator::isBootstrapping() const
00124 {
00125     return (TotalPeerSlots - p->freePeerSlots) < BootstrappingThreshold;
00126 }
00127 
00128 bool SlotAllocator::isWellConnected() const
00129 {
00130     return (TotalPeerSlots - p->freePeerSlots) >= WellConnectedThreshold;
00131 }
00132 
00133 SlotAllocator::SlotAllocator (LocalPeer *localPeer)
00134  :  p (new SlotAllocatorPrivate (localPeer))
00135 {
00136     connect (&p->destroyedMapper, SIGNAL (mapped (QObject *)),
00137              this, SLOT (freeSlot (QObject *)));
00138 }
00139 
00140 SlotAllocator::~SlotAllocator()
00141 {
00142     delete p;
00143 }
00144 
00145 bool SlotAllocator::hasSlotFor (const NodeInfo &otherNodeInfo) const
00146 {
00147     if (!p->localPeer->isUltrapeer()) {
00148         return hasFreeUltrapeerSlots();
00149     } else {
00150         if (otherNodeInfo.type == TypeLeaf)
00151             return hasFreeLeafSlots();
00152         else
00153             return hasFreePeerSlots();
00154     }
00155 }
00156 
00157 bool SlotAllocator::allocateSlot (HandshakeSession *session)
00158 {
00159     qDebug() << "SlotAllocator::allocateSlot (handshakeSession)";
00160 
00161     Q_ASSERT (session != 0);
00164     p->freeHandshakingSlots--;
00165     Slot *slot = new Slot;
00166     slot->type = HandshakingSlot;
00167     connect (session, SIGNAL (destroyed()), &p->destroyedMapper, SLOT (map()));
00168     p->destroyedMapper.setMapping (session, reinterpret_cast <QObject *> (slot));
00169 
00170     qDebug() << "SlotAllocator::allocateSlot (handshakeSession) exit";
00171     return true;
00172 }
00173 
00174 bool SlotAllocator::allocateSlot (PacketSession *session)
00175 {
00176     qDebug() << "SlotAllocator::allocateSlot (packetSession)";
00177 
00178     NodeInfo otherNodeInfo = session->nodeInfo();
00179     if (!hasSlotFor (otherNodeInfo))
00180         return false;
00181 
00182     Slot *slot = new Slot;
00183     if (!p->localPeer->isUltrapeer()) {
00184         slot->type = UltrapeerSlot;
00185         Q_ASSERT (p->freeUltrapeerSlots > 0);
00186         p->freeUltrapeerSlots--;
00187     } else {
00188         if (otherNodeInfo.type == TypeLeaf) {
00189             slot->type = LeafSlot;
00190             Q_ASSERT (p->freeLeafSlots > 0);
00191             p->freeLeafSlots--;
00192         } else {
00193             slot->type = PeerSlot;
00194             Q_ASSERT (p->freePeerSlots > 0);
00195             p->freePeerSlots--;
00196         }
00197     }
00198 
00199     connect (session, SIGNAL (destroyed()), &p->destroyedMapper, SLOT (map()));
00200     p->destroyedMapper.setMapping (session, reinterpret_cast <QObject *> (slot));
00201 
00202     return true;
00203 }
00204 
00205 void SlotAllocator::freeSlot (QObject *pointer)
00206 {
00207     qDebug() << "SlotAllocator::freeSlot";
00208 
00209     Slot *slot = reinterpret_cast <Slot *> (pointer);
00210     Q_ASSERT (slot != 0);
00211 
00212     switch (slot->type) {
00213     case HandshakingSlot:
00214         p->freeHandshakingSlots++;
00215         emit handshakingSlotFreed();
00216         break;
00217     case LeafSlot:
00218         p->freeLeafSlots++;
00219         emit leafSlotFreed();
00220         break;
00221     case PeerSlot:
00222         p->freePeerSlots++;
00223         emit peerSlotFreed();
00224         break;
00225     case UltrapeerSlot:
00226         p->freeUltrapeerSlots++;
00227         emit ultrapeerSlotFreed();
00228         break;
00229     default:
00230         Q_ASSERT (false);
00231         break;
00232     }
00233     delete slot;
00234 
00235     // Not need to explicitly call removeMapping() now. All signals are
00236     // automatically disconnected when the sender is being destroyed.
00237 }