Improve config locking by using optimistic locking strategy

Loop using jitter until the update succeeds
This commit is contained in:
Brice Fernandes authored and Bryan Boreham committed 2017-11-14 14:06:33 +00:00
1 parent 71b39489da
commit 497dddabc1
2 files changed
+50 -18

No files matched your search

+33 -3
View File
@@ -2,12 +2,15 @@ package main
import (
"encoding/json"
"log"
"time"
"github.com/pkg/errors"
v1 "k8s.io/api/core/v1"
kubeErrors "k8s.io/apimachinery/pkg/api/errors"
api "k8s.io/apimachinery/pkg/apis/meta/v1"
wait "k8s.io/apimachinery/pkg/util/wait"
kubernetes "k8s.io/client-go/kubernetes"
corev1client "k8s.io/client-go/kubernetes/typed/core/v1"
)
@@ -50,6 +53,9 @@ func (pl *peerList) add(peerName string, name string) {
}
const (
retryPeriod = time.Second * 2
jitterFactor = 1.0
// KubePeersAnnotationKey is the default annotation key
KubePeersAnnotationKey = "kube-peers.weave.works/peers"
)
@@ -99,7 +105,6 @@ func (cml *configMapAnnotations) GetPeerList() (*peerList, error) {
return &record, nil
}
// Update will update and existing annotation on a given resource.
func (cml *configMapAnnotations) UpdatePeerList(list peerList) error {
if cml.cm == nil {
return errors.New("endpoint not initialized, call Init first")
@@ -108,7 +113,32 @@ func (cml *configMapAnnotations) UpdatePeerList(list peerList) error {
if err != nil {
return err
}
cml.cm.Annotations[KubePeersAnnotationKey] = string(recordBytes)
cml.cm, err = cml.Client.ConfigMaps(cml.Namespace).Update(cml.cm)
cm := cml.cm
cm.Annotations[KubePeersAnnotationKey] = string(recordBytes)
cm, err = cml.Client.ConfigMaps(cml.Namespace).Update(cml.cm)
if err == nil {
cml.cm = cm
}
return err
}
// Loop with jitter, fetching the cml data and calling f() until it
// doesn't get an optimistic locking conflict.
// If it succeeds or gets any other kind of error, stop the loop.
func (cml *configMapAnnotations) LoopUpdate(f func() error) error {
stop := make(chan struct{})
var err error
wait.JitterUntil(func() {
if err = cml.Init(); err != nil {
close(stop)
return
}
err = f()
if err != nil && kubeErrors.IsConflict(err) {
log.Printf("Optimistic locking conflict: trying again: %s", err)
return
}
close(stop)
}, retryPeriod, jitterFactor, true, stop)
return err
}
+17 -15
View File
@@ -56,23 +56,25 @@ const (
// update the list of all peers that have gone through this code path
func addMyselfToPeerList(c *kubernetes.Clientset, peerName, name string) (*peerList, error) {
cml := newConfigMapAnnotations(configMapNamespace, configMapName, c)
if err := cml.Init(); err != nil {
return nil, err
}
list, err := cml.GetPeerList()
if err != nil {
return nil, err
}
log.Println("Fetched existing peer list", list)
if !list.contains(peerName) {
list.add(peerName, name)
log.Println("Storing new peer list", list)
err = cml.UpdatePeerList(*list)
var list *peerList
err := cml.LoopUpdate(func() error {
var err error
list, err = cml.GetPeerList()
if err != nil {
return nil, err
return err
}
}
return list, nil
log.Println("Fetched existing peer list", list)
if !list.contains(peerName) {
list.add(peerName, name)
log.Println("Storing new peer list", list)
err = cml.UpdatePeerList(*list)
if err != nil {
return err
}
}
return nil
})
return list, err
}
func main() {