Change:
<!-- Please use this template while reporting a bug and provide as much info as possible. Not doing so may result in your bug not being addressed in a timely manner. Thanks! If the matter is security related, please disclose it privately via --What happened: In the new scheduler framework, plugins and scheduler core share the same , both of them use the returned by ) the in the beginning of every schedule cycle, plugins(e.g. permit plugins, bind plugins) in another goroutine might read the in the same time. Then there will be a concurrent read/write error(refer ). What you expected to happen: No concurrent read/write error happens. How to reproduce it (as minimally and precisely as possible): Anything else we need to know?: Environment: Kubernetes version (use ): Cloud provider or hardware configuration: OS (e.g: ): Kernel (e.g. ): Install tools: Network plugin and version (if this is a network-related bug): Others: /sig scheduling /assign /cc
That is a very good catch. The binding cycle is run in a , and so updating NodeInfoSnapshot could happen concurrently with the execution of permit/prebind/bind/postbind plugins of another pod.
There are 3 proposals to solve it: Proposal 1: Add a RWLock for the struct . It is an intuitive solution. Code need to hold a lock when visiting data of . Pros: No need to change the interface of . There should be little performance impact since most operations are read, RWLock works well for this case. But if plugins hold RLock for quite a long time, it will impact the scheduler core framework to update the , there is no promise for it. Cons: Code need to hold a lock first. And it is error prone for plugins to forget it. Proposal 2: Add other methods for interface , replacing with and , it works similar to 's two method and . Pros: Easy to use We could avoid exposing internal struct to users. Cons: Need to change the interface of . We will use RWLock to implement it. So the cons of proposal 1 also exist: If plugins hold RLock for quite a long time, it will impact the scheduler core framework to update the , there is no promise for it. Update: I checked the Golang's RWLock's implementation, it is writers-preference. So we do not need to worry about it now. Proposal 3: Use  instead of for in the struct . Pros: is useful for this case Cons: There might be some performance impact by for some cases(Ref: , ). We need change a lot related code because 's interface is different from plain Go map. Conclusion: I prefer to choose proposal 2, because it is easier to use and it is acceptable to change interface at alpha stage, and we could find other ways to solve the .
A NodeInfo snapshot is meant to be used during a scheduling cycle, not in a bind cycle. Please refer to . It does not make sense for plugins in "binding cycle" to use the nodeinfo snapshot. A snapshot is meant to be fixed and non-changing. Binding cycle plugins should use the scheduler cache instead.
We have already that the snapshot changes after "Reserve". I think we should expand that comment and explicitly state that plugins in the binding cycle should not use the snapshot.
Documenting sounds good to me, I think the comment should explicitly warn against using it in permit/prebind/bind/postbind plugins, and mention that using it in those plugins is practically a bug.
Thanks for the explanation. It is OK if it is not intended for use by bind cycle. I'll update the document for it. BTW: I could not find any scheduler cache related code in the framework code. Anyway we can add it when it is needed.

Discussion:
// NodeInfoSnapshot return the latest NodeInfo snapshot. The snapshot // is taken at the beginning of a scheduling cycle and remains unchanged until // a pod finishes "Reserve" point. There is no guarantee that the information <del> // remains unchanged in the binding phase of scheduling. </del> <ins> // remains unchanged in the binding phase of scheduling, so plugins in the binding // cycle(permit/pre-bind/bind/post-bind/un-reserve plugin) should not use it, // otherwise a concurrent read/write error might occur, they should use scheduler // cache instead. </ins> NodeInfoSnapshot() *internalcache.NodeInfoSnapshot // IterateOverWaitingPods acquires a read lock and iterates over the WaitingPods map.