Share declaring import assembly
This commit is contained in:
@@ -54,6 +54,8 @@ filesystems. [Native link resolver](../../internal/engine/filesystem_links.go#L2
|
|||||||
|
|
||||||
## Finding 2 — Contextless imports duplicate root contribution assembly
|
## Finding 2 — Contextless imports duplicate root contribution assembly
|
||||||
|
|
||||||
|
**Status** — Complete. Bound and contextless imports share root charging, placement, and sequence-item scope assembly. The full test suite passed.
|
||||||
|
|
||||||
**Priority P3.** Stage 4 calls for sharing the root contribution assembly
|
**Priority P3.** Stage 4 calls for sharing the root contribution assembly
|
||||||
and accounting. The new contextless path has its own source charging,
|
and accounting. The new contextless path has its own source charging,
|
||||||
mapping placement, wrapper charging, pending sequence-item scope
|
mapping placement, wrapper charging, pending sequence-item scope
|
||||||
|
|||||||
@@ -48,36 +48,22 @@ func acquireContextlessInput(input assembledInput, request inputAcquisitionReque
|
|||||||
}
|
}
|
||||||
return input, diagnostics
|
return input, diagnostics
|
||||||
}
|
}
|
||||||
key := importKeyForMainSource(parsed.source)
|
accounting, limits := input.accounting, policy.importLimits
|
||||||
info := cloneSourceInfo(*parsed.source)
|
if diagnostic := chargeDeclaringImport(parsed, accounting, limits); diagnostic != nil {
|
||||||
accounting := input.accounting
|
return input, []Diagnostic{*diagnostic}
|
||||||
accounting.sources++
|
|
||||||
accounting.bytes += parsed.bytes
|
|
||||||
accounting.nodes += countInputNodes(parsed.document)
|
|
||||||
limits := policy.importLimits
|
|
||||||
if accounting.sources > limits.sources || accounting.bytes > limits.bytes || accounting.nodes > limits.nodes {
|
|
||||||
return input, []Diagnostic{importDiagnostic(CodeImportLimitExceeded, "configuration exceeds the aggregate input limit", nil)}
|
|
||||||
}
|
}
|
||||||
contribution := acquiredContribution{source: info, payload: body, identity: key, role: importRoleMain, scopeOwner: key, processing: processing, sequenceDeclarations: sequences}
|
key := importKeyForMainSource(parsed.source)
|
||||||
var scope acquisitionScope
|
root := acquiredContribution{
|
||||||
if request.input.placementMode == PlacementModeSequenceItem {
|
source: cloneSourceInfo(*parsed.source), payload: body, identity: key,
|
||||||
contribution.document = body
|
role: importRoleMain, scopeOwner: key, processing: processing, sequenceDeclarations: sequences,
|
||||||
local := acquisitionScope{owner: key, contributions: []acquiredContribution{contribution}}
|
}
|
||||||
scope = acquisitionScope{owner: key, destination: destination.clone(), contributions: []acquiredContribution{{source: info, payload: body, identity: key, role: importRoleMain, scopeOwner: key, destination: destination.clone(), processing: processing, sequenceDeclarations: sequences, pendingItem: &local}}}
|
scope, diagnostic := prepareDeclaringImportScope(root, accounting, limits)
|
||||||
if diagnostic := reservePendingItemPlacements(&scope, limits, accounting); diagnostic != nil {
|
if diagnostic != nil {
|
||||||
return input, []Diagnostic{*diagnostic}
|
return input, []Diagnostic{*diagnostic}
|
||||||
}
|
}
|
||||||
} else {
|
scope, diagnostic = finalizeDeclaringImportScope(scope, root, accounting, limits)
|
||||||
_, placed, err := placeDocument(body, destination, body.Location, maxDocumentDepth, maxDocumentNodes)
|
if diagnostic != nil {
|
||||||
if err != nil {
|
return input, []Diagnostic{*diagnostic}
|
||||||
return input, []Diagnostic{sourceDiagnostic(CodeSourceLimitExceeded, info.ID, "configuration exceeds the source depth or node limit after destination placement")}
|
|
||||||
}
|
|
||||||
accounting.nodes += destinationWrapperNodeCount(destination)
|
|
||||||
if accounting.nodes > limits.nodes {
|
|
||||||
return input, []Diagnostic{importDiagnostic(CodeImportLimitExceeded, "configuration exceeds the aggregate node limit", nil)}
|
|
||||||
}
|
|
||||||
contribution.document, contribution.destination = placed, destination.clone()
|
|
||||||
scope = acquisitionScope{owner: key, destination: destination.clone(), contributions: []acquiredContribution{contribution}}
|
|
||||||
}
|
}
|
||||||
input.document = body
|
input.document = body
|
||||||
input.composition = &composedDocument{acquisition: []acquisitionScope{scope}, importGraph: newImportInclusionGraph(), inputBytes: accounting.bytes, inputNodes: accounting.nodes}
|
input.composition = &composedDocument{acquisition: []acquisitionScope{scope}, importGraph: newImportInclusionGraph(), inputBytes: accounting.bytes, inputNodes: accounting.nodes}
|
||||||
|
|||||||
@@ -112,9 +112,6 @@ func acquireImportedWithAccess(request importAcquisitionRequest, policy *acquisi
|
|||||||
_ = closeAccess()
|
_ = closeAccess()
|
||||||
return nil, sourceInfos(main.source), []Diagnostic{importRepeatedDiagnostic(Location{SourceID: main.source.ID}, previous, importRoute{})}
|
return nil, sourceInfos(main.source), []Diagnostic{importRepeatedDiagnostic(Location{SourceID: main.source.ID}, previous, importRoute{})}
|
||||||
}
|
}
|
||||||
accounting.sources++
|
|
||||||
accounting.bytes += main.bytes
|
|
||||||
accounting.nodes += countInputNodes(main.document)
|
|
||||||
directiveContext := request.input.directiveContext
|
directiveContext := request.input.directiveContext
|
||||||
if directiveContext == 0 {
|
if directiveContext == 0 {
|
||||||
directiveContext = rootDirectiveContextImportsOnly
|
directiveContext = rootDirectiveContextImportsOnly
|
||||||
@@ -125,7 +122,6 @@ func acquireImportedWithAccess(request importAcquisitionRequest, policy *acquisi
|
|||||||
request.input.directiveContext = directiveContext
|
request.input.directiveContext = directiveContext
|
||||||
state := importTraversal{
|
state := importTraversal{
|
||||||
access: access, request: request, policy: policy, state: loadState, tier: tier,
|
access: access, request: request, policy: policy, state: loadState, tier: tier,
|
||||||
scope: acquisitionScope{owner: mainNodeKey, destination: destination.clone()},
|
|
||||||
sources: []SourceInfo{mainInfo},
|
sources: []SourceInfo{mainInfo},
|
||||||
active: make(map[resourceIdentity]int),
|
active: make(map[resourceIdentity]int),
|
||||||
importGraph: newImportInclusionGraph(),
|
importGraph: newImportInclusionGraph(),
|
||||||
@@ -134,11 +130,10 @@ func acquireImportedWithAccess(request importAcquisitionRequest, policy *acquisi
|
|||||||
state.itemScope = true
|
state.itemScope = true
|
||||||
state.itemPrefix = destination.clone()
|
state.itemPrefix = destination.clone()
|
||||||
state.itemFallback = destination.clone()
|
state.itemFallback = destination.clone()
|
||||||
state.scope.destination = Path{}
|
|
||||||
state.sources[0] = cloneSourceInfo(mainInfo)
|
state.sources[0] = cloneSourceInfo(mainInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
if diagnostic := state.checkInitialLimits(); diagnostic != nil {
|
if diagnostic := chargeDeclaringImport(main, accounting, limits); diagnostic != nil {
|
||||||
_ = closeAccess()
|
_ = closeAccess()
|
||||||
return nil, cloneSourceInfos(state.sources), []Diagnostic{*diagnostic}
|
return nil, cloneSourceInfos(state.sources), []Diagnostic{*diagnostic}
|
||||||
}
|
}
|
||||||
@@ -164,31 +159,18 @@ func acquireImportedWithAccess(request importAcquisitionRequest, policy *acquisi
|
|||||||
} else {
|
} else {
|
||||||
body, declarations, diagnostics = splitImportDirectives(main.document)
|
body, declarations, diagnostics = splitImportDirectives(main.document)
|
||||||
}
|
}
|
||||||
|
root := acquiredContribution{
|
||||||
|
source: cloneSourceInfo(mainInfo), payload: body, identity: mainNodeKey,
|
||||||
|
role: importRoleMain, scopeOwner: mainNodeKey, processing: processing,
|
||||||
|
sequenceDeclarations: sequenceDeclarations,
|
||||||
|
}
|
||||||
if len(diagnostics) == 0 {
|
if len(diagnostics) == 0 {
|
||||||
if mainIsItem {
|
scope, diagnostic := prepareDeclaringImportScope(root, accounting, limits)
|
||||||
state.scope.contributions = append(state.scope.contributions, acquiredContribution{
|
if diagnostic != nil {
|
||||||
source: cloneSourceInfo(mainInfo), identity: mainNodeKey, role: importRoleMain,
|
diagnostics = []Diagnostic{*diagnostic}
|
||||||
scopeOwner: mainNodeKey, payload: body, document: body, processing: processing,
|
|
||||||
sequenceDeclarations: cloneSequenceDeclarations(sequenceDeclarations),
|
|
||||||
})
|
|
||||||
diagnostics = state.walkDeclarations(basePath, declarations, 0, Path{}, 0)
|
|
||||||
} else {
|
} else {
|
||||||
_, placed, err := placeDocument(body, destination, body.Location, maxDocumentDepth, maxDocumentNodes)
|
state.scope = scope
|
||||||
placementNodes := destinationWrapperNodeCount(destination)
|
diagnostics = state.walkDeclarations(basePath, declarations, 0, scope.destination, 0)
|
||||||
if err != nil {
|
|
||||||
diagnostics = []Diagnostic{sourceDiagnostic(CodeSourceLimitExceeded, main.source.ID, "configuration exceeds the source depth or node limit after destination placement")}
|
|
||||||
} else if accounting.nodes+placementNodes > limits.nodes {
|
|
||||||
diagnostics = []Diagnostic{importDiagnostic(CodeImportLimitExceeded, "configuration exceeds the aggregate node limit", nil)}
|
|
||||||
} else {
|
|
||||||
accounting.nodes += placementNodes
|
|
||||||
state.scope.contributions = append(state.scope.contributions, acquiredContribution{
|
|
||||||
source: cloneSourceInfo(mainInfo), payload: body, document: placed,
|
|
||||||
identity: mainNodeKey, role: importRoleMain, scopeOwner: mainNodeKey,
|
|
||||||
destination: destination.clone(), processing: processing,
|
|
||||||
sequenceDeclarations: cloneSequenceDeclarations(sequenceDeclarations),
|
|
||||||
})
|
|
||||||
diagnostics = state.walkDeclarations(basePath, declarations, 0, destination, 0)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(diagnostics) == 0 {
|
if len(diagnostics) == 0 {
|
||||||
@@ -205,19 +187,8 @@ func acquireImportedWithAccess(request importAcquisitionRequest, policy *acquisi
|
|||||||
if closeErr != nil {
|
if closeErr != nil {
|
||||||
return nil, cloneSourceInfos(state.sources), []Diagnostic{importDiagnostic(CodeImportRead, "configuration root could not be closed", nil)}
|
return nil, cloneSourceInfos(state.sources), []Diagnostic{importDiagnostic(CodeImportRead, "configuration root could not be closed", nil)}
|
||||||
}
|
}
|
||||||
acquisition := state.scope
|
acquisition, diagnostic := finalizeDeclaringImportScope(state.scope, root, accounting, limits)
|
||||||
if mainIsItem {
|
if diagnostic != nil {
|
||||||
localScope := state.scope
|
|
||||||
acquisition = acquisitionScope{
|
|
||||||
owner: mainNodeKey, destination: destination.clone(),
|
|
||||||
contributions: []acquiredContribution{{
|
|
||||||
source: cloneSourceInfo(mainInfo), payload: body, identity: mainNodeKey,
|
|
||||||
role: importRoleMain, scopeOwner: mainNodeKey, destination: destination.clone(),
|
|
||||||
processing: processing, sequenceDeclarations: cloneSequenceDeclarations(sequenceDeclarations), pendingItem: &localScope,
|
|
||||||
}},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if diagnostic := reservePendingItemPlacements(&acquisition, limits, accounting); diagnostic != nil {
|
|
||||||
return nil, cloneSourceInfos(state.sources), []Diagnostic{*diagnostic}
|
return nil, cloneSourceInfos(state.sources), []Diagnostic{*diagnostic}
|
||||||
}
|
}
|
||||||
return &composedDocument{
|
return &composedDocument{
|
||||||
@@ -226,22 +197,6 @@ func acquireImportedWithAccess(request importAcquisitionRequest, policy *acquisi
|
|||||||
}, cloneSourceInfos(state.sources), nil
|
}, cloneSourceInfos(state.sources), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *importTraversal) checkInitialLimits() *Diagnostic {
|
|
||||||
if s.state.accounting.sources > s.policy.importLimits.sources {
|
|
||||||
value := importDiagnostic(CodeImportLimitExceeded, "configuration exceeds the source-count limit", nil)
|
|
||||||
return &value
|
|
||||||
}
|
|
||||||
if s.state.accounting.bytes > s.policy.importLimits.bytes {
|
|
||||||
value := importDiagnostic(CodeImportLimitExceeded, "configuration exceeds the aggregate byte limit", nil)
|
|
||||||
return &value
|
|
||||||
}
|
|
||||||
if s.state.accounting.nodes > s.policy.importLimits.nodes {
|
|
||||||
value := importDiagnostic(CodeImportLimitExceeded, "configuration exceeds the aggregate node limit", nil)
|
|
||||||
return &value
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func prepareImportDeclarations(declarations []importDeclarationSpec, defaults ImportDefaults, parentDestination Path) ([]resolvedImportPolicy, []Diagnostic) {
|
func prepareImportDeclarations(declarations []importDeclarationSpec, defaults ImportDefaults, parentDestination Path) ([]resolvedImportPolicy, []Diagnostic) {
|
||||||
policies := make([]resolvedImportPolicy, len(declarations))
|
policies := make([]resolvedImportPolicy, len(declarations))
|
||||||
for index, spec := range declarations {
|
for index, spec := range declarations {
|
||||||
|
|||||||
@@ -285,3 +285,58 @@ func importedVersionClaim(documents []*document.Node, scope acquisitionScope, co
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The declaring payload contributes once even when there are no admitted imports.
|
||||||
|
func chargeDeclaringImport(parsed parsedSource, accounting *importAccounting, limits importLimits) *Diagnostic {
|
||||||
|
accounting.sources++
|
||||||
|
accounting.bytes += parsed.bytes
|
||||||
|
accounting.nodes += countInputNodes(parsed.document)
|
||||||
|
if accounting.sources > limits.sources {
|
||||||
|
value := importDiagnostic(CodeImportLimitExceeded, "configuration exceeds the source-count limit", nil)
|
||||||
|
return &value
|
||||||
|
}
|
||||||
|
if accounting.bytes > limits.bytes {
|
||||||
|
value := importDiagnostic(CodeImportLimitExceeded, "configuration exceeds the aggregate byte limit", nil)
|
||||||
|
return &value
|
||||||
|
}
|
||||||
|
if accounting.nodes > limits.nodes {
|
||||||
|
value := importDiagnostic(CodeImportLimitExceeded, "configuration exceeds the aggregate node limit", nil)
|
||||||
|
return &value
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func prepareDeclaringImportScope(root acquiredContribution, accounting *importAccounting, limits importLimits) (acquisitionScope, *Diagnostic) {
|
||||||
|
scope := acquisitionScope{owner: root.identity}
|
||||||
|
if root.source.placementMode == PlacementModeSequenceItem {
|
||||||
|
root.document = root.payload
|
||||||
|
} else {
|
||||||
|
destination := root.source.Destination
|
||||||
|
_, placed, err := placeDocument(root.payload, destination, root.payload.Location, maxDocumentDepth, maxDocumentNodes)
|
||||||
|
if err != nil {
|
||||||
|
diagnostic := sourceDiagnostic(CodeSourceLimitExceeded, root.source.ID, "configuration exceeds the source depth or node limit after destination placement")
|
||||||
|
return acquisitionScope{}, &diagnostic
|
||||||
|
}
|
||||||
|
placementNodes := destinationWrapperNodeCount(destination)
|
||||||
|
if accounting.nodes+placementNodes > limits.nodes {
|
||||||
|
diagnostic := importDiagnostic(CodeImportLimitExceeded, "configuration exceeds the aggregate node limit", nil)
|
||||||
|
return acquisitionScope{}, &diagnostic
|
||||||
|
}
|
||||||
|
accounting.nodes += placementNodes
|
||||||
|
root.document, root.destination = placed, destination.clone()
|
||||||
|
scope.destination = destination.clone()
|
||||||
|
}
|
||||||
|
scope.contributions = []acquiredContribution{root}
|
||||||
|
return scope, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func finalizeDeclaringImportScope(scope acquisitionScope, root acquiredContribution, accounting *importAccounting, limits importLimits) (acquisitionScope, *Diagnostic) {
|
||||||
|
if root.source.placementMode == PlacementModeSequenceItem {
|
||||||
|
root.destination = root.source.Destination.clone()
|
||||||
|
localScope := scope
|
||||||
|
root.pendingItem = &localScope
|
||||||
|
scope = acquisitionScope{owner: root.identity, destination: root.destination.clone(), contributions: []acquiredContribution{root}}
|
||||||
|
}
|
||||||
|
diagnostic := reservePendingItemPlacements(&scope, limits, accounting)
|
||||||
|
return scope, diagnostic
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user