Fix datastore performance regression for update_withoutValueChange

Bug: 327517311
Test: ./gradlew :datastore:datastore-core:jvmTest
Change-Id: I5711ccbb5eb21b58075b628b743e476c145f3319
diff --git a/datastore/datastore-core/src/androidInstrumentedTest/kotlin/androidx/datastore/core/MultiProcessDataStoreSingleProcessTest.kt b/datastore/datastore-core/src/androidInstrumentedTest/kotlin/androidx/datastore/core/MultiProcessDataStoreSingleProcessTest.kt
index 9ecbb53..cb15048 100644
--- a/datastore/datastore-core/src/androidInstrumentedTest/kotlin/androidx/datastore/core/MultiProcessDataStoreSingleProcessTest.kt
+++ b/datastore/datastore-core/src/androidInstrumentedTest/kotlin/androidx/datastore/core/MultiProcessDataStoreSingleProcessTest.kt
@@ -952,6 +952,17 @@
         StrictMode.allowThreadDiskWrites()
     }
 
+    @Test
+    fun testWriteSameValueSkipDisk() = runTest {
+        // write a non-default value to force a disk write
+        store.updateData { 10 }
+        assertThat(serializerConfig.writeCount).isEqualTo(1)
+
+        // write same value again
+        store.updateData { 10 }
+        assertThat(serializerConfig.writeCount).isEqualTo(1)
+    }
+
     // Mutable wrapper around a byte
     data class ByteWrapper(var byte: Byte) {
         internal class ByteWrapperSerializer() : Serializer<ByteWrapper> {
diff --git a/datastore/datastore-core/src/commonMain/kotlin/androidx/datastore/core/DataStoreImpl.kt b/datastore/datastore-core/src/commonMain/kotlin/androidx/datastore/core/DataStoreImpl.kt
index 89f7160..35caa9c 100644
--- a/datastore/datastore-core/src/commonMain/kotlin/androidx/datastore/core/DataStoreImpl.kt
+++ b/datastore/datastore-core/src/commonMain/kotlin/androidx/datastore/core/DataStoreImpl.kt
@@ -341,7 +341,7 @@
         // Check that curData has not changed...
         curData.checkHashCode()
 
-        if (curData != newData) {
+        if (curData.value != newData) {
             writeData(newData, updateCache = true)
         }
         newData
diff --git a/datastore/datastore-core/src/commonTest/kotlin/androidx/datastore/core/SingleProcessDataStoreTest.kt b/datastore/datastore-core/src/commonTest/kotlin/androidx/datastore/core/SingleProcessDataStoreTest.kt
index 92f53a3..fb364a6 100644
--- a/datastore/datastore-core/src/commonTest/kotlin/androidx/datastore/core/SingleProcessDataStoreTest.kt
+++ b/datastore/datastore-core/src/commonTest/kotlin/androidx/datastore/core/SingleProcessDataStoreTest.kt
@@ -1142,6 +1142,17 @@
         }
     }
 
+    @Test
+    fun testWriteSameValueSkipDisk() = runTest {
+        // write a non-default value to force a disk write
+        store.updateData { 10 }
+        assertThat(serializerConfig.writeCount).isEqualTo(1)
+
+        // write same value again
+        store.updateData { 10 }
+        assertThat(serializerConfig.writeCount).isEqualTo(1)
+    }
+
     private class TestingCorruptionHandler(
         private val replaceWith: Byte? = null
     ) : CorruptionHandler<Byte> {
diff --git a/testutils/testutils-datastore/src/commonMain/kotlin/androidx/datastore/TestingOkioSerializer.kt b/testutils/testutils-datastore/src/commonMain/kotlin/androidx/datastore/TestingOkioSerializer.kt
index 61fa156..2a0a0bb 100644
--- a/testutils/testutils-datastore/src/commonMain/kotlin/androidx/datastore/TestingOkioSerializer.kt
+++ b/testutils/testutils-datastore/src/commonMain/kotlin/androidx/datastore/TestingOkioSerializer.kt
@@ -51,6 +51,7 @@
     }
 
     override suspend fun writeTo(t: Byte, sink: BufferedSink) {
+        config.writeCount++
         if (config.failingWrite) {
             throw IOException("I was asked to fail on writes")
         }
diff --git a/testutils/testutils-datastore/src/commonMain/kotlin/androidx/datastore/TestingSerializerConfig.kt b/testutils/testutils-datastore/src/commonMain/kotlin/androidx/datastore/TestingSerializerConfig.kt
index 8186ad9..6c9c946 100644
--- a/testutils/testutils-datastore/src/commonMain/kotlin/androidx/datastore/TestingSerializerConfig.kt
+++ b/testutils/testutils-datastore/src/commonMain/kotlin/androidx/datastore/TestingSerializerConfig.kt
@@ -27,4 +27,7 @@
     // TestSerializer uses the values from this list in sequence first before it always uses the
     // value of failReadWithCorruptionException.
     @Volatile var listOfFailReadWithCorruptionException: List<Boolean> = listOf(),
+    // This field enables the TestingSerializer to keep the count of file writes that is readable
+    // from the test methods.
+    @Volatile var writeCount: Int = 0,
 )
diff --git a/testutils/testutils-datastore/src/jvmMain/kotlin/androidx/datastore/TestingSerializer.jvm.kt b/testutils/testutils-datastore/src/jvmMain/kotlin/androidx/datastore/TestingSerializer.jvm.kt
index 007d973..ef20c6c 100644
--- a/testutils/testutils-datastore/src/jvmMain/kotlin/androidx/datastore/TestingSerializer.jvm.kt
+++ b/testutils/testutils-datastore/src/jvmMain/kotlin/androidx/datastore/TestingSerializer.jvm.kt
@@ -51,6 +51,7 @@
     }
 
     override suspend fun writeTo(t: Byte, output: OutputStream) {
+        config.writeCount++
         if (config.failingWrite) {
             throw IOException("I was asked to fail on writes")
         }