mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
#525 - Automatic autotune data
This commit is contained in:
@@ -230,5 +230,6 @@ public class AutoTuneConfig {
|
||||
profilingBase = p.getInt("autoTune.profilingBase", profilingBase);
|
||||
profilingRate = p.getDouble("autoTune.profilingRate", profilingRate);
|
||||
profilingFile = p.get("autoTune.profilingFile", profilingFile);
|
||||
profilingUpdateFrequency = p.getInt("autoTune.profilingUpdateFrequency", profilingUpdateFrequency);
|
||||
}
|
||||
}
|
||||
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
package com.avaje.ebeaninternal.server.autotune.service;
|
||||
|
||||
import com.avaje.ebeaninternal.server.autotune.model.Autotune;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* Event where all tuned query information is collected.
|
||||
* <p>
|
||||
* This is for writing the "all" file on shutdown when using runtime tuning.
|
||||
* </p>
|
||||
*/
|
||||
public class AutoTuneAllCollection {
|
||||
|
||||
final Autotune document = new Autotune();
|
||||
|
||||
final BaseQueryTuner queryTuner;
|
||||
|
||||
/**
|
||||
* Construct to collect/report all tuned queries.
|
||||
*/
|
||||
public AutoTuneAllCollection(BaseQueryTuner queryTuner) {
|
||||
this.queryTuner = queryTuner;
|
||||
loadAllTuned();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of origin elements in the document.
|
||||
*/
|
||||
public int size() {
|
||||
return document.getOrigin().size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Autotune document object.
|
||||
*/
|
||||
public Autotune getDocument() {
|
||||
return document;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the document as an xml file.
|
||||
*/
|
||||
public void writeFile(String filePrefix) {
|
||||
|
||||
AutoTuneXmlWriter writer = new AutoTuneXmlWriter();
|
||||
writer.write(document, filePrefix);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads all the existing query tuning into the document.
|
||||
*/
|
||||
private void loadAllTuned() {
|
||||
|
||||
Collection<TunedQueryInfo> all = queryTuner.getAll();
|
||||
for (TunedQueryInfo tuned: all) {
|
||||
document.getOrigin().add(tuned.getOrigin());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+164
@@ -0,0 +1,164 @@
|
||||
package com.avaje.ebeaninternal.server.autotune.service;
|
||||
|
||||
import com.avaje.ebean.bean.ObjectGraphOrigin;
|
||||
import com.avaje.ebeaninternal.server.autotune.AutoTuneCollection;
|
||||
import com.avaje.ebeaninternal.server.autotune.model.Autotune;
|
||||
import com.avaje.ebeaninternal.server.autotune.model.Origin;
|
||||
import com.avaje.ebeaninternal.server.autotune.model.ProfileDiff;
|
||||
import com.avaje.ebeaninternal.server.autotune.model.ProfileNew;
|
||||
import com.avaje.ebeaninternal.server.querydefn.OrmQueryDetail;
|
||||
|
||||
/**
|
||||
* Event where profiling information is collected and processed for differences
|
||||
* relative to the current query tuning.
|
||||
*/
|
||||
public class AutoTuneDiffCollection {
|
||||
|
||||
final Autotune document = new Autotune();
|
||||
|
||||
final AutoTuneCollection profiling;
|
||||
|
||||
final BaseQueryTuner queryTuner;
|
||||
|
||||
final boolean updateTuning;
|
||||
|
||||
int newCount;
|
||||
|
||||
int diffCount;
|
||||
|
||||
/**
|
||||
* Construct to collect/report the new/diff query tuning entries.
|
||||
*/
|
||||
public AutoTuneDiffCollection(AutoTuneCollection profiling, BaseQueryTuner queryTuner, boolean updateTuning) {
|
||||
this.profiling = profiling;
|
||||
this.queryTuner = queryTuner;
|
||||
this.updateTuning = updateTuning;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if there are no new or diff entries.
|
||||
*/
|
||||
public boolean isEmpty() {
|
||||
return newCount == 0 && diffCount == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the underlying Autotune document object.
|
||||
*/
|
||||
public Autotune getDocument() {
|
||||
return document;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of diff entries.
|
||||
*/
|
||||
public int getDiffCount() {
|
||||
return diffCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of new entries.
|
||||
*/
|
||||
public int getNewCount() {
|
||||
return newCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the total new and diff entries.
|
||||
*/
|
||||
public int getChangeCount() {
|
||||
return newCount + diffCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the underlying document as an xml file.
|
||||
*/
|
||||
public void writeFile(String filePrefix) {
|
||||
|
||||
AutoTuneXmlWriter writer = new AutoTuneXmlWriter();
|
||||
writer.write(document, filePrefix);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process checking profiling entries against existing query tuning.
|
||||
*/
|
||||
public boolean process() {
|
||||
|
||||
for (AutoTuneCollection.Entry entry : profiling.getEntries()) {
|
||||
addToDocument(entry);
|
||||
}
|
||||
|
||||
return isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the entry is new or diff and add as necessary.
|
||||
*/
|
||||
private void addToDocument(AutoTuneCollection.Entry entry) {
|
||||
|
||||
ObjectGraphOrigin point = entry.getOrigin();
|
||||
OrmQueryDetail profileDetail = entry.getDetail();
|
||||
|
||||
// compare with the existing query tuning entry
|
||||
OrmQueryDetail tuneDetail = queryTuner.get(point.getKey());
|
||||
if (tuneDetail == null) {
|
||||
addToDocumentNewEntry(entry, point);
|
||||
|
||||
} else if (!tuneDetail.isAutoTuneEqual(profileDetail)) {
|
||||
addToDocumentDiffEntry(entry, point, tuneDetail);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add as a diff entry.
|
||||
*/
|
||||
private void addToDocumentDiffEntry(AutoTuneCollection.Entry entry, ObjectGraphOrigin point, OrmQueryDetail tuneDetail) {
|
||||
|
||||
diffCount++;
|
||||
|
||||
Origin origin = createOrigin(entry, point, tuneDetail.toString());
|
||||
ProfileDiff diff = document.getProfileDiff();
|
||||
if (diff == null) {
|
||||
diff = new ProfileDiff();
|
||||
document.setProfileDiff(diff);
|
||||
}
|
||||
diff.getOrigin().add(origin);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add as a "new" entry.
|
||||
*/
|
||||
private void addToDocumentNewEntry(AutoTuneCollection.Entry entry, ObjectGraphOrigin point) {
|
||||
|
||||
newCount++;
|
||||
|
||||
ProfileNew profileNew = document.getProfileNew();
|
||||
if (profileNew == null) {
|
||||
profileNew = new ProfileNew();
|
||||
document.setProfileNew(profileNew);
|
||||
}
|
||||
Origin origin = createOrigin(entry, point, entry.getOriginalQuery());
|
||||
profileNew.getOrigin().add(origin);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create the XML Origin bean for the given entry and ObjectGraphOrigin.
|
||||
*/
|
||||
private Origin createOrigin(AutoTuneCollection.Entry entry, ObjectGraphOrigin point, String query) {
|
||||
|
||||
Origin origin = new Origin();
|
||||
origin.setKey(point.getKey());
|
||||
origin.setBeanType(point.getBeanType());
|
||||
origin.setDetail(entry.getDetail().toString());
|
||||
origin.setCallStack(point.getCallStack().description("\n"));
|
||||
origin.setOriginal(query);
|
||||
|
||||
if (updateTuning) {
|
||||
queryTuner.put(origin);
|
||||
}
|
||||
|
||||
return origin;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -7,12 +7,29 @@ import javax.xml.bind.JAXBContext;
|
||||
import javax.xml.bind.JAXBException;
|
||||
import javax.xml.bind.Marshaller;
|
||||
import java.io.File;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* Simple writer for output of the AutoTune Profiling as an XML document.
|
||||
*/
|
||||
public class AutoTuneXmlWriter {
|
||||
|
||||
/**
|
||||
* Write the document as xml file with the given prefix.
|
||||
*/
|
||||
public void write(Autotune document, String filePrefix) {
|
||||
|
||||
SortAutoTuneDocument.sort(document);
|
||||
|
||||
SimpleDateFormat df = new SimpleDateFormat("yyyyMMdd-HHmmss");
|
||||
String now = df.format(new Date());
|
||||
|
||||
// write the file with serverName and now suffix as we can output the profiling many times
|
||||
File file = new File(filePrefix + "-" + now + ".xml");
|
||||
write(document, file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write Profiling to a file as xml.
|
||||
*/
|
||||
|
||||
@@ -2,17 +2,16 @@ package com.avaje.ebeaninternal.server.autotune.service;
|
||||
|
||||
import com.avaje.ebean.bean.CallStack;
|
||||
import com.avaje.ebean.bean.ObjectGraphNode;
|
||||
import com.avaje.ebean.bean.ObjectGraphOrigin;
|
||||
import com.avaje.ebean.config.AutoTuneConfig;
|
||||
import com.avaje.ebean.config.AutoTuneMode;
|
||||
import com.avaje.ebeaninternal.api.SpiEbeanServer;
|
||||
import com.avaje.ebeaninternal.api.SpiQuery;
|
||||
import com.avaje.ebeaninternal.server.autotune.AutoTuneCollection;
|
||||
import com.avaje.ebeaninternal.server.autotune.ProfilingListener;
|
||||
import com.avaje.ebeaninternal.server.autotune.model.Origin;
|
||||
import com.avaje.ebeaninternal.server.querydefn.OrmQueryDetail;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
@@ -52,17 +51,16 @@ public class BaseQueryTuner {
|
||||
}
|
||||
|
||||
/**
|
||||
* Load an entry from the source tuning xml.
|
||||
* Return all the current tuned query entries.
|
||||
*/
|
||||
public void load(Origin origin) {
|
||||
|
||||
tunedQueryInfoMap.put(origin.getKey(), new TunedQueryInfo(origin));
|
||||
public Collection<TunedQueryInfo> getAll() {
|
||||
return tunedQueryInfoMap.values();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an entry at runtime.
|
||||
* Put a query tuning entry.
|
||||
*/
|
||||
public void add(Origin origin) {
|
||||
public void put(Origin origin) {
|
||||
|
||||
tunedQueryInfoMap.put(origin.getKey(), new TunedQueryInfo(origin));
|
||||
}
|
||||
|
||||
+44
-22
@@ -43,6 +43,8 @@ public class DefaultAutoTuneService implements AutoTuneService {
|
||||
|
||||
private final int profilingUpdateFrequency;
|
||||
|
||||
private long runtimeChangeCount;
|
||||
|
||||
public DefaultAutoTuneService(SpiEbeanServer server, ServerConfig serverConfig) {
|
||||
|
||||
AutoTuneConfig config = serverConfig.getAutoTuneConfig();
|
||||
@@ -68,18 +70,18 @@ public class DefaultAutoTuneService implements AutoTuneService {
|
||||
|
||||
if (queryTuning) {
|
||||
loadTuningFile();
|
||||
automaticProfiling();
|
||||
if (isRuntimeTuningUpdates()) {
|
||||
// periodically gather and update query tuning
|
||||
server.getBackgroundExecutor().executePeriodically(new ProfilingUpdate(), profilingUpdateFrequency, TimeUnit.SECONDS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void automaticProfiling() {
|
||||
|
||||
if (isAutomaticTuningUpdate()) {
|
||||
server.getBackgroundExecutor().executePeriodically(new ProfilingUpdate(), profilingUpdateFrequency, TimeUnit.SECONDS);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isAutomaticTuningUpdate() {
|
||||
/**
|
||||
* Return true if the tuning should update periodically at runtime.
|
||||
*/
|
||||
private boolean isRuntimeTuningUpdates() {
|
||||
return profilingUpdateFrequency > 0;
|
||||
}
|
||||
|
||||
@@ -104,29 +106,33 @@ public class DefaultAutoTuneService implements AutoTuneService {
|
||||
Autotune profiling = reader.read(file);
|
||||
logger.info("AutoTune loading {} tuning entries", profiling.getOrigin().size());
|
||||
for (Origin origin : profiling.getOrigin()) {
|
||||
queryTuner.load(origin);
|
||||
queryTuner.put(origin);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect profiling, check for new/diff to existing tuning and apply changes.
|
||||
*/
|
||||
private void runtimeTuningUpdate() {
|
||||
|
||||
synchronized (this) {
|
||||
try {
|
||||
long start = System.currentTimeMillis();
|
||||
|
||||
AutoTuneCollection profiling = profileManager.profilingCollection(false);
|
||||
|
||||
ProfileCollectionEvent event = new ProfileCollectionEvent(profiling, queryTuner, false);
|
||||
|
||||
if (!event.process()) {
|
||||
AutoTuneDiffCollection event = new AutoTuneDiffCollection(profiling, queryTuner, true);
|
||||
if (event.process()) {
|
||||
long exeMillis = System.currentTimeMillis() - start;
|
||||
logger.debug("No tuning updates for server:{} executionMillis:{}", serverName, exeMillis);
|
||||
logger.debug("No query tuning updates for server:{} executionMillis:{}", serverName, exeMillis);
|
||||
|
||||
} else {
|
||||
|
||||
event.writeFile(profilingFile + "-" + serverName + "-tuningupdate");
|
||||
// report the query tuning changes that have been made
|
||||
runtimeChangeCount += event.getChangeCount();
|
||||
event.writeFile(profilingFile + "-" + serverName + "-update");
|
||||
long exeMillis = System.currentTimeMillis() - start;
|
||||
logger.info("query tuning update - new:{} diff:{} for server:{} executionMillis:{}", event.getNewCount(), event.getDiffCount(), serverName, exeMillis);
|
||||
logger.info("query tuning updates - new:{} diff:{} for server:{} executionMillis:{}", event.getNewCount(), event.getDiffCount(), serverName, exeMillis);
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
logger.error("Error collecting or applying automatic query tuning", e);
|
||||
@@ -137,15 +143,15 @@ public class DefaultAutoTuneService implements AutoTuneService {
|
||||
private void saveProfilingOnShutdown(boolean reset) {
|
||||
|
||||
synchronized (this) {
|
||||
if (isAutomaticTuningUpdate()) {
|
||||
if (isRuntimeTuningUpdates()) {
|
||||
runtimeTuningUpdate();
|
||||
outputAggregateTuning();
|
||||
outputAllTuning();
|
||||
|
||||
} else {
|
||||
|
||||
AutoTuneCollection profiling = profileManager.profilingCollection(reset);
|
||||
ProfileCollectionEvent event = new ProfileCollectionEvent(profiling, queryTuner, true);
|
||||
|
||||
AutoTuneDiffCollection event = new AutoTuneDiffCollection(profiling, queryTuner, false);
|
||||
if (!event.process()) {
|
||||
logger.info("No new or diff entries for profiling server:{}", serverName);
|
||||
|
||||
@@ -157,12 +163,28 @@ public class DefaultAutoTuneService implements AutoTuneService {
|
||||
}
|
||||
}
|
||||
|
||||
private void outputAggregateTuning() {
|
||||
/**
|
||||
* Output all the query tuning (the "all" file).
|
||||
* <p>
|
||||
* This is the originally loaded tuning plus any tuning changes picked up and applied at runtime.
|
||||
* </p>
|
||||
* <p>
|
||||
* This "all" file can be used as the next "ebean-autotune.xml" file.
|
||||
* </p>
|
||||
*/
|
||||
private void outputAllTuning() {
|
||||
|
||||
//TODO outputAggregateTuning()
|
||||
if (runtimeChangeCount == 0) {
|
||||
logger.info("no runtime query tuning changes for server:{}", serverName);
|
||||
|
||||
} else {
|
||||
AutoTuneAllCollection event = new AutoTuneAllCollection(queryTuner);
|
||||
int size = event.size();
|
||||
event.writeFile(profilingFile + "-" + serverName + "-all");
|
||||
logger.info("query tuning detected [{}] changes, writing all [{}] tuning entries for server:{}", runtimeChangeCount, size, serverName);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Shutdown the listener.
|
||||
* <p>
|
||||
|
||||
-224
@@ -1,224 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.autotune.service;
|
||||
|
||||
import com.avaje.ebean.bean.ObjectGraphOrigin;
|
||||
import com.avaje.ebeaninternal.server.autotune.AutoTuneCollection;
|
||||
import com.avaje.ebeaninternal.server.autotune.model.Autotune;
|
||||
import com.avaje.ebeaninternal.server.autotune.model.Origin;
|
||||
import com.avaje.ebeaninternal.server.autotune.model.ProfileDiff;
|
||||
import com.avaje.ebeaninternal.server.autotune.model.ProfileEmpty;
|
||||
import com.avaje.ebeaninternal.server.autotune.model.ProfileNew;
|
||||
import com.avaje.ebeaninternal.server.querydefn.OrmQueryDetail;
|
||||
|
||||
import java.io.File;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Event where profiling information collected and processed.
|
||||
* <p>
|
||||
*
|
||||
* </p>
|
||||
*/
|
||||
public class ProfileCollectionEvent {
|
||||
|
||||
//private static final Logger logger = LoggerFactory.getLogger(ProfileCollectionEvent.class);
|
||||
|
||||
final Autotune document = new Autotune();
|
||||
|
||||
final AutoTuneCollection profiling;
|
||||
|
||||
final BaseQueryTuner queryTuner;
|
||||
|
||||
final boolean emptyEntries;
|
||||
|
||||
int newCount;
|
||||
|
||||
int diffCount;
|
||||
|
||||
public ProfileCollectionEvent(AutoTuneCollection profiling, BaseQueryTuner queryTuner, boolean emptyEntries) {
|
||||
this.profiling = profiling;
|
||||
this.queryTuner = queryTuner;
|
||||
this.emptyEntries = emptyEntries;
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return newCount == 0 && diffCount == 0;
|
||||
}
|
||||
|
||||
public Autotune getDocument() {
|
||||
return document;
|
||||
}
|
||||
|
||||
public int getDiffCount() {
|
||||
return diffCount;
|
||||
}
|
||||
|
||||
public int getNewCount() {
|
||||
return newCount;
|
||||
}
|
||||
|
||||
public void writeFile(String filePrefix) {
|
||||
|
||||
SimpleDateFormat df = new SimpleDateFormat("yyyyMMdd-HHmmss");
|
||||
String now = df.format(new Date());
|
||||
|
||||
// write the file with serverName and now suffix as we can output the profiling many times
|
||||
File file = new File(filePrefix + "-" + now + ".xml");
|
||||
AutoTuneXmlWriter writer = new AutoTuneXmlWriter();
|
||||
writer.write(document, file);
|
||||
}
|
||||
|
||||
public boolean process() {
|
||||
|
||||
|
||||
Set<String> tunerKeys = (emptyEntries) ? queryTuner.keySet() : null;
|
||||
Set<String> profileKeys = (emptyEntries) ? new HashSet<String>() : null;
|
||||
|
||||
List<AutoTuneCollection.Entry> profilingEntries = profiling.getEntries();
|
||||
|
||||
for (AutoTuneCollection.Entry entry : profilingEntries) {
|
||||
addToDocument(entry);
|
||||
if (profileKeys != null) {
|
||||
// only collect if we are actively looking for tuning
|
||||
// entries that were not used
|
||||
profileKeys.add(entry.getOrigin().getKey());
|
||||
}
|
||||
}
|
||||
|
||||
if (tunerKeys != null) {
|
||||
// report the origin keys that we didn't collect any profiling on
|
||||
for (String tuneKey : tunerKeys) {
|
||||
if (!profileKeys.contains(tuneKey)) {
|
||||
ProfileEmpty profileEmpty = document.getProfileEmpty();
|
||||
if (profileEmpty == null) {
|
||||
profileEmpty = new ProfileEmpty();
|
||||
document.setProfileEmpty(profileEmpty);
|
||||
}
|
||||
Origin emptyOrigin = new Origin();
|
||||
emptyOrigin.setKey(tuneKey);
|
||||
profileEmpty.getOrigin().add(emptyOrigin);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!isEmpty()) {
|
||||
sortDocument(document);
|
||||
}
|
||||
|
||||
return isEmpty();
|
||||
}
|
||||
|
||||
|
||||
private void addToDocument(AutoTuneCollection.Entry entry) {
|
||||
|
||||
ObjectGraphOrigin point = entry.getOrigin();
|
||||
OrmQueryDetail profileDetail = entry.getDetail();
|
||||
|
||||
// compare with the existing query tuning entry
|
||||
OrmQueryDetail tuneDetail = queryTuner.get(point.getKey());
|
||||
if (tuneDetail == null) {
|
||||
Origin origin = addToDocumentNewEntry(entry, point);
|
||||
queryTuner.add(origin);
|
||||
|
||||
} else if (!tuneDetail.isAutoTuneEqual(profileDetail)) {
|
||||
addToDocumentDiffEntry(entry, point, tuneDetail);
|
||||
}
|
||||
}
|
||||
|
||||
private Origin addToDocumentDiffEntry(AutoTuneCollection.Entry entry, ObjectGraphOrigin point, OrmQueryDetail tuneDetail) {
|
||||
|
||||
diffCount++;
|
||||
|
||||
Origin origin = createOrigin(entry, point);
|
||||
origin.setOriginal(tuneDetail.toString());
|
||||
ProfileDiff diff = document.getProfileDiff();
|
||||
if (diff == null) {
|
||||
diff = new ProfileDiff();
|
||||
document.setProfileDiff(diff);
|
||||
}
|
||||
diff.getOrigin().add(origin);
|
||||
return origin;
|
||||
}
|
||||
|
||||
private Origin addToDocumentNewEntry(AutoTuneCollection.Entry entry, ObjectGraphOrigin point) {
|
||||
|
||||
newCount++;
|
||||
|
||||
ProfileNew profileNew = document.getProfileNew();
|
||||
if (profileNew == null) {
|
||||
profileNew = new ProfileNew();
|
||||
document.setProfileNew(profileNew);
|
||||
}
|
||||
Origin origin = createOrigin(entry, point);
|
||||
origin.setOriginal(entry.getOriginalQuery());
|
||||
profileNew.getOrigin().add(origin);
|
||||
return origin;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create the XML Origin bean for the given entry and ObjectGraphOrigin.
|
||||
*/
|
||||
private Origin createOrigin(AutoTuneCollection.Entry entry, ObjectGraphOrigin point) {
|
||||
Origin origin = new Origin();
|
||||
origin.setKey(point.getKey());
|
||||
origin.setBeanType(point.getBeanType());
|
||||
origin.setDetail(entry.getDetail().toString());
|
||||
origin.setCallStack(point.getCallStack().description("\n"));
|
||||
return origin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the diff and new entries by bean type followed by key.
|
||||
*/
|
||||
private void sortDocument(Autotune document) {
|
||||
|
||||
ProfileDiff profileDiff = document.getProfileDiff();
|
||||
if (profileDiff != null) {
|
||||
Collections.sort(profileDiff.getOrigin(), NAME_KEY_SORT);
|
||||
}
|
||||
ProfileNew profileNew = document.getProfileNew();
|
||||
if (profileNew != null) {
|
||||
Collections.sort(profileNew.getOrigin(), NAME_KEY_SORT);
|
||||
}
|
||||
ProfileEmpty profileEmpty = document.getProfileEmpty();
|
||||
if (profileEmpty != null) {
|
||||
Collections.sort(profileEmpty.getOrigin(), KEY_SORT);
|
||||
}
|
||||
}
|
||||
|
||||
private static final OriginNameKeySort NAME_KEY_SORT = new OriginNameKeySort();
|
||||
|
||||
private static final OriginKeySort KEY_SORT = new OriginKeySort();
|
||||
|
||||
/**
|
||||
* Comparator sort by bean type then key.
|
||||
*/
|
||||
private static class OriginNameKeySort implements Comparator<Origin> {
|
||||
|
||||
@Override
|
||||
public int compare(Origin o1, Origin o2) {
|
||||
int comp = o1.getBeanType().compareTo(o2.getBeanType());
|
||||
if (comp == 0) {
|
||||
comp = o1.getKey().compareTo(o2.getKey());
|
||||
}
|
||||
return comp;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Comparator sort by bean type then key.
|
||||
*/
|
||||
private static class OriginKeySort implements Comparator<Origin> {
|
||||
|
||||
@Override
|
||||
public int compare(Origin o1, Origin o2) {
|
||||
return o1.getKey().compareTo(o2.getKey());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -118,7 +118,6 @@ public class ProfileManager implements ProfilingListener {
|
||||
AutoTuneCollection req = new AutoTuneCollection();
|
||||
|
||||
for (ProfileOrigin origin : profileMap.values()) {
|
||||
|
||||
BeanDescriptor<?> desc = server.getBeanDescriptorById(origin.getOrigin().getBeanType());
|
||||
if (desc != null) {
|
||||
origin.profilingCollection(desc, req, reset);
|
||||
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
package com.avaje.ebeaninternal.server.autotune.service;
|
||||
|
||||
import com.avaje.ebeaninternal.server.autotune.model.Autotune;
|
||||
import com.avaje.ebeaninternal.server.autotune.model.Origin;
|
||||
import com.avaje.ebeaninternal.server.autotune.model.ProfileDiff;
|
||||
import com.avaje.ebeaninternal.server.autotune.model.ProfileEmpty;
|
||||
import com.avaje.ebeaninternal.server.autotune.model.ProfileNew;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Sorts Autotune document by
|
||||
*/
|
||||
public class SortAutoTuneDocument {
|
||||
|
||||
|
||||
/**
|
||||
* Set the diff and new entries by bean type followed by key.
|
||||
*/
|
||||
public static void sort(Autotune document) {
|
||||
|
||||
ProfileDiff profileDiff = document.getProfileDiff();
|
||||
if (profileDiff != null) {
|
||||
Collections.sort(profileDiff.getOrigin(), NAME_KEY_SORT);
|
||||
}
|
||||
ProfileNew profileNew = document.getProfileNew();
|
||||
if (profileNew != null) {
|
||||
Collections.sort(profileNew.getOrigin(), NAME_KEY_SORT);
|
||||
}
|
||||
ProfileEmpty profileEmpty = document.getProfileEmpty();
|
||||
if (profileEmpty != null) {
|
||||
Collections.sort(profileEmpty.getOrigin(), KEY_SORT);
|
||||
}
|
||||
List<Origin> origins = document.getOrigin();
|
||||
if (!origins.isEmpty()) {
|
||||
Collections.sort(origins, NAME_KEY_SORT);
|
||||
}
|
||||
}
|
||||
|
||||
private static final OriginNameKeySort NAME_KEY_SORT = new OriginNameKeySort();
|
||||
|
||||
private static final OriginKeySort KEY_SORT = new OriginKeySort();
|
||||
|
||||
/**
|
||||
* Comparator sort by bean type then key.
|
||||
*/
|
||||
private static class OriginNameKeySort implements Comparator<Origin> {
|
||||
|
||||
@Override
|
||||
public int compare(Origin o1, Origin o2) {
|
||||
int comp = o1.getBeanType().compareTo(o2.getBeanType());
|
||||
if (comp == 0) {
|
||||
comp = o1.getKey().compareTo(o2.getKey());
|
||||
}
|
||||
return comp;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Comparator sort by bean type then key.
|
||||
*/
|
||||
private static class OriginKeySort implements Comparator<Origin> {
|
||||
|
||||
@Override
|
||||
public int compare(Origin o1, Origin o2) {
|
||||
return o1.getKey().compareTo(o2.getKey());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,9 @@ package com.avaje.tests.autofetch;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import com.avaje.ebeaninternal.server.autotune.model.Origin;
|
||||
import org.avaje.ebeantest.LoggedSqlCollector;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
@@ -33,34 +35,6 @@ public class TunedQueryInfoTest extends BaseTestCase {
|
||||
serverCacheManager.setCaching(Order.class, false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void withSelectNull() {
|
||||
|
||||
init();
|
||||
|
||||
OrmQueryDetail tunedDetail = new OrmQueryDetail();
|
||||
tunedDetail.select(null);
|
||||
|
||||
TunedQueryInfo tunedInfo = new TunedQueryInfo(tunedDetail);
|
||||
|
||||
Query<Order> query = server.find(Order.class).setId(1);
|
||||
|
||||
tunedInfo.tuneQuery((SpiQuery<?>) query);
|
||||
|
||||
Order order = query.findUnique();
|
||||
EntityBean eb = (EntityBean)order;
|
||||
EntityBeanIntercept ebi = eb._ebean_getIntercept();
|
||||
|
||||
Assert.assertTrue(ebi.isFullyLoadedBean());
|
||||
|
||||
Set<String> loadedPropertyNames = ebi.getLoadedPropertyNames();
|
||||
Assert.assertNull(loadedPropertyNames);
|
||||
|
||||
// invoke lazy loading
|
||||
order.getCustomer();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void withSelectEmpty() {
|
||||
|
||||
@@ -68,9 +42,9 @@ public class TunedQueryInfoTest extends BaseTestCase {
|
||||
|
||||
OrmQueryDetail tunedDetail = new OrmQueryDetail();
|
||||
tunedDetail.select("");
|
||||
|
||||
TunedQueryInfo tunedInfo = new TunedQueryInfo(tunedDetail);
|
||||
|
||||
|
||||
TunedQueryInfo tunedInfo = createTunedQueryInfo(tunedDetail);
|
||||
|
||||
Query<Order> query = server.find(Order.class).setId(1);
|
||||
|
||||
tunedInfo.tuneQuery((SpiQuery<?>) query);
|
||||
@@ -95,9 +69,9 @@ public class TunedQueryInfoTest extends BaseTestCase {
|
||||
|
||||
OrmQueryDetail tunedDetail = new OrmQueryDetail();
|
||||
tunedDetail.select("somethingThatDoesNotExist");
|
||||
|
||||
TunedQueryInfo tunedInfo = new TunedQueryInfo(tunedDetail);
|
||||
|
||||
|
||||
TunedQueryInfo tunedInfo = createTunedQueryInfo(tunedDetail);
|
||||
|
||||
Query<Order> query = server.find(Order.class).setId(1);
|
||||
|
||||
tunedInfo.tuneQuery((SpiQuery<?>) query);
|
||||
@@ -123,7 +97,14 @@ public class TunedQueryInfoTest extends BaseTestCase {
|
||||
Assert.assertTrue(loggedSql.get(0).contains("select t0.id c0, t0.id c1 from o_order t0 where t0.id = ?"));
|
||||
Assert.assertTrue(loggedSql.get(1).contains("select t0.id c0, t0.status c1,"));
|
||||
}
|
||||
|
||||
|
||||
@NotNull
|
||||
private TunedQueryInfo createTunedQueryInfo(OrmQueryDetail tunedDetail) {
|
||||
Origin origin = new Origin();
|
||||
origin.setDetail(tunedDetail.toString());
|
||||
return new TunedQueryInfo(origin);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void withSelectSomeIncludeLazyLoaded() {
|
||||
|
||||
@@ -132,7 +113,7 @@ public class TunedQueryInfoTest extends BaseTestCase {
|
||||
OrmQueryDetail tunedDetail = new OrmQueryDetail();
|
||||
tunedDetail.select("status, customer");
|
||||
|
||||
TunedQueryInfo tunedInfo = new TunedQueryInfo(tunedDetail);
|
||||
TunedQueryInfo tunedInfo = createTunedQueryInfo(tunedDetail);
|
||||
|
||||
Query<Order> query = server.find(Order.class).setId(1);
|
||||
|
||||
@@ -167,7 +148,7 @@ public class TunedQueryInfoTest extends BaseTestCase {
|
||||
OrmQueryDetail tunedDetail = new OrmQueryDetail();
|
||||
tunedDetail.select("status");
|
||||
|
||||
TunedQueryInfo tunedInfo = new TunedQueryInfo(tunedDetail);
|
||||
TunedQueryInfo tunedInfo = createTunedQueryInfo(tunedDetail);
|
||||
|
||||
Query<Order> query = server.find(Order.class).setId(1);
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.avaje.tests.cache;
|
||||
|
||||
import com.avaje.ebeaninternal.server.autotune.model.Origin;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
@@ -14,6 +16,13 @@ import com.avaje.tests.model.basic.FeatureDescription;
|
||||
|
||||
public class TestL2CacheWithSharedBean extends BaseTestCase {
|
||||
|
||||
@NotNull
|
||||
private TunedQueryInfo createTunedQueryInfo(OrmQueryDetail tunedDetail) {
|
||||
Origin origin = new Origin();
|
||||
origin.setDetail(tunedDetail.toString());
|
||||
return new TunedQueryInfo(origin);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
|
||||
@@ -28,7 +37,7 @@ public class TestL2CacheWithSharedBean extends BaseTestCase {
|
||||
|
||||
OrmQueryDetail tunedDetail = new OrmQueryDetail();
|
||||
tunedDetail.select("name");
|
||||
TunedQueryInfo tunedInfo = new TunedQueryInfo(tunedDetail);
|
||||
TunedQueryInfo tunedInfo = createTunedQueryInfo(tunedDetail);
|
||||
|
||||
Query<FeatureDescription> query = Ebean.find(FeatureDescription.class).setId(f1.getId());
|
||||
|
||||
|
||||
@@ -7,23 +7,52 @@ import com.avaje.tests.model.basic.Customer;
|
||||
import com.avaje.tests.model.basic.Order;
|
||||
import com.avaje.tests.model.basic.OrderDetail;
|
||||
import com.avaje.tests.model.basic.ResetBasicData;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
public class TestAutoTuneProfiling extends BaseTestCase {
|
||||
|
||||
@Ignore
|
||||
@Test
|
||||
public void test() {
|
||||
public void test() throws InterruptedException {
|
||||
|
||||
ResetBasicData.reset();
|
||||
|
||||
System.out.println("Start .......");
|
||||
|
||||
for (int i = 0; i < 1; i++) {
|
||||
execute();
|
||||
}
|
||||
|
||||
|
||||
collectUsage();
|
||||
|
||||
System.out.println("Sleeping ...");
|
||||
sortOfBusy();
|
||||
|
||||
System.out.println("Run after collection");
|
||||
|
||||
for (int i = 0; i < 10; i++) {
|
||||
execute();
|
||||
}
|
||||
collectUsage();
|
||||
|
||||
System.out.println("Sleeping ...");
|
||||
sortOfBusy();
|
||||
|
||||
System.out.println("Run after collection");
|
||||
|
||||
for (int i = 0; i < 1; i++) {
|
||||
execute();
|
||||
}
|
||||
}
|
||||
|
||||
private void sortOfBusy() {
|
||||
|
||||
for (int i = 0; i < 90000000; i++) {
|
||||
new Random().nextLong();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ ebean.encryptKeyManager=com.avaje.tests.basic.encrypt.BasicEncyptKeyManager
|
||||
|
||||
ebean.autotune.querytuning=true
|
||||
ebean.autotune.profiling=true
|
||||
|
||||
#ebean.autotune.profilingUpdateFrequency=5
|
||||
|
||||
ebean.ddl.generate=true
|
||||
ebean.ddl.run=true
|
||||
|
||||
@@ -86,6 +86,6 @@
|
||||
<logger name="org.avaje.ebean.cache.NATKEY" level="TRACE"/>
|
||||
|
||||
<logger name="com.avaje.tests" level="DEBUG"/>
|
||||
<logger name="com.avaje.ebean.config.dbplatform.H2HistoryTrigger" level="DEBUG"/>
|
||||
<!--<logger name="com.avaje.ebean.config.dbplatform.H2HistoryTrigger" level="DEBUG"/>-->
|
||||
|
||||
</configuration>
|
||||
Reference in New Issue
Block a user