// This file is part of OpenTSDB.
// Copyright (C) 2015 The OpenTSDB Authors.
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 2.1 of the License, or (at your
// option) any later version. This program is distributed in the hope that it
// will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
// General Public License for more details. You should have received a copy
// of the GNU Lesser General Public License along with this program. If not,
// see <http://www.gnu.org/licenses/>.
package net.opentsdb.query.expression;
import java.util.HashSet;
import java.util.Set;
import org.hbase.async.Bytes.ByteMap;
import net.opentsdb.core.DataPoint;
import net.opentsdb.core.DataPoints;
import net.opentsdb.core.MutableDataPoint;
import net.opentsdb.utils.ByteSet;
/**
* Contains the information for a series that has been processed through an
* expression iterator. Each time a metric data point series set is added we
* add the metric and compute the tag sets.
* <p>
* As the iterator progresses, it will call into the {@link #reset} methods.
* @since 2.3
*/
public class ExpressionDataPoint implements DataPoint {
/** A list of metric UIDs wrapped up into this expression result */
private final ByteSet metric_uids;
/** The list of tag key/value pairs common to all series in this expression */
private final ByteMap<byte[]> tags;
/** The list of aggregated tag keys common to all series in this expression */
private final ByteSet aggregated_tags;
/** The list of TSUIDs from all series in this expression */
private final Set<String> tsuids;
/** The size of the aggregated results.
* TODO - this is simply the size of the first series added. We need a way
* to compute this properly.
*/
private long size;
/** The total number of raw data points in all series */
private long raw_size;
/** The data point overwritten each time through the iterator */
private final MutableDataPoint dp;
/** An index in the original {@link TimeSyncedIterator} iterator array */
private int index;
/**
* Default ctor that simply sets up new objects for all internal fields.
* TODO - lazily initialize the field to avoid unused objects
*/
public ExpressionDataPoint() {
metric_uids = new ByteSet();
tags = new ByteMap<byte[]>();
aggregated_tags = new ByteSet();
tsuids = new HashSet<String>();
dp = new MutableDataPoint();
}
/**
* Ctor that sets up the meta data maps and initializes an empty dp
* @param dps The data point to pull meta from
*/
@SuppressWarnings("unchecked")
public ExpressionDataPoint(final DataPoints dps) {
metric_uids = new ByteSet();
metric_uids.add(dps.metricUID());
tags = dps.getTagUids() != null ?
(ByteMap<byte[]>) dps.getTagUids().clone() : new ByteMap<byte[]>();
aggregated_tags = new ByteSet();
if (dps.getAggregatedTagUids() != null) {
for (final byte[] tagk : dps.getAggregatedTagUids()) {
aggregated_tags.add(tagk);
}
}
tsuids = new HashSet<String>(dps.getTSUIDs());
// TODO - restore when these are faster
//size = dps.size();
//raw_size = dps.aggregatedSize();
dp = new MutableDataPoint();
dp.reset(Long.MAX_VALUE, Double.NaN);
}
/**
* Ctor that clones the meta data of the existing dps and sets up an empty value
* @param dps The data point to pull meta from
*/
@SuppressWarnings("unchecked")
public ExpressionDataPoint(final ExpressionDataPoint dps) {
metric_uids = new ByteSet();
metric_uids.addAll(dps.metric_uids);
tags = (ByteMap<byte[]>) dps.tags.clone();
aggregated_tags = new ByteSet();
aggregated_tags.addAll(dps.aggregated_tags);
tsuids = new HashSet<String>(dps.tsuids);
size = dps.size;
raw_size = dps.raw_size;
dp = new MutableDataPoint();
dp.reset(Long.MAX_VALUE, Double.NaN);
}
/**
* Add another metric series to this collection, computing the tag and
* agg intersections and incrementing the size.
* @param dps The series to add
*/
public void add(final DataPoints dps) {
metric_uids.add(dps.metricUID());
// TODO - tags intersection
for (final byte[] tagk : dps.getAggregatedTagUids()) {
aggregated_tags.add(tagk);
}
tsuids.addAll(dps.getTSUIDs());
// TODO - this ain't right. We need to number of dps emitted from HERE. For
// now we'll just take the first dps size. If it's downsampled then this
// will be accurate.
//size += dps.size();
// TODO - restore when this is faster
//raw_size += dps.aggregatedSize();
}
/**
* Add another metric series to this collection, computing the tag and
* agg intersections and incrementing the size.
* @param dps The series to add
*/
public void add(final ExpressionDataPoint dps) {
metric_uids.addAll(dps.metric_uids);
// TODO - tags intersection
aggregated_tags.addAll(dps.aggregated_tags);
tsuids.addAll(dps.tsuids);
// TODO - this ain't right. We need to number of dps emitted from HERE. For
// now we'll just take the first dps size. If it's downsampled then this
// will be accurate.
//size += dps.size();
raw_size += dps.raw_size;
}
/** @return the metric UIDs */
public ByteSet metricUIDs() {
return metric_uids;
}
/** @return the list of common tag pairs in the series */
public ByteMap<byte[]> tags() {
return tags;
}
/** @return the list of aggregated tags */
public ByteSet aggregatedTags() {
return aggregated_tags;
}
/** @return the list of TSUIDs aggregated into this series */
public Set<String> tsuids() {
return tsuids;
}
/** @return the aggregated number of data points in this series */
public long size() {
return size;
}
/** @return the number of raw data points in this series */
public long rawSize() {
return raw_size;
}
/**
* Stores a Double data point
* @param timestamp The timestamp
* @param value The value
*/
public void reset(final long timestamp, final double value) {
dp.reset(timestamp, value);
}
/**
* Stores a data point pulled from the given data point interface
* @param dp the data point to read from
*/
public void reset(final DataPoint dp) {
this.dp.reset(dp);
}
@Override
public String toString() {
final StringBuffer buf = new StringBuffer();
buf.append("ExpressionDataPoint(metricUIDs=")
.append(metric_uids)
.append(", tsuids=")
.append(tsuids)
.append(")");
return buf.toString();
}
// DataPoint implementations
@Override
public long timestamp() {
return dp.timestamp();
}
@Override
public boolean isInteger() {
return dp.isInteger();
}
@Override
public long longValue() {
return dp.longValue();
}
@Override
public double doubleValue() {
return dp.doubleValue();
}
@Override
public double toDouble() {
return dp.toDouble();
}
/** @param index The index in the {@link TimeSyncedIterator} array */
public void setIndex(final int index) {
this.index = index;
}
/** @return the index in the {@link TimeSyncedIterator} array */
public int getIndex() {
return index;
}
}