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
dad64459
Unverified
Commit
dad64459
authored
Apr 27, 2017
by
Andy Lindeman
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Uses container/heap
parent
21ca6c49
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
84 additions
and
73 deletions
+84
-73
delaying_queue.go
...ing/src/k8s.io/client-go/util/workqueue/delaying_queue.go
+83
-72
rate_limitting_queue_test.go
....io/client-go/util/workqueue/rate_limitting_queue_test.go
+1
-1
No files found.
staging/src/k8s.io/client-go/util/workqueue/delaying_queue.go
View file @
dad64459
...
...
@@ -17,7 +17,7 @@ limitations under the License.
package
workqueue
import
(
"
sort
"
"
container/heap
"
"time"
utilruntime
"k8s.io/apimachinery/pkg/util/runtime"
...
...
@@ -43,13 +43,12 @@ func NewNamedDelayingQueue(name string) DelayingInterface {
func
newDelayingQueue
(
clock
clock
.
Clock
,
name
string
)
DelayingInterface
{
ret
:=
&
delayingType
{
Interface
:
NewNamed
(
name
),
clock
:
clock
,
heartbeat
:
clock
.
Tick
(
maxWait
),
stopCh
:
make
(
chan
struct
{}),
waitingTimeByEntry
:
map
[
t
]
time
.
Time
{},
waitingForAddCh
:
make
(
chan
waitFor
,
1000
),
metrics
:
newRetryMetrics
(
name
),
Interface
:
NewNamed
(
name
),
clock
:
clock
,
heartbeat
:
clock
.
Tick
(
maxWait
),
stopCh
:
make
(
chan
struct
{}),
waitingForAddCh
:
make
(
chan
*
waitFor
,
1000
),
metrics
:
newRetryMetrics
(
name
),
}
go
ret
.
waitingLoop
()
...
...
@@ -73,12 +72,8 @@ type delayingType struct {
// clock.Tick will leak.
heartbeat
<-
chan
time
.
Time
// waitingForAdd is an ordered slice of items to be added to the contained work queue
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
chan
waitFor
waitingForAddCh
chan
*
waitFor
// metrics counts the number of retries
metrics
retryMetrics
...
...
@@ -88,6 +83,55 @@ type delayingType struct {
type
waitFor
struct
{
data
t
readyAt
time
.
Time
// index in the priority queue (heap)
index
int
}
// waitForPriorityQueue implements a priority queue for waitFor items.
//
// waitForPriorityQueue implements heap.Interface. The item occuring next in
// time (i.e., the item with the smallest readyAt) is at the root (index 0).
// Peek returns this minimum item at index 0. Pop returns the minimum item after
// it has been removed from the queue and placed at index Len()-1 by
// container/heap. Push adds an item at index Len(), and container/heap
// percolates it into the correct location.
type
waitForPriorityQueue
[]
*
waitFor
func
(
pq
waitForPriorityQueue
)
Len
()
int
{
return
len
(
pq
)
}
func
(
pq
waitForPriorityQueue
)
Less
(
i
,
j
int
)
bool
{
return
pq
[
i
]
.
readyAt
.
Before
(
pq
[
j
]
.
readyAt
)
}
func
(
pq
waitForPriorityQueue
)
Swap
(
i
,
j
int
)
{
pq
[
i
],
pq
[
j
]
=
pq
[
j
],
pq
[
i
]
pq
[
i
]
.
index
=
i
pq
[
j
]
.
index
=
j
}
// Push adds an item to the queue. Push should not be called directly; instead,
// use `heap.Push`.
func
(
pq
*
waitForPriorityQueue
)
Push
(
x
interface
{})
{
n
:=
len
(
*
pq
)
item
:=
x
.
(
*
waitFor
)
item
.
index
=
n
*
pq
=
append
(
*
pq
,
item
)
}
// Pop removes an item from the queue. Pop should not be called directly;
// instead, use `heap.Pop`.
func
(
pq
*
waitForPriorityQueue
)
Pop
()
interface
{}
{
n
:=
len
(
*
pq
)
item
:=
(
*
pq
)[
n
-
1
]
item
.
index
=
-
1
*
pq
=
(
*
pq
)[
0
:
(
n
-
1
)]
return
item
}
// Peek returns the item at the beginning of the queue, without removing the
// item or otherwise mutating the queue. It is safe to call directly.
func
(
pq
waitForPriorityQueue
)
Peek
()
interface
{}
{
return
pq
[
0
]
}
// ShutDown gives a way to shut off this queue
...
...
@@ -114,7 +158,7 @@ func (q *delayingType) AddAfter(item interface{}, duration time.Duration) {
select
{
case
<-
q
.
stopCh
:
// unblock if ShutDown() is called
case
q
.
waitingForAddCh
<-
waitFor
{
data
:
item
,
readyAt
:
q
.
clock
.
Now
()
.
Add
(
duration
)}
:
case
q
.
waitingForAddCh
<-
&
waitFor
{
data
:
item
,
readyAt
:
q
.
clock
.
Now
()
.
Add
(
duration
)}
:
}
}
...
...
@@ -130,32 +174,35 @@ func (q *delayingType) waitingLoop() {
// Make a placeholder channel to use when there are no items in our list
never
:=
make
(
<-
chan
time
.
Time
)
waitingForQueue
:=
&
waitForPriorityQueue
{}
heap
.
Init
(
waitingForQueue
)
waitingEntryByData
:=
map
[
t
]
*
waitFor
{}
for
{
if
q
.
Interface
.
ShuttingDown
()
{
// discard waiting entries
q
.
waitingForAdd
=
nil
q
.
waitingTimeByEntry
=
nil
return
}
now
:=
q
.
clock
.
Now
()
// Add ready entries
readyEntries
:=
0
for
_
,
entry
:=
range
q
.
waitingForAdd
{
for
waitingForQueue
.
Len
()
>
0
{
entry
:=
waitingForQueue
.
Peek
()
.
(
*
waitFor
)
if
entry
.
readyAt
.
After
(
now
)
{
break
}
entry
=
heap
.
Pop
(
waitingForQueue
)
.
(
*
waitFor
)
q
.
Add
(
entry
.
data
)
delete
(
q
.
waitingTimeByEntry
,
entry
.
data
)
readyEntries
++
delete
(
waitingEntryByData
,
entry
.
data
)
}
q
.
waitingForAdd
=
q
.
waitingForAdd
[
readyEntries
:
]
// Set up a wait for the first item's readyAt (if one exists)
nextReadyAt
:=
never
if
len
(
q
.
waitingForAdd
)
>
0
{
nextReadyAt
=
q
.
clock
.
After
(
q
.
waitingForAdd
[
0
]
.
readyAt
.
Sub
(
now
))
if
waitingForQueue
.
Len
()
>
0
{
entry
:=
waitingForQueue
.
Peek
()
.
(
*
waitFor
)
nextReadyAt
=
q
.
clock
.
After
(
entry
.
readyAt
.
Sub
(
now
))
}
select
{
...
...
@@ -170,7 +217,7 @@ func (q *delayingType) waitingLoop() {
case
waitEntry
:=
<-
q
.
waitingForAddCh
:
if
waitEntry
.
readyAt
.
After
(
q
.
clock
.
Now
())
{
q
.
waitingForAdd
=
insert
(
q
.
waitingForAdd
,
q
.
waitingTimeByEntry
,
waitEntry
)
insert
(
waitingForQueue
,
waitingEntryByData
,
waitEntry
)
}
else
{
q
.
Add
(
waitEntry
.
data
)
}
...
...
@@ -180,7 +227,7 @@ func (q *delayingType) waitingLoop() {
select
{
case
waitEntry
:=
<-
q
.
waitingForAddCh
:
if
waitEntry
.
readyAt
.
After
(
q
.
clock
.
Now
())
{
q
.
waitingForAdd
=
insert
(
q
.
waitingForAdd
,
q
.
waitingTimeByEntry
,
waitEntry
)
insert
(
waitingForQueue
,
waitingEntryByData
,
waitEntry
)
}
else
{
q
.
Add
(
waitEntry
.
data
)
}
...
...
@@ -192,55 +239,19 @@ func (q *delayingType) waitingLoop() {
}
}
// inserts the given entry into the sorted entries list
// same semantics as append()... the given slice may be modified,
// and the returned value should be used
//
// TODO: This should probably be converted to use container/heap to improve
// running time for a large number of items.
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
// insert adds the entry to the priority queue, or updates the readyAt if it already exists in the queue
func
insert
(
q
*
waitForPriorityQueue
,
knownEntries
map
[
t
]
*
waitFor
,
entry
*
waitFor
)
{
// if the entry already exists, update the time only if it would cause the item to be queued sooner
existing
,
exists
:=
knownEntries
[
entry
.
data
]
if
exists
{
if
existingIndex
:=
findEntryIndex
(
entries
,
existingTime
,
entry
.
data
);
existingIndex
>=
0
&&
existingIndex
<
len
(
entries
)
{
entries
=
append
(
entries
[
:
existingIndex
],
entries
[
existingIndex
+
1
:
]
...
)
if
existing
.
readyAt
.
After
(
entry
.
readyAt
)
{
existing
.
readyAt
=
entry
.
readyAt
heap
.
Fix
(
q
,
existing
.
index
)
}
}
insertionIndex
:=
sort
.
Search
(
len
(
entries
),
func
(
i
int
)
bool
{
return
entry
.
readyAt
.
Before
(
entries
[
i
]
.
readyAt
)
})
// grow by 1
entries
=
append
(
entries
,
waitFor
{})
// shift items from the insertion point to the end
copy
(
entries
[
insertionIndex
+
1
:
],
entries
[
insertionIndex
:
])
// insert the record
entries
[
insertionIndex
]
=
entry
knownEntries
[
entry
.
data
]
=
entry
.
readyAt
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
}
return
index
heap
.
Push
(
q
,
entry
)
knownEntries
[
entry
.
data
]
=
entry
}
staging/src/k8s.io/client-go/util/workqueue/rate_limitting_queue_test.go
View file @
dad64459
...
...
@@ -32,7 +32,7 @@ func TestRateLimitingQueue(t *testing.T) {
clock
:
fakeClock
,
heartbeat
:
fakeClock
.
Tick
(
maxWait
),
stopCh
:
make
(
chan
struct
{}),
waitingForAddCh
:
make
(
chan
waitFor
,
1000
),
waitingForAddCh
:
make
(
chan
*
waitFor
,
1000
),
metrics
:
newRetryMetrics
(
""
),
}
queue
.
DelayingInterface
=
delayingQueue
...
...
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