src/Pure/Tools/build_schedule.scala
changeset 79190 2039f3609884
parent 79189 f52201fc15b4
child 79191 ee405c40db72
equal deleted inserted replaced
79189:f52201fc15b4 79190:2039f3609884
   433     type Graph = isabelle.Graph[String, Node]
   433     type Graph = isabelle.Graph[String, Node]
   434 
   434 
   435     def init(build_uuid: String): Schedule = Schedule(build_uuid, "none", Date.now(), Graph.empty)
   435     def init(build_uuid: String): Schedule = Schedule(build_uuid, "none", Date.now(), Graph.empty)
   436   }
   436   }
   437 
   437 
   438   case class Schedule(build_uuid: String, generator: String, start: Date, graph: Schedule.Graph) {
   438   case class Schedule(
       
   439     build_uuid: String,
       
   440     generator: String,
       
   441     start: Date,
       
   442     graph: Schedule.Graph,
       
   443     serial: Long = 0,
       
   444   ) {
       
   445     require(serial >= 0, "serial underflow")
       
   446     def inc_serial: Schedule = {
       
   447       require(serial < Long.MaxValue, "serial overflow")
       
   448       copy(serial = serial + 1)
       
   449     }
       
   450     
   439     def end: Date =
   451     def end: Date =
   440       if (graph.is_empty) start
   452       if (graph.is_empty) start
   441       else graph.maximals.map(graph.get_node).map(_.end).maxBy(_.unix_epoch)
   453       else graph.maximals.map(graph.get_node).map(_.end).maxBy(_.unix_epoch)
   442 
   454 
   443     def duration: Time = end.time - start.time
   455     def duration: Time = end.time - start.time
   812           case Some(db) =>
   824           case Some(db) =>
   813             Build_Schedule.private_data.transaction_lock(db, label = label) {
   825             Build_Schedule.private_data.transaction_lock(db, label = label) {
   814               val old_schedule = Build_Schedule.private_data.pull_schedule(db, _schedule)
   826               val old_schedule = Build_Schedule.private_data.pull_schedule(db, _schedule)
   815               _schedule = old_schedule
   827               _schedule = old_schedule
   816               val res = body
   828               val res = body
   817               Build_Schedule.private_data.update_schedule(db, _schedule)
   829               _schedule = Build_Schedule.private_data.update_schedule(db, _schedule, old_schedule)
   818               res
   830               res
   819             }
   831             }
   820         }
   832         }
   821       }
   833       }
   822 
   834 
   966 
   978 
   967     object Schedules {
   979     object Schedules {
   968       val build_uuid = Generic.build_uuid.make_primary_key
   980       val build_uuid = Generic.build_uuid.make_primary_key
   969       val generator = SQL.Column.string("generator")
   981       val generator = SQL.Column.string("generator")
   970       val start = SQL.Column.date("start")
   982       val start = SQL.Column.date("start")
   971 
   983       val serial = SQL.Column.long("serial")
   972       val table = make_table(List(build_uuid, generator, start), name = "schedules")
   984 
   973     }
   985       val table = make_table(List(build_uuid, generator, start, serial), name = "schedules")
       
   986     }
       
   987 
       
   988     def read_serial(db: SQL.Database, build_uuid: String = ""): Long =
       
   989       db.execute_query_statementO[Long](
       
   990         Schedules.table.select(List(Schedules.serial.max), sql = 
       
   991           SQL.where(if_proper(build_uuid, Schedules.build_uuid.equal(build_uuid)))),
       
   992           _.long(Schedules.serial)).getOrElse(0L)
   974 
   993 
   975     def read_scheduled_builds_domain(db: SQL.Database): List[String] =
   994     def read_scheduled_builds_domain(db: SQL.Database): List[String] =
   976       db.execute_query_statement(
   995       db.execute_query_statement(
   977         Schedules.table.select(List(Schedules.build_uuid)),
   996         Schedules.table.select(List(Schedules.build_uuid)),
   978         List.from[String], res => res.string(Schedules.build_uuid))
   997         List.from[String], res => res.string(Schedules.build_uuid))
   993         val nodes = private_data.read_nodes(db, build_uuid = schedule.build_uuid)
  1012         val nodes = private_data.read_nodes(db, build_uuid = schedule.build_uuid)
   994         schedule.copy(graph = Graph.make(nodes))
  1013         schedule.copy(graph = Graph.make(nodes))
   995       }
  1014       }
   996     }
  1015     }
   997 
  1016 
   998     def update_schedule(db: SQL.Database, schedule: Schedule): Unit = {
  1017     def write_schedule(db: SQL.Database, schedule: Schedule): Unit = {
   999       db.execute_statement(
  1018       db.execute_statement(
  1000         Schedules.table.delete(Schedules.build_uuid.where_equal(schedule.build_uuid)))
  1019         Schedules.table.delete(Schedules.build_uuid.where_equal(schedule.build_uuid)))
  1001       db.execute_statement(Schedules.table.insert(), { stmt =>
  1020       db.execute_statement(Schedules.table.insert(), { stmt =>
  1002         stmt.string(1) = schedule.build_uuid
  1021         stmt.string(1) = schedule.build_uuid
  1003         stmt.string(2) = schedule.generator
  1022         stmt.string(2) = schedule.generator
  1004         stmt.date(3) = schedule.start
  1023         stmt.date(3) = schedule.start
       
  1024         stmt.long(4) = schedule.serial
  1005       })
  1025       })
  1006       update_nodes(db, schedule.build_uuid, schedule.graph.dest)
  1026       update_nodes(db, schedule.build_uuid, schedule.graph.dest)
  1007     }
  1027     }
  1008 
  1028 
  1009 
  1029 
  1060           stmt.date(7) = node.start
  1080           stmt.date(7) = node.start
  1061           stmt.long(8) = node.duration.ms
  1081           stmt.long(8) = node.duration.ms
  1062         })
  1082         })
  1063     }
  1083     }
  1064 
  1084 
  1065     def pull_schedule(
  1085     def pull_schedule(db: SQL.Database, old_schedule: Schedule): Build_Schedule.Schedule = {
  1066       db: SQL.Database,
  1086       val serial_db = read_serial(db)
  1067       schedule: Schedule,
  1087       if (serial_db == old_schedule.serial) old_schedule
  1068     ): Build_Schedule.Schedule =
  1088       else {
  1069       read_schedules(db, schedule.build_uuid) match {
  1089         read_schedules(db, old_schedule.build_uuid) match {
  1070         case Nil => schedule
  1090           case Nil => old_schedule
  1071         case schedules => Library.the_single(schedules)
  1091           case schedules => Library.the_single(schedules)
  1072       }
  1092         }
       
  1093       }
       
  1094     }
       
  1095 
       
  1096     def update_schedule(db: SQL.Database, schedule: Schedule, old_schedule: Schedule): Schedule = {
       
  1097       val changed =
       
  1098         schedule.generator != old_schedule.generator ||
       
  1099         schedule.start != old_schedule.start ||
       
  1100         schedule.graph != old_schedule.graph
       
  1101       
       
  1102       val schedule1 =
       
  1103         if (changed) schedule.copy(serial = old_schedule.serial).inc_serial else schedule
       
  1104       if (schedule1.serial != schedule.serial) write_schedule(db, schedule1)
       
  1105       
       
  1106       schedule1
       
  1107     }
  1073 
  1108 
  1074     def remove_schedules(db: SQL.Database, remove: List[String]): Unit =
  1109     def remove_schedules(db: SQL.Database, remove: List[String]): Unit =
  1075       if (remove.nonEmpty) {
  1110       if (remove.nonEmpty) {
  1076         val sql = Generic.build_uuid.where_member(remove)
  1111         val sql = Generic.build_uuid.where_member(remove)
  1077         db.execute_statement(SQL.MULTI(tables.map(_.delete(sql = sql))))
  1112         db.execute_statement(SQL.MULTI(tables.map(_.delete(sql = sql))))