stevedlawrence commented on a change in pull request #739:
URL: https://github.com/apache/daffodil/pull/739#discussion_r795804526



##########
File path: 
daffodil-tdml-lib/src/main/scala/org/apache/daffodil/tdml/TDMLRunner.scala
##########
@@ -2585,64 +2613,85 @@ object UTF8Encoder {
 
 }
 
-object TDMLCompileResultCache {
+case class TDMLCompileResultCacheKey(
+  impl: String,
+  suppliedSchema: DaffodilSchemaSource,
+  useSerializedProcessor: Boolean,
+  optRootName: Option[String],
+  optRootNamespace: Option[String],
+  tunables: Map[String, String],
+)
 
-  case class Key (
-    impl: String,
-    suppliedSchema: DaffodilSchemaSource,
-    useSerializedProcessor: Boolean,
-    optRootName: Option[String],
-    optRootNamespace: Option[String],
-    tunables: Map[String, String],
-  )
+/**
+ * Stores the compile result as well as the time when this compile result
+ * should be removed from the cache. If optExpireTime is set to None, it means
+ * a DFDLTestSuite exists that is using this compile result, and so it should
+ * not expire. If optExpireTime is set to Some, it means no DFDLTestSuite
+ * currently uses the compile result, and so it can be expired once we reach
+ * the current time reaches the Some value time
+ */
+case class TDMLCompileResultCacheValue(
+  compileResult: TDML.CompileResult,
+  var optExpireTime: Option[Long] = None,
+)
 
-  private val cache = new mutable.WeakHashMap[Key, TDML.CompileResult]()
+case class TDMLCompileResultCache(entryExpireDuration: Option[Long]) {
+
+  private val cache = new mutable.HashMap[TDMLCompileResultCacheKey, 
TDMLCompileResultCacheValue]()
+
+  private def removeExpiredEntries(): Unit = {
+    val now = System.currentTimeMillis()
+    cache.retain { case (_, v) =>
+      val retainEntry = v.optExpireTime.map { now < _ }.getOrElse(true)
+      retainEntry
+    }
+  }
+
+  def setEntriesFinished(keys: mutable.Set[TDMLCompileResultCacheKey]): Unit = 
this.synchronized {
+    val now = System.currentTimeMillis()
+    val expireTime = Some(now + (entryExpireDuration.get * 1000))
+    keys.foreach { key =>
+      val optVal = cache.get(key)
+      if (optVal.isDefined) {
+        optVal.get.optExpireTime = expireTime
+      }
+    }
+  }
 
-  /**
-   * Get a compile result. This might come from a cache of compiled results, or
-   * it might compile a new processor if it hasn't been cached or has been
-   * removed from the cache.
-   *
-   * The CompileResult is guaranteed to not be evicted from cache as long as
-   * there exists a strong reference to the returned key. For this reason, it
-   * is important that callers must maintain a strong reference to the key as
-   * long as they want the CompileResult to stay in the cache.
-   */
   def getCompileResult(
     impl: AbstractTDMLDFDLProcessorFactory,
-    suppliedSchema: DaffodilSchemaSource,
-    useSerializedProcessor: Boolean,
-    optRootName: Option[String],
-    optRootNamespace: Option[String],
-    tunables: Map[String, String]): (Key, TDML.CompileResult) = 
this.synchronized {
+    key: TDMLCompileResultCacheKey): TDML.CompileResult = this.synchronized {
 
-    val tmpKey = Key(
-      impl.implementationName,
-      suppliedSchema,
-      useSerializedProcessor,
-      optRootName,
-      optRootNamespace,
-      tunables)
+    if (entryExpireDuration.isDefined) {
+      removeExpiredEntries()
+    }
 
-    val maybeKeyVal = cache.find { case (k, v) => k == tmpKey }
-    if (maybeKeyVal.isDefined) {
-      // the key is already in the cache, throw away our temp key and return
-      // the actual key and value that is in the WeakHashMap
-      maybeKeyVal.get
+    val optVal = cache.get(key)
+    if (optVal.isDefined) {
+      val v = optVal.get
+      // if some other DFDL Test Suite set an expire time for this compile
+      // result, but another test suite is now reusing it before reaching the
+      // expire time, we reset the expire time so that the entry isn't removed
+      // until the new test suite using it is finished.
+      v.optExpireTime = None
+      v.compileResult
     } else {
-      // the key either was never added to the cache, or it was garbage
-      // collected from the WeakHashMap. Get the processor, add it to the
-      // cache, and return the key/value
-      val processor = impl.getProcessor(
-        suppliedSchema,
-        useSerializedProcessor,
-        optRootName,
-        optRootNamespace,
-        tunables)
-      val kv = (tmpKey, processor)
-      cache += kv
-      kv
+      val compileResult = impl.getProcessor(
+        key.suppliedSchema,
+        key.useSerializedProcessor,
+        key.optRootName,
+        key.optRootNamespace,
+        key.tunables)
+      cache += (key -> TDMLCompileResultCacheValue(compileResult, None))
+      compileResult
     }
   }
 
 }
+
+object GlobalTDMLCompileResultCache {
+  val expireTime = 30

Review comment:
       Fixed




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


Reply via email to