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
1cf69bde
Commit
1cf69bde
authored
Feb 05, 2015
by
derekwaynecarr
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Support multiple index functions, address feedback
parent
7a2d6304
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
120 additions
and
71 deletions
+120
-71
index.go
pkg/client/cache/index.go
+52
-0
store.go
pkg/client/cache/store.go
+55
-64
store_test.go
pkg/client/cache/store_test.go
+13
-7
No files found.
pkg/client/cache/index.go
0 → 100644
View file @
1cf69bde
/*
Copyright 2014 Google Inc. All rights reserved.
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
cache
import
(
"fmt"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/meta"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
)
// Indexer is a storage interface that lets you list objects using multiple indexing functions
type
Indexer
interface
{
Store
// Retrieve list of objects that match on the named indexing function
Index
(
indexName
string
,
obj
interface
{})
([]
interface
{},
error
)
}
// IndexFunc knows how to provide an indexed value for an object.
type
IndexFunc
func
(
obj
interface
{})
(
string
,
error
)
// MetaNamespaceIndexFunc is a default index function that indexes based on an object's namespace
func
MetaNamespaceIndexFunc
(
obj
interface
{})
(
string
,
error
)
{
meta
,
err
:=
meta
.
Accessor
(
obj
)
if
err
!=
nil
{
return
""
,
fmt
.
Errorf
(
"object has no meta: %v"
,
err
)
}
return
meta
.
Namespace
(),
nil
}
// Index maps the indexed value to a set of keys in the store that match on that value
type
Index
map
[
string
]
util
.
StringSet
// Indexers maps a name to a IndexFunc
type
Indexers
map
[
string
]
IndexFunc
// Indices maps a name to an Index
type
Indices
map
[
string
]
Index
pkg/client/cache/store.go
View file @
1cf69bde
...
@@ -60,35 +60,16 @@ func MetaNamespaceKeyFunc(obj interface{}) (string, error) {
...
@@ -60,35 +60,16 @@ func MetaNamespaceKeyFunc(obj interface{}) (string, error) {
return
meta
.
Namespace
()
+
"/"
+
meta
.
Name
(),
nil
return
meta
.
Namespace
()
+
"/"
+
meta
.
Name
(),
nil
}
}
// Index is a generic object storage interface that lets you list objects by their Index
type
Index
interface
{
Store
Index
(
obj
interface
{})
([]
interface
{},
error
)
}
// IndexFunc knows how to provide an indexed value for an object.
type
IndexFunc
func
(
obj
interface
{})
(
string
,
error
)
// MetaNamespaceIndexFunc is a convenient default IndexFun which knows how to index
// an object by its namespace.
func
MetaNamespaceIndexFunc
(
obj
interface
{})
(
string
,
error
)
{
meta
,
err
:=
meta
.
Accessor
(
obj
)
if
err
!=
nil
{
return
""
,
fmt
.
Errorf
(
"object has no meta: %v"
,
err
)
}
return
meta
.
Namespace
(),
nil
}
type
cache
struct
{
type
cache
struct
{
lock
sync
.
RWMutex
lock
sync
.
RWMutex
items
map
[
string
]
interface
{}
items
map
[
string
]
interface
{}
// keyFunc is used to make the key for objects stored in and retrieved from items, and
// keyFunc is used to make the key for objects stored in and retrieved from items, and
// should be deterministic.
// should be deterministic.
keyFunc
KeyFunc
keyFunc
KeyFunc
// index
Func is used to make the index value for objects stored in an retrieved from index
// index
ers maps a name to an IndexFunc
index
Func
IndexFunc
index
ers
Indexers
//
maps the indexFunc value for an object to a set whose keys are keys in items
//
indices maps a name to an Index
ind
ex
map
[
string
]
util
.
StringSet
ind
ices
Indices
}
}
// Add inserts an item into the cache.
// Add inserts an item into the cache.
...
@@ -100,53 +81,57 @@ func (c *cache) Add(obj interface{}) error {
...
@@ -100,53 +81,57 @@ func (c *cache) Add(obj interface{}) error {
c
.
lock
.
Lock
()
c
.
lock
.
Lock
()
defer
c
.
lock
.
Unlock
()
defer
c
.
lock
.
Unlock
()
c
.
items
[
key
]
=
obj
c
.
items
[
key
]
=
obj
c
.
updateInd
ex
(
obj
)
c
.
updateInd
ices
(
obj
)
return
nil
return
nil
}
}
// updateIndex adds or modifies an object in the index
// updateIndices modifies the objects location in the managed indexes
// it is intended to be called from a function that already has a lock on the cache
// updateIndices must be called from a function that already has a lock on the cache
func
(
c
*
cache
)
updateIndex
(
obj
interface
{})
error
{
func
(
c
*
cache
)
updateIndices
(
obj
interface
{})
error
{
if
c
.
indexFunc
==
nil
{
return
nil
}
key
,
err
:=
c
.
keyFunc
(
obj
)
key
,
err
:=
c
.
keyFunc
(
obj
)
if
err
!=
nil
{
if
err
!=
nil
{
return
err
return
err
}
}
indexValue
,
err
:=
c
.
indexFunc
(
obj
)
for
name
,
indexFunc
:=
range
c
.
indexers
{
if
err
!=
nil
{
indexValue
,
err
:=
indexFunc
(
obj
)
return
err
if
err
!=
nil
{
}
return
err
set
:=
c
.
index
[
indexValue
]
}
if
set
==
nil
{
index
:=
c
.
indices
[
name
]
set
=
util
.
StringSet
{}
if
index
==
nil
{
c
.
index
[
indexValue
]
=
set
index
=
Index
{}
c
.
indices
[
name
]
=
index
}
set
:=
index
[
indexValue
]
if
set
==
nil
{
set
=
util
.
StringSet
{}
index
[
indexValue
]
=
set
}
set
.
Insert
(
key
)
}
}
set
.
Insert
(
key
)
return
nil
return
nil
}
}
// deleteFromInd
ex removes an entry from the index
// deleteFromInd
ices removes the object from each of the managed indexes
// it is intended to be called from a function that already has a lock on the cache
// it is intended to be called from a function that already has a lock on the cache
func
(
c
*
cache
)
deleteFromIndex
(
obj
interface
{})
error
{
func
(
c
*
cache
)
deleteFromIndices
(
obj
interface
{})
error
{
if
c
.
indexFunc
==
nil
{
return
nil
}
key
,
err
:=
c
.
keyFunc
(
obj
)
key
,
err
:=
c
.
keyFunc
(
obj
)
if
err
!=
nil
{
if
err
!=
nil
{
return
err
return
err
}
}
indexValue
,
err
:=
c
.
indexFunc
(
obj
)
for
name
,
indexFunc
:=
range
c
.
indexers
{
if
err
!=
nil
{
indexValue
,
err
:=
indexFunc
(
obj
)
return
err
if
err
!=
nil
{
}
return
err
set
:=
c
.
index
[
indexValue
]
}
if
set
==
nil
{
index
:=
c
.
indices
[
name
]
set
=
util
.
StringSet
{}
if
index
!=
nil
{
c
.
index
[
indexValue
]
=
set
set
:=
index
[
indexValue
]
if
set
!=
nil
{
set
.
Delete
(
key
)
}
}
}
}
set
.
Delete
(
key
)
return
nil
return
nil
}
}
...
@@ -159,7 +144,7 @@ func (c *cache) Update(obj interface{}) error {
...
@@ -159,7 +144,7 @@ func (c *cache) Update(obj interface{}) error {
c
.
lock
.
Lock
()
c
.
lock
.
Lock
()
defer
c
.
lock
.
Unlock
()
defer
c
.
lock
.
Unlock
()
c
.
items
[
key
]
=
obj
c
.
items
[
key
]
=
obj
c
.
updateInd
ex
(
obj
)
c
.
updateInd
ices
(
obj
)
return
nil
return
nil
}
}
...
@@ -172,7 +157,7 @@ func (c *cache) Delete(obj interface{}) error {
...
@@ -172,7 +157,7 @@ func (c *cache) Delete(obj interface{}) error {
c
.
lock
.
Lock
()
c
.
lock
.
Lock
()
defer
c
.
lock
.
Unlock
()
defer
c
.
lock
.
Unlock
()
delete
(
c
.
items
,
key
)
delete
(
c
.
items
,
key
)
c
.
deleteFromInd
ex
(
obj
)
c
.
deleteFromInd
ices
(
obj
)
return
nil
return
nil
}
}
...
@@ -190,15 +175,21 @@ func (c *cache) List() []interface{} {
...
@@ -190,15 +175,21 @@ func (c *cache) List() []interface{} {
// Index returns a list of items that match on the index function
// Index returns a list of items that match on the index function
// Index is thread-safe so long as you treat all items as immutable
// Index is thread-safe so long as you treat all items as immutable
func
(
c
*
cache
)
Index
(
obj
interface
{})
([]
interface
{},
error
)
{
func
(
c
*
cache
)
Index
(
indexName
string
,
obj
interface
{})
([]
interface
{},
error
)
{
c
.
lock
.
RLock
()
c
.
lock
.
RLock
()
defer
c
.
lock
.
RUnlock
()
defer
c
.
lock
.
RUnlock
()
indexKey
,
err
:=
c
.
indexFunc
(
obj
)
indexFunc
:=
c
.
indexers
[
indexName
]
if
indexFunc
==
nil
{
return
nil
,
fmt
.
Errorf
(
"Index with name %s does not exist"
,
indexName
)
}
indexKey
,
err
:=
indexFunc
(
obj
)
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
err
return
nil
,
err
}
}
set
:=
c
.
index
[
indexKey
]
index
:=
c
.
indices
[
indexName
]
set
:=
index
[
indexKey
]
list
:=
make
([]
interface
{},
0
,
set
.
Len
())
list
:=
make
([]
interface
{},
0
,
set
.
Len
())
for
_
,
key
:=
range
set
.
List
()
{
for
_
,
key
:=
range
set
.
List
()
{
list
=
append
(
list
,
c
.
items
[
key
])
list
=
append
(
list
,
c
.
items
[
key
])
...
@@ -243,9 +234,9 @@ func (c *cache) Replace(list []interface{}) error {
...
@@ -243,9 +234,9 @@ func (c *cache) Replace(list []interface{}) error {
c
.
items
=
items
c
.
items
=
items
// rebuild any index
// rebuild any index
c
.
ind
ex
=
map
[
string
]
util
.
StringSet
{}
c
.
ind
ices
=
Indices
{}
for
_
,
item
:=
range
c
.
items
{
for
_
,
item
:=
range
c
.
items
{
c
.
updateInd
ex
(
item
)
c
.
updateInd
ices
(
item
)
}
}
return
nil
return
nil
...
@@ -253,10 +244,10 @@ func (c *cache) Replace(list []interface{}) error {
...
@@ -253,10 +244,10 @@ func (c *cache) Replace(list []interface{}) error {
// NewStore returns a Store implemented simply with a map and a lock.
// NewStore returns a Store implemented simply with a map and a lock.
func
NewStore
(
keyFunc
KeyFunc
)
Store
{
func
NewStore
(
keyFunc
KeyFunc
)
Store
{
return
&
cache
{
items
:
map
[
string
]
interface
{}{},
keyFunc
:
keyFunc
}
return
&
cache
{
items
:
map
[
string
]
interface
{}{},
keyFunc
:
keyFunc
,
indexers
:
Indexers
{},
indices
:
Indices
{}
}
}
}
// NewIndex
returns an Index
implemented simply with a map and a lock.
// NewIndex
er returns an Indexer
implemented simply with a map and a lock.
func
NewIndex
(
keyFunc
KeyFunc
,
indexFunc
IndexFunc
)
Index
{
func
NewIndex
er
(
keyFunc
KeyFunc
,
indexers
Indexers
)
Indexer
{
return
&
cache
{
items
:
map
[
string
]
interface
{}{},
keyFunc
:
keyFunc
,
index
Func
:
indexFunc
,
index
:
map
[
string
]
util
.
StringSet
{}}
return
&
cache
{
items
:
map
[
string
]
interface
{}{},
keyFunc
:
keyFunc
,
index
ers
:
indexers
,
indices
:
Indices
{}}
}
}
pkg/client/cache/store_test.go
View file @
1cf69bde
...
@@ -87,7 +87,7 @@ func doTestStore(t *testing.T, store Store) {
...
@@ -87,7 +87,7 @@ func doTestStore(t *testing.T, store Store) {
}
}
// Test public interface
// Test public interface
func
doTestIndex
(
t
*
testing
.
T
,
index
Index
)
{
func
doTestIndex
(
t
*
testing
.
T
,
index
er
Indexer
)
{
mkObj
:=
func
(
id
string
,
val
string
)
testStoreObject
{
mkObj
:=
func
(
id
string
,
val
string
)
testStoreObject
{
return
testStoreObject
{
id
:
id
,
val
:
val
}
return
testStoreObject
{
id
:
id
,
val
:
val
}
}
}
...
@@ -97,14 +97,14 @@ func doTestIndex(t *testing.T, index Index) {
...
@@ -97,14 +97,14 @@ func doTestIndex(t *testing.T, index Index) {
expected
[
"b"
]
=
util
.
NewStringSet
(
"a"
,
"c"
)
expected
[
"b"
]
=
util
.
NewStringSet
(
"a"
,
"c"
)
expected
[
"f"
]
=
util
.
NewStringSet
(
"e"
)
expected
[
"f"
]
=
util
.
NewStringSet
(
"e"
)
expected
[
"h"
]
=
util
.
NewStringSet
(
"g"
)
expected
[
"h"
]
=
util
.
NewStringSet
(
"g"
)
index
.
Add
(
mkObj
(
"a"
,
"b"
))
index
er
.
Add
(
mkObj
(
"a"
,
"b"
))
index
.
Add
(
mkObj
(
"c"
,
"b"
))
index
er
.
Add
(
mkObj
(
"c"
,
"b"
))
index
.
Add
(
mkObj
(
"e"
,
"f"
))
index
er
.
Add
(
mkObj
(
"e"
,
"f"
))
index
.
Add
(
mkObj
(
"g"
,
"h"
))
index
er
.
Add
(
mkObj
(
"g"
,
"h"
))
{
{
for
k
,
v
:=
range
expected
{
for
k
,
v
:=
range
expected
{
found
:=
util
.
StringSet
{}
found
:=
util
.
StringSet
{}
indexResults
,
err
:=
index
.
Index
(
mkObj
(
""
,
k
))
indexResults
,
err
:=
index
er
.
Index
(
"by_val"
,
mkObj
(
""
,
k
))
if
err
!=
nil
{
if
err
!=
nil
{
t
.
Errorf
(
"Unexpected error %v"
,
err
)
t
.
Errorf
(
"Unexpected error %v"
,
err
)
}
}
...
@@ -127,6 +127,12 @@ func testStoreIndexFunc(obj interface{}) (string, error) {
...
@@ -127,6 +127,12 @@ func testStoreIndexFunc(obj interface{}) (string, error) {
return
obj
.
(
testStoreObject
)
.
val
,
nil
return
obj
.
(
testStoreObject
)
.
val
,
nil
}
}
func
testStoreIndexers
()
Indexers
{
indexers
:=
Indexers
{}
indexers
[
"by_val"
]
=
testStoreIndexFunc
return
indexers
}
type
testStoreObject
struct
{
type
testStoreObject
struct
{
id
string
id
string
val
string
val
string
...
@@ -146,5 +152,5 @@ func TestUndeltaStore(t *testing.T) {
...
@@ -146,5 +152,5 @@ func TestUndeltaStore(t *testing.T) {
}
}
func
TestIndex
(
t
*
testing
.
T
)
{
func
TestIndex
(
t
*
testing
.
T
)
{
doTestIndex
(
t
,
NewIndex
(
testStoreKeyFunc
,
testStoreIndexFunc
))
doTestIndex
(
t
,
NewIndex
er
(
testStoreKeyFunc
,
testStoreIndexers
()
))
}
}
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