mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-29 06:27:05 +00:00
Merge pull request #21606 from lavalamp/fix-cache-lock
Auto commit by PR queue bot
This commit is contained in:
commit
c44c63c20e
@ -171,9 +171,8 @@ func NewCacherFromConfig(config CacherConfig) *Cacher {
|
|||||||
stopCh: make(chan struct{}),
|
stopCh: make(chan struct{}),
|
||||||
stopWg: sync.WaitGroup{},
|
stopWg: sync.WaitGroup{},
|
||||||
}
|
}
|
||||||
|
// See startCaching method for explanation and where this is unlocked.
|
||||||
cacher.usable.Lock()
|
cacher.usable.Lock()
|
||||||
// See startCaching method for why explanation on it.
|
|
||||||
watchCache.SetOnReplace(func() { cacher.usable.Unlock() })
|
|
||||||
watchCache.SetOnEvent(cacher.processEvent)
|
watchCache.SetOnEvent(cacher.processEvent)
|
||||||
|
|
||||||
stopCh := cacher.stopCh
|
stopCh := cacher.stopCh
|
||||||
@ -192,16 +191,22 @@ func NewCacherFromConfig(config CacherConfig) *Cacher {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *Cacher) startCaching(stopChannel <-chan struct{}) {
|
func (c *Cacher) startCaching(stopChannel <-chan struct{}) {
|
||||||
// Whenever we enter startCaching method, usable mutex is held.
|
// The 'usable' lock is always 'RLock'able when it is safe to use the cache.
|
||||||
// We explicitly do NOT Unlock it in this method, because we do
|
// It is safe to use the cache after a successful list until a disconnection.
|
||||||
// not want to allow any Watch/List methods not explicitly redirected
|
// We start with usable (write) locked. The below OnReplace function will
|
||||||
// to the underlying storage when the cache is being initialized.
|
// unlock it after a successful list. The below defer will then re-lock
|
||||||
// Once the underlying cache is propagated, onReplace handler will
|
// it when this function exits (always due to disconnection), only if
|
||||||
// be called, which will do the usable.Unlock() as configured in
|
// we actually got a successful list. This cycle will repeat as needed.
|
||||||
// NewCacher().
|
successfulList := false
|
||||||
// Note: the same behavior is also triggered every time we fall out of
|
c.watchCache.SetOnReplace(func() {
|
||||||
// backend storage watch event window.
|
successfulList = true
|
||||||
defer c.usable.Lock()
|
c.usable.Unlock()
|
||||||
|
})
|
||||||
|
defer func() {
|
||||||
|
if successfulList {
|
||||||
|
c.usable.Lock()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
c.terminateAllWatchers()
|
c.terminateAllWatchers()
|
||||||
// Note that since onReplace may be not called due to errors, we explicitly
|
// Note that since onReplace may be not called due to errors, we explicitly
|
||||||
|
@ -17,6 +17,7 @@ limitations under the License.
|
|||||||
package storage_test
|
package storage_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strconv"
|
"strconv"
|
||||||
"testing"
|
"testing"
|
||||||
@ -171,8 +172,23 @@ func verifyWatchEvent(t *testing.T, w watch.Interface, eventType watch.EventType
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type injectListError struct {
|
||||||
|
errors int
|
||||||
|
storage.Interface
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *injectListError) List(ctx context.Context, key string, resourceVersion string, filter storage.FilterFunc, listObj runtime.Object) error {
|
||||||
|
if self.errors > 0 {
|
||||||
|
self.errors--
|
||||||
|
return fmt.Errorf("injected error")
|
||||||
|
}
|
||||||
|
return self.Interface.List(ctx, key, resourceVersion, filter, listObj)
|
||||||
|
}
|
||||||
|
|
||||||
func TestWatch(t *testing.T) {
|
func TestWatch(t *testing.T) {
|
||||||
server, etcdStorage := newEtcdTestStorage(t, testapi.Default.Codec(), etcdtest.PathPrefix())
|
server, etcdStorage := newEtcdTestStorage(t, testapi.Default.Codec(), etcdtest.PathPrefix())
|
||||||
|
// Inject one list error to make sure we test the relist case.
|
||||||
|
etcdStorage = &injectListError{errors: 1, Interface: etcdStorage}
|
||||||
defer server.Terminate(t)
|
defer server.Terminate(t)
|
||||||
cacher := newTestCacher(etcdStorage)
|
cacher := newTestCacher(etcdStorage)
|
||||||
defer cacher.Stop()
|
defer cacher.Stop()
|
||||||
|
Loading…
Reference in New Issue
Block a user