forked from barak/tarpoon
Add glide.yaml and vendor deps
This commit is contained in:
parent
db918f12ad
commit
5b3d5e81bd
18880 changed files with 5166045 additions and 1 deletions
72
vendor/k8s.io/kubernetes/pkg/controller/garbagecollector/BUILD
generated
vendored
Normal file
72
vendor/k8s.io/kubernetes/pkg/controller/garbagecollector/BUILD
generated
vendored
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_binary",
|
||||
"go_library",
|
||||
"go_test",
|
||||
"cgo_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"garbagecollector.go",
|
||||
"metrics.go",
|
||||
"rate_limiter_helper.go",
|
||||
"uid_cache.go",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//pkg/api:go_default_library",
|
||||
"//pkg/api/errors:go_default_library",
|
||||
"//pkg/api/meta:go_default_library",
|
||||
"//pkg/api/meta/metatypes:go_default_library",
|
||||
"//pkg/api/v1:go_default_library",
|
||||
"//pkg/apis/meta/v1:go_default_library",
|
||||
"//pkg/client/cache:go_default_library",
|
||||
"//pkg/client/typed/dynamic:go_default_library",
|
||||
"//pkg/controller/garbagecollector/metaonly:go_default_library",
|
||||
"//pkg/runtime:go_default_library",
|
||||
"//pkg/runtime/schema:go_default_library",
|
||||
"//pkg/types:go_default_library",
|
||||
"//pkg/util/clock:go_default_library",
|
||||
"//pkg/util/errors:go_default_library",
|
||||
"//pkg/util/metrics:go_default_library",
|
||||
"//pkg/util/runtime:go_default_library",
|
||||
"//pkg/util/sets:go_default_library",
|
||||
"//pkg/util/wait:go_default_library",
|
||||
"//pkg/util/workqueue:go_default_library",
|
||||
"//pkg/watch:go_default_library",
|
||||
"//vendor:github.com/golang/glog",
|
||||
"//vendor:github.com/golang/groupcache/lru",
|
||||
"//vendor:github.com/prometheus/client_golang/prometheus",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["garbagecollector_test.go"],
|
||||
library = "go_default_library",
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//pkg/api/install:go_default_library",
|
||||
"//pkg/api/meta/metatypes:go_default_library",
|
||||
"//pkg/api/v1:go_default_library",
|
||||
"//pkg/apimachinery/registered:go_default_library",
|
||||
"//pkg/apis/meta/v1:go_default_library",
|
||||
"//pkg/client/restclient:go_default_library",
|
||||
"//pkg/client/typed/dynamic:go_default_library",
|
||||
"//pkg/controller/garbagecollector/metaonly:go_default_library",
|
||||
"//pkg/runtime/schema:go_default_library",
|
||||
"//pkg/runtime/serializer:go_default_library",
|
||||
"//pkg/types:go_default_library",
|
||||
"//pkg/util/clock:go_default_library",
|
||||
"//pkg/util/json:go_default_library",
|
||||
"//pkg/util/sets:go_default_library",
|
||||
"//pkg/util/workqueue:go_default_library",
|
||||
"//vendor:github.com/stretchr/testify/assert",
|
||||
],
|
||||
)
|
||||
801
vendor/k8s.io/kubernetes/pkg/controller/garbagecollector/garbagecollector.go
generated
vendored
Normal file
801
vendor/k8s.io/kubernetes/pkg/controller/garbagecollector/garbagecollector.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
477
vendor/k8s.io/kubernetes/pkg/controller/garbagecollector/garbagecollector_test.go
generated
vendored
Normal file
477
vendor/k8s.io/kubernetes/pkg/controller/garbagecollector/garbagecollector_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,477 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
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 garbagecollector
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
_ "k8s.io/kubernetes/pkg/api/install"
|
||||
|
||||
"k8s.io/kubernetes/pkg/api/meta/metatypes"
|
||||
"k8s.io/kubernetes/pkg/api/v1"
|
||||
"k8s.io/kubernetes/pkg/apimachinery/registered"
|
||||
metav1 "k8s.io/kubernetes/pkg/apis/meta/v1"
|
||||
"k8s.io/kubernetes/pkg/client/restclient"
|
||||
"k8s.io/kubernetes/pkg/client/typed/dynamic"
|
||||
"k8s.io/kubernetes/pkg/controller/garbagecollector/metaonly"
|
||||
"k8s.io/kubernetes/pkg/runtime/schema"
|
||||
"k8s.io/kubernetes/pkg/runtime/serializer"
|
||||
"k8s.io/kubernetes/pkg/types"
|
||||
"k8s.io/kubernetes/pkg/util/clock"
|
||||
"k8s.io/kubernetes/pkg/util/json"
|
||||
"k8s.io/kubernetes/pkg/util/sets"
|
||||
"k8s.io/kubernetes/pkg/util/workqueue"
|
||||
)
|
||||
|
||||
func TestNewGarbageCollector(t *testing.T) {
|
||||
config := &restclient.Config{}
|
||||
config.ContentConfig.NegotiatedSerializer = serializer.DirectCodecFactory{CodecFactory: metaonly.NewMetadataCodecFactory()}
|
||||
metaOnlyClientPool := dynamic.NewClientPool(config, registered.RESTMapper(), dynamic.LegacyAPIPathResolverFunc)
|
||||
config.ContentConfig.NegotiatedSerializer = nil
|
||||
clientPool := dynamic.NewClientPool(config, registered.RESTMapper(), dynamic.LegacyAPIPathResolverFunc)
|
||||
podResource := []schema.GroupVersionResource{{Version: "v1", Resource: "pods"}}
|
||||
gc, err := NewGarbageCollector(metaOnlyClientPool, clientPool, registered.RESTMapper(), podResource)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
assert.Equal(t, 1, len(gc.monitors))
|
||||
}
|
||||
|
||||
// fakeAction records information about requests to aid in testing.
|
||||
type fakeAction struct {
|
||||
method string
|
||||
path string
|
||||
query string
|
||||
}
|
||||
|
||||
// String returns method=path to aid in testing
|
||||
func (f *fakeAction) String() string {
|
||||
return strings.Join([]string{f.method, f.path}, "=")
|
||||
}
|
||||
|
||||
type FakeResponse struct {
|
||||
statusCode int
|
||||
content []byte
|
||||
}
|
||||
|
||||
// fakeActionHandler holds a list of fakeActions received
|
||||
type fakeActionHandler struct {
|
||||
// statusCode and content returned by this handler for different method + path.
|
||||
response map[string]FakeResponse
|
||||
|
||||
lock sync.Mutex
|
||||
actions []fakeAction
|
||||
}
|
||||
|
||||
// ServeHTTP logs the action that occurred and always returns the associated status code
|
||||
func (f *fakeActionHandler) ServeHTTP(response http.ResponseWriter, request *http.Request) {
|
||||
f.lock.Lock()
|
||||
defer f.lock.Unlock()
|
||||
|
||||
f.actions = append(f.actions, fakeAction{method: request.Method, path: request.URL.Path, query: request.URL.RawQuery})
|
||||
fakeResponse, ok := f.response[request.Method+request.URL.Path]
|
||||
if !ok {
|
||||
fakeResponse.statusCode = 200
|
||||
fakeResponse.content = []byte("{\"kind\": \"List\"}")
|
||||
}
|
||||
response.Header().Set("Content-Type", "application/json")
|
||||
response.WriteHeader(fakeResponse.statusCode)
|
||||
response.Write(fakeResponse.content)
|
||||
}
|
||||
|
||||
// testServerAndClientConfig returns a server that listens and a config that can reference it
|
||||
func testServerAndClientConfig(handler func(http.ResponseWriter, *http.Request)) (*httptest.Server, *restclient.Config) {
|
||||
srv := httptest.NewServer(http.HandlerFunc(handler))
|
||||
config := &restclient.Config{
|
||||
Host: srv.URL,
|
||||
}
|
||||
return srv, config
|
||||
}
|
||||
|
||||
func setupGC(t *testing.T, config *restclient.Config) *GarbageCollector {
|
||||
config.ContentConfig.NegotiatedSerializer = serializer.DirectCodecFactory{CodecFactory: metaonly.NewMetadataCodecFactory()}
|
||||
metaOnlyClientPool := dynamic.NewClientPool(config, registered.RESTMapper(), dynamic.LegacyAPIPathResolverFunc)
|
||||
config.ContentConfig.NegotiatedSerializer = nil
|
||||
clientPool := dynamic.NewClientPool(config, registered.RESTMapper(), dynamic.LegacyAPIPathResolverFunc)
|
||||
podResource := []schema.GroupVersionResource{{Version: "v1", Resource: "pods"}}
|
||||
gc, err := NewGarbageCollector(metaOnlyClientPool, clientPool, registered.RESTMapper(), podResource)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return gc
|
||||
}
|
||||
|
||||
func getPod(podName string, ownerReferences []v1.OwnerReference) *v1.Pod {
|
||||
return &v1.Pod{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "Pod",
|
||||
APIVersion: "v1",
|
||||
},
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Name: podName,
|
||||
Namespace: "ns1",
|
||||
OwnerReferences: ownerReferences,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func serilizeOrDie(t *testing.T, object interface{}) []byte {
|
||||
data, err := json.Marshal(object)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
// test the processItem function making the expected actions.
|
||||
func TestProcessItem(t *testing.T) {
|
||||
pod := getPod("ToBeDeletedPod", []v1.OwnerReference{
|
||||
{
|
||||
Kind: "ReplicationController",
|
||||
Name: "owner1",
|
||||
UID: "123",
|
||||
APIVersion: "v1",
|
||||
},
|
||||
})
|
||||
testHandler := &fakeActionHandler{
|
||||
response: map[string]FakeResponse{
|
||||
"GET" + "/api/v1/namespaces/ns1/replicationcontrollers/owner1": {
|
||||
404,
|
||||
[]byte{},
|
||||
},
|
||||
"GET" + "/api/v1/namespaces/ns1/pods/ToBeDeletedPod": {
|
||||
200,
|
||||
serilizeOrDie(t, pod),
|
||||
},
|
||||
},
|
||||
}
|
||||
srv, clientConfig := testServerAndClientConfig(testHandler.ServeHTTP)
|
||||
defer srv.Close()
|
||||
gc := setupGC(t, clientConfig)
|
||||
item := &node{
|
||||
identity: objectReference{
|
||||
OwnerReference: metatypes.OwnerReference{
|
||||
Kind: pod.Kind,
|
||||
APIVersion: pod.APIVersion,
|
||||
Name: pod.Name,
|
||||
UID: pod.UID,
|
||||
},
|
||||
Namespace: pod.Namespace,
|
||||
},
|
||||
// owners are intentionally left empty. The processItem routine should get the latest item from the server.
|
||||
owners: nil,
|
||||
}
|
||||
err := gc.processItem(item)
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected Error: %v", err)
|
||||
}
|
||||
expectedActionSet := sets.NewString()
|
||||
expectedActionSet.Insert("GET=/api/v1/namespaces/ns1/replicationcontrollers/owner1")
|
||||
expectedActionSet.Insert("DELETE=/api/v1/namespaces/ns1/pods/ToBeDeletedPod")
|
||||
expectedActionSet.Insert("GET=/api/v1/namespaces/ns1/pods/ToBeDeletedPod")
|
||||
|
||||
actualActionSet := sets.NewString()
|
||||
for _, action := range testHandler.actions {
|
||||
actualActionSet.Insert(action.String())
|
||||
}
|
||||
if !expectedActionSet.Equal(actualActionSet) {
|
||||
t.Errorf("expected actions:\n%v\n but got:\n%v\nDifference:\n%v", expectedActionSet,
|
||||
actualActionSet, expectedActionSet.Difference(actualActionSet))
|
||||
}
|
||||
}
|
||||
|
||||
// verifyGraphInvariants verifies that all of a node's owners list the node as a
|
||||
// dependent and vice versa. uidToNode has all the nodes in the graph.
|
||||
func verifyGraphInvariants(scenario string, uidToNode map[types.UID]*node, t *testing.T) {
|
||||
for myUID, node := range uidToNode {
|
||||
for dependentNode := range node.dependents {
|
||||
found := false
|
||||
for _, owner := range dependentNode.owners {
|
||||
if owner.UID == myUID {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
t.Errorf("scenario: %s: node %s has node %s as a dependent, but it's not present in the latter node's owners list", scenario, node.identity, dependentNode.identity)
|
||||
}
|
||||
}
|
||||
|
||||
for _, owner := range node.owners {
|
||||
ownerNode, ok := uidToNode[owner.UID]
|
||||
if !ok {
|
||||
// It's possible that the owner node doesn't exist
|
||||
continue
|
||||
}
|
||||
if _, ok := ownerNode.dependents[node]; !ok {
|
||||
t.Errorf("node %s has node %s as an owner, but it's not present in the latter node's dependents list", node.identity, ownerNode.identity)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func createEvent(eventType eventType, selfUID string, owners []string) event {
|
||||
var ownerReferences []v1.OwnerReference
|
||||
for i := 0; i < len(owners); i++ {
|
||||
ownerReferences = append(ownerReferences, v1.OwnerReference{UID: types.UID(owners[i])})
|
||||
}
|
||||
return event{
|
||||
eventType: eventType,
|
||||
obj: &v1.Pod{
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
UID: types.UID(selfUID),
|
||||
OwnerReferences: ownerReferences,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func TestProcessEvent(t *testing.T) {
|
||||
var testScenarios = []struct {
|
||||
name string
|
||||
// a series of events that will be supplied to the
|
||||
// Propagator.eventQueue.
|
||||
events []event
|
||||
}{
|
||||
{
|
||||
name: "test1",
|
||||
events: []event{
|
||||
createEvent(addEvent, "1", []string{}),
|
||||
createEvent(addEvent, "2", []string{"1"}),
|
||||
createEvent(addEvent, "3", []string{"1", "2"}),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "test2",
|
||||
events: []event{
|
||||
createEvent(addEvent, "1", []string{}),
|
||||
createEvent(addEvent, "2", []string{"1"}),
|
||||
createEvent(addEvent, "3", []string{"1", "2"}),
|
||||
createEvent(addEvent, "4", []string{"2"}),
|
||||
createEvent(deleteEvent, "2", []string{"doesn't matter"}),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "test3",
|
||||
events: []event{
|
||||
createEvent(addEvent, "1", []string{}),
|
||||
createEvent(addEvent, "2", []string{"1"}),
|
||||
createEvent(addEvent, "3", []string{"1", "2"}),
|
||||
createEvent(addEvent, "4", []string{"3"}),
|
||||
createEvent(updateEvent, "2", []string{"4"}),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "reverse test2",
|
||||
events: []event{
|
||||
createEvent(addEvent, "4", []string{"2"}),
|
||||
createEvent(addEvent, "3", []string{"1", "2"}),
|
||||
createEvent(addEvent, "2", []string{"1"}),
|
||||
createEvent(addEvent, "1", []string{}),
|
||||
createEvent(deleteEvent, "2", []string{"doesn't matter"}),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, scenario := range testScenarios {
|
||||
propagator := &Propagator{
|
||||
eventQueue: workqueue.NewTimedWorkQueue(),
|
||||
uidToNode: &concurrentUIDToNode{
|
||||
RWMutex: &sync.RWMutex{},
|
||||
uidToNode: make(map[types.UID]*node),
|
||||
},
|
||||
gc: &GarbageCollector{
|
||||
dirtyQueue: workqueue.NewTimedWorkQueue(),
|
||||
clock: clock.RealClock{},
|
||||
absentOwnerCache: NewUIDCache(2),
|
||||
},
|
||||
}
|
||||
for i := 0; i < len(scenario.events); i++ {
|
||||
propagator.eventQueue.Add(&workqueue.TimedWorkQueueItem{StartTime: propagator.gc.clock.Now(), Object: &scenario.events[i]})
|
||||
propagator.processEvent()
|
||||
verifyGraphInvariants(scenario.name, propagator.uidToNode.uidToNode, t)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestDependentsRace relies on golang's data race detector to check if there is
|
||||
// data race among in the dependents field.
|
||||
func TestDependentsRace(t *testing.T) {
|
||||
gc := setupGC(t, &restclient.Config{})
|
||||
|
||||
const updates = 100
|
||||
owner := &node{dependents: make(map[*node]struct{})}
|
||||
ownerUID := types.UID("owner")
|
||||
gc.propagator.uidToNode.Write(owner)
|
||||
go func() {
|
||||
for i := 0; i < updates; i++ {
|
||||
dependent := &node{}
|
||||
gc.propagator.addDependentToOwners(dependent, []metatypes.OwnerReference{{UID: ownerUID}})
|
||||
gc.propagator.removeDependentFromOwners(dependent, []metatypes.OwnerReference{{UID: ownerUID}})
|
||||
}
|
||||
}()
|
||||
go func() {
|
||||
gc.orphanQueue.Add(&workqueue.TimedWorkQueueItem{StartTime: gc.clock.Now(), Object: owner})
|
||||
for i := 0; i < updates; i++ {
|
||||
gc.orphanFinalizer()
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// test the list and watch functions correctly converts the ListOptions
|
||||
func TestGCListWatcher(t *testing.T) {
|
||||
testHandler := &fakeActionHandler{}
|
||||
srv, clientConfig := testServerAndClientConfig(testHandler.ServeHTTP)
|
||||
defer srv.Close()
|
||||
clientPool := dynamic.NewClientPool(clientConfig, registered.RESTMapper(), dynamic.LegacyAPIPathResolverFunc)
|
||||
podResource := schema.GroupVersionResource{Version: "v1", Resource: "pods"}
|
||||
client, err := clientPool.ClientForGroupVersionResource(podResource)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
lw := gcListWatcher(client, podResource)
|
||||
lw.Watch(v1.ListOptions{ResourceVersion: "1"})
|
||||
lw.List(v1.ListOptions{ResourceVersion: "1"})
|
||||
if e, a := 2, len(testHandler.actions); e != a {
|
||||
t.Errorf("expect %d requests, got %d", e, a)
|
||||
}
|
||||
if e, a := "resourceVersion=1", testHandler.actions[0].query; e != a {
|
||||
t.Errorf("expect %s, got %s", e, a)
|
||||
}
|
||||
if e, a := "resourceVersion=1", testHandler.actions[1].query; e != a {
|
||||
t.Errorf("expect %s, got %s", e, a)
|
||||
}
|
||||
}
|
||||
|
||||
func podToGCNode(pod *v1.Pod) *node {
|
||||
return &node{
|
||||
identity: objectReference{
|
||||
OwnerReference: metatypes.OwnerReference{
|
||||
Kind: pod.Kind,
|
||||
APIVersion: pod.APIVersion,
|
||||
Name: pod.Name,
|
||||
UID: pod.UID,
|
||||
},
|
||||
Namespace: pod.Namespace,
|
||||
},
|
||||
// owners are intentionally left empty. The processItem routine should get the latest item from the server.
|
||||
owners: nil,
|
||||
}
|
||||
}
|
||||
|
||||
func TestAbsentUIDCache(t *testing.T) {
|
||||
rc1Pod1 := getPod("rc1Pod1", []v1.OwnerReference{
|
||||
{
|
||||
Kind: "ReplicationController",
|
||||
Name: "rc1",
|
||||
UID: "1",
|
||||
APIVersion: "v1",
|
||||
},
|
||||
})
|
||||
rc1Pod2 := getPod("rc1Pod2", []v1.OwnerReference{
|
||||
{
|
||||
Kind: "ReplicationController",
|
||||
Name: "rc1",
|
||||
UID: "1",
|
||||
APIVersion: "v1",
|
||||
},
|
||||
})
|
||||
rc2Pod1 := getPod("rc2Pod1", []v1.OwnerReference{
|
||||
{
|
||||
Kind: "ReplicationController",
|
||||
Name: "rc2",
|
||||
UID: "2",
|
||||
APIVersion: "v1",
|
||||
},
|
||||
})
|
||||
rc3Pod1 := getPod("rc3Pod1", []v1.OwnerReference{
|
||||
{
|
||||
Kind: "ReplicationController",
|
||||
Name: "rc3",
|
||||
UID: "3",
|
||||
APIVersion: "v1",
|
||||
},
|
||||
})
|
||||
testHandler := &fakeActionHandler{
|
||||
response: map[string]FakeResponse{
|
||||
"GET" + "/api/v1/namespaces/ns1/pods/rc1Pod1": {
|
||||
200,
|
||||
serilizeOrDie(t, rc1Pod1),
|
||||
},
|
||||
"GET" + "/api/v1/namespaces/ns1/pods/rc1Pod2": {
|
||||
200,
|
||||
serilizeOrDie(t, rc1Pod2),
|
||||
},
|
||||
"GET" + "/api/v1/namespaces/ns1/pods/rc2Pod1": {
|
||||
200,
|
||||
serilizeOrDie(t, rc2Pod1),
|
||||
},
|
||||
"GET" + "/api/v1/namespaces/ns1/pods/rc3Pod1": {
|
||||
200,
|
||||
serilizeOrDie(t, rc3Pod1),
|
||||
},
|
||||
"GET" + "/api/v1/namespaces/ns1/replicationcontrollers/rc1": {
|
||||
404,
|
||||
[]byte{},
|
||||
},
|
||||
"GET" + "/api/v1/namespaces/ns1/replicationcontrollers/rc2": {
|
||||
404,
|
||||
[]byte{},
|
||||
},
|
||||
"GET" + "/api/v1/namespaces/ns1/replicationcontrollers/rc3": {
|
||||
404,
|
||||
[]byte{},
|
||||
},
|
||||
},
|
||||
}
|
||||
srv, clientConfig := testServerAndClientConfig(testHandler.ServeHTTP)
|
||||
defer srv.Close()
|
||||
gc := setupGC(t, clientConfig)
|
||||
gc.absentOwnerCache = NewUIDCache(2)
|
||||
gc.processItem(podToGCNode(rc1Pod1))
|
||||
gc.processItem(podToGCNode(rc2Pod1))
|
||||
// rc1 should already be in the cache, no request should be sent. rc1 should be promoted in the UIDCache
|
||||
gc.processItem(podToGCNode(rc1Pod2))
|
||||
// after this call, rc2 should be evicted from the UIDCache
|
||||
gc.processItem(podToGCNode(rc3Pod1))
|
||||
// check cache
|
||||
if !gc.absentOwnerCache.Has(types.UID("1")) {
|
||||
t.Errorf("expected rc1 to be in the cache")
|
||||
}
|
||||
if gc.absentOwnerCache.Has(types.UID("2")) {
|
||||
t.Errorf("expected rc2 to not exist in the cache")
|
||||
}
|
||||
if !gc.absentOwnerCache.Has(types.UID("3")) {
|
||||
t.Errorf("expected rc3 to be in the cache")
|
||||
}
|
||||
// check the request sent to the server
|
||||
count := 0
|
||||
for _, action := range testHandler.actions {
|
||||
if action.String() == "GET=/api/v1/namespaces/ns1/replicationcontrollers/rc1" {
|
||||
count++
|
||||
}
|
||||
}
|
||||
if count != 1 {
|
||||
t.Errorf("expected only 1 GET rc1 request, got %d", count)
|
||||
}
|
||||
}
|
||||
47
vendor/k8s.io/kubernetes/pkg/controller/garbagecollector/metaonly/BUILD
generated
vendored
Normal file
47
vendor/k8s.io/kubernetes/pkg/controller/garbagecollector/metaonly/BUILD
generated
vendored
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_binary",
|
||||
"go_library",
|
||||
"go_test",
|
||||
"cgo_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"metaonly.go",
|
||||
"types.generated.go",
|
||||
"types.go",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//pkg/api:go_default_library",
|
||||
"//pkg/api/v1:go_default_library",
|
||||
"//pkg/apis/meta/v1:go_default_library",
|
||||
"//pkg/runtime:go_default_library",
|
||||
"//pkg/runtime/schema:go_default_library",
|
||||
"//pkg/runtime/serializer:go_default_library",
|
||||
"//pkg/types:go_default_library",
|
||||
"//vendor:github.com/ugorji/go/codec",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["metaonly_test.go"],
|
||||
library = "go_default_library",
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//pkg/api/install:go_default_library",
|
||||
"//pkg/api/meta:go_default_library",
|
||||
"//pkg/api/v1:go_default_library",
|
||||
"//pkg/apis/meta/v1:go_default_library",
|
||||
"//pkg/runtime:go_default_library",
|
||||
"//pkg/runtime/schema:go_default_library",
|
||||
"//pkg/runtime/serializer:go_default_library",
|
||||
],
|
||||
)
|
||||
65
vendor/k8s.io/kubernetes/pkg/controller/garbagecollector/metaonly/metaonly.go
generated
vendored
Normal file
65
vendor/k8s.io/kubernetes/pkg/controller/garbagecollector/metaonly/metaonly.go
generated
vendored
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
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 metaonly
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
metav1 "k8s.io/kubernetes/pkg/apis/meta/v1"
|
||||
"k8s.io/kubernetes/pkg/runtime"
|
||||
"k8s.io/kubernetes/pkg/runtime/schema"
|
||||
"k8s.io/kubernetes/pkg/runtime/serializer"
|
||||
)
|
||||
|
||||
func (obj *MetadataOnlyObject) GetObjectKind() schema.ObjectKind { return obj }
|
||||
func (obj *MetadataOnlyObjectList) GetObjectKind() schema.ObjectKind { return obj }
|
||||
|
||||
type metaOnlyJSONScheme struct{}
|
||||
|
||||
// This function can be extended to mapping different gvk to different MetadataOnlyObject,
|
||||
// which embedded with different version of ObjectMeta. Currently the system
|
||||
// only supports v1.ObjectMeta.
|
||||
func gvkToMetadataOnlyObject(gvk schema.GroupVersionKind) runtime.Object {
|
||||
if strings.HasSuffix(gvk.Kind, "List") {
|
||||
return &MetadataOnlyObjectList{}
|
||||
} else {
|
||||
return &MetadataOnlyObject{}
|
||||
}
|
||||
}
|
||||
|
||||
func NewMetadataCodecFactory() serializer.CodecFactory {
|
||||
// populating another scheme from api.Scheme, registering every kind with
|
||||
// MetadataOnlyObject (or MetadataOnlyObjectList).
|
||||
scheme := runtime.NewScheme()
|
||||
allTypes := api.Scheme.AllKnownTypes()
|
||||
for kind := range allTypes {
|
||||
if kind.Version == runtime.APIVersionInternal {
|
||||
continue
|
||||
}
|
||||
metaOnlyObject := gvkToMetadataOnlyObject(kind)
|
||||
scheme.AddKnownTypeWithName(kind, metaOnlyObject)
|
||||
}
|
||||
scheme.AddUnversionedTypes(api.Unversioned, &metav1.Status{})
|
||||
return serializer.NewCodecFactory(scheme)
|
||||
}
|
||||
|
||||
// String converts a MetadataOnlyObject to a human-readable string.
|
||||
func (metaOnly MetadataOnlyObject) String() string {
|
||||
return fmt.Sprintf("%s/%s, name: %s, DeletionTimestamp:%v", metaOnly.TypeMeta.APIVersion, metaOnly.TypeMeta.Kind, metaOnly.ObjectMeta.Name, metaOnly.ObjectMeta.DeletionTimestamp)
|
||||
}
|
||||
164
vendor/k8s.io/kubernetes/pkg/controller/garbagecollector/metaonly/metaonly_test.go
generated
vendored
Normal file
164
vendor/k8s.io/kubernetes/pkg/controller/garbagecollector/metaonly/metaonly_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,164 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
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 metaonly
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
_ "k8s.io/kubernetes/pkg/api/install"
|
||||
"k8s.io/kubernetes/pkg/api/meta"
|
||||
"k8s.io/kubernetes/pkg/api/v1"
|
||||
metav1 "k8s.io/kubernetes/pkg/apis/meta/v1"
|
||||
"k8s.io/kubernetes/pkg/runtime"
|
||||
"k8s.io/kubernetes/pkg/runtime/schema"
|
||||
"k8s.io/kubernetes/pkg/runtime/serializer"
|
||||
)
|
||||
|
||||
func getPod() *v1.Pod {
|
||||
return &v1.Pod{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "Pod",
|
||||
APIVersion: "v1",
|
||||
},
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Name: "pod",
|
||||
OwnerReferences: []v1.OwnerReference{
|
||||
{UID: "1234"},
|
||||
},
|
||||
},
|
||||
Spec: v1.PodSpec{
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Name: "fake-name",
|
||||
Image: "fakeimage",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func getPodJson(t *testing.T) []byte {
|
||||
data, err := json.Marshal(getPod())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
func getPodListJson(t *testing.T) []byte {
|
||||
data, err := json.Marshal(&v1.PodList{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "PodList",
|
||||
APIVersion: "v1",
|
||||
},
|
||||
Items: []v1.Pod{
|
||||
*getPod(),
|
||||
*getPod(),
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
func verfiyMetadata(description string, t *testing.T, in *MetadataOnlyObject) {
|
||||
pod := getPod()
|
||||
if e, a := pod.ObjectMeta, in.ObjectMeta; !reflect.DeepEqual(e, a) {
|
||||
t.Errorf("%s: expected %#v, got %#v", description, e, a)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDecodeToMetadataOnlyObject(t *testing.T) {
|
||||
data := getPodJson(t)
|
||||
cf := serializer.DirectCodecFactory{CodecFactory: NewMetadataCodecFactory()}
|
||||
info, ok := runtime.SerializerInfoForMediaType(cf.SupportedMediaTypes(), runtime.ContentTypeJSON)
|
||||
if !ok {
|
||||
t.Fatalf("expected to get a JSON serializer")
|
||||
}
|
||||
codec := cf.DecoderToVersion(info.Serializer, schema.GroupVersion{Group: "SOMEGROUP", Version: "SOMEVERSION"})
|
||||
// decode with into
|
||||
into := &MetadataOnlyObject{}
|
||||
ret, _, err := codec.Decode(data, nil, into)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
metaOnly, ok := ret.(*MetadataOnlyObject)
|
||||
if !ok {
|
||||
t.Fatalf("expected ret to be *runtime.MetadataOnlyObject")
|
||||
}
|
||||
verfiyMetadata("check returned metaonly with into", t, metaOnly)
|
||||
verfiyMetadata("check into", t, into)
|
||||
// decode without into
|
||||
ret, _, err = codec.Decode(data, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
metaOnly, ok = ret.(*MetadataOnlyObject)
|
||||
if !ok {
|
||||
t.Fatalf("expected ret to be *runtime.MetadataOnlyObject")
|
||||
}
|
||||
verfiyMetadata("check returned metaonly without into", t, metaOnly)
|
||||
}
|
||||
|
||||
func verifyListMetadata(t *testing.T, metaOnlyList *MetadataOnlyObjectList) {
|
||||
items, err := meta.ExtractList(metaOnlyList)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, item := range items {
|
||||
metaOnly, ok := item.(*MetadataOnlyObject)
|
||||
if !ok {
|
||||
t.Fatalf("expected item to be *MetadataOnlyObject")
|
||||
}
|
||||
verfiyMetadata("check list", t, metaOnly)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDecodeToMetadataOnlyObjectList(t *testing.T) {
|
||||
data := getPodListJson(t)
|
||||
cf := serializer.DirectCodecFactory{CodecFactory: NewMetadataCodecFactory()}
|
||||
info, ok := runtime.SerializerInfoForMediaType(cf.SupportedMediaTypes(), runtime.ContentTypeJSON)
|
||||
if !ok {
|
||||
t.Fatalf("expected to get a JSON serializer")
|
||||
}
|
||||
codec := cf.DecoderToVersion(info.Serializer, schema.GroupVersion{Group: "SOMEGROUP", Version: "SOMEVERSION"})
|
||||
// decode with into
|
||||
into := &MetadataOnlyObjectList{}
|
||||
ret, _, err := codec.Decode(data, nil, into)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
metaOnlyList, ok := ret.(*MetadataOnlyObjectList)
|
||||
if !ok {
|
||||
t.Fatalf("expected ret to be *runtime.UnstructuredList")
|
||||
}
|
||||
verifyListMetadata(t, metaOnlyList)
|
||||
verifyListMetadata(t, into)
|
||||
// decode without into
|
||||
ret, _, err = codec.Decode(data, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
metaOnlyList, ok = ret.(*MetadataOnlyObjectList)
|
||||
if !ok {
|
||||
t.Fatalf("expected ret to be *runtime.UnstructuredList")
|
||||
}
|
||||
verifyListMetadata(t, metaOnlyList)
|
||||
}
|
||||
791
vendor/k8s.io/kubernetes/pkg/controller/garbagecollector/metaonly/types.generated.go
generated
vendored
Normal file
791
vendor/k8s.io/kubernetes/pkg/controller/garbagecollector/metaonly/types.generated.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
42
vendor/k8s.io/kubernetes/pkg/controller/garbagecollector/metaonly/types.go
generated
vendored
Normal file
42
vendor/k8s.io/kubernetes/pkg/controller/garbagecollector/metaonly/types.go
generated
vendored
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
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 metaonly
|
||||
|
||||
import (
|
||||
"k8s.io/kubernetes/pkg/api/v1"
|
||||
metav1 "k8s.io/kubernetes/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
// MetadataOnlyObject allows decoding only the apiVersion, kind, and metadata fields of
|
||||
// JSON data.
|
||||
// TODO: enable meta-only decoding for protobuf.
|
||||
type MetadataOnlyObject struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
// +optional
|
||||
v1.ObjectMeta `json:"metadata,omitempty"`
|
||||
}
|
||||
|
||||
// MetadataOnlyObjectList allows decoding from JSON data only the typemeta and metadata of
|
||||
// a list, and those of the enclosing objects.
|
||||
// TODO: enable meta-only decoding for protobuf.
|
||||
type MetadataOnlyObjectList struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
// +optional
|
||||
metav1.ListMeta `json:"metadata,omitempty"`
|
||||
|
||||
Items []MetadataOnlyObject `json:"items"`
|
||||
}
|
||||
73
vendor/k8s.io/kubernetes/pkg/controller/garbagecollector/metrics.go
generated
vendored
Normal file
73
vendor/k8s.io/kubernetes/pkg/controller/garbagecollector/metrics.go
generated
vendored
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
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 garbagecollector
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"k8s.io/kubernetes/pkg/util/clock"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
)
|
||||
|
||||
const (
|
||||
GarbageCollectSubsystem = "garbage_collector"
|
||||
EventProcessingLatencyKey = "event_processing_latency_microseconds"
|
||||
DirtyProcessingLatencyKey = "dirty_processing_latency_microseconds"
|
||||
OrphanProcessingLatencyKey = "orphan_processing_latency_microseconds"
|
||||
)
|
||||
|
||||
var (
|
||||
EventProcessingLatency = prometheus.NewSummary(
|
||||
prometheus.SummaryOpts{
|
||||
Subsystem: GarbageCollectSubsystem,
|
||||
Name: EventProcessingLatencyKey,
|
||||
Help: "Time in microseconds of an event spend in the eventQueue",
|
||||
},
|
||||
)
|
||||
DirtyProcessingLatency = prometheus.NewSummary(
|
||||
prometheus.SummaryOpts{
|
||||
Subsystem: GarbageCollectSubsystem,
|
||||
Name: DirtyProcessingLatencyKey,
|
||||
Help: "Time in microseconds of an item spend in the dirtyQueue",
|
||||
},
|
||||
)
|
||||
OrphanProcessingLatency = prometheus.NewSummary(
|
||||
prometheus.SummaryOpts{
|
||||
Subsystem: GarbageCollectSubsystem,
|
||||
Name: OrphanProcessingLatencyKey,
|
||||
Help: "Time in microseconds of an item spend in the orphanQueue",
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
var registerMetrics sync.Once
|
||||
|
||||
// Register all metrics.
|
||||
func Register() {
|
||||
// Register the metrics.
|
||||
registerMetrics.Do(func() {
|
||||
prometheus.MustRegister(EventProcessingLatency)
|
||||
prometheus.MustRegister(DirtyProcessingLatency)
|
||||
prometheus.MustRegister(OrphanProcessingLatency)
|
||||
})
|
||||
}
|
||||
|
||||
func sinceInMicroseconds(clock clock.Clock, start time.Time) float64 {
|
||||
return float64(clock.Since(start).Nanoseconds() / time.Microsecond.Nanoseconds())
|
||||
}
|
||||
60
vendor/k8s.io/kubernetes/pkg/controller/garbagecollector/rate_limiter_helper.go
generated
vendored
Normal file
60
vendor/k8s.io/kubernetes/pkg/controller/garbagecollector/rate_limiter_helper.go
generated
vendored
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
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 garbagecollector
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"k8s.io/kubernetes/pkg/client/typed/dynamic"
|
||||
"k8s.io/kubernetes/pkg/runtime/schema"
|
||||
"k8s.io/kubernetes/pkg/util/metrics"
|
||||
)
|
||||
|
||||
// RegisteredRateLimiter records the registered RateLimters to avoid
|
||||
// duplication.
|
||||
type RegisteredRateLimiter struct {
|
||||
rateLimiters map[schema.GroupVersion]*sync.Once
|
||||
}
|
||||
|
||||
// NewRegisteredRateLimiter returns a new RegisteredRateLimiater.
|
||||
// TODO: NewRegisteredRateLimiter is not dynamic. We need to find a better way
|
||||
// when GC dynamically change the resources it monitors.
|
||||
func NewRegisteredRateLimiter(resources []schema.GroupVersionResource) *RegisteredRateLimiter {
|
||||
rateLimiters := make(map[schema.GroupVersion]*sync.Once)
|
||||
for _, resource := range resources {
|
||||
gv := resource.GroupVersion()
|
||||
if _, found := rateLimiters[gv]; !found {
|
||||
rateLimiters[gv] = &sync.Once{}
|
||||
}
|
||||
}
|
||||
return &RegisteredRateLimiter{rateLimiters: rateLimiters}
|
||||
}
|
||||
|
||||
func (r *RegisteredRateLimiter) registerIfNotPresent(gv schema.GroupVersion, client *dynamic.Client, prefix string) {
|
||||
once, found := r.rateLimiters[gv]
|
||||
if !found {
|
||||
return
|
||||
}
|
||||
once.Do(func() {
|
||||
if rateLimiter := client.GetRateLimiter(); rateLimiter != nil {
|
||||
group := strings.Replace(gv.Group, ".", ":", -1)
|
||||
metrics.RegisterMetricAndTrackRateLimiterUsage(fmt.Sprintf("%s_%s_%s", prefix, group, gv.Version), rateLimiter)
|
||||
}
|
||||
})
|
||||
}
|
||||
52
vendor/k8s.io/kubernetes/pkg/controller/garbagecollector/uid_cache.go
generated
vendored
Normal file
52
vendor/k8s.io/kubernetes/pkg/controller/garbagecollector/uid_cache.go
generated
vendored
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
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 garbagecollector
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/golang/groupcache/lru"
|
||||
"k8s.io/kubernetes/pkg/types"
|
||||
)
|
||||
|
||||
// UIDCache is an LRU cache for uid.
|
||||
type UIDCache struct {
|
||||
mutex sync.Mutex
|
||||
cache *lru.Cache
|
||||
}
|
||||
|
||||
// NewUIDCache returns a UIDCache.
|
||||
func NewUIDCache(maxCacheEntries int) *UIDCache {
|
||||
return &UIDCache{
|
||||
cache: lru.New(maxCacheEntries),
|
||||
}
|
||||
}
|
||||
|
||||
// Add adds a uid to the cache.
|
||||
func (c *UIDCache) Add(uid types.UID) {
|
||||
c.mutex.Lock()
|
||||
defer c.mutex.Unlock()
|
||||
c.cache.Add(uid, nil)
|
||||
}
|
||||
|
||||
// Has returns if a uid is in the cache.
|
||||
func (c *UIDCache) Has(uid types.UID) bool {
|
||||
c.mutex.Lock()
|
||||
defer c.mutex.Unlock()
|
||||
_, found := c.cache.Get(uid)
|
||||
return found
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue