blob: 5d10b90c21a002de41ca1c854c640202fa192f4c [file] [log] [blame]
Alexander Afanasyeva98cdd22011-08-29 17:32:37 -07001/* -*- 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#include "ccnx-pit.h"
22#include <algorithm>
23
24CcnxPit::CcnxPit( Ccnx &node )
25: _node(node)
26{
27};
28
29CcnxPit::~CcnxPit( ) { }
30
31//Find corresponding CS entry for the given content name
32PitIterator CcnxPit::lookup( const string &prefix )
33{
34 QNThreadLock lock( &_pitMutex );
35
36 PitIterator entry=_pit.find( prefix );
37 return entry;
38}
39
40// add new PIT entry
41bool CcnxPit::add( const string &name, const PitIncomingInterest &interest )
42{
43 QNThreadLock lock( &_pitMutex );
44
45 PitEntry *entry=NULL;
46
47 PitIterator existent_entry = _pit.find( name );
48 if( isValid(existent_entry) )
49 {
50 if( VALUE(existent_entry).timerExpired )
51 {
52 _node.fillAvailableInterfacesInPitEntry( VALUE(existent_entry) );
53 }
54
55 add( VALUE(existent_entry), interest );
56 }
57 else
58 {
59 PitEntry &entry = _pit[ name ];
60 entry.contentName = name;
61
62 _node.fillAvailableInterfacesInPitEntry( entry );
63
64 add( entry, interest );
65 }
66}
67
68// Remove expired records from PIT
69void CcnxPit::cleanExpired( clocktype time )
70{
71 QNThreadLock lock( &_pitMutex );
72
73 while( !_pitExpirationList.empty() )
74 {
75 PitExpirationIterator entry = _pitExpirationList.begin( );
76
77 if( VALUE(entry)->expireTime <= time )
78 {
79 deleteIncomingInterest( *(KEY(entry)), VALUE(entry)->interfaceIndex );
80
81 // delete entry if all incoming interests expired
82 if( KEY(entry)->incomingInterests.size()==0 )
83 {
84 _pit.erase( KEY(entry)->contentName );
85 }
86 }
87 else
88 break;
89 }
90}
91
92//delete PIT entry
93void CcnxPit::erase( const string &name )
94{
95 // should not call `lookup' method !!!
96
97 QNThreadLock lock( &_pitMutex );
98
99 PitIterator pe = _pit.find( name );
100
101 if( !isValid(pe) ) return;
102
103 if( VALUE(pe).timerMsg ) MESSAGE_CancelSelfMsg( _node.getNode(), VALUE(pe).timerMsg );
104
105 PitIncomingIterator it = VALUE(pe).incomingInterests.begin();
106 while( it!=VALUE(pe).incomingInterests.end() )
107 {
108 deleteIncomingInterest( VALUE(pe), it );
109
110 it = VALUE(pe).incomingInterests.begin();
111 }
112
113 resetPendingState( VALUE(pe) );
114
115 _pit.erase( name );
116}
117
118//delete incoming interest from PIT entry
119//return 0 if interest does not exist, 1 otherwise
120bool CcnxPit::deleteIncomingInterest( PitEntry &pe, int interfaceIndex )
121{
122 // should not lock thread !!! Otherwise there will be a deadlock
123 if( pe.incomingInterests.size()==0 ) return false; //nothing to delete. Can happen when duplicate data arrives to the node
124
125 PitIncomingIterator it = findIncoming( pe, interfaceIndex );
126
127 if( !isValid(pe, it) ) return false;
128
129 deleteIncomingInterest( pe, it );
130
131 return true;
132}
133
134void CcnxPit::deleteAllIncomingInterests( PitEntry &pe )
135{
136 PitIncomingIterator it = pe.incomingInterests.begin();
137 while( it!=pe.incomingInterests.end() )
138 {
139 deleteIncomingInterest( pe, it );
140
141 it = pe.incomingInterests.begin();
142 }
143}
144
145void CcnxPit::deleteIncomingInterest( PitEntry &pe, PitIncomingIterator it )
146{
147 assert( KEY(it->expirationPosition)==&pe );
148 assert( VALUE(it->expirationPosition)->interfaceIndex==it->interfaceIndex );
149
150 _pitExpirationList.erase( it->expirationPosition );
151 pe.incomingInterests.erase( it );
152}
153
154//add new incoming interest to PIT entry
155//returns false if interface already exists, true otherwise
156bool CcnxPit::add( PitEntry &pe, const PitIncomingInterest &interest )
157{
158 pe.availableInterfaces.remove( interest.interfaceIndex );
159
160 PitIncomingIterator it=findIncoming( pe, interest.interfaceIndex );
161
162 if( isValid(pe, it) )
163 {
164 //update expiration time
165 it->expireTime = interest.expireTime;
166 it->nonce = interest.nonce;
167
168 //move Interest to the end of the node's Interest list
169 _pitExpirationList.erase( it->expirationPosition );
170 _pitExpirationList.push_back( PitExpirationEntry(&pe,&(*it)) );
171
172 it->expirationPosition = --_pitExpirationList.end();
173 return false;
174 }
175
176 pe.incomingInterests.push_back( interest );
177 PitIncomingInterest *incoming = &pe.incomingInterests.back();
178
179 //Add to the end of the node's Interest list
180 _pitExpirationList.push_back( PitExpirationEntry(&pe,incoming) );
181 incoming->expirationPosition = -- _pitExpirationList.end();
182
183 return true;
184}
185
186//add new outgoing interest to PIT entry
187//returns false interface limit reached or interest exists and is still marked as outstanding (nonce will not be changed)
188// true otherwise
189int CcnxPit::add( PitEntry &pe, const PitOutgoingInterest &interest )
190{
191 if( _node.isRateLimit && _bucketsPerInterface[interest.interfaceIndex]+1.0 >= maxBucketsPerInterface[interest.interfaceIndex] )
192 {
193// printf( "DEBUG: bucket overflow. Should not forward anything to interface %d\n", interest.interfaceIndex );
194 return false;
195 }
196
197 _bucketsPerInterface[interest.interfaceIndex] = _bucketsPerInterface[interest.interfaceIndex] + 1.0;
198 pe.availableInterfaces.remove( interest.interfaceIndex );
199
200 PitOutgoingIterator it = findOutgoing(pe, interest.interfaceIndex);
201 if( isValid(pe, it) )
202 {
203 if( it->outstanding ) return false;
204
205 it->retxNum ++;
206 it->nonce = interest.nonce;
207 it->outstanding = true;
208 it->waitingInVain = false;
209 }
210 else
211 {
212 //add to the head of the list
213 pe.outgoingInterests.push_front( interest );
214 }
215
216 return true;
217}
218
219void CcnxPit::resetPendingState( PitEntry &pe )
220{
221 for( PitOutgoingIterator it = pe.outgoingInterests.begin();
222 it != pe.outgoingInterests.end();
223 it++ )
224 {
225 it->outstanding = false;
226 }
227}
228
229void CcnxPit::leakBuckets( )
230{
231 for( PitBucketIterator it=_bucketsPerInterface.begin();
232 it != _bucketsPerInterface.end();
233 it++ )
234 {
235 it->second = max( 0.0, it->second - leakSize[it->first] );
236 }
237}
238
239void CcnxPit::leakBucket( int interface, int amount )
240{
241 _bucketsPerInterface[interface] =
242 max( 0.0, _bucketsPerInterface[interface] - amount );
243}