/*
* Copyright 2015-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.glowroot.agent.model;
import javax.annotation.Nullable;
// TODO update this comment that was copied from TimerImpl
//
// instances are updated by a single thread, but can be read by other threads
// memory visibility is therefore an issue for the reading threads
//
// memory visibility could be guaranteed by making selfNestingLevel volatile
//
// selfNestingLevel is written after other fields are written and it is read before
// other fields are read, so it could be used to create a memory barrier and make the latest values
// of the other fields visible to the reading thread
//
// but benchmarking shows making selfNestingLevel non-volatile reduces timer capture overhead
// from 88 nanoseconds down to 41 nanoseconds, which is very good since System.nanoTime() takes 17
// nanoseconds and each timer capture has to call it twice
//
// the down side is that the latest updates to timers for transactions that are captured
// in-flight (e.g. partial traces and active traces displayed in the UI) may not be visible
//
// all timing data is in nanoseconds
public class QueryData {
private final String queryType;
private final String queryText;
private final @Nullable QueryData nextQueryData;
// nanosecond rollover (292 years) isn't a concern for total time on a single transaction
private long totalDurationNanos;
private long executionCount;
// this is needed to differentiate between queries that return no rows, and queries which don't
// even have a concept of row (e.g. http client requests which are also tracked as queries)
private boolean hasTotalRows;
private long totalRows;
private long startTick;
private int selfNestingLevel;
public QueryData(String queryType, String queryText, @Nullable QueryData nextQueryData) {
this.queryType = queryType;
this.queryText = queryText;
this.nextQueryData = nextQueryData;
}
public String getQueryType() {
return queryType;
}
public String getQueryText() {
return queryText;
}
public @Nullable QueryData getNextQueryData() {
return nextQueryData;
}
public void start(long startTick, long batchSize) {
if (selfNestingLevel++ == 0) {
this.startTick = startTick;
executionCount += batchSize;
}
}
void end(long endTick) {
if (--selfNestingLevel == 0) {
endInternal(endTick);
}
}
void setHasTotalRows() {
hasTotalRows = true;
}
void incrementRowCount(long inc) {
hasTotalRows = true;
totalRows += inc;
}
public long getTotalDurationNanos() {
return totalDurationNanos;
}
// only called after transaction completion
public long getExecutionCount() {
return executionCount;
}
// only called after transaction completion
public boolean hasTotalRows() {
return hasTotalRows;
}
// only called after transaction completion
public long getTotalRows() {
return totalRows;
}
void extend(long startTick) {
if (selfNestingLevel++ == 0) {
this.startTick = startTick;
}
}
private void endInternal(long endTick) {
totalDurationNanos += endTick - startTick;
}
}