// Package limits provides the engine's topology ceilings and reusable work // accounting primitives. It deliberately has no dependency on graph, layout, // or routing types so every layout domain can consume the same limits without // introducing package cycles.
package limits import ( ) const ( // MaxEngineNodes is the largest node count the engine processes in one attempt. MaxEngineNodes = 10_000 // MaxEngineEdges is the largest edge count the engine processes in one attempt. MaxEngineEdges = 50_000 // MaxEngineRoutePoints bounds aggregate route storage throughout the engine. MaxEngineRoutePoints = 1_000_000 // MaxEngineTreeDepth bounds recursive topology throughout the engine. MaxEngineTreeDepth = 256 // MaxGraphSize is the maximum supported width or height at a pipeline stage // boundary. MaxGraphSize = 30_000 contextCheckStride = 64 cancellableContextCheckStride = 1024 workUnitsPerEntity = 1_024 // MaxEngineWorkUnits is the default aggregate work budget for a graph. MaxEngineWorkUnits = int64(MaxEngineNodes+MaxEngineEdges) * workUnitsPerEntity // MaxTransactionWorkUnits allows a complete layout transaction to compare // many nearby placements without resetting the ordinary engine budget for // every candidate. MaxTransactionWorkUnits int64 = 1_000_000_000 // MaxTransactionOverlapReferences bounds retained existing-overlap // references. Exceptions are retained in both directions because hot // placement checks key by the moved node. MaxTransactionOverlapReferences int64 = 4_000_000 // MaxBinPackWorkUnits spans the complete recursive bin-packing operation, // including speculative transactions and route scans. MaxBinPackWorkUnits int64 = 1_000_000_000 // MaxPlaceTreesWorkUnits is calibrated for the superlinear candidate and // obstacle work performed by tree placement. MaxPlaceTreesWorkUnits int64 = 68_000_000 // MaxLabelPlacementWorkUnits bounds the quadratic overlap and candidate // search performed while positioning labels and icons. MaxLabelPlacementWorkUnits int64 = 50_000_000 ) // WorkGuard accounts a complete operation's signed work units and polls its // context at a fixed stride. The limit is an explicit non-negative ceiling; // zero permits cancellation checks but no charged work. type WorkGuard struct { ctx context.Context done <-chan struct{} location string used int64 limit int64 } // NewWorkGuard constructs a work guard and observes cancellation before any // operation work begins. func ( context.Context, string, int64) (*WorkGuard, error) { if == nil { return nil, fmt.Errorf("TALA %s requires a context", ) } if < 0 { return nil, fmt.Errorf("TALA %s work limit must not be negative", ) } := &WorkGuard{ ctx: , done: .Done(), location: , limit: , } if := .Finish(); != nil { return nil, } return , nil } // Step charges one work unit. func ( *WorkGuard) () error { .used++ if .used > .limit { return fmt.Errorf( "TALA %s work exceeds limit %d", .location, .limit, ) } return .checkAtStride() } // Add records multiple work units as one accounting operation. It enforces // Step's work limit and polls cancellation when the accepted charge reaches or // crosses a Step polling boundary. On a positive-limit overflow, Used reports // the first rejected unit even when a crossed boundary observes cancellation. func ( *WorkGuard) ( int64) error { if < 0 { return fmt.Errorf("TALA %s work charge must not be negative", .location) } if > .limit || .used > .limit- { := .used .used = .limit + 1 := .pollingStride() if <= .limit && / != .limit/ { if := .Check(); != nil { return } } return fmt.Errorf("TALA %s work exceeds limit %d", .location, .limit) } := .used .used += return .checkAfterAdd() } func ( *WorkGuard) ( int64) error { := .pollingStride() // Add(0) polls an exact boundary; positive charges also poll when their // interval crosses one. if .used% != 0 && / == .used/ { return nil } return .Check() } func ( *WorkGuard) () error { := .pollingStride() if .used% != 0 { return nil } return .Check() } func ( *WorkGuard) () int64 { if .done == nil { // Contexts without Done need the shorter stride because cancellation is // observable only by polling Err. return contextCheckStride } return cancellableContextCheckStride } // Check observes cancellation immediately. Step and Add use a bounded stride // in hot loops, while callers use Check at explicit cancellation boundaries. func ( *WorkGuard) () error { if := cachedContextErr(.ctx, .done); != nil { return fmt.Errorf("%s: %w", .location, ) } return nil } // Finish observes cancellation regardless of the current work count. func ( *WorkGuard) () error { return .Check() } // SetLimit changes the ceiling without resetting already consumed work. func ( *WorkGuard) ( int64) { .limit = } // Used returns the number of charged or first-rejected work units. func ( *WorkGuard) () int64 { return .used } // cachedContextErr avoids repeatedly traversing context value wrappers in hot // guarded loops. Standard cancellable contexts close Done before Err becomes // observable. Context implementations without a Done channel retain per-call // Err polling, which also preserves synthetic cancellation contexts. func cachedContextErr( context.Context, <-chan struct{}) error { if == nil { return .Err() } select { case <-: return .Err() default: return nil } }