From efb178f0afe0c40d029561103f7b4aa63c0e5737 Mon Sep 17 00:00:00 2001 From: M66B Date: Tue, 22 Mar 2022 07:56:33 +0100 Subject: [PATCH] Revert ROOM 2.4.1 --- app/build.gradle | 2 +- .../androidx/room/InvalidationTracker.java | 48 +++++++++++++------ 2 files changed, 34 insertions(+), 16 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 72d5e9de63..27728ae028 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -345,7 +345,7 @@ dependencies { def documentfile_version = "1.1.0-alpha01" def lifecycle_version = "2.4.0" // 2.5.0-alpha04 def lifecycle_extensions_version = "2.2.0" - def room_version = "2.4.2" // 2.5.0-alpha01 + def room_version = "2.4.1" // 2.5.0-alpha01 def sqlite_version = "2.2.0" // 2.3.0-alpha01 def requery_version = "3.36.0" def paging_version = "2.1.2" // 3.1.1 diff --git a/app/src/main/java/androidx/room/InvalidationTracker.java b/app/src/main/java/androidx/room/InvalidationTracker.java index 3a0c5ca530..fe0ae9a9ae 100644 --- a/app/src/main/java/androidx/room/InvalidationTracker.java +++ b/app/src/main/java/androidx/room/InvalidationTracker.java @@ -104,7 +104,7 @@ public class InvalidationTracker { @SuppressWarnings("WeakerAccess") /* synthetic access */ volatile SupportSQLiteStatement mCleanupStatement; - private final ObservedTableTracker mObservedTableTracker; + private ObservedTableTracker mObservedTableTracker; private final InvalidationLiveDataContainer mInvalidationLiveDataContainer; @@ -115,8 +115,6 @@ public class InvalidationTracker { private MultiInstanceInvalidationClient mMultiInstanceInvalidationClient; - private final Object mSyncTriggersLock = new Object(); - /** * Used by the generated code. * @@ -539,13 +537,14 @@ public class InvalidationTracker { return; } try { - Lock closeLock = mDatabase.getCloseLock(); - closeLock.lock(); - try { - // Serialize adding and removing table trackers, this is specifically important - // to avoid missing invalidation before a transaction starts but there are - // pending (possibly concurrent) observer changes. - synchronized (mSyncTriggersLock) { + // This method runs in a while loop because while changes are synced to db, another + // runnable may be skipped. If we cause it to skip, we need to do its work. + while (true) { + Lock closeLock = mDatabase.getCloseLock(); + closeLock.lock(); + try { + // there is a potential race condition where another mSyncTriggers runnable + // can start running right after we get the tables list to sync. final int[] tablesToSync = mObservedTableTracker.getTablesToSync(); if (tablesToSync == null) { return; @@ -567,9 +566,10 @@ public class InvalidationTracker { } finally { database.endTransaction(); } + mObservedTableTracker.onSyncCompleted(); + } finally { + closeLock.unlock(); } - } finally { - closeLock.unlock(); } } catch (IllegalStateException | SQLiteException exception) { // may happen if db is closed. just log. @@ -789,6 +789,13 @@ public class InvalidationTracker { boolean mNeedsSync; + /** + * After we return non-null value from getTablesToSync, we expect a onSyncCompleted before + * returning any non-null value from getTablesToSync. + * This allows us to workaround any multi-threaded state syncing issues. + */ + boolean mPendingSync; + ObservedTableTracker(int tableCount) { mTableObservers = new long[tableCount]; mTriggerStates = new boolean[tableCount]; @@ -845,7 +852,7 @@ public class InvalidationTracker { } /** - * If this returns non-null there are no pending sync operations. + * If this returns non-null, you must call onSyncCompleted. * * @return int[] An int array where the index for each tableId has the action for that * table. @@ -853,7 +860,7 @@ public class InvalidationTracker { @Nullable int[] getTablesToSync() { synchronized (this) { - if (!mNeedsSync) { + if (!mNeedsSync || mPendingSync) { return null; } final int tableCount = mTableObservers.length; @@ -866,8 +873,19 @@ public class InvalidationTracker { } mTriggerStates[i] = newState; } + mPendingSync = true; mNeedsSync = false; - return mTriggerStateChanges.clone(); + return mTriggerStateChanges; + } + } + + /** + * if getTablesToSync returned non-null, the called should call onSyncCompleted once it + * is done. + */ + void onSyncCompleted() { + synchronized (this) { + mPendingSync = false; } } }