Infinito Nirone 7

白羽の矢を刺すスタイル

マルチプロセスに対応した DataStore とプロセス間の排他制御

androidx.datastore の DataStore はデータを非同期にストレージへ読み書きするためのフレームワークです。

DataStore は 1 つのファイルに対しデータの読み書きを実行するので、同一のプロセス内では必ず DataStore のインスタンスは 1 つ(シングルトン)に限らなければなりません。同一プロセス内で複数のおなじ DataStore インスタンスを使おうとすると例外が発生します。この制限は複数のプロセスで同じ DataStore を使う場合にも適用されますが、Java/Kotlin が提供している Mutex や Semaphore などではプロセスを超える排他制御ができないため、DataStore の作り方がすこし異なります。

複数のプロセスで同一の DataStore を使う場合、DataStore は MultiProcessDataStoreFactory をつかって初期化します。このとき、どのプロセスでも必ず MultiProcessDataStoreFactory を使って初期化しなければなりません。 MultiProcessDataStoreFactory を使うと、内部で FileLock を使ったファイルロックの仕組みで排他制御されます。

ファイルロックによる排他制御は MultiProcessCoordinator が実装していて、実はこの MultiProcessCoordinatorcreateMultiProcessCoordinator を呼び出すことで DataStore 以外の場所でも使えます。 次のコード例では DataStore は使わず Mutex を使うのと同じ感覚でクリティカルセクションを定義できます。 Kotlin では Mutex#withLock でブロックを抜けたときにロックを解除しますが、MultiProcessCoordinatorlock のブロックを抜けたときにファイルロックを解除します。

class Sample(
  coroutineScope: CoroutineScope,
) {
  private val lockFile = File(context.filesDir, "my_critical_section_lock")
  private val coordinator = createMultiProcessCoordinator(
    coroutineScope.coroutineContext,
    lockFile
  )

  suspend fun somethingImportant() {
    coordinator.lock {
      // critical section
      // do some work!
    }
  }
}