Skip to content

Commit 2402d62

Browse files
Ray Cromwellarcs-c3po
authored andcommitted
test write only storage stack end-to-end
PiperOrigin-RevId: 369522237
1 parent 7cb569a commit 2402d62

File tree

6 files changed

+59
-10
lines changed

6 files changed

+59
-10
lines changed

java/arcs/core/host/ParticleContext.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ class ParticleContext(
184184
// Trigger the StorageProxy sync request for each readable handle. Once
185185
// the StorageEvent.READY notifications have all, been received, we can
186186
// call particle.onReady (handled by notify below).
187-
awaitingReady.forEach { it.maybeInitiateSync() }
187+
awaitingReady.toSet().forEach { it.maybeInitiateSync() }
188188
}
189189

190190
log.debug { "runParticleAsync finished" }

java/arcs/core/host/Utils.kt

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ import arcs.core.entity.Reference
2121
import arcs.core.host.api.HandleHolder
2222
import arcs.core.host.api.Particle
2323
import arcs.core.storage.StorageKey
24+
import arcs.core.storage.StorageKeyProtocol
25+
import arcs.core.storage.referencemode.ReferenceModeStorageKey
2426
import arcs.core.type.Tag
2527
import arcs.flags.BuildFlags
2628
import kotlin.reflect.KClass
@@ -151,11 +153,18 @@ object NoOpArcHostParticle : Particle {
151153

152154
/**
153155
* Examines all [Plan.HandleConnection]s in a given [Plan.Partition] and returns true if and only if
154-
* every connection with a matching key is both a [Tag.CollectionType] and uses a [HandleMode]
155-
* that cannot read.
156+
* every connection with a matching key is both a [Tag.CollectionType], uses a [HandleMode]
157+
* that cannot read, and is a database backed (as opposed to volatile or ramdisk) key.
156158
*/
157159
fun isWriteOnlyStorageKey(partition: Plan.Partition, key: StorageKey): Boolean =
158160
BuildFlags.WRITE_ONLY_STORAGE_STACK &&
159161
partition.particles.flatMap { it.handles.values }.filter { it.storageKey == key }.all {
160-
!it.mode.canRead && it.type.tag == Tag.Collection
162+
!it.mode.canRead && it.type.tag == Tag.Collection && isDatabaseKey(it.storageKey)
161163
}
164+
165+
/** True iff and key is backed by a database, not a ramdisk or volatile. */
166+
fun isDatabaseKey(key: StorageKey): Boolean = when (key.protocol) {
167+
StorageKeyProtocol.ReferenceMode -> isDatabaseKey((key as ReferenceModeStorageKey).backingKey)
168+
StorageKeyProtocol.Database -> true
169+
else -> false
170+
}

java/arcs/core/storage/WriteOnlyStorageProxyImpl.kt

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,12 +45,29 @@ class WriteOnlyStorageProxyImpl<Data : CrdtData, Op : CrdtOperation, T> private
4545
// WriteOnly proxies do not perform sync requests.
4646
override fun prepareForSync() = Unit
4747

48-
override fun maybeInitiateSync() = Unit
48+
override fun maybeInitiateSync() {
49+
notifyCallback?.let { callback ->
50+
scheduler.schedule(
51+
HandleCallbackTask(callbackId!!, "notify(READY)") {
52+
callback(StorageEvent.READY)
53+
}
54+
)
55+
}
56+
callbackId = null
57+
notifyCallback = null
58+
}
59+
60+
private var callbackId: CallbackIdentifier? = null
61+
private var notifyCallback: ((StorageEvent) -> Unit)? = null
4962

5063
// WriteOnly proxies are immediately ready.
5164
override fun registerForStorageEvents(id: CallbackIdentifier, notify: (StorageEvent) -> Unit) {
5265
checkNotClosed()
53-
notify(StorageEvent.READY)
66+
require(callbackId == null && notifyCallback == null) {
67+
"You can only registerForStorageEvents once."
68+
}
69+
callbackId = id
70+
notifyCallback = notify
5471
}
5572

5673
// WriteOnly proxies can't have errors as there are no events.

javatests/arcs/core/host/UtilsTest.kt

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import arcs.core.entity.ForeignReferenceCheckerImpl
2828
import arcs.core.host.api.HandleHolder
2929
import arcs.core.storage.api.DriverAndKeyConfigurator
3030
import arcs.core.storage.driver.RamDisk
31+
import arcs.core.storage.keys.DatabaseStorageKey
3132
import arcs.core.storage.keys.RamDiskStorageKey
3233
import arcs.core.storage.referencemode.ReferenceModeStorageKey
3334
import arcs.core.storage.testutil.testStorageEndpointManager
@@ -171,9 +172,13 @@ class UtilsTest(private val params: Params) {
171172
}
172173
}
173174

174-
private fun generateHandle(key: String, type: Type) =
175+
private fun generateHandle(key: String, type: Type, db: Boolean = true) =
175176
Plan.Handle(
176-
RamDiskStorageKey(key),
177+
if (!db) RamDiskStorageKey(key)
178+
else ReferenceModeStorageKey(
179+
backingKey = DatabaseStorageKey.Persistent("backing$key", "1234a", dbName = "test"),
180+
storageKey = DatabaseStorageKey.Persistent("entity$key", "1234a", dbName = "test"),
181+
),
177182
type,
178183
emptyList()
179184
)
@@ -213,6 +218,22 @@ class UtilsTest(private val params: Params) {
213218
assertThat(isWriteOnlyStorageKey(partition, handle.storageKey)).isTrue()
214219
}
215220

221+
@Test
222+
fun isWriteOnlyStorageKey_withOneParticleAndAllWriteOnlyRamDiskConnections_isFalse() {
223+
BuildFlags.WRITE_ONLY_STORAGE_STACK = true
224+
225+
val handle = generateHandle("foo", collectionType, db = false)
226+
val connection = generateConnection(handle, collectionType, HandleMode.Write)
227+
val particle = generateParticle("foo", "bar" to connection)
228+
229+
val partition = Plan.Partition(
230+
"fooId",
231+
"fooHost",
232+
listOf(particle)
233+
)
234+
assertThat(isWriteOnlyStorageKey(partition, handle.storageKey)).isFalse()
235+
}
236+
216237
@Test
217238
fun isWriteOnlyStorageKey_withOneParticleAndOneSingletonConnection_isFalse() {
218239
BuildFlags.WRITE_ONLY_STORAGE_STACK = true

javatests/arcs/core/storage/WriteOnlyStorageProxyImplTest.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,10 +161,12 @@ class WriteOnlyStorageProxyImplTest {
161161
}
162162

163163
@Test
164-
fun storageEventReadyImmediatelyCalled() = runTest {
164+
fun storageEventReadyCalledAfterMaybeInitiateSync() = runTest {
165165
val proxy = mockProxy()
166166
val callback: () -> Unit = mock()
167167
proxy.registerForStorageEvents(callbackId) { callback() }
168+
proxy.prepareForSync()
169+
proxy.maybeInitiateSync()
168170
verify(callback).invoke()
169171
}
170172

third_party/java/arcs/flags/flags.bzl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ ARCS_BUILD_FLAGS = [
8585
name = "write_only_storage_stack",
8686
desc = "Optimized write-only storage stack.",
8787
bug_id = "b/181723292",
88-
status = "NOT_READY",
88+
status = "LAUNCHED",
8989
stopwords = [
9090
"write.?only.?storage.?stack",
9191
"DatabaseOp",

0 commit comments

Comments
 (0)