clarified data representation: more uniform treatment of State.Pending vs. State.Running;
authorwenzelm
Sat, 09 Mar 2024 14:52:28 +0100
changeset 79828 5969ead9f900
parent 79827 e38f5f81592d
child 79829 a9da5e99e22f
clarified data representation: more uniform treatment of State.Pending vs. State.Running;
src/Pure/Build/build_process.scala
src/Pure/Build/build_schedule.scala
--- a/src/Pure/Build/build_process.scala	Sat Mar 09 13:06:13 2024 +0100
+++ b/src/Pure/Build/build_process.scala	Sat Mar 09 14:52:28 2024 +0100
@@ -44,10 +44,10 @@
     name: String,
     deps: List[String],
     build_uuid: String
-  ) {
+  ) extends Library.Named {
     def is_ready: Boolean = deps.isEmpty
-    def resolve(dep: String): Task =
-      if (deps.contains(dep)) copy(deps = deps.filterNot(_ == dep)) else this
+    def resolve(dep: String): Option[Task] =
+      if (deps.contains(dep)) Some(copy(deps = deps.filterNot(_ == dep))) else None
   }
 
   sealed case class Job(
@@ -198,7 +198,7 @@
     results: State.Results)     // finished results
 
   object State {
-    type Pending = List[Task]
+    type Pending = Map[String, Task]
     type Running = Map[String, Job]
     type Results = Map[String, Result]
   }
@@ -207,7 +207,7 @@
     serial: Long = 0,
     numa_nodes: List[Int] = Nil,
     sessions: Sessions = Sessions.empty,
-    pending: State.Pending = Nil,
+    pending: State.Pending = Map.empty,
     running: State.Running = Map.empty,
     results: State.Results = Map.empty
   ) {
@@ -217,12 +217,21 @@
       copy(serial = serial + 1)
     }
 
-    def ready: State.Pending = pending.filter(_.is_ready)
-    def next_ready: State.Pending = ready.filter(entry => !is_running(entry.name))
+    def ready: List[Task] = pending.valuesIterator.filter(_.is_ready).toList.sortBy(_.name)
+    def next_ready: List[Task] = ready.filter(entry => !is_running(entry.name))
 
-    def remove_pending(name: String): State =
-      copy(pending = pending.flatMap(
-        entry => if (entry.name == name) None else Some(entry.resolve(name))))
+    def remove_pending(a: String): State =
+      copy(pending =
+        pending.foldLeft(pending) {
+          case (map, (b, task)) =>
+            if (a == b) map - a
+            else {
+              task.resolve(a) match {
+                case None => map
+                case Some(task1) => map + (b -> task1)
+              }
+            }
+        })
 
     def is_running(name: String): Boolean = running.isDefinedAt(name)
 
@@ -565,15 +574,15 @@
       val table = make_table(List(name, deps, build_uuid), name = "pending")
     }
 
-    def read_pending(db: SQL.Database): List[Task] =
+    def read_pending(db: SQL.Database): State.Pending =
       db.execute_query_statement(
-        Pending.table.select(sql = SQL.order_by(List(Pending.name))),
-        List.from[Task],
+        Pending.table.select(),
+        Map.from[String, Task],
         { res =>
           val name = res.string(Pending.name)
           val deps = res.string(Pending.deps)
           val build_uuid = res.string(Pending.build_uuid)
-          Task(name, split_lines(deps), build_uuid)
+          name -> Task(name, split_lines(deps), build_uuid)
         })
 
     def update_pending(
@@ -581,7 +590,9 @@
       pending: State.Pending,
       old_pending: State.Pending
     ): Boolean = {
-      val (delete, insert) = Library.symmetric_difference(old_pending, pending)
+      val pending0 = old_pending.valuesIterator.toList
+      val pending1 = pending.valuesIterator.toList
+      val (delete, insert) = Library.symmetric_difference(pending0, pending1)
 
       if (delete.nonEmpty) {
         db.execute_statement(
@@ -788,7 +799,7 @@
         stamp_worker(db, worker_uuid, serial)
 
         val sessions = state.sessions.pull(read_sessions_domain(db), read_sessions(db, _))
-        val pending = read_pending(db)
+        val pending = pull0(read_pending(db), state.pending)
         val running = pull0(read_running(db), state.running)
         val results = pull1(read_results_domain(db), read_results(db, _), state.results)
 
@@ -966,14 +977,12 @@
 
   protected def init_state(state: Build_Process.State): Build_Process.State = {
     val sessions1 = state.sessions.init(build_context, _database_server, progress = build_progress)
-
-    val old_pending = state.pending.iterator.map(_.name).toSet
-    val new_pending =
-      List.from(
-        for (session <- sessions1.iterator if !old_pending(session.name))
-          yield Build_Process.Task(session.name, session.deps, build_uuid))
-    val pending1 = new_pending ::: state.pending
-
+    val pending1 =
+      sessions1.iterator.foldLeft(state.pending) {
+        case (map, session) =>
+          if (map.isDefinedAt(session.name)) map
+          else map + (session.name -> Build_Process.Task(session.name, session.deps, build_uuid))
+      }
     state.copy(sessions = sessions1, pending = pending1)
   }
 
--- a/src/Pure/Build/build_schedule.scala	Sat Mar 09 13:06:13 2024 +0100
+++ b/src/Pure/Build/build_schedule.scala	Sat Mar 09 14:52:28 2024 +0100
@@ -503,7 +503,6 @@
 
     def update(state: Build_Process.State): Schedule = {
       val start1 = Date.now()
-      val pending = state.pending.map(_.name).toSet
 
       def shift_elapsed(graph: Schedule.Graph, name: String): Schedule.Graph =
         graph.map_node(name, { node =>
@@ -517,7 +516,8 @@
           node.copy(start = starts.max(Date.Ordering))
         })
 
-      val graph0 = state.running.keys.foldLeft(graph.restrict(pending.contains))(shift_elapsed)
+      val graph0 =
+        state.running.keys.foldLeft(graph.restrict(state.pending.isDefinedAt))(shift_elapsed)
       val graph1 = graph0.topological_order.foldLeft(graph0)(shift_starts)
 
       copy(start = start1, graph = graph1)
@@ -1333,7 +1333,8 @@
         Build_Process.Task(session.name, session.deps, build_context.build_uuid)
 
       val build_state =
-        Build_Process.State(sessions = sessions, pending = sessions.iterator.map(task).toList)
+        Build_Process.State(sessions = sessions,
+          pending = sessions.iterator.map(session => (session.name -> task(session))).toMap)
 
       val scheduler = Build_Engine.scheduler(timing_data, build_context)
       def schedule_msg(res: Exn.Result[Schedule]): String =