func NewPieceData(bitfield *bit_field.Bitfield, pieceLength, lastPieceLength int64) (p *PieceData) { p = new(PieceData) p.pieces = make(map[int64]*Piece, bitfield.Len()) p.peers = make(map[string]map[uint64]int64, ACTIVE_PEERS+INCOMING_PEERS) p.bitfield = bitfield p.pieceLength = pieceLength p.lastPieceLength = lastPieceLength return }
func (pd *PieceData) SearchPiece(addr string, bitfield *bit_field.Bitfield) (rpiece int64, rblock int, err os.Error) { // Check if peer has some of the active pieces to finish them //log.Println("PieceData -> Searching for an already present piece") for k, piece := range pd.pieces { available := -1 for block, downloads := range piece.downloaderCount { if downloads == 0 { available = block break } } if available != -1 && bitfield.IsSet(k) { // Send request piece k, block available pd.Add(addr, k, available) rpiece, rblock = k, available return } } //log.Println("PieceData -> No suitable piece found in active set") // Check what piece we can request totalPieces := pd.bitfield.Len() bytes := bitfield.Bytes() start := rand.Int63n(totalPieces) // Search fordward //log.Println("PieceData -> Searching fordwards") for piece := pd.bitfield.FindNextPiece(start, bytes); piece != -1 && piece < totalPieces; piece = pd.bitfield.FindNextPiece(piece+1, bytes) { //log.Println("PieceData -> Piece found, see if it's already in active piece set:", piece) if _, ok := pd.pieces[piece]; !ok { // Add new piece to set pd.Add(addr, piece, 0) rpiece, rblock = piece, 0 return } } // Search backwards //log.Println("PieceData -> Searching backwards") for piece := pd.bitfield.FindNextPiece(0, bytes); piece != -1 && piece < start; piece = pd.bitfield.FindNextPiece(piece+1, bytes) { //log.Println("PieceData -> Piece found, see if it's already in active piece set:", piece) if _, ok := pd.pieces[piece]; !ok { // Add new piece to set pd.Add(addr, piece, 0) rpiece, rblock = piece, 0 return } } // If all pieces are taken, double up on an active piece // if only 20% of pieces remaining //log.Println("PieceData -> Trying to enter endgame mode") if float64(pd.bitfield.Count())/float64(pd.bitfield.Len()) < 0.80 { err = os.NewError("No available block found") return } //log.Println("PieceData -> Doubling up on an active piece") first := true min := 0 for k, piece := range pd.pieces { for block, downloads := range piece.downloaderCount { if bitfield.IsSet(k) && !pd.CheckRequested(addr, k, block) { if first && downloads != -1 { rpiece, rblock, min = k, block, downloads first = false } if downloads != -1 && downloads < min { rpiece, rblock, min = k, block, downloads } } } } if !first && min < MAX_PIECE_REQUESTS { pd.Add(addr, rpiece, rblock) return } err = os.NewError("No available block found") return }