Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Showing
with
566 additions
and 202 deletions.
- +8 −0 common-test-resources/application.conf
- +12 −3 slick-hikaricp/src/main/scala/slick/jdbc/hikaricp/HikariCPJdbcDataSource.scala
- +5 −5 slick-testkit/src/main/scala/com/typesafe/slick/testkit/util/DelegateConnection.scala
- +55 −2 slick-testkit/src/test/scala/slick/test/jdbc/DataSourceTest.scala
- +86 −0 slick-testkit/src/test/scala/slick/test/jdbc/hikaricp/SlickDeadlockTest.scala
- +23 −8 slick/src/main/scala/slick/basic/BasicBackend.scala
- +5 −11 slick/src/main/scala/slick/jdbc/JdbcBackend.scala
- +11 −2 slick/src/main/scala/slick/jdbc/JdbcDataSource.scala
- +69 −15 slick/src/main/scala/slick/util/AsyncExecutor.scala
- +179 −0 slick/src/main/scala/slick/util/InternalArrayQueue.scala
- +113 −156 slick/src/main/scala/slick/util/ManagedArrayBlockingQueue.scala
@@ -0,0 +1,86 @@ | ||
package slick.test.jdbc.hikaricp | ||
|
||
import java.sql.Blob | ||
import java.util.concurrent.TimeUnit | ||
import javax.sql.rowset.serial.SerialBlob | ||
|
||
import com.typesafe.slick.testkit.util.{AsyncTest, JdbcTestDB} | ||
import org.junit.{After, Before, Ignore, Test} | ||
import slick.jdbc.H2Profile.api._ | ||
import slick.lifted.{ProvenShape, TableQuery} | ||
|
||
import scala.concurrent.duration._ | ||
import scala.concurrent.{Await, Future} | ||
|
||
class SlickDeadlockTest extends AsyncTest[JdbcTestDB] { | ||
|
||
class TestTable(tag: Tag) extends Table[(Int)](tag, "SDL") { | ||
|
||
def id: Rep[Int] = column[Int]("ID") | ||
def * : ProvenShape[(Int)] = id | ||
|
||
} | ||
|
||
class BlobTable(tag: Tag) extends Table[(Int, Blob)](tag, "SDLIO") { | ||
def id = column[Int]("id") | ||
def data = column[Blob]("data") | ||
def * = (id, data) | ||
} | ||
|
||
|
||
var database: Database = _ | ||
val testTable: TableQuery[TestTable] = TableQuery[TestTable] | ||
val blobTable: TableQuery[BlobTable] = TableQuery[BlobTable] | ||
|
||
@Before | ||
def openDatabase() = { | ||
database = Database.forConfig("h2mem1") | ||
Await.result(database.run((testTable.schema ++ blobTable.schema).create), 2.seconds) | ||
} | ||
|
||
@After | ||
def closeDatabase() = { | ||
Await.result(database.run((testTable.schema ++ blobTable.schema).drop), 2.seconds) | ||
database.close() | ||
} | ||
|
||
|
||
@Test def slickDoesNotDeadlock() { | ||
|
||
val tasks = 1 to 100 map { i => | ||
val action = { testTable += i } | ||
.flatMap { _ => testTable.length.result } | ||
.flatMap { _ => DBIO.successful(s"inserted value $i") } | ||
|
||
database.run(action.transactionally) | ||
} | ||
Await.result(Future.sequence(tasks), Duration(10, TimeUnit.SECONDS)) | ||
} | ||
|
||
@Test def slickDoesNotDeadlockWithSleeps(): Unit = { | ||
val tasks = 1 to 50 map { c => | ||
val action = sql"select $c".as[Int].head.map { i => Thread.sleep(if(c == 1) 100 else 200); i } | ||
|
||
database.run(action.transactionally) | ||
} | ||
Await.result(Future.sequence(tasks), Duration(10, TimeUnit.SECONDS)) | ||
|
||
} | ||
|
||
@Test def slickDoesNotDeadlockWithIo() { | ||
|
||
Await.result(database.run(( | ||
(blobTable += (1, new SerialBlob(Array[Byte](1,2,3)))) >> | ||
(blobTable += (2, new SerialBlob(Array[Byte](4,5)))) >> | ||
blobTable.result | ||
).transactionally), Duration(2, TimeUnit.SECONDS)) | ||
|
||
val tasks = 1 to 100 map { i => | ||
materializeAsync[(Int, Blob), (Int, String)](database.stream(blobTable.result.transactionally, bufferNext = false), | ||
{ case (id, data) => database.io((id, data.getBytes(1, data.length.toInt).mkString)) }) | ||
} | ||
|
||
Await.result(Future.sequence(tasks), Duration(10, TimeUnit.SECONDS)) | ||
} | ||
|
||
} |
Oops, something went wrong.