2727 * but, contrary to the store, it initializes {@link Map.Entry}s eagerly to optimize iteration
2828 * performance and avoid type-pollution issues when checking the type of contained objects.
2929 * <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>
3033 * Methods accessing / modifying the map with {@link Object} typed parameters will need
3134 * to type check against the instance identity interface which might be inefficient,
3235 * 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) {
107110 * equality check ({@code ==}) with the provided key to ensure it corresponds to the mapped one
108111 */
109112 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+ }
113128 }
114129 return null ;
115130 }
@@ -133,8 +148,12 @@ private boolean containsMapping(Object key, Object value) {
133148 throw new NullPointerException ( "This map does not support null keys" );
134149 }
135150
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 ) );
138157 if ( old == null ) {
139158 size ++;
140159 return null ;
@@ -154,9 +173,14 @@ private boolean containsMapping(Object key, Object value) {
154173 * equality check ({@code ==}) with the provided key to ensure it corresponds to the mapped one
155174 */
156175 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 );
158182 if ( page != null ) {
159- final int pageOffset = toPageOffset ( instanceId );
183+ final int pageOffset = toPageOffset ( index );
160184 final Map .Entry <K , V > entry = page .set ( pageOffset , null );
161185 // Check that the provided instance really matches with the key contained in the map
162186 if ( entry != null ) {
@@ -165,8 +189,10 @@ private boolean containsMapping(Object key, Object value) {
165189 return entry .getValue ();
166190 }
167191 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+ );
170196 }
171197 }
172198 }
0 commit comments