src/Pure/Tools/build_process.scala
changeset 77536 7c7f1473e51a
parent 77534 fc57886e37dd
child 77538 fcda9a009213
equal deleted inserted replaced
77535:334a286b2975 77536:7c7f1473e51a
    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