diff --git a/realm/realm-library/src/androidTest/java/io/realm/FrozenObjectsTests.java b/realm/realm-library/src/androidTest/java/io/realm/FrozenObjectsTests.java index 28332d8561..4b8b8155cb 100644 --- a/realm/realm-library/src/androidTest/java/io/realm/FrozenObjectsTests.java +++ b/realm/realm-library/src/androidTest/java/io/realm/FrozenObjectsTests.java @@ -93,6 +93,34 @@ public void freezeRealm() { frozenRealm.close(); } + @Test + public void freezeRealmTwice_atSameVersion() { + // Freeze the realm twice at the same version + assertFalse(realm.isFrozen()); + Realm frozenRealm1 = realm.freeze(); + Realm frozenRealm2 = realm.freeze(); + + // If we close one frozen instance, the other instance should be unaffected + frozenRealm2.close(); + assertFalse(frozenRealm1.isClosed()); + frozenRealm1.close(); + } + + @Test + public void freezeRealmTwice_atDifferentVersions() { + // Freeze the realm twice at different versions + assertFalse(realm.isFrozen()); + Realm frozenRealm1 = realm.freeze(); + realm.executeTransaction((Realm) -> realm.copyToRealm(new Dog("Woof", 3))); + Realm frozenRealm2 = realm.freeze(); + + // If we close one frozen instance, the other instance should be unaffected + frozenRealm1.close(); + assertTrue(frozenRealm1.isClosed()); + assertFalse(frozenRealm2.isClosed()); + frozenRealm2.close(); + } + @Test public void freezeDynamicRealm() { DynamicRealm dynamicRealm = DynamicRealm.getInstance(realmConfig); diff --git a/realm/realm-library/src/main/java/io/realm/RealmCache.java b/realm/realm-library/src/main/java/io/realm/RealmCache.java index f3149eae35..78a56bed05 100644 --- a/realm/realm-library/src/main/java/io/realm/RealmCache.java +++ b/realm/realm-library/src/main/java/io/realm/RealmCache.java @@ -70,8 +70,6 @@ interface Callback0 { private abstract static class ReferenceCounter { - // How many references to this Realm instance in this thread. - protected final ThreadLocal localCount = new ThreadLocal<>(); // How many threads have instances refer to this configuration. protected AtomicInteger globalCount = new AtomicInteger(0); @@ -79,10 +77,7 @@ private abstract static class ReferenceCounter { abstract boolean hasInstanceAvailableForThread(); // Increment how many times an instance has been handed out for the current thread. - public void incrementThreadCount(int increment) { - Integer currentCount = localCount.get(); - localCount.set(currentCount != null ? currentCount + increment : increment); - } + public abstract void incrementThreadCount(int increment); // Returns the Realm instance for the caller thread abstract BaseRealm getRealmInstance(); @@ -97,11 +92,9 @@ public void incrementThreadCount(int increment) { abstract int getThreadLocalCount(); // Updates the number of references handed out for a given thread - public void setThreadCount(int refCount) { - localCount.set(refCount); - } + public abstract void setThreadCount(int refCount); - // Returns the number of gloal instances handed out. This is roughly equivalent + // Returns the number of global instances handed out. This is roughly equivalent // to the number of threads currently using the Realm as each thread also does // reference counting of Realm instances. public int getGlobalCount() { @@ -118,6 +111,11 @@ boolean hasInstanceAvailableForThread() { return cachedRealm != null; } + @Override + public void incrementThreadCount(int increment) { + globalCount.addAndGet(increment); + } + @Override BaseRealm getRealmInstance() { return cachedRealm; @@ -128,9 +126,9 @@ void onRealmCreated(BaseRealm realm) { // The Realm instance has been created without exceptions. Cache and reference count can be updated now. cachedRealm = realm; - localCount.set(0); - // This is the first instance in current thread, increase the global count. - globalCount.incrementAndGet(); + // The global count for a frozen Realm has the same role as the local count for a live + // Realm, so initialise it to 0. + globalCount.set(0); } @@ -138,9 +136,7 @@ void onRealmCreated(BaseRealm realm) { public void clearThreadLocalCache() { String canonicalPath = cachedRealm.getPath(); - // The last instance in this thread. - // Clears local ref & counter. - localCount.set(null); + // The last instance of this frozen Realm. Clear reference. cachedRealm = null; // Clears global counter. @@ -156,18 +152,33 @@ int getThreadLocalCount() { // of a thread local count doesn't make sense. Just return the global count instead. return globalCount.get(); } + + @Override + public void setThreadCount(int refCount) { + // Since the concept of a thread local count doesn't make sense, we instead set the + // global count here. + globalCount.set(refCount); + } } // Reference counter for Realms that are thread confined private static class ThreadConfinedReferenceCounter extends ReferenceCounter { // The Realm instance in this thread. private final ThreadLocal localRealm = new ThreadLocal<>(); + // How many references to this Realm instance in this thread. + private final ThreadLocal localCount = new ThreadLocal<>(); @Override public boolean hasInstanceAvailableForThread() { return localRealm.get() != null; } + @Override + public void incrementThreadCount(int increment) { + Integer currentCount = localCount.get(); + localCount.set(currentCount != null ? currentCount + increment : increment); + } + @Override public BaseRealm getRealmInstance() { return localRealm.get(); @@ -203,6 +214,11 @@ public int getThreadLocalCount() { Integer refCount = localCount.get(); return (refCount != null) ? refCount : 0; } + + @Override + public void setThreadCount(int refCount) { + localCount.set(refCount); + } } private enum RealmCacheType {