Status Update
Comments
ow...@google.com <ow...@google.com>
ro...@google.com <ro...@google.com>
yb...@google.com <yb...@google.com> #2
there are some image for help
yb...@google.com <yb...@google.com> #4
I looked into this a bit but not straightforward.
There are 2 cases that will keep DatastoreImpl in memory: a) the scope callback the bug mentions b) the file watcher for multi-process
b is relatively easy to fix w/ a weak reference back.
a is hard. We require StorageConnection instances to be closed so SimpleActor cannot have a weak callback to DataStore.
We could try make that weak and try to close storage connection in the finalize block of DataStoreImpl but that might be a bit more tricky for kotlin native (but should be feasible via cleaner
).
Given that we are trying to go beta and this is a 1.0 issue, we likely won't be able to fix this in 1.1. A proper fix is likely providing a datastore.close
API. Though we might also go for a bigger change as we don't necessarily like the scope attachment decision we made in 1.0.
Description
Version used: 1.0.0
Theme used: N/A
Devices/Android versions reproduced on: Unit tests
The effect I am trying to achieve is to:
1. Create a `DataStore` for a particular file, that is shared when needed but is garbage-collectable when no longer needed
2. Create a new `DataStore` for that file when it has been garbage collected and is once again needed
This is currently difficult because:
1. Keeping a reference to a `DataStore`'s `scope` prevents it from being garbage collected
2. The only way to remove a value from `activeFiles` is to cancel the `DataStore`'s `scope`
One potential fix for this is to avoid capturing a strong reference to the `DataStore` or its `downstreamFlow` in the `consumeMessage` callback passed to `SimpleActor`. This would allow keeping a reference to the scope for cancellation while still allowing the DataStore and its value to be garbage-collectable.
The following code illustrates what I would like to do, but it loops forever at MARK A:
@Test fun test() {
val scope = CoroutineScope(Dispatchers.IO + SupervisorJob())
var store: DataStore<Unit>? = DataStoreFactory.create(
object : Serializer<Unit> {
override val defaultValue = Unit
override suspend fun readFrom(input: InputStream) = Unit
override suspend fun writeTo(t: Unit, output: OutputStream) {
}
},
produceFile = { File("/tmp/foo") },
scope = scope!!,
)
val storeReference = WeakReference(store)
store = null
while (storeReference.get() != null) { // MARK A
System.gc()
}
scope.cancel()
}