Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
K
k3s
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Jacklull
k3s
Commits
6b28a69a
Commit
6b28a69a
authored
Apr 12, 2015
by
David Oppenheimer
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Clarify comments describing how GuaranteedUpdate() (previously AtomicUpdate() works. Closes #6626.
parent
d02139d2
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
27 additions
and
25 deletions
+27
-25
resthandler.go
pkg/apiserver/resthandler.go
+1
-1
etcd.go
pkg/registry/generic/etcd/etcd.go
+1
-1
etcd.go
pkg/registry/pod/etcd/etcd.go
+1
-1
etcd_helper.go
pkg/tools/etcd_helper.go
+12
-10
etcd_helper_test.go
pkg/tools/etcd_helper_test.go
+12
-12
No files found.
pkg/apiserver/resthandler.go
View file @
6b28a69a
...
@@ -244,7 +244,7 @@ func CreateResource(r rest.Creater, scope RequestScope, typer runtime.ObjectType
...
@@ -244,7 +244,7 @@ func CreateResource(r rest.Creater, scope RequestScope, typer runtime.ObjectType
}
}
// PatchResource returns a function that will handle a resource patch
// PatchResource returns a function that will handle a resource patch
// TODO: Eventually PatchResource should just use
Atomic
Update and this routine should be a bit cleaner
// TODO: Eventually PatchResource should just use
Guaranteed
Update and this routine should be a bit cleaner
func
PatchResource
(
r
rest
.
Patcher
,
scope
RequestScope
,
typer
runtime
.
ObjectTyper
,
admit
admission
.
Interface
,
converter
runtime
.
ObjectConvertor
)
restful
.
RouteFunction
{
func
PatchResource
(
r
rest
.
Patcher
,
scope
RequestScope
,
typer
runtime
.
ObjectTyper
,
admit
admission
.
Interface
,
converter
runtime
.
ObjectConvertor
)
restful
.
RouteFunction
{
return
func
(
req
*
restful
.
Request
,
res
*
restful
.
Response
)
{
return
func
(
req
*
restful
.
Request
,
res
*
restful
.
Response
)
{
w
:=
res
.
ResponseWriter
w
:=
res
.
ResponseWriter
...
...
pkg/registry/generic/etcd/etcd.go
View file @
6b28a69a
...
@@ -255,7 +255,7 @@ func (e *Etcd) Update(ctx api.Context, obj runtime.Object) (runtime.Object, bool
...
@@ -255,7 +255,7 @@ func (e *Etcd) Update(ctx api.Context, obj runtime.Object) (runtime.Object, bool
// TODO: expose TTL
// TODO: expose TTL
creating
:=
false
creating
:=
false
out
:=
e
.
NewFunc
()
out
:=
e
.
NewFunc
()
err
=
e
.
Helper
.
Atomic
Update
(
key
,
out
,
true
,
func
(
existing
runtime
.
Object
)
(
runtime
.
Object
,
uint64
,
error
)
{
err
=
e
.
Helper
.
Guaranteed
Update
(
key
,
out
,
true
,
func
(
existing
runtime
.
Object
)
(
runtime
.
Object
,
uint64
,
error
)
{
version
,
err
:=
e
.
Helper
.
Versioner
.
ObjectResourceVersion
(
existing
)
version
,
err
:=
e
.
Helper
.
Versioner
.
ObjectResourceVersion
(
existing
)
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
0
,
err
return
nil
,
0
,
err
...
...
pkg/registry/pod/etcd/etcd.go
View file @
6b28a69a
...
@@ -135,7 +135,7 @@ func (r *BindingREST) setPodHostAndAnnotations(ctx api.Context, podID, oldMachin
...
@@ -135,7 +135,7 @@ func (r *BindingREST) setPodHostAndAnnotations(ctx api.Context, podID, oldMachin
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
err
return
nil
,
err
}
}
err
=
r
.
store
.
Helper
.
Atomic
Update
(
podKey
,
&
api
.
Pod
{},
false
,
func
(
obj
runtime
.
Object
)
(
runtime
.
Object
,
uint64
,
error
)
{
err
=
r
.
store
.
Helper
.
Guaranteed
Update
(
podKey
,
&
api
.
Pod
{},
false
,
func
(
obj
runtime
.
Object
)
(
runtime
.
Object
,
uint64
,
error
)
{
pod
,
ok
:=
obj
.
(
*
api
.
Pod
)
pod
,
ok
:=
obj
.
(
*
api
.
Pod
)
if
!
ok
{
if
!
ok
{
return
nil
,
0
,
fmt
.
Errorf
(
"unexpected object: %#v"
,
obj
)
return
nil
,
0
,
fmt
.
Errorf
(
"unexpected object: %#v"
,
obj
)
...
...
pkg/tools/etcd_helper.go
View file @
6b28a69a
...
@@ -284,31 +284,33 @@ func (h *EtcdHelper) SetObj(key string, obj, out runtime.Object, ttl uint64) err
...
@@ -284,31 +284,33 @@ func (h *EtcdHelper) SetObj(key string, obj, out runtime.Object, ttl uint64) err
return
err
return
err
}
}
// Pass an EtcdUpdateFunc to EtcdHelper.
AtomicUpdate to make an atomic etcd update
.
// Pass an EtcdUpdateFunc to EtcdHelper.
GuaranteedUpdate to make an etcd update that is guaranteed to succeed
.
// See the comment for
Atomic
Update for more detail.
// See the comment for
Guaranteed
Update for more detail.
type
EtcdUpdateFunc
func
(
input
runtime
.
Object
)
(
output
runtime
.
Object
,
ttl
uint64
,
err
error
)
type
EtcdUpdateFunc
func
(
input
runtime
.
Object
)
(
output
runtime
.
Object
,
ttl
uint64
,
err
error
)
// AtomicUpdate generalizes the pattern that allows for making atomic updates to etcd objects.
// GuaranteedUpdate calls "tryUpdate()" to update key "key" that is of type "ptrToType". It keeps
// Note, tryUpdate may be called more than once.
// calling tryUpdate() and retrying the update until success if there is etcd index conflict. Note that object
// passed to tryUpdate() may change across invocations of tryUpdate() if other writers are simultaneously
// updating it, so tryUpdate() needs to take into account the current contents of the object when
// deciding how the updated object (that it returns) should look.
//
//
// Example:
// Example:
//
//
// h := &util.EtcdHelper{client, encoding, versioning}
// h := &util.EtcdHelper{client, encoding, versioning}
// err := h.AtomicUpdate("myKey", &MyType{}, true, func(input runtime.Object) (runtime.Object, uint64, error) {
// err := h.GuaranteedUpdate("myKey", &MyType{}, true, func(input runtime.Object) (runtime.Object, uint64, error) {
// // Before this function is called, currentObj has been reset to etcd's current
// // Before each invocation of the user-defined function, "input" is reset to etcd's current contents for "myKey".
// // contents for "myKey".
//
//
// cur := input.(*MyType) // Guaranteed to
work
.
// cur := input.(*MyType) // Guaranteed to
succeed
.
//
//
// // Make a *modification*.
// // Make a *modification*.
// cur.Counter++
// cur.Counter++
//
//
// // Return the modified object. Return an error to stop iterating. Return a non-zero uint64 to set
// // Return the modified object. Return an error to stop iterating. Return a non-zero uint64 to set
// // the TTL on the object.
//
// the TTL on the object.
// return cur, 0, nil
// return cur, 0, nil
// })
// })
//
//
func
(
h
*
EtcdHelper
)
Atomic
Update
(
key
string
,
ptrToType
runtime
.
Object
,
ignoreNotFound
bool
,
tryUpdate
EtcdUpdateFunc
)
error
{
func
(
h
*
EtcdHelper
)
Guaranteed
Update
(
key
string
,
ptrToType
runtime
.
Object
,
ignoreNotFound
bool
,
tryUpdate
EtcdUpdateFunc
)
error
{
v
,
err
:=
conversion
.
EnforcePtr
(
ptrToType
)
v
,
err
:=
conversion
.
EnforcePtr
(
ptrToType
)
if
err
!=
nil
{
if
err
!=
nil
{
// Panic is appropriate, because this is a programming error.
// Panic is appropriate, because this is a programming error.
...
...
pkg/tools/etcd_helper_test.go
View file @
6b28a69a
...
@@ -503,7 +503,7 @@ func TestSetObjNilOutParam(t *testing.T) {
...
@@ -503,7 +503,7 @@ func TestSetObjNilOutParam(t *testing.T) {
}
}
}
}
func
Test
Atomic
Update
(
t
*
testing
.
T
)
{
func
Test
Guaranteed
Update
(
t
*
testing
.
T
)
{
fakeClient
:=
NewFakeEtcdClient
(
t
)
fakeClient
:=
NewFakeEtcdClient
(
t
)
fakeClient
.
TestIndex
=
true
fakeClient
.
TestIndex
=
true
helper
:=
NewEtcdHelper
(
fakeClient
,
codec
)
helper
:=
NewEtcdHelper
(
fakeClient
,
codec
)
...
@@ -511,7 +511,7 @@ func TestAtomicUpdate(t *testing.T) {
...
@@ -511,7 +511,7 @@ func TestAtomicUpdate(t *testing.T) {
// Create a new node.
// Create a new node.
fakeClient
.
ExpectNotFoundGet
(
"/some/key"
)
fakeClient
.
ExpectNotFoundGet
(
"/some/key"
)
obj
:=
&
TestResource
{
ObjectMeta
:
api
.
ObjectMeta
{
Name
:
"foo"
},
Value
:
1
}
obj
:=
&
TestResource
{
ObjectMeta
:
api
.
ObjectMeta
{
Name
:
"foo"
},
Value
:
1
}
err
:=
helper
.
Atomic
Update
(
"/some/key"
,
&
TestResource
{},
true
,
func
(
in
runtime
.
Object
)
(
runtime
.
Object
,
uint64
,
error
)
{
err
:=
helper
.
Guaranteed
Update
(
"/some/key"
,
&
TestResource
{},
true
,
func
(
in
runtime
.
Object
)
(
runtime
.
Object
,
uint64
,
error
)
{
return
obj
,
0
,
nil
return
obj
,
0
,
nil
})
})
if
err
!=
nil
{
if
err
!=
nil
{
...
@@ -530,7 +530,7 @@ func TestAtomicUpdate(t *testing.T) {
...
@@ -530,7 +530,7 @@ func TestAtomicUpdate(t *testing.T) {
// Update an existing node.
// Update an existing node.
callbackCalled
:=
false
callbackCalled
:=
false
objUpdate
:=
&
TestResource
{
ObjectMeta
:
api
.
ObjectMeta
{
Name
:
"foo"
},
Value
:
2
}
objUpdate
:=
&
TestResource
{
ObjectMeta
:
api
.
ObjectMeta
{
Name
:
"foo"
},
Value
:
2
}
err
=
helper
.
Atomic
Update
(
"/some/key"
,
&
TestResource
{},
true
,
func
(
in
runtime
.
Object
)
(
runtime
.
Object
,
uint64
,
error
)
{
err
=
helper
.
Guaranteed
Update
(
"/some/key"
,
&
TestResource
{},
true
,
func
(
in
runtime
.
Object
)
(
runtime
.
Object
,
uint64
,
error
)
{
callbackCalled
=
true
callbackCalled
=
true
if
in
.
(
*
TestResource
)
.
Value
!=
1
{
if
in
.
(
*
TestResource
)
.
Value
!=
1
{
...
@@ -557,7 +557,7 @@ func TestAtomicUpdate(t *testing.T) {
...
@@ -557,7 +557,7 @@ func TestAtomicUpdate(t *testing.T) {
}
}
}
}
func
Test
Atomic
UpdateNoChange
(
t
*
testing
.
T
)
{
func
Test
Guaranteed
UpdateNoChange
(
t
*
testing
.
T
)
{
fakeClient
:=
NewFakeEtcdClient
(
t
)
fakeClient
:=
NewFakeEtcdClient
(
t
)
fakeClient
.
TestIndex
=
true
fakeClient
.
TestIndex
=
true
helper
:=
NewEtcdHelper
(
fakeClient
,
codec
)
helper
:=
NewEtcdHelper
(
fakeClient
,
codec
)
...
@@ -565,7 +565,7 @@ func TestAtomicUpdateNoChange(t *testing.T) {
...
@@ -565,7 +565,7 @@ func TestAtomicUpdateNoChange(t *testing.T) {
// Create a new node.
// Create a new node.
fakeClient
.
ExpectNotFoundGet
(
"/some/key"
)
fakeClient
.
ExpectNotFoundGet
(
"/some/key"
)
obj
:=
&
TestResource
{
ObjectMeta
:
api
.
ObjectMeta
{
Name
:
"foo"
},
Value
:
1
}
obj
:=
&
TestResource
{
ObjectMeta
:
api
.
ObjectMeta
{
Name
:
"foo"
},
Value
:
1
}
err
:=
helper
.
Atomic
Update
(
"/some/key"
,
&
TestResource
{},
true
,
func
(
in
runtime
.
Object
)
(
runtime
.
Object
,
uint64
,
error
)
{
err
:=
helper
.
Guaranteed
Update
(
"/some/key"
,
&
TestResource
{},
true
,
func
(
in
runtime
.
Object
)
(
runtime
.
Object
,
uint64
,
error
)
{
return
obj
,
0
,
nil
return
obj
,
0
,
nil
})
})
if
err
!=
nil
{
if
err
!=
nil
{
...
@@ -575,7 +575,7 @@ func TestAtomicUpdateNoChange(t *testing.T) {
...
@@ -575,7 +575,7 @@ func TestAtomicUpdateNoChange(t *testing.T) {
// Update an existing node with the same data
// Update an existing node with the same data
callbackCalled
:=
false
callbackCalled
:=
false
objUpdate
:=
&
TestResource
{
ObjectMeta
:
api
.
ObjectMeta
{
Name
:
"foo"
},
Value
:
1
}
objUpdate
:=
&
TestResource
{
ObjectMeta
:
api
.
ObjectMeta
{
Name
:
"foo"
},
Value
:
1
}
err
=
helper
.
Atomic
Update
(
"/some/key"
,
&
TestResource
{},
true
,
func
(
in
runtime
.
Object
)
(
runtime
.
Object
,
uint64
,
error
)
{
err
=
helper
.
Guaranteed
Update
(
"/some/key"
,
&
TestResource
{},
true
,
func
(
in
runtime
.
Object
)
(
runtime
.
Object
,
uint64
,
error
)
{
fakeClient
.
Err
=
errors
.
New
(
"should not be called"
)
fakeClient
.
Err
=
errors
.
New
(
"should not be called"
)
callbackCalled
=
true
callbackCalled
=
true
return
objUpdate
,
0
,
nil
return
objUpdate
,
0
,
nil
...
@@ -588,7 +588,7 @@ func TestAtomicUpdateNoChange(t *testing.T) {
...
@@ -588,7 +588,7 @@ func TestAtomicUpdateNoChange(t *testing.T) {
}
}
}
}
func
Test
Atomic
UpdateKeyNotFound
(
t
*
testing
.
T
)
{
func
Test
Guaranteed
UpdateKeyNotFound
(
t
*
testing
.
T
)
{
fakeClient
:=
NewFakeEtcdClient
(
t
)
fakeClient
:=
NewFakeEtcdClient
(
t
)
fakeClient
.
TestIndex
=
true
fakeClient
.
TestIndex
=
true
helper
:=
NewEtcdHelper
(
fakeClient
,
codec
)
helper
:=
NewEtcdHelper
(
fakeClient
,
codec
)
...
@@ -602,19 +602,19 @@ func TestAtomicUpdateKeyNotFound(t *testing.T) {
...
@@ -602,19 +602,19 @@ func TestAtomicUpdateKeyNotFound(t *testing.T) {
}
}
ignoreNotFound
:=
false
ignoreNotFound
:=
false
err
:=
helper
.
Atomic
Update
(
"/some/key"
,
&
TestResource
{},
ignoreNotFound
,
f
)
err
:=
helper
.
Guaranteed
Update
(
"/some/key"
,
&
TestResource
{},
ignoreNotFound
,
f
)
if
err
==
nil
{
if
err
==
nil
{
t
.
Errorf
(
"Expected error for key not found."
)
t
.
Errorf
(
"Expected error for key not found."
)
}
}
ignoreNotFound
=
true
ignoreNotFound
=
true
err
=
helper
.
Atomic
Update
(
"/some/key"
,
&
TestResource
{},
ignoreNotFound
,
f
)
err
=
helper
.
Guaranteed
Update
(
"/some/key"
,
&
TestResource
{},
ignoreNotFound
,
f
)
if
err
!=
nil
{
if
err
!=
nil
{
t
.
Errorf
(
"Unexpected error %v."
,
err
)
t
.
Errorf
(
"Unexpected error %v."
,
err
)
}
}
}
}
func
Test
Atomic
Update_CreateCollision
(
t
*
testing
.
T
)
{
func
Test
Guaranteed
Update_CreateCollision
(
t
*
testing
.
T
)
{
fakeClient
:=
NewFakeEtcdClient
(
t
)
fakeClient
:=
NewFakeEtcdClient
(
t
)
fakeClient
.
TestIndex
=
true
fakeClient
.
TestIndex
=
true
helper
:=
NewEtcdHelper
(
fakeClient
,
codec
)
helper
:=
NewEtcdHelper
(
fakeClient
,
codec
)
...
@@ -633,11 +633,11 @@ func TestAtomicUpdate_CreateCollision(t *testing.T) {
...
@@ -633,11 +633,11 @@ func TestAtomicUpdate_CreateCollision(t *testing.T) {
defer
wgDone
.
Done
()
defer
wgDone
.
Done
()
firstCall
:=
true
firstCall
:=
true
err
:=
helper
.
Atomic
Update
(
"/some/key"
,
&
TestResource
{},
true
,
func
(
in
runtime
.
Object
)
(
runtime
.
Object
,
uint64
,
error
)
{
err
:=
helper
.
Guaranteed
Update
(
"/some/key"
,
&
TestResource
{},
true
,
func
(
in
runtime
.
Object
)
(
runtime
.
Object
,
uint64
,
error
)
{
defer
func
()
{
firstCall
=
false
}()
defer
func
()
{
firstCall
=
false
}()
if
firstCall
{
if
firstCall
{
// Force collision by joining all concurrent
Atomic
Update operations here.
// Force collision by joining all concurrent
Guaranteed
Update operations here.
wgForceCollision
.
Done
()
wgForceCollision
.
Done
()
wgForceCollision
.
Wait
()
wgForceCollision
.
Wait
()
}
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment