diff --git a/src/main/java/com/avaje/ebean/config/AutoTuneConfig.java b/src/main/java/com/avaje/ebean/config/AutoTuneConfig.java index fba744528..2b1ff7996 100644 --- a/src/main/java/com/avaje/ebean/config/AutoTuneConfig.java +++ b/src/main/java/com/avaje/ebean/config/AutoTuneConfig.java @@ -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); } } diff --git a/src/main/java/com/avaje/ebeaninternal/server/autotune/service/AutoTuneAllCollection.java b/src/main/java/com/avaje/ebeaninternal/server/autotune/service/AutoTuneAllCollection.java new file mode 100644 index 000000000..6ff6ff300 --- /dev/null +++ b/src/main/java/com/avaje/ebeaninternal/server/autotune/service/AutoTuneAllCollection.java @@ -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. + *

+ * This is for writing the "all" file on shutdown when using runtime tuning. + *

+ */ +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 all = queryTuner.getAll(); + for (TunedQueryInfo tuned: all) { + document.getOrigin().add(tuned.getOrigin()); + } + } + +} diff --git a/src/main/java/com/avaje/ebeaninternal/server/autotune/service/AutoTuneDiffCollection.java b/src/main/java/com/avaje/ebeaninternal/server/autotune/service/AutoTuneDiffCollection.java new file mode 100644 index 000000000..f281e796b --- /dev/null +++ b/src/main/java/com/avaje/ebeaninternal/server/autotune/service/AutoTuneDiffCollection.java @@ -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; + } + +} diff --git a/src/main/java/com/avaje/ebeaninternal/server/autotune/service/AutoTuneXmlWriter.java b/src/main/java/com/avaje/ebeaninternal/server/autotune/service/AutoTuneXmlWriter.java index de0b341c6..d4f6e4c32 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/autotune/service/AutoTuneXmlWriter.java +++ b/src/main/java/com/avaje/ebeaninternal/server/autotune/service/AutoTuneXmlWriter.java @@ -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. */ diff --git a/src/main/java/com/avaje/ebeaninternal/server/autotune/service/BaseQueryTuner.java b/src/main/java/com/avaje/ebeaninternal/server/autotune/service/BaseQueryTuner.java index 7cb600cae..03366ecbf 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/autotune/service/BaseQueryTuner.java +++ b/src/main/java/com/avaje/ebeaninternal/server/autotune/service/BaseQueryTuner.java @@ -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 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)); } diff --git a/src/main/java/com/avaje/ebeaninternal/server/autotune/service/DefaultAutoTuneService.java b/src/main/java/com/avaje/ebeaninternal/server/autotune/service/DefaultAutoTuneService.java index b4cac2e75..59377738c 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/autotune/service/DefaultAutoTuneService.java +++ b/src/main/java/com/avaje/ebeaninternal/server/autotune/service/DefaultAutoTuneService.java @@ -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). + *

+ * This is the originally loaded tuning plus any tuning changes picked up and applied at runtime. + *

+ *

+ * This "all" file can be used as the next "ebean-autotune.xml" file. + *

+ */ + 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. *

diff --git a/src/main/java/com/avaje/ebeaninternal/server/autotune/service/ProfileCollectionEvent.java b/src/main/java/com/avaje/ebeaninternal/server/autotune/service/ProfileCollectionEvent.java deleted file mode 100644 index bcf55c4fa..000000000 --- a/src/main/java/com/avaje/ebeaninternal/server/autotune/service/ProfileCollectionEvent.java +++ /dev/null @@ -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. - *

- * - *

- */ -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 tunerKeys = (emptyEntries) ? queryTuner.keySet() : null; - Set profileKeys = (emptyEntries) ? new HashSet() : null; - - List 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 { - - @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 { - - @Override - public int compare(Origin o1, Origin o2) { - return o1.getKey().compareTo(o2.getKey()); - } - } -} diff --git a/src/main/java/com/avaje/ebeaninternal/server/autotune/service/ProfileManager.java b/src/main/java/com/avaje/ebeaninternal/server/autotune/service/ProfileManager.java index f5a7d4e38..ff4cca43a 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/autotune/service/ProfileManager.java +++ b/src/main/java/com/avaje/ebeaninternal/server/autotune/service/ProfileManager.java @@ -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); diff --git a/src/main/java/com/avaje/ebeaninternal/server/autotune/service/SortAutoTuneDocument.java b/src/main/java/com/avaje/ebeaninternal/server/autotune/service/SortAutoTuneDocument.java new file mode 100644 index 000000000..fd3d51523 --- /dev/null +++ b/src/main/java/com/avaje/ebeaninternal/server/autotune/service/SortAutoTuneDocument.java @@ -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 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 { + + @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 { + + @Override + public int compare(Origin o1, Origin o2) { + return o1.getKey().compareTo(o2.getKey()); + } + } +} diff --git a/src/test/java/com/avaje/tests/autofetch/TunedQueryInfoTest.java b/src/test/java/com/avaje/tests/autofetch/TunedQueryInfoTest.java index ba907024d..99a0ead5f 100644 --- a/src/test/java/com/avaje/tests/autofetch/TunedQueryInfoTest.java +++ b/src/test/java/com/avaje/tests/autofetch/TunedQueryInfoTest.java @@ -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 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 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 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 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 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 query = server.find(Order.class).setId(1); diff --git a/src/test/java/com/avaje/tests/cache/TestL2CacheWithSharedBean.java b/src/test/java/com/avaje/tests/cache/TestL2CacheWithSharedBean.java index 6d6a31df4..9fbd01a43 100644 --- a/src/test/java/com/avaje/tests/cache/TestL2CacheWithSharedBean.java +++ b/src/test/java/com/avaje/tests/cache/TestL2CacheWithSharedBean.java @@ -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 query = Ebean.find(FeatureDescription.class).setId(f1.getId()); diff --git a/src/test/java/com/avaje/tests/query/autotune/TestAutoTuneProfiling.java b/src/test/java/com/avaje/tests/query/autotune/TestAutoTuneProfiling.java index 2bcccb34a..df36e07ca 100644 --- a/src/test/java/com/avaje/tests/query/autotune/TestAutoTuneProfiling.java +++ b/src/test/java/com/avaje/tests/query/autotune/TestAutoTuneProfiling.java @@ -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(); + } } diff --git a/src/test/resources/ebean.properties b/src/test/resources/ebean.properties index fabebeacb..1aa1085c5 100644 --- a/src/test/resources/ebean.properties +++ b/src/test/resources/ebean.properties @@ -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 diff --git a/src/test/resources/logback-test.xml b/src/test/resources/logback-test.xml index 0feee6d67..153e25712 100644 --- a/src/test/resources/logback-test.xml +++ b/src/test/resources/logback-test.xml @@ -86,6 +86,6 @@ - + \ No newline at end of file