Skip to content

Commit 181e8c5

Browse files
committed
[jacodb-storage] Add ability to fine-tune Xodus K/V storage using its own EnvironmentConfig
As an example of the feature use, added a test which opens a read-only storage listening to changes made by another R/W storage.
1 parent 3b6a17f commit 181e8c5

File tree

5 files changed

+54
-6
lines changed

5 files changed

+54
-6
lines changed

jacodb-storage/src/main/kotlin/org/jacodb/impl/JcErsSettings.kt

+5
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,10 @@
1616

1717
package org.jacodb.impl
1818

19+
import jetbrains.exodus.env.EnvironmentConfig
1920
import org.jacodb.api.storage.ers.ErsSettings
2021
import org.jacodb.impl.storage.kv.lmdb.LMDB_KEY_VALUE_STORAGE_SPI
22+
import org.jacodb.impl.storage.kv.xodus.XODUS_KEY_VALUE_STORAGE_SPI
2123

2224
class RamErsSettings(
2325
val immutableDumpsPath: String? = null
@@ -31,3 +33,6 @@ open class JcKvErsSettings(val kvId: String) : ErsSettings
3133
// by default, mapSize is 1Gb
3234
class JcLmdbErsSettings(val mapSize: Long = 0x40_00_00_00) : JcKvErsSettings(LMDB_KEY_VALUE_STORAGE_SPI)
3335

36+
class JcXodusErsSettings(val configurer: (EnvironmentConfig.() -> Unit)? = null) :
37+
JcKvErsSettings(XODUS_KEY_VALUE_STORAGE_SPI)
38+

jacodb-storage/src/main/kotlin/org/jacodb/impl/storage/kv/xodus/XodusKeyValueStorage.kt

+9-2
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package org.jacodb.impl.storage.kv.xodus
1818

1919
import jetbrains.exodus.env.Environment
20+
import jetbrains.exodus.env.EnvironmentConfig
2021
import jetbrains.exodus.env.Environments
2122
import jetbrains.exodus.env.Store
2223
import jetbrains.exodus.env.StoreConfig.WITHOUT_DUPLICATES_WITH_PREFIXING
@@ -25,14 +26,20 @@ import jetbrains.exodus.env.TransactionBase
2526
import org.jacodb.api.storage.kv.PluggableKeyValueStorage
2627
import org.jacodb.api.storage.kv.Transaction
2728

28-
internal class XodusKeyValueStorage(location: String) : PluggableKeyValueStorage() {
29+
internal class XodusKeyValueStorage(location: String, configurer: (EnvironmentConfig.() -> Unit)?) :
30+
PluggableKeyValueStorage() {
2931

30-
private val env: Environment = Environments.newInstance(location,
32+
private val env: Environment = Environments.newInstance(
33+
location,
3134
environmentConfig {
3235
logFileSize = 32768
3336
logCachePageSize = 65536 * 4
3437
gcStartIn = 600_000
3538
useVersion1Format = false // use v2 data format, as we use stores with prefixing, i.e., patricia trees
39+
40+
// If a configurer is set, apply it after default settings ^^^ are defined.
41+
// This allows overriding them as well.
42+
configurer?.let { it() }
3643
}
3744
)
3845

jacodb-storage/src/main/kotlin/org/jacodb/impl/storage/kv/xodus/XodusKeyValueStorageSPI.kt

+8-2
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package org.jacodb.impl.storage.kv.xodus
1919
import org.jacodb.api.storage.ers.ErsSettings
2020
import org.jacodb.api.storage.kv.PluggableKeyValueStorage
2121
import org.jacodb.api.storage.kv.PluggableKeyValueStorageSPI
22+
import org.jacodb.impl.JcXodusErsSettings
2223
import kotlin.io.path.createTempDirectory
2324

2425
const val XODUS_KEY_VALUE_STORAGE_SPI = "org.jacodb.impl.storage.kv.xodus.XodusKeyValueStorageSPI"
@@ -27,6 +28,11 @@ class XodusKeyValueStorageSPI : PluggableKeyValueStorageSPI {
2728

2829
override val id = XODUS_KEY_VALUE_STORAGE_SPI
2930

30-
override fun newStorage(location: String?, settings: ErsSettings): PluggableKeyValueStorage =
31-
XodusKeyValueStorage(location ?: createTempDirectory(prefix = "xodusKeyValueStorage").toString())
31+
override fun newStorage(location: String?, settings: ErsSettings): PluggableKeyValueStorage {
32+
val configurer = (settings as? JcXodusErsSettings)?.configurer
33+
return XodusKeyValueStorage(
34+
location ?: createTempDirectory(prefix = "xodusKeyValueStorage").toString(),
35+
configurer
36+
)
37+
}
3238
}

jacodb-storage/src/test/kotlin/org/jacodb/testing/storage/kv/XodusKeyValueStorageTest.kt

+27
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,36 @@
1616

1717
package org.jacodb.testing.storage.kv
1818

19+
import jetbrains.exodus.io.DataReaderWriterProvider
20+
import org.jacodb.impl.JcXodusErsSettings
1921
import org.jacodb.impl.storage.kv.xodus.XODUS_KEY_VALUE_STORAGE_SPI
22+
import org.junit.jupiter.api.Assertions.assertEquals
23+
import org.junit.jupiter.api.Assertions.assertNotNull
24+
import org.junit.jupiter.api.Assertions.assertNull
25+
import org.junit.jupiter.api.Assertions.assertTrue
26+
import org.junit.jupiter.api.Test
27+
import java.lang.Long.getLong
2028

2129
class XodusKeyValueStorageTest : PluggableKeyValueStorageTest() {
2230

2331
override val kvStorageId = XODUS_KEY_VALUE_STORAGE_SPI
32+
33+
@Test
34+
fun `test shared usage of the same db`() {
35+
val settings = JcXodusErsSettings {
36+
logDataReaderWriterProvider = DataReaderWriterProvider.WATCHING_READER_WRITER_PROVIDER
37+
}
38+
val roStorage = kvStorageSpi.newStorage(location = location, settings = settings)
39+
roStorage.transactional { txn ->
40+
assertTrue(txn.isReadonly)
41+
assertNull(txn.get("a map", "key".asByteArray))
42+
}
43+
putGet()
44+
Thread.sleep(getLong("jetbrains.exodus.io.watching.forceCheckEach", 3000L) + 500)
45+
roStorage.transactional { txn ->
46+
val got = txn.get("a map", "key".asByteArray)
47+
assertNotNull(got)
48+
assertEquals("value", got?.asString)
49+
}
50+
}
2451
}

jacodb-storage/src/testFixtures/kotlin/org/jacodb/testing/storage/kv/PluggableKeyValueStorageTest.kt

+5-2
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,16 @@ import org.junit.jupiter.api.Assertions.assertNull
2828
import org.junit.jupiter.api.Assertions.assertTrue
2929
import org.junit.jupiter.api.BeforeEach
3030
import org.junit.jupiter.api.Test
31+
import kotlin.io.path.createTempDirectory
3132

3233
abstract class PluggableKeyValueStorageTest {
3334

3435
abstract val kvStorageId: String
3536

36-
private val kvStorageSpi by lazy(LazyThreadSafetyMode.NONE) {
37+
protected val kvStorageSpi by lazy(LazyThreadSafetyMode.NONE) {
3738
PluggableKeyValueStorageSPI.getProvider(kvStorageId)
3839
}
40+
protected lateinit var location: String
3941
protected lateinit var storage: PluggableKeyValueStorage
4042

4143
@Test
@@ -145,7 +147,8 @@ abstract class PluggableKeyValueStorageTest {
145147

146148
@BeforeEach
147149
fun setUp() {
148-
storage = kvStorageSpi.newStorage(null).apply {
150+
location = createTempDirectory(prefix = "pluggableKeyValueStorage").toString()
151+
storage = kvStorageSpi.newStorage(location = location).apply {
149152
isMapWithKeyDuplicates = { mapName -> mapName.endsWith("withDuplicates") }
150153
}
151154
}

0 commit comments

Comments
 (0)