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

New runtime flag to switch PackageMonitoringListener to use Arcs deletion propagation. Also set up a package.arcs manifest with an empty package Schema that can be used for foreign references. This is part of setting up chronicle to use the arcs automatic deletion propagation (next steps are the reconcile job and installing the foreign reference checker). #6893

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ class DatabaseGarbageCollectionPeriodicTaskV2(
// work on any important threads that you're using elsewhere.
override fun doWork(): Result = runBlocking {
log.debug { "Running." }
val success = StorageServiceManagerEndpoint(
val success = StorageServiceManagerEndpointImpl(
binderHelper,
this,
storageServiceClass.java
Expand Down
Original file line number Diff line number Diff line change
@@ -1,95 +1,32 @@
package arcs.sdk.android.storage.service

import arcs.android.storage.service.IHardReferencesRemovalCallback
import arcs.android.storage.service.IResultCallback
import arcs.android.storage.service.IStorageServiceManager
import arcs.android.storage.service.StorageServiceManager
import arcs.android.storage.service.suspendForHardReferencesCallback
import arcs.android.storage.service.suspendForResultCallback
import arcs.core.data.Schema
import arcs.core.storage.keys.ForeignStorageKey
import kotlinx.coroutines.CoroutineScope

/**
* A [StorageServiceManagerEndpoint] can be used to bind to an Android [StorageServiceManager] and
* call its callback-style methods.
*/
class StorageServiceManagerEndpoint(
private val bindHelper: BindHelper,
private val scope: CoroutineScope,
private val storageServiceClass: Class<*> = StorageService::class.java
) {
interface StorageServiceManagerEndpoint {

/**
* Triggers a hard reference deletions for foreign hard references with the given Schema namespace
* and ID.
* Triggers a hard reference deletions for foreign hard references with the given Schema [namespace]
* and [id].
*
* @return the number of entities removed.
*/
suspend fun triggerForeignHardReferenceDeletion(namespace: Schema, id: String): Long {
return runOnStorageServiceManager { manager, result ->
manager.triggerHardReferenceDeletion(stringForeignStorageKey(namespace), id, result)
}
}
suspend fun triggerForeignHardReferenceDeletion(namespace: Schema, id: String): Long

/**
* Triggers a hard reference reconciliation for foreign hard references with the given Schema
* namespace and ID.
* [namespace] and [id].
*
* @return the number of entities removed.
*/
suspend fun reconcileForeignHardReference(namespace: Schema, idsToRetain: Set<String>): Long {
return runOnStorageServiceManager { manager, result ->
manager.reconcileHardReferences(
stringForeignStorageKey(namespace),
idsToRetain.toList(),
result
)
}
}
suspend fun reconcileForeignHardReference(namespace: Schema, idsToRetain: Set<String>): Long

/**
* Binds to the IStorageServiceManager and starts a garbage collection run.
*/
suspend fun runGarbageCollection(): Boolean {
return runIResultCallbackOnStorageServiceManager { manager, callback ->
manager.runGarbageCollection(callback)
}
}

/**
* Binds to the IStorageServiceManager, and runs the given block on it. It can be used to run one
* of the methods that take a [IResultCallback].
*/
private suspend fun runIResultCallbackOnStorageServiceManager(
block: (IStorageServiceManager, IResultCallback) -> Unit
): Boolean {
return withBoundService {
suspendForResultCallback { resultCallback ->
block(it, resultCallback)
}
}
}

private suspend fun runOnStorageServiceManager(
block: (IStorageServiceManager, IHardReferencesRemovalCallback) -> Unit
): Long {
return withBoundService {
suspendForHardReferencesCallback { resultCallback ->
block(it, resultCallback)
}
}
}

private suspend fun <T> withBoundService(block: suspend (IStorageServiceManager) -> T): T {
val intent = StorageServiceIntentHelpers.managerIntent(bindHelper.context, storageServiceClass)
val boundService = bindHelper.bindForIntent(
intent,
scope,
IStorageServiceManager.Stub::asInterface
)
try {
return block(boundService.service)
} finally {
boundService.disconnect()
}
}

private fun stringForeignStorageKey(namespace: Schema) = ForeignStorageKey(namespace).toString()
suspend fun runGarbageCollection()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package arcs.sdk.android.storage.service

import arcs.android.storage.service.IHardReferencesRemovalCallback
import arcs.android.storage.service.IResultCallback
import arcs.android.storage.service.IStorageServiceManager
import arcs.android.storage.service.StorageServiceManager
import arcs.android.storage.service.suspendForHardReferencesCallback
import arcs.android.storage.service.suspendForResultCallback
import arcs.core.data.Schema
import arcs.core.storage.keys.ForeignStorageKey
import kotlinx.coroutines.CoroutineScope

/**
* Implementation of [StorageServiceManagerEndpoint] that binds to an Android [StorageServiceManager] and
* call its callback-style methods.
*/
class StorageServiceManagerEndpointImpl(
private val bindHelper: BindHelper,
private val scope: CoroutineScope,
private val storageServiceClass: Class<*> = StorageService::class.java
) : StorageServiceManagerEndpoint {

override suspend fun triggerForeignHardReferenceDeletion(namespace: Schema, id: String): Long {
return runOnStorageServiceManager { manager, result ->
manager.triggerHardReferenceDeletion(stringForeignStorageKey(namespace), id, result)
}
}

override suspend fun reconcileForeignHardReference(
namespace: Schema,
idsToRetain: Set<String>
): Long {
return runOnStorageServiceManager { manager, result ->
manager.reconcileHardReferences(
stringForeignStorageKey(namespace),
idsToRetain.toList(),
result
)
}
}

override suspend fun runGarbageCollection() {
runIResultCallbackOnStorageServiceManager { manager, callback ->
manager.runGarbageCollection(callback)
}
}

/**
* Binds to the IStorageServiceManager, and runs the given block on it. It can be used to run one
* of the methods that take a [IResultCallback].
*/
private suspend fun runIResultCallbackOnStorageServiceManager(
block: (IStorageServiceManager, IResultCallback) -> Unit
): Boolean {
return withBoundService {
suspendForResultCallback { resultCallback ->
block(it, resultCallback)
}
}
}

private suspend fun runOnStorageServiceManager(
block: (IStorageServiceManager, IHardReferencesRemovalCallback) -> Unit
): Long {
return withBoundService {
suspendForHardReferencesCallback { resultCallback ->
block(it, resultCallback)
}
}
}

private suspend fun <T> withBoundService(block: suspend (IStorageServiceManager) -> T): T {
val intent = StorageServiceIntentHelpers.managerIntent(bindHelper.context, storageServiceClass)
val boundService = bindHelper.bindForIntent(
intent,
scope,
IStorageServiceManager.Stub::asInterface
)
try {
return block(boundService.service)
} finally {
boundService.disconnect()
}
}

private fun stringForeignStorageKey(namespace: Schema) = ForeignStorageKey(namespace).toString()
}
6 changes: 3 additions & 3 deletions javatests/arcs/android/integration/IntegrationEnvironment.kt
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ import arcs.sdk.android.storage.AndroidStorageServiceEndpointManager
import arcs.sdk.android.storage.service.DatabaseGarbageCollectionPeriodicTaskV2
import arcs.sdk.android.storage.service.StorageService
import arcs.sdk.android.storage.service.StorageService.StorageServiceConfig
import arcs.sdk.android.storage.service.StorageServiceManagerEndpoint
import arcs.sdk.android.storage.service.StorageServiceManagerEndpointImpl
import arcs.sdk.android.storage.service.testutil.TestBindHelper
import arcs.sdk.android.storage.service.testutil.TestWorkerFactory
import kotlin.coroutines.CoroutineContext
Expand Down Expand Up @@ -322,14 +322,14 @@ class IntegrationEnvironment(
}

suspend fun triggerHardReferenceDelete(namespace: Schema, id: String): Long {
return StorageServiceManagerEndpoint(
return StorageServiceManagerEndpointImpl(
TestBindHelper(ApplicationProvider.getApplicationContext()),
testScope
).triggerForeignHardReferenceDeletion(namespace, id)
}

suspend fun reconcileHardReference(namespace: Schema, fullSet: Set<String>): Long {
return StorageServiceManagerEndpoint(
return StorageServiceManagerEndpointImpl(
TestBindHelper(ApplicationProvider.getApplicationContext()),
testScope
).reconcileForeignHardReference(namespace, fullSet)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import org.junit.runner.RunWith

@OptIn(ExperimentalCoroutinesApi::class)
@RunWith(AndroidJUnit4::class)
class StorageServiceManagerEndpointTest {
class StorageServiceManagerEndpointImplTest {

private lateinit var app: Application
private val SCHEMA_NAME = "name"
Expand Down Expand Up @@ -53,7 +53,7 @@ class StorageServiceManagerEndpointTest {
@Test
fun triggerForeignHardReferenceDeletion_propagatesToDatabase() = runBlocking {
val testBindHelper = TestBindHelper(app)
val endpoint = StorageServiceManagerEndpoint(testBindHelper, this@runBlocking)
val endpoint = StorageServiceManagerEndpointImpl(testBindHelper, this@runBlocking)

endpoint.triggerForeignHardReferenceDeletion(schema, "id")

Expand All @@ -66,7 +66,7 @@ class StorageServiceManagerEndpointTest {
@Test
fun triggerForeignHardReferenceDeletion_sequenceOfCalls() = runBlocking {
val testBindHelper = TestBindHelper(app)
val endpoint = StorageServiceManagerEndpoint(testBindHelper, this@runBlocking)
val endpoint = StorageServiceManagerEndpointImpl(testBindHelper, this@runBlocking)
assertThat(database.hardReferenceDeletes).isEmpty()

endpoint.triggerForeignHardReferenceDeletion(schema, "id")
Expand All @@ -86,7 +86,7 @@ class StorageServiceManagerEndpointTest {
@Test
fun reconcileForeignHardReference_deletesOne() = runBlocking {
val testBindHelper = TestBindHelper(app)
val endpoint = StorageServiceManagerEndpoint(testBindHelper, this@runBlocking)
val endpoint = StorageServiceManagerEndpointImpl(testBindHelper, this@runBlocking)
database.allHardReferenceIds.add("id1")

endpoint.reconcileForeignHardReference(schema, setOf("id2"))
Expand All @@ -100,7 +100,7 @@ class StorageServiceManagerEndpointTest {
@Test
fun reconcileForeignHardReference_partialOvelap() = runBlocking {
val testBindHelper = TestBindHelper(app)
val endpoint = StorageServiceManagerEndpoint(testBindHelper, this@runBlocking)
val endpoint = StorageServiceManagerEndpointImpl(testBindHelper, this@runBlocking)
database.allHardReferenceIds.addAll(listOf("id1", "id2"))

endpoint.reconcileForeignHardReference(schema, setOf("id2"))
Expand All @@ -114,7 +114,7 @@ class StorageServiceManagerEndpointTest {
@Test
fun reconcileForeignHardReference_deletesNone() = runBlocking {
val testBindHelper = TestBindHelper(app)
val endpoint = StorageServiceManagerEndpoint(testBindHelper, this@runBlocking)
val endpoint = StorageServiceManagerEndpointImpl(testBindHelper, this@runBlocking)
database.allHardReferenceIds.add("id1")

endpoint.reconcileForeignHardReference(schema, setOf("id1"))
Expand All @@ -126,7 +126,7 @@ class StorageServiceManagerEndpointTest {
@Test
fun reconcileForeignHardReference_emptyValidSet() = runBlocking {
val testBindHelper = TestBindHelper(app)
val endpoint = StorageServiceManagerEndpoint(testBindHelper, this@runBlocking)
val endpoint = StorageServiceManagerEndpointImpl(testBindHelper, this@runBlocking)
database.allHardReferenceIds.add("id1")

endpoint.reconcileForeignHardReference(schema, emptySet())
Expand All @@ -143,7 +143,7 @@ class StorageServiceManagerEndpointTest {
val databaseManager = FakeDatabaseManager { dbManagerGcCalled = true }
DriverAndKeyConfigurator.configure(databaseManager)
val testBindHelper = TestBindHelper(app)
val endpoint = StorageServiceManagerEndpoint(testBindHelper, this@runBlocking)
val endpoint = StorageServiceManagerEndpointImpl(testBindHelper, this@runBlocking)

endpoint.runGarbageCollection()

Expand All @@ -158,7 +158,7 @@ class StorageServiceManagerEndpointTest {
}
DriverAndKeyConfigurator.configure(databaseManager)
val testBindHelper = TestBindHelper(app)
val endpoint = StorageServiceManagerEndpoint(testBindHelper, this@runBlocking)
val endpoint = StorageServiceManagerEndpointImpl(testBindHelper, this@runBlocking)

val e = assertFailsWith<CrdtException> {
endpoint.runGarbageCollection()
Expand Down