1 /*
2  * Created on Jul 17, 2006
3  * Created by Alon Rohter
4  * Copyright (C) Azureus Software, Inc, All Rights Reserved.
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
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  * AELITIS, SARL au capital de 30,000 euros
19  * 8 Allee Lenotre, La Grille Royale, 78600 Le Mesnil le Roi, France.
20  *
21  */
22 package com.aelitis.azureus.core.peermanager.uploadslots;
23 
24 import java.util.*;
25 
26 import org.gudy.azureus2.core3.peer.PEPeer;
27 import org.gudy.azureus2.core3.util.*;
28 
29 
30 
31 
32 /**
33  *
34  */
35 public class UploadSessionPicker {
36 
37 	private final LinkedList next_optimistics = new LinkedList();
38 	private final AEMonitor next_optimistics_mon = new AEMonitor( "UploadSessionPicker" );
39 
40 	private final LinkedList helpers = new LinkedList();
41 
42 	private final DownloadingRanker down_ranker = new DownloadingRanker();
43 	private final SeedingRanker seed_ranker = new SeedingRanker();
44 
45 
UploadSessionPicker()46 	protected UploadSessionPicker() {
47 		/*nothing*/
48 	}
49 
50 
51 
registerHelper( UploadHelper helper )52 	protected void registerHelper( UploadHelper helper ) {
53 		try {  next_optimistics_mon.enter();
54 			helpers.add( helper );
55 
56 			int priority = helper.getPriority();
57 
58 			//the higher the priority, the more optimistic unchoke chances they get
59 			for( int i=0; i < priority; i++ ) {
60 				insertHelper( helper );
61 			}
62 		}
63 		finally {  next_optimistics_mon.exit();  }
64 	}
65 
66 
67 
deregisterHelper( UploadHelper helper )68 	protected void deregisterHelper( UploadHelper helper ) {
69 		try {  next_optimistics_mon.enter();
70 			helpers.remove( helper );
71 
72 			boolean rem = next_optimistics.removeAll( Collections.singleton( helper ) );
73 			if( !rem ) Debug.out( "!rem" );
74 		}
75 		finally {  next_optimistics_mon.exit();  }
76 	}
77 
78 
79 
updateHelper( UploadHelper helper )80 	protected void updateHelper( UploadHelper helper ) {
81 		try {  next_optimistics_mon.enter();
82 			int priority = helper.getPriority();  //new priority
83 
84 			int count = 0;
85 
86 			for( Iterator it = next_optimistics.iterator(); it.hasNext(); ) {
87 				UploadHelper h = (UploadHelper)it.next();
88 				if( h == helper ) {
89 					count++;
90 
91 					if( count > priority ) {  //new priority is lower
92 						it.remove();  //trim
93 					}
94 				}
95 			}
96 
97 			if( count < priority ) {  //new priority is higher
98 				for( int i=count; i < priority; i++ ) {
99 					insertHelper( helper );  //add
100 				}
101 			}
102 		}
103 		finally {  next_optimistics_mon.exit();  }
104 	}
105 
106 
107 
insertHelper( UploadHelper helper )108 	private void insertHelper( UploadHelper helper ) {
109 		int pos = RandomUtils.nextInt( next_optimistics.size() + 1 );  //pick a random location
110 		next_optimistics.add( pos, helper );  //store into location
111 	}
112 
113 
114 
115 
getHelperCount()116 	protected int getHelperCount() {
117 		try {  next_optimistics_mon.enter();
118 			return next_optimistics.size();
119 		}
120 		finally {  next_optimistics_mon.exit();  }
121 	}
122 
123 
124 
125 	//this picks both downloading and seeding sessions
pickNextOptimisticSession()126 	protected UploadSession pickNextOptimisticSession() {
127 
128 		try {  next_optimistics_mon.enter();
129 
130 			HashSet failed_helpers = null;
131 
132 			int loops_allowed = next_optimistics.size();
133 
134 			while( loops_allowed > 0 ) {
135 
136 				UploadHelper helper = (UploadHelper)next_optimistics.removeFirst();  //take from front
137 
138 				next_optimistics.addLast( helper );   //add back at end
139 
140 				if( failed_helpers == null || !failed_helpers.contains( helper ) ) {   //pre-emptive check to see if we've already tried this helper
141 
142 					PEPeer peer;
143 
144 					if( helper.isSeeding() ) {
145 						peer = seed_ranker.getNextOptimisticPeer( helper.getAllPeers() );
146 					}
147 					else {
148 						peer = down_ranker.getNextOptimisticPeer( helper.getAllPeers() );
149 					}
150 
151 					if( peer == null )  {  //no peers from this helper to unchoke
152 
153 						if( failed_helpers == null )  failed_helpers = new HashSet();   //lazy alloc
154 
155 						failed_helpers.add( helper );  //remember this helper in case we get it again in another loop round
156 					}
157 					else {   //found an optimistic peer!
158 
159 						return new UploadSession( peer, helper.isSeeding() ? UploadSession.TYPE_SEED : UploadSession.TYPE_DOWNLOAD );
160 					}
161 				}
162 
163 				loops_allowed--;
164 			}
165 
166 			return null;  //no optimistic peer found
167 
168 		}
169 		finally {  next_optimistics_mon.exit();  }
170 	}
171 
172 
173 
174 
globalGetAllDownloadPeers()175 	private ArrayList<PEPeer> globalGetAllDownloadPeers() {
176 		try {  next_optimistics_mon.enter();
177 			ArrayList<PEPeer> all = new ArrayList<PEPeer>();
178 
179 			for( Iterator<PEPeer> it = helpers.iterator(); it.hasNext(); ) {
180 				UploadHelper helper = (UploadHelper)it.next();
181 
182 				if( !helper.isSeeding() )  {  //filter out seeding
183 					all.addAll( helper.getAllPeers() );
184 				}
185 			}
186 
187 			return all;
188 		}
189 		finally {  next_optimistics_mon.exit();  }
190 	}
191 
192 
193 
194 	//this picks downloading sessions only
pickBestDownloadSessions( int max_sessions )195 	protected LinkedList<UploadSession> pickBestDownloadSessions( int max_sessions ) {
196 		//TODO factor download priority into best calculation?
197 
198 		ArrayList<PEPeer> all_peers = globalGetAllDownloadPeers();
199 
200 		if( all_peers.isEmpty() )  return new LinkedList();
201 
202 		ArrayList<PEPeer> best = down_ranker.rankPeers( max_sessions, all_peers );
203 
204 		if( best.size() != max_sessions ) {
205 			Debug.outNoStack( "best.size()[" +best.size()+ "] != max_sessions[" +max_sessions+ "]" );
206 		}
207 
208 		if( best.isEmpty() ) {
209 			return new LinkedList<UploadSession>();
210 		}
211 
212 
213 		LinkedList<UploadSession> best_sessions = new LinkedList<UploadSession>();
214 
215 		for( Iterator<PEPeer> it = best.iterator(); it.hasNext(); ) {
216 			PEPeer peer = it.next();
217 			UploadSession session = new UploadSession( peer, UploadSession.TYPE_DOWNLOAD );
218 			best_sessions.add( session );
219 		}
220 
221 		return best_sessions;
222 	}
223 
224 
225 
226 
227 }
228