⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 piecepickerimpl.java

📁 这是一个基于java编写的torrent的P2P源码
💻 JAVA
📖 第 1 页 / 共 5 页
字号:
/*
 * Created by Joseph Bridgewater
 * Created on Jan 2, 2006
 * 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 com.aelitis.azureus.core.peermanager.piecepicker.impl;

import java.util.*;

import org.gudy.azureus2.core3.config.*;
import org.gudy.azureus2.core3.disk.*;
import org.gudy.azureus2.core3.disk.impl.DiskManagerFileInfoImpl;
import org.gudy.azureus2.core3.disk.impl.piecemapper.DMPieceList;
import org.gudy.azureus2.core3.logging.*;
import org.gudy.azureus2.core3.peer.*;
import org.gudy.azureus2.core3.peer.impl.*;
import org.gudy.azureus2.core3.util.*;

import com.aelitis.azureus.core.peermanager.control.PeerControlScheduler;
import com.aelitis.azureus.core.peermanager.piecepicker.*;
import com.aelitis.azureus.core.peermanager.piecepicker.util.BitFlags;
import com.aelitis.azureus.core.peermanager.unchoker.UnchokerUtil;
import com.aelitis.azureus.core.util.CopyOnWriteList;

/**
 * @author MjrTom
 * 
 */

public class PiecePickerImpl
	implements PiecePicker
{
	private static final boolean	LOG_RTA	= false;
	
	private static final LogIDs LOGID = LogIDs.PIECES;

    /** min ms for recalculating availability - reducing this has serious ramifications */
    private static final long TIME_MIN_AVAILABILITY	=974;
    /** min ms for recalculating base priorities */
    private static final long TIME_MIN_PRIORITIES	=999;
    /** min ms for forced availability rebuild */
    private static final long TIME_AVAIL_REBUILD	=5*60*1000 -24; 

	// The following are added to the base User setting based priorities (for all inspected pieces)
    /** user select prioritize first/last */
	private static final int PRIORITY_W_FIRSTLAST	=1300;
    /** min # pieces in file for first/last prioritization */
    private static final long FIRST_PIECE_MIN_NB	=4;
    /** number of pieces for first pieces prioritization */
    // private static final int FIRST_PIECE_RANGE_PERCENT= 10;
    /** user sets file as "High" */
    private static final int PRIORITY_W_FILE		=1000;
    /** Additional boost for more completed High priority */
    private static final int PRIORITY_W_COMPLETION	=2000;
  

	// The following are only used when resuming already running pieces
    /** priority boost due to being too old */
    private static final int PRIORITY_W_AGE		=900;
    /** ms a block is expected to complete in */
    private static final int PRIORITY_DW_AGE		=60 *1000;
    /** ms since last write */
    private static final int PRIORITY_DW_STALE		=120 *1000;
    /** finish pieces already almost done */
    private static final int PRIORITY_W_PIECE_DONE	=900;
    /** keep working on same piece */
    private static final int PRIORITY_W_SAME_PIECE	=700;

    	/** currently webseeds + other explicit priorities are around 10000 or more - at this point we ignore rarity */
    
    private static final int PRIORITY_OVERRIDES_RAREST	= 9000;
    
    	/** priority at and above which pieces require real-time scheduling */
    
    private static final int PRIORITY_REALTIME		= 9999999;
    
    /** Min number of requests sent to a peer */
    private static final int REQUESTS_MIN	=2;
    /** Max number of request sent to a peer */
    private static final int REQUESTS_MAX	=256;
	/** Default number of requests sent to a peer, (for each X B/s another request will be used) */
	private static final int SLOPE_REQUESTS	=4 *1024;
	
	private static final long END_GAME_MODE_SIZE_TRIGGER	=20 *1024 *1024;
	private static final long END_GAME_MODE_TIMEOUT			=60 *END_GAME_MODE_SIZE_TRIGGER /16384;
	
	protected static volatile boolean	firstPiecePriority	=COConfigurationManager.getBooleanParameter("Prioritize First Piece" );
	protected static volatile boolean	completionPriority	=COConfigurationManager.getBooleanParameter("Prioritize Most Completed Files");
    /** event # of user settings controlling priority changes */
    protected static volatile long		paramPriorityChange =Long.MIN_VALUE;

    private static final int	NO_REQUEST_BACKOFF_MAX_MILLIS	= 5*1000;
    private static final int	NO_REQUEST_BACKOFF_MAX_LOOPS	= NO_REQUEST_BACKOFF_MAX_MILLIS / PeerControlScheduler.SCHEDULE_PERIOD_MILLIS;
    
    
	private final DiskManager			diskManager;
	private final PEPeerControl			peerControl;
	
	private final DiskManagerListenerImpl	diskManagerListener;
	
	protected final Map					peerListeners;
	private final PEPeerManagerListener	peerManagerListener;
	
	protected final int			nbPieces;
	protected final DiskManagerPiece[]	dmPieces;
	protected final PEPiece[]			pePieces;
	
	protected final AEMonitor availabilityMon = new AEMonitor("PiecePicker:avail");
	private final AEMonitor endGameModeChunks_mon =new AEMonitor("PiecePicker:EGM");

	protected volatile int	nbPiecesDone;
	
    /** asyncronously updated availability */
    protected volatile int[]	availabilityAsynch;
    /** indicates availability needs to be recomputed due to detected drift */
    protected volatile long		availabilityDrift;
    private long				timeAvailRebuild =TIME_AVAIL_REBUILD;
	
    /** periodically updated consistent view of availability for calculating */
    protected volatile int[]	availability;
	
	private long			time_last_avail;
	protected volatile long	availabilityChange;
	private volatile long	availabilityComputeChange;
	private long			time_last_rebuild;
	
	private float		globalAvail;
	private float		globalAvgAvail;
	private int			nbRarestActive;
	private int			globalMin;
	/**
	 * The rarest availability level of pieces that we affirmatively want to try to request from others soonest
	 * ie; our prime targets for requesting rarest pieces
	 */
	private volatile int		globalMinOthers;
	
    /** event # of user file priority settings changes */
    protected volatile long		filePriorityChange;
	
    /** last user parameter settings event # when priority bases were calculated */
    private volatile long		priorityParamChange;
    /** last user priority event # when priority bases were calculated */
    private volatile long		priorityFileChange;
    /** last availability event # when priority bases were calculated */
    private volatile long		priorityAvailChange;
	
    private boolean 			priorityRTAexists;
    
    /** time that base priorities were last computed */
    private long				timeLastPriorities;
	
    /** the priority for starting each piece/base priority for resuming */
    private int[]				startPriorities;
	
	protected volatile boolean	hasNeededUndonePiece;
	protected volatile long		neededUndonePieceChange;
	
	/** A flag to indicate when we're in endgame mode */
	private volatile boolean	endGameMode;
	private volatile boolean	endGameModeAbandoned;
	private volatile long		timeEndGameModeEntered;
	/** The list of chunks needing to be downloaded (the mechanism change when entering end-game mode) */
	private List 				endGameModeChunks;
	
	private long				lastProviderRecalcTime;
	private CopyOnWriteList		rta_providers = new CopyOnWriteList();
	private long[]				provider_piece_rtas;
	private CopyOnWriteList		priority_providers = new CopyOnWriteList();
	private long[]				provider_piece_priorities;

	private int					allocate_request_loop_count;
	
	private CopyOnWriteList		listeners = new CopyOnWriteList();
	
	static
	{
		class ParameterListenerImpl
			implements ParameterListener
		{
			public final void parameterChanged(final String parameterName)
			{
				if (parameterName.equals("Prioritize Most Completed Files"))
				{
					completionPriority =COConfigurationManager.getBooleanParameter(parameterName);
					paramPriorityChange++;	// this is a user's priority change event
				} else if (parameterName.equals("Prioritize First Piece"))
				{
					firstPiecePriority =COConfigurationManager.getBooleanParameter(parameterName);
					paramPriorityChange++;	// this is a user's priority change event
			    }
		    }
		}

		final ParameterListenerImpl	parameterListener =new ParameterListenerImpl();

		COConfigurationManager.addParameterListener("Prioritize Most Completed Files", parameterListener);
		COConfigurationManager.addAndFireParameterListener("Prioritize First Piece", parameterListener);

	}
	
	
	public PiecePickerImpl(final PEPeerControl pc)
	{
		// class administration first

		peerControl	= pc;
		diskManager = peerControl.getDiskManager();
		dmPieces =diskManager.getPieces();

 		nbPieces =diskManager.getNbPieces();
		nbPiecesDone =0;
		
		pePieces = pc.getPieces();
		
		// now do stuff related to availability
		availability =new int[nbPieces];  //always needed
		
		hasNeededUndonePiece =false;
		neededUndonePieceChange =Long.MIN_VALUE;
		
		// ensure all periodic calculaters perform operations at least once
		time_last_avail =Long.MIN_VALUE;
		availabilityChange =Long.MIN_VALUE +1;
		availabilityComputeChange =Long.MIN_VALUE;
		availabilityDrift =nbPieces;
		
		// initialize each piece; on going changes will use event driven tracking
		for (int i =0; i <nbPieces; i++)
		{
			if (dmPieces[i].isDone()){
				availability[i]++;
				nbPiecesDone++;
			}else{
				hasNeededUndonePiece |=dmPieces[i].calcNeeded();
			}
		}
		if (hasNeededUndonePiece)
			neededUndonePieceChange++;
		
		updateAvailability();
		
		// with availability charged and primed, ready for peer messages
		peerListeners =new HashMap();
		peerManagerListener =new PEPeerManagerListenerImpl();
		peerControl.addListener(peerManagerListener);
		
		
		// now do stuff related to starting/continuing pieces
//		startPriorities =new long[nbPieces];    //allocate on demand
		filePriorityChange =Long.MIN_VALUE;
		
		priorityParamChange =Long.MIN_VALUE;
		priorityFileChange =Long.MIN_VALUE;
		priorityAvailChange =Long.MIN_VALUE;
		
		timeLastPriorities =Long.MIN_VALUE;
		
		endGameMode =false;
		endGameModeAbandoned =false;
		timeEndGameModeEntered =0;
		
//		computeBasePriorities();
		
		// with priorities charged and primed, ready for dm messages
		diskManagerListener =new DiskManagerListenerImpl();
		diskManager.addListener(diskManagerListener);
	}
	

    public final void addHavePiece(final PEPeer peer, final int pieceNumber)
	{
    		// peer is null if called from disk-manager callback
		try
		{	availabilityMon.enter();
			if ( availabilityAsynch == null ){
				availabilityAsynch = (int[])availability.clone();
			}
			++availabilityAsynch[pieceNumber];
			availabilityChange++;
		} finally {availabilityMon.exit();}
		
			// if this is an interesting piece then clear any record of "no requests" so the peer gets
			// scheduled next loop
		
		if ( peer != null && dmPieces[pieceNumber].isDownloadable()){
			peer.setConsecutiveNoRequestCount(0);
		}
	}
	
    /**
     * This methd will compute the pieces' overall availability (including ourself)
     * and the _globalMinOthers & _globalAvail
     */
    public final void updateAvailability()
    {
        final long now =SystemTime.getCurrentTime();
        if (now >=time_last_avail &&now <time_last_avail +TIME_MIN_AVAILABILITY)
            return;
        if (availabilityDrift >0 || now < time_last_rebuild ||  (now - time_last_rebuild) > timeAvailRebuild){
            try
            {	availabilityMon.enter();
                
                time_last_rebuild	= now;
                final int[]	new_availability = recomputeAvailability();
                
                if (Constants.isCVSVersion())
                {
                    final int[]   old_availability =availabilityAsynch ==null ?availability :availabilityAsynch;
                    int	    errors	= 0;
                    
                    for (int i=0;i<new_availability.length;i++){
                        if ( new_availability[i] != old_availability[i]){
                            errors++;
                        }
                    }
                    if (errors >0 &&errors !=nbPieces)
                    {
                        if (Logger.isEnabled())
                            Logger.log(new LogEvent(peerControl, LOGID, LogEvent.LT_ERROR,
                                "updateAvailability(): availability rebuild errors =" +errors
                                +" timeAvailRebuild =" +timeAvailRebuild
                            ));

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -