
mb.pie.runtime.exec.TopDown.kt Maven / Gradle / Ivy
The newest version!
package mb.pie.runtime.exec
import mb.pie.api.*
import mb.pie.api.exec.*
import mb.pie.api.fs.stamp.FileSystemStamper
import mb.pie.api.stamp.OutputStamper
class TopDownExecutorImpl constructor(
private val taskDefs: TaskDefs,
private val resourceSystems: ResourceSystems,
private val store: Store,
private val share: Share,
private val defaultOutputStamper: OutputStamper,
private val defaultRequireFileSystemStamper: FileSystemStamper,
private val defaultProvideFileSystemStamper: FileSystemStamper,
private val layerFactory: (Logger) -> Layer,
private val logger: Logger,
private val executorLoggerFactory: (Logger) -> ExecutorLogger
) : TopDownExecutor {
override fun newSession(): TopDownSession {
return TopDownSessionImpl(taskDefs, resourceSystems, store, share, defaultOutputStamper, defaultRequireFileSystemStamper, defaultProvideFileSystemStamper, layerFactory(logger), logger, executorLoggerFactory(logger))
}
}
open class TopDownSessionImpl(
taskDefs: TaskDefs,
resourceSystems: ResourceSystems,
private val store: Store,
share: Share,
defaultOutputStamper: OutputStamper,
defaultRequireFileSystemStamper: FileSystemStamper,
defaultProvideFileSystemStamper: FileSystemStamper,
private val layer: Layer,
logger: Logger,
private val executorLogger: ExecutorLogger
) : TopDownSession, RequireTask {
private val visited = mutableMapOf>()
private val executor = TaskExecutor(taskDefs, resourceSystems, visited, store, share, defaultOutputStamper, defaultRequireFileSystemStamper, defaultProvideFileSystemStamper, layer, logger, executorLogger, null)
private val requireShared = RequireShared(taskDefs, resourceSystems, visited, store, executorLogger)
override fun requireInitial(task: Task): O {
return requireInitial(task, NullCancelled())
}
override fun requireInitial(task: Task, cancel: Cancelled): O {
try {
val key = task.key()
executorLogger.requireTopDownInitialStart(key, task)
val output = require(key, task, cancel)
executorLogger.requireTopDownInitialEnd(key, task, output)
return output
} finally {
store.sync()
}
}
override fun require(key: TaskKey, task: Task, cancel: Cancelled): O {
cancel.throwIfCancelled()
Stats.addRequires()
layer.requireTopDownStart(key, task.input)
executorLogger.requireTopDownStart(key, task)
try {
val (data, wasExecuted) = getData(key, task, cancel)
val output = data.output
if(!wasExecuted) {
// Validate well-formedness of the dependency graph.
store.readTxn().use { layer.validatePostWrite(key, data, it) }
// Mark task as visited.
visited[key] = data
}
executorLogger.requireTopDownEnd(key, task, output)
return output
} finally {
layer.requireTopDownEnd(key)
}
}
data class DataW(val data: TaskData, val executed: Boolean) {
constructor(data: TaskData) : this(data, true)
}
/**
* Get data for given task/key, either by getting existing data or through execution.
*/
private fun getData(key: TaskKey, task: Task, cancel: Cancelled): DataW {
// Check if task was already visited this execution. Return immediately if so.
val visitedData = requireShared.dataFromVisited(key)
if(visitedData != null) {
return DataW(visitedData.cast(), false)
}
// Check if data is stored for task. Execute if not.
val storedData = requireShared.dataFromStore(key)
if(storedData == null) {
return DataW(exec(key, task, NoData(), cancel))
}
// Check consistency of task.
val existingData = storedData.cast()
val (input, output, taskRequires, resourceRequires, resourceProvides) = existingData
// Internal consistency: input changes.
with(requireShared.checkInput(input, task)) {
if(this != null) {
return DataW(exec(key, task, this, cancel))
}
}
// Internal consistency: transient output consistency.
with(requireShared.checkOutputConsistency(output)) {
if(this != null) {
return DataW(exec(key, task, this, cancel))
}
}
// Internal consistency: resoruce requires.
for(fileReq in resourceRequires) {
with(requireShared.checkResourceRequire(key, task, fileReq)) {
if(this != null) {
return DataW(exec(key, task, this, cancel))
}
}
}
// Internal consistency: resource provides.
for(fileGen in resourceProvides) {
with(requireShared.checkResourceProvide(key, task, fileGen)) {
if(this != null) {
return DataW(exec(key, task, this, cancel))
}
}
}
// Total consistency: call requirements.
for(taskReq in taskRequires) {
with(requireShared.checkTaskRequire(key, task, taskReq, this, cancel)) {
if(this != null) {
return DataW(exec(key, task, this, cancel))
}
}
}
// Task is consistent.
return DataW(existingData, false)
}
open fun exec(key: TaskKey, task: Task, reason: ExecReason, cancel: Cancelled): TaskData {
return executor.exec(key, task, reason, this, cancel)
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy