Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#1768 - Initial refactor extracting CallOrigin interface #1791

Merged
merged 1 commit into from Aug 14, 2019
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
22 changes: 22 additions & 0 deletions src/main/java/io/ebean/bean/CallOrigin.java
@@ -0,0 +1,22 @@
package io.ebean.bean;

/**
* A call origin for query execution profiling to collect graph use (for query tuning).
*/
public interface CallOrigin {

/**
* Return the top element. Typically the top stack element with class and line.
*/
String getTopElement();

/**
* Return the full description of the call origin.
*/
String getFullDescription();

/**
* Compute and return an origin key based on the query hash.
*/
String getOriginKey(int queryHash);
}
81 changes: 22 additions & 59 deletions src/main/java/io/ebean/bean/CallStack.java
Expand Up @@ -3,6 +3,8 @@
import java.io.Serializable;
import java.util.Arrays;

import static io.ebean.util.EncodeB64.enc;

/**
* Represent the call stack (stack trace elements).
* <p>
Expand All @@ -17,15 +19,15 @@
* Note the call stack is trimmed to remove the common ebean internal elements.
* </p>
*/
public final class CallStack implements Serializable {
public final class CallStack implements Serializable, CallOrigin {

private static final long serialVersionUID = -8590644046907438579L;

private static final String NEWLINE = "\n";

private final String zeroHash;
private final String pathHash;

private final StackTraceElement[] callStack;

private final int hc;

public CallStack(StackTraceElement[] callStack, int zeroHash, int pathHash) {
Expand All @@ -37,12 +39,17 @@ public CallStack(StackTraceElement[] callStack, int zeroHash, int pathHash) {

private int computeHashCode() {
int hc = 0;
for (StackTraceElement aCallStack : callStack) {
hc = 92821 * hc + aCallStack.hashCode();
for (StackTraceElement element : callStack) {
hc = 92821 * hc + element.hashCode();
}
return hc;
}

@Override
public String toString() {
return zeroHash + ":" + pathHash + ":" + callStack[0];
}

@Override
public int hashCode() {
return hc;
Expand All @@ -63,73 +70,29 @@ public boolean equals(Object obj) {
/**
* Return the first element of the call stack.
*/
public StackTraceElement getFirstStackTraceElement() {
return callStack[0];
}

/**
* Return the call stack.
*/
public StackTraceElement[] getCallStack() {
return callStack;
}

/**
* Return the hash for the first stack element.
*/
public String getZeroHash() {
return zeroHash;
}

/**
* Return the hash for the stack elements (excluding first stack element).
*/
public String getPathHash() {
return pathHash;
}

@Override
public String toString() {
return zeroHash + ":" + pathHash + ":" + callStack[0];
public String getTopElement() {
return callStack[0].toString();
}

/**
* Return the call stack lines appended with the given newLine string.
*/
public String description(String newLine) {
@Override
public String getFullDescription() {
StringBuilder sb = new StringBuilder(400);
for (StackTraceElement aCallStack : callStack) {
sb.append(aCallStack.toString()).append(newLine);
for (int i = 0; i < callStack.length; i++) {
if (i > 0) {
sb.append(NEWLINE);
}
sb.append(callStack[i].toString());
}
return sb.toString();
}

@Override
public String getOriginKey(int queryHash) {
return enc(queryHash) + "." + zeroHash + "." + pathHash;
}

private static final int radix = 1 << 6;
private static final int mask = radix - 1;

/**
* Convert the integer to unsigned base 64.
*/
public static String enc(int i) {
char[] buf = new char[32];
int charPos = 32;
do {
buf[--charPos] = intToBase64[i & mask];
i >>>= 6;
} while (i != 0);

return new String(buf, charPos, (32 - charPos));
}

private static final char intToBase64[] = {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_'
};
}
22 changes: 11 additions & 11 deletions src/main/java/io/ebean/bean/ObjectGraphOrigin.java
Expand Up @@ -16,19 +16,19 @@ public final class ObjectGraphOrigin implements Serializable {

private static final long serialVersionUID = 410937765287968708L;

private final CallStack callStack;
private final CallOrigin callOrigin;

private final String beanType;

private final int queryHash;

private final String key;

public ObjectGraphOrigin(int queryHash, CallStack callStack, String beanType) {
this.callStack = callStack;
public ObjectGraphOrigin(int queryHash, CallOrigin callOrigin, String beanType) {
this.callOrigin = callOrigin;
this.beanType = beanType;
this.queryHash = queryHash;
this.key = callStack.getOriginKey(queryHash);
this.key = callOrigin.getOriginKey(queryHash);
}

/**
Expand All @@ -49,22 +49,22 @@ public String getBeanType() {
/**
* The call stack involved.
*/
public CallStack getCallStack() {
return callStack;
public CallOrigin getCallOrigin() {
return callOrigin;
}

public String getFirstStackElement() {
return callStack.getFirstStackTraceElement().toString();
public String getTopElement() {
return callOrigin.getTopElement();
}

@Override
public String toString() {
return "key[" + key + "] type[" + beanType + "] " + callStack.getFirstStackTraceElement() + " ";
return "key[" + key + "] type[" + beanType + "] " + callOrigin.getTopElement();
}

@Override
public int hashCode() {
int hc = 92821 * callStack.hashCode();
int hc = 92821 * callOrigin.hashCode();
hc = 92821 * hc + beanType.hashCode();
hc = 92821 * hc + queryHash;
return hc;
Expand All @@ -82,6 +82,6 @@ public boolean equals(Object obj) {
ObjectGraphOrigin e = (ObjectGraphOrigin) obj;
return e.queryHash == queryHash
&& e.beanType.equals(beanType)
&& e.callStack.equals(callStack);
&& e.callOrigin.equals(callOrigin);
}
}
1 change: 1 addition & 0 deletions src/main/java/io/ebean/config/ServerConfig.java
Expand Up @@ -2929,6 +2929,7 @@ protected void loadSettings(PropertiesWrapper p) {
}
loadDocStoreSettings(p);

maxCallStack = p.getInt("maxCallStack", maxCallStack);
dumpMetricsOnShutdown = p.getBoolean("dumpMetricsOnShutdown", dumpMetricsOnShutdown);
dumpMetricsOptions = p.get("dumpMetricsOptions", dumpMetricsOptions);
queryPlanTTLSeconds = p.getInt("queryPlanTTLSeconds", queryPlanTTLSeconds);
Expand Down
32 changes: 32 additions & 0 deletions src/main/java/io/ebean/util/EncodeB64.java
@@ -0,0 +1,32 @@
package io.ebean.util;

/**
* Integer to base64 encoder.
*/
public final class EncodeB64 {

private static final int radix = 1 << 6;
private static final int mask = radix - 1;

/**
* Convert the integer to unsigned base 64.
*/
public static String enc(int i) {
char[] buf = new char[32];
int charPos = 32;
do {
buf[--charPos] = intToBase64[i & mask];
i >>>= 6;
} while (i != 0);

return new String(buf, charPos, (32 - charPos));
}

private static final char intToBase64[] = {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_'
};
}
4 changes: 2 additions & 2 deletions src/main/java/io/ebeaninternal/api/SpiEbeanServer.java
Expand Up @@ -11,7 +11,7 @@
import io.ebean.TxScope;
import io.ebean.bean.BeanCollectionLoader;
import io.ebean.bean.BeanLoader;
import io.ebean.bean.CallStack;
import io.ebean.bean.CallOrigin;
import io.ebean.bean.ObjectGraphNode;
import io.ebean.config.ServerConfig;
import io.ebean.config.dbplatform.DatabasePlatform;
Expand Down Expand Up @@ -81,7 +81,7 @@ public interface SpiEbeanServer extends ExtendedServer, EbeanServer, BeanLoader,
* graph costing.
* </p>
*/
CallStack createCallStack();
CallOrigin createCallOrigin();

/**
* Return the PersistenceContextScope to use defined at query or server level.
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/io/ebeaninternal/api/SpiQuery.java
Expand Up @@ -7,7 +7,7 @@
import io.ebean.PersistenceContextScope;
import io.ebean.ProfileLocation;
import io.ebean.Query;
import io.ebean.bean.CallStack;
import io.ebean.bean.CallOrigin;
import io.ebean.bean.ObjectGraphNode;
import io.ebean.bean.PersistenceContext;
import io.ebean.event.readaudit.ReadEvent;
Expand Down Expand Up @@ -558,7 +558,7 @@ public static TemporalMode of(SpiQuery<?> query) {
* because the queryPlanHash is used to identify the query point.
* </p>
*/
ObjectGraphNode setOrigin(CallStack callStack);
ObjectGraphNode setOrigin(CallOrigin callOrigin);

/**
* Set the profile point of the bean or collection that is lazy loading.
Expand Down
Expand Up @@ -149,7 +149,7 @@ private Origin createOrigin(AutoTuneCollection.Entry entry, ObjectGraphOrigin po
origin.setKey(point.getKey());
origin.setBeanType(point.getBeanType());
origin.setDetail(entry.getDetail().toString());
origin.setCallStack(point.getCallStack().description("\n"));
origin.setCallStack(point.getCallOrigin().getFullDescription());
origin.setOriginal(query);

if (updateTuning) {
Expand Down
@@ -1,6 +1,6 @@
package io.ebeaninternal.server.autotune.service;

import io.ebean.bean.CallStack;
import io.ebean.bean.CallOrigin;
import io.ebean.bean.ObjectGraphNode;
import io.ebean.config.AutoTuneConfig;
import io.ebean.config.AutoTuneMode;
Expand Down Expand Up @@ -97,7 +97,7 @@ boolean tuneQuery(SpiQuery<?> query) {

if (!useTuning(query)) {
if (profiling) {
profiling(query, server.createCallStack());
profiling(query, server.createCallOrigin());
}
return false;
}
Expand All @@ -110,8 +110,8 @@ boolean tuneQuery(SpiQuery<?> query) {
}

// create a query point to identify the query
CallStack stack = server.createCallStack();
ObjectGraphNode origin = query.setOrigin(stack);
CallOrigin callOrigin = server.createCallOrigin();
ObjectGraphNode origin = query.setOrigin(callOrigin);

if (profiling) {
if (profilingListener.isProfileRequest(origin, query)) {
Expand Down Expand Up @@ -154,10 +154,10 @@ private boolean tunableQuery(SpiQuery<?> query) {
}
}

private void profiling(SpiQuery<?> query, CallStack stack) {
private void profiling(SpiQuery<?> query, CallOrigin call) {

// create a query point to identify the query
ObjectGraphNode origin = query.setOrigin(stack);
ObjectGraphNode origin = query.setOrigin(call);
if (profilingListener.isProfileRequest(origin, query)) {
// collect more profiling based on profiling rate etc
query.setProfilingListener(profilingListener);
Expand Down
14 changes: 14 additions & 0 deletions src/main/java/io/ebeaninternal/server/core/CallOriginFactory.java
@@ -0,0 +1,14 @@
package io.ebeaninternal.server.core;

import io.ebean.bean.CallOrigin;

/**
* Creates CallOrigin based on the stack trace.
*/
public interface CallOriginFactory {

/**
* Create and return the CallStack given the stack trace elements.
*/
CallOrigin createCallOrigin();
}
14 changes: 0 additions & 14 deletions src/main/java/io/ebeaninternal/server/core/CallStackFactory.java

This file was deleted.