27
27
* but, contrary to the store, it initializes {@link Map.Entry}s eagerly to optimize iteration
28
28
* performance and avoid type-pollution issues when checking the type of contained objects.
29
29
* <p>
30
+ * Instance ids are considered to start from 1, and if two instances are found to have the
31
+ * same identifier a {@link java.util.ConcurrentModificationException will be thrown}.
32
+ * <p>
30
33
* Methods accessing / modifying the map with {@link Object} typed parameters will need
31
34
* to type check against the instance identity interface which might be inefficient,
32
35
* so it's recommended to use the position (int) based variant of those methods.
@@ -107,9 +110,21 @@ private boolean containsMapping(Object key, Object value) {
107
110
* equality check ({@code ==}) with the provided key to ensure it corresponds to the mapped one
108
111
*/
109
112
public @ Nullable V get (int instanceId , Object key ) {
110
- final Entry <K , V > entry = get ( instanceId );
111
- if ( entry != null && entry .getKey () == key ) {
112
- return entry .getValue ();
113
+ if ( instanceId <= 0 ) {
114
+ return null ;
115
+ }
116
+
117
+ final Entry <K , V > entry = get ( instanceId - 1 );
118
+ if ( entry != null ) {
119
+ if ( entry .getKey () == key ) {
120
+ return entry .getValue ();
121
+ }
122
+ else {
123
+ throw new ConcurrentModificationException (
124
+ "Found a different instance corresponding to instanceId [" + instanceId +
125
+ "], this might indicate a concurrent access to this persistence context."
126
+ );
127
+ }
113
128
}
114
129
return null ;
115
130
}
@@ -133,8 +148,12 @@ private boolean containsMapping(Object key, Object value) {
133
148
throw new NullPointerException ( "This map does not support null keys" );
134
149
}
135
150
136
- final int instanceId = key .$$_hibernate_getInstanceId ();
137
- final Map .Entry <K , V > old = set ( instanceId , new AbstractMap .SimpleImmutableEntry <>( key , value ) );
151
+ final int index = key .$$_hibernate_getInstanceId () - 1 ;
152
+ if ( index < 0 ) {
153
+ throw new IllegalArgumentException ( "Instance ID must be a positive value" );
154
+ }
155
+
156
+ final Map .Entry <K , V > old = set ( index , new AbstractMap .SimpleImmutableEntry <>( key , value ) );
138
157
if ( old == null ) {
139
158
size ++;
140
159
return null ;
@@ -154,9 +173,14 @@ private boolean containsMapping(Object key, Object value) {
154
173
* equality check ({@code ==}) with the provided key to ensure it corresponds to the mapped one
155
174
*/
156
175
public @ Nullable V remove (int instanceId , Object key ) {
157
- final Page <Map .Entry <K , V >> page = getPage ( instanceId );
176
+ if ( instanceId <= 0 ) {
177
+ return null ;
178
+ }
179
+
180
+ final int index = instanceId - 1 ;
181
+ final Page <Map .Entry <K , V >> page = getPage ( index );
158
182
if ( page != null ) {
159
- final int pageOffset = toPageOffset ( instanceId );
183
+ final int pageOffset = toPageOffset ( index );
160
184
final Map .Entry <K , V > entry = page .set ( pageOffset , null );
161
185
// Check that the provided instance really matches with the key contained in the map
162
186
if ( entry != null ) {
@@ -165,8 +189,10 @@ private boolean containsMapping(Object key, Object value) {
165
189
return entry .getValue ();
166
190
}
167
191
else {
168
- // If it doesn't, reset the array value to the old key
169
- page .set ( pageOffset , entry );
192
+ throw new ConcurrentModificationException (
193
+ "Found a different instance corresponding to instanceId [" + instanceId +
194
+ "], this might indicate a concurrent access to this persistence context."
195
+ );
170
196
}
171
197
}
172
198
}
0 commit comments