// waitUntilFreshAndBlock waits until cache is at least as fresh as given <resourceVersion>. // NOTE: This function acquired lock and doesn't release it. // You HAVE TO explicitly call w.RUnlock() after this function. func (w *watchCache) waitUntilFreshAndBlock(resourceVersion uint64, trace *util.Trace) error { startTime := w.clock.Now() go func() { // Wake us up when the time limit has expired. The docs // promise that time.After (well, NewTimer, which it calls) // will wait *at least* the duration given. Since this go // routine starts sometime after we record the start time, and // it will wake up the loop below sometime after the broadcast, // we don't need to worry about waking it up before the time // has expired accidentally. <-w.clock.After(MaximumListWait) w.cond.Broadcast() }() w.RLock() if trace != nil { trace.Step("watchCache locked acquired") } for w.resourceVersion < resourceVersion { if w.clock.Since(startTime) >= MaximumListWait { return fmt.Errorf("time limit exceeded while waiting for resource version %v (current value: %v)", resourceVersion, w.resourceVersion) } w.cond.Wait() } if trace != nil { trace.Step("watchCache fresh enough") } return nil }
// waitUntilFreshAndBlock waits until cache is at least as fresh as given <resourceVersion>. // NOTE: This function acquired lock and doesn't release it. // You HAVE TO explicitly call w.RUnlock() after this function. func (w *watchCache) waitUntilFreshAndBlock(resourceVersion uint64, trace *util.Trace) error { startTime := w.clock.Now() go func() { // Wake us up when the time limit has expired. The docs // promise that time.After (well, NewTimer, which it calls) // will wait *at least* the duration given. Since this go // routine starts sometime after we record the start time, and // it will wake up the loop below sometime after the broadcast, // we don't need to worry about waking it up before the time // has expired accidentally. <-w.clock.After(blockTimeout) w.cond.Broadcast() }() w.RLock() if trace != nil { trace.Step("watchCache locked acquired") } for w.resourceVersion < resourceVersion { if w.clock.Since(startTime) >= blockTimeout { // Timeout with retry after 1 second. return errors.NewTimeoutError(fmt.Sprintf("Too large resource version: %v, current: %v", resourceVersion, w.resourceVersion), 1) } w.cond.Wait() } if trace != nil { trace.Step("watchCache fresh enough") } return nil }
// Schedule tries to schedule the given pod to one of node in the node list. // If it succeeds, it will return the name of the node. // If it fails, it will return a Fiterror error with reasons. func (g *genericScheduler) Schedule(pod *api.Pod, nodeLister algorithm.NodeLister) (string, error) { var trace *util.Trace if pod != nil { trace = util.NewTrace(fmt.Sprintf("Scheduling %s/%s", pod.Namespace, pod.Name)) } else { trace = util.NewTrace("Scheduling <nil> pod") } defer trace.LogIfLong(20 * time.Millisecond) nodes, err := nodeLister.List() if err != nil { return "", err } if len(nodes) == 0 { return "", ErrNoNodesAvailable } // Used for all fit and priority funcs. err = g.cache.UpdateNodeNameToInfoMap(g.cachedNodeInfoMap) if err != nil { return "", err } trace.Step("Computing predicates") filteredNodes, failedPredicateMap, err := findNodesThatFit(pod, g.cachedNodeInfoMap, nodes, g.predicates, g.extenders) if err != nil { return "", err } if len(filteredNodes) == 0 { return "", &FitError{ Pod: pod, FailedPredicates: failedPredicateMap, } } trace.Step("Prioritizing") meta := g.priorityMetaProducer(pod) priorityList, err := PrioritizeNodes(pod, g.cachedNodeInfoMap, meta, g.prioritizers, filteredNodes, g.extenders) if err != nil { return "", err } trace.Step("Selecting host") return g.selectHost(priorityList) }