src/Pure/Thy/thy_resources.scala
changeset 68936 90c08c7bab9c
parent 68935 7a420bee1eea
child 68943 e564605d4cac
equal deleted inserted replaced
68935:7a420bee1eea 68936:90c08c7bab9c
     6 
     6 
     7 package isabelle
     7 package isabelle
     8 
     8 
     9 
     9 
    10 import java.io.{File => JFile}
    10 import java.io.{File => JFile}
       
    11 
       
    12 import scala.annotation.tailrec
    11 
    13 
    12 
    14 
    13 object Thy_Resources
    15 object Thy_Resources
    14 {
    16 {
    15   /* PIDE session */
    17   /* PIDE session */
    76       (nodes.iterator ++ nodes_committed.iterator).forall({ case (_, st) => st.ok })
    78       (nodes.iterator ++ nodes_committed.iterator).forall({ case (_, st) => st.ok })
    77   }
    79   }
    78 
    80 
    79   val default_check_delay: Double = 0.5
    81   val default_check_delay: Double = 0.5
    80   val default_nodes_status_delay: Double = -1.0
    82   val default_nodes_status_delay: Double = -1.0
       
    83   val default_commit_clean_delay: Double = 60.0
    81 
    84 
    82 
    85 
    83   class Session private[Thy_Resources](
    86   class Session private[Thy_Resources](
    84     session_name: String,
    87     session_name: String,
    85     session_options: Options,
    88     session_options: Options,
   133           } yield name
   136           } yield name
   134         (initialized, copy(already_initialized = already_initialized ++ initialized))
   137         (initialized, copy(already_initialized = already_initialized ++ initialized))
   135       }
   138       }
   136 
   139 
   137       def cancel_result { result.cancel }
   140       def cancel_result { result.cancel }
       
   141       def finished_result: Boolean = result.is_finished
   138       def await_result { result.join_result }
   142       def await_result { result.join_result }
   139       def join_result: Theories_Result = result.join
   143       def join_result: Theories_Result = result.join
   140       def check_result(
   144       def check_result(
   141           state: Document.State,
   145           state: Document.State,
   142           version: Document.Version,
   146           version: Document.Version,
   195       watchdog_timeout: Time = Time.zero,
   199       watchdog_timeout: Time = Time.zero,
   196       nodes_status_delay: Time = Time.seconds(default_nodes_status_delay),
   200       nodes_status_delay: Time = Time.seconds(default_nodes_status_delay),
   197       id: UUID = UUID(),
   201       id: UUID = UUID(),
   198       // commit: must not block, must not fail
   202       // commit: must not block, must not fail
   199       commit: Option[(Document.Snapshot, Document_Status.Node_Status) => Unit] = None,
   203       commit: Option[(Document.Snapshot, Document_Status.Node_Status) => Unit] = None,
       
   204       commit_clean_delay: Time = Time.seconds(default_commit_clean_delay),
   200       progress: Progress = No_Progress): Theories_Result =
   205       progress: Progress = No_Progress): Theories_Result =
   201     {
   206     {
   202       val dep_theories =
   207       val dep_theories =
   203       {
   208       {
   204         val import_names =
   209         val import_names =
   239         val delay_nodes_status =
   244         val delay_nodes_status =
   240           Standard_Thread.delay_first(nodes_status_delay max Time.zero) {
   245           Standard_Thread.delay_first(nodes_status_delay max Time.zero) {
   241             progress.nodes_status(use_theories_state.value.nodes_status)
   246             progress.nodes_status(use_theories_state.value.nodes_status)
   242           }
   247           }
   243 
   248 
       
   249         val delay_commit_clean =
       
   250           Standard_Thread.delay_first(commit_clean_delay max Time.zero) {
       
   251             val clean = use_theories_state.value.already_committed.keySet
       
   252             resources.clean_theories(session, id, clean)
       
   253           }
       
   254 
   244         Session.Consumer[Session.Commands_Changed](getClass.getName) {
   255         Session.Consumer[Session.Commands_Changed](getClass.getName) {
   245           case changed =>
   256           case changed =>
   246             if (changed.nodes.exists(dep_theories_set)) {
   257             if (changed.nodes.exists(dep_theories_set)) {
   247               val snapshot = session.snapshot()
   258               val snapshot = session.snapshot()
   248               val state = snapshot.state
   259               val state = snapshot.state
   289 
   300 
   290               for ((theory, percentage) <- theory_percentages)
   301               for ((theory, percentage) <- theory_percentages)
   291                 progress.theory_percentage("", theory, percentage)
   302                 progress.theory_percentage("", theory, percentage)
   292 
   303 
   293               check_result()
   304               check_result()
       
   305 
       
   306               if (commit.isDefined && commit_clean_delay >= Time.zero) {
       
   307                 if (use_theories_state.value.finished_result)
       
   308                   delay_commit_clean.revoke
       
   309                 else delay_commit_clean.invoke
       
   310               }
   294             }
   311             }
   295         }
   312         }
   296       }
   313       }
   297 
   314 
   298       try {
   315       try {
   361 
   378 
   362   sealed case class State(
   379   sealed case class State(
   363     required: Multi_Map[Document.Node.Name, UUID] = Multi_Map.empty,
   380     required: Multi_Map[Document.Node.Name, UUID] = Multi_Map.empty,
   364     theories: Map[Document.Node.Name, Theory] = Map.empty)
   381     theories: Map[Document.Node.Name, Theory] = Map.empty)
   365   {
   382   {
       
   383     lazy val theory_graph: Graph[Document.Node.Name, Unit] =
       
   384     {
       
   385       val entries =
       
   386         for ((name, theory) <- theories.toList)
       
   387         yield ((name, ()), theory.node_header.imports.map(_._1).filter(theories.isDefinedAt(_)))
       
   388       Graph.make(entries, symmetric = true)(Document.Node.Name.Ordering)
       
   389     }
       
   390 
   366     def is_required(name: Document.Node.Name): Boolean = required.isDefinedAt(name)
   391     def is_required(name: Document.Node.Name): Boolean = required.isDefinedAt(name)
   367 
   392 
   368     def insert_required(id: UUID, names: List[Document.Node.Name]): State =
   393     def insert_required(id: UUID, names: List[Document.Node.Name]): State =
   369       copy(required = (required /: names)(_.insert(_, id)))
   394       copy(required = (required /: names)(_.insert(_, id)))
   370 
   395 
   384     {
   409     {
   385       require(remove.forall(name => !is_required(name)))
   410       require(remove.forall(name => !is_required(name)))
   386       copy(theories = theories -- remove)
   411       copy(theories = theories -- remove)
   387     }
   412     }
   388 
   413 
   389     lazy val theory_graph: Graph[Document.Node.Name, Unit] =
   414     def unload_theories(session: Session, id: UUID, dep_theories: List[Document.Node.Name]): State =
   390     {
   415     {
   391       val entries =
   416       val st1 = remove_required(id, dep_theories)
   392         for ((name, theory) <- theories.toList)
   417       val theory_edits =
   393         yield ((name, ()), theory.node_header.imports.map(_._1).filter(theories.isDefinedAt(_)))
   418         for {
   394       Graph.make(entries, symmetric = true)(Document.Node.Name.Ordering)
   419           node_name <- dep_theories
       
   420           theory <- st1.theories.get(node_name)
       
   421         }
       
   422         yield {
       
   423           val theory1 = theory.required(st1.is_required(node_name))
       
   424           val edits = theory1.node_edits(Some(theory))
       
   425           (edits, (node_name, theory1))
       
   426         }
       
   427       session.update(Document.Blobs.empty, theory_edits.flatMap(_._1))
       
   428       st1.update_theories(theory_edits.map(_._2))
       
   429     }
       
   430 
       
   431     def purge_theories(session: Session, nodes: List[Document.Node.Name])
       
   432       : ((List[Document.Node.Name], List[Document.Node.Name]), State) =
       
   433     {
       
   434       val all_nodes = theory_graph.topological_order
       
   435       val purge = nodes.filterNot(is_required(_)).toSet
       
   436 
       
   437       val retain = theory_graph.all_preds(all_nodes.filterNot(purge)).toSet
       
   438       val (retained, purged) = all_nodes.partition(retain)
       
   439 
       
   440       val purge_edits = purged.flatMap(name => theories(name).purge_edits)
       
   441       session.update(Document.Blobs.empty, purge_edits)
       
   442 
       
   443       ((purged, retained), remove_theories(purged))
       
   444     }
       
   445 
       
   446     def frontier_theories(clean: Set[Document.Node.Name]): Set[Document.Node.Name] =
       
   447     {
       
   448       @tailrec def frontier(base: List[Document.Node.Name], front: Set[Document.Node.Name])
       
   449         : Set[Document.Node.Name] =
       
   450       {
       
   451         val add = base.filter(b => theory_graph.imm_succs(b).forall(front))
       
   452         if (add.isEmpty) front
       
   453         else {
       
   454           val pre_add = add.map(theory_graph.imm_preds)
       
   455           val base1 = (pre_add.head /: pre_add.tail)(_ ++ _).toList.filter(clean)
       
   456           frontier(base1, front ++ add)
       
   457         }
       
   458       }
       
   459       frontier(theory_graph.maximals.filter(clean), Set.empty)
   395     }
   460     }
   396   }
   461   }
   397 }
   462 }
   398 
   463 
   399 class Thy_Resources(session_base: Sessions.Base, log: Logger = No_Logger)
   464 class Thy_Resources(session_base: Sessions.Base, log: Logger = No_Logger)
   436         session.update(Document.Blobs.empty, theory_edits.flatMap(_._1))
   501         session.update(Document.Blobs.empty, theory_edits.flatMap(_._1))
   437         st1.update_theories(theory_edits.map(_._2))
   502         st1.update_theories(theory_edits.map(_._2))
   438       })
   503       })
   439   }
   504   }
   440 
   505 
   441   def unload_theories(session: Session, id: UUID, dep_theories: List[Document.Node.Name])
   506   def unload_theories(
       
   507     session: Thy_Resources.Session, id: UUID, dep_theories: List[Document.Node.Name])
       
   508   {
       
   509     state.change(_.unload_theories(session, id, dep_theories))
       
   510   }
       
   511 
       
   512   def clean_theories(session: Thy_Resources.Session, id: UUID, clean: Set[Document.Node.Name])
   442   {
   513   {
   443     state.change(st =>
   514     state.change(st =>
   444       {
   515       {
   445         val st1 = st.remove_required(id, dep_theories)
   516         val frontier = st.frontier_theories(clean).toList
   446         val theory_edits =
   517         if (frontier.isEmpty) st
   447           for {
   518         else {
   448             node_name <- dep_theories
   519           val st1 = st.unload_theories(session, id, frontier)
   449             theory <- st1.theories.get(node_name)
   520           val (_, st2) = st1.purge_theories(session, frontier)
   450           }
   521           st2
   451           yield {
   522         }
   452             val theory1 = theory.required(st1.is_required(node_name))
       
   453             val edits = theory1.node_edits(Some(theory))
       
   454             (edits, (node_name, theory1))
       
   455           }
       
   456         session.update(Document.Blobs.empty, theory_edits.flatMap(_._1))
       
   457         st1.update_theories(theory_edits.map(_._2))
       
   458       })
   523       })
   459   }
   524   }
   460 
   525 
   461   def purge_theories(session: Session, nodes: Option[List[Document.Node.Name]])
   526   def purge_theories(session: Thy_Resources.Session, nodes: Option[List[Document.Node.Name]])
   462     : (List[Document.Node.Name], List[Document.Node.Name]) =
   527     : (List[Document.Node.Name], List[Document.Node.Name]) =
   463   {
   528   {
   464     state.change_result(st =>
   529     state.change_result(st => st.purge_theories(session, nodes getOrElse st.theory_graph.keys))
   465       {
       
   466         val graph = st.theory_graph
       
   467         val all_nodes = graph.topological_order
       
   468 
       
   469         val purge =
       
   470           (if (nodes.isEmpty) all_nodes else nodes.get.filter(graph.defined(_))).
       
   471             filterNot(st.is_required(_)).toSet
       
   472 
       
   473         val retain = graph.all_preds(all_nodes.filterNot(purge)).toSet
       
   474         val (retained, purged) = all_nodes.partition(retain)
       
   475 
       
   476         val purge_edits = purged.flatMap(name => st.theories(name).purge_edits)
       
   477         session.update(Document.Blobs.empty, purge_edits)
       
   478 
       
   479         ((purged, retained), st.remove_theories(purged))
       
   480       })
       
   481   }
   530   }
   482 }
   531 }