src/Pure/Tools/build_cluster.scala
author wenzelm
Fri, 21 Jul 2023 13:02:07 +0200
changeset 78426 0be7e94fd243
parent 78425 62d7ef1da441
child 78427 5b7d1cb073db
permissions -rw-r--r--
more accurate print vs. parse;
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
78398
ea5adf7acc2d support for management of build cluster;
wenzelm
parents:
diff changeset
     1
/*  Title:      Pure/Tools/build_cluster.scala
ea5adf7acc2d support for management of build cluster;
wenzelm
parents:
diff changeset
     2
    Author:     Makarius
ea5adf7acc2d support for management of build cluster;
wenzelm
parents:
diff changeset
     3
ea5adf7acc2d support for management of build cluster;
wenzelm
parents:
diff changeset
     4
Management of build cluster: independent ssh hosts with access to shared
ea5adf7acc2d support for management of build cluster;
wenzelm
parents:
diff changeset
     5
PostgreSQL server.
ea5adf7acc2d support for management of build cluster;
wenzelm
parents:
diff changeset
     6
*/
ea5adf7acc2d support for management of build cluster;
wenzelm
parents:
diff changeset
     7
ea5adf7acc2d support for management of build cluster;
wenzelm
parents:
diff changeset
     8
package isabelle
ea5adf7acc2d support for management of build cluster;
wenzelm
parents:
diff changeset
     9
ea5adf7acc2d support for management of build cluster;
wenzelm
parents:
diff changeset
    10
ea5adf7acc2d support for management of build cluster;
wenzelm
parents:
diff changeset
    11
object Build_Cluster {
78413
6f3066a9b609 more pro-forma support for Build_Cluster;
wenzelm
parents: 78408
diff changeset
    12
  /* host specifications */
6f3066a9b609 more pro-forma support for Build_Cluster;
wenzelm
parents: 78408
diff changeset
    13
78399
facf1a324807 more operations;
wenzelm
parents: 78398
diff changeset
    14
  object Host {
78408
092f1e435b3a proper Build_Cluster.Host.parse for parameters and system options;
wenzelm
parents: 78401
diff changeset
    15
    private val rfc822_specials = """()<>@,;:\"[]"""
092f1e435b3a proper Build_Cluster.Host.parse for parameters and system options;
wenzelm
parents: 78401
diff changeset
    16
092f1e435b3a proper Build_Cluster.Host.parse for parameters and system options;
wenzelm
parents: 78401
diff changeset
    17
    private val USER = "user"
092f1e435b3a proper Build_Cluster.Host.parse for parameters and system options;
wenzelm
parents: 78401
diff changeset
    18
    private val PORT = "port"
092f1e435b3a proper Build_Cluster.Host.parse for parameters and system options;
wenzelm
parents: 78401
diff changeset
    19
    private val JOBS = "jobs"
092f1e435b3a proper Build_Cluster.Host.parse for parameters and system options;
wenzelm
parents: 78401
diff changeset
    20
    private val NUMA = "numa"
092f1e435b3a proper Build_Cluster.Host.parse for parameters and system options;
wenzelm
parents: 78401
diff changeset
    21
092f1e435b3a proper Build_Cluster.Host.parse for parameters and system options;
wenzelm
parents: 78401
diff changeset
    22
    val parameters: Options =
092f1e435b3a proper Build_Cluster.Host.parse for parameters and system options;
wenzelm
parents: 78401
diff changeset
    23
      Options.inline("""
092f1e435b3a proper Build_Cluster.Host.parse for parameters and system options;
wenzelm
parents: 78401
diff changeset
    24
        option user : string = ""   -- "explicit SSH user"
092f1e435b3a proper Build_Cluster.Host.parse for parameters and system options;
wenzelm
parents: 78401
diff changeset
    25
        option port : int = 0       -- "explicit SSH port"
092f1e435b3a proper Build_Cluster.Host.parse for parameters and system options;
wenzelm
parents: 78401
diff changeset
    26
        option jobs : int = 1       -- "maximum number of parallel jobs"
092f1e435b3a proper Build_Cluster.Host.parse for parameters and system options;
wenzelm
parents: 78401
diff changeset
    27
        option numa : bool = false  -- "cyclic shuffling of NUMA CPU nodes"
092f1e435b3a proper Build_Cluster.Host.parse for parameters and system options;
wenzelm
parents: 78401
diff changeset
    28
      """)
092f1e435b3a proper Build_Cluster.Host.parse for parameters and system options;
wenzelm
parents: 78401
diff changeset
    29
092f1e435b3a proper Build_Cluster.Host.parse for parameters and system options;
wenzelm
parents: 78401
diff changeset
    30
    def is_parameter(spec: Options.Spec): Boolean = parameters.defined(spec.name)
092f1e435b3a proper Build_Cluster.Host.parse for parameters and system options;
wenzelm
parents: 78401
diff changeset
    31
092f1e435b3a proper Build_Cluster.Host.parse for parameters and system options;
wenzelm
parents: 78401
diff changeset
    32
    lazy val test_options: Options = Options.init0()
78399
facf1a324807 more operations;
wenzelm
parents: 78398
diff changeset
    33
facf1a324807 more operations;
wenzelm
parents: 78398
diff changeset
    34
    def apply(
78416
f26eba6281b1 tuned signature;
wenzelm
parents: 78413
diff changeset
    35
      name: String = "",
78408
092f1e435b3a proper Build_Cluster.Host.parse for parameters and system options;
wenzelm
parents: 78401
diff changeset
    36
      user: String = parameters.string(USER),
092f1e435b3a proper Build_Cluster.Host.parse for parameters and system options;
wenzelm
parents: 78401
diff changeset
    37
      port: Int = parameters.int(PORT),
092f1e435b3a proper Build_Cluster.Host.parse for parameters and system options;
wenzelm
parents: 78401
diff changeset
    38
      jobs: Int = parameters.int(JOBS),
092f1e435b3a proper Build_Cluster.Host.parse for parameters and system options;
wenzelm
parents: 78401
diff changeset
    39
      numa: Boolean = parameters.bool(NUMA),
78399
facf1a324807 more operations;
wenzelm
parents: 78398
diff changeset
    40
      options: List[Options.Spec] = Nil
78416
f26eba6281b1 tuned signature;
wenzelm
parents: 78413
diff changeset
    41
    ): Host = new Host(name, user, port, jobs, numa, options)
78401
822ddccda899 proforma support for remote build hosts;
wenzelm
parents: 78399
diff changeset
    42
78408
092f1e435b3a proper Build_Cluster.Host.parse for parameters and system options;
wenzelm
parents: 78401
diff changeset
    43
    def parse(str: String): Host = {
78416
f26eba6281b1 tuned signature;
wenzelm
parents: 78413
diff changeset
    44
      val name = str.takeWhile(c => !rfc822_specials.contains(c))
78408
092f1e435b3a proper Build_Cluster.Host.parse for parameters and system options;
wenzelm
parents: 78401
diff changeset
    45
      val (params, options) =
092f1e435b3a proper Build_Cluster.Host.parse for parameters and system options;
wenzelm
parents: 78401
diff changeset
    46
        try {
092f1e435b3a proper Build_Cluster.Host.parse for parameters and system options;
wenzelm
parents: 78401
diff changeset
    47
          val rest = {
092f1e435b3a proper Build_Cluster.Host.parse for parameters and system options;
wenzelm
parents: 78401
diff changeset
    48
            val n = str.length
78416
f26eba6281b1 tuned signature;
wenzelm
parents: 78413
diff changeset
    49
            val m = name.length
78408
092f1e435b3a proper Build_Cluster.Host.parse for parameters and system options;
wenzelm
parents: 78401
diff changeset
    50
            val l =
092f1e435b3a proper Build_Cluster.Host.parse for parameters and system options;
wenzelm
parents: 78401
diff changeset
    51
              if (m == n) n
092f1e435b3a proper Build_Cluster.Host.parse for parameters and system options;
wenzelm
parents: 78401
diff changeset
    52
              else if (str(m) == ':') m + 1
78423
645b54f3244a tuned output;
wenzelm
parents: 78421
diff changeset
    53
              else error("Missing \":\" after host name")
78408
092f1e435b3a proper Build_Cluster.Host.parse for parameters and system options;
wenzelm
parents: 78401
diff changeset
    54
            str.substring(l)
092f1e435b3a proper Build_Cluster.Host.parse for parameters and system options;
wenzelm
parents: 78401
diff changeset
    55
          }
092f1e435b3a proper Build_Cluster.Host.parse for parameters and system options;
wenzelm
parents: 78401
diff changeset
    56
          val (specs1, specs2) = Options.parse_specs(rest).partition(is_parameter)
092f1e435b3a proper Build_Cluster.Host.parse for parameters and system options;
wenzelm
parents: 78401
diff changeset
    57
          (parameters ++ specs1, { test_options ++ specs2; specs2 })
092f1e435b3a proper Build_Cluster.Host.parse for parameters and system options;
wenzelm
parents: 78401
diff changeset
    58
        }
092f1e435b3a proper Build_Cluster.Host.parse for parameters and system options;
wenzelm
parents: 78401
diff changeset
    59
        catch {
092f1e435b3a proper Build_Cluster.Host.parse for parameters and system options;
wenzelm
parents: 78401
diff changeset
    60
          case ERROR(msg) =>
092f1e435b3a proper Build_Cluster.Host.parse for parameters and system options;
wenzelm
parents: 78401
diff changeset
    61
            cat_error(msg, "The error(s) above occurred in host specification " + quote(str))
092f1e435b3a proper Build_Cluster.Host.parse for parameters and system options;
wenzelm
parents: 78401
diff changeset
    62
        }
78416
f26eba6281b1 tuned signature;
wenzelm
parents: 78413
diff changeset
    63
      apply(name = name,
78408
092f1e435b3a proper Build_Cluster.Host.parse for parameters and system options;
wenzelm
parents: 78401
diff changeset
    64
        user = params.string(USER),
092f1e435b3a proper Build_Cluster.Host.parse for parameters and system options;
wenzelm
parents: 78401
diff changeset
    65
        port = params.int(PORT),
092f1e435b3a proper Build_Cluster.Host.parse for parameters and system options;
wenzelm
parents: 78401
diff changeset
    66
        jobs = params.int(JOBS),
092f1e435b3a proper Build_Cluster.Host.parse for parameters and system options;
wenzelm
parents: 78401
diff changeset
    67
        numa = params.bool(NUMA),
092f1e435b3a proper Build_Cluster.Host.parse for parameters and system options;
wenzelm
parents: 78401
diff changeset
    68
        options = options)
092f1e435b3a proper Build_Cluster.Host.parse for parameters and system options;
wenzelm
parents: 78401
diff changeset
    69
    }
78426
0be7e94fd243 more accurate print vs. parse;
wenzelm
parents: 78425
diff changeset
    70
0be7e94fd243 more accurate print vs. parse;
wenzelm
parents: 78425
diff changeset
    71
    def print_name(s: String): String =
0be7e94fd243 more accurate print vs. parse;
wenzelm
parents: 78425
diff changeset
    72
      Token.quote_name(Options.specs_syntax.keywords, s)
0be7e94fd243 more accurate print vs. parse;
wenzelm
parents: 78425
diff changeset
    73
0be7e94fd243 more accurate print vs. parse;
wenzelm
parents: 78425
diff changeset
    74
    def print_option(spec: Options.Spec): String = {
0be7e94fd243 more accurate print vs. parse;
wenzelm
parents: 78425
diff changeset
    75
      def print_value =
0be7e94fd243 more accurate print vs. parse;
wenzelm
parents: 78425
diff changeset
    76
        spec.value.get match {
0be7e94fd243 more accurate print vs. parse;
wenzelm
parents: 78425
diff changeset
    77
          case s@Value.Boolean(_) => s
0be7e94fd243 more accurate print vs. parse;
wenzelm
parents: 78425
diff changeset
    78
          case s@Value.Long(_) => s
0be7e94fd243 more accurate print vs. parse;
wenzelm
parents: 78425
diff changeset
    79
          case s@Value.Double(_) => s
0be7e94fd243 more accurate print vs. parse;
wenzelm
parents: 78425
diff changeset
    80
          case s => print_name(s)
0be7e94fd243 more accurate print vs. parse;
wenzelm
parents: 78425
diff changeset
    81
        }
0be7e94fd243 more accurate print vs. parse;
wenzelm
parents: 78425
diff changeset
    82
      spec.name + if_proper(spec.value, "=" + print_value)
0be7e94fd243 more accurate print vs. parse;
wenzelm
parents: 78425
diff changeset
    83
    }
78399
facf1a324807 more operations;
wenzelm
parents: 78398
diff changeset
    84
  }
facf1a324807 more operations;
wenzelm
parents: 78398
diff changeset
    85
facf1a324807 more operations;
wenzelm
parents: 78398
diff changeset
    86
  final class Host private(
78416
f26eba6281b1 tuned signature;
wenzelm
parents: 78413
diff changeset
    87
    name: String,
78399
facf1a324807 more operations;
wenzelm
parents: 78398
diff changeset
    88
    user: String,
facf1a324807 more operations;
wenzelm
parents: 78398
diff changeset
    89
    port: Int,
facf1a324807 more operations;
wenzelm
parents: 78398
diff changeset
    90
    jobs: Int,
facf1a324807 more operations;
wenzelm
parents: 78398
diff changeset
    91
    numa: Boolean,
facf1a324807 more operations;
wenzelm
parents: 78398
diff changeset
    92
    options: List[Options.Spec]
facf1a324807 more operations;
wenzelm
parents: 78398
diff changeset
    93
  ) {
78425
62d7ef1da441 clarified signature;
wenzelm
parents: 78424
diff changeset
    94
    def is_local: Boolean = SSH.is_local(name)
78413
6f3066a9b609 more pro-forma support for Build_Cluster;
wenzelm
parents: 78408
diff changeset
    95
78408
092f1e435b3a proper Build_Cluster.Host.parse for parameters and system options;
wenzelm
parents: 78401
diff changeset
    96
    override def toString: String = print
78399
facf1a324807 more operations;
wenzelm
parents: 78398
diff changeset
    97
facf1a324807 more operations;
wenzelm
parents: 78398
diff changeset
    98
    def print: String = {
78408
092f1e435b3a proper Build_Cluster.Host.parse for parameters and system options;
wenzelm
parents: 78401
diff changeset
    99
      val params =
78399
facf1a324807 more operations;
wenzelm
parents: 78398
diff changeset
   100
        List(
78426
0be7e94fd243 more accurate print vs. parse;
wenzelm
parents: 78425
diff changeset
   101
          if (user.isEmpty) "" else Properties.Eq(Host.USER, Host.print_name(user)),
78399
facf1a324807 more operations;
wenzelm
parents: 78398
diff changeset
   102
          if (port == 0) "" else Properties.Eq(Host.PORT, port.toString),
facf1a324807 more operations;
wenzelm
parents: 78398
diff changeset
   103
          if (jobs == 1) "" else Properties.Eq(Host.JOBS, jobs.toString),
facf1a324807 more operations;
wenzelm
parents: 78398
diff changeset
   104
          if_proper(numa, Host.NUMA)
facf1a324807 more operations;
wenzelm
parents: 78398
diff changeset
   105
        ).filter(_.nonEmpty)
78426
0be7e94fd243 more accurate print vs. parse;
wenzelm
parents: 78425
diff changeset
   106
      val rest = (params ::: options.map(Host.print_option)).mkString(",")
78408
092f1e435b3a proper Build_Cluster.Host.parse for parameters and system options;
wenzelm
parents: 78401
diff changeset
   107
78425
62d7ef1da441 clarified signature;
wenzelm
parents: 78424
diff changeset
   108
      SSH.print_local(name) + if_proper(rest, ":" + rest)
78399
facf1a324807 more operations;
wenzelm
parents: 78398
diff changeset
   109
    }
facf1a324807 more operations;
wenzelm
parents: 78398
diff changeset
   110
facf1a324807 more operations;
wenzelm
parents: 78398
diff changeset
   111
    def open_ssh_session(options: Options): SSH.Session =
78416
f26eba6281b1 tuned signature;
wenzelm
parents: 78413
diff changeset
   112
      SSH.open_session(options, name, port = port, user = user)
78399
facf1a324807 more operations;
wenzelm
parents: 78398
diff changeset
   113
  }
78413
6f3066a9b609 more pro-forma support for Build_Cluster;
wenzelm
parents: 78408
diff changeset
   114
6f3066a9b609 more pro-forma support for Build_Cluster;
wenzelm
parents: 78408
diff changeset
   115
6f3066a9b609 more pro-forma support for Build_Cluster;
wenzelm
parents: 78408
diff changeset
   116
  /* remote sessions */
6f3066a9b609 more pro-forma support for Build_Cluster;
wenzelm
parents: 78408
diff changeset
   117
6f3066a9b609 more pro-forma support for Build_Cluster;
wenzelm
parents: 78408
diff changeset
   118
  class Session(host: Host) extends AutoCloseable {
6f3066a9b609 more pro-forma support for Build_Cluster;
wenzelm
parents: 78408
diff changeset
   119
    override def close(): Unit = ()
6f3066a9b609 more pro-forma support for Build_Cluster;
wenzelm
parents: 78408
diff changeset
   120
  }
78398
ea5adf7acc2d support for management of build cluster;
wenzelm
parents:
diff changeset
   121
}
78413
6f3066a9b609 more pro-forma support for Build_Cluster;
wenzelm
parents: 78408
diff changeset
   122
6f3066a9b609 more pro-forma support for Build_Cluster;
wenzelm
parents: 78408
diff changeset
   123
// class extensible via Build.Engine.build_process() and Build_Process.init_cluster()
6f3066a9b609 more pro-forma support for Build_Cluster;
wenzelm
parents: 78408
diff changeset
   124
class Build_Cluster(
78421
fd24f380b588 clarified modules;
wenzelm
parents: 78416
diff changeset
   125
  build_context: Build.Context,
78413
6f3066a9b609 more pro-forma support for Build_Cluster;
wenzelm
parents: 78408
diff changeset
   126
  remote_hosts: List[Build_Cluster.Host],
6f3066a9b609 more pro-forma support for Build_Cluster;
wenzelm
parents: 78408
diff changeset
   127
  progress: Progress = new Progress
6f3066a9b609 more pro-forma support for Build_Cluster;
wenzelm
parents: 78408
diff changeset
   128
) extends AutoCloseable {
78424
e5908be41a36 clarified signature (again);
wenzelm
parents: 78423
diff changeset
   129
  require(remote_hosts.nonEmpty && !remote_hosts.exists(_.is_local), "remote hosts required")
78413
6f3066a9b609 more pro-forma support for Build_Cluster;
wenzelm
parents: 78408
diff changeset
   130
6f3066a9b609 more pro-forma support for Build_Cluster;
wenzelm
parents: 78408
diff changeset
   131
  override def toString: String = remote_hosts.mkString("Build_Cluster(", ", ", ")")
6f3066a9b609 more pro-forma support for Build_Cluster;
wenzelm
parents: 78408
diff changeset
   132
6f3066a9b609 more pro-forma support for Build_Cluster;
wenzelm
parents: 78408
diff changeset
   133
  progress.echo("Remote hosts:\n" + cat_lines(remote_hosts.map("  " + _)))
6f3066a9b609 more pro-forma support for Build_Cluster;
wenzelm
parents: 78408
diff changeset
   134
6f3066a9b609 more pro-forma support for Build_Cluster;
wenzelm
parents: 78408
diff changeset
   135
  def start(): Unit = ()
6f3066a9b609 more pro-forma support for Build_Cluster;
wenzelm
parents: 78408
diff changeset
   136
  def stop(): Unit = ()
6f3066a9b609 more pro-forma support for Build_Cluster;
wenzelm
parents: 78408
diff changeset
   137
6f3066a9b609 more pro-forma support for Build_Cluster;
wenzelm
parents: 78408
diff changeset
   138
  override def close(): Unit = ()
6f3066a9b609 more pro-forma support for Build_Cluster;
wenzelm
parents: 78408
diff changeset
   139
}