00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "StdAfx.h"
00023 #include "Shareaza.h"
00024 #include "Settings.h"
00025 #include "Uploads.h"
00026 #include "UploadQueue.h"
00027 #include "UploadQueues.h"
00028 #include "UploadTransfer.h"
00029 #include "QuerySearch.h"
00030 #include "Neighbours.h"
00031
00032 #ifdef _DEBUG
00033 #undef THIS_FILE
00034 static char THIS_FILE[]=__FILE__;
00035 #define new DEBUG_NEW
00036 #endif
00037
00038
00040
00041
00042 CUploadQueue::CUploadQueue()
00043 {
00044 m_nIndex = 0;
00045 m_bEnable = TRUE;
00046
00047 m_nProtocols = 0;
00048 m_nMinSize = 0;
00049 m_nMaxSize = 0xFFFFFFFFFFFFFFFF;
00050 m_bPartial = FALSE;
00051
00052 m_nCapacity = 20;
00053 m_nMinTransfers = 1;
00054 m_nMaxTransfers = 10;
00055 m_nBandwidthPoints = 10;
00056 m_bRotate = FALSE;
00057 m_nRotateTime = 300;
00058 m_nRotateChunk = 0;
00059 m_bRewardUploaders = FALSE;
00060
00061 m_bExpanded = TRUE;
00062 m_bSelected = FALSE;
00063 m_nMeasured = 0;
00064 }
00065
00066 CUploadQueue::~CUploadQueue()
00067 {
00068 for ( POSITION pos = m_pActive.GetHeadPosition() ; pos ; )
00069 {
00070 CUploadTransfer* pUpload = (CUploadTransfer*)m_pActive.GetNext( pos );
00071 pUpload->m_pQueue = NULL;
00072 }
00073
00074 for ( int nPosition = 0 ; nPosition < m_pQueued.GetSize() ; nPosition++ )
00075 {
00076 CUploadTransfer* pUpload = (CUploadTransfer*)m_pQueued.GetAt( nPosition );
00077 pUpload->m_pQueue = NULL;
00078 }
00079 }
00080
00082
00083
00084 CString CUploadQueue::GetCriteriaString() const
00085 {
00086 CString str1, str2;
00087
00088 if ( m_nProtocols != 0 )
00089 {
00090 if ( m_nProtocols & (1<<PROTOCOL_HTTP) )
00091 {
00092 if ( str1.GetLength() ) str1 += _T(", ");
00093 str1 += _T("HTTP");
00094 }
00095 if ( m_nProtocols & (1<<PROTOCOL_ED2K) )
00096 {
00097 if ( str1.GetLength() ) str1 += _T(", ");
00098 str1 += _T("ED2K");
00099 }
00100 }
00101
00102 if ( m_nMinSize > 0 )
00103 {
00104 if ( str1.GetLength() ) str1 += _T(", ");
00105 str2.Format( _T(">=%s"), (LPCTSTR)Settings.SmartVolume( m_nMinSize, FALSE ) );
00106 str1 += str2;
00107 }
00108
00109 if ( m_nMaxSize < 0xFFFFFFFFFFFFFFFF )
00110 {
00111 if ( str1.GetLength() ) str1 += _T(", ");
00112 str2.Format( _T("<=%s"), (LPCTSTR)Settings.SmartVolume( m_nMaxSize, FALSE ) );
00113 str1 += str2;
00114 }
00115
00116 if ( m_bPartial )
00117 {
00118 if ( str1.GetLength() ) str1 += _T(", ");
00119 LoadString( str2, IDS_UPLOAD_QUEUE_PARTIAL );
00120 str1 += str2;
00121 }
00122
00123
00124
00125 return str1;
00126 }
00127
00129
00130
00131 BOOL CUploadQueue::CanAccept(PROTOCOLID nProtocol, LPCTSTR pszName, QWORD nSize, BOOL bPartial, LPCTSTR pszShareTags) const
00132 {
00133 if ( ! m_bEnable ) return FALSE;
00134
00135 if ( nSize < m_nMinSize ) return FALSE;
00136 if ( nSize > m_nMaxSize ) return FALSE;
00137
00138 if ( m_nProtocols != 0 &&
00139 ( m_nProtocols & ( 1 << nProtocol ) ) == 0 ) return FALSE;
00140
00141 if ( m_bPartial && !bPartial ) return FALSE;
00142
00143 if ( m_sShareTag.GetLength() > 0 )
00144 {
00145 if ( pszShareTags == NULL ) return FALSE;
00146 if ( _tcsistr( pszShareTags, m_sShareTag ) == NULL ) return FALSE;
00147 }
00148
00149 if ( m_sNameMatch.GetLength() > 0 )
00150 {
00151 if ( pszName == NULL ) return FALSE;
00152 if ( CQuerySearch::WordMatch( pszName, m_sNameMatch ) == FALSE ) return FALSE;
00153 }
00154
00155 return TRUE;
00156 }
00157
00159
00160
00161 BOOL CUploadQueue::Enqueue(CUploadTransfer* pUpload, BOOL bForce, BOOL bStart)
00162 {
00163 ASSERT( pUpload != NULL );
00164 ASSERT( pUpload->m_pQueue == NULL );
00165
00166 if ( ! bForce && ! bStart )
00167 {
00168 if ( m_bRewardUploaders && ( pUpload->m_nUserRating > urSharing ) )
00169 {
00170
00171 if ( ( ( GetQueueCapacity() * ( 100 - Settings.Uploads.RewardQueuePercentage ) ) / 100 ) - ( GetQueuedCount() ) <= 0 )
00172 {
00173 return FALSE;
00174 }
00175 }
00176 else
00177 {
00178
00179 if ( GetQueueRemaining() <= 0 )
00180 return FALSE;
00181 }
00182 }
00183
00184 m_pQueued.Add( pUpload );
00185 pUpload->m_pQueue = this;
00186
00187 if ( bStart )
00188 {
00189 StartImpl( pUpload );
00190
00191 if ( GetTransferCount() <= m_nMinTransfers )
00192 SpreadBandwidth();
00193 else
00194 pUpload->m_nBandwidth = Settings.Bandwidth.Uploads / max( 1, m_nMinTransfers );
00195 }
00196
00197 return TRUE;
00198 }
00199
00201
00202
00203 BOOL CUploadQueue::Dequeue(CUploadTransfer* pUpload)
00204 {
00205 ASSERT( pUpload != NULL );
00206 ASSERT( pUpload->m_pQueue == this );
00207
00208 if ( POSITION pos = m_pActive.Find( pUpload ) )
00209 {
00210 pUpload->m_pQueue = NULL;
00211 m_pActive.RemoveAt( pos );
00212 RescaleBandwidth();
00213 return TRUE;
00214 }
00215
00216 for ( int nPosition = 0 ; nPosition < m_pQueued.GetSize() ; nPosition++ )
00217 {
00218 if ( m_pQueued.GetAt( nPosition ) == pUpload )
00219 {
00220 pUpload->m_pQueue = NULL;
00221 m_pQueued.RemoveAt( nPosition );
00222 return TRUE;
00223 }
00224 }
00225
00226 return FALSE;
00227 }
00228
00230
00231
00232 int CUploadQueue::GetPosition(CUploadTransfer* pUpload, BOOL bStart)
00233 {
00234 ASSERT( pUpload != NULL );
00235 ASSERT( pUpload->m_pQueue == this );
00236
00237 if ( m_pActive.Find( pUpload ) ) return 0;
00238
00239 for ( int nPosition = 0 ; nPosition < m_pQueued.GetSize() ; nPosition++ )
00240 {
00241 if ( m_pQueued.GetAt( nPosition ) == pUpload )
00242 {
00243 if ( nPosition == 0 && Start( pUpload, ! bStart ) ) return 0;
00244 return nPosition + 1;
00245 }
00246 }
00247
00248 return -1;
00249 }
00250
00252
00253
00254 BOOL CUploadQueue::StealPosition(CUploadTransfer* pTarget, CUploadTransfer* pSource)
00255 {
00256 ASSERT( pTarget != NULL );
00257 ASSERT( pSource != NULL );
00258 ASSERT( pTarget->m_pQueue == NULL );
00259 ASSERT( pSource->m_pQueue == this );
00260
00261 if ( POSITION pos = m_pActive.Find( pSource ) )
00262 {
00263 m_pActive.SetAt( pos, pTarget );
00264 pTarget->m_pQueue = this;
00265 pSource->m_pQueue = NULL;
00266 pTarget->m_nBandwidth = pSource->m_nBandwidth;
00267 return TRUE;
00268 }
00269
00270 for ( int nPosition = 0 ; nPosition < m_pQueued.GetSize() ; nPosition++ )
00271 {
00272 if ( m_pQueued.GetAt( nPosition ) == pSource )
00273 {
00274 m_pQueued.SetAt( nPosition, pTarget );
00275 pTarget->m_pQueue = this;
00276 pSource->m_pQueue = NULL;
00277 return TRUE;
00278 }
00279 }
00280
00281 return FALSE;
00282 }
00283
00285
00286
00287 BOOL CUploadQueue::Start(CUploadTransfer* pUpload, BOOL bPeek)
00288 {
00289 ASSERT( pUpload != NULL );
00290 ASSERT( pUpload->m_pQueue == this );
00291 ASSERT( m_pActive.Find( pUpload ) == NULL );
00292
00293 int nTransfers = GetTransferCount();
00294 if ( nTransfers >= m_nMaxTransfers ) return FALSE;
00295
00296 if ( nTransfers < m_nMinTransfers )
00297 {
00298 if ( bPeek ) return TRUE;
00299 StartImpl( pUpload );
00300 SpreadBandwidth();
00301 theApp.Message( MSG_DEBUG, _T("Starting upload to %s because the minimum has not been reached."),
00302 (LPCTSTR)pUpload->m_sAddress );
00303 return TRUE;
00304 }
00305
00306 if ( DWORD nAvailable = GetAvailableBandwidth() )
00307 {
00308 if ( bPeek ) return TRUE;
00309 StartImpl( pUpload );
00310 pUpload->SetSpeedLimit( nAvailable );
00311 theApp.Message( MSG_DEBUG, _T("Starting upload to %s because there is %s available."),
00312 (LPCTSTR)pUpload->m_sAddress, (LPCTSTR)Settings.SmartVolume( nAvailable * 8, FALSE, TRUE ) );
00313 return TRUE;
00314 }
00315
00316 return FALSE;
00317 }
00318
00319 void CUploadQueue::StartImpl(CUploadTransfer* pUpload)
00320 {
00321 ASSERT( pUpload != NULL );
00322 ASSERT( pUpload->m_pQueue == this );
00323 Dequeue( pUpload );
00324 m_pActive.AddTail( pUpload );
00325 pUpload->m_pQueue = this;
00326 }
00327
00329
00330
00331 int CUploadQueue::GetBandwidthPoints(int nTransfers) const
00332 {
00333 if ( nTransfers < 0 ) nTransfers = GetTransferCount();
00334
00335 if ( nTransfers == 0 ) return 0;
00336 if ( nTransfers >= m_nMinTransfers ) return m_nBandwidthPoints;
00337
00338 return m_nBandwidthPoints * nTransfers / max( 1, m_nMinTransfers );
00339 }
00340
00341 DWORD CUploadQueue::GetBandwidthLimit(int nTransfers) const
00342 {
00343 int nLocalPoints = GetBandwidthPoints( nTransfers );
00344 if ( nLocalPoints == 0 ) return 0;
00345
00346 int nTotalPoints = nLocalPoints;
00347
00348 for ( POSITION pos = UploadQueues.GetIterator() ; pos ; )
00349 {
00350 CUploadQueue* pOther = UploadQueues.GetNext( pos );
00351 if ( pOther != this ) nTotalPoints += pOther->GetBandwidthPoints();
00352 }
00353
00354 DWORD nTotal = Settings.Connection.OutSpeed * 128;
00355 DWORD nLimit = Neighbours.m_nLeafCount ? Settings.Bandwidth.HubUploads : Settings.Bandwidth.Uploads;
00356 if ( nLimit == 0 || nLimit > nTotal ) nLimit = nTotal;
00357
00358
00359 if ( Uploads.m_nTorrentSpeed > 0 ) nLimit = ( nLimit * ( 100 - Settings.BitTorrent.BandwidthPercentage ) ) / 100;
00360
00361 return nLimit * ( nLocalPoints + Settings.Uploads.ThrottleMode ) / max( 1, nTotalPoints );
00362 }
00363
00364 DWORD CUploadQueue::GetAvailableBandwidth() const
00365 {
00366 int nTransfers = GetTransferCount();
00367
00368 if ( nTransfers < m_nMinTransfers )
00369 {
00370 nTransfers ++;
00371 return GetBandwidthLimit( nTransfers ) / nTransfers;
00372 }
00373
00374 DWORD nTotal = GetBandwidthLimit();
00375 DWORD nUsed = 0;
00376
00377 for ( POSITION pos = m_pActive.GetHeadPosition() ; pos ; )
00378 {
00379 CUploadTransfer* pActive = (CUploadTransfer*)m_pActive.GetNext( pos );
00380 nUsed += pActive->m_nBandwidth;
00381 }
00382
00383 if ( nUsed >= nTotal ) return 0;
00384
00385 DWORD nAvailable = nTotal - nUsed;
00386
00387 if ( nAvailable < Settings.Uploads.FreeBandwidthValue ) return 0;
00388 if ( nAvailable < ( nTotal * Settings.Uploads.FreeBandwidthFactor / 100 ) ) return 0;
00389
00390 return nAvailable;
00391 }
00392
00393 DWORD CUploadQueue::GetPredictedBandwidth() const
00394 {
00395
00396 return GetBandwidthLimit( m_nMinTransfers ) / min( max( m_nMinTransfers, 1 ), GetTransferCount() + 1 );
00397 }
00398
00400
00401
00402 void CUploadQueue::SpreadBandwidth()
00403 {
00404 ASSERT( GetTransferCount() <= m_nMinTransfers );
00405
00406 DWORD nTotal = GetBandwidthLimit();
00407
00408 for ( POSITION pos = m_pActive.GetHeadPosition() ; pos ; )
00409 {
00410 CUploadTransfer* pActive = (CUploadTransfer*)m_pActive.GetNext( pos );
00411 pActive->SetSpeedLimit( nTotal / GetTransferCount() );
00412 }
00413 }
00414
00415 void CUploadQueue::RescaleBandwidth()
00416 {
00417 if ( GetTransferCount() <= m_nMinTransfers )
00418 {
00419 SpreadBandwidth();
00420 return;
00421 }
00422
00423 DWORD nTotal = GetBandwidthLimit();
00424 DWORD nAllocated = 0;
00425
00426 if ( nTotal == 0 ) return;
00427
00428 for ( POSITION pos = m_pActive.GetHeadPosition() ; pos ; )
00429 {
00430 CUploadTransfer* pActive = (CUploadTransfer*)m_pActive.GetNext( pos );
00431 nAllocated += pActive->m_nBandwidth;
00432 }
00433
00434 double nScale = (double)nTotal / (double)nAllocated;
00435
00436 for ( POSITION pos = m_pActive.GetHeadPosition() ; pos ; )
00437 {
00438 CUploadTransfer* pActive = (CUploadTransfer*)m_pActive.GetNext( pos );
00439 pActive->SetSpeedLimit( (DWORD)( nScale * pActive->m_nBandwidth ) );
00440 }
00441 }
00442
00444
00445
00446 void CUploadQueue::Serialize(CArchive& ar, int nVersion)
00447 {
00448 if ( ar.IsStoring() )
00449 {
00450 ar << m_sName;
00451 ar << m_bEnable;
00452
00453 ar << m_nProtocols;
00454 ar << m_nMinSize;
00455 ar << m_nMaxSize;
00456 ar << m_bPartial;
00457 ar << m_sShareTag;
00458 ar << m_sNameMatch;
00459
00460 ar << m_nCapacity;
00461 ar << m_nMinTransfers;
00462 ar << m_nMaxTransfers;
00463 ar << m_nBandwidthPoints;
00464 ar << m_bRotate;
00465 ar << m_nRotateTime;
00466 ar << m_nRotateChunk;
00467 ar << m_bRewardUploaders;
00468
00469 ar << m_bExpanded;
00470 }
00471 else
00472 {
00473 ar >> m_sName;
00474 ar >> m_bEnable;
00475
00476 ar >> m_nProtocols;
00477
00478 if ( nVersion >= 3 )
00479 {
00480 ar >> m_nMinSize;
00481 ar >> m_nMaxSize;
00482 }
00483 else
00484 {
00485 DWORD nInt32;
00486 ar >> nInt32;
00487 m_nMinSize = nInt32;
00488 ar >> nInt32;
00489 m_nMaxSize = nInt32;
00490 }
00491
00492 ar >> m_bPartial;
00493 ar >> m_sShareTag;
00494 ar >> m_sNameMatch;
00495
00496 ar >> m_nCapacity;
00497 ar >> m_nMinTransfers;
00498 ar >> m_nMaxTransfers;
00499 ar >> m_nBandwidthPoints;
00500 ar >> m_bRotate;
00501 ar >> m_nRotateTime;
00502 ar >> m_nRotateChunk;
00503
00504 if ( nVersion >= 5 ) ar >> m_bRewardUploaders;
00505
00506 if ( nVersion >= 4 ) ar >> m_bExpanded;
00507 }
00508 }