📄 downloadmanagercontroller.java
字号:
/*
* Created on 29-Jul-2005
* Created by Paul Gardner
* Copyright (C) 2005, 2006 Aelitis, All Rights Reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* AELITIS, SAS au capital de 46,603.30 euros
* 8 Allee Lenotre, La Grille Royale, 78600 Le Mesnil le Roi, France.
*
*/
package org.gudy.azureus2.core3.download.impl;
import java.io.File;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.gudy.azureus2.core3.config.COConfigurationManager;
import org.gudy.azureus2.core3.disk.DiskManager;
import org.gudy.azureus2.core3.disk.DiskManagerFactory;
import org.gudy.azureus2.core3.disk.DiskManagerFileInfo;
import org.gudy.azureus2.core3.disk.DiskManagerFileInfoListener;
import org.gudy.azureus2.core3.disk.DiskManagerListener;
import org.gudy.azureus2.core3.disk.DiskManagerPiece;
import org.gudy.azureus2.core3.download.DownloadManager;
import org.gudy.azureus2.core3.download.DownloadManagerDiskListener;
import org.gudy.azureus2.core3.download.DownloadManagerState;
import org.gudy.azureus2.core3.global.GlobalManager;
import org.gudy.azureus2.core3.global.GlobalManagerStats;
import org.gudy.azureus2.core3.internat.MessageText;
import org.gudy.azureus2.core3.logging.*;
import org.gudy.azureus2.core3.peer.PEPeer;
import org.gudy.azureus2.core3.peer.PEPeerManager;
import org.gudy.azureus2.core3.peer.PEPeerManagerAdapter;
import org.gudy.azureus2.core3.peer.PEPeerManagerFactory;
import org.gudy.azureus2.core3.peer.PEPeerSource;
import org.gudy.azureus2.core3.peer.PEPiece;
import org.gudy.azureus2.core3.torrent.TOTorrent;
import org.gudy.azureus2.core3.torrent.TOTorrentException;
import org.gudy.azureus2.core3.torrent.TOTorrentFile;
import org.gudy.azureus2.core3.tracker.client.TRTrackerAnnouncer;
import org.gudy.azureus2.core3.tracker.client.TRTrackerAnnouncerDataProvider;
import org.gudy.azureus2.core3.tracker.client.TRTrackerScraperResponse;
import org.gudy.azureus2.core3.util.*;
import org.gudy.azureus2.plugins.network.ConnectionManager;
import com.aelitis.azureus.core.AzureusCoreFactory;
import com.aelitis.azureus.core.peermanager.PeerManager;
import com.aelitis.azureus.core.peermanager.PeerManagerRegistration;
import com.aelitis.azureus.core.peermanager.PeerManagerRegistrationAdapter;
import com.aelitis.azureus.core.peermanager.peerdb.PeerItemFactory;
import com.aelitis.azureus.core.util.bloom.BloomFilter;
import com.aelitis.azureus.core.util.bloom.BloomFilterFactory;
import com.aelitis.azureus.plugins.extseed.ExternalSeedPlugin;
public class
DownloadManagerController
extends LogRelation
implements PEPeerManagerAdapter, PeerManagerRegistrationAdapter
{
private static long STATE_FLAG_HASDND = 0x01;
private static long STATE_FLAG_COMPLETE_NO_DND = 0x02;
private static long skeleton_builds;
private static ExternalSeedPlugin ext_seed_plugin;
private static boolean ext_seed_plugin_tried;
private static ExternalSeedPlugin
getExternalSeedPlugin()
{
if ( !ext_seed_plugin_tried ){
ext_seed_plugin_tried = true;
try {
ext_seed_plugin = (ExternalSeedPlugin)AzureusCoreFactory.getSingleton().getPluginManager().getPluginInterfaceByClass(
ExternalSeedPlugin.class).getPlugin();
}catch (Throwable e){
Debug.printStackTrace( e );
}
}
return( ext_seed_plugin );
}
// DISK listeners
private static final int LDT_DL_ADDED = 1;
private static final int LDT_DL_REMOVED = 2;
private static ListenerManager disk_listeners_agregator = ListenerManager.createAsyncManager(
"DMC:DiskListenAgregatorDispatcher",
new ListenerManagerDispatcher()
{
public void
dispatch(
Object _listener,
int type,
Object value )
{
DownloadManagerDiskListener listener = (DownloadManagerDiskListener)_listener;
if ( type == LDT_DL_ADDED ){
listener.diskManagerAdded((DiskManager)value);
}else if ( type == LDT_DL_REMOVED ){
listener.diskManagerRemoved((DiskManager)value);
}
}
});
private ListenerManager disk_listeners = ListenerManager.createManager(
"DMC:DiskListenDispatcher",
new ListenerManagerDispatcher()
{
public void
dispatch(
Object listener,
int type,
Object value )
{
disk_listeners_agregator.dispatch( listener, type, value );
}
});
private AEMonitor disk_listeners_mon = new AEMonitor( "DownloadManagerController:DL" );
protected AEMonitor this_mon = new AEMonitor( "DownloadManagerController" );
protected AEMonitor state_mon = new AEMonitor( "DownloadManagerController:State" );
protected AEMonitor facade_mon = new AEMonitor( "DownloadManagerController:Facade" );
private DownloadManagerImpl download_manager;
private DownloadManagerStatsImpl stats;
// these are volatile as we want to ensure that if a state is read it is always the
// most up to date value available (as we don't synchronize state read - see below
// for comments)
private volatile int state_set_by_method = DownloadManager.STATE_START_OF_DAY;
private volatile int substate;
private volatile boolean force_start;
// to try and ensure people don't start using disk_manager without properly considering its
// access implications we've given it a silly name
private volatile DiskManager disk_manager_use_accessors;
private DiskManagerListener disk_manager_listener_use_accessors;
private fileInfoFacade[] files_facade = new fileInfoFacade[0]; // default before torrent avail
private boolean files_facade_destroyed;
private boolean cached_complete_excluding_dnd;
private boolean cached_has_dnd_files;
private boolean cached_values_set;
private PeerManagerRegistration peer_manager_registration;
private PEPeerManager peer_manager;
private String errorDetail;
private GlobalManagerStats global_stats;
private boolean bInitialized = false;
private long data_send_rate_at_close;
private static final int ACTIVATION_REBUILD_TIME = 10*60*1000;
private static final int BLOOM_SIZE = 64;
private volatile BloomFilter activation_bloom;
private volatile long activation_bloom_create_time = SystemTime.getCurrentTime();
private volatile int activation_count;
private volatile long activation_count_time;
protected
DownloadManagerController(
DownloadManagerImpl _download_manager )
{
download_manager = _download_manager;
GlobalManager gm = download_manager.getGlobalManager();
global_stats = gm.getStats();
stats = (DownloadManagerStatsImpl)download_manager.getStats();
cached_values_set = false;
}
protected void
setInitialState(
int initial_state )
{
// only take note if there's been no errors
bInitialized = true;
if ( getState() == DownloadManager.STATE_START_OF_DAY ){
setState( initial_state, true );
}
TOTorrent torrent = download_manager.getTorrent();
if (torrent != null) {
try{
peer_manager_registration = PeerManager.getSingleton().registerLegacyManager( torrent.getHashWrapper(), this );
}catch( TOTorrentException e ){
Debug.printStackTrace(e);
}
}
DownloadManagerState state = download_manager.getDownloadState();
if (state.parameterExists(DownloadManagerState.PARAM_DND_FLAGS)) {
long flags = state.getLongParameter(DownloadManagerState.PARAM_DND_FLAGS);
cached_complete_excluding_dnd = (flags & STATE_FLAG_COMPLETE_NO_DND) != 0;
cached_has_dnd_files = (flags & STATE_FLAG_HASDND) != 0;
cached_values_set = true;
}
}
public void
startDownload(
TRTrackerAnnouncer tracker_client )
{
DiskManager dm;
try{
this_mon.enter();
if ( getState() != DownloadManager.STATE_READY ){
Debug.out( "DownloadManagerController::startDownload state must be ready, " + getState());
setFailed( "Inconsistent download state: startDownload, state = " + getState());
return;
}
if ( tracker_client == null ){
Debug.out( "DownloadManagerController:startDownload: tracker_client is null" );
// one day we should really do a proper state machine for this. In the meantime...
// probably caused by a "stop" during initialisation, I've reproduced it once or twice
// in my life... Tidy things up so we don't sit here in a READ state that can't
// be started.
stopIt( DownloadManager.STATE_STOPPED, false, false );
return;
}
if ( peer_manager != null ){
Debug.out( "DownloadManagerController::startDownload: peer manager not null" );
// try and continue....
peer_manager.stopAll();
peer_manager = null;
}
dm = getDiskManager();
if ( dm == null ){
Debug.out( "DownloadManagerController::startDownload: disk manager is null" );
return;
}
setState( DownloadManager.STATE_DOWNLOADING, false );
}finally{
this_mon.exit();
}
// make sure it is started before making it "visible"
final PEPeerManager temp = PEPeerManagerFactory.create( tracker_client.getPeerId(), this, dm );
temp.start();
//The connection to the tracker
tracker_client.setAnnounceDataProvider(
new TRTrackerAnnouncerDataProvider()
{
public String
getName()
{
return( getDisplayName());
}
public long
getTotalSent()
{
return(temp.getStats().getTotalDataBytesSent());
}
public long
getTotalReceived()
{
long verified =
temp.getStats().getTotalDataBytesReceived() -
( temp.getStats().getTotalDiscarded() + temp.getStats().getTotalHashFailBytes());
return( verified < 0?0:verified );
}
public long
getRemaining()
{
return( temp.getRemaining());
}
public String
getExtensions()
{
return( getTrackerClientExtensions());
}
public int
getMaxNewConnectionsAllowed()
{
return( temp.getMaxNewConnectionsAllowed());
}
public int
getUploadSpeedKBSec(
boolean estimate )
{
long current_local = stats.getDataSendRate();
if ( estimate ){
// see if we have an old value from previous stop/start
current_local = data_send_rate_at_close;
if ( current_local == 0 ){
int current_global = global_stats.getDataSendRate();
int old_global = global_stats.getDataSendRateAtClose();
if ( current_global < old_global ){
current_global = old_global;
}
List managers = download_manager.getGlobalManager().getDownloadManagers();
int num_dls = 0;
// be optimistic and share out the bytes between non-seeds
for (int i=0;i<managers.size();i++){
DownloadManager dm = (DownloadManager)managers.get(i);
if ( dm.getStats().getDownloadCompleted( false ) == 1000 ){
continue;
}
int state = dm.getState();
if ( state != DownloadManager.STATE_ERROR &&
state != DownloadManager.STATE_STOPPING &&
state != DownloadManager.STATE_STOPPED ){
num_dls++;
}
}
if ( num_dls == 0 ){
current_local = current_global;
}else{
current_local = current_global/num_dls;
}
}
}
return((int)((current_local+1023)/1024 ));
}
});
peer_manager = temp;
// Inform only after peer_manager.start(), because it
// may have switched it to STATE_SEEDING (in which case we don't need to
// inform).
if (getState() == DownloadManager.STATE_DOWNLOADING) {
download_manager.informStateChanged();
}
download_manager.informStarted( temp );
}
public void
initializeDiskManager(
final boolean open_for_seeding )
{
initializeDiskManagerSupport(
DownloadManager.STATE_INITIALIZED,
new DiskManagerListener()
{
public void
stateChanged(
int oldDMState,
int newDMState )
{
DiskManager dm;
try{
this_mon.enter();
dm = getDiskManager();
if ( dm == null ){
// already been cleared down
return;
}
}finally{
this_mon.exit();
}
try{
if ( newDMState == DiskManager.FAULTY ){
setFailed( dm.getErrorMessage());
}
if ( oldDMState == DiskManager.CHECKING ){
// good time to trigger minimum file info fixup as the disk manager's
// files are now in a good state
makeSureFilesFacadeFilled(true);
stats.setDownloadCompleted(stats.getDownloadCompleted(true));
download_manager.setAssumedComplete(isDownloadComplete(false));
}
if ( newDMState == DiskManager.READY ){
if ( stats.getTotalDataBytesReceived() == 0 &&
stats.getTotalDataBytesSent() == 0 &&
stats.getSecondsDownloading() == 0 ){
int completed = stats.getDownloadCompleted(false);
if ( completed < 1000 ){
if ( open_for_seeding ){
setFailed( "File check failed" );
download_manager.getDownloadState().clearResumeData();
}else{
// make up some sensible "downloaded" figure for torrents that have been re-added to Azureus
// and resumed
// assume downloaded = uploaded, optimistic but at least results in
// future share ratios relevant to amount up/down from now on
// see bug 1077060
long amount_downloaded = (completed*dm.getTotalLength())/1000;
stats.setSavedDownloadedUploaded( amount_downloaded, amount_downloaded );
}
}else{
// see GlobalManager for comment on this
int dl_copies = COConfigurationManager.getIntParameter("StartStopManager_iAddForSeedingDLCopyCount");
if ( dl_copies > 0 ){
stats.setSavedDownloadedUploaded( download_manager.getSize()*dl_copies, stats.getTotalDataBytesSent());
}
download_manager.getDownloadState().setFlag( DownloadManagerState.FLAG_ONLY_EVER_SEEDED, true );
}
}
}
}finally{
download_manager.informStateChanged();
}
}
public void
filePriorityChanged(
DiskManagerFileInfo file )
{
download_manager.informPriorityChange( file );
}
public void
pieceDoneChanged(
DiskManagerPiece piece )
{
}
public void
fileAccessModeChanged(
DiskManagerFileInfo file,
int old_mode,
int new_mode )
{
}
});
}
protected void
initializeDiskManagerSupport(
int initialising_state,
DiskManagerListener listener )
{
try{
this_mon.enter();
int entry_state = getState();
if ( entry_state != DownloadManager.STATE_WAITING &&
entry_state != DownloadManager.STATE_STOPPED &&
entry_state != DownloadManager.STATE_QUEUED &&
entry_state != DownloadManager.STATE_ERROR ){
Debug.out( "DownloadManagerController::initializeDiskManager: Illegal initialize state, " + entry_state );
setFailed( "Inconsistent download state: initSupport, state = " + entry_state );
return;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -