Limit inheritance policy work to the relevant scope
This commit is contained in:
123
internal/engine/inheritance_policy_index.go
Normal file
123
internal/engine/inheritance_policy_index.go
Normal file
@@ -0,0 +1,123 @@
|
||||
package engine
|
||||
|
||||
// inheritancePolicyIndex borrows immutable policy entries. Semantic path
|
||||
// segments keep mapping keys distinct from sequence indexes. Record-owned
|
||||
// scopes have their own indexes, just as they have their own policy tables.
|
||||
type inheritancePolicyIndex struct {
|
||||
entry *collectionPolicyEntry
|
||||
children map[pathSegment]*inheritancePolicyIndex
|
||||
records map[int]*inheritancePolicyIndex
|
||||
}
|
||||
|
||||
func newInheritancePolicyIndex(scope collectionPolicyScope) *inheritancePolicyIndex {
|
||||
index := &inheritancePolicyIndex{}
|
||||
for _, entry := range scope.collections {
|
||||
index.set(entry)
|
||||
}
|
||||
return index
|
||||
}
|
||||
|
||||
func (index *inheritancePolicyIndex) set(entry collectionPolicyEntry) {
|
||||
node := index
|
||||
for _, segment := range entry.destination.segments {
|
||||
if node.children == nil {
|
||||
node.children = make(map[pathSegment]*inheritancePolicyIndex)
|
||||
}
|
||||
if node.children[segment] == nil {
|
||||
node.children[segment] = &inheritancePolicyIndex{}
|
||||
}
|
||||
node = node.children[segment]
|
||||
}
|
||||
node.entry = &entry
|
||||
node.records = nil
|
||||
for position, owner := range entry.policy.recordOrder {
|
||||
scope := entry.policy.recordPolicies[owner]
|
||||
if len(scope.collections) == 0 {
|
||||
continue
|
||||
}
|
||||
if node.records == nil {
|
||||
node.records = make(map[int]*inheritancePolicyIndex)
|
||||
}
|
||||
node.records[position] = newInheritancePolicyIndex(scope)
|
||||
}
|
||||
}
|
||||
|
||||
// localize copies only policies in the requested scope. Earlier record-owned
|
||||
// policies are considered before direct entries added by destination expansion.
|
||||
func (index *inheritancePolicyIndex) localize(prefix Path) collectionPolicyScope {
|
||||
localized := collectionPolicyScope{}
|
||||
node := index
|
||||
for offset, segment := range prefix.segments {
|
||||
if node == nil {
|
||||
return localized
|
||||
}
|
||||
if segment.kind == pathSegmentIndex {
|
||||
if record := node.records[segment.index]; record != nil {
|
||||
remainder := Path{segments: prefix.segments[offset+1:]}
|
||||
for _, entry := range record.localize(remainder).collections {
|
||||
localized.set(entry.destination, entry.policy)
|
||||
}
|
||||
}
|
||||
}
|
||||
node = node.children[segment]
|
||||
}
|
||||
var collect func(*inheritancePolicyIndex)
|
||||
collect = func(node *inheritancePolicyIndex) {
|
||||
if node == nil {
|
||||
return
|
||||
}
|
||||
if node.entry != nil {
|
||||
relative, _ := relativeHistoryPath(prefix, node.entry.destination)
|
||||
localized.set(relative, cloneCollectionPolicyForInheritance(node.entry.policy))
|
||||
}
|
||||
for _, child := range node.children {
|
||||
collect(child)
|
||||
}
|
||||
}
|
||||
collect(node)
|
||||
return localized
|
||||
}
|
||||
|
||||
func (index *inheritancePolicyIndex) absoluteScope(prefix Path) collectionPolicyScope {
|
||||
scope := collectionPolicyScope{}
|
||||
for _, entry := range index.localize(prefix).collections {
|
||||
scope.set(appendDestination(prefix, entry.destination), entry.policy)
|
||||
}
|
||||
return scope
|
||||
}
|
||||
|
||||
// replace updates the walker's owned table and its borrowed index together.
|
||||
// Retirement visits only direct entries below the changed destination.
|
||||
func (index *inheritancePolicyIndex) replace(scope *collectionPolicyScope, prefix Path, replacement collectionPolicyScope) {
|
||||
node := index
|
||||
var parent *inheritancePolicyIndex
|
||||
var last pathSegment
|
||||
for _, segment := range prefix.segments {
|
||||
if node == nil {
|
||||
break
|
||||
}
|
||||
parent, last, node = node, segment, node.children[segment]
|
||||
}
|
||||
var remove func(*inheritancePolicyIndex)
|
||||
remove = func(node *inheritancePolicyIndex) {
|
||||
if node == nil {
|
||||
return
|
||||
}
|
||||
if node.entry != nil {
|
||||
delete(scope.collections, node.entry.destination.String())
|
||||
}
|
||||
for _, child := range node.children {
|
||||
remove(child)
|
||||
}
|
||||
}
|
||||
remove(node)
|
||||
if parent == nil {
|
||||
*index = inheritancePolicyIndex{}
|
||||
} else {
|
||||
delete(parent.children, last)
|
||||
}
|
||||
for _, entry := range replacement.collections {
|
||||
scope.set(entry.destination, entry.policy)
|
||||
index.set(scope.collections[entry.destination.String()])
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user