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
56598898
Commit
56598898
authored
Jun 28, 2016
by
deads2k
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
dedup workqueue requeuing
parent
b4ee63f6
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
111 additions
and
20 deletions
+111
-20
delaying_queue.go
pkg/util/workqueue/delaying_queue.go
+45
-8
delaying_queue_test.go
pkg/util/workqueue/delaying_queue_test.go
+66
-12
No files found.
pkg/util/workqueue/delaying_queue.go
View file @
56598898
...
@@ -39,11 +39,12 @@ func NewDelayingQueue() DelayingInterface {
...
@@ -39,11 +39,12 @@ func NewDelayingQueue() DelayingInterface {
func
newDelayingQueue
(
clock
util
.
Clock
)
DelayingInterface
{
func
newDelayingQueue
(
clock
util
.
Clock
)
DelayingInterface
{
ret
:=
&
delayingType
{
ret
:=
&
delayingType
{
Interface
:
New
(),
Interface
:
New
(),
clock
:
clock
,
clock
:
clock
,
heartbeat
:
clock
.
Tick
(
maxWait
),
heartbeat
:
clock
.
Tick
(
maxWait
),
stopCh
:
make
(
chan
struct
{}),
stopCh
:
make
(
chan
struct
{}),
waitingForAddCh
:
make
(
chan
waitFor
,
1000
),
waitingTimeByEntry
:
map
[
t
]
time
.
Time
{},
waitingForAddCh
:
make
(
chan
waitFor
,
1000
),
}
}
go
ret
.
waitingLoop
()
go
ret
.
waitingLoop
()
...
@@ -66,6 +67,8 @@ type delayingType struct {
...
@@ -66,6 +67,8 @@ type delayingType struct {
// waitingForAdd is an ordered slice of items to be added to the contained work queue
// waitingForAdd is an ordered slice of items to be added to the contained work queue
waitingForAdd
[]
waitFor
waitingForAdd
[]
waitFor
// waitingTimeByEntry holds wait time by entry, so we can lookup pre-existing indexes
waitingTimeByEntry
map
[
t
]
time
.
Time
// waitingForAddCh is a buffered channel that feeds waitingForAdd
// waitingForAddCh is a buffered channel that feeds waitingForAdd
waitingForAddCh
chan
waitFor
waitingForAddCh
chan
waitFor
}
}
...
@@ -118,6 +121,7 @@ func (q *delayingType) waitingLoop() {
...
@@ -118,6 +121,7 @@ func (q *delayingType) waitingLoop() {
if
q
.
Interface
.
ShuttingDown
()
{
if
q
.
Interface
.
ShuttingDown
()
{
// discard waiting entries
// discard waiting entries
q
.
waitingForAdd
=
nil
q
.
waitingForAdd
=
nil
q
.
waitingTimeByEntry
=
nil
return
return
}
}
...
@@ -130,6 +134,7 @@ func (q *delayingType) waitingLoop() {
...
@@ -130,6 +134,7 @@ func (q *delayingType) waitingLoop() {
break
break
}
}
q
.
Add
(
entry
.
data
)
q
.
Add
(
entry
.
data
)
delete
(
q
.
waitingTimeByEntry
,
entry
.
data
)
readyEntries
++
readyEntries
++
}
}
q
.
waitingForAdd
=
q
.
waitingForAdd
[
readyEntries
:
]
q
.
waitingForAdd
=
q
.
waitingForAdd
[
readyEntries
:
]
...
@@ -152,7 +157,7 @@ func (q *delayingType) waitingLoop() {
...
@@ -152,7 +157,7 @@ func (q *delayingType) waitingLoop() {
case
waitEntry
:=
<-
q
.
waitingForAddCh
:
case
waitEntry
:=
<-
q
.
waitingForAddCh
:
if
waitEntry
.
readyAt
.
After
(
q
.
clock
.
Now
())
{
if
waitEntry
.
readyAt
.
After
(
q
.
clock
.
Now
())
{
q
.
waitingForAdd
=
insert
(
q
.
waitingForAdd
,
waitEntry
)
q
.
waitingForAdd
=
insert
(
q
.
waitingForAdd
,
q
.
waitingTimeByEntry
,
waitEntry
)
}
else
{
}
else
{
q
.
Add
(
waitEntry
.
data
)
q
.
Add
(
waitEntry
.
data
)
}
}
...
@@ -162,7 +167,7 @@ func (q *delayingType) waitingLoop() {
...
@@ -162,7 +167,7 @@ func (q *delayingType) waitingLoop() {
select
{
select
{
case
waitEntry
:=
<-
q
.
waitingForAddCh
:
case
waitEntry
:=
<-
q
.
waitingForAddCh
:
if
waitEntry
.
readyAt
.
After
(
q
.
clock
.
Now
())
{
if
waitEntry
.
readyAt
.
After
(
q
.
clock
.
Now
())
{
q
.
waitingForAdd
=
insert
(
q
.
waitingForAdd
,
waitEntry
)
q
.
waitingForAdd
=
insert
(
q
.
waitingForAdd
,
q
.
waitingTimeByEntry
,
waitEntry
)
}
else
{
}
else
{
q
.
Add
(
waitEntry
.
data
)
q
.
Add
(
waitEntry
.
data
)
}
}
...
@@ -177,7 +182,20 @@ func (q *delayingType) waitingLoop() {
...
@@ -177,7 +182,20 @@ func (q *delayingType) waitingLoop() {
// inserts the given entry into the sorted entries list
// inserts the given entry into the sorted entries list
// same semantics as append()... the given slice may be modified,
// same semantics as append()... the given slice may be modified,
// and the returned value should be used
// and the returned value should be used
func
insert
(
entries
[]
waitFor
,
entry
waitFor
)
[]
waitFor
{
func
insert
(
entries
[]
waitFor
,
knownEntries
map
[
t
]
time
.
Time
,
entry
waitFor
)
[]
waitFor
{
// if the entry is already in our retry list and the existing time is before the new one, just skip it
existingTime
,
exists
:=
knownEntries
[
entry
.
data
]
if
exists
&&
existingTime
.
Before
(
entry
.
readyAt
)
{
return
entries
}
// if the entry exists and is scheduled for later, go ahead and remove the entry
if
exists
{
if
existingIndex
:=
findEntryIndex
(
entries
,
existingTime
,
entry
.
data
);
existingIndex
>=
0
&&
existingIndex
<
len
(
entries
)
{
entries
=
append
(
entries
[
:
existingIndex
],
entries
[
existingIndex
+
1
:
]
...
)
}
}
insertionIndex
:=
sort
.
Search
(
len
(
entries
),
func
(
i
int
)
bool
{
insertionIndex
:=
sort
.
Search
(
len
(
entries
),
func
(
i
int
)
bool
{
return
entry
.
readyAt
.
Before
(
entries
[
i
]
.
readyAt
)
return
entry
.
readyAt
.
Before
(
entries
[
i
]
.
readyAt
)
})
})
...
@@ -189,5 +207,24 @@ func insert(entries []waitFor, entry waitFor) []waitFor {
...
@@ -189,5 +207,24 @@ func insert(entries []waitFor, entry waitFor) []waitFor {
// insert the record
// insert the record
entries
[
insertionIndex
]
=
entry
entries
[
insertionIndex
]
=
entry
knownEntries
[
entry
.
data
]
=
entry
.
readyAt
return
entries
return
entries
}
}
// findEntryIndex returns the index for an existing entry
func
findEntryIndex
(
entries
[]
waitFor
,
existingTime
time
.
Time
,
data
t
)
int
{
index
:=
sort
.
Search
(
len
(
entries
),
func
(
i
int
)
bool
{
return
entries
[
i
]
.
readyAt
.
After
(
existingTime
)
||
existingTime
==
entries
[
i
]
.
readyAt
})
// we know this is the earliest possible index, but there could be multiple with the same time
// iterate from here to find the dupe
for
;
index
<
len
(
entries
);
index
++
{
if
entries
[
index
]
.
data
==
data
{
break
}
}
return
index
}
pkg/util/workqueue/delaying_queue_test.go
View file @
56598898
...
@@ -43,7 +43,7 @@ func TestSimpleQueue(t *testing.T) {
...
@@ -43,7 +43,7 @@ func TestSimpleQueue(t *testing.T) {
fakeClock
.
Step
(
60
*
time
.
Millisecond
)
fakeClock
.
Step
(
60
*
time
.
Millisecond
)
if
err
:=
waitForAdded
(
t
,
q
,
1
);
err
!=
nil
{
if
err
:=
waitForAdded
(
q
,
1
);
err
!=
nil
{
t
.
Errorf
(
"should have added"
)
t
.
Errorf
(
"should have added"
)
}
}
item
,
_
:=
q
.
Get
()
item
,
_
:=
q
.
Get
()
...
@@ -68,6 +68,65 @@ func TestSimpleQueue(t *testing.T) {
...
@@ -68,6 +68,65 @@ func TestSimpleQueue(t *testing.T) {
}
}
}
}
func
TestDeduping
(
t
*
testing
.
T
)
{
fakeClock
:=
util
.
NewFakeClock
(
time
.
Now
())
q
:=
newDelayingQueue
(
fakeClock
)
first
:=
"foo"
q
.
AddAfter
(
first
,
50
*
time
.
Millisecond
)
if
err
:=
waitForWaitingQueueToFill
(
q
);
err
!=
nil
{
t
.
Fatalf
(
"unexpected err: %v"
,
err
)
}
q
.
AddAfter
(
first
,
70
*
time
.
Millisecond
)
if
err
:=
waitForWaitingQueueToFill
(
q
);
err
!=
nil
{
t
.
Fatalf
(
"unexpected err: %v"
,
err
)
}
if
q
.
Len
()
!=
0
{
t
.
Errorf
(
"should not have added"
)
}
// step past the first block, we should receive now
fakeClock
.
Step
(
60
*
time
.
Millisecond
)
if
err
:=
waitForAdded
(
q
,
1
);
err
!=
nil
{
t
.
Errorf
(
"should have added"
)
}
item
,
_
:=
q
.
Get
()
q
.
Done
(
item
)
// step past the second add
fakeClock
.
Step
(
20
*
time
.
Millisecond
)
if
q
.
Len
()
!=
0
{
t
.
Errorf
(
"should not have added"
)
}
// test again, but this time the earlier should override
q
.
AddAfter
(
first
,
50
*
time
.
Millisecond
)
q
.
AddAfter
(
first
,
30
*
time
.
Millisecond
)
if
err
:=
waitForWaitingQueueToFill
(
q
);
err
!=
nil
{
t
.
Fatalf
(
"unexpected err: %v"
,
err
)
}
if
q
.
Len
()
!=
0
{
t
.
Errorf
(
"should not have added"
)
}
fakeClock
.
Step
(
40
*
time
.
Millisecond
)
if
err
:=
waitForAdded
(
q
,
1
);
err
!=
nil
{
t
.
Errorf
(
"should have added"
)
}
item
,
_
=
q
.
Get
()
q
.
Done
(
item
)
// step past the second add
fakeClock
.
Step
(
20
*
time
.
Millisecond
)
if
q
.
Len
()
!=
0
{
t
.
Errorf
(
"should not have added"
)
}
if
q
.
Len
()
!=
0
{
t
.
Errorf
(
"should not have added"
)
}
}
func
TestAddTwoFireEarly
(
t
*
testing
.
T
)
{
func
TestAddTwoFireEarly
(
t
*
testing
.
T
)
{
fakeClock
:=
util
.
NewFakeClock
(
time
.
Now
())
fakeClock
:=
util
.
NewFakeClock
(
time
.
Now
())
q
:=
newDelayingQueue
(
fakeClock
)
q
:=
newDelayingQueue
(
fakeClock
)
...
@@ -88,7 +147,7 @@ func TestAddTwoFireEarly(t *testing.T) {
...
@@ -88,7 +147,7 @@ func TestAddTwoFireEarly(t *testing.T) {
fakeClock
.
Step
(
60
*
time
.
Millisecond
)
fakeClock
.
Step
(
60
*
time
.
Millisecond
)
if
err
:=
waitForAdded
(
t
,
q
,
1
);
err
!=
nil
{
if
err
:=
waitForAdded
(
q
,
1
);
err
!=
nil
{
t
.
Fatalf
(
"unexpected err: %v"
,
err
)
t
.
Fatalf
(
"unexpected err: %v"
,
err
)
}
}
item
,
_
:=
q
.
Get
()
item
,
_
:=
q
.
Get
()
...
@@ -99,7 +158,7 @@ func TestAddTwoFireEarly(t *testing.T) {
...
@@ -99,7 +158,7 @@ func TestAddTwoFireEarly(t *testing.T) {
q
.
AddAfter
(
third
,
2
*
time
.
Second
)
q
.
AddAfter
(
third
,
2
*
time
.
Second
)
fakeClock
.
Step
(
1
*
time
.
Second
)
fakeClock
.
Step
(
1
*
time
.
Second
)
if
err
:=
waitForAdded
(
t
,
q
,
1
);
err
!=
nil
{
if
err
:=
waitForAdded
(
q
,
1
);
err
!=
nil
{
t
.
Fatalf
(
"unexpected err: %v"
,
err
)
t
.
Fatalf
(
"unexpected err: %v"
,
err
)
}
}
item
,
_
=
q
.
Get
()
item
,
_
=
q
.
Get
()
...
@@ -108,7 +167,7 @@ func TestAddTwoFireEarly(t *testing.T) {
...
@@ -108,7 +167,7 @@ func TestAddTwoFireEarly(t *testing.T) {
}
}
fakeClock
.
Step
(
2
*
time
.
Second
)
fakeClock
.
Step
(
2
*
time
.
Second
)
if
err
:=
waitForAdded
(
t
,
q
,
1
);
err
!=
nil
{
if
err
:=
waitForAdded
(
q
,
1
);
err
!=
nil
{
t
.
Fatalf
(
"unexpected err: %v"
,
err
)
t
.
Fatalf
(
"unexpected err: %v"
,
err
)
}
}
item
,
_
=
q
.
Get
()
item
,
_
=
q
.
Get
()
...
@@ -139,7 +198,7 @@ func TestCopyShifting(t *testing.T) {
...
@@ -139,7 +198,7 @@ func TestCopyShifting(t *testing.T) {
fakeClock
.
Step
(
2
*
time
.
Second
)
fakeClock
.
Step
(
2
*
time
.
Second
)
if
err
:=
waitForAdded
(
t
,
q
,
3
);
err
!=
nil
{
if
err
:=
waitForAdded
(
q
,
3
);
err
!=
nil
{
t
.
Fatalf
(
"unexpected err: %v"
,
err
)
t
.
Fatalf
(
"unexpected err: %v"
,
err
)
}
}
actualFirst
,
_
:=
q
.
Get
()
actualFirst
,
_
:=
q
.
Get
()
...
@@ -156,19 +215,14 @@ func TestCopyShifting(t *testing.T) {
...
@@ -156,19 +215,14 @@ func TestCopyShifting(t *testing.T) {
}
}
}
}
func
waitForAdded
(
t
*
testing
.
T
,
q
DelayingInterface
,
depth
int
)
error
{
func
waitForAdded
(
q
DelayingInterface
,
depth
int
)
error
{
err
:=
wait
.
Poll
(
1
*
time
.
Millisecond
,
2
0
*
time
.
Second
,
func
()
(
done
bool
,
err
error
)
{
return
wait
.
Poll
(
1
*
time
.
Millisecond
,
1
0
*
time
.
Second
,
func
()
(
done
bool
,
err
error
)
{
if
q
.
Len
()
==
depth
{
if
q
.
Len
()
==
depth
{
return
true
,
nil
return
true
,
nil
}
}
return
false
,
nil
return
false
,
nil
})
})
if
err
!=
nil
{
t
.
Logf
(
"failed: len=%v, everything=%#v"
,
q
.
Len
(),
q
)
}
return
err
}
}
func
waitForWaitingQueueToFill
(
q
DelayingInterface
)
error
{
func
waitForWaitingQueueToFill
(
q
DelayingInterface
)
error
{
...
...
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