124 lines
3.7 KiB
Go
124 lines
3.7 KiB
Go
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()])
|
|
}
|
|
}
|