Repository: kubernetes/kubernetes
File: staging/src/k8s.io/dynamic-resource-allocation/structured/internal/incubating/allocator_incubating.go (Go)

Code before:
		slicesOnNode:      slicesOnNode,
		slicesShared:      slicesShared,
		celCache:          celCache,
		availableCounters: make(map[draapi.UniqueString]counterSets),
	}, nil
}

func (a *Allocator) Channel() internal.AllocatorChannel {
	return internal.Incubating
}

func (a *Allocator) Allocate(ctx context.Context, node *v1.Node, claims []*resourceapi.ResourceClaim) (finalResult []resourceapi.AllocationResult, finalErr error) {
	alloc := &allocator{
		Allocator:            a,
		ctx:                  ctx, // all methods share the same a and thus ctx
		logger:               klog.FromContext(ctx),
		node:                 node,
		claimsToAllocate:     claims,
		deviceMatchesRequest: make(map[matchKey]bool),
		constraints:          make([][]constraint, len(claims)),
		consumedCounters:     make(map[draapi.UniqueString]counterSets),
		requestData:          make(map[requestIndices]requestData),
		result:               make([]internalAllocationResult, len(claims)),
	}

	resourceSlices := append(alloc.slicesOnNode[node.Name], alloc.slicesShared...)
	alloc.logger.V(5).Info("Starting allocation", "numClaims", len(alloc.claimsToAllocate), "numSlices", len(resourceSlices))
	defer func() {
		alloc.logger.V(5).Info("Done with allocation", "success", len(finalResult) == len(alloc.claimsToAllocate), "err", finalErr)
	}()

	// First determine all eligible pools.
	pools, err := GatherPools(ctx, resourceSlices, node, a.features)
	if err != nil {
		return nil, fmt.Errorf("gather pool information: %w", err)
	}
	alloc.pools = pools
	alloc.logger.V(5).Info("Gathered pool information", "pools", logPools(alloc.logger, pools))

	// We allocate one claim after the other and for each claim, all of
	// its requests. For each individual device we pick one possible
	// candidate after the other, checking constraints as we go.
	// Each chosen candidate is marked as "in use" and the process
	// continues, recursively. This way, all requests get matched against
	// all candidates in all possible orders.
	//
	// The first full solution is chosen.
	//
	// In other words, this is an exhaustive search. This is okay because
	// it aborts early. Once scoring gets added, more intelligence may be
	// needed to avoid trying "equivalent" solutions (two identical

Review comment (suggestion):
I'm paranoid: this indirectly modifies the `alloc.slicesOnNode[node.Name]` slice by adding more elements in the underlying vector. This should be okay because only a single goroutine will ever do Filter for the given node, but this is a bit speculative and might not always be how this code is called.

I'd be more comfortable with:

```suggestion
	resourceSlices := slices.Concat(alloc.slicesOnNode[node.Name], alloc.slicesShared)
```


Code after:

var _ internal.AllocatorExtended = &Allocator{}

// NewAllocator returns an allocator for a certain set of claims or an error if
// some problem was detected which makes it impossible to allocate claims.
//
// The returned Allocator can be used multiple times and is thread-safe.
func NewAllocator(ctx context.Context,
	features Features,
	allocatedState AllocatedState,
	classLister DeviceClassLister,
	slices []*resourceapi.ResourceSlice,
	celCache *cel.Cache,
) (*Allocator, error) {
	slicesOnNode := make(map[string][]*resourceapi.ResourceSlice)
	slicesShared := make([]*resourceapi.ResourceSlice, 0)
	for _, slice := range slices {
		nodeName := ptr.Deref(slice.Spec.NodeName, "")
		if nodeName == "" || len(slice.Spec.SharedCounters) > 0 {
			slicesShared = append(slicesShared, slice)
		} else {
			slicesOnNode[nodeName] = append(slicesOnNode[nodeName], slice)
		}
	}
	return &Allocator{
		features:          features,
		allocatedState:    allocatedState,
		classLister:       classLister,
		slicesOnNode:      slicesOnNode,
		slicesShared:      slicesShared,
		allSlices:         slices,
		celCache:          celCache,
		availableCounters: make(map[draapi.UniqueString]counterSets),
	}, nil
}

func (a *Allocator) Channel() internal.AllocatorChannel {
	return internal.Experimental
}

func (a *Allocator) Allocate(ctx context.Context, node *v1.Node, claims []*resourceapi.ResourceClaim) (finalResult []resourceapi.AllocationResult, finalErr error) {
	alloc := &allocator{
		Allocator:            a,
		ctx:                  ctx, // all methods share the same a and thus ctx
		logger:               klog.FromContext(ctx),
		node:                 node,
		claimsToAllocate:     claims,
		deviceMatchesRequest: make(map[matchKey]bool),
		constraints:          make([][]constraint, len(claims)),
		consumedCounters:     make(map[draapi.UniqueString]counterSets),
		requestData:          make(map[requestIndices]requestData),