| author | wenzelm | 
| Sat, 08 Jul 2023 19:28:26 +0200 | |
| changeset 78271 | c0dc000d2a40 | 
| parent 78178 | a177f71dc79f | 
| child 78956 | 12abaffb0346 | 
| permissions | -rw-r--r-- | 
| 69012 | 1 | /* Title: Pure/PIDE/headless.scala | 
| 67054 | 2 | Author: Makarius | 
| 3 | ||
| 69012 | 4 | Headless PIDE session and resources from file-system. | 
| 67054 | 5 | */ | 
| 6 | ||
| 7 | package isabelle | |
| 8 | ||
| 9 | ||
| 67925 | 10 | import java.io.{File => JFile}
 | 
| 11 | ||
| 68936 
90c08c7bab9c
continuously clean frontier of already committed theories: much less resource requirements;
 wenzelm parents: 
68935diff
changeset | 12 | import scala.annotation.tailrec | 
| 69562 
636b3c03a61a
include loaded_files as doc_blobs (without purging);
 wenzelm parents: 
69538diff
changeset | 13 | import scala.collection.mutable | 
| 68936 
90c08c7bab9c
continuously clean frontier of already committed theories: much less resource requirements;
 wenzelm parents: 
68935diff
changeset | 14 | |
| 67925 | 15 | |
| 75393 | 16 | object Headless {
 | 
| 69012 | 17 | /** session **/ | 
| 67061 
2efa25302f34
synchronous session start (similar to isabelle.vscode.Server);
 wenzelm parents: 
67059diff
changeset | 18 | |
| 68916 | 19 | private def stable_snapshot( | 
| 75393 | 20 | state: Document.State, | 
| 21 | version: Document.Version, | |
| 22 | name: Document.Node.Name | |
| 23 |   ): Document.Snapshot = {
 | |
| 68916 | 24 | val snapshot = state.snapshot(name) | 
| 25 | assert(version.id == snapshot.version.id) | |
| 26 | snapshot | |
| 27 | } | |
| 28 | ||
| 69013 | 29 | class Use_Theories_Result private[Headless]( | 
| 67883 | 30 | val state: Document.State, | 
| 67889 | 31 | val version: Document.Version, | 
| 68925 | 32 | val nodes: List[(Document.Node.Name, Document_Status.Node_Status)], | 
| 75393 | 33 | val nodes_committed: List[(Document.Node.Name, Document_Status.Node_Status)] | 
| 34 |   ) {
 | |
| 35 |     def nodes_pending: List[(Document.Node.Name, Document_Status.Node_Status)] = {
 | |
| 69032 
90bb4cabe1e8
clarified errors: no result from forced session.stop, check pending theories;
 wenzelm parents: 
69013diff
changeset | 36 | val committed = nodes_committed.iterator.map(_._1).toSet | 
| 
90bb4cabe1e8
clarified errors: no result from forced session.stop, check pending theories;
 wenzelm parents: 
69013diff
changeset | 37 | nodes.filter(p => !committed(p._1)) | 
| 
90bb4cabe1e8
clarified errors: no result from forced session.stop, check pending theories;
 wenzelm parents: 
69013diff
changeset | 38 | } | 
| 
90bb4cabe1e8
clarified errors: no result from forced session.stop, check pending theories;
 wenzelm parents: 
69013diff
changeset | 39 | |
| 68925 | 40 | def snapshot(name: Document.Node.Name): Document.Snapshot = | 
| 41 | stable_snapshot(state, version, name) | |
| 42 | ||
| 43 | def ok: Boolean = | |
| 44 |       (nodes.iterator ++ nodes_committed.iterator).forall({ case (_, st) => st.ok })
 | |
| 67879 | 45 | } | 
| 46 | ||
| 69520 | 47 | class Session private[Headless]( | 
| 48 | session_name: String, | |
| 49 | _session_options: => Options, | |
| 75393 | 50 | override val resources: Resources) | 
| 51 |   extends isabelle.Session(_session_options, resources) {
 | |
| 69520 | 52 | session => | 
| 68694 
03e104be99af
added check_delay / check_limit for more robust treatment of structurally broken theory sources (or genuine non-termination);
 wenzelm parents: 
68365diff
changeset | 53 | |
| 
03e104be99af
added check_delay / check_limit for more robust treatment of structurally broken theory sources (or genuine non-termination);
 wenzelm parents: 
68365diff
changeset | 54 | |
| 70653 
f7c5b30fc432
load theories in stages, to reduce ML heap requirements;
 wenzelm parents: 
70649diff
changeset | 55 | private def loaded_theory(name: Document.Node.Name): Boolean = | 
| 
f7c5b30fc432
load theories in stages, to reduce ML heap requirements;
 wenzelm parents: 
70649diff
changeset | 56 | resources.session_base.loaded_theory(name.theory) | 
| 
f7c5b30fc432
load theories in stages, to reduce ML heap requirements;
 wenzelm parents: 
70649diff
changeset | 57 | |
| 
f7c5b30fc432
load theories in stages, to reduce ML heap requirements;
 wenzelm parents: 
70649diff
changeset | 58 | |
| 69520 | 59 | /* options */ | 
| 60 | ||
| 70787 | 61 |     override def consolidate_delay: Time = session_options.seconds("headless_consolidate_delay")
 | 
| 62 |     override def prune_delay: Time = session_options.seconds("headless_prune_delay")
 | |
| 63 | ||
| 69520 | 64 |     def default_check_delay: Time = session_options.seconds("headless_check_delay")
 | 
| 65 |     def default_check_limit: Int = session_options.int("headless_check_limit")
 | |
| 66 |     def default_nodes_status_delay: Time = session_options.seconds("headless_nodes_status_delay")
 | |
| 67 |     def default_watchdog_timeout: Time = session_options.seconds("headless_watchdog_timeout")
 | |
| 68 |     def default_commit_cleanup_delay: Time = session_options.seconds("headless_commit_cleanup_delay")
 | |
| 67063 | 69 | |
| 77137 
79231a210f5d
observe option "show_states" in headless server (see also 951abf9db857);
 wenzelm parents: 
77112diff
changeset | 70 |     def show_states: Boolean = session_options.bool("show_states")
 | 
| 
79231a210f5d
observe option "show_states" in headless server (see also 951abf9db857);
 wenzelm parents: 
77112diff
changeset | 71 | |
| 68922 | 72 | |
| 73 | /* temporary directory */ | |
| 74 | ||
| 67925 | 75 |     val tmp_dir: JFile = Isabelle_System.tmp_dir("server_session")
 | 
| 67946 | 76 | val tmp_dir_name: String = File.path(tmp_dir).implode | 
| 67925 | 77 | |
| 68923 | 78 | def master_directory(master_dir: String): String = | 
| 79 | proper_string(master_dir) getOrElse tmp_dir_name | |
| 80 | ||
| 67945 | 81 | override def toString: String = session_name | 
| 82 | ||
| 75393 | 83 |     override def stop(): Process_Result = {
 | 
| 67925 | 84 |       try { super.stop() }
 | 
| 85 |       finally { Isabelle_System.rm_tree(tmp_dir) }
 | |
| 86 | } | |
| 87 | ||
| 67936 | 88 | |
| 89 | /* theories */ | |
| 90 | ||
| 75393 | 91 |     private object Load_State {
 | 
| 77709 | 92 | def finished: Load_State = Load_State(Nil, Nil, Space.zero) | 
| 70872 | 93 | |
| 94 | def count_file(name: Document.Node.Name): Long = | |
| 77112 | 95 | if (loaded_theory(name)) 0 else File.space(name.path).bytes | 
| 70872 | 96 | } | 
| 97 | ||
| 98 | private case class Load_State( | |
| 75393 | 99 | pending: List[Document.Node.Name], | 
| 100 | rest: List[Document.Node.Name], | |
| 77709 | 101 | load_limit: Space | 
| 75393 | 102 |     ) {
 | 
| 70872 | 103 | def next( | 
| 104 | dep_graph: Document.Node.Name.Graph[Unit], | |
| 76310 
c5c747ce46d2
proper update of non-committed theories (see also 2bf1d0e57695, 2a1583baaaa0);
 wenzelm parents: 
76309diff
changeset | 105 | consolidated: Document.Node.Name => Boolean | 
| 75393 | 106 |       ): (List[Document.Node.Name], Load_State) = {
 | 
| 107 | def load_requirements( | |
| 108 | pending1: List[Document.Node.Name], | |
| 109 | rest1: List[Document.Node.Name] | |
| 110 |         ) : (List[Document.Node.Name], Load_State) = {
 | |
| 76310 
c5c747ce46d2
proper update of non-committed theories (see also 2bf1d0e57695, 2a1583baaaa0);
 wenzelm parents: 
76309diff
changeset | 111 | val load_theories = dep_graph.all_preds_rev(pending1) | 
| 70872 | 112 | (load_theories, Load_State(pending1, rest1, load_limit)) | 
| 113 | } | |
| 114 | ||
| 76310 
c5c747ce46d2
proper update of non-committed theories (see also 2bf1d0e57695, 2a1583baaaa0);
 wenzelm parents: 
76309diff
changeset | 115 | if (!pending.forall(consolidated)) (Nil, this) | 
| 70872 | 116 | else if (rest.isEmpty) (Nil, Load_State.finished) | 
| 77709 | 117 | else if (!load_limit.is_proper) load_requirements(rest, Nil) | 
| 70872 | 118 |         else {
 | 
| 119 | val reachable = | |
| 77709 | 120 | dep_graph.reachable_limit( | 
| 121 | load_limit.bytes, Load_State.count_file, dep_graph.imm_preds, rest) | |
| 70872 | 122 | val (pending1, rest1) = rest.partition(reachable) | 
| 123 | load_requirements(pending1, rest1) | |
| 124 | } | |
| 125 | } | |
| 126 | } | |
| 127 | ||
| 68914 | 128 | private sealed case class Use_Theories_State( | 
| 70697 | 129 | dep_graph: Document.Node.Name.Graph[Unit], | 
| 70765 | 130 | load_state: Load_State, | 
| 70653 
f7c5b30fc432
load theories in stages, to reduce ML heap requirements;
 wenzelm parents: 
70649diff
changeset | 131 | watchdog_timeout: Time, | 
| 
f7c5b30fc432
load theories in stages, to reduce ML heap requirements;
 wenzelm parents: 
70649diff
changeset | 132 | commit: Option[(Document.Snapshot, Document_Status.Node_Status) => Unit], | 
| 68914 | 133 | last_update: Time = Time.now(), | 
| 134 | nodes_status: Document_Status.Nodes_Status = Document_Status.Nodes_Status.empty, | |
| 68925 | 135 | already_committed: Map[Document.Node.Name, Document_Status.Node_Status] = Map.empty, | 
| 76320 | 136 | changed_nodes: Set[Document.Node.Name] = Set.empty, | 
| 137 | changed_assignment: Boolean = false, | |
| 75393 | 138 | result: Option[Exn.Result[Use_Theories_Result]] = None | 
| 139 |     ) {
 | |
| 76316 | 140 | def nodes_status_update(state: Document.State, version: Document.Version, | 
| 141 | domain: Option[Set[Document.Node.Name]] = None, | |
| 76319 | 142 | trim: Boolean = false | 
| 76316 | 143 |       ): (Boolean, Use_Theories_State) = {
 | 
| 144 | val (nodes_status_changed, nodes_status1) = | |
| 145 | nodes_status.update(resources, state, version, domain = domain, trim = trim) | |
| 76319 | 146 | val st1 = copy(last_update = Time.now(), nodes_status = nodes_status1) | 
| 76316 | 147 | (nodes_status_changed, st1) | 
| 148 | } | |
| 68914 | 149 | |
| 76320 | 150 | def changed( | 
| 151 | nodes: IterableOnce[Document.Node.Name], | |
| 152 | assignment: Boolean | |
| 153 |       ): Use_Theories_State = {
 | |
| 154 | copy( | |
| 155 | changed_nodes = changed_nodes ++ nodes, | |
| 156 | changed_assignment = changed_assignment || assignment) | |
| 157 | } | |
| 158 | ||
| 159 | def reset_changed: Use_Theories_State = | |
| 160 | if (changed_nodes.isEmpty && !changed_assignment) this | |
| 161 | else copy(changed_nodes = Set.empty, changed_assignment = false) | |
| 162 | ||
| 70653 
f7c5b30fc432
load theories in stages, to reduce ML heap requirements;
 wenzelm parents: 
70649diff
changeset | 163 | def watchdog: Boolean = | 
| 68914 | 164 | watchdog_timeout > Time.zero && Time.now() - last_update > watchdog_timeout | 
| 165 | ||
| 70644 
b23a6dfcfd57
clarified state variable: avoid extra mutability via Promise;
 wenzelm parents: 
70640diff
changeset | 166 | def finished_result: Boolean = result.isDefined | 
| 
b23a6dfcfd57
clarified state variable: avoid extra mutability via Promise;
 wenzelm parents: 
70640diff
changeset | 167 | |
| 
b23a6dfcfd57
clarified state variable: avoid extra mutability via Promise;
 wenzelm parents: 
70640diff
changeset | 168 | def join_result: Option[(Exn.Result[Use_Theories_Result], Use_Theories_State)] = | 
| 
b23a6dfcfd57
clarified state variable: avoid extra mutability via Promise;
 wenzelm parents: 
70640diff
changeset | 169 | if (finished_result) Some((result.get, this)) else None | 
| 
b23a6dfcfd57
clarified state variable: avoid extra mutability via Promise;
 wenzelm parents: 
70640diff
changeset | 170 | |
| 
b23a6dfcfd57
clarified state variable: avoid extra mutability via Promise;
 wenzelm parents: 
70640diff
changeset | 171 | def cancel_result: Use_Theories_State = | 
| 
b23a6dfcfd57
clarified state variable: avoid extra mutability via Promise;
 wenzelm parents: 
70640diff
changeset | 172 | if (finished_result) this else copy(result = Some(Exn.Exn(Exn.Interrupt()))) | 
| 
b23a6dfcfd57
clarified state variable: avoid extra mutability via Promise;
 wenzelm parents: 
70640diff
changeset | 173 | |
| 75393 | 174 |       def clean_theories: (List[Document.Node.Name], Use_Theories_State) = {
 | 
| 175 | @tailrec def frontier( | |
| 176 | base: List[Document.Node.Name], | |
| 177 | front: Set[Document.Node.Name] | |
| 178 |         ) : Set[Document.Node.Name] = {
 | |
| 70698 | 179 | val add = base.filter(name => dep_graph.imm_succs(name).forall(front)) | 
| 180 | if (add.isEmpty) front | |
| 181 |           else {
 | |
| 182 | val preds = add.map(dep_graph.imm_preds) | |
| 73359 | 183 | val base1 = | 
| 184 | preds.tail.foldLeft(preds.head)(_ ++ _).toList.filter(already_committed.keySet) | |
| 70698 | 185 | frontier(base1, front ++ add) | 
| 186 | } | |
| 187 | } | |
| 188 | ||
| 70763 
5fae55752c70
tuned messages (again) -- avoid confusion wrt. total remaining size;
 wenzelm parents: 
70710diff
changeset | 189 | if (already_committed.isEmpty) (Nil, this) | 
| 70698 | 190 |         else {
 | 
| 70705 | 191 | val base = | 
| 192 |             (for {
 | |
| 193 | (name, (_, (_, succs))) <- dep_graph.iterator | |
| 194 | if succs.isEmpty && already_committed.isDefinedAt(name) | |
| 195 | } yield name).toList | |
| 196 | val clean = frontier(base, Set.empty) | |
| 70763 
5fae55752c70
tuned messages (again) -- avoid confusion wrt. total remaining size;
 wenzelm parents: 
70710diff
changeset | 197 | if (clean.isEmpty) (Nil, this) | 
| 70698 | 198 |           else {
 | 
| 70763 
5fae55752c70
tuned messages (again) -- avoid confusion wrt. total remaining size;
 wenzelm parents: 
70710diff
changeset | 199 | (dep_graph.topological_order.filter(clean), | 
| 70699 | 200 | copy(dep_graph = dep_graph.exclude(clean))) | 
| 70698 | 201 | } | 
| 202 | } | |
| 203 | } | |
| 70653 
f7c5b30fc432
load theories in stages, to reduce ML heap requirements;
 wenzelm parents: 
70649diff
changeset | 204 | |
| 76315 | 205 | private def consolidated( | 
| 206 | state: Document.State, | |
| 207 | version: Document.Version, | |
| 208 | name: Document.Node.Name | |
| 209 |       ): Boolean = {
 | |
| 210 | loaded_theory(name) || | |
| 211 | nodes_status.quasi_consolidated(name) || | |
| 212 | (if (commit.isDefined) already_committed.isDefinedAt(name) | |
| 213 | else state.node_consolidated(version, name)) | |
| 214 | } | |
| 215 | ||
| 75393 | 216 | def check( | 
| 217 | state: Document.State, | |
| 218 | version: Document.Version, | |
| 219 | beyond_limit: Boolean | |
| 220 |       ) : (List[Document.Node.Name], Use_Theories_State) = {
 | |
| 76315 | 221 | val st1 = | 
| 70653 
f7c5b30fc432
load theories in stages, to reduce ML heap requirements;
 wenzelm parents: 
70649diff
changeset | 222 |           commit match {
 | 
| 76315 | 223 | case None => this | 
| 70653 
f7c5b30fc432
load theories in stages, to reduce ML heap requirements;
 wenzelm parents: 
70649diff
changeset | 224 | case Some(commit_fn) => | 
| 76315 | 225 | copy(already_committed = | 
| 226 |                 dep_graph.topological_order.foldLeft(already_committed) {
 | |
| 227 | case (committed, name) => | |
| 228 | def parents_committed: Boolean = | |
| 229 | version.nodes(name).header.imports.forall(parent => | |
| 230 | loaded_theory(parent) || committed.isDefinedAt(parent)) | |
| 231 | if (!committed.isDefinedAt(name) && parents_committed && | |
| 232 |                         state.node_consolidated(version, name)) {
 | |
| 233 | val snapshot = stable_snapshot(state, version, name) | |
| 234 | val status = Document_Status.Node_Status.make(state, version, name) | |
| 235 | commit_fn(snapshot, status) | |
| 236 | committed + (name -> status) | |
| 237 | } | |
| 238 | else committed | |
| 239 | }) | |
| 68916 | 240 | } | 
| 241 | ||
| 76310 
c5c747ce46d2
proper update of non-committed theories (see also 2bf1d0e57695, 2a1583baaaa0);
 wenzelm parents: 
76309diff
changeset | 242 | def committed(name: Document.Node.Name): Boolean = | 
| 76315 | 243 | loaded_theory(name) || st1.already_committed.isDefinedAt(name) | 
| 76310 
c5c747ce46d2
proper update of non-committed theories (see also 2bf1d0e57695, 2a1583baaaa0);
 wenzelm parents: 
76309diff
changeset | 244 | |
| 76323 
3637a0d06fe1
avoid result based on outdated state, e.g. relevant for use_theories with changed files;
 wenzelm parents: 
76320diff
changeset | 245 | val (load_theories0, load_state1) = | 
| 
3637a0d06fe1
avoid result based on outdated state, e.g. relevant for use_theories with changed files;
 wenzelm parents: 
76320diff
changeset | 246 | load_state.next(dep_graph, consolidated(state, version, _)) | 
| 
3637a0d06fe1
avoid result based on outdated state, e.g. relevant for use_theories with changed files;
 wenzelm parents: 
76320diff
changeset | 247 | |
| 
3637a0d06fe1
avoid result based on outdated state, e.g. relevant for use_theories with changed files;
 wenzelm parents: 
76320diff
changeset | 248 | val load_theories = load_theories0.filterNot(committed) | 
| 
3637a0d06fe1
avoid result based on outdated state, e.g. relevant for use_theories with changed files;
 wenzelm parents: 
76320diff
changeset | 249 | |
| 76320 | 250 |         val result1 = {
 | 
| 251 | val stopped = beyond_limit || watchdog | |
| 76323 
3637a0d06fe1
avoid result based on outdated state, e.g. relevant for use_theories with changed files;
 wenzelm parents: 
76320diff
changeset | 252 | if (!finished_result && load_theories.isEmpty && | 
| 76320 | 253 | (stopped || dep_graph.keys_iterator.forall(consolidated(state, version, _))) | 
| 76315 | 254 |           ) {
 | 
| 76320 | 255 | @tailrec def make_nodes( | 
| 256 | input: List[Document.Node.Name], | |
| 257 | output: List[(Document.Node.Name, Document_Status.Node_Status)] | |
| 258 |             ): Option[List[(Document.Node.Name, Document_Status.Node_Status)]] = {
 | |
| 259 |               input match {
 | |
| 260 | case name :: rest => | |
| 261 | if (loaded_theory(name)) make_nodes(rest, output) | |
| 262 |                   else {
 | |
| 263 | val status = Document_Status.Node_Status.make(state, version, name) | |
| 76328 | 264 | val ok = if (commit.isDefined) committed(name) else status.consolidated | 
| 265 | if (stopped || ok) make_nodes(rest, (name -> status) :: output) else None | |
| 76320 | 266 | } | 
| 267 | case Nil => Some(output) | |
| 268 | } | |
| 269 | } | |
| 270 | ||
| 271 |             for (nodes <- make_nodes(dep_graph.topological_order.reverse, Nil)) yield {
 | |
| 272 | val nodes_committed = | |
| 273 |                 (for {
 | |
| 274 | name <- dep_graph.keys_iterator | |
| 275 | status <- st1.already_committed.get(name) | |
| 276 | } yield name -> status).toList | |
| 277 | Exn.Res(new Use_Theories_Result(state, version, nodes, nodes_committed)) | |
| 278 | } | |
| 70644 
b23a6dfcfd57
clarified state variable: avoid extra mutability via Promise;
 wenzelm parents: 
70640diff
changeset | 279 | } | 
| 
b23a6dfcfd57
clarified state variable: avoid extra mutability via Promise;
 wenzelm parents: 
70640diff
changeset | 280 | else result | 
| 76320 | 281 | } | 
| 68925 | 282 | |
| 76323 
3637a0d06fe1
avoid result based on outdated state, e.g. relevant for use_theories with changed files;
 wenzelm parents: 
76320diff
changeset | 283 | (load_theories, st1.copy(result = result1, load_state = load_state1)) | 
| 68916 | 284 | } | 
| 68914 | 285 | } | 
| 286 | ||
| 67064 
fb487246ef4f
synchronous use_theories, based on consolidated_state;
 wenzelm parents: 
67063diff
changeset | 287 | def use_theories( | 
| 67940 
b4e80f062fbf
clarified signature -- eliminated somewhat pointless positions;
 wenzelm parents: 
67939diff
changeset | 288 | theories: List[String], | 
| 67064 
fb487246ef4f
synchronous use_theories, based on consolidated_state;
 wenzelm parents: 
67063diff
changeset | 289 | qualifier: String = Sessions.DRAFT, | 
| 67881 | 290 | master_dir: String = "", | 
| 69920 | 291 | unicode_symbols: Boolean = false, | 
| 68943 | 292 | check_delay: Time = default_check_delay, | 
| 69520 | 293 | check_limit: Int = default_check_limit, | 
| 68947 | 294 | watchdog_timeout: Time = default_watchdog_timeout, | 
| 68943 | 295 | nodes_status_delay: Time = default_nodes_status_delay, | 
| 69458 | 296 | id: UUID.T = UUID.random(), | 
| 68916 | 297 | // commit: must not block, must not fail | 
| 298 | commit: Option[(Document.Snapshot, Document_Status.Node_Status) => Unit] = None, | |
| 68981 | 299 | commit_cleanup_delay: Time = default_commit_cleanup_delay, | 
| 75393 | 300 | progress: Progress = new Progress | 
| 301 |     ): Use_Theories_Result = {
 | |
| 302 |       val dependencies = {
 | |
| 68894 
1dbdad1b57a5
more robust: load_theories after consumer is installed;
 wenzelm parents: 
68888diff
changeset | 303 | val import_names = | 
| 68923 | 304 | theories.map(thy => | 
| 305 | resources.import_name(qualifier, master_directory(master_dir), thy) -> Position.none) | |
| 69562 
636b3c03a61a
include loaded_files as doc_blobs (without purging);
 wenzelm parents: 
69538diff
changeset | 306 | resources.dependencies(import_names, progress = progress).check_errors | 
| 68894 
1dbdad1b57a5
more robust: load_theories after consumer is installed;
 wenzelm parents: 
68888diff
changeset | 307 | } | 
| 69562 
636b3c03a61a
include loaded_files as doc_blobs (without purging);
 wenzelm parents: 
69538diff
changeset | 308 | val dep_theories = dependencies.theories | 
| 70653 
f7c5b30fc432
load theories in stages, to reduce ML heap requirements;
 wenzelm parents: 
70649diff
changeset | 309 | val dep_theories_set = dep_theories.toSet | 
| 76886 
f405fcc3db33
clarified signature: avoid somewhat fragile Document.Node.Name.master_dir_path;
 wenzelm parents: 
76858diff
changeset | 310 | val dep_files = dependencies.loaded_files | 
| 67064 
fb487246ef4f
synchronous use_theories, based on consolidated_state;
 wenzelm parents: 
67063diff
changeset | 311 | |
| 75393 | 312 |       val use_theories_state = {
 | 
| 70797 | 313 | val dep_graph = dependencies.theory_graph | 
| 314 | ||
| 315 | val maximals = dep_graph.maximals | |
| 316 | val rest = | |
| 317 | if (maximals.isEmpty || maximals.tail.isEmpty) maximals | |
| 318 |           else {
 | |
| 70800 | 319 | val depth = dep_graph.node_depth(Load_State.count_file) | 
| 70797 | 320 | maximals.sortBy(node => - depth(node)) | 
| 321 | } | |
| 70800 | 322 | val load_limit = | 
| 77709 | 323 |           if (commit.isDefined) Space.MiB(session_options.real("headless_load_limit"))
 | 
| 324 | else Space.zero | |
| 70798 | 325 | val load_state = Load_State(Nil, rest, load_limit) | 
| 70797 | 326 | |
| 327 | Synchronized(Use_Theories_State(dep_graph, load_state, watchdog_timeout, commit)) | |
| 328 | } | |
| 67064 
fb487246ef4f
synchronous use_theories, based on consolidated_state;
 wenzelm parents: 
67063diff
changeset | 329 | |
| 76320 | 330 | def check_state( | 
| 331 | beyond_limit: Boolean = false, | |
| 332 | state: Document.State = session.get_state() | |
| 333 |       ): Unit = {
 | |
| 70797 | 334 |         for {
 | 
| 335 | version <- state.stable_tip_version | |
| 336 | load_theories = use_theories_state.change_result(_.check(state, version, beyond_limit)) | |
| 337 | if load_theories.nonEmpty | |
| 338 | } resources.load_theories(session, id, load_theories, dep_files, unicode_symbols, progress) | |
| 67064 
fb487246ef4f
synchronous use_theories, based on consolidated_state;
 wenzelm parents: 
67063diff
changeset | 339 | } | 
| 
fb487246ef4f
synchronous use_theories, based on consolidated_state;
 wenzelm parents: 
67063diff
changeset | 340 | |
| 76311 
fab6568b119d
more robust: active consumer for check_state/check_progress;
 wenzelm parents: 
76310diff
changeset | 341 |       lazy val check_progress = {
 | 
| 68694 
03e104be99af
added check_delay / check_limit for more robust treatment of structurally broken theory sources (or genuine non-termination);
 wenzelm parents: 
68365diff
changeset | 342 | var check_count = 0 | 
| 75393 | 343 |         Event_Timer.request(Time.now(), repeat = Some(check_delay)) {
 | 
| 344 | if (progress.stopped) use_theories_state.change(_.cancel_result) | |
| 345 |           else {
 | |
| 346 | check_count += 1 | |
| 347 | check_state(check_limit > 0 && check_count > check_limit) | |
| 68694 
03e104be99af
added check_delay / check_limit for more robust treatment of structurally broken theory sources (or genuine non-termination);
 wenzelm parents: 
68365diff
changeset | 348 | } | 
| 75393 | 349 | } | 
| 68694 
03e104be99af
added check_delay / check_limit for more robust treatment of structurally broken theory sources (or genuine non-termination);
 wenzelm parents: 
68365diff
changeset | 350 | } | 
| 67894 
fee080c4045f
more robust check_state loop, even without session activity (e.g. idempotent use_theories);
 wenzelm parents: 
67893diff
changeset | 351 | |
| 75393 | 352 |       val consumer = {
 | 
| 68906 | 353 | val delay_nodes_status = | 
| 71704 | 354 |           Delay.first(nodes_status_delay max Time.zero) {
 | 
| 69818 
60d0ee8f2ddb
more robust: avoid potentially unrelated snapshot for the sake of is_suppressed;
 wenzelm parents: 
69817diff
changeset | 355 | progress.nodes_status(use_theories_state.value.nodes_status) | 
| 68906 | 356 | } | 
| 68770 
add44e2b8cb0
optional notification of nodes_status (via progress);
 wenzelm parents: 
68758diff
changeset | 357 | |
| 68936 
90c08c7bab9c
continuously clean frontier of already committed theories: much less resource requirements;
 wenzelm parents: 
68935diff
changeset | 358 | val delay_commit_clean = | 
| 71704 | 359 |           Delay.first(commit_cleanup_delay max Time.zero) {
 | 
| 70763 
5fae55752c70
tuned messages (again) -- avoid confusion wrt. total remaining size;
 wenzelm parents: 
70710diff
changeset | 360 | val clean_theories = use_theories_state.change_result(_.clean_theories) | 
| 76330 | 361 |             if (clean_theories.nonEmpty && session.is_ready) {
 | 
| 70770 | 362 |               progress.echo("Removing " + clean_theories.length + " theories ...")
 | 
| 70702 | 363 | resources.clean_theories(session, id, clean_theories) | 
| 364 | } | |
| 68936 
90c08c7bab9c
continuously clean frontier of already committed theories: much less resource requirements;
 wenzelm parents: 
68935diff
changeset | 365 | } | 
| 
90c08c7bab9c
continuously clean frontier of already committed theories: much less resource requirements;
 wenzelm parents: 
68935diff
changeset | 366 | |
| 76320 | 367 |         isabelle.Session.Consumer[isabelle.Session.Commands_Changed](getClass.getName) { changed =>
 | 
| 368 | val state = session.get_state() | |
| 369 | ||
| 370 | def apply_changed(st: Use_Theories_State): Use_Theories_State = | |
| 371 | st.changed(changed.nodes.iterator.filter(dep_theories_set), changed.assignment) | |
| 68770 
add44e2b8cb0
optional notification of nodes_status (via progress);
 wenzelm parents: 
68758diff
changeset | 372 | |
| 76320 | 373 |           state.stable_tip_version match {
 | 
| 374 | case None => use_theories_state.change(apply_changed) | |
| 375 | case Some(version) => | |
| 76329 | 376 | val theory_progress = | 
| 75394 | 377 |                 use_theories_state.change_result { st =>
 | 
| 76320 | 378 | val changed_st = apply_changed(st) | 
| 379 | ||
| 75393 | 380 | val domain = | 
| 381 | if (st.nodes_status.is_empty) dep_theories_set | |
| 76320 | 382 | else changed_st.changed_nodes | 
| 68899 | 383 | |
| 76316 | 384 | val (nodes_status_changed, st1) = | 
| 76320 | 385 | st.reset_changed.nodes_status_update(state, version, | 
| 386 | domain = Some(domain), trim = changed_st.changed_assignment) | |
| 68899 | 387 | |
| 75393 | 388 |                   if (nodes_status_delay >= Time.zero && nodes_status_changed) {
 | 
| 389 | delay_nodes_status.invoke() | |
| 390 | } | |
| 68883 
3653b3ad729e
clarified Thy_Resources.Session.use_theories: "terminated" node status is sufficient;
 wenzelm parents: 
68771diff
changeset | 391 | |
| 75393 | 392 | val theory_progress = | 
| 393 |                     (for {
 | |
| 76716 
a7602257a825
clarified state document nodes for Theories_Status / Document_Dockable;
 wenzelm parents: 
76702diff
changeset | 394 | (name, node_status) <- st1.nodes_status.present().iterator | 
| 
a7602257a825
clarified state document nodes for Theories_Status / Document_Dockable;
 wenzelm parents: 
76702diff
changeset | 395 | if !node_status.is_empty && changed_st.changed_nodes(name) && | 
| 
a7602257a825
clarified state document nodes for Theories_Status / Document_Dockable;
 wenzelm parents: 
76702diff
changeset | 396 | !st.already_committed.isDefinedAt(name) | 
| 75393 | 397 | p1 = node_status.percentage | 
| 75742 | 398 | if p1 > 0 && !st.nodes_status.get(name).map(_.percentage).contains(p1) | 
| 75393 | 399 | } yield Progress.Theory(name.theory, percentage = Some(p1))).toList | 
| 68903 | 400 | |
| 76329 | 401 |                   if (commit.isDefined && commit_cleanup_delay > Time.zero) {
 | 
| 402 | if (st1.finished_result) delay_commit_clean.revoke() | |
| 403 | else delay_commit_clean.invoke() | |
| 404 | } | |
| 405 | ||
| 406 | (theory_progress, st1) | |
| 75394 | 407 | } | 
| 68330 | 408 | |
| 71601 | 409 | theory_progress.foreach(progress.theory) | 
| 68903 | 410 | |
| 76320 | 411 | check_state(state = state) | 
| 412 | } | |
| 67064 
fb487246ef4f
synchronous use_theories, based on consolidated_state;
 wenzelm parents: 
67063diff
changeset | 413 | } | 
| 68906 | 414 | } | 
| 67064 
fb487246ef4f
synchronous use_theories, based on consolidated_state;
 wenzelm parents: 
67063diff
changeset | 415 | |
| 67892 | 416 |       try {
 | 
| 417 | session.commands_changed += consumer | |
| 76311 
fab6568b119d
more robust: active consumer for check_state/check_progress;
 wenzelm parents: 
76310diff
changeset | 418 | check_progress | 
| 70644 
b23a6dfcfd57
clarified state variable: avoid extra mutability via Promise;
 wenzelm parents: 
70640diff
changeset | 419 | use_theories_state.guarded_access(_.join_result) | 
| 73367 | 420 | check_progress.cancel() | 
| 67892 | 421 | } | 
| 422 |       finally {
 | |
| 68907 | 423 | session.commands_changed -= consumer | 
| 67892 | 424 | resources.unload_theories(session, id, dep_theories) | 
| 425 | } | |
| 67884 
43af581d7d8e
unload_theories after consolidation -- reset node_required;
 wenzelm parents: 
67883diff
changeset | 426 | |
| 70644 
b23a6dfcfd57
clarified state variable: avoid extra mutability via Promise;
 wenzelm parents: 
70640diff
changeset | 427 | Exn.release(use_theories_state.guarded_access(_.join_result)) | 
| 67064 
fb487246ef4f
synchronous use_theories, based on consolidated_state;
 wenzelm parents: 
67063diff
changeset | 428 | } | 
| 67936 | 429 | |
| 67939 | 430 | def purge_theories( | 
| 68915 | 431 | theories: List[String], | 
| 432 | qualifier: String = Sessions.DRAFT, | |
| 433 | master_dir: String = "", | |
| 75393 | 434 | all: Boolean = false | 
| 435 |     ): (List[Document.Node.Name], List[Document.Node.Name]) = {
 | |
| 68923 | 436 | val nodes = | 
| 437 | if (all) None | |
| 438 | else Some(theories.map(resources.import_name(qualifier, master_directory(master_dir), _))) | |
| 75743 | 439 | resources.purge_theories(nodes) | 
| 68915 | 440 | } | 
| 67063 | 441 | } | 
| 442 | ||
| 67061 
2efa25302f34
synchronous session start (similar to isabelle.vscode.Server);
 wenzelm parents: 
67059diff
changeset | 443 | |
| 67054 | 444 | |
| 69012 | 445 | /** resources **/ | 
| 68922 | 446 | |
| 75393 | 447 |   object Resources {
 | 
| 76656 | 448 | def apply( | 
| 449 | options: Options, | |
| 76657 | 450 | session_background: Sessions.Background, | 
| 76656 | 451 | log: Logger = No_Logger | 
| 76657 | 452 | ): Resources = new Resources(options, session_background, log = log) | 
| 69536 | 453 | |
| 454 | def make( | |
| 455 | options: Options, | |
| 456 | session_name: String, | |
| 457 | session_dirs: List[Path] = Nil, | |
| 458 | include_sessions: List[String] = Nil, | |
| 71726 
a5fda30edae2
clarified signature: more uniform treatment of stopped/interrupted state;
 wenzelm parents: 
71704diff
changeset | 459 | progress: Progress = new Progress, | 
| 75393 | 460 | log: Logger = No_Logger | 
| 461 |     ): Resources = {
 | |
| 76657 | 462 | val session_background = | 
| 76656 | 463 | Sessions.background(options, session_name, dirs = session_dirs, | 
| 69536 | 464 | include_sessions = include_sessions, progress = progress) | 
| 76657 | 465 | apply(options, session_background, log = log) | 
| 69536 | 466 | } | 
| 467 | ||
| 69012 | 468 | final class Theory private[Headless]( | 
| 469 | val node_name: Document.Node.Name, | |
| 470 | val node_header: Document.Node.Header, | |
| 471 | val text: String, | |
| 75393 | 472 | val node_required: Boolean | 
| 473 |     ) {
 | |
| 69012 | 474 | override def toString: String = node_name.toString | 
| 68922 | 475 | |
| 76702 | 476 | def node_perspective: Document.Node.Perspective_Text.T = | 
| 69012 | 477 | Document.Node.Perspective(node_required, Text.Perspective.empty, Document.Node.Overlays.empty) | 
| 68922 | 478 | |
| 69012 | 479 | def make_edits(text_edits: List[Text.Edit]): List[Document.Edit_Text] = | 
| 480 | List(node_name -> Document.Node.Deps(node_header), | |
| 481 | node_name -> Document.Node.Edits(text_edits), | |
| 482 | node_name -> node_perspective) | |
| 68922 | 483 | |
| 75393 | 484 |       def node_edits(old: Option[Theory]): List[Document.Edit_Text] = {
 | 
| 69012 | 485 | val (text_edits, old_required) = | 
| 486 | if (old.isEmpty) (Text.Edit.inserts(0, text), false) | |
| 487 | else (Text.Edit.replace(0, old.get.text, text), old.get.node_required) | |
| 67887 
a4d5342898b1
unload_theories: actually observe required state;
 wenzelm parents: 
67885diff
changeset | 488 | |
| 69012 | 489 | if (text_edits.isEmpty && node_required == old_required) Nil | 
| 490 | else make_edits(text_edits) | |
| 491 | } | |
| 67887 
a4d5342898b1
unload_theories: actually observe required state;
 wenzelm parents: 
67885diff
changeset | 492 | |
| 69012 | 493 | def purge_edits: List[Document.Edit_Text] = | 
| 494 | make_edits(Text.Edit.removes(0, text)) | |
| 67936 | 495 | |
| 76312 | 496 | def set_required(required: Boolean): Theory = | 
| 69012 | 497 | if (required == node_required) this | 
| 498 | else new Theory(node_name, node_header, text, required) | |
| 67936 | 499 | } | 
| 500 | ||
| 69012 | 501 | sealed case class State( | 
| 76904 
e27d097d7d15
tuned signature: avoid confusion with Document.Node.Blob and Command.Blob;
 wenzelm parents: 
76902diff
changeset | 502 | blobs: Map[Document.Node.Name, Document.Blobs.Item] = Map.empty, | 
| 69562 
636b3c03a61a
include loaded_files as doc_blobs (without purging);
 wenzelm parents: 
69538diff
changeset | 503 | theories: Map[Document.Node.Name, Theory] = Map.empty, | 
| 75393 | 504 | required: Multi_Map[Document.Node.Name, UUID.T] = Multi_Map.empty | 
| 505 |     ) {
 | |
| 69562 
636b3c03a61a
include loaded_files as doc_blobs (without purging);
 wenzelm parents: 
69538diff
changeset | 506 | /* blobs */ | 
| 
636b3c03a61a
include loaded_files as doc_blobs (without purging);
 wenzelm parents: 
69538diff
changeset | 507 | |
| 
636b3c03a61a
include loaded_files as doc_blobs (without purging);
 wenzelm parents: 
69538diff
changeset | 508 | def doc_blobs: Document.Blobs = Document.Blobs(blobs) | 
| 
636b3c03a61a
include loaded_files as doc_blobs (without purging);
 wenzelm parents: 
69538diff
changeset | 509 | |
| 75393 | 510 |       def update_blobs(names: List[Document.Node.Name]): (Document.Blobs, State) = {
 | 
| 69562 
636b3c03a61a
include loaded_files as doc_blobs (without purging);
 wenzelm parents: 
69538diff
changeset | 511 | val new_blobs = | 
| 75394 | 512 |           names.flatMap { name =>
 | 
| 69562 
636b3c03a61a
include loaded_files as doc_blobs (without purging);
 wenzelm parents: 
69538diff
changeset | 513 | val bytes = Bytes.read(name.path) | 
| 
636b3c03a61a
include loaded_files as doc_blobs (without purging);
 wenzelm parents: 
69538diff
changeset | 514 |             blobs.get(name) match {
 | 
| 76902 | 515 | case Some(blob) if blob.bytes == bytes => None | 
| 76906 | 516 | case _ => | 
| 517 | val text = bytes.text | |
| 518 | val blob = Document.Blobs.Item(bytes, text, Symbol.Text_Chunk(text), changed = true) | |
| 519 | Some(name -> blob) | |
| 69562 
636b3c03a61a
include loaded_files as doc_blobs (without purging);
 wenzelm parents: 
69538diff
changeset | 520 | } | 
| 75394 | 521 | } | 
| 73359 | 522 | val blobs1 = new_blobs.foldLeft(blobs)(_ + _) | 
| 523 |         val blobs2 = new_blobs.foldLeft(blobs) { case (map, (a, b)) => map + (a -> b.unchanged) }
 | |
| 69562 
636b3c03a61a
include loaded_files as doc_blobs (without purging);
 wenzelm parents: 
69538diff
changeset | 524 | (Document.Blobs(blobs1), copy(blobs = blobs2)) | 
| 
636b3c03a61a
include loaded_files as doc_blobs (without purging);
 wenzelm parents: 
69538diff
changeset | 525 | } | 
| 
636b3c03a61a
include loaded_files as doc_blobs (without purging);
 wenzelm parents: 
69538diff
changeset | 526 | |
| 75393 | 527 | def blob_edits( | 
| 528 | name: Document.Node.Name, | |
| 76904 
e27d097d7d15
tuned signature: avoid confusion with Document.Node.Blob and Command.Blob;
 wenzelm parents: 
76902diff
changeset | 529 | old_blob: Option[Document.Blobs.Item] | 
| 75393 | 530 |       ) : List[Document.Edit_Text] = {
 | 
| 69562 
636b3c03a61a
include loaded_files as doc_blobs (without purging);
 wenzelm parents: 
69538diff
changeset | 531 |         val blob = blobs.getOrElse(name, error("Missing blob " + quote(name.toString)))
 | 
| 
636b3c03a61a
include loaded_files as doc_blobs (without purging);
 wenzelm parents: 
69538diff
changeset | 532 | val text_edits = | 
| 
636b3c03a61a
include loaded_files as doc_blobs (without purging);
 wenzelm parents: 
69538diff
changeset | 533 |           old_blob match {
 | 
| 
636b3c03a61a
include loaded_files as doc_blobs (without purging);
 wenzelm parents: 
69538diff
changeset | 534 | case None => List(Text.Edit.insert(0, blob.source)) | 
| 
636b3c03a61a
include loaded_files as doc_blobs (without purging);
 wenzelm parents: 
69538diff
changeset | 535 | case Some(blob0) => Text.Edit.replace(0, blob0.source, blob.source) | 
| 
636b3c03a61a
include loaded_files as doc_blobs (without purging);
 wenzelm parents: 
69538diff
changeset | 536 | } | 
| 
636b3c03a61a
include loaded_files as doc_blobs (without purging);
 wenzelm parents: 
69538diff
changeset | 537 | if (text_edits.isEmpty) Nil | 
| 
636b3c03a61a
include loaded_files as doc_blobs (without purging);
 wenzelm parents: 
69538diff
changeset | 538 | else List(name -> Document.Node.Blob(blob), name -> Document.Node.Edits(text_edits)) | 
| 
636b3c03a61a
include loaded_files as doc_blobs (without purging);
 wenzelm parents: 
69538diff
changeset | 539 | } | 
| 
636b3c03a61a
include loaded_files as doc_blobs (without purging);
 wenzelm parents: 
69538diff
changeset | 540 | |
| 
636b3c03a61a
include loaded_files as doc_blobs (without purging);
 wenzelm parents: 
69538diff
changeset | 541 | |
| 
636b3c03a61a
include loaded_files as doc_blobs (without purging);
 wenzelm parents: 
69538diff
changeset | 542 | /* theories */ | 
| 
636b3c03a61a
include loaded_files as doc_blobs (without purging);
 wenzelm parents: 
69538diff
changeset | 543 | |
| 70674 
29bb1ebb188f
clarified signature: proper Document.Node.Ordering conforming to equality (e.g. required in situations where theory names are ambiguous due to overlapping session directories);
 wenzelm parents: 
70657diff
changeset | 544 | lazy val theory_graph: Document.Node.Name.Graph[Unit] = | 
| 
29bb1ebb188f
clarified signature: proper Document.Node.Ordering conforming to equality (e.g. required in situations where theory names are ambiguous due to overlapping session directories);
 wenzelm parents: 
70657diff
changeset | 545 | Document.Node.Name.make_graph( | 
| 69012 | 546 | for ((name, theory) <- theories.toList) | 
| 71601 | 547 | yield ((name, ()), theory.node_header.imports.filter(theories.isDefinedAt))) | 
| 67056 | 548 | |
| 69012 | 549 | def is_required(name: Document.Node.Name): Boolean = required.isDefinedAt(name) | 
| 550 | ||
| 69458 | 551 | def insert_required(id: UUID.T, names: List[Document.Node.Name]): State = | 
| 73359 | 552 | copy(required = names.foldLeft(required)(_.insert(_, id))) | 
| 69012 | 553 | |
| 69458 | 554 | def remove_required(id: UUID.T, names: List[Document.Node.Name]): State = | 
| 73359 | 555 | copy(required = names.foldLeft(required)(_.remove(_, id))) | 
| 68958 | 556 | |
| 76317 | 557 | def update_theories(update: List[Theory]): State = | 
| 69012 | 558 | copy(theories = | 
| 73359 | 559 |           update.foldLeft(theories) {
 | 
| 76317 | 560 | case (thys, thy) => | 
| 561 |               thys.get(thy.node_name) match {
 | |
| 73359 | 562 | case Some(thy1) if thy1 == thy => thys | 
| 76317 | 563 | case _ => thys + (thy.node_name -> thy) | 
| 73359 | 564 | } | 
| 565 | }) | |
| 69012 | 566 | |
| 75393 | 567 |       def remove_theories(remove: List[Document.Node.Name]): State = {
 | 
| 73120 
c3589f2dff31
more informative errors: simplify diagnosis of spurious failures reported by users;
 wenzelm parents: 
72816diff
changeset | 568 | require(remove.forall(name => !is_required(name)), "attempt to remove required nodes") | 
| 69012 | 569 | copy(theories = theories -- remove) | 
| 570 | } | |
| 571 | ||
| 75393 | 572 | def unload_theories( | 
| 573 | id: UUID.T, | |
| 574 | theories: List[Document.Node.Name] | |
| 575 |       ) : (List[Document.Edit_Text], State) = {
 | |
| 70649 | 576 | val st1 = remove_required(id, theories) | 
| 67893 | 577 | val theory_edits = | 
| 69012 | 578 |           for {
 | 
| 70649 | 579 | node_name <- theories | 
| 69012 | 580 | theory <- st1.theories.get(node_name) | 
| 581 | } | |
| 67893 | 582 |           yield {
 | 
| 76312 | 583 | val theory1 = theory.set_required(st1.is_required(node_name)) | 
| 69012 | 584 | val edits = theory1.node_edits(Some(theory)) | 
| 76317 | 585 | (theory1, edits) | 
| 67893 | 586 | } | 
| 76317 | 587 | (theory_edits.flatMap(_._2), st1.update_theories(theory_edits.map(_._1))) | 
| 69012 | 588 | } | 
| 589 | ||
| 75393 | 590 | def purge_theories( | 
| 591 | nodes: Option[List[Document.Node.Name]] | |
| 592 |       ) : ((List[Document.Node.Name], List[Document.Node.Name], List[Document.Edit_Text]), State) = {
 | |
| 69012 | 593 | val all_nodes = theory_graph.topological_order | 
| 71601 | 594 | val purge = nodes.getOrElse(all_nodes).filterNot(is_required).toSet | 
| 69012 | 595 | |
| 596 | val retain = theory_graph.all_preds(all_nodes.filterNot(purge)).toSet | |
| 597 | val (retained, purged) = all_nodes.partition(retain) | |
| 70783 | 598 | val purge_edits = purged.flatMap(name => theories(name).purge_edits) | 
| 69012 | 599 | |
| 70783 | 600 | ((purged, retained, purge_edits), remove_theories(purged)) | 
| 69012 | 601 | } | 
| 602 | } | |
| 68936 
90c08c7bab9c
continuously clean frontier of already committed theories: much less resource requirements;
 wenzelm parents: 
68935diff
changeset | 603 | } | 
| 
90c08c7bab9c
continuously clean frontier of already committed theories: much less resource requirements;
 wenzelm parents: 
68935diff
changeset | 604 | |
| 69536 | 605 | class Resources private[Headless]( | 
| 76665 | 606 | val options: Options, | 
| 607 | session_background: Sessions.Background, | |
| 608 | log: Logger = No_Logger) | |
| 609 |   extends isabelle.Resources(session_background.check_errors, log = log) {
 | |
| 69012 | 610 | resources => | 
| 611 | ||
| 78178 | 612 | val store: Store = Store(options) | 
| 71600 | 613 | |
| 69536 | 614 | |
| 615 | /* session */ | |
| 616 | ||
| 75393 | 617 | def start_session( | 
| 618 | print_mode: List[String] = Nil, | |
| 619 | progress: Progress = new Progress | |
| 620 |     ): Session = {
 | |
| 76656 | 621 | val session_name = session_background.session_name | 
| 75921 
423021c98500
clarified signature: Sessions.Base_Info follows Sessions.Base;
 wenzelm parents: 
75920diff
changeset | 622 | val session = new Session(session_name, options, resources) | 
| 77414 
0d5994eef9e6
clarified signature: allow to provide session_heaps by different means, e.g. from tmp directory or alternative session structure;
 wenzelm parents: 
77168diff
changeset | 623 | val session_heaps = ML_Process.session_heaps(store, session_background, logic = session_name) | 
| 69536 | 624 | |
| 75921 
423021c98500
clarified signature: Sessions.Base_Info follows Sessions.Base;
 wenzelm parents: 
75920diff
changeset | 625 |       progress.echo("Starting session " + session_name + " ...")
 | 
| 77414 
0d5994eef9e6
clarified signature: allow to provide session_heaps by different means, e.g. from tmp directory or alternative session structure;
 wenzelm parents: 
77168diff
changeset | 626 | Isabelle_Process.start( | 
| 
0d5994eef9e6
clarified signature: allow to provide session_heaps by different means, e.g. from tmp directory or alternative session structure;
 wenzelm parents: 
77168diff
changeset | 627 | options, session, session_background, session_heaps, modes = print_mode).await_startup() | 
| 69536 | 628 | |
| 71604 | 629 | session | 
| 69536 | 630 | } | 
| 631 | ||
| 632 | ||
| 633 | /* theories */ | |
| 634 | ||
| 69012 | 635 | private val state = Synchronized(Resources.State()) | 
| 636 | ||
| 637 | def load_theories( | |
| 638 | session: Session, | |
| 69458 | 639 | id: UUID.T, | 
| 70649 | 640 | theories: List[Document.Node.Name], | 
| 641 | files: List[Document.Node.Name], | |
| 69920 | 642 | unicode_symbols: Boolean, | 
| 75393 | 643 | progress: Progress | 
| 644 |     ): Unit = {
 | |
| 69012 | 645 | val loaded_theories = | 
| 70649 | 646 | for (node_name <- theories) | 
| 69012 | 647 |         yield {
 | 
| 648 | val path = node_name.path | |
| 649 |           if (!node_name.is_theory) error("Not a theory file: " + path)
 | |
| 650 | ||
| 651 | progress.expose_interrupt() | |
| 77168 
547d140f0780
more uniform use of Symbol.output, even in situations where its Symbol.encode is usually redundant;
 wenzelm parents: 
77137diff
changeset | 652 | val text = Symbol.output(unicode_symbols, File.read(path)) | 
| 72772 | 653 | val node_header = resources.check_thy(node_name, Scan.char_reader(text)) | 
| 69012 | 654 | new Resources.Theory(node_name, node_header, text, true) | 
| 68936 
90c08c7bab9c
continuously clean frontier of already committed theories: much less resource requirements;
 wenzelm parents: 
68935diff
changeset | 655 | } | 
| 69012 | 656 | |
| 657 | val loaded = loaded_theories.length | |
| 658 |       if (loaded > 1) progress.echo("Loading " + loaded + " theories ...")
 | |
| 659 | ||
| 75394 | 660 |       state.change { st =>
 | 
| 75393 | 661 | val (doc_blobs1, st1) = st.insert_required(id, theories).update_blobs(files) | 
| 662 | val theory_edits = | |
| 663 | for (theory <- loaded_theories) | |
| 664 |           yield {
 | |
| 665 | val node_name = theory.node_name | |
| 76313 
f67e8a557b7d
tuned: clarified old_theory (in contrast to 4d5342898b1);
 wenzelm parents: 
76312diff
changeset | 666 | val old_theory = st.theories.get(node_name) | 
| 76312 | 667 | val theory1 = theory.set_required(st1.is_required(node_name)) | 
| 76313 
f67e8a557b7d
tuned: clarified old_theory (in contrast to 4d5342898b1);
 wenzelm parents: 
76312diff
changeset | 668 | val edits = theory1.node_edits(old_theory) | 
| 76317 | 669 | (theory1, edits) | 
| 75393 | 670 | } | 
| 671 | val file_edits = | |
| 672 |           for { node_name <- files if doc_blobs1.changed(node_name) }
 | |
| 673 | yield st1.blob_edits(node_name, st.blobs.get(node_name)) | |
| 69562 
636b3c03a61a
include loaded_files as doc_blobs (without purging);
 wenzelm parents: 
69538diff
changeset | 674 | |
| 76317 | 675 | session.update(doc_blobs1, theory_edits.flatMap(_._2) ::: file_edits.flatten) | 
| 676 | st1.update_theories(theory_edits.map(_._1)) | |
| 75394 | 677 | } | 
| 69012 | 678 | } | 
| 67936 | 679 | |
| 75393 | 680 |     def unload_theories(session: Session, id: UUID.T, theories: List[Document.Node.Name]): Unit = {
 | 
| 75394 | 681 |       state.change { st =>
 | 
| 75743 | 682 | val (edits, st1) = st.unload_theories(id, theories) | 
| 70783 | 683 | session.update(st.doc_blobs, edits) | 
| 684 | st1 | |
| 75394 | 685 | } | 
| 69012 | 686 | } | 
| 687 | ||
| 75393 | 688 |     def clean_theories(session: Session, id: UUID.T, theories: List[Document.Node.Name]): Unit = {
 | 
| 75394 | 689 |       state.change { st =>
 | 
| 75743 | 690 | val (edits1, st1) = st.unload_theories(id, theories) | 
| 691 | val ((_, _, edits2), st2) = st1.purge_theories(None) | |
| 70783 | 692 | session.update(st.doc_blobs, edits1 ::: edits2) | 
| 693 | st2 | |
| 75394 | 694 | } | 
| 69012 | 695 | } | 
| 696 | ||
| 75393 | 697 | def purge_theories( | 
| 698 | nodes: Option[List[Document.Node.Name]] | |
| 699 |     ) : (List[Document.Node.Name], List[Document.Node.Name]) = {
 | |
| 75394 | 700 |       state.change_result { st =>
 | 
| 75743 | 701 | val ((purged, retained, _), st1) = st.purge_theories(nodes) | 
| 70783 | 702 | ((purged, retained), st1) | 
| 75394 | 703 | } | 
| 69012 | 704 | } | 
| 67936 | 705 | } | 
| 67054 | 706 | } |