github.com/kaisenlinux/docker@v0.0.0-20230510090727-ea55db55fac7/swarmkit/api/genericresource/resource_management.go (about)

     1  package genericresource
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/docker/swarmkit/api"
     7  )
     8  
     9  // Claim assigns GenericResources to a task by taking them from the
    10  // node's GenericResource list and storing them in the task's available list
    11  func Claim(nodeAvailableResources, taskAssigned *[]*api.GenericResource,
    12  	taskReservations []*api.GenericResource) error {
    13  	var resSelected []*api.GenericResource
    14  
    15  	for _, res := range taskReservations {
    16  		tr := res.GetDiscreteResourceSpec()
    17  		if tr == nil {
    18  			return fmt.Errorf("task should only hold Discrete type")
    19  		}
    20  
    21  		// Select the resources
    22  		nrs, err := selectNodeResources(*nodeAvailableResources, tr)
    23  		if err != nil {
    24  			return err
    25  		}
    26  
    27  		resSelected = append(resSelected, nrs...)
    28  	}
    29  
    30  	ClaimResources(nodeAvailableResources, taskAssigned, resSelected)
    31  	return nil
    32  }
    33  
    34  // ClaimResources adds the specified resources to the task's list
    35  // and removes them from the node's generic resource list
    36  func ClaimResources(nodeAvailableResources, taskAssigned *[]*api.GenericResource,
    37  	resSelected []*api.GenericResource) {
    38  	*taskAssigned = append(*taskAssigned, resSelected...)
    39  	ConsumeNodeResources(nodeAvailableResources, resSelected)
    40  }
    41  
    42  func selectNodeResources(nodeRes []*api.GenericResource,
    43  	tr *api.DiscreteGenericResource) ([]*api.GenericResource, error) {
    44  	var nrs []*api.GenericResource
    45  
    46  	for _, res := range nodeRes {
    47  		if Kind(res) != tr.Kind {
    48  			continue
    49  		}
    50  
    51  		switch nr := res.Resource.(type) {
    52  		case *api.GenericResource_DiscreteResourceSpec:
    53  			if nr.DiscreteResourceSpec.Value >= tr.Value && tr.Value != 0 {
    54  				nrs = append(nrs, NewDiscrete(tr.Kind, tr.Value))
    55  			}
    56  
    57  			return nrs, nil
    58  		case *api.GenericResource_NamedResourceSpec:
    59  			nrs = append(nrs, res.Copy())
    60  
    61  			if int64(len(nrs)) == tr.Value {
    62  				return nrs, nil
    63  			}
    64  		}
    65  	}
    66  
    67  	if len(nrs) == 0 {
    68  		return nil, fmt.Errorf("not enough resources available for task reservations: %+v", tr)
    69  	}
    70  
    71  	return nrs, nil
    72  }
    73  
    74  // Reclaim adds the resources taken by the task to the node's store
    75  func Reclaim(nodeAvailableResources *[]*api.GenericResource, taskAssigned, nodeRes []*api.GenericResource) error {
    76  	err := reclaimResources(nodeAvailableResources, taskAssigned)
    77  	if err != nil {
    78  		return err
    79  	}
    80  
    81  	sanitize(nodeRes, nodeAvailableResources)
    82  
    83  	return nil
    84  }
    85  
    86  func reclaimResources(nodeAvailableResources *[]*api.GenericResource, taskAssigned []*api.GenericResource) error {
    87  	// The node could have been updated
    88  	if nodeAvailableResources == nil {
    89  		return fmt.Errorf("node no longer has any resources")
    90  	}
    91  
    92  	for _, res := range taskAssigned {
    93  		switch tr := res.Resource.(type) {
    94  		case *api.GenericResource_DiscreteResourceSpec:
    95  			nrs := GetResource(tr.DiscreteResourceSpec.Kind, *nodeAvailableResources)
    96  
    97  			// If the resource went down to 0 it's no longer in the
    98  			// available list
    99  			if len(nrs) == 0 {
   100  				*nodeAvailableResources = append(*nodeAvailableResources, res.Copy())
   101  			}
   102  
   103  			if len(nrs) != 1 {
   104  				continue // Type change
   105  			}
   106  
   107  			nr := nrs[0].GetDiscreteResourceSpec()
   108  			if nr == nil {
   109  				continue // Type change
   110  			}
   111  
   112  			nr.Value += tr.DiscreteResourceSpec.Value
   113  		case *api.GenericResource_NamedResourceSpec:
   114  			*nodeAvailableResources = append(*nodeAvailableResources, res.Copy())
   115  		}
   116  	}
   117  
   118  	return nil
   119  }
   120  
   121  // sanitize checks that nodeAvailableResources does not add resources unknown
   122  // to the nodeSpec (nodeRes) or goes over the integer bound specified
   123  // by the spec.
   124  // Note this is because the user is able to update a node's resources
   125  func sanitize(nodeRes []*api.GenericResource, nodeAvailableResources *[]*api.GenericResource) {
   126  	// - We add the sanitized resources at the end, after
   127  	// having removed the elements from the list
   128  
   129  	// - When a set changes to a Discrete we also need
   130  	// to make sure that we don't add the Discrete multiple
   131  	// time hence, the need of a map to remember that
   132  	var sanitized []*api.GenericResource
   133  	kindSanitized := make(map[string]struct{})
   134  	w := 0
   135  
   136  	for _, na := range *nodeAvailableResources {
   137  		ok, nrs := sanitizeResource(nodeRes, na)
   138  		if !ok {
   139  			if _, ok = kindSanitized[Kind(na)]; ok {
   140  				continue
   141  			}
   142  
   143  			kindSanitized[Kind(na)] = struct{}{}
   144  			sanitized = append(sanitized, nrs...)
   145  
   146  			continue
   147  		}
   148  
   149  		(*nodeAvailableResources)[w] = na
   150  		w++
   151  	}
   152  
   153  	*nodeAvailableResources = (*nodeAvailableResources)[:w]
   154  	*nodeAvailableResources = append(*nodeAvailableResources, sanitized...)
   155  }
   156  
   157  // Returns true if the element is in nodeRes and "sane"
   158  // Returns false if the element isn't in nodeRes and "sane" and the element(s) that should be replacing it
   159  func sanitizeResource(nodeRes []*api.GenericResource, res *api.GenericResource) (ok bool, nrs []*api.GenericResource) {
   160  	switch na := res.Resource.(type) {
   161  	case *api.GenericResource_DiscreteResourceSpec:
   162  		nrs := GetResource(na.DiscreteResourceSpec.Kind, nodeRes)
   163  
   164  		// Type change or removed: reset
   165  		if len(nrs) != 1 {
   166  			return false, nrs
   167  		}
   168  
   169  		// Type change: reset
   170  		nr := nrs[0].GetDiscreteResourceSpec()
   171  		if nr == nil {
   172  			return false, nrs
   173  		}
   174  
   175  		// Amount change: reset
   176  		if na.DiscreteResourceSpec.Value > nr.Value {
   177  			return false, nrs
   178  		}
   179  	case *api.GenericResource_NamedResourceSpec:
   180  		nrs := GetResource(na.NamedResourceSpec.Kind, nodeRes)
   181  
   182  		// Type change
   183  		if len(nrs) == 0 {
   184  			return false, nrs
   185  		}
   186  
   187  		for _, nr := range nrs {
   188  			// Type change: reset
   189  			if nr.GetDiscreteResourceSpec() != nil {
   190  				return false, nrs
   191  			}
   192  
   193  			if na.NamedResourceSpec.Value == nr.GetNamedResourceSpec().Value {
   194  				return true, nil
   195  			}
   196  		}
   197  
   198  		// Removed
   199  		return false, nil
   200  	}
   201  
   202  	return true, nil
   203  }