-
Notifications
You must be signed in to change notification settings - Fork 487
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
New Mutable Authorized Entry Cache (#4451)
Signed-off-by: Andrew Harding <[email protected]>
- Loading branch information
Showing
14 changed files
with
1,179 additions
and
39 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
package authorizedentries | ||
|
||
type agentRecord struct { | ||
ID string | ||
|
||
// ExpiresAt is seconds since unix epoch. Using intead of time.Time for | ||
// reduced memory usage and better cache locality. | ||
ExpiresAt int64 | ||
|
||
Selectors selectorSet | ||
} | ||
|
||
func agentRecordByID(a, b agentRecord) bool { | ||
return a.ID < b.ID | ||
} | ||
|
||
func agentRecordByExpiresAt(a, b agentRecord) bool { | ||
switch { | ||
case a.ExpiresAt < b.ExpiresAt: | ||
return true | ||
case a.ExpiresAt > b.ExpiresAt: | ||
return false | ||
default: | ||
return a.ID < b.ID | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
package authorizedentries | ||
|
||
import ( | ||
"testing" | ||
"unsafe" | ||
|
||
"github.com/stretchr/testify/assert" | ||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
func TestAgentRecordSize(t *testing.T) { | ||
// The motivation for this test is to bring awareness and visibility into | ||
// how much size the record occupies. We want to minimize the size to | ||
// increase cache locality in the btree. | ||
require.Equal(t, uintptr(32), unsafe.Sizeof(agentRecord{})) | ||
} | ||
|
||
func TestAgentRecordByID(t *testing.T) { | ||
assertLess := func(lesser, greater agentRecord) { | ||
t.Helper() | ||
assert.Truef(t, agentRecordByID(lesser, greater), "expected A%sE%s<A%sE%s", lesser.ID, lesser.ExpiresAt, greater.ID, greater.ExpiresAt) | ||
assert.Falsef(t, agentRecordByID(greater, lesser), "expected A%sE%s>A%sE%s", greater.ID, greater.ExpiresAt, lesser.ID, lesser.ExpiresAt) | ||
} | ||
|
||
// ExpiresAt is irrelevant. | ||
records := []agentRecord{ | ||
agentRecord{ID: "1", ExpiresAt: 9999}, | ||
agentRecord{ID: "2", ExpiresAt: 8888}, | ||
} | ||
|
||
lesser := agentRecord{} | ||
for _, greater := range records { | ||
assertLess(lesser, greater) | ||
lesser = greater | ||
} | ||
|
||
// Since there should only be one agent record by ID, the ExpiresAt field | ||
// is ignored for purposes of placement in the btree. | ||
assert.False(t, agentRecordByID(agentRecord{ID: "FOO", ExpiresAt: 1}, agentRecord{ID: "FOO", ExpiresAt: 2})) | ||
assert.False(t, agentRecordByID(agentRecord{ID: "FOO", ExpiresAt: 2}, agentRecord{ID: "FOO", ExpiresAt: 1})) | ||
} | ||
|
||
func TestAgentRecordByExpiresAt(t *testing.T) { | ||
assertLess := func(lesser, greater agentRecord) { | ||
t.Helper() | ||
assert.Truef(t, agentRecordByExpiresAt(lesser, greater), "expected A%sE%d<A%sE%d", lesser.ID, lesser.ExpiresAt, greater.ID, greater.ExpiresAt) | ||
assert.Falsef(t, agentRecordByExpiresAt(greater, lesser), "expected A%sE%d>A%sE%d", greater.ID, greater.ExpiresAt, lesser.ID, lesser.ExpiresAt) | ||
} | ||
|
||
records := []agentRecord{ | ||
agentRecord{ID: "1"}, | ||
agentRecord{ID: "2"}, | ||
agentRecord{ID: "1", ExpiresAt: 1}, | ||
agentRecord{ID: "2", ExpiresAt: 1}, | ||
agentRecord{ID: "1", ExpiresAt: 2}, | ||
agentRecord{ID: "2", ExpiresAt: 2}, | ||
} | ||
|
||
lesser := agentRecord{} | ||
for _, greater := range records { | ||
assertLess(lesser, greater) | ||
lesser = greater | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
package authorizedentries | ||
|
||
type aliasRecord struct { | ||
// EntryID is the ID of the registration entry that defines this node | ||
// alias. | ||
EntryID string | ||
|
||
// AliasID is the SPIFFE ID of nodes that match this alias. | ||
AliasID string | ||
|
||
// Selector is the specific selector we use to fan out to this record | ||
// during the crawl. | ||
Selector Selector | ||
|
||
// AllSelectors is here out of convenience to verify that the agent | ||
// possesses a superset of the alias's selectors and is therefore | ||
// authorized for the alias. | ||
AllSelectors selectorSet | ||
} | ||
|
||
func aliasRecordByEntryID(a, b aliasRecord) bool { | ||
switch { | ||
case a.EntryID < b.EntryID: | ||
return true | ||
case a.EntryID > b.EntryID: | ||
return false | ||
case a.Selector.Type < b.Selector.Type: | ||
return true | ||
case a.Selector.Type > b.Selector.Type: | ||
return false | ||
default: | ||
return a.Selector.Value < b.Selector.Value | ||
} | ||
} | ||
|
||
func aliasRecordBySelector(a, b aliasRecord) bool { | ||
switch { | ||
case a.Selector.Type < b.Selector.Type: | ||
return true | ||
case a.Selector.Type > b.Selector.Type: | ||
return false | ||
case a.Selector.Value < b.Selector.Value: | ||
return true | ||
case a.Selector.Value > b.Selector.Value: | ||
return false | ||
default: | ||
return a.EntryID < b.EntryID | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
package authorizedentries | ||
|
||
import ( | ||
"testing" | ||
"unsafe" | ||
|
||
"github.com/stretchr/testify/assert" | ||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
func TestAliasRecordSize(t *testing.T) { | ||
// The motivation for this test is to bring awareness and visibility into | ||
// how much size the record occupies. We want to minimize the size to | ||
// increase cache locality in the btree. | ||
require.Equal(t, uintptr(72), unsafe.Sizeof(aliasRecord{})) | ||
} | ||
|
||
func TestAliasRecordByEntryID(t *testing.T) { | ||
assertLess := func(lesser, greater aliasRecord) { | ||
t.Helper() | ||
assert.Truef(t, aliasRecordByEntryID(lesser, greater), "expected E%sP%s<E%sP%s", lesser.EntryID, lesser.Selector, greater.EntryID, greater.Selector) | ||
assert.Falsef(t, aliasRecordByEntryID(greater, lesser), "expected E%sP%s>E%sP%s", greater.EntryID, greater.Selector, lesser.EntryID, lesser.Selector) | ||
} | ||
|
||
records := []aliasRecord{ | ||
aliasRecord{EntryID: "1"}, | ||
aliasRecord{EntryID: "1", Selector: Selector{Type: "1", Value: "1"}}, | ||
aliasRecord{EntryID: "1", Selector: Selector{Type: "1", Value: "2"}}, | ||
aliasRecord{EntryID: "1", Selector: Selector{Type: "2", Value: "1"}}, | ||
aliasRecord{EntryID: "1", Selector: Selector{Type: "2", Value: "2"}}, | ||
aliasRecord{EntryID: "2"}, | ||
aliasRecord{EntryID: "2", Selector: Selector{Type: "1", Value: "1"}}, | ||
aliasRecord{EntryID: "2", Selector: Selector{Type: "1", Value: "2"}}, | ||
aliasRecord{EntryID: "2", Selector: Selector{Type: "2", Value: "1"}}, | ||
aliasRecord{EntryID: "2", Selector: Selector{Type: "2", Value: "2"}}, | ||
} | ||
|
||
lesser := aliasRecord{} | ||
for _, greater := range records { | ||
assertLess(lesser, greater) | ||
lesser = greater | ||
} | ||
} | ||
|
||
func TestAliasRecordBySelector(t *testing.T) { | ||
assertLess := func(lesser, greater aliasRecord) { | ||
t.Helper() | ||
assert.True(t, aliasRecordBySelector(lesser, greater), "expected P%sE%s<P%sE%s", lesser.Selector, lesser.EntryID, greater.Selector, greater.EntryID) | ||
assert.False(t, aliasRecordBySelector(greater, lesser), "expected P%sE%s>P%sE%s", greater.Selector, greater.EntryID, lesser.Selector, lesser.EntryID) | ||
} | ||
|
||
records := []aliasRecord{ | ||
aliasRecord{Selector: Selector{Type: "1", Value: "1"}}, | ||
aliasRecord{Selector: Selector{Type: "1", Value: "1"}, EntryID: "1"}, | ||
aliasRecord{Selector: Selector{Type: "1", Value: "1"}, EntryID: "2"}, | ||
aliasRecord{Selector: Selector{Type: "1", Value: "2"}, EntryID: "1"}, | ||
aliasRecord{Selector: Selector{Type: "1", Value: "2"}, EntryID: "2"}, | ||
aliasRecord{Selector: Selector{Type: "2", Value: "1"}}, | ||
aliasRecord{Selector: Selector{Type: "2", Value: "1"}, EntryID: "1"}, | ||
aliasRecord{Selector: Selector{Type: "2", Value: "1"}, EntryID: "2"}, | ||
aliasRecord{Selector: Selector{Type: "2", Value: "2"}}, | ||
aliasRecord{Selector: Selector{Type: "2", Value: "2"}, EntryID: "1"}, | ||
aliasRecord{Selector: Selector{Type: "2", Value: "2"}, EntryID: "2"}, | ||
} | ||
lesser := aliasRecord{} | ||
for _, greater := range records { | ||
assertLess(lesser, greater) | ||
lesser = greater | ||
} | ||
} |
Oops, something went wrong.