1 /* 2 * Copyright 2022 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.datastore.core.handlers.NoOpCorruptionHandler 20 import androidx.datastore.core.handlers.ReplaceFileCorruptionHandler 21 import java.io.File 22 import kotlinx.coroutines.CoroutineScope 23 import kotlinx.coroutines.Dispatchers 24 import kotlinx.coroutines.SupervisorJob 25 26 public object MultiProcessDataStoreFactory { 27 /** 28 * Create an instance of MultiProcessDataStore, which provides cross-process eventual 29 * consistency. Never create more than one instance of DataStore for a given file in the same 30 * process; doing so can break all DataStore functionality. You should consider managing your 31 * DataStore instance for each file as a singleton. If there are multiple DataStores active for 32 * a given file in the same process, DataStore will throw IllegalStateException when reading or 33 * updating data. A DataStore is considered active as long as its scope is active. Having 34 * multiple instances, each for a different file, in the same process is OK. 35 * 36 * T is the type DataStore acts on. The type T must be immutable. Mutating a type used in 37 * DataStore invalidates any guarantees that DataStore provides and will result in potentially 38 * serious, hard-to-catch bugs. We strongly recommend using protocol buffers: 39 * https://developers.google.com/protocol-buffers/docs/javatutorial - which provides 40 * immutability guarantees, a simple API and efficient serialization. 41 * 42 * @param storage Storage to handle file reads and writes used with DataStore. The type T must 43 * be immutable. The storage must operate on the same file as the one passed in {@link 44 * produceFile}. 45 * @param corruptionHandler The [ReplaceFileCorruptionHandler] is invoked if DataStore 46 * encounters a [CorruptionException] when attempting to read data. CorruptionExceptions are 47 * thrown by serializers when data can not be de-serialized. 48 * @param migrations Migrations are run before any access to data can occur. Migrations must be 49 * idempotent. 50 * @param scope The scope in which IO operations and transform functions will execute. 51 * @return a new DataStore instance with the provided configuration 52 */ 53 @JvmOverloads // Generate constructors for default params for java users. createnull54 public fun <T> create( 55 storage: Storage<T>, 56 corruptionHandler: ReplaceFileCorruptionHandler<T>? = null, 57 migrations: List<DataMigration<T>> = listOf(), 58 scope: CoroutineScope = CoroutineScope(Dispatchers.IO + SupervisorJob()) 59 ): DataStore<T> = 60 DataStoreImpl<T>( 61 storage = storage, 62 initTasksList = listOf(DataMigrationInitializer.getInitializer(migrations)), 63 corruptionHandler = corruptionHandler ?: NoOpCorruptionHandler(), 64 scope = scope 65 ) 66 67 /** 68 * Create an instance of MultiProcessDataStore, which provides cross-process eventual 69 * consistency. Never create more than one instance of DataStore for a given file in the same 70 * process; doing so can break all DataStore functionality. You should consider managing your 71 * DataStore instance for each file as a singleton. If there are multiple DataStores active for 72 * a given file in the same process, DataStore will throw IllegalStateException when reading or 73 * updating data. A DataStore is considered active as long as its scope is active. Having 74 * multiple instances, each for a different file, in the same process is OK. 75 * 76 * T is the type DataStore acts on. The type T must be immutable. Mutating a type used in 77 * DataStore invalidates any guarantees that DataStore provides and will result in potentially 78 * serious, hard-to-catch bugs. We strongly recommend using protocol buffers: 79 * https://developers.google.com/protocol-buffers/docs/javatutorial - which provides 80 * immutability guarantees, a simple API and efficient serialization. 81 * 82 * @param serializer Serializer for the type T used with DataStore. The type T must be 83 * immutable. 84 * @param corruptionHandler The {@link 85 * androidx.datastore.core.handlers.ReplaceFileCorruptionHandler} is invoked if DataStore 86 * encounters a [CorruptionException] when attempting to read data. CorruptionExceptions are 87 * thrown by serializers when data can not be de-serialized. 88 * @param migrations Migrations are run before any access to data can occur. Migrations must be 89 * idempotent. 90 * @param scope The scope in which IO operations and transform functions will execute. 91 * @param produceFile Function which returns the file that the new DataStore will act on. The 92 * function must return the same path every time. No two instances of DataStore should act on 93 * the same file at the same time in the same process. 94 * @return a new DataStore instance with the provided configuration 95 */ 96 @JvmOverloads // Generate constructors for default params for java users. 97 public fun <T> create( 98 serializer: Serializer<T>, 99 corruptionHandler: ReplaceFileCorruptionHandler<T>? = null, 100 migrations: List<DataMigration<T>> = listOf(), 101 scope: CoroutineScope = CoroutineScope(Dispatchers.IO + SupervisorJob()), 102 produceFile: () -> File 103 ): DataStore<T> = 104 DataStoreImpl<T>( 105 storage = 106 FileStorage( 107 serializer, 108 { MultiProcessCoordinator(scope.coroutineContext, it) }, 109 produceFile 110 ), 111 initTasksList = listOf(DataMigrationInitializer.getInitializer(migrations)), 112 corruptionHandler = corruptionHandler ?: NoOpCorruptionHandler(), 113 scope = scope 114 ) 115 } 116