Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Native: assume New Memory Manager #4287

Merged
merged 32 commits into from Aug 1, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
d28b302
Enable new memory manager on tests, and updates coroutines to the lat…
BoD Jul 21, 2022
c03f05b
- Use newFixedThreadPoolContext for default and newSingleThreadContex…
BoD Jul 21, 2022
9821345
Add a test executing operations not on the main thread
BoD Jul 21, 2022
5f87c9e
Make Apple's runTest use runBlocking, and mark it as deprecated.
BoD Jul 21, 2022
bc9c733
Use a Mutex for Apple's Guard
BoD Jul 21, 2022
59dfda5
Remove NonMainWorker as we're no longer on the main thread on Apple
BoD Jul 22, 2022
cfedcee
Fix LoggingInterceptorTest on Apple
BoD Jul 22, 2022
055ee68
Remove all calls to freeze, ensureNeverFrozen and isFrozen
BoD Jul 22, 2022
e0a332f
Update API dump
BoD Jul 22, 2022
bb7e73b
Update apollo-runtime/src/commonMain/kotlin/com/apollographql/apollo3…
BoD Jul 22, 2022
afea875
Enable new MM on apollo-mockserver tests and ios-test
BoD Jul 22, 2022
c59044e
Mark HttpResponse.Builder.body(ByteString) as deprecated
BoD Jul 22, 2022
88f9491
Re-introduce actual for assertMainThreadOnNative, ensureNeverFrozen, …
BoD Jul 22, 2022
391f238
Rename BackgroundDispatcher -> CloseableSingleThreadDispatcher
BoD Jul 22, 2022
6dabfb7
Simplify defaultDispatcher
BoD Jul 22, 2022
21ad5b7
Remove unneeded suspend
BoD Jul 22, 2022
50ce24f
Use Dispatchers.Default as the main dispatcher on Apple
BoD Jul 22, 2022
b209e0f
Discard Guard, instead use a Mutex directly in DefaultApolloStore
BoD Jul 25, 2022
3d4ed51
Revert "Discard Guard, instead use a Mutex directly in DefaultApolloS…
BoD Jul 25, 2022
3a40a12
Suppress one deprecation warning
BoD Jul 25, 2022
a22f6f3
Discard Guard, instead use a Mutex directly in DefaultApolloStore
BoD Jul 25, 2022
f502aaa
Fix coroutines-mt not running
BoD Jul 25, 2022
60167d5
Crash with a useful message when running on the legacy memory manager
BoD Jul 25, 2022
6d17217
MockServer: crash with a useful message when running on the legacy me…
BoD Jul 26, 2022
64e0c7d
Use Dispatchers.Main.immediate to avoid hanging the main thread
BoD Jul 26, 2022
1241715
Update apollo-api/src/commonMain/kotlin/com/apollographql/apollo3/api…
BoD Jul 28, 2022
de61dad
Use Gradle programmatic configuration instead of properties for confi…
BoD Jul 28, 2022
8e21819
Get rid of withContext(Dispatchers.Main.immediate) {
BoD Jul 28, 2022
85db782
Report Guard/Lock changes to incubating module
BoD Jul 28, 2022
a5c3dd4
Use DeprecationLevel.ERROR instead of HIDDEN (better upgrade path)
BoD Jul 28, 2022
f01a3ff
Tweak design-docs/Threading.md after change to use the new memory man…
BoD Jul 28, 2022
867522f
Update native benchmarks measurements
BoD Aug 1, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions apollo-annotations/api/apollo-annotations.api
Expand Up @@ -12,6 +12,7 @@ public final class com/apollographql/apollo3/annotations/ApolloDeprecatedSince$V
public static final field v3_3_1 Lcom/apollographql/apollo3/annotations/ApolloDeprecatedSince$Version;
public static final field v3_3_2 Lcom/apollographql/apollo3/annotations/ApolloDeprecatedSince$Version;
public static final field v3_3_3 Lcom/apollographql/apollo3/annotations/ApolloDeprecatedSince$Version;
public static final field v3_4_1 Lcom/apollographql/apollo3/annotations/ApolloDeprecatedSince$Version;
public static fun valueOf (Ljava/lang/String;)Lcom/apollographql/apollo3/annotations/ApolloDeprecatedSince$Version;
public static fun values ()[Lcom/apollographql/apollo3/annotations/ApolloDeprecatedSince$Version;
}
Expand Down
Expand Up @@ -23,5 +23,6 @@ annotation class ApolloDeprecatedSince(val version: Version) {
v3_3_1,
v3_3_2,
v3_3_3,
v3_4_1,
}
}
@@ -1,5 +1,7 @@
package com.apollographql.apollo3.api.http

import com.apollographql.apollo3.annotations.ApolloDeprecatedSince
import com.apollographql.apollo3.annotations.ApolloDeprecatedSince.Version.v3_4_1
import com.apollographql.apollo3.annotations.ApolloExperimental
import okio.Buffer
import okio.BufferedSink
Expand Down Expand Up @@ -110,8 +112,8 @@ private constructor(
*/
private val bodySource: BufferedSource?,
/**
* An immutable body that can be freezed when used from Kotlin native.
* Prefer [bodySource] on non-native so that the response can be streamed.
* An immutable body.
* Prefer [bodySource] on so that the response can be streamed.
*/
private val bodyString: ByteString?,
) {
Expand All @@ -123,6 +125,7 @@ private constructor(
statusCode = statusCode,
).apply {
if (bodySource != null) body(bodySource)
@Suppress("DEPRECATION")
if (bodyString != null) body(bodyString)
addHeaders(headers)
}
Expand All @@ -145,9 +148,11 @@ private constructor(
}

/**
* An immutable body that can be freezed when used from Kotlin native.
* Prefer [bodySource] on non-native so that the response can be streamed.
* An immutable body.
* Prefer [bodySource] so that the response can be streamed.
*/
@Deprecated("Use body(BufferedSource) instead", ReplaceWith("Buffer().write(bodyString)", "okio.Buffer"))
@ApolloDeprecatedSince(v3_4_1)
fun body(bodyString: ByteString) = apply {
martinbonnin marked this conversation as resolved.
Show resolved Hide resolved
check(!hasBody) { "body() can only be called once" }
this.bodyString = bodyString
Expand Down
Expand Up @@ -24,17 +24,24 @@ import platform.posix.pthread_join
import platform.posix.pthread_tVar
import platform.posix.sockaddr_in
import platform.posix.socket
import kotlin.native.concurrent.freeze

/**
* @param acceptDelayMillis: an artificial delay introduced before each `accept()`
* call. Can be used to simulate slow connections.
*/
@OptIn(ExperimentalStdlibApi::class)
actual class MockServer(
private val acceptDelayMillis: Long,
override val mockServerHandler: MockServerHandler = QueueMockServerHandler(),
) : MockServerInterface {

init {
check(isExperimentalMM()) {
"Apollo: The legacy memory manager is no longer supported, please use the new memory manager instead. " +
"See https://github.com/JetBrains/kotlin/blob/master/kotlin-native/NEW_MM.md for more information."
}
}

actual constructor(mockServerHandler: MockServerHandler) : this(0, mockServerHandler)

private val pthreadT: pthread_tVar
Expand Down Expand Up @@ -73,7 +80,7 @@ actual class MockServer(

socket = Socket(socketFd, acceptDelayMillis, mockServerHandler)

val stableRef = StableRef.create(socket!!.freeze())
val stableRef = StableRef.create(socket!!)

pthread_create(pthreadT.ptr, null, staticCFunction { arg ->
initRuntimeIfNeeded()
Expand Down
@@ -1,13 +1,12 @@
package com.apollographql.apollo3.mockserver

import platform.Foundation.NSMutableArray
import kotlin.native.concurrent.freeze

internal actual class QueueMockServerHandler : MockServerHandler {
private val queue = NSMutableArray()

actual fun enqueue(response: MockResponse) {
queue.addObject(response.freeze())
queue.addObject(response)
}

actual override fun handle(request: MockRequest): MockResponse {
Expand Down
Expand Up @@ -30,7 +30,6 @@ import platform.posix.usleep
import platform.posix.write
import kotlin.experimental.and
import kotlin.native.concurrent.AtomicInt
import kotlin.native.concurrent.freeze

class Socket(
private val socketFd: Int,
Expand Down Expand Up @@ -131,7 +130,7 @@ class Socket(
debug("Got request: ${request.method} ${request.path}")

val mockResponse = synchronized(lock) {
recordedRequests.addObject(request.freeze())
recordedRequests.addObject(request)
try {
mockServerHandler.handle(request)
} catch (e: Exception) {
Expand Down
Expand Up @@ -5,10 +5,6 @@ import platform.Foundation.NSDateFormatter
import platform.Foundation.NSThread
import platform.Foundation.timeIntervalSince1970
import platform.posix.pthread_self
import kotlin.native.concurrent.ensureNeverFrozen
import kotlin.native.concurrent.freeze
import kotlin.native.concurrent.isFrozen
import kotlin.system.getTimeMillis

actual fun currentTimeMillis(): Long {
return (NSDate().timeIntervalSince1970 * 1000).toLong()
Expand All @@ -33,19 +29,13 @@ actual fun currentThreadName(): String {
}

actual fun ensureNeverFrozen(obj: Any) {
obj.ensureNeverFrozen()
}

actual fun isFrozen(obj: Any) = obj.isFrozen

actual fun isFrozen(obj: Any) = false
actual fun freeze(obj: Any) {
obj.freeze()
}

actual fun assertMainThreadOnNative() {
check(NSThread.isMainThread()) {
"Non-main native call"
}
martinbonnin marked this conversation as resolved.
Show resolved Hide resolved
}

actual fun platform() = Platform.Native
Expand Up @@ -2,6 +2,8 @@

package com.apollographql.apollo3.mpp

import com.apollographql.apollo3.annotations.ApolloDeprecatedSince
import com.apollographql.apollo3.annotations.ApolloDeprecatedSince.Version.v3_4_1
import com.apollographql.apollo3.annotations.ApolloInternal
import kotlin.jvm.JvmName

Expand All @@ -21,12 +23,20 @@ expect fun currentThreadId(): String
@ApolloInternal
expect fun currentThreadName(): String

expect fun ensureNeverFrozen(obj: Any)
@Deprecated("With the new Memory Manager this method is no longer needed and is a no-op", level = DeprecationLevel.ERROR)
@ApolloDeprecatedSince(v3_4_1)
expect fun ensureNeverFrozen(@Suppress("UNUSED_PARAMETER") obj: Any)

expect fun isFrozen(obj: Any): Boolean
@Deprecated("With the new Memory Manager this method is no longer needed and always return false", ReplaceWith("false"), level = DeprecationLevel.ERROR)
@ApolloDeprecatedSince(v3_4_1)
expect fun isFrozen(@Suppress("UNUSED_PARAMETER") obj: Any): Boolean

expect fun freeze(obj: Any)
@Deprecated("With the new Memory Manager this method is no longer needed and is a no-op", level = DeprecationLevel.ERROR)
@ApolloDeprecatedSince(v3_4_1)
expect fun freeze(@Suppress("UNUSED_PARAMETER") obj: Any)

@Deprecated("With the new Memory Manager this method is no longer needed and is a no-op", level = DeprecationLevel.ERROR)
@ApolloDeprecatedSince(v3_4_1)
expect fun assertMainThreadOnNative()

enum class Platform {
Expand Down
3 changes: 3 additions & 0 deletions apollo-normalized-cache-incubating/build.gradle.kts
Expand Up @@ -11,6 +11,9 @@ kotlin {
api(projects.apolloRuntime)
api(projects.apolloNormalizedCacheApiIncubating)
api(groovy.util.Eval.x(project, "x.dep.kotlinCoroutines"))
implementation(groovy.util.Eval.x(project, "x.dep.atomicfu").toString()) {
because("Use of ReentrantLock in DefaultApolloStore for Apple (we don't use the gradle plugin rewrite)")
}
}
}
}
Expand Down

This file was deleted.

@@ -0,0 +1,17 @@
package com.apollographql.apollo3.cache.normalized.internal

import kotlinx.atomicfu.locks.ReentrantLock
import kotlinx.atomicfu.locks.reentrantLock
import kotlinx.atomicfu.locks.withLock

internal actual class Lock {
private val lock: ReentrantLock = reentrantLock()

actual fun <T> read(block: () -> T): T {
return lock.withLock(block)
}

actual fun <T> write(block: () -> T): T {
return lock.withLock(block)
}
}
Expand Up @@ -175,8 +175,7 @@ interface ApolloStore {
/**
* Direct access to the cache.
*
* @param block a function that can access the cache. The function and its captured variables will
* be called from a background thread and freezed
* @param block a function that can access the cache. The function will be called from a background thread
*/
suspend fun <R> accessCache(block: (NormalizedCache) -> R): R

Expand Down

This file was deleted.

Expand Up @@ -39,12 +39,6 @@ import kotlinx.coroutines.launch
internal class ApolloCacheInterceptor(
val store: ApolloStore,
) : ApolloInterceptor {
init {
// The store has a MutableSharedFlow that doesn't like being frozen when using coroutines
// But is ok to freeze when using coroutines-native-mt (see https://github.com/apollographql/apollo-android/issues/3357)
// ensureNeverFrozen(store)
}

private suspend fun <D : Operation.Data> maybeAsync(request: ApolloRequest<D>, block: suspend () -> Unit) {
if (request.writeToCacheAsynchronously) {
val scope = request.executionContext[ConcurrencyInfo]!!.coroutineScope
Expand Down