more thorough ML_Heap.restore: include ancestors; prefer simultaneous ML_Heap.get_entries: just one database access for heap hierarchy;
authorwenzelm
Thu, 10 Aug 2023 20:30:37 +0200
changeset 78510 8f45302a9ff0
parent 78509 146468e05dd4
child 78511 f5fb5bb2533f
more thorough ML_Heap.restore: include ancestors; prefer simultaneous ML_Heap.get_entries: just one database access for heap hierarchy;
src/Pure/ML/ml_heap.scala
src/Pure/Thy/store.scala
src/Pure/Tools/build_process.scala
--- a/src/Pure/ML/ml_heap.scala	Thu Aug 10 19:58:23 2023 +0200
+++ b/src/Pure/ML/ml_heap.scala	Thu Aug 10 20:30:37 2023 +0200
@@ -77,11 +77,19 @@
         name = "slices_size")
     }
 
-    def get_entry(db: SQL.Database, name: String): Option[SHA1.Digest] =
-      db.execute_query_statementO[String](
-        Base.table.select(List(Base.digest), sql = Generic.name.where_equal(name)),
-        _.string(Base.digest)
-      ).flatMap(proper_string).map(SHA1.fake_digest)
+    def get_entries(db: SQL.Database, names: Iterable[String]): Map[String, SHA1.Digest] = {
+      require(names.nonEmpty)
+
+      db.execute_query_statement(
+        Base.table.select(List(Base.name, Base.digest),
+          sql = Generic.name.where_member(names)),
+        List.from[(String, String)],
+        res => res.string(Base.name) -> res.string(Base.digest)
+      ).flatMap({
+        case (_, "") => None
+        case (name, digest) => Some(name -> SHA1.fake_digest(digest))
+      }).toMap
+    }
 
     def read_entry(db: SQL.Database, name: String): List[Bytes] =
       db.execute_query_statement(
@@ -127,9 +135,9 @@
       private_data.clean_entry(db, session_name)
     }
 
-  def get_entry(db: SQL.Database, session_name: String): Option[SHA1.Digest] =
-    private_data.transaction_lock(db, create = true, label = "ML_Heap.get_entry") {
-      private_data.get_entry(db, session_name)
+  def get_entries(db: SQL.Database, names: Iterable[String]): Map[String, SHA1.Digest] =
+    private_data.transaction_lock(db, create = true, label = "ML_Heap.get_entries") {
+      private_data.get_entries(db, names)
     }
 
   def store(
@@ -181,33 +189,35 @@
 
   def restore(
     database: Option[SQL.Database],
-    session_name: String,
-    heap: Path,
+    heaps: List[Path],
     cache: Compress.Cache = Compress.Cache.none
   ): Unit = {
     database match {
-      case None =>
-      case Some(db) =>
+      case Some(db) if heaps.nonEmpty =>
         private_data.transaction_lock(db, create = true, label = "ML_Heap.restore") {
-          val db_digest = private_data.get_entry(db, session_name)
-          val file_digest = read_file_digest(heap)
-
-          if (db_digest.isDefined && db_digest != file_digest) {
-            val base_dir = Isabelle_System.make_directory(heap.expand.dir)
-            Isabelle_System.with_tmp_file(session_name + "_", base_dir = base_dir.file) { tmp =>
-              Bytes.write(tmp, Bytes.empty)
-              for (slice <- private_data.read_entry(db, session_name)) {
-                Bytes.append(tmp, slice.uncompress(cache = cache))
+          val db_digests = private_data.get_entries(db, heaps.map(_.file_name))
+          for (heap <- heaps) {
+            val session_name = heap.file_name
+            val file_digest = read_file_digest(heap)
+            val db_digest = db_digests.get(session_name)
+            if (db_digest.isDefined && db_digest != file_digest) {
+              val base_dir = Isabelle_System.make_directory(heap.expand.dir)
+              Isabelle_System.with_tmp_file(session_name + "_", base_dir = base_dir.file) { tmp =>
+                Bytes.write(tmp, Bytes.empty)
+                for (slice <- private_data.read_entry(db, session_name)) {
+                  Bytes.append(tmp, slice.uncompress(cache = cache))
+                }
+                val digest = write_file_digest(tmp)
+                if (db_digest.get == digest) {
+                  Isabelle_System.chmod("a+r", tmp)
+                  Isabelle_System.move_file(tmp, heap)
+                }
+                else error("Incoherent content for session heap " + quote(session_name))
               }
-              val digest = write_file_digest(tmp)
-              if (db_digest.get == digest) {
-                Isabelle_System.chmod("a+r", tmp)
-                Isabelle_System.move_file(tmp, heap)
-              }
-              else error("Incoherent content for session heap " + quote(session_name))
             }
           }
         }
+      case _ =>
     }
   }
 }
--- a/src/Pure/Thy/store.scala	Thu Aug 10 19:58:23 2023 +0200
+++ b/src/Pure/Thy/store.scala	Thu Aug 10 20:30:37 2023 +0200
@@ -271,8 +271,15 @@
         cat_lines(input_dirs.map(dir => "  " + File.standard_path(dir))))
 
   def heap_shasum(database_server: Option[SQL.Database], name: String): SHA1.Shasum = {
-    def get_database = database_server.flatMap(ML_Heap.get_entry(_, name))
-    def get_file = find_heap(name).flatMap(ML_Heap.read_file_digest)
+    def get_database: Option[SHA1.Digest] = {
+      for {
+        db <- database_server
+        digest <- ML_Heap.get_entries(db, List(name)).valuesIterator.nextOption()
+      } yield digest
+    }
+
+    def get_file: Option[SHA1.Digest] =
+      find_heap(name).flatMap(ML_Heap.read_file_digest)
 
     get_database orElse get_file match {
       case Some(digest) => SHA1.shasum(digest, name)
--- a/src/Pure/Tools/build_process.scala	Thu Aug 10 19:58:23 2023 +0200
+++ b/src/Pure/Tools/build_process.scala	Thu Aug 10 20:30:37 2023 +0200
@@ -995,8 +995,8 @@
     val cancelled = progress.stopped || !ancestor_results.forall(_.ok)
 
     if (!skipped && !cancelled) {
-      ML_Heap.restore(_database_server, session_name, store.output_heap(session_name),
-        cache = store.cache.compress)
+      val heaps = (session_name :: ancestor_results.map(_.name)).map(store.output_heap)
+      ML_Heap.restore(_database_server, heaps, cache = store.cache.compress)
     }
 
     val result_name = (session_name, worker_uuid, build_uuid)