Alexander Afanasyev | c74a602 | 2011-08-15 20:01:35 -0700 | [diff] [blame] | 1 | /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */ |
| 2 | // |
| 3 | // Copyright (c) 2010,2011 UCLA |
| 4 | // |
| 5 | // This program is free software; you can redistribute it and/or modify |
| 6 | // it under the terms of the GNU General Public License version 2 as |
| 7 | // published by the Free Software Foundation; |
| 8 | // |
| 9 | // This program is distributed in the hope that it will be useful, |
| 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 12 | // GNU General Public License for more details. |
| 13 | // |
| 14 | // You should have received a copy of the GNU General Public License |
| 15 | // along with this program; if not, write to the Free Software |
| 16 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| 17 | // |
| 18 | // Author: |
| 19 | // |
| 20 | |
| 21 | #ifndef CCNX_PIT_H |
| 22 | #define CCNX_PIT_H |
| 23 | |
| 24 | #include "ns3/nstime.h" |
| 25 | #include "hash-helper.h" |
| 26 | #include <list> |
| 27 | |
| 28 | namespace ns3 { |
| 29 | |
| 30 | class Ccnx; |
| 31 | class PitEntry; |
| 32 | class PitIncomingInterest; |
| 33 | typedef pair<PitEntry*,PitIncomingInterest*> PitExpirationEntry; |
| 34 | typedef list<PitExpirationEntry>::iterator PitExpirationIterator; |
| 35 | |
| 36 | struct PitIncomingInterest |
| 37 | { |
| 38 | int interfaceIndex; // interface index of the incoming Interest |
| 39 | Time expireTime; // life time of the incoming Interest |
| 40 | int nonce; // nonce of the last received incoming Interest on this interface |
| 41 | |
| 42 | PitExpirationIterator expirationPosition; |
| 43 | |
| 44 | public: |
| 45 | PitIncomingInterest( int _interface, clocktype _expire, int _nonce ) |
| 46 | : interfaceIndex(_interface) |
| 47 | , expireTime(_expire) |
| 48 | , nonce(_nonce) |
| 49 | { }; |
| 50 | |
| 51 | bool operator==( const PitIncomingInterest &dst ) { return interfaceIndex==dst.interfaceIndex; } |
| 52 | bool operator==( int interface ) { return interfaceIndex==interface; } |
| 53 | }; |
| 54 | |
| 55 | struct PitOutgoingInterest |
| 56 | { |
| 57 | int interfaceIndex; |
| 58 | clocktype sendTime; //time when the first outgoing interest is sent |
| 59 | int retxNum; //number of retransmission |
| 60 | int nonce; //nonce of the outgoing Interest |
| 61 | bool outstanding; //flag to indicate that this interest is currently pending |
| 62 | bool waitingInVain; //when flag is set, we do not expect data for this interest, only a small hope that it will happen |
| 63 | |
| 64 | public: |
| 65 | PitOutgoingInterest( int interface, clocktype time, int nonce ) |
| 66 | : interfaceIndex(interface) |
| 67 | , sendTime( time ) |
| 68 | , retxNum( 0 ) |
| 69 | , nonce( nonce ) |
| 70 | , outstanding( true ) |
| 71 | , waitingInVain( false ) |
| 72 | { }; |
| 73 | |
| 74 | bool operator==( const PitIncomingInterest &dst ) { return interfaceIndex==dst.interfaceIndex; } |
| 75 | bool operator==( int interface ) { return interfaceIndex==interface; } |
| 76 | }; |
| 77 | |
| 78 | |
| 79 | //structure for PIT entry |
| 80 | struct PitEntry |
| 81 | { |
| 82 | string contentName; |
| 83 | list<PitIncomingInterest> incomingInterests; |
| 84 | list<PitOutgoingInterest> outgoingInterests; |
| 85 | |
| 86 | bool timerExpired; |
| 87 | int counterExpirations; //whether timer is expired (+ number of times timer expired) |
| 88 | |
| 89 | /** |
| 90 | * This variable provides a list of interfaces that will be tried to propagate interest |
| 91 | * |
| 92 | * It should be initialized with all available interfaces upon reception of first or |
| 93 | * any retransmitted (i.e., after STO expired), but not duplicate interests |
| 94 | * |
| 95 | * Reaction to duplicate interests depends on strategy. |
| 96 | * |
| 97 | * In case of flooding, this variable should always be empty (it is filled initially with |
| 98 | * all avaialble interfaces and then immediately emptied by interest flooding) |
| 99 | * |
| 100 | * In case of routing strategies, this list will guide (and limit) the local recovery process |
| 101 | */ |
| 102 | list<int> availableInterfaces; |
| 103 | |
| 104 | Message *timerMsg; //the timer message, used to cancel message if data is received |
| 105 | |
| 106 | // Changing PIT removal policy. From now on it will be deleted only when all outgoing |
| 107 | // interests are satisfied |
| 108 | // |
| 109 | // bool dontDeleteOnFirstData; //don't delete when first data packet comes |
| 110 | // //(PIT will be deleted only upon timeout or reception data |
| 111 | // //packets or prunes for all outgoing interests) |
| 112 | |
| 113 | public: |
| 114 | PitEntry() |
| 115 | : timerExpired( false ) |
| 116 | , counterExpirations( 0 ) |
| 117 | , timerMsg( NULL ) |
| 118 | { } |
| 119 | |
| 120 | inline void fillAvailableInterfacesFromFIB( const FibEntry &fe ); |
| 121 | |
| 122 | // Find best candidate, skipping `skip' first candidates (modulo availableInterfaces.size()) |
| 123 | // !!! assert( availableInterfaces.size()>0 ) !!! |
| 124 | inline int findBestCandidate( int skip = 0 ); |
| 125 | |
| 126 | // Get number of outgoing interests that we're expecting data from |
| 127 | inline size_t numberOfPromisingInterests( ) const; |
| 128 | }; |
| 129 | |
| 130 | typedef string_key_hash_t<PitEntry>::point_iterator PitIterator; |
| 131 | typedef string_key_hash_t<PitEntry>::iterator PitRangeIterator; |
| 132 | |
| 133 | typedef list<PitIncomingInterest>::iterator PitIncomingIterator; |
| 134 | typedef list<PitOutgoingInterest>::iterator PitOutgoingIterator; |
| 135 | typedef list<PitOutgoingInterest>::const_iterator PitOutgoingConstIterator; |
| 136 | |
| 137 | typedef map<int,int> PitCounter; |
| 138 | typedef map<int,int>::iterator PitCounterIterator; |
| 139 | |
| 140 | typedef map<int,double> PitBucket; |
| 141 | typedef map<int,double>::iterator PitBucketIterator; |
| 142 | |
| 143 | |
| 144 | //////////////////////////////////////////////////////////////////////// |
| 145 | //////////////////////////////////////////////////////////////////////// |
| 146 | |
| 147 | // class implementing Pending Interests Table |
| 148 | class CcnxPit |
| 149 | { |
| 150 | public: |
| 151 | /** |
| 152 | * PIT constructor |
| 153 | */ |
| 154 | CcnxPit( Ccnx &node ); |
| 155 | virtual ~CcnxPit( ); |
| 156 | |
| 157 | //Find corresponding PIT entry for the given content name |
| 158 | PitIterator lookup( const string &prefix ); |
| 159 | bool isValid( const PitIterator &it ) { return it!=_pit.end(); } |
| 160 | |
| 161 | inline PitIncomingIterator findIncoming( PitEntry &pe, int interfaceIndex ); |
| 162 | inline bool isValid( PitEntry &pe, PitIncomingIterator it ); |
| 163 | inline PitOutgoingIterator findOutgoing( PitEntry &pe, int interfaceIndex ); |
| 164 | inline bool isValid( PitEntry &pe, PitOutgoingIterator it ); |
| 165 | |
| 166 | // Add a new PIT entry and a correspondent new incoming interest |
| 167 | bool add( const string &contentName, const PitIncomingInterest &interest ); |
| 168 | |
| 169 | // Add a new outgoing interest |
| 170 | int add( PitEntry &pe, const PitOutgoingInterest &interest ); |
| 171 | |
| 172 | // remove a PIT entry |
| 173 | void erase( const string &contentName ); |
| 174 | |
| 175 | // inline bool InterestAlreadyForwarded( PitEntry &pe, int interfaceIndex ); |
| 176 | |
| 177 | // Remove expired records from PIT |
| 178 | void cleanExpired( clocktype time ); |
| 179 | |
| 180 | // Dump content store entries |
| 181 | void dump( ); |
| 182 | |
| 183 | // Reset pending state in outgoing interests |
| 184 | void resetPendingState( PitEntry &pe ); |
| 185 | |
| 186 | // // Check if there are any interfaces that we haven't sent data to yet |
| 187 | // bool areFreeInterfaces( PitEntry &pe, int interface ); |
| 188 | |
| 189 | // Periodically generate pre-calculated number of tokens (leak buckets) |
| 190 | void leakBuckets( ); |
| 191 | |
| 192 | // Selectively leak a bucket |
| 193 | void leakBucket( int interface, int amount ); |
| 194 | |
| 195 | // Delete incoming interest for the interface |
| 196 | bool deleteIncomingInterest( PitEntry &pe, int interfaceIndex ); |
| 197 | |
| 198 | // Remove all incoming interests |
| 199 | void deleteAllIncomingInterests( PitEntry &pe ); |
| 200 | |
| 201 | public: |
| 202 | PitBucket maxBucketsPerInterface; // maximum number of buckets. Automatically computed based on link capacity |
| 203 | // averaging over 1 second (bandwidth * 1second) |
| 204 | PitBucket leakSize; // size of a periodic bucket leak |
| 205 | |
| 206 | private: |
| 207 | bool add( PitEntry &pe, const PitIncomingInterest &interest ); |
| 208 | void deleteIncomingInterest( PitEntry &pe, PitIncomingIterator it ); |
| 209 | |
| 210 | private: |
| 211 | Ccnx &_node; |
| 212 | |
| 213 | string_key_hash_t<PitEntry> _pit; |
| 214 | |
| 215 | list<PitExpirationEntry> _pitExpirationList; //list of incoming Interests sorted by expiration time |
| 216 | |
| 217 | PitBucket _bucketsPerInterface; // pending interface counter per interface |
| 218 | |
| 219 | QNThreadMutex _pitMutex; // just to make sure |
| 220 | }; |
| 221 | |
| 222 | //////////////////////////////////////////////////////////////////////// |
| 223 | //////////////////////////////////////////////////////////////////////// |
| 224 | |
| 225 | PitIncomingIterator CcnxPit::findIncoming( PitEntry &pe, int interfaceIndex ) |
| 226 | { |
| 227 | return find( pe.incomingInterests.begin( ), |
| 228 | pe.incomingInterests.end( ), |
| 229 | interfaceIndex ); |
| 230 | } |
| 231 | |
| 232 | PitOutgoingIterator CcnxPit::findOutgoing( PitEntry &pe, int interfaceIndex ) |
| 233 | { |
| 234 | return find( pe.outgoingInterests.begin( ), |
| 235 | pe.outgoingInterests.end( ), |
| 236 | interfaceIndex ); |
| 237 | } |
| 238 | |
| 239 | bool CcnxPit::isValid( PitEntry &pe, PitIncomingIterator it ) |
| 240 | { |
| 241 | return it!=pe.incomingInterests.end( ); |
| 242 | } |
| 243 | |
| 244 | bool CcnxPit::isValid( PitEntry &pe, PitOutgoingIterator it ) |
| 245 | { |
| 246 | return it!=pe.outgoingInterests.end( ); |
| 247 | } |
| 248 | |
| 249 | int PitEntry::findBestCandidate( int skip/* = 0*/ ) |
| 250 | { |
| 251 | assert( availableInterfaces.size()>0 ); |
| 252 | |
| 253 | skip = skip % availableInterfaces.size(); |
| 254 | list<int>::iterator candidate = availableInterfaces.begin( ); |
| 255 | while( skip>0 /* && candidate!=availableInterfaces.end() */ ) { skip--; candidate++; } |
| 256 | |
| 257 | return *candidate; |
| 258 | } |
| 259 | |
| 260 | size_t PitEntry::numberOfPromisingInterests( ) const |
| 261 | { |
| 262 | size_t count = 0; |
| 263 | |
| 264 | for( PitOutgoingConstIterator i = outgoingInterests.begin(); |
| 265 | i!=outgoingInterests.end(); |
| 266 | i++ ) |
| 267 | { |
| 268 | if( !i->waitingInVain ) count++; |
| 269 | } |
| 270 | |
| 271 | return count; |
| 272 | } |
| 273 | |
| 274 | } // namespace ns3 |
| 275 | |
| 276 | #endif /* CCNX_PIT_H */ |