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
2735e6a4
Commit
2735e6a4
authored
Feb 13, 2015
by
saadali
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Switch events history to use LRU cache instead of map
parent
842867e2
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
239 additions
and
24 deletions
+239
-24
Godeps.json
Godeps/Godeps.json
+4
-0
lru.go
...ps/_workspace/src/github.com/golang/groupcache/lru/lru.go
+121
-0
lru_test.go
...orkspace/src/github.com/golang/groupcache/lru/lru_test.go
+73
-0
event.go
pkg/client/record/event.go
+2
-2
events_cache.go
pkg/client/record/events_cache.go
+31
-14
events_cache_test.go
pkg/client/record/events_cache_test.go
+8
-8
No files found.
Godeps/Godeps.json
View file @
2735e6a4
...
@@ -110,6 +110,10 @@
...
@@ -110,6 +110,10 @@
"Rev"
:
"44145f04b68cf362d9c4df2182967c2275eaefed"
"Rev"
:
"44145f04b68cf362d9c4df2182967c2275eaefed"
},
},
{
{
"ImportPath"
:
"github.com/golang/groupcache/lru"
,
"Rev"
:
"604ed5785183e59ae2789449d89e73f3a2a77987"
},
{
"ImportPath"
:
"github.com/golang/protobuf/proto"
,
"ImportPath"
:
"github.com/golang/protobuf/proto"
,
"Rev"
:
"7f07925444bb51fa4cf9dfe6f7661876f8852275"
"Rev"
:
"7f07925444bb51fa4cf9dfe6f7661876f8852275"
},
},
...
...
Godeps/_workspace/src/github.com/golang/groupcache/lru/lru.go
0 → 100644
View file @
2735e6a4
/*
Copyright 2013 Google Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Package lru implements an LRU cache.
package
lru
import
"container/list"
// Cache is an LRU cache. It is not safe for concurrent access.
type
Cache
struct
{
// MaxEntries is the maximum number of cache entries before
// an item is evicted. Zero means no limit.
MaxEntries
int
// OnEvicted optionally specificies a callback function to be
// executed when an entry is purged from the cache.
OnEvicted
func
(
key
Key
,
value
interface
{})
ll
*
list
.
List
cache
map
[
interface
{}]
*
list
.
Element
}
// A Key may be any value that is comparable. See http://golang.org/ref/spec#Comparison_operators
type
Key
interface
{}
type
entry
struct
{
key
Key
value
interface
{}
}
// New creates a new Cache.
// If maxEntries is zero, the cache has no limit and it's assumed
// that eviction is done by the caller.
func
New
(
maxEntries
int
)
*
Cache
{
return
&
Cache
{
MaxEntries
:
maxEntries
,
ll
:
list
.
New
(),
cache
:
make
(
map
[
interface
{}]
*
list
.
Element
),
}
}
// Add adds a value to the cache.
func
(
c
*
Cache
)
Add
(
key
Key
,
value
interface
{})
{
if
c
.
cache
==
nil
{
c
.
cache
=
make
(
map
[
interface
{}]
*
list
.
Element
)
c
.
ll
=
list
.
New
()
}
if
ee
,
ok
:=
c
.
cache
[
key
];
ok
{
c
.
ll
.
MoveToFront
(
ee
)
ee
.
Value
.
(
*
entry
)
.
value
=
value
return
}
ele
:=
c
.
ll
.
PushFront
(
&
entry
{
key
,
value
})
c
.
cache
[
key
]
=
ele
if
c
.
MaxEntries
!=
0
&&
c
.
ll
.
Len
()
>
c
.
MaxEntries
{
c
.
RemoveOldest
()
}
}
// Get looks up a key's value from the cache.
func
(
c
*
Cache
)
Get
(
key
Key
)
(
value
interface
{},
ok
bool
)
{
if
c
.
cache
==
nil
{
return
}
if
ele
,
hit
:=
c
.
cache
[
key
];
hit
{
c
.
ll
.
MoveToFront
(
ele
)
return
ele
.
Value
.
(
*
entry
)
.
value
,
true
}
return
}
// Remove removes the provided key from the cache.
func
(
c
*
Cache
)
Remove
(
key
Key
)
{
if
c
.
cache
==
nil
{
return
}
if
ele
,
hit
:=
c
.
cache
[
key
];
hit
{
c
.
removeElement
(
ele
)
}
}
// RemoveOldest removes the oldest item from the cache.
func
(
c
*
Cache
)
RemoveOldest
()
{
if
c
.
cache
==
nil
{
return
}
ele
:=
c
.
ll
.
Back
()
if
ele
!=
nil
{
c
.
removeElement
(
ele
)
}
}
func
(
c
*
Cache
)
removeElement
(
e
*
list
.
Element
)
{
c
.
ll
.
Remove
(
e
)
kv
:=
e
.
Value
.
(
*
entry
)
delete
(
c
.
cache
,
kv
.
key
)
if
c
.
OnEvicted
!=
nil
{
c
.
OnEvicted
(
kv
.
key
,
kv
.
value
)
}
}
// Len returns the number of items in the cache.
func
(
c
*
Cache
)
Len
()
int
{
if
c
.
cache
==
nil
{
return
0
}
return
c
.
ll
.
Len
()
}
Godeps/_workspace/src/github.com/golang/groupcache/lru/lru_test.go
0 → 100644
View file @
2735e6a4
/*
Copyright 2013 Google Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package
lru
import
(
"testing"
)
type
simpleStruct
struct
{
int
string
}
type
complexStruct
struct
{
int
simpleStruct
}
var
getTests
=
[]
struct
{
name
string
keyToAdd
interface
{}
keyToGet
interface
{}
expectedOk
bool
}{
{
"string_hit"
,
"myKey"
,
"myKey"
,
true
},
{
"string_miss"
,
"myKey"
,
"nonsense"
,
false
},
{
"simple_struct_hit"
,
simpleStruct
{
1
,
"two"
},
simpleStruct
{
1
,
"two"
},
true
},
{
"simeple_struct_miss"
,
simpleStruct
{
1
,
"two"
},
simpleStruct
{
0
,
"noway"
},
false
},
{
"complex_struct_hit"
,
complexStruct
{
1
,
simpleStruct
{
2
,
"three"
}},
complexStruct
{
1
,
simpleStruct
{
2
,
"three"
}},
true
},
}
func
TestGet
(
t
*
testing
.
T
)
{
for
_
,
tt
:=
range
getTests
{
lru
:=
New
(
0
)
lru
.
Add
(
tt
.
keyToAdd
,
1234
)
val
,
ok
:=
lru
.
Get
(
tt
.
keyToGet
)
if
ok
!=
tt
.
expectedOk
{
t
.
Fatalf
(
"%s: cache hit = %v; want %v"
,
tt
.
name
,
ok
,
!
ok
)
}
else
if
ok
&&
val
!=
1234
{
t
.
Fatalf
(
"%s expected get to return 1234 but got %v"
,
tt
.
name
,
val
)
}
}
}
func
TestRemove
(
t
*
testing
.
T
)
{
lru
:=
New
(
0
)
lru
.
Add
(
"myKey"
,
1234
)
if
val
,
ok
:=
lru
.
Get
(
"myKey"
);
!
ok
{
t
.
Fatal
(
"TestRemove returned no match"
)
}
else
if
val
!=
1234
{
t
.
Fatalf
(
"TestRemove failed. Expected %d, got %v"
,
1234
,
val
)
}
lru
.
Remove
(
"myKey"
)
if
_
,
ok
:=
lru
.
Get
(
"myKey"
);
ok
{
t
.
Fatal
(
"TestRemove returned a removed entry"
)
}
}
pkg/client/record/event.go
View file @
2735e6a4
...
@@ -59,7 +59,7 @@ func StartRecording(recorder EventRecorder, source api.EventSource) watch.Interf
...
@@ -59,7 +59,7 @@ func StartRecording(recorder EventRecorder, source api.EventSource) watch.Interf
event
=
&
eventCopy
event
=
&
eventCopy
event
.
Source
=
source
event
.
Source
=
source
previousEvent
:=
G
etEvent
(
event
)
previousEvent
:=
g
etEvent
(
event
)
updateExistingEvent
:=
previousEvent
.
Count
>
0
updateExistingEvent
:=
previousEvent
.
Count
>
0
if
updateExistingEvent
{
if
updateExistingEvent
{
event
.
Count
=
previousEvent
.
Count
+
1
event
.
Count
=
previousEvent
.
Count
+
1
...
@@ -102,7 +102,7 @@ func recordEvent(recorder EventRecorder, event *api.Event, updateExistingEvent b
...
@@ -102,7 +102,7 @@ func recordEvent(recorder EventRecorder, event *api.Event, updateExistingEvent b
newEvent
,
err
=
recorder
.
Create
(
event
)
newEvent
,
err
=
recorder
.
Create
(
event
)
}
}
if
err
==
nil
{
if
err
==
nil
{
A
ddOrUpdateEvent
(
newEvent
)
a
ddOrUpdateEvent
(
newEvent
)
return
true
return
true
}
}
...
...
pkg/client/record/events_cache.go
View file @
2735e6a4
...
@@ -19,10 +19,11 @@ package record
...
@@ -19,10 +19,11 @@ package record
import
(
import
(
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
"github.com/golang/groupcache/lru"
"sync"
"sync"
)
)
type
H
istory
struct
{
type
h
istory
struct
{
// The number of times the event has occured since first occurance.
// The number of times the event has occured since first occurance.
Count
int
Count
int
...
@@ -36,36 +37,52 @@ type History struct {
...
@@ -36,36 +37,52 @@ type History struct {
ResourceVersion
string
ResourceVersion
string
}
}
type
historyMap
struct
{
const
(
maxLruCacheEntries
=
4096
)
type
historyCache
struct
{
sync
.
RWMutex
sync
.
RWMutex
table
map
[
string
]
History
cache
*
lru
.
Cache
}
}
var
previousEvents
=
history
Map
{
table
:
make
(
map
[
string
]
History
)}
var
previousEvents
=
history
Cache
{
cache
:
lru
.
New
(
maxLruCacheEntries
)}
//
A
ddOrUpdateEvent creates a new entry for the given event in the previous events hash table if the event
//
a
ddOrUpdateEvent creates a new entry for the given event in the previous events hash table if the event
// doesn't already exist, otherwise it updates the existing entry.
// doesn't already exist, otherwise it updates the existing entry.
func
AddOrUpdateEvent
(
newEvent
*
api
.
Event
)
H
istory
{
func
addOrUpdateEvent
(
newEvent
*
api
.
Event
)
h
istory
{
key
:=
getEventKey
(
newEvent
)
key
:=
getEventKey
(
newEvent
)
previousEvents
.
Lock
()
previousEvents
.
Lock
()
defer
previousEvents
.
Unlock
()
defer
previousEvents
.
Unlock
()
previousEvents
.
table
[
key
]
=
previousEvents
.
cache
.
Add
(
History
{
key
,
history
{
Count
:
newEvent
.
Count
,
Count
:
newEvent
.
Count
,
FirstTimestamp
:
newEvent
.
FirstTimestamp
,
FirstTimestamp
:
newEvent
.
FirstTimestamp
,
Name
:
newEvent
.
Name
,
Name
:
newEvent
.
Name
,
ResourceVersion
:
newEvent
.
ResourceVersion
,
ResourceVersion
:
newEvent
.
ResourceVersion
,
}
}
)
return
previousEvents
.
table
[
key
]
return
getEventFromCache
(
key
)
}
}
//
GetEvent returns the entry corresponding to the given event, if one exists, otherwise a H
istory object
//
getEvent returns the entry corresponding to the given event, if one exists, otherwise a h
istory object
// with a count of
1
is returned.
// with a count of
0
is returned.
func
GetEvent
(
event
*
api
.
Event
)
H
istory
{
func
getEvent
(
event
*
api
.
Event
)
h
istory
{
key
:=
getEventKey
(
event
)
key
:=
getEventKey
(
event
)
previousEvents
.
RLock
()
previousEvents
.
RLock
()
defer
previousEvents
.
RUnlock
()
defer
previousEvents
.
RUnlock
()
return
previousEvents
.
table
[
key
]
return
getEventFromCache
(
key
)
}
func
getEventFromCache
(
key
string
)
history
{
value
,
ok
:=
previousEvents
.
cache
.
Get
(
key
)
if
ok
{
historyValue
,
ok
:=
value
.
(
history
)
if
ok
{
return
historyValue
}
}
return
history
{}
}
}
func
getEventKey
(
event
*
api
.
Event
)
string
{
func
getEventKey
(
event
*
api
.
Event
)
string
{
...
...
pkg/client/record/events_cache_test.go
View file @
2735e6a4
...
@@ -45,7 +45,7 @@ func TestAddOrUpdateEventNoExisting(t *testing.T) {
...
@@ -45,7 +45,7 @@ func TestAddOrUpdateEventNoExisting(t *testing.T) {
}
}
// Act
// Act
result
:=
A
ddOrUpdateEvent
(
&
event
)
result
:=
a
ddOrUpdateEvent
(
&
event
)
// Assert
// Assert
compareEventWithHistoryEntry
(
&
event
,
&
result
,
t
)
compareEventWithHistoryEntry
(
&
event
,
&
result
,
t
)
...
@@ -99,9 +99,9 @@ func TestAddOrUpdateEventExisting(t *testing.T) {
...
@@ -99,9 +99,9 @@ func TestAddOrUpdateEventExisting(t *testing.T) {
}
}
// Act
// Act
A
ddOrUpdateEvent
(
&
event1
)
a
ddOrUpdateEvent
(
&
event1
)
result1
:=
A
ddOrUpdateEvent
(
&
event2
)
result1
:=
a
ddOrUpdateEvent
(
&
event2
)
result2
:=
G
etEvent
(
&
event1
)
result2
:=
g
etEvent
(
&
event1
)
// Assert
// Assert
compareEventWithHistoryEntry
(
&
event2
,
&
result1
,
t
)
compareEventWithHistoryEntry
(
&
event2
,
&
result1
,
t
)
...
@@ -128,7 +128,7 @@ func TestGetEventNoExisting(t *testing.T) {
...
@@ -128,7 +128,7 @@ func TestGetEventNoExisting(t *testing.T) {
}
}
// Act
// Act
existingEvent
:=
G
etEvent
(
&
event
)
existingEvent
:=
g
etEvent
(
&
event
)
// Assert
// Assert
if
existingEvent
.
Count
!=
0
{
if
existingEvent
.
Count
!=
0
{
...
@@ -157,16 +157,16 @@ func TestGetEventExisting(t *testing.T) {
...
@@ -157,16 +157,16 @@ func TestGetEventExisting(t *testing.T) {
FirstTimestamp
:
eventTime
,
FirstTimestamp
:
eventTime
,
LastTimestamp
:
eventTime
,
LastTimestamp
:
eventTime
,
}
}
A
ddOrUpdateEvent
(
&
event
)
a
ddOrUpdateEvent
(
&
event
)
// Act
// Act
existingEvent
:=
G
etEvent
(
&
event
)
existingEvent
:=
g
etEvent
(
&
event
)
// Assert
// Assert
compareEventWithHistoryEntry
(
&
event
,
&
existingEvent
,
t
)
compareEventWithHistoryEntry
(
&
event
,
&
existingEvent
,
t
)
}
}
func
compareEventWithHistoryEntry
(
expected
*
api
.
Event
,
actual
*
H
istory
,
t
*
testing
.
T
)
{
func
compareEventWithHistoryEntry
(
expected
*
api
.
Event
,
actual
*
h
istory
,
t
*
testing
.
T
)
{
if
actual
.
Count
!=
expected
.
Count
{
if
actual
.
Count
!=
expected
.
Count
{
t
.
Fatalf
(
"There should be one existing instance of this event in the hash table."
)
t
.
Fatalf
(
"There should be one existing instance of this event in the hash table."
)
...
...
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