19 object Context { |
19 object Context { |
20 def apply( |
20 def apply( |
21 store: Sessions.Store, |
21 store: Sessions.Store, |
22 build_deps: Sessions.Deps, |
22 build_deps: Sessions.Deps, |
23 progress: Progress = new Progress, |
23 progress: Progress = new Progress, |
|
24 ml_platform: String = Isabelle_System.getenv("ML_PLATFORM"), |
24 hostname: String = Isabelle_System.hostname(), |
25 hostname: String = Isabelle_System.hostname(), |
25 numa_shuffling: Boolean = false, |
26 numa_shuffling: Boolean = false, |
26 build_heap: Boolean = false, |
27 build_heap: Boolean = false, |
27 max_jobs: Int = 1, |
28 max_jobs: Int = 1, |
28 fresh_build: Boolean = false, |
29 fresh_build: Boolean = false, |
78 case ord => ord |
79 case ord => ord |
79 } |
80 } |
80 } |
81 } |
81 |
82 |
82 val numa_nodes = Host.numa_nodes(enabled = numa_shuffling) |
83 val numa_nodes = Host.numa_nodes(enabled = numa_shuffling) |
83 new Context(store, build_deps, sessions, ordering, hostname, numa_nodes, |
84 new Context(store, build_deps, sessions, ordering, ml_platform, hostname, numa_nodes, |
84 build_heap = build_heap, max_jobs = max_jobs, fresh_build = fresh_build, |
85 build_heap = build_heap, max_jobs = max_jobs, fresh_build = fresh_build, |
85 no_build = no_build, session_setup, build_uuid = build_uuid) |
86 no_build = no_build, session_setup, build_uuid = build_uuid) |
86 } |
87 } |
87 } |
88 } |
88 |
89 |
89 final class Context private( |
90 final class Context private( |
90 val store: Sessions.Store, |
91 val store: Sessions.Store, |
91 val build_deps: Sessions.Deps, |
92 val build_deps: Sessions.Deps, |
92 val sessions: State.Sessions, |
93 val sessions: State.Sessions, |
93 val ordering: Ordering[String], |
94 val ordering: Ordering[String], |
|
95 val ml_platform: String, |
94 val hostname: String, |
96 val hostname: String, |
95 val numa_nodes: List[Int], |
97 val numa_nodes: List[Int], |
96 val build_heap: Boolean, |
98 val build_heap: Boolean, |
97 val max_jobs: Int, |
99 val max_jobs: Int, |
98 val fresh_build: Boolean, |
100 val fresh_build: Boolean, |
120 val db = SQLite.open_database(Build_Process.Data.database) |
122 val db = SQLite.open_database(Build_Process.Data.database) |
121 try { Isabelle_System.chmod("600", Build_Process.Data.database) } |
123 try { Isabelle_System.chmod("600", Build_Process.Data.database) } |
122 catch { case exn: Throwable => db.close(); throw exn } |
124 catch { case exn: Throwable => db.close(); throw exn } |
123 Some(db) |
125 Some(db) |
124 } |
126 } |
|
127 |
|
128 def prepare_database(): Unit = { |
|
129 using_option(open_database()) { db => |
|
130 db.transaction { for (table <- Data.all_tables) db.create_table(table) } |
|
131 db.rebuild() |
|
132 } |
|
133 } |
125 |
134 |
126 def store_heap(name: String): Boolean = |
135 def store_heap(name: String): Boolean = |
127 build_heap || Sessions.is_pure(name) || |
136 build_heap || Sessions.is_pure(name) || |
128 sessions.valuesIterator.exists(_.ancestors.contains(name)) |
137 sessions.valuesIterator.exists(_.ancestors.contains(name)) |
129 } |
138 } |
254 if_proper(worker_uuid, Generic.worker_uuid.equal(worker_uuid)), |
263 if_proper(worker_uuid, Generic.worker_uuid.equal(worker_uuid)), |
255 if_proper(name, Generic.name.equal(name)), |
264 if_proper(name, Generic.name.equal(name)), |
256 if_proper(names, Generic.name.member(names))) |
265 if_proper(names, Generic.name.member(names))) |
257 } |
266 } |
258 |
267 |
|
268 |
|
269 /* base table */ |
|
270 |
259 object Base { |
271 object Base { |
260 val build_uuid = Generic.build_uuid.make_primary_key |
272 val build_uuid = Generic.build_uuid.make_primary_key |
261 val ml_platform = SQL.Column.string("ml_platform") |
273 val ml_platform = SQL.Column.string("ml_platform") |
262 val options = SQL.Column.string("options") |
274 val options = SQL.Column.string("options") |
263 |
275 val start = SQL.Column.date("start") |
264 val table = make_table("", List(build_uuid, ml_platform, options)) |
276 |
|
277 val table = make_table("", List(build_uuid, ml_platform, options, start)) |
|
278 } |
|
279 |
|
280 def start_build( |
|
281 db: SQL.Database, |
|
282 build_uuid: String, |
|
283 ml_platform: String, |
|
284 options: String |
|
285 ): Unit = { |
|
286 db.using_statement(Base.table.insert()) { stmt => |
|
287 stmt.string(1) = build_uuid |
|
288 stmt.string(2) = ml_platform |
|
289 stmt.string(3) = options |
|
290 stmt.date(4) = db.now() |
|
291 stmt.execute() |
|
292 } |
265 } |
293 } |
266 |
294 |
267 |
295 |
268 /* sessions */ |
296 /* sessions */ |
269 |
297 |
581 Pending.table, |
609 Pending.table, |
582 Running.table, |
610 Running.table, |
583 Results.table, |
611 Results.table, |
584 Host.Data.Node_Info.table) |
612 Host.Data.Node_Info.table) |
585 |
613 |
586 def init_database(db: SQL.Database, build_context: Build_Process.Context): Unit = { |
|
587 for (table <- all_tables) db.create_table(table) |
|
588 |
|
589 val old_pending = Data.read_pending(db) |
|
590 if (old_pending.nonEmpty) { |
|
591 error("Cannot init build process, because of unfinished " + |
|
592 commas_quote(old_pending.map(_.name))) |
|
593 } |
|
594 |
|
595 for (table <- all_tables) db.using_statement(table.delete())(_.execute()) |
|
596 |
|
597 db.using_statement(Base.table.insert()) { stmt => |
|
598 stmt.string(1) = build_context.build_uuid |
|
599 stmt.string(2) = Isabelle_System.getenv("ML_PLATFORM") |
|
600 stmt.string(3) = build_context.store.options.make_prefs(Options.init(prefs = "")) |
|
601 stmt.execute() |
|
602 } |
|
603 } |
|
604 |
|
605 def update_database( |
614 def update_database( |
606 db: SQL.Database, |
615 db: SQL.Database, |
607 worker_uuid: String, |
616 worker_uuid: String, |
608 build_uuid: String, |
617 build_uuid: String, |
609 hostname: String, |
618 hostname: String, |
650 |
659 |
651 private val _database: Option[SQL.Database] = build_context.open_database() |
660 private val _database: Option[SQL.Database] = build_context.open_database() |
652 |
661 |
653 def close(): Unit = synchronized { _database.foreach(_.close()) } |
662 def close(): Unit = synchronized { _database.foreach(_.close()) } |
654 |
663 |
655 private def setup_database(): Unit = |
|
656 synchronized { |
|
657 for (db <- _database) { |
|
658 db.transaction { Build_Process.Data.init_database(db, build_context) } |
|
659 db.rebuild() |
|
660 } |
|
661 } |
|
662 |
|
663 protected def synchronized_database[A](body: => A): A = |
664 protected def synchronized_database[A](body: => A): A = |
664 synchronized { |
665 synchronized { |
665 _database match { |
666 _database match { |
666 case None => body |
667 case None => body |
667 case Some(db) => db.transaction { body } |
668 case Some(db) => db.transaction { body } |
795 |
796 |
796 /* run */ |
797 /* run */ |
797 |
798 |
798 def run(): Map[String, Process_Result] = { |
799 def run(): Map[String, Process_Result] = { |
799 def finished(): Boolean = synchronized_database { _state.finished } |
800 def finished(): Boolean = synchronized_database { _state.finished } |
|
801 |
|
802 def init(): Unit = synchronized_database { |
|
803 for (db <- _database) { |
|
804 Build_Process.Data.start_build(db, build_uuid, build_context.ml_platform, |
|
805 store.options.make_prefs(Options.init(prefs = ""))) |
|
806 } |
|
807 } |
800 |
808 |
801 def sleep(): Unit = |
809 def sleep(): Unit = |
802 Isabelle_Thread.interrupt_handler(_ => progress.stop()) { |
810 Isabelle_Thread.interrupt_handler(_ => progress.stop()) { |
803 build_options.seconds("editor_input_delay").sleep() |
811 build_options.seconds("editor_input_delay").sleep() |
804 } |
812 } |
818 if (finished()) { |
826 if (finished()) { |
819 progress.echo_warning("Nothing to build") |
827 progress.echo_warning("Nothing to build") |
820 Map.empty[String, Process_Result] |
828 Map.empty[String, Process_Result] |
821 } |
829 } |
822 else { |
830 else { |
823 setup_database() |
831 init() |
824 while (!finished()) { |
832 while (!finished()) { |
825 if (progress.stopped) synchronized_database { _state.stop_running() } |
833 if (progress.stopped) synchronized_database { _state.stop_running() } |
826 |
834 |
827 for (job <- synchronized_database { _state.finished_running() }) { |
835 for (job <- synchronized_database { _state.finished_running() }) { |
828 val job_name = job.job_name |
836 val job_name = job.job_name |