Skip to content

Commit baa9723

Browse files
committed
0.5.0-SNAPSHOT
1 parent c3c0796 commit baa9723

File tree

16 files changed

+402
-25
lines changed

16 files changed

+402
-25
lines changed

SQLiter/gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
kotlin.code.style=official
1818

1919
GROUP=co.touchlab
20-
VERSION_NAME=0.4.3-SNAPSHOT
20+
VERSION_NAME=0.5.0-SNAPSHOT
2121

2222
STATELY_VERSION=0.4.0-SNAPSHOT
2323
KOTLIN_VERSION=1.3.10

SQLiter/src/commonMain/kotlin/co/touchlab/sqliter/DatabaseManager.kt

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,26 @@
1717
package co.touchlab.sqliter
1818

1919
interface DatabaseManager{
20-
fun createConnection():DatabaseConnection
20+
/**
21+
* Create a connection with locked access to the underlying sqlite instance. Use this
22+
* in most cases.
23+
*/
24+
fun createMultiThreadedConnection():DatabaseConnection
25+
26+
/**
27+
* Create a connection without locked access to the underlying sqlite instance. Use this only
28+
* if you are absolutely sure you're only accessing from one thread. It will proactively fail
29+
* if you are attempting otherwise. Performance is better, but marginally so.
30+
*/
31+
fun createSingleThreadedConnection():DatabaseConnection
2132
val configuration:DatabaseConfiguration
2233
}
2334

2435
//expect fun createDatabaseManager(configuration: DatabaseConfiguration):DatabaseManager
2536
//expect fun deleteDatabase(name:String)
2637

2738
fun <R> DatabaseManager.withConnection(block:(DatabaseConnection) -> R):R{
28-
val connection = createConnection()
39+
val connection = createMultiThreadedConnection()
2940
try {
3041
return block(connection)
3142
}finally {
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
/*
2+
* Copyright (C) 2018 Touchlab, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package co.touchlab.sqliter.concurrency
18+
19+
import co.touchlab.sqliter.Cursor
20+
import co.touchlab.sqliter.DatabaseConnection
21+
import co.touchlab.sqliter.FieldType
22+
import co.touchlab.sqliter.Statement
23+
import co.touchlab.stately.concurrency.ReentrantLock
24+
import co.touchlab.stately.concurrency.withLock
25+
26+
class ConcurrentDatabaseConnection(private val delegateConnection:DatabaseConnection):DatabaseConnection{
27+
private val accessLock = ReentrantLock()
28+
29+
override fun createStatement(sql: String): Statement = accessLock.withLock { ConcurrentStatement(delegateConnection.createStatement(sql)) }
30+
31+
override fun beginTransaction() = accessLock.withLock { delegateConnection.beginTransaction() }
32+
33+
override fun setTransactionSuccessful() = accessLock.withLock { delegateConnection.setTransactionSuccessful() }
34+
35+
override fun endTransaction() = accessLock.withLock { delegateConnection.endTransaction() }
36+
37+
override fun close() = accessLock.withLock { delegateConnection.close() }
38+
39+
override val closed: Boolean
40+
get() = accessLock.withLock { delegateConnection.closed }
41+
42+
inner class ConcurrentCursor(private val delegateCursor: Cursor):Cursor{
43+
override fun next(): Boolean = accessLock.withLock { delegateCursor.next() }
44+
45+
override fun isNull(index: Int): Boolean = accessLock.withLock { delegateCursor.isNull(index) }
46+
47+
override fun getString(index: Int): String = accessLock.withLock { delegateCursor.getString(index) }
48+
49+
override fun getLong(index: Int): Long = accessLock.withLock { delegateCursor.getLong(index) }
50+
51+
override fun getBytes(index: Int): ByteArray = accessLock.withLock { delegateCursor.getBytes(index) }
52+
53+
override fun getDouble(index: Int): Double = accessLock.withLock { delegateCursor.getDouble(index) }
54+
55+
override fun getType(index: Int): FieldType = accessLock.withLock { delegateCursor.getType(index) }
56+
57+
override val columnCount: Int
58+
get() = accessLock.withLock { delegateCursor.columnCount }
59+
60+
override fun columnName(index: Int): String = accessLock.withLock { delegateCursor.columnName(index) }
61+
62+
override val columnNames: Map<String, Int>
63+
get() = accessLock.withLock { delegateCursor.columnNames }
64+
override val statement: Statement
65+
get() = accessLock.withLock { delegateCursor.statement }
66+
67+
}
68+
69+
inner class ConcurrentStatement(private val delegateStatement:Statement):Statement{
70+
override fun execute() = accessLock.withLock { delegateStatement.execute() }
71+
72+
override fun executeInsert(): Long = accessLock.withLock { delegateStatement.executeInsert() }
73+
74+
override fun executeUpdateDelete(): Int = accessLock.withLock { delegateStatement.executeUpdateDelete() }
75+
76+
override fun query(): Cursor = accessLock.withLock { ConcurrentCursor(delegateStatement.query()) }
77+
78+
override fun finalizeStatement() = accessLock.withLock { delegateStatement.finalizeStatement() }
79+
80+
override fun resetStatement() = accessLock.withLock { delegateStatement.resetStatement() }
81+
82+
override fun clearBindings() = accessLock.withLock { delegateStatement.clearBindings() }
83+
84+
override fun bindNull(index: Int) = accessLock.withLock { delegateStatement.bindNull(index) }
85+
86+
override fun bindLong(index: Int, value: Long) = accessLock.withLock { delegateStatement.bindLong(index, value) }
87+
88+
override fun bindDouble(index: Int, value: Double) = accessLock.withLock { delegateStatement.bindDouble(index, value) }
89+
90+
override fun bindString(index: Int, value: String) = accessLock.withLock { delegateStatement.bindString(index, value) }
91+
92+
override fun bindBlob(index: Int, value: ByteArray) = accessLock.withLock { delegateStatement.bindBlob(index, value) }
93+
94+
override fun bindParameterIndex(paramName: String): Int = accessLock.withLock { delegateStatement.bindParameterIndex(paramName) }
95+
}
96+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/*
2+
* Copyright (C) 2018 Touchlab, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package co.touchlab.sqliter.concurrency
18+
19+
import co.touchlab.sqliter.DatabaseConnection
20+
import co.touchlab.stately.ensureNeverFrozen
21+
22+
class SingleThreadDatabaseConnection(delegateConnection: DatabaseConnection):DatabaseConnection by delegateConnection
23+
{
24+
init {
25+
ensureNeverFrozen()
26+
}
27+
}

SQLiter/src/nativeCommonMain/kotlin/co/touchlab/sqliter/NativeDatabaseManager.kt

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,23 @@
1616

1717
package co.touchlab.sqliter
1818

19+
import co.touchlab.sqliter.concurrency.ConcurrentDatabaseConnection
20+
import co.touchlab.sqliter.concurrency.SingleThreadDatabaseConnection
1921
import platform.Foundation.NSLock
2022
import kotlin.native.concurrent.AtomicInt
23+
import kotlin.native.concurrent.freeze
2124

2225
class NativeDatabaseManager(private val path:String,
2326
override val configuration: DatabaseConfiguration
2427
):DatabaseManager{
28+
override fun createMultiThreadedConnection(): DatabaseConnection {
29+
return ConcurrentDatabaseConnection(createConnection()).freeze()
30+
}
31+
32+
override fun createSingleThreadedConnection(): DatabaseConnection {
33+
return SingleThreadDatabaseConnection(createConnection())
34+
}
35+
2536
val lock = NSLock()
2637

2738
companion object {
@@ -30,7 +41,7 @@ class NativeDatabaseManager(private val path:String,
3041

3142
internal val connectionCount = AtomicInt(0)
3243

33-
override fun createConnection(): DatabaseConnection {
44+
private fun createConnection(): DatabaseConnection {
3445
lock.lock()
3546

3647
try {

SQLiter/src/nativeCommonTest/kotlin/co/touchlab/sqliter/BasicTest.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ class BasicTest{
2626
@Test
2727
fun createTable(){
2828
basicTestDb {manager ->
29-
val connection = manager.createConnection()
29+
val connection = manager.createSingleThreadedConnection()
3030
val start = getTimeMillis()
3131
connection.withTransaction {
3232
val statement = it.createStatement("INSERT INTO test VALUES (?, ?, ?, ?)")

SQLiter/src/nativeCommonTest/kotlin/co/touchlab/sqliter/CursorTest.kt

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@
1616

1717
package co.touchlab.sqliter
1818

19-
import kotlin.test.AfterEach
20-
import kotlin.test.BeforeEach
2119
import kotlin.test.Test
2220
import kotlin.test.assertEquals
2321

@@ -31,7 +29,7 @@ class CursorTest:BaseDatabaseTest(){
3129
}
3230
}))
3331

34-
val connection = manager.createConnection()
32+
val connection = manager.surpriseMeConnection()
3533
connection.withStatement("insert into test(num, str)values(?,?)"){
3634
bindLong(1, 2)
3735
bindString(2, "asdf")

SQLiter/src/nativeCommonTest/kotlin/co/touchlab/sqliter/DatabaseConfigurationTest.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ class DatabaseConfigurationTest : BaseDatabaseTest(){
6262
}
6363
}))
6464

65-
val conn = manager.createConnection()
65+
val conn = manager.surpriseMeConnection()
6666
println("tr 0")
6767
assertEquals(conn.journalMode, JournalMode.WAL)
6868
println("tr 1")
@@ -86,7 +86,7 @@ class DatabaseConfigurationTest : BaseDatabaseTest(){
8686
fail("Same version shouldn't run")
8787
}))
8888

89-
val conn2 = manager2.createConnection()
89+
val conn2 = manager2.surpriseMeConnection()
9090
assertEquals(conn2.journalMode, JournalMode.WAL)
9191
conn2.close()
9292
}

SQLiter/src/nativeCommonTest/kotlin/co/touchlab/sqliter/DatabaseConnectionTest.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,7 @@ class DatabaseConnectionTest {
246246
)
247247
)
248248

249-
val conn1 = man.createConnection()
249+
val conn1 = man.surpriseMeConnection()
250250

251251
conn1.withTransaction {
252252
it.withStatement("insert into test(num, str)values(?,?)") {
@@ -258,7 +258,7 @@ class DatabaseConnectionTest {
258258

259259
assertEquals(1, conn1.longForQuery("select count(*) from test"))
260260

261-
val conn2 = man.createConnection()
261+
val conn2 = man.surpriseMeConnection()
262262
conn2.withTransaction {
263263
it.withStatement("insert into test(num, str)values(?,?)") {
264264
bindLong(1, 232)
@@ -283,7 +283,7 @@ class DatabaseConnectionTest {
283283
@Test
284284
fun closed(){
285285
basicTestDb(TWO_COL) {
286-
val conn = it.createConnection()
286+
val conn = it.surpriseMeConnection()
287287
assertFalse(conn.closed)
288288
conn.close()
289289
assertTrue(conn.closed)

SQLiter/src/nativeCommonTest/kotlin/co/touchlab/sqliter/DatabaseManagerTest.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ class DatabaseManagerTest : BaseDatabaseTest(){
2323
@Test
2424
fun connectionCount(){
2525
basicTestDb {man ->
26-
val conn = man.createConnection()
26+
val conn = man.surpriseMeConnection()
2727
assertEquals(1, countLiveConnections(man))
2828
man.withConnection {
2929
assertEquals(2, countLiveConnections(man))

0 commit comments

Comments
 (0)