<commit_before>package worker

import (
	"errors"
	"fmt"
	"math/rand"
	"time"

	"github.com/concourse/atc/db"
	"github.com/pivotal-golang/lager"
)

//go:generate counterfeiter . WorkerProvider

type WorkerProvider interface {
	Workers() ([]Worker, error)
	GetWorker(string) (Worker, bool, error)
	FindContainerInfoForIdentifier(Identifier) (db.ContainerInfo, bool, error)
	GetContainerInfo(string) (db.ContainerInfo, bool, error)
}

var (
	ErrNoWorkers        = errors.New("no workers")
	ErrDBGardenMismatch = errors.New("discrepancy between db and garden worker containers found")
)

type NoCompatibleWorkersError struct {
	Spec    WorkerSpec
	Workers []Worker
}

func (err NoCompatibleWorkersError) Error() string {
	availableWorkers := ""
	for _, worker := range err.Workers {
		availableWorkers += "\n  - " + worker.Description()
	}

	return fmt.Sprintf(
		"no workers satisfying: %s\n\navailable workers: %s",
		err.Spec.Description(),
		availableWorkers,
	)
}

type pool struct {
	provider WorkerProvider

	rand *rand.Rand
}

func NewPool(provider WorkerProvider) Client {
	return &pool{
		provider: provider,
		rand:     rand.New(rand.NewSource(time.Now().UnixNano())),
	}
}

func (pool *pool) Satisfying(spec WorkerSpec) (Worker, error) {
	workers, err := pool.provider.Workers()
	if err != nil {
		return nil, err
	}

	if len(workers) == 0 {
		return nil, ErrNoWorkers
	}

	compatibleWorkers := []Worker{}
	for _, worker := range workers {
		satisfyingWorker, err := worker.Satisfying(spec)
		if err == nil {
			compatibleWorkers = append(compatibleWorkers, satisfyingWorker)
		}
	}

	if len(compatibleWorkers) == 0 {
		return nil, NoCompatibleWorkersError{
			Spec:    spec,
			Workers: workers,
		}
	}

	randomWorker := compatibleWorkers[pool.rand.Intn(len(compatibleWorkers))]

	return randomWorker, nil
}

func (pool *pool) CreateContainer(logger lager.Logger, id Identifier, spec ContainerSpec) (Container, error) {
	worker, err := pool.Satisfying(spec.WorkerSpec())
	if err != nil {
		return nil, err
	}

	container, err := worker.CreateContainer(logger, id, spec)
	if err != nil {
		return nil, err
	}

	return container, nil
}

func (pool *pool) FindContainerForIdentifier(logger lager.Logger, id Identifier) (Container, bool, error) {
	logger.Info("finding-container-for-identifer", lager.Data{"identifier": id})

	containerInfo, found, err := pool.provider.FindContainerInfoForIdentifier(id)
	if err != nil {
		return nil, false, err
	}

	if !found {
		return nil, found, nil
	}

	worker, found, err := pool.provider.GetWorker(containerInfo.WorkerName)
	if err != nil {
		return nil, found, err
	}

	if !found {
		err = ErrDBGardenMismatch
		logger.Error("found-container-for-missing-worker", err, lager.Data{
			"container-handle": containerInfo.Handle,
			"worker-name":      containerInfo.WorkerName,
		})
		return nil, false, err
	}

	container, found, err := worker.LookupContainer(logger, containerInfo.Handle)
	if err != nil {<commit_msg>remove logging so we don't expose source in logs<commit_after>package worker

import (
	"errors"
	"fmt"
	"math/rand"
	"time"

	"github.com/concourse/atc/db"
	"github.com/pivotal-golang/lager"
)

//go:generate counterfeiter . WorkerProvider

type WorkerProvider interface {
	Workers() ([]Worker, error)
	GetWorker(string) (Worker, bool, error)
	FindContainerInfoForIdentifier(Identifier) (db.ContainerInfo, bool, error)
	GetContainerInfo(string) (db.ContainerInfo, bool, error)
}

var (
	ErrNoWorkers        = errors.New("no workers")
	ErrDBGardenMismatch = errors.New("discrepancy between db and garden worker containers found")
)

type NoCompatibleWorkersError struct {
	Spec    WorkerSpec
	Workers []Worker
}

func (err NoCompatibleWorkersError) Error() string {
	availableWorkers := ""
	for _, worker := range err.Workers {
		availableWorkers += "\n  - " + worker.Description()
	}

	return fmt.Sprintf(
		"no workers satisfying: %s\n\navailable workers: %s",
		err.Spec.Description(),
		availableWorkers,
	)
}

type pool struct {
	provider WorkerProvider

	rand *rand.Rand
}

func NewPool(provider WorkerProvider) Client {
	return &pool{
		provider: provider,
		rand:     rand.New(rand.NewSource(time.Now().UnixNano())),
	}
}

func (pool *pool) Satisfying(spec WorkerSpec) (Worker, error) {
	workers, err := pool.provider.Workers()
	if err != nil {
		return nil, err
	}

	if len(workers) == 0 {
		return nil, ErrNoWorkers
	}

	compatibleWorkers := []Worker{}
	for _, worker := range workers {
		satisfyingWorker, err := worker.Satisfying(spec)
		if err == nil {
			compatibleWorkers = append(compatibleWorkers, satisfyingWorker)
		}
	}

	if len(compatibleWorkers) == 0 {
		return nil, NoCompatibleWorkersError{
			Spec:    spec,
			Workers: workers,
		}
	}

	randomWorker := compatibleWorkers[pool.rand.Intn(len(compatibleWorkers))]

	return randomWorker, nil
}

func (pool *pool) CreateContainer(logger lager.Logger, id Identifier, spec ContainerSpec) (Container, error) {
	worker, err := pool.Satisfying(spec.WorkerSpec())
	if err != nil {
		return nil, err
	}

	container, err := worker.CreateContainer(logger, id, spec)
	if err != nil {
		return nil, err
	}

	return container, nil
}

func (pool *pool) FindContainerForIdentifier(logger lager.Logger, id Identifier) (Container, bool, error) {
	containerInfo, found, err := pool.provider.FindContainerInfoForIdentifier(id)
	if err != nil {
		return nil, false, err
	}

	if !found {
		return nil, found, nil
	}

	worker, found, err := pool.provider.GetWorker(containerInfo.WorkerName)
	if err != nil {
		return nil, found, err
	}

	if !found {
		err = ErrDBGardenMismatch
		logger.Error("found-container-for-missing-worker", err, lager.Data{
			"container-handle": containerInfo.Handle,
			"worker-name":      containerInfo.WorkerName,
		})
		return nil, false, err
	}

	container, found, err := worker.LookupContainer(logger, containerInfo.Handle)
	if err != nil {
{'fraction_non_alphanumeric': 0.12406526172671652, 'fraction_numerical': 0.0006798096532970768, 'mean_word_length': 4.404040404040404, 'pattern_counts': {'":': 5, '<': 3, '<?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': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '712721', 'n_tokens_mistral': 2041, 'n_tokens_neox': 1931, 'n_words': 485}