Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

[#907] Changed avoidCascadeSaveLoop to use a Set rather then a List.

Using a List for detecting save loops has severe performance implications -
approx O(n^2). Given a structure that had 2000 items in a list representing
a many-to-one relationship a save was taking approximately 90 seconds.
Switching to the Set dropped this to less that a second.
  • Loading branch information...
commit 65a95638280523dea9df6720f380125bf5f4cb0e 1 parent 79f1639
@markhibberd markhibberd authored mbknor committed
View
10 framework/src/play/db/jpa/JPABase.java
@@ -53,7 +53,7 @@ public void _save() {
em().persist(this);
PlayPlugin.postEvent("JPASupport.objectPersisted", this);
}
- avoidCascadeSaveLoops.set(new ArrayList<JPABase>());
+ avoidCascadeSaveLoops.set(new HashSet<JPABase>());
try {
saveAndCascade(true);
} finally {
@@ -68,7 +68,7 @@ public void _save() {
throw e;
}
}
- avoidCascadeSaveLoops.set(new ArrayList<JPABase>());
+ avoidCascadeSaveLoops.set(new HashSet<JPABase>());
try {
saveAndCascade(false);
} finally {
@@ -78,7 +78,7 @@ public void _save() {
public void _delete() {
try {
- avoidCascadeSaveLoops.set(new ArrayList<JPABase>());
+ avoidCascadeSaveLoops.set(new HashSet<JPABase>());
try {
saveAndCascade(true);
} finally {
@@ -94,7 +94,7 @@ public void _delete() {
throw e;
}
}
- avoidCascadeSaveLoops.set(new ArrayList<JPABase>());
+ avoidCascadeSaveLoops.set(new HashSet<JPABase>());
try {
saveAndCascade(false);
} finally {
@@ -114,7 +114,7 @@ public Object _key() {
// ~~~ SAVING
public transient boolean willBeSaved = false;
- static transient ThreadLocal<List<JPABase>> avoidCascadeSaveLoops = new ThreadLocal<List<JPABase>>();
+ static transient ThreadLocal<Set<JPABase>> avoidCascadeSaveLoops = new ThreadLocal<Set<JPABase>>();
private void saveAndCascade(boolean willBeSaved) {
this.willBeSaved = willBeSaved;
View
21 samples-and-tests/just-test-cases/app/models/Customer.java
@@ -0,0 +1,21 @@
+package models;
+
+import play.db.jpa.Model;
+import javax.persistence.*;
+import java.util.*;
+
+@Entity
+public class Customer extends Model {
+ public String name;
+
+ @OneToMany(mappedBy = "customer", cascade = CascadeType.ALL, orphanRemoval = true)
+ @OrderBy("id")
+ public List<Order> orders;
+
+ public Customer() {}
+
+ public Customer(String name) {
+ this.name = name;
+ this.orders = new ArrayList();
+ }
+}
View
20 samples-and-tests/just-test-cases/app/models/Order.java
@@ -0,0 +1,20 @@
+package models;
+
+import play.db.jpa.Model;
+import javax.persistence.*;
+
+@Entity(name="customer_order")
+public class Order extends Model {
+ public String product;
+ public Integer items;
+
+ @ManyToOne
+ public Customer customer;
+
+ public Order() {}
+
+ public Order(String product, Integer items) {
+ this.product = product;
+ this.items = items;
+ }
+}
View
44 samples-and-tests/just-test-cases/test/CascadeAllTest.java
@@ -0,0 +1,44 @@
+import org.junit.*;
+import java.util.*;
+import play.test.*;
+import models.*;
+
+public class CascadeAllTest extends UnitTest {
+ @Before
+ public void setup() {
+ Fixtures.deleteAll();
+ Fixtures.load("cascade-all.yml");
+ }
+
+ @Test
+ public void insert() {
+ Customer frank = new Customer("frank");
+ frank.orders.add(new Order("coffee", 2));
+ frank.orders.add(new Order("tea", 1));
+ frank.save();
+ assertEquals(2, Customer.count());
+ assertEquals(4, Order.count());
+ Customer actual = Customer.find("byName", "frank").first();
+ assertEquals(frank, actual);
+ }
+
+ @Test
+ public void update() {
+ Customer bob = Customer.find("byName", "bob").first();
+ bob.orders.clear();
+ bob.orders.add(new Order("ice cream", 3));
+ bob.save();
+ assertEquals(1, Customer.count());
+ assertEquals(1, Order.count());
+ Customer actual = Customer.find("byName", "bob").first();
+ assertEquals(bob, actual);
+ }
+
+ @Test
+ public void delete() {
+ Customer bob = Customer.find("byName", "bob").first();
+ bob.delete();
+ assertEquals(0, Customer.count());
+ assertEquals(0, Order.count());
+ }
+}
View
12 samples-and-tests/just-test-cases/test/cascade-all.yml
@@ -0,0 +1,12 @@
+Customer(bob):
+ name: bob
+
+Order(cake):
+ product: cake
+ items: 3
+ customer: bob
+
+Order(biscuits):
+ product: biscuits
+ items: 4
+ customer: bob
Please sign in to comment.
Something went wrong with that request. Please try again.