1 /* 2 * Copyright 2023 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package androidx.datastore.core 18 19 import androidx.annotation.RestrictTo 20 import kotlinx.coroutines.flow.Flow 21 22 /** 23 * InterProcessCoordinator provides functionalities that support DataStore instances to coordinate 24 * the concurrent work running on multiple threads and multiple processes to guarantee its data 25 * consistency. Typically users should use default coordinators provided by the library, including 26 * [createSingleProcessCoordinator] for use cases where DataStore is only used in a single process, 27 * and [createMultiProcessCoordinator] for a DataStore that needs to be accessed in multiple 28 * processes. 29 */ 30 interface InterProcessCoordinator { 31 32 /** 33 * A flow that emits a Unit when the data for the DataStore changes. [DataStore] collects this 34 * flow to signal the action to invalidate cache and re-read data from disk. 35 */ 36 val updateNotifications: Flow<Unit> 37 38 /** 39 * Get the exclusive lock shared by the coordinators from DataStore instances (even from 40 * different processes) to run a suspending code [block] that returns type `T`. It guarantees 41 * one-at-a-time execution for all the [block] called with this method. If some other process or 42 * thread is holding the lock, it will wait until the lock is available. 43 * 44 * @param block The block of code that is performed with the lock resource. 45 */ locknull46 suspend fun <T> lock(block: suspend () -> T): T 47 48 /** 49 * Attempt to get the exclusive lock shared by the coordinators from DataStore instances (even 50 * from different processes) and run the code [block] regardless of the attempt result. Pass a 51 * boolean to [block] to indicate if the attempt succeeds. If the attempt fails, [block] will 52 * run immediately after the attempt, without waiting for the lock to become available. 53 * 54 * @param block The block of code that is performed after attempting to get the lock resource. 55 * Block will receive a Boolean parameter which is true if the try lock succeeded. 56 */ 57 suspend fun <T> tryLock(block: suspend (Boolean) -> T): T 58 59 /** 60 * Atomically get the current version. [DataStore] instances for the same data use this method 61 * to access the shared version for its cached data and internal state. Notice concurrent access 62 * to the version should guarantee data consistency. 63 */ 64 suspend fun getVersion(): Int 65 66 /** 67 * Atomically increment version and return the new version. [DataStore] instances for the same 68 * data use this method to access the shared version for its cached data and internal state. 69 * Notice concurrent access to the version should guarantee data consistency. 70 * 71 * Note that the number of calls to the `incrementAndGetVersion` is an internal implementation 72 * detail for DataStore and implementers of this API should not make any assumption based on the 73 * number of version increments. 74 */ 75 suspend fun incrementAndGetVersion(): Int 76 } 77 78 /** 79 * Create a coordinator for single process use cases. 80 * 81 * @param filePath The canonical file path of the file managed by [SingleProcessCoordinator] 82 */ 83 @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) 84 fun createSingleProcessCoordinator(filePath: String): InterProcessCoordinator = 85 SingleProcessCoordinator(filePath) 86