<commit_before>package renter

// TODO: Need to make sure that we do not end up with two workers for the same
// host, which could potentially happen over renewals because the contract ids
// will be different.

import (
	"errors"
	"time"

	"github.com/NebulousLabs/Sia/build"
	"github.com/NebulousLabs/Sia/crypto"
	"github.com/NebulousLabs/Sia/types"
)

var (
	// errWorkerDoesNotExist is returned if retireWorker is called for a
	// contract id that does not have a worker associated with it.
	errWorkerDoesNotExist = errors.New("no worker exists for that contract id")

	// errWorkerExists is returned if addWorker is called for a contract id
	// that already has a worker.
	errWorkerExists = errors.New("there is already a worker for that contract id")
)

type (
	// downloadWork contains instructions to download a piece from a host, and
	// a channel for returning the results.
	downloadWork struct {
		// dataRoot is the MerkleRoot of the data being requested, which serves
		// as an ID when requesting data from the host.
		dataRoot   crypto.Hash
		pieceIndex uint64

		chunkDownload *chunkDownload

		// resultChan is a channel that the worker will use to return the
		// results of the download.
		resultChan chan finishedDownload
	}

	// finishedDownload contains the data and error from performing a download.
	finishedDownload struct {
		chunkDownload *chunkDownload
		data          []byte
		err           error
		pieceIndex    uint64
		workerID      types.FileContractID
	}

	// finishedUpload contains the Merkle root and error from performing an
	// upload.
	finishedUpload struct {
		chunkID    chunkID
		dataRoot   crypto.Hash
		err        error
		pieceIndex uint64
		workerID   types.FileContractID
	}

	// uploadWork contains instructions to upload a piece to a host, and a
	// channel for returning the results.
	uploadWork struct {
		// data is the payload of the upload.
		chunkID    chunkID
		data       []byte
		file       *file
		pieceIndex uint64

		// resultChan is a channel that the worker will use to return the
		// results of the upload.
		resultChan chan finishedUpload
	}

	// A worker listens for work on a certain host.
	worker struct {
		// contractID specifies which contract the worker specifically works
		// with.
		contractID types.FileContractID

		// If there is work on all three channels, the worker will first do all
		// of the work in the download chan, then all of the work in the
		// priority upload chan, and finally all of the work in the upload
		// chan.
		//
		// A busy higher priority channel is able to entriely starve all of the
		// channels with lower priority.
		downloadChan         chan downloadWork // higher priority than all uploads
		killChan             chan struct{}     // highest priority
		priorityDownloadChan chan downloadWork // higher priority than downloads (used for user-initiated downloads)
		uploadChan           chan uploadWork   // lowest priority

		// recentUploadFailure documents the most recent time that an upload
		// has failed. The repair loop ignores workers that have had an upload
		// failure in the past two hours.
		recentUploadFailure time.Time

		// Utilities
		renter *Renter
	}
)

// download will perform some download work.
func (w *worker) download(dw downloadWork) {
	d, err := w.renter.hostContractor.Downloader(w.contractID)
	if err != nil {
		dw.resultChan <- finishedDownload{dw.chunkDownload, nil, err, dw.pieceIndex, w.contractID}
		return
	}
	defer d.Close()

	data, err := d.Sector(dw.dataRoot)
	dw.resultChan <- finishedDownload{dw.chunkDownload, data, err, dw.pieceIndex, w.contractID}
}

// upload will perform some upload work.
func (w *worker) upload(uw uploadWork) {
	e, err := w.renter.hostContractor.Editor(w.contractID)
	if err != nil {<commit_msg>add early exit to download work<commit_after>package renter

// TODO: Need to make sure that we do not end up with two workers for the same
// host, which could potentially happen over renewals because the contract ids
// will be different.

import (
	"errors"
	"time"

	"github.com/NebulousLabs/Sia/build"
	"github.com/NebulousLabs/Sia/crypto"
	"github.com/NebulousLabs/Sia/types"
)

var (
	// errWorkerDoesNotExist is returned if retireWorker is called for a
	// contract id that does not have a worker associated with it.
	errWorkerDoesNotExist = errors.New("no worker exists for that contract id")

	// errWorkerExists is returned if addWorker is called for a contract id
	// that already has a worker.
	errWorkerExists = errors.New("there is already a worker for that contract id")
)

type (
	// downloadWork contains instructions to download a piece from a host, and
	// a channel for returning the results.
	downloadWork struct {
		// dataRoot is the MerkleRoot of the data being requested, which serves
		// as an ID when requesting data from the host.
		dataRoot   crypto.Hash
		pieceIndex uint64

		chunkDownload *chunkDownload

		// resultChan is a channel that the worker will use to return the
		// results of the download.
		resultChan chan finishedDownload
	}

	// finishedDownload contains the data and error from performing a download.
	finishedDownload struct {
		chunkDownload *chunkDownload
		data          []byte
		err           error
		pieceIndex    uint64
		workerID      types.FileContractID
	}

	// finishedUpload contains the Merkle root and error from performing an
	// upload.
	finishedUpload struct {
		chunkID    chunkID
		dataRoot   crypto.Hash
		err        error
		pieceIndex uint64
		workerID   types.FileContractID
	}

	// uploadWork contains instructions to upload a piece to a host, and a
	// channel for returning the results.
	uploadWork struct {
		// data is the payload of the upload.
		chunkID    chunkID
		data       []byte
		file       *file
		pieceIndex uint64

		// resultChan is a channel that the worker will use to return the
		// results of the upload.
		resultChan chan finishedUpload
	}

	// A worker listens for work on a certain host.
	worker struct {
		// contractID specifies which contract the worker specifically works
		// with.
		contractID types.FileContractID

		// If there is work on all three channels, the worker will first do all
		// of the work in the download chan, then all of the work in the
		// priority upload chan, and finally all of the work in the upload
		// chan.
		//
		// A busy higher priority channel is able to entriely starve all of the
		// channels with lower priority.
		downloadChan         chan downloadWork // higher priority than all uploads
		killChan             chan struct{}     // highest priority
		priorityDownloadChan chan downloadWork // higher priority than downloads (used for user-initiated downloads)
		uploadChan           chan uploadWork   // lowest priority

		// recentUploadFailure documents the most recent time that an upload
		// has failed. The repair loop ignores workers that have had an upload
		// failure in the past two hours.
		recentUploadFailure time.Time

		// Utilities
		renter *Renter
	}
)

// download will perform some download work.
func (w *worker) download(dw downloadWork) {
	d, err := w.renter.hostContractor.Downloader(w.contractID)
	if err != nil {
		select {
		case dw.resultChan <- finishedDownload{dw.chunkDownload, nil, err, dw.pieceIndex, w.contractID}:
		case <-w.renter.tg.StopChan():
		}
		return
	}
	defer d.Close()

	data, err := d.Sector(dw.dataRoot)
	select {
	case dw.resultChan <- finishedDownload{dw.chunkDownload, data, err, dw.pieceIndex, w.contractID}:
	case <-w.renter.tg.StopChan():
	}
}

// upload will perform some upload work.
func (w *worker) upload(uw uploadWork) {
	e, err := w.renter.hostContractor.Editor(w.contractID)
	if err != nil {
{'fraction_non_alphanumeric': 0.06879478827361564, 'fraction_numerical': 0.002084690553745928, 'mean_word_length': 3.1380053908355796, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 57, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4193443', 'n_tokens_mistral': 2303, 'n_tokens_neox': 2115, 'n_words': 913}