Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions ebean-core/src/main/java/io/ebeaninternal/api/BindValuesKey.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.ebeaninternal.api;

import io.ebean.bean.EntityBean;
import java.util.ArrayList;
import java.util.List;

Expand All @@ -13,10 +14,23 @@ public final class BindValuesKey {

private final List<Object> values = new ArrayList<>();

private final SpiEbeanServer server;

public BindValuesKey(SpiEbeanServer server) {
this.server = server;
}

/**
* Add a bind value.
*/
public BindValuesKey add(Object value) {
if (value instanceof EntityBean) {
// Only interested in id to keep the memory footprint low
Object id = server.beanId(value);
if (id != null) {
value = id;
}
}
values.add(value);
return this;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1244,7 +1244,7 @@ public final void queryBindKey(BindValuesKey key) {
public final HashQuery queryHash() {
// calculateQueryPlanHash is called just after potential AutoTune tuning
// so queryPlanHash is calculated well before this method is called
BindValuesKey bindKey = new BindValuesKey();
BindValuesKey bindKey = new BindValuesKey(server);
queryBindKey(bindKey);
return new HashQuery(queryPlanKey, bindKey);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ public void assert_queryBindHash_isSame(RawExpression exp0, RawExpression exp1)
}

private BindValuesKey bindKey(RawExpression query) {
BindValuesKey bindValuesKey = new BindValuesKey();
BindValuesKey bindValuesKey = new BindValuesKey(spiEbeanServer());
query.queryBindKey(bindValuesKey);
return bindValuesKey;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
package io.ebeaninternal.server.querydefn;

import io.ebeaninternal.api.BindValuesKey;
import io.ebeaninternal.server.deploy.BaseTest;
import org.junit.jupiter.api.Test;

import static org.assertj.core.api.Assertions.assertThat;

public class BindValuesKeyTest {
public class BindValuesKeyTest extends BaseTest {

@Test
public void update_with_null() {

BindValuesKey hash = new BindValuesKey();
BindValuesKey hash = new BindValuesKey(spiEbeanServer());
hash.add(1).add(null).add("hello");

BindValuesKey hash2 = new BindValuesKey();
BindValuesKey hash2 = new BindValuesKey(spiEbeanServer());
hash2.add(1).add(null).add("hello");

assertThat(hash).isEqualTo(hash2);
Expand All @@ -22,13 +23,13 @@ public void update_with_null() {
@Test
public void notEqual() {

BindValuesKey hash = new BindValuesKey();
BindValuesKey hash = new BindValuesKey(spiEbeanServer());
hash.add(1).add(null).add("hello");

BindValuesKey hash2 = new BindValuesKey();
BindValuesKey hash2 = new BindValuesKey(spiEbeanServer());
hash2.add(1).add("hello");

BindValuesKey hash3 = new BindValuesKey();
BindValuesKey hash3 = new BindValuesKey(spiEbeanServer());
hash2.add(1).add(null);

assertThat(hash).isNotEqualTo(hash2);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ private <T> void prepare(DefaultOrmQuery<T> q1, DefaultOrmQuery<T> q2) {
}

private BindValuesKey bindKey(DefaultOrmQuery<Order> query) {
BindValuesKey key = new BindValuesKey();
BindValuesKey key = new BindValuesKey(spiEbeanServer());
query.queryBindKey(key);
return key;
}
Expand Down
21 changes: 21 additions & 0 deletions ebean-test/src/test/java/org/tests/model/memleak/MemleakChild.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package org.tests.model.memleak;

import jakarta.persistence.Entity;
import jakarta.persistence.Id;

/**
* Class with @Cache(enableQueryCache = true)
*
* @author Jonas Fr&ouml;hler, FOCONIS AG
*/
@Entity
public class MemleakChild {

@Id
Long id;

String name;

transient byte[] memConsumer = new byte[1000000];

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package org.tests.model.memleak;

import io.ebean.annotation.Cache;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.ManyToOne;

/**
* Class that holds the {@link MemleakChild}.
*
* @author Jonas Fr&ouml;hler, Foconis Analytics GmbH
*/
@Entity
@Cache(enableQueryCache = true)
public class MemleakParent {

@Id
Long id;

@ManyToOne()
MemleakChild child;

String name;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package org.tests.model.memleak;

import io.ebean.DB;
import io.ebean.xtest.BaseTestCase;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;

/**
* The query cache holds the bean (MemleakChild). If there are "big" beans, then an OOM may occur.
*
* @author Jonas Fr&ouml;hler, Foconis Analytics GmbH
*/
public class TestQueryCacheHoldsBean extends BaseTestCase {

@Test
@Disabled("Run manually with -Xmx128M")
void testQueryCacheHoldsBean() {
for (long id = 0; id <= 1000; id++) {
DB.find(MemleakParent.class)
.where().eq("id", id)
.eq("child", DB.reference(MemleakChild.class, id))
.setUseQueryCache(true)
.findOne();
}
}
}