Skip to content

Commit

Permalink
Java ConcurrentMap wrapper updateWith is compute
Browse files Browse the repository at this point in the history
The racy unit test requires more cycles to be less false-negative.

Co-authored-by: Igor Gabaydulin <igabaydulin@gmail.com>
  • Loading branch information
som-snytt and igabaydulin committed May 5, 2022
1 parent df355f9 commit 3e40c11
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 2 deletions.
Expand Up @@ -452,6 +452,10 @@ private[collection] object JavaCollectionWrappers extends Serializable {
case _ if isEmpty => None
case _ => Try(last).toOption
}

override def updateWith(key: K)(remappingFunction: Option[V] => Option[V]): Option[V] = Option {
underlying.compute(key, (_: K, v: V) => remappingFunction(Option(v)).getOrElse(null.asInstanceOf[V]))
}
}

@SerialVersionUID(3L)
Expand Down
32 changes: 30 additions & 2 deletions test/junit/scala/collection/convert/MapWrapperTest.scala
@@ -1,13 +1,14 @@
package scala.collection.convert

import java.util
import java.{util => jutil}

import org.junit.Assert._
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4

import scala.jdk.CollectionConverters._
import scala.util.chaining._

@RunWith(classOf[JUnit4])
class MapWrapperTest {
Expand Down Expand Up @@ -63,7 +64,7 @@ class MapWrapperTest {
// regression test for https://github.com/scala/bug/issues/10663
@Test
def testHashCodeEqualsMatchesJavaMap(): Unit = {
val jmap = new util.HashMap[String, String]()
val jmap = new jutil.HashMap[String, String]()
jmap.put("scala", "rocks")
jmap.put("java interop is fun!", "ya!")
jmap.put("Ĺởồҝ ïŧ\\'ş ūŋǐčōđẹ", "whyyyy")
Expand All @@ -79,4 +80,31 @@ class MapWrapperTest {
assertTrue(jmap == mapWrapper)
assertTrue(mapWrapper == jmap)
}

// was: induce intermittent failure due to contention, where updater is called more than once
@Test def `t12586 updateWith should delegate to compute`: Unit = {
final val limit = 100 // retries until trigger
@volatile var count = 0
val jmap = new jutil.concurrent.ConcurrentHashMap[String, String]()
class Loki extends Runnable {
@volatile var done = false
def run(): Unit = {
while (!done) {
jmap.put("KEY", "VALUE")
//Thread.`yield`()
}
}
}
val loki = new Loki
val runner = new Thread(loki).tap(_.start)
val wrapped = jmap.asScala
def updater(old: Option[String]) = { count += 1 ; old.map(_ * 2) }
for (i <- 1 to limit) {
count = 0
wrapped.updateWith("KEY")(updater)
assertEquals(s"index $i", 1, count)
}
loki.done = true
runner.join()
}
}

0 comments on commit 3e40c11

Please sign in to comment.