Skip to content

Commit

Permalink
Merge branch 'main' into cm/keypath-notifications
Browse files Browse the repository at this point in the history
# Conflicts:
#	packages/external/core
#	packages/jni-swig-stub/realm.i
#	packages/jni-swig-stub/src/main/jni/realm_api_helpers.cpp
#	packages/jni-swig-stub/src/main/jni/realm_api_helpers.h
  • Loading branch information
Christian Melchior committed Nov 8, 2023
2 parents caa4f38 + e19b1d1 commit d73ed88
Show file tree
Hide file tree
Showing 30 changed files with 562 additions and 221 deletions.
37 changes: 35 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,33 @@
## 1.12.0-SNAPSHOT (YYYY-MM-DD)
## 1.13.0-SNAPSHOT (YYYY-MM-DD)

### Breaking Changes
* None.

### Enhancements
* None.

### Fixed
* None.

### Compatibility
* File format: Generates Realms with file format v23.
* Realm Studio 13.0.0 or above is required to open Realms created by this version.
* This release is compatible with the following Kotlin releases:
* Kotlin 1.8.0 and above. The K2 compiler is not supported yet.
* Ktor 2.1.2 and above.
* Coroutines 1.7.0 and above.
* AtomicFu 0.18.3 and above.
* The new memory model only. See https://github.com/realm/realm-kotlin#kotlin-memory-model-and-coroutine-compatibility
* Minimum Kbson 0.3.0.
* Minimum Gradle version: 6.8.3.
* Minimum Android Gradle Plugin version: 4.1.3.
* Minimum Android SDK: 16.

### Internal
* None.


## 1.12.0 (2023-11-02)

This release upgrades the Sync metadata in a way that is not compatible with older versions. To downgrade a Sync app from this version, you'll need to manually delete the metadata folder located at `$[SYNC-ROOT-DIRECTORY]/mongodb-realm/[APP-ID]/server-utility/metadata/`. This will log out all users.

Expand All @@ -10,6 +39,10 @@ This release upgrades the Sync metadata in a way that is not compatible with old
* The Realm Gradle Plugin no longer has a dependency on KAPT. (Issue [#1513](https://github.com/realm/realm-kotlin/issues/1513))

### Fixed
* `Realm.getNumberOfActiveVersions` now returns the actual number of active versions. (Core issue [#6960](https://github.com/realm/realm-core/pull/6960))
* Fixed memory leak on Darwin caused by a reference cycle between resources and the GC cleaner. (Issue [#1530](https://github.com/realm/realm-kotlin/pull/1530))
* Fixed memory leaks on the JVM platform, see PR for more information. (Issue [#1526](https://github.com/realm/realm-kotlin/pull/1526))
* Removed pin on the initial realm version after opening a Realm. (Issue [#1519](https://github.com/realm/realm-kotlin/pull/1519))
* `Realm.close()` is now idempotent.
* Fix error in `RealmAny.equals` that would sometimes return `true` when comparing RealmAnys wrapping same type but different values. (Issue [#1523](https://github.com/realm/realm-kotlin/pull/1523))
* [Sync] If calling a function on App Services that resulted in a redirect, it would only redirect for GET requests. (Issue [#1517](https://github.com/realm/realm-kotlin/pull/1517))
Expand All @@ -34,7 +67,7 @@ GET requests. (Issue [#1517](https://github.com/realm/realm-kotlin/pull/1517))
* Minimum Android SDK: 16.

### Internal
* Updated to Realm Core 13.23.1, commit 3618b2e9d679cd2880be8df17b79d4cc6d71ff76.
* Updated to Realm Core 13.23.2, commit e6271d72308b40399890060f58a88cf568c2ee22.


## 1.11.1 (2023-09-07)
Expand Down
2 changes: 1 addition & 1 deletion buildSrc/src/main/kotlin/Config.kt
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ val HOST_OS: OperatingSystem = findHostOs()

object Realm {
val ciBuild = (System.getenv("JENKINS_HOME") != null)
const val version = "1.12.0-SNAPSHOT"
const val version = "1.13.0-SNAPSHOT"
const val group = "io.realm.kotlin"
const val projectUrl = "https://realm.io"
const val pluginPortalId = "io.realm.kotlin"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import io.realm.kotlin.internal.interop.realm_sync_errno_connection_e
import io.realm.kotlin.internal.interop.realm_sync_errno_session_e
import io.realm.kotlin.internal.interop.realm_sync_session_resync_mode_e
import io.realm.kotlin.internal.interop.realm_sync_session_state_e
import io.realm.kotlin.internal.interop.realm_sync_socket_callback_result_e
import io.realm.kotlin.internal.interop.realm_user_state_e
import io.realm.kotlin.internal.interop.realm_web_socket_errno_e
import io.realm.kotlin.internal.interop.sync.AuthProvider
Expand All @@ -38,6 +39,7 @@ import io.realm.kotlin.internal.interop.sync.MetadataMode
import io.realm.kotlin.internal.interop.sync.SyncConnectionErrorCode
import io.realm.kotlin.internal.interop.sync.SyncSessionErrorCode
import io.realm.kotlin.internal.interop.sync.SyncSessionResyncMode
import io.realm.kotlin.internal.interop.sync.WebsocketCallbackResult
import io.realm.kotlin.internal.interop.sync.WebsocketErrorCode
import org.junit.Test
import kotlin.reflect.KClass
Expand Down Expand Up @@ -135,6 +137,13 @@ class SyncEnumTests {
}
}

@Test
fun websocketResultCode() {
checkEnum(realm_sync_socket_callback_result_e::class) { nativeValue ->
WebsocketCallbackResult.of(nativeValue)
}
}

private inline fun <T : Any> checkEnum(
enumClass: KClass<out Any>,
mapNativeValue: (Int) -> T?
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,12 +93,6 @@ interface MemAllocator {
* Instantiates a [RealmValue] representing a `realm_value_t` of type `RLM_TYPE_LINK`.
*/
fun realmObjectTransport(value: RealmObjectInterop?): RealmValue

/**
* Instantiates a [RealmQueryArgumentList] representing a `realm_query_arg_t` that describe and
* references the incoming [RealmValueList] arguments.
*/
fun queryArgsOf(queryArgs: List<RealmQueryArgument>): RealmQueryArgumentList
}

/**
Expand All @@ -118,6 +112,12 @@ interface MemTrackingAllocator : MemAllocator {
*/
fun byteArrayTransport(value: ByteArray?): RealmValue

/**
* Instantiates a [RealmQueryArgumentList] representing a `realm_query_arg_t` that describe and
* references the incoming [RealmValueList] arguments.
*/
fun queryArgsOf(queryArgs: List<RealmQueryArgument>): RealmQueryArgumentList

/**
* Frees resources linked to this allocator. See implementations for more details.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,3 +124,22 @@ expect enum class WebsocketErrorCode : CodeDescription {
internal fun of(nativeValue: Int): WebsocketErrorCode?
}
}

/**
* Wrapper for C-API `realm_sync_socket_callback_result`
* See https://github.com/realm/realm-core/blob/master/src/realm/error_codes.h#L298
*/
expect enum class WebsocketCallbackResult : CodeDescription {
RLM_ERR_SYNC_SOCKET_SUCCESS,
RLM_ERR_SYNC_SOCKET_OPERATION_ABORTED,
RLM_ERR_SYNC_SOCKET_RUNTIME,
RLM_ERR_SYNC_SOCKET_OUT_OF_MEMORY,
RLM_ERR_SYNC_SOCKET_ADDRESS_SPACE_EXHAUSTED,
RLM_ERR_SYNC_SOCKET_CONNECTION_CLOSED,
RLM_ERR_SYNC_SOCKET_NOT_SUPPORTED,
RLM_ERR_SYNC_SOCKET_INVALID_ARGUMENT;

companion object {
fun of(nativeValue: Int): WebsocketCallbackResult?
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,35 @@ actual object RealmInterop {
realmc.classArray_setitem(cclasses, i, cclass)
realmc.propertyArrayArray_setitem(cproperties, i, classProperties)
}
return LongPointerWrapper(realmc.realm_schema_new(cclasses, count.toLong(), cproperties))
try {
return LongPointerWrapper(realmc.realm_schema_new(cclasses, count.toLong(), cproperties))
} finally {
// Clean up classes
for (classIndex in 0 until count) {
val classInfo = realmc.classArray_getitem(cclasses, classIndex)

// Clean properties
val propertyArray = realmc.propertyArrayArray_getitem(cproperties, classIndex)

val propertyCount = classInfo.getNum_properties() + classInfo.getNum_computed_properties()
for (propertyIndex in 0 until propertyCount) {
val property = realmc.propertyArray_getitem(propertyArray, propertyIndex.toInt())

realmc.realm_property_info_t_cleanup(property)
property.delete()
}

realmc.delete_propertyArray(propertyArray)

// end clean properties

realmc.realm_class_info_t_cleanup(classInfo)
classInfo.delete()
}

realmc.delete_propertyArrayArray(cproperties)
realmc.delete_classArray(cclasses)
}
}

actual fun realm_config_new(): RealmConfigurationPointer {
Expand Down Expand Up @@ -317,23 +345,27 @@ actual object RealmInterop {
val properties = realmc.new_propertyArray(max.toInt())
val outCount = longArrayOf(0)
realmc.realm_get_class_properties(realm.cptr(), classKey.key, properties, max, outCount)
return if (outCount[0] > 0) {
(0 until outCount[0]).map { i ->
with(realmc.propertyArray_getitem(properties, i.toInt())) {
PropertyInfo(
name,
public_name,
PropertyType.from(type),
CollectionType.from(collection_type),
link_target,
link_origin_property_name,
PropertyKey(key),
flags
)
try {
return if (outCount[0] > 0) {
(0 until outCount[0]).map { i ->
with(realmc.propertyArray_getitem(properties, i.toInt())) {
PropertyInfo(
name,
public_name,
PropertyType.from(type),
CollectionType.from(collection_type),
link_target,
link_origin_property_name,
PropertyKey(key),
flags
)
}
}
} else {
emptyList()
}
} else {
emptyList()
} finally {
realmc.delete_propertyArray(properties)
}
}

Expand Down Expand Up @@ -941,6 +973,8 @@ actual object RealmInterop {
builder.initIndicesArray(builder::modificationIndices, modificationIndices)
builder.initIndicesArray(builder::modificationIndicesAfter, modificationIndicesAfter)
builder.movesCount = movesCount[0].toInt()

realmc.delete_collectionMoveArray(moves)
}

actual fun <T, R> realm_collection_changes_get_ranges(
Expand Down Expand Up @@ -988,6 +1022,12 @@ actual object RealmInterop {
builder.initRangesArray(builder::insertionRanges, insertionRanges, insertRangesCount[0])
builder.initRangesArray(builder::modificationRanges, modificationRanges, modificationRangesCount[0])
builder.initRangesArray(builder::modificationRangesAfter, modificationRangesAfter, modificationRangesCount[0])

realmc.delete_indexRangeArray(insertionRanges)
realmc.delete_indexRangeArray(modificationRanges)
realmc.delete_indexRangeArray(modificationRangesAfter)
realmc.delete_indexRangeArray(deletionRanges)
realmc.delete_collectionMoveArray(moves)
}

actual fun <R> realm_dictionary_get_changes(
Expand Down Expand Up @@ -1126,6 +1166,8 @@ actual object RealmInterop {
}
} else {
emptyList()
}.also {
realmc.delete_identityArray(keys)
}
}

Expand Down Expand Up @@ -1624,7 +1666,7 @@ actual object RealmInterop {
realm: RealmPointer,
classKey: ClassKey,
query: String,
args: RealmQueryArgumentList
args: RealmQueryArgumentList,
): RealmQueryPointer {
return LongPointerWrapper(
realmc.realm_query_parse(
Expand All @@ -1640,7 +1682,7 @@ actual object RealmInterop {
actual fun realm_query_parse_for_results(
results: RealmResultsPointer,
query: String,
args: RealmQueryArgumentList
args: RealmQueryArgumentList,
): RealmQueryPointer {
return LongPointerWrapper(
realmc.realm_query_parse_for_results(
Expand All @@ -1655,7 +1697,7 @@ actual object RealmInterop {
actual fun realm_query_parse_for_list(
list: RealmListPointer,
query: String,
args: RealmQueryArgumentList
args: RealmQueryArgumentList,
): RealmQueryPointer {
return LongPointerWrapper(
realmc.realm_query_parse_for_list(
Expand All @@ -1670,7 +1712,7 @@ actual object RealmInterop {
actual fun realm_query_parse_for_set(
set: RealmSetPointer,
query: String,
args: RealmQueryArgumentList
args: RealmQueryArgumentList,
): RealmQueryPointer {
return LongPointerWrapper(
realmc.realm_query_parse_for_set(
Expand Down Expand Up @@ -1708,7 +1750,7 @@ actual object RealmInterop {
actual fun realm_query_append_query(
query: RealmQueryPointer,
filter: String,
args: RealmQueryArgumentList
args: RealmQueryArgumentList,
): RealmQueryPointer {
return LongPointerWrapper(
realmc.realm_query_append_query(query.cptr(), filter, args.size, args.head)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,28 +93,6 @@ object JvmMemAllocator : MemAllocator {
link = realmc.realm_object_as_link(it.objectPointer.cptr())
}

override fun queryArgsOf(queryArgs: List<RealmQueryArgument>): RealmQueryArgumentList {
val cArgs = realmc.new_queryArgArray(queryArgs.size)
queryArgs.mapIndexed { index, arg ->
val queryArg = realm_query_arg_t().apply {
when (arg) {
is RealmQueryListArgument -> {
nb_args = arg.arguments.size.toLong()
is_list = true
this.arg = arg.arguments.head
}
is RealmQuerySingleArgument -> {
nb_args = 1
is_list = false
this.arg = arg.argument.value
}
}
}
realmc.queryArgArray_setitem(cArgs, index, queryArg)
}
return RealmQueryArgumentList(queryArgs.size.toLong(), cArgs)
}

private inline fun <T> createTransport(
value: T?,
type: Int,
Expand Down Expand Up @@ -151,6 +129,32 @@ class JvmMemTrackingAllocator : MemAllocator by JvmMemAllocator, MemTrackingAllo
}
}

override fun queryArgsOf(queryArgs: List<RealmQueryArgument>): RealmQueryArgumentList {
val cArgs = realmc.new_queryArgArray(queryArgs.size)
queryArgs.mapIndexed { index, arg ->
val queryArg = realm_query_arg_t().apply {
when (arg) {
is RealmQueryListArgument -> {
nb_args = arg.arguments.size.toLong()
is_list = true
this.arg = arg.arguments.head

scope.manageQueryListArgument(arg)
}
is RealmQuerySingleArgument -> {
nb_args = 1
is_list = false
this.arg = arg.argument.value
}
}
}
realmc.queryArgArray_setitem(cArgs, index, queryArg)
}
return RealmQueryArgumentList(queryArgs.size.toLong(), cArgs).also {
scope.manageQueryArgumentList(it)
}
}

/**
* Frees resources linked to this allocator's [scope], more specifically strings and binary
* buffers. See [MemScope.free] for more details.
Expand Down Expand Up @@ -180,16 +184,28 @@ class JvmMemTrackingAllocator : MemAllocator by JvmMemAllocator, MemTrackingAllo
* copied out afterwards).
*/
class MemScope {
val values: MutableSet<RealmValueT> = mutableSetOf()
val values: MutableSet<Any> = mutableSetOf()

fun manageRealmValue(value: RealmValueT): RealmValueT {
values.add(value)
return value
}

fun manageQueryArgumentList(value: RealmQueryArgumentList): RealmQueryArgumentList = value.also {
values.add(value)
}

fun manageQueryListArgument(value: RealmQueryListArgument): RealmQueryListArgument = value.also {
values.add(value)
}

fun free() {
values.map {
realmc.realm_value_t_cleanup(it)
values.forEach {
when (it) {
is RealmValueT -> realmc.realm_value_t_cleanup(it)
is RealmQueryArgumentList -> realmc.delete_queryArgArray(it.head)
is RealmQueryListArgument -> realmc.delete_valueArray(it.arguments.head)
}
}
}
}
Expand Down
Loading

0 comments on commit d73ed88

Please sign in to comment.