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)))) |