src/Pure/ML/ml_heap.scala
author wenzelm
Wed, 21 Feb 2024 19:54:17 +0100
changeset 79683 ade429ddb1fc
parent 79682 1fa1b32b0379
child 79685 45af93b0370a
permissions -rw-r--r--
more accurate types;
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
76991
6a078c80eab6 clarified modules;
wenzelm
parents:
diff changeset
     1
/*  Title:      Pure/ML/ml_heap.scala
6a078c80eab6 clarified modules;
wenzelm
parents:
diff changeset
     2
    Author:     Makarius
6a078c80eab6 clarified modules;
wenzelm
parents:
diff changeset
     3
6a078c80eab6 clarified modules;
wenzelm
parents:
diff changeset
     4
ML heap operations.
6a078c80eab6 clarified modules;
wenzelm
parents:
diff changeset
     5
*/
6a078c80eab6 clarified modules;
wenzelm
parents:
diff changeset
     6
6a078c80eab6 clarified modules;
wenzelm
parents:
diff changeset
     7
package isabelle
6a078c80eab6 clarified modules;
wenzelm
parents:
diff changeset
     8
6a078c80eab6 clarified modules;
wenzelm
parents:
diff changeset
     9
6a078c80eab6 clarified modules;
wenzelm
parents:
diff changeset
    10
import java.nio.ByteBuffer
6a078c80eab6 clarified modules;
wenzelm
parents:
diff changeset
    11
import java.nio.channels.FileChannel
6a078c80eab6 clarified modules;
wenzelm
parents:
diff changeset
    12
import java.nio.file.StandardOpenOption
6a078c80eab6 clarified modules;
wenzelm
parents:
diff changeset
    13
6a078c80eab6 clarified modules;
wenzelm
parents:
diff changeset
    14
6a078c80eab6 clarified modules;
wenzelm
parents:
diff changeset
    15
object ML_Heap {
6a078c80eab6 clarified modules;
wenzelm
parents:
diff changeset
    16
  /** heap file with SHA1 digest **/
6a078c80eab6 clarified modules;
wenzelm
parents:
diff changeset
    17
6a078c80eab6 clarified modules;
wenzelm
parents:
diff changeset
    18
  private val sha1_prefix = "SHA1:"
6a078c80eab6 clarified modules;
wenzelm
parents:
diff changeset
    19
78182
31835adf148a tuned signature;
wenzelm
parents: 77720
diff changeset
    20
  def read_file_digest(heap: Path): Option[SHA1.Digest] = {
76991
6a078c80eab6 clarified modules;
wenzelm
parents:
diff changeset
    21
    if (heap.is_file) {
77711
25fd62cba347 clarified signature: more general operation Bytes.read_slice;
wenzelm
parents: 77206
diff changeset
    22
      val l = sha1_prefix.length
25fd62cba347 clarified signature: more general operation Bytes.read_slice;
wenzelm
parents: 77206
diff changeset
    23
      val m = l + SHA1.digest_length
78958
c125f75a5144 more robust: prefer strict operations;
wenzelm
parents: 78956
diff changeset
    24
      val n = File.size(heap)
78953
b6116a86d2ac clarified signature;
wenzelm
parents: 78510
diff changeset
    25
      val bs = Bytes.read_file(heap, offset = n - m)
77711
25fd62cba347 clarified signature: more general operation Bytes.read_slice;
wenzelm
parents: 77206
diff changeset
    26
      if (bs.length == m) {
25fd62cba347 clarified signature: more general operation Bytes.read_slice;
wenzelm
parents: 77206
diff changeset
    27
        val s = bs.text
25fd62cba347 clarified signature: more general operation Bytes.read_slice;
wenzelm
parents: 77206
diff changeset
    28
        if (s.startsWith(sha1_prefix)) Some(SHA1.fake_digest(s.substring(l)))
76991
6a078c80eab6 clarified modules;
wenzelm
parents:
diff changeset
    29
        else None
6a078c80eab6 clarified modules;
wenzelm
parents:
diff changeset
    30
      }
77711
25fd62cba347 clarified signature: more general operation Bytes.read_slice;
wenzelm
parents: 77206
diff changeset
    31
      else None
76991
6a078c80eab6 clarified modules;
wenzelm
parents:
diff changeset
    32
    }
6a078c80eab6 clarified modules;
wenzelm
parents:
diff changeset
    33
    else None
6a078c80eab6 clarified modules;
wenzelm
parents:
diff changeset
    34
  }
6a078c80eab6 clarified modules;
wenzelm
parents:
diff changeset
    35
78182
31835adf148a tuned signature;
wenzelm
parents: 77720
diff changeset
    36
  def write_file_digest(heap: Path): SHA1.Digest =
31835adf148a tuned signature;
wenzelm
parents: 77720
diff changeset
    37
    read_file_digest(heap) getOrElse {
77206
6784eaef7d0c prefer explicit shasum;
wenzelm
parents: 76992
diff changeset
    38
      val digest = SHA1.digest(heap)
6784eaef7d0c prefer explicit shasum;
wenzelm
parents: 76992
diff changeset
    39
      File.append(heap, sha1_prefix + digest.toString)
6784eaef7d0c prefer explicit shasum;
wenzelm
parents: 76992
diff changeset
    40
      digest
76991
6a078c80eab6 clarified modules;
wenzelm
parents:
diff changeset
    41
    }
77720
f750047e9386 tuned comments;
wenzelm
parents: 77718
diff changeset
    42
f750047e9386 tuned comments;
wenzelm
parents: 77718
diff changeset
    43
f750047e9386 tuned comments;
wenzelm
parents: 77718
diff changeset
    44
  /* SQL data model */
f750047e9386 tuned comments;
wenzelm
parents: 77718
diff changeset
    45
79682
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
    46
  sealed case class Log_DB(uuid: String, content: Bytes)
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
    47
78396
7853d9072d1b renamed object Data to private_data, to emphasize its intended scope (but it is publicly accessible in the database);
wenzelm
parents: 78369
diff changeset
    48
  object private_data extends SQL.Data("isabelle_heaps") {
78187
2df0f3604a67 clarified signature: more explicit class SQL.Data;
wenzelm
parents: 78186
diff changeset
    49
    override lazy val tables = SQL.Tables(Base.table, Slices.table)
78183
8d57ed9e27a7 store heaps within database server;
wenzelm
parents: 78182
diff changeset
    50
8d57ed9e27a7 store heaps within database server;
wenzelm
parents: 78182
diff changeset
    51
    object Generic {
8d57ed9e27a7 store heaps within database server;
wenzelm
parents: 78182
diff changeset
    52
      val name = SQL.Column.string("name").make_primary_key
8d57ed9e27a7 store heaps within database server;
wenzelm
parents: 78182
diff changeset
    53
    }
8d57ed9e27a7 store heaps within database server;
wenzelm
parents: 78182
diff changeset
    54
8d57ed9e27a7 store heaps within database server;
wenzelm
parents: 78182
diff changeset
    55
    object Base {
8d57ed9e27a7 store heaps within database server;
wenzelm
parents: 78182
diff changeset
    56
      val name = Generic.name
8d57ed9e27a7 store heaps within database server;
wenzelm
parents: 78182
diff changeset
    57
      val size = SQL.Column.long("size")
8d57ed9e27a7 store heaps within database server;
wenzelm
parents: 78182
diff changeset
    58
      val digest = SQL.Column.string("digest")
79682
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
    59
      val uuid = SQL.Column.string("uuid")
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
    60
      val log_db = SQL.Column.bytes("log_db")
78183
8d57ed9e27a7 store heaps within database server;
wenzelm
parents: 78182
diff changeset
    61
79682
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
    62
      val table = make_table(List(name, size, digest, uuid, log_db))
78183
8d57ed9e27a7 store heaps within database server;
wenzelm
parents: 78182
diff changeset
    63
    }
8d57ed9e27a7 store heaps within database server;
wenzelm
parents: 78182
diff changeset
    64
8d57ed9e27a7 store heaps within database server;
wenzelm
parents: 78182
diff changeset
    65
    object Slices {
8d57ed9e27a7 store heaps within database server;
wenzelm
parents: 78182
diff changeset
    66
      val name = Generic.name
8d57ed9e27a7 store heaps within database server;
wenzelm
parents: 78182
diff changeset
    67
      val slice = SQL.Column.int("slice").make_primary_key
8d57ed9e27a7 store heaps within database server;
wenzelm
parents: 78182
diff changeset
    68
      val content = SQL.Column.bytes("content")
8d57ed9e27a7 store heaps within database server;
wenzelm
parents: 78182
diff changeset
    69
78266
d8c99a497502 clarified signature;
wenzelm
parents: 78213
diff changeset
    70
      val table = make_table(List(name, slice, content), name = "slices")
78183
8d57ed9e27a7 store heaps within database server;
wenzelm
parents: 78182
diff changeset
    71
    }
8d57ed9e27a7 store heaps within database server;
wenzelm
parents: 78182
diff changeset
    72
78278
5717310a0c6a create database view for diagnostic purposes;
wenzelm
parents: 78266
diff changeset
    73
    object Slices_Size {
5717310a0c6a create database view for diagnostic purposes;
wenzelm
parents: 78266
diff changeset
    74
      val name = Generic.name
79683
ade429ddb1fc more accurate types;
wenzelm
parents: 79682
diff changeset
    75
      val slice = Slices.slice
ade429ddb1fc more accurate types;
wenzelm
parents: 79682
diff changeset
    76
      val size = SQL.Column.string("size")
78278
5717310a0c6a create database view for diagnostic purposes;
wenzelm
parents: 78266
diff changeset
    77
5717310a0c6a create database view for diagnostic purposes;
wenzelm
parents: 78266
diff changeset
    78
      val table = make_table(List(name, slice, size),
5717310a0c6a create database view for diagnostic purposes;
wenzelm
parents: 78266
diff changeset
    79
        body = "SELECT name, slice, pg_size_pretty(length(content)::bigint) as size FROM " +
5717310a0c6a create database view for diagnostic purposes;
wenzelm
parents: 78266
diff changeset
    80
          Slices.table.ident,
5717310a0c6a create database view for diagnostic purposes;
wenzelm
parents: 78266
diff changeset
    81
        name = "slices_size")
5717310a0c6a create database view for diagnostic purposes;
wenzelm
parents: 78266
diff changeset
    82
    }
5717310a0c6a create database view for diagnostic purposes;
wenzelm
parents: 78266
diff changeset
    83
79677
49370f0f7911 clarified names;
wenzelm
parents: 78958
diff changeset
    84
    def read_digests(db: SQL.Database, names: Iterable[String]): Map[String, SHA1.Digest] = {
78510
8f45302a9ff0 more thorough ML_Heap.restore: include ancestors; prefer simultaneous ML_Heap.get_entries: just one database access for heap hierarchy;
wenzelm
parents: 78509
diff changeset
    85
      require(names.nonEmpty)
8f45302a9ff0 more thorough ML_Heap.restore: include ancestors; prefer simultaneous ML_Heap.get_entries: just one database access for heap hierarchy;
wenzelm
parents: 78509
diff changeset
    86
8f45302a9ff0 more thorough ML_Heap.restore: include ancestors; prefer simultaneous ML_Heap.get_entries: just one database access for heap hierarchy;
wenzelm
parents: 78509
diff changeset
    87
      db.execute_query_statement(
8f45302a9ff0 more thorough ML_Heap.restore: include ancestors; prefer simultaneous ML_Heap.get_entries: just one database access for heap hierarchy;
wenzelm
parents: 78509
diff changeset
    88
        Base.table.select(List(Base.name, Base.digest),
8f45302a9ff0 more thorough ML_Heap.restore: include ancestors; prefer simultaneous ML_Heap.get_entries: just one database access for heap hierarchy;
wenzelm
parents: 78509
diff changeset
    89
          sql = Generic.name.where_member(names)),
8f45302a9ff0 more thorough ML_Heap.restore: include ancestors; prefer simultaneous ML_Heap.get_entries: just one database access for heap hierarchy;
wenzelm
parents: 78509
diff changeset
    90
        List.from[(String, String)],
8f45302a9ff0 more thorough ML_Heap.restore: include ancestors; prefer simultaneous ML_Heap.get_entries: just one database access for heap hierarchy;
wenzelm
parents: 78509
diff changeset
    91
        res => res.string(Base.name) -> res.string(Base.digest)
8f45302a9ff0 more thorough ML_Heap.restore: include ancestors; prefer simultaneous ML_Heap.get_entries: just one database access for heap hierarchy;
wenzelm
parents: 78509
diff changeset
    92
      ).flatMap({
8f45302a9ff0 more thorough ML_Heap.restore: include ancestors; prefer simultaneous ML_Heap.get_entries: just one database access for heap hierarchy;
wenzelm
parents: 78509
diff changeset
    93
        case (_, "") => None
8f45302a9ff0 more thorough ML_Heap.restore: include ancestors; prefer simultaneous ML_Heap.get_entries: just one database access for heap hierarchy;
wenzelm
parents: 78509
diff changeset
    94
        case (name, digest) => Some(name -> SHA1.fake_digest(digest))
8f45302a9ff0 more thorough ML_Heap.restore: include ancestors; prefer simultaneous ML_Heap.get_entries: just one database access for heap hierarchy;
wenzelm
parents: 78509
diff changeset
    95
      }).toMap
8f45302a9ff0 more thorough ML_Heap.restore: include ancestors; prefer simultaneous ML_Heap.get_entries: just one database access for heap hierarchy;
wenzelm
parents: 78509
diff changeset
    96
    }
78183
8d57ed9e27a7 store heaps within database server;
wenzelm
parents: 78182
diff changeset
    97
79677
49370f0f7911 clarified names;
wenzelm
parents: 78958
diff changeset
    98
    def read_slices(db: SQL.Database, name: String): List[Bytes] =
78196
140a6f2e3728 restore heaps from database, which takes precedence over file-system;
wenzelm
parents: 78193
diff changeset
    99
      db.execute_query_statement(
140a6f2e3728 restore heaps from database, which takes precedence over file-system;
wenzelm
parents: 78193
diff changeset
   100
        Slices.table.select(List(Slices.content),
140a6f2e3728 restore heaps from database, which takes precedence over file-system;
wenzelm
parents: 78193
diff changeset
   101
          sql = Generic.name.where_equal(name) + SQL.order_by(List(Slices.slice))),
140a6f2e3728 restore heaps from database, which takes precedence over file-system;
wenzelm
parents: 78193
diff changeset
   102
        List.from[Bytes], _.bytes(Slices.content))
140a6f2e3728 restore heaps from database, which takes precedence over file-system;
wenzelm
parents: 78193
diff changeset
   103
79682
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   104
    def read_log_db(db: SQL.Database, name: String, old_uuid: String = ""): Option[Log_DB] =
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   105
      db.execute_query_statement(
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   106
        Base.table.select(List(Base.uuid, Base.log_db), sql =
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   107
          SQL.where_and(
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   108
            Generic.name.equal(name),
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   109
            if_proper(old_uuid, Base.uuid.ident + " <> " + SQL.string(old_uuid)))),
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   110
        List.from[(String, Bytes)],
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   111
        res => (res.string(Base.uuid), res.bytes(Base.log_db))
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   112
      ).collectFirst(
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   113
        {
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   114
          case (uuid, content) if uuid.nonEmpty && !content.is_empty =>
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   115
            Log_DB(uuid, content)
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   116
        })
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   117
79680
wenzelm
parents: 79678
diff changeset
   118
    def write_slice(db: SQL.Database, name: String, slice: Int, content: Bytes): Unit =
wenzelm
parents: 79678
diff changeset
   119
      db.execute_statement(Slices.table.insert(), body =
wenzelm
parents: 79678
diff changeset
   120
      { stmt =>
wenzelm
parents: 79678
diff changeset
   121
        stmt.string(1) = name
wenzelm
parents: 79678
diff changeset
   122
        stmt.int(2) = slice
wenzelm
parents: 79678
diff changeset
   123
        stmt.bytes(3) = content
wenzelm
parents: 79678
diff changeset
   124
      })
wenzelm
parents: 79678
diff changeset
   125
78183
8d57ed9e27a7 store heaps within database server;
wenzelm
parents: 78182
diff changeset
   126
    def clean_entry(db: SQL.Database, name: String): Unit = {
8d57ed9e27a7 store heaps within database server;
wenzelm
parents: 78182
diff changeset
   127
      for (table <- List(Base.table, Slices.table)) {
8d57ed9e27a7 store heaps within database server;
wenzelm
parents: 78182
diff changeset
   128
        db.execute_statement(table.delete(sql = Base.name.where_equal(name)))
8d57ed9e27a7 store heaps within database server;
wenzelm
parents: 78182
diff changeset
   129
      }
78278
5717310a0c6a create database view for diagnostic purposes;
wenzelm
parents: 78266
diff changeset
   130
      db.create_view(Slices_Size.table)
78183
8d57ed9e27a7 store heaps within database server;
wenzelm
parents: 78182
diff changeset
   131
    }
8d57ed9e27a7 store heaps within database server;
wenzelm
parents: 78182
diff changeset
   132
79680
wenzelm
parents: 79678
diff changeset
   133
    def init_entry(db: SQL.Database, name: String): Unit =
78183
8d57ed9e27a7 store heaps within database server;
wenzelm
parents: 78182
diff changeset
   134
      db.execute_statement(Base.table.insert(), body =
8d57ed9e27a7 store heaps within database server;
wenzelm
parents: 78182
diff changeset
   135
        { stmt =>
8d57ed9e27a7 store heaps within database server;
wenzelm
parents: 78182
diff changeset
   136
          stmt.string(1) = name
8d57ed9e27a7 store heaps within database server;
wenzelm
parents: 78182
diff changeset
   137
          stmt.long(2) = None
8d57ed9e27a7 store heaps within database server;
wenzelm
parents: 78182
diff changeset
   138
          stmt.string(3) = None
79682
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   139
          stmt.string(4) = None
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   140
          stmt.bytes(5) = None
78183
8d57ed9e27a7 store heaps within database server;
wenzelm
parents: 78182
diff changeset
   141
        })
8d57ed9e27a7 store heaps within database server;
wenzelm
parents: 78182
diff changeset
   142
79682
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   143
    def finish_entry(
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   144
      db: SQL.Database,
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   145
      name: String,
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   146
      size: Long,
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   147
      opt_digest: Option[SHA1.Digest],
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   148
      opt_log_db: Option[Log_DB]
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   149
    ): Unit =
78183
8d57ed9e27a7 store heaps within database server;
wenzelm
parents: 78182
diff changeset
   150
      db.execute_statement(
79682
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   151
        Base.table.update(List(Base.size, Base.digest, Base.uuid, Base.log_db),
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   152
          sql = Base.name.where_equal(name)),
78183
8d57ed9e27a7 store heaps within database server;
wenzelm
parents: 78182
diff changeset
   153
        body =
8d57ed9e27a7 store heaps within database server;
wenzelm
parents: 78182
diff changeset
   154
          { stmt =>
8d57ed9e27a7 store heaps within database server;
wenzelm
parents: 78182
diff changeset
   155
            stmt.long(1) = size
79682
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   156
            stmt.string(2) = opt_digest.map(_.toString)
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   157
            stmt.string(3) = opt_log_db.map(_.uuid)
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   158
            stmt.bytes(4) = opt_log_db.map(_.content)
78183
8d57ed9e27a7 store heaps within database server;
wenzelm
parents: 78182
diff changeset
   159
          })
8d57ed9e27a7 store heaps within database server;
wenzelm
parents: 78182
diff changeset
   160
  }
8d57ed9e27a7 store heaps within database server;
wenzelm
parents: 78182
diff changeset
   161
78204
0aa5360fa88b clarified signature;
wenzelm
parents: 78197
diff changeset
   162
  def clean_entry(db: SQL.Database, session_name: String): Unit =
78396
7853d9072d1b renamed object Data to private_data, to emphasize its intended scope (but it is publicly accessible in the database);
wenzelm
parents: 78369
diff changeset
   163
    private_data.transaction_lock(db, create = true, label = "ML_Heap.clean_entry") {
7853d9072d1b renamed object Data to private_data, to emphasize its intended scope (but it is publicly accessible in the database);
wenzelm
parents: 78369
diff changeset
   164
      private_data.clean_entry(db, session_name)
78213
fd0430a7b7a4 avoid repeated open_database_server: synchronized transaction_lock;
wenzelm
parents: 78204
diff changeset
   165
    }
78186
721c118f7001 proper ML_Heap.clean_entry;
wenzelm
parents: 78183
diff changeset
   166
79677
49370f0f7911 clarified names;
wenzelm
parents: 78958
diff changeset
   167
  def read_digests(db: SQL.Database, names: Iterable[String]): Map[String, SHA1.Digest] =
79682
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   168
    if (names.isEmpty) Map.empty
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   169
    else {
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   170
      private_data.transaction_lock(db, create = true, label = "ML_Heap.read_digests") {
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   171
        private_data.read_digests(db, names)
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   172
      }
78213
fd0430a7b7a4 avoid repeated open_database_server: synchronized transaction_lock;
wenzelm
parents: 78204
diff changeset
   173
    }
78196
140a6f2e3728 restore heaps from database, which takes precedence over file-system;
wenzelm
parents: 78193
diff changeset
   174
78191
6e52cda26ad4 tuned signature;
wenzelm
parents: 78188
diff changeset
   175
  def store(
79682
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   176
    db: SQL.Database,
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   177
    session: Store.Session,
79678
5979ba127524 clarified signature;
wenzelm
parents: 79677
diff changeset
   178
    slice: Space,
79682
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   179
    cache: Compress.Cache = Compress.Cache.none,
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   180
    progress: Progress = new Progress
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   181
  ): Unit = {
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   182
    val size =
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   183
      session.heap match {
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   184
        case Some(heap) => File.size(heap) - sha1_prefix.length - SHA1.digest_length
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   185
        case None => 0L
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   186
      }
78183
8d57ed9e27a7 store heaps within database server;
wenzelm
parents: 78182
diff changeset
   187
79682
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   188
    val slice_size = slice.bytes max Space.MiB(1).bytes
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   189
    val slices = (size.toDouble / slice_size.toDouble).ceil.toInt
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   190
    val step = if (slices > 0) (size.toDouble / slices.toDouble).ceil.toLong else 0L
78183
8d57ed9e27a7 store heaps within database server;
wenzelm
parents: 78182
diff changeset
   191
79682
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   192
    try {
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   193
      private_data.transaction_lock(db, create = true, label = "ML_Heap.store1") {
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   194
        private_data.init_entry(db, session.name)
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   195
      }
78183
8d57ed9e27a7 store heaps within database server;
wenzelm
parents: 78182
diff changeset
   196
79682
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   197
      if (slices > 0) progress.echo("Storing " + session.name + " ...")
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   198
      for (i <- 0 until slices) {
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   199
        val j = i + 1
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   200
        val offset = step * i
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   201
        val limit = if (j < slices) step * j else size
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   202
        val content =
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   203
          Bytes.read_file(session.the_heap, offset = offset, limit = limit)
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   204
            .compress(cache = cache)
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   205
        private_data.transaction_lock(db, label = "ML_Heap.store2") {
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   206
          private_data.write_slice(db, session.name, i, content)
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   207
        }
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   208
      }
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   209
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   210
      val opt_digest =
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   211
        for {
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   212
          path <- session.heap
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   213
          digest <- read_file_digest(path)
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   214
        } yield digest
78183
8d57ed9e27a7 store heaps within database server;
wenzelm
parents: 78182
diff changeset
   215
79682
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   216
      val opt_log_db =
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   217
        for {
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   218
          path <- session.log_db
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   219
          uuid <- proper_string(Store.read_build_uuid(path, session.name))
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   220
        } yield Log_DB(uuid, Bytes.read(path))
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   221
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   222
      if (opt_log_db.isDefined) progress.echo("Storing " + session.name + ".db ...")
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   223
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   224
      private_data.transaction_lock(db, label = "ML_Heap.store3") {
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   225
        private_data.finish_entry(db, session.name, size, opt_digest, opt_log_db)
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   226
      }
78183
8d57ed9e27a7 store heaps within database server;
wenzelm
parents: 78182
diff changeset
   227
    }
79682
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   228
    catch { case exn: Throwable =>
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   229
      private_data.transaction_lock(db, create = true, label = "ML_Heap.store4") {
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   230
        private_data.clean_entry(db, session.name)
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   231
      }
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   232
      throw exn
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   233
    }
78183
8d57ed9e27a7 store heaps within database server;
wenzelm
parents: 78182
diff changeset
   234
  }
78196
140a6f2e3728 restore heaps from database, which takes precedence over file-system;
wenzelm
parents: 78193
diff changeset
   235
140a6f2e3728 restore heaps from database, which takes precedence over file-system;
wenzelm
parents: 78193
diff changeset
   236
  def restore(
78204
0aa5360fa88b clarified signature;
wenzelm
parents: 78197
diff changeset
   237
    database: Option[SQL.Database],
79682
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   238
    sessions: List[Store.Session],
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   239
    cache: Compress.Cache = Compress.Cache.none,
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   240
    progress: Progress = new Progress
78196
140a6f2e3728 restore heaps from database, which takes precedence over file-system;
wenzelm
parents: 78193
diff changeset
   241
  ): Unit = {
78204
0aa5360fa88b clarified signature;
wenzelm
parents: 78197
diff changeset
   242
    database match {
79682
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   243
      case Some(db) if sessions.exists(_.defined) =>
78396
7853d9072d1b renamed object Data to private_data, to emphasize its intended scope (but it is publicly accessible in the database);
wenzelm
parents: 78369
diff changeset
   244
        private_data.transaction_lock(db, create = true, label = "ML_Heap.restore") {
79682
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   245
          /* heap */
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   246
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   247
          val defined_heaps =
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   248
            for (session <- sessions; heap <- session.heap)
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   249
              yield session.name -> heap
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   250
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   251
          val db_digests = private_data.read_digests(db, defined_heaps.map(_._1))
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   252
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   253
          for ((session_name, heap) <- defined_heaps) {
78510
8f45302a9ff0 more thorough ML_Heap.restore: include ancestors; prefer simultaneous ML_Heap.get_entries: just one database access for heap hierarchy;
wenzelm
parents: 78509
diff changeset
   254
            val file_digest = read_file_digest(heap)
8f45302a9ff0 more thorough ML_Heap.restore: include ancestors; prefer simultaneous ML_Heap.get_entries: just one database access for heap hierarchy;
wenzelm
parents: 78509
diff changeset
   255
            val db_digest = db_digests.get(session_name)
8f45302a9ff0 more thorough ML_Heap.restore: include ancestors; prefer simultaneous ML_Heap.get_entries: just one database access for heap hierarchy;
wenzelm
parents: 78509
diff changeset
   256
            if (db_digest.isDefined && db_digest != file_digest) {
79682
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   257
              progress.echo("Restoring " + session_name + " ...")
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   258
78510
8f45302a9ff0 more thorough ML_Heap.restore: include ancestors; prefer simultaneous ML_Heap.get_entries: just one database access for heap hierarchy;
wenzelm
parents: 78509
diff changeset
   259
              val base_dir = Isabelle_System.make_directory(heap.expand.dir)
8f45302a9ff0 more thorough ML_Heap.restore: include ancestors; prefer simultaneous ML_Heap.get_entries: just one database access for heap hierarchy;
wenzelm
parents: 78509
diff changeset
   260
              Isabelle_System.with_tmp_file(session_name + "_", base_dir = base_dir.file) { tmp =>
8f45302a9ff0 more thorough ML_Heap.restore: include ancestors; prefer simultaneous ML_Heap.get_entries: just one database access for heap hierarchy;
wenzelm
parents: 78509
diff changeset
   261
                Bytes.write(tmp, Bytes.empty)
79677
49370f0f7911 clarified names;
wenzelm
parents: 78958
diff changeset
   262
                for (slice <- private_data.read_slices(db, session_name)) {
78510
8f45302a9ff0 more thorough ML_Heap.restore: include ancestors; prefer simultaneous ML_Heap.get_entries: just one database access for heap hierarchy;
wenzelm
parents: 78509
diff changeset
   263
                  Bytes.append(tmp, slice.uncompress(cache = cache))
8f45302a9ff0 more thorough ML_Heap.restore: include ancestors; prefer simultaneous ML_Heap.get_entries: just one database access for heap hierarchy;
wenzelm
parents: 78509
diff changeset
   264
                }
8f45302a9ff0 more thorough ML_Heap.restore: include ancestors; prefer simultaneous ML_Heap.get_entries: just one database access for heap hierarchy;
wenzelm
parents: 78509
diff changeset
   265
                val digest = write_file_digest(tmp)
8f45302a9ff0 more thorough ML_Heap.restore: include ancestors; prefer simultaneous ML_Heap.get_entries: just one database access for heap hierarchy;
wenzelm
parents: 78509
diff changeset
   266
                if (db_digest.get == digest) {
8f45302a9ff0 more thorough ML_Heap.restore: include ancestors; prefer simultaneous ML_Heap.get_entries: just one database access for heap hierarchy;
wenzelm
parents: 78509
diff changeset
   267
                  Isabelle_System.chmod("a+r", tmp)
8f45302a9ff0 more thorough ML_Heap.restore: include ancestors; prefer simultaneous ML_Heap.get_entries: just one database access for heap hierarchy;
wenzelm
parents: 78509
diff changeset
   268
                  Isabelle_System.move_file(tmp, heap)
8f45302a9ff0 more thorough ML_Heap.restore: include ancestors; prefer simultaneous ML_Heap.get_entries: just one database access for heap hierarchy;
wenzelm
parents: 78509
diff changeset
   269
                }
79682
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   270
                else error("Incoherent content for session heap " + heap)
78204
0aa5360fa88b clarified signature;
wenzelm
parents: 78197
diff changeset
   271
              }
78509
146468e05dd4 more robust: atomic file-system result via tmp file;
wenzelm
parents: 78396
diff changeset
   272
            }
78196
140a6f2e3728 restore heaps from database, which takes precedence over file-system;
wenzelm
parents: 78193
diff changeset
   273
          }
79682
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   274
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   275
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   276
          /* log_db */
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   277
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   278
          for (session <- sessions; path <- session.log_db) {
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   279
            val file_uuid = Store.read_build_uuid(path, session.name)
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   280
            private_data.read_log_db(db, session.name, old_uuid = file_uuid) match {
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   281
              case Some(log_db) if file_uuid.isEmpty =>
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   282
                progress.echo("Restoring " + session.name + ".db ...")
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   283
                Isabelle_System.make_directory(path.expand.dir)
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   284
                Bytes.write(path, log_db.content)
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   285
              case Some(_) => error("Incoherent content for session database " + path)
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   286
              case None =>
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   287
            }
1fa1b32b0379 build local log_db, with store/restore via optional database server;
wenzelm
parents: 79680
diff changeset
   288
          }
78204
0aa5360fa88b clarified signature;
wenzelm
parents: 78197
diff changeset
   289
        }
78510
8f45302a9ff0 more thorough ML_Heap.restore: include ancestors; prefer simultaneous ML_Heap.get_entries: just one database access for heap hierarchy;
wenzelm
parents: 78509
diff changeset
   290
      case _ =>
78196
140a6f2e3728 restore heaps from database, which takes precedence over file-system;
wenzelm
parents: 78193
diff changeset
   291
    }
140a6f2e3728 restore heaps from database, which takes precedence over file-system;
wenzelm
parents: 78193
diff changeset
   292
  }
76991
6a078c80eab6 clarified modules;
wenzelm
parents:
diff changeset
   293
}