Skip to content

Commit 84bbbcb

Browse files
committed
Implement reference counting for frozen realms
1 parent da73241 commit 84bbbcb

File tree

2 files changed

+60
-16
lines changed

2 files changed

+60
-16
lines changed

realm/realm-library/src/androidTest/java/io/realm/FrozenObjectsTests.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,34 @@ public void freezeRealm() {
9393
frozenRealm.close();
9494
}
9595

96+
@Test
97+
public void freezeRealmTwice_atSameVersion() {
98+
// Freeze the realm twice at the same version
99+
assertFalse(realm.isFrozen());
100+
Realm frozenRealm1 = realm.freeze();
101+
Realm frozenRealm2 = realm.freeze();
102+
103+
// If we close one frozen instance, the other instance should be unaffected
104+
frozenRealm2.close();
105+
assertFalse(frozenRealm1.isClosed());
106+
frozenRealm1.close();
107+
}
108+
109+
@Test
110+
public void freezeRealmTwice_atDifferentVersions() {
111+
// Freeze the realm twice at different versions
112+
assertFalse(realm.isFrozen());
113+
Realm frozenRealm1 = realm.freeze();
114+
realm.executeTransaction((Realm) -> realm.copyToRealm(new Dog("Woof", 3)));
115+
Realm frozenRealm2 = realm.freeze();
116+
117+
// If we close one frozen instance, the other instance should be unaffected
118+
frozenRealm1.close();
119+
assertTrue(frozenRealm1.isClosed());
120+
assertFalse(frozenRealm2.isClosed());
121+
frozenRealm2.close();
122+
}
123+
96124
@Test
97125
public void freezeDynamicRealm() {
98126
DynamicRealm dynamicRealm = DynamicRealm.getInstance(realmConfig);

realm/realm-library/src/main/java/io/realm/RealmCache.java

Lines changed: 32 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -70,19 +70,14 @@ interface Callback0 {
7070

7171
private abstract static class ReferenceCounter {
7272

73-
// How many references to this Realm instance in this thread.
74-
protected final ThreadLocal<Integer> localCount = new ThreadLocal<>();
7573
// How many threads have instances refer to this configuration.
7674
protected AtomicInteger globalCount = new AtomicInteger(0);
7775

7876
// Returns `true` if an instance of the Realm is available on the caller thread.
7977
abstract boolean hasInstanceAvailableForThread();
8078

8179
// Increment how many times an instance has been handed out for the current thread.
82-
public void incrementThreadCount(int increment) {
83-
Integer currentCount = localCount.get();
84-
localCount.set(currentCount != null ? currentCount + increment : increment);
85-
}
80+
public abstract void incrementThreadCount(int increment);
8681

8782
// Returns the Realm instance for the caller thread
8883
abstract BaseRealm getRealmInstance();
@@ -97,11 +92,9 @@ public void incrementThreadCount(int increment) {
9792
abstract int getThreadLocalCount();
9893

9994
// Updates the number of references handed out for a given thread
100-
public void setThreadCount(int refCount) {
101-
localCount.set(refCount);
102-
}
95+
public abstract void setThreadCount(int refCount);
10396

104-
// Returns the number of gloal instances handed out. This is roughly equivalent
97+
// Returns the number of global instances handed out. This is roughly equivalent
10598
// to the number of threads currently using the Realm as each thread also does
10699
// reference counting of Realm instances.
107100
public int getGlobalCount() {
@@ -118,6 +111,11 @@ boolean hasInstanceAvailableForThread() {
118111
return cachedRealm != null;
119112
}
120113

114+
@Override
115+
public void incrementThreadCount(int increment) {
116+
globalCount.addAndGet(increment);
117+
}
118+
121119
@Override
122120
BaseRealm getRealmInstance() {
123121
return cachedRealm;
@@ -128,19 +126,17 @@ void onRealmCreated(BaseRealm realm) {
128126
// The Realm instance has been created without exceptions. Cache and reference count can be updated now.
129127
cachedRealm = realm;
130128

131-
localCount.set(0);
132-
// This is the first instance in current thread, increase the global count.
133-
globalCount.incrementAndGet();
129+
// The global count for a frozen Realm has the same role as the local count for a live
130+
// Realm, so initialise it to 0.
131+
globalCount.set(0);
134132

135133
}
136134

137135
@Override
138136
public void clearThreadLocalCache() {
139137
String canonicalPath = cachedRealm.getPath();
140138

141-
// The last instance in this thread.
142-
// Clears local ref & counter.
143-
localCount.set(null);
139+
// The last instance of this frozen Realm. Clear reference.
144140
cachedRealm = null;
145141

146142
// Clears global counter.
@@ -156,18 +152,33 @@ int getThreadLocalCount() {
156152
// of a thread local count doesn't make sense. Just return the global count instead.
157153
return globalCount.get();
158154
}
155+
156+
@Override
157+
public void setThreadCount(int refCount) {
158+
// Since the concept of a thread local count doesn't make sense, we instead set the
159+
// global count here.
160+
globalCount.set(refCount);
161+
}
159162
}
160163

161164
// Reference counter for Realms that are thread confined
162165
private static class ThreadConfinedReferenceCounter extends ReferenceCounter {
163166
// The Realm instance in this thread.
164167
private final ThreadLocal<BaseRealm> localRealm = new ThreadLocal<>();
168+
// How many references to this Realm instance in this thread.
169+
private final ThreadLocal<Integer> localCount = new ThreadLocal<>();
165170

166171
@Override
167172
public boolean hasInstanceAvailableForThread() {
168173
return localRealm.get() != null;
169174
}
170175

176+
@Override
177+
public void incrementThreadCount(int increment) {
178+
Integer currentCount = localCount.get();
179+
localCount.set(currentCount != null ? currentCount + increment : increment);
180+
}
181+
171182
@Override
172183
public BaseRealm getRealmInstance() {
173184
return localRealm.get();
@@ -203,6 +214,11 @@ public int getThreadLocalCount() {
203214
Integer refCount = localCount.get();
204215
return (refCount != null) ? refCount : 0;
205216
}
217+
218+
@Override
219+
public void setThreadCount(int refCount) {
220+
localCount.set(refCount);
221+
}
206222
}
207223

208224
private enum RealmCacheType {

0 commit comments

Comments
 (0)