Skip to content

Commit

Permalink
OptimisticLockException while using L2 cache fix (#2248) (#2252)
Browse files Browse the repository at this point in the history
Under specific conditions is org.eclipse.persistence.exceptions.OptimisticLockException incorrectly thrown.
Environment conditions are:

    JPA L2 cache enabled
    Weaving is applied to used entities
    @Version annotation is used

Test org.eclipse.persistence.testing.tests.advanced2.weave.WeaveVersionTest#testWeavedEntitiesWithVersionL2Cache describe sequence of steps which leads into org.eclipse.persistence.exceptions.OptimisticLockException if fix is not applied.

Purpose of fix in org.eclipse.persistence.internal.sessions.UnitOfWorkImpl#cloneAndRegisterObject(java.lang.Object, org.eclipse.persistence.internal.identitymaps.CacheKey, org.eclipse.persistence.internal.identitymaps.CacheKey, org.eclipse.persistence.descriptors.ClassDescriptor) is update current working object with non-invalidated version from UnitOfWork scope if original is still invalid.

Signed-off-by: Radek Felcman <[email protected]>
(cherry picked from commit c4fc6f1)
  • Loading branch information
rfelcman authored Aug 26, 2024
1 parent e012b74 commit 178d3f2
Show file tree
Hide file tree
Showing 7 changed files with 495 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1074,6 +1074,9 @@ public Object cloneAndRegisterObject(Object original, CacheKey parentCacheKey, C
}
}
try {
if (isConsideredInvalid(original, parentCacheKey, descriptor) && unitOfWorkCacheKey.getObject() != null) {
original = unitOfWorkCacheKey.getObject();
}
// bug:6167576 Must acquire the lock before cloning.
workingClone = builder.instantiateWorkingCopyClone(original, this);
// PERF: Cache the primary key if implements PersistenceEntity.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -209,4 +209,17 @@
</properties>
</persistence-unit>

<persistence-unit name="pu-with-dynamic-weaving" transaction-type="RESOURCE_LOCAL">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<class>org.eclipse.persistence.testing.models.jpa21.advanced.weave.IsolatedEntity</class>
<class>org.eclipse.persistence.testing.models.jpa21.advanced.weave.Location</class>
<class>org.eclipse.persistence.testing.models.jpa21.advanced.weave.Node</class>
<class>org.eclipse.persistence.testing.models.jpa21.advanced.weave.Order</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
<shared-cache-mode>DISABLE_SELECTIVE</shared-cache-mode>
<properties>
<property name="eclipselink.weaving" value="true"/>
<property name="jakarta.persistence.schema-generation.database.action" value="drop-and-create"/>
</properties>
</persistence-unit>
</persistence>
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0,
* or the Eclipse Distribution License v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
package org.eclipse.persistence.testing.models.jpa21.advanced.weave;

import java.util.Objects;

import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import jakarta.persistence.Version;

@Entity
@Table(name="JPA21_ISOLATED_ENTITY")
public class IsolatedEntity {

@Id
protected String id;

@Version
protected Integer version;

public IsolatedEntity() {
super();
}

public IsolatedEntity(String id) {
this.id = id;
}

public String getId() {
return id;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
IsolatedEntity that = (IsolatedEntity) o;
return Objects.equals(id, that.id) && Objects.equals(version, that.version);
}

@Override
public int hashCode() {
return Objects.hash(id, version);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/*
* Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0,
* or the Eclipse Distribution License v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
package org.eclipse.persistence.testing.models.jpa21.advanced.weave;

import java.util.Objects;

import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.Id;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
import jakarta.persistence.Version;

@Entity
@Table(name="JPA21_LOCATION")
public class Location {

@Id
protected Long id;

protected String locationId;

@ManyToOne(fetch = FetchType.LAZY)
protected Node node;

@Version
protected Integer version;

public Location(long id, String locationId) {
this.id = id;
this.locationId = locationId;
}

protected Location() {
}

public Long getId() {
return this.id;
}

public String getLocationId() {
return this.locationId;
}

public Node getNode() {
return node;
}

public void setNode(Node node) {
this.node = node;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Location location = (Location) o;
return Objects.equals(id, location.id) && Objects.equals(locationId, location.locationId) && Objects.equals(node, location.node) && Objects.equals(version, location.version);
}

@Override
public int hashCode() {
return Objects.hash(id, locationId, node, version);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/*
* Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0,
* or the Eclipse Distribution License v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
package org.eclipse.persistence.testing.models.jpa21.advanced.weave;

import java.util.Objects;

import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import jakarta.persistence.Version;

@Entity
@Table(name="JPA21_NODE")
public class Node {

@Id
protected String id;

protected int availableBufferCapacity = 10;

@Version
protected Integer version;

public Node(String id) {
this.id = id;
}

protected Node() {
}

public String getId() {
return id;
}

public int getAvailableBufferCapacity() {
return availableBufferCapacity;
}

public void reserveBufferCapacity() {
availableBufferCapacity--;
}

public Integer getVersion() {
return version;
}

/*
public void setVersion(Integer version) {
this.version = version;
}
*/

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Node node = (Node) o;
return availableBufferCapacity == node.availableBufferCapacity && Objects.equals(id, node.id) && Objects.equals(version, node.version);
}

@Override
public int hashCode() {
return Objects.hash(id, availableBufferCapacity, version);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*
* Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0,
* or the Eclipse Distribution License v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
package org.eclipse.persistence.testing.models.jpa21.advanced.weave;

import java.util.Objects;

import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.Id;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
import jakarta.persistence.Version;

@Entity
@Table(name="JPA21_ORDER_1")
public class Order {

@Id
protected Long id;

@ManyToOne(fetch = FetchType.LAZY)
protected Node node;

@Version
protected Integer version;

protected Order() {
}

public Order(long id) {

this.id = id;
}

public Long getId() {
return id;
}

public Node getNode() {
return node;
}

public void setNode(Node destinationNode) {
this.node = destinationNode;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Order order = (Order) o;
return Objects.equals(id, order.id) && Objects.equals(node, order.node) && Objects.equals(version, order.version);
}

@Override
public int hashCode() {
return Objects.hash(id, node, version);
}
}
Loading

0 comments on commit 178d3f2

Please sign in to comment.