001package io.ebeaninternal.server.autotune.service;
002
003import io.ebean.bean.ObjectGraphOrigin;
004import io.ebeaninternal.server.autotune.model.Autotune;
005import io.ebeaninternal.server.autotune.model.Origin;
006import io.ebeaninternal.server.autotune.model.ProfileDiff;
007import io.ebeaninternal.server.autotune.model.ProfileNew;
008import io.ebeaninternal.server.querydefn.OrmQueryDetail;
009
010/**
011 * Event where profiling information is collected and processed for differences
012 * relative to the current query tuning.
013 */
014public class AutoTuneDiffCollection {
015
016  final Autotune document = new Autotune();
017
018  final AutoTuneCollection profiling;
019
020  final BaseQueryTuner queryTuner;
021
022  final boolean updateTuning;
023
024  int newCount;
025
026  int diffCount;
027
028  /**
029   * Construct to collect/report the new/diff query tuning entries.
030   */
031  public AutoTuneDiffCollection(AutoTuneCollection profiling, BaseQueryTuner queryTuner, boolean updateTuning) {
032    this.profiling = profiling;
033    this.queryTuner = queryTuner;
034    this.updateTuning = updateTuning;
035  }
036
037  /**
038   * Return true if there are no new or diff entries.
039   */
040  public boolean isEmpty() {
041    return newCount == 0 && diffCount == 0;
042  }
043
044  /**
045   * Return the underlying Autotune document object.
046   */
047  public Autotune getDocument() {
048    return document;
049  }
050
051  /**
052   * Return the number of diff entries.
053   */
054  public int getDiffCount() {
055    return diffCount;
056  }
057
058  /**
059   * Return the number of new entries.
060   */
061  public int getNewCount() {
062    return newCount;
063  }
064
065  /**
066   * Return the total new and diff entries.
067   */
068  public int getChangeCount() {
069    return newCount + diffCount;
070  }
071
072  /**
073   * Write the underlying document as an xml file.
074   */
075  public void writeFile(String filePrefix) {
076
077    AutoTuneXmlWriter writer = new AutoTuneXmlWriter();
078    writer.write(document, filePrefix, true);
079  }
080
081  /**
082   * Process checking profiling entries against existing query tuning.
083   */
084  public void process() {
085
086    for (AutoTuneCollection.Entry entry : profiling.getEntries()) {
087      addToDocument(entry);
088    }
089  }
090
091  /**
092   * Check if the entry is new or diff and add as necessary.
093   */
094  private void addToDocument(AutoTuneCollection.Entry entry) {
095
096    ObjectGraphOrigin point = entry.getOrigin();
097    OrmQueryDetail profileDetail = entry.getDetail();
098
099    // compare with the existing query tuning entry
100    OrmQueryDetail tuneDetail = queryTuner.get(point.getKey());
101    if (tuneDetail == null) {
102      addToDocumentNewEntry(entry, point);
103
104    } else if (!tuneDetail.isAutoTuneEqual(profileDetail)) {
105      addToDocumentDiffEntry(entry, point, tuneDetail);
106    }
107  }
108
109  /**
110   * Add as a diff entry.
111   */
112  private void addToDocumentDiffEntry(AutoTuneCollection.Entry entry, ObjectGraphOrigin point, OrmQueryDetail tuneDetail) {
113
114    diffCount++;
115
116    Origin origin = createOrigin(entry, point, tuneDetail.toString());
117    ProfileDiff diff = document.getProfileDiff();
118    if (diff == null) {
119      diff = new ProfileDiff();
120      document.setProfileDiff(diff);
121    }
122    diff.getOrigin().add(origin);
123  }
124
125  /**
126   * Add as a "new" entry.
127   */
128  private void addToDocumentNewEntry(AutoTuneCollection.Entry entry, ObjectGraphOrigin point) {
129
130    newCount++;
131
132    ProfileNew profileNew = document.getProfileNew();
133    if (profileNew == null) {
134      profileNew = new ProfileNew();
135      document.setProfileNew(profileNew);
136    }
137    Origin origin = createOrigin(entry, point, entry.getOriginalQuery());
138    profileNew.getOrigin().add(origin);
139  }
140
141
142  /**
143   * Create the XML Origin bean for the given entry and ObjectGraphOrigin.
144   */
145  private Origin createOrigin(AutoTuneCollection.Entry entry, ObjectGraphOrigin point, String query) {
146
147    Origin origin = new Origin();
148    origin.setKey(point.getKey());
149    origin.setBeanType(point.getBeanType());
150    origin.setDetail(entry.getDetail().toString());
151    origin.setCallStack(point.getCallOrigin().getFullDescription());
152    origin.setOriginal(query);
153
154    if (updateTuning) {
155      queryTuner.put(origin);
156    }
157
158    return origin;
159  }
160
161}