/* * Copyright 2010 NCHOVY * * 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.krakenapps.rrd.impl; import java.io.IOException; import java.io.PrintWriter; import org.krakenapps.rrd.ConsolidateFunc; import org.krakenapps.rrd.io.PersistentLayer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class ConsolidatedDataPoint { private Logger logger = LoggerFactory.getLogger(ConsolidatedDataPoint.class); private Archive archive; private double primaryValue = Double.NaN; private double secondaryValue = Double.NaN; private double value = Double.NaN; private long unknownDatapoints = 0; private double lastCheckpointValue = Double.NaN; public ConsolidatedDataPoint(Archive archive) { this.archive = archive; } public ConsolidatedDataPoint(Archive archive, PersistentLayer persLayer) throws IOException { this(archive); primaryValue = persLayer.readDouble(); secondaryValue = persLayer.readDouble(); value = persLayer.readDouble(); unknownDatapoints = persLayer.readLong(); lastCheckpointValue = persLayer.readDouble(); } public void update(long currentTime, long lastUpdate, double checkpointValue) { long step = archive.getRrd().getStep(); if (archive.isCdpExpired(currentTime - step)) logger.debug("Cdp Expired unexpectedly: {}, {}", new Object[] { currentTime - step, archive.getLastUpdate() }); if (Double.isNaN(value)) value = checkpointValue; else if (archive.getCf() == ConsolidateFunc.AVERAGE || archive.getCf() == ConsolidateFunc.SUM) value = value + (Double.isNaN(checkpointValue) ? 0 : checkpointValue); else if (archive.getCf() == ConsolidateFunc.MAX) value = Math.max(value, (Double.isNaN(checkpointValue) ? Double.MIN_VALUE : checkpointValue)); else if (archive.getCf() == ConsolidateFunc.MIN) value = Math.min(value, (Double.isNaN(checkpointValue) ? Double.MAX_VALUE : checkpointValue)); else if (archive.getCf() == ConsolidateFunc.LAST) value = checkpointValue; // currentTime must be multiplier of step. // reason of -1: currentTime - lastUpdate is // from 1 to 10 : unknownDatapoints + 0 // from 11 to 20 : unknownDatapoints + 1 long cdpSeconds = step * archive.getPdpPerRow(); long unknownSeconds = Math.min((currentTime - lastUpdate - 1), currentTime % cdpSeconds); this.unknownDatapoints += (unknownSeconds / step) + (Double.isNaN(checkpointValue) ? 1 : 0); // System.err.printf("cdp updated: value: %s (unknownDatapoints: %d)\n", // Double.toString(this.value), this.unknownDatapoints); this.lastCheckpointValue = checkpointValue; } public Double getCdpValue(long t) { // long lastUpdate = rrd.get().getLastUpdateLong(); // long lastPdpIndex = archive.get().getLastPdpOfCdp(getCdpIndex(lastUpdate)); // long numUnknown = this.unknownDatapoints + lastPdpIndex - getPdpIndex(lastUpdate); long lastPdpIndex = archive.getLastPdpOfCdp(archive.getCdpIndex(t)); @SuppressWarnings("unused") long numUnknown = this.unknownDatapoints + lastPdpIndex - archive.getPdpIndex(t); /* * xff The xfiles factor defines what part of a consolidation interval may be made up from *UNKNOWN* data while the * consolidated value is still regarded as known. It is given as the ratio of allowed *UNKNOWN* PDPs to the number of PDPs * in the interval. Thus, it ranges from 0 to 1 (exclusive). */ /* * if ((double) numUnknown / (double) pdpPerRow > archive.get().getXff()) { System.err.println("warning: xff operated"); * return Double.NaN; } */ // XXX: because I can't find exact formula to calc xff(exactly numUnknown), // I removed concerning xff in evaluation cdp value temporarily. if (archive.getCf() == ConsolidateFunc.AVERAGE) return this.value / (archive.getPdpPerRow() /*- numUnknown*/); return this.value; } public void prepareNewCdp(double primaryValue) { this.primaryValue = primaryValue; this.secondaryValue = this.lastCheckpointValue; this.lastCheckpointValue = Double.NaN; this.value = Double.NaN; this.unknownDatapoints = 0; } public void writeToPersLayer(PersistentLayer persLayer) throws IOException { persLayer.writeDouble(primaryValue); persLayer.writeDouble(secondaryValue); persLayer.writeDouble(value); persLayer.writeLong(unknownDatapoints); persLayer.writeDouble(lastCheckpointValue); } public void dump(PrintWriter writer) { writer.printf("primary: %f, secondary: %f, value: %f\n", primaryValue, secondaryValue, value); writer.printf("unknown datapoints: %d, lastCheckpointValue: %f", unknownDatapoints, lastCheckpointValue); } @Override public boolean equals(Object obj) { ConsolidatedDataPoint rhs = (ConsolidatedDataPoint) obj; if (!RrdUtil.doubleEqual(this.primaryValue, rhs.primaryValue)) return false; if (!RrdUtil.doubleEqual(this.secondaryValue, rhs.secondaryValue)) return false; if (!RrdUtil.doubleEqual(this.value, rhs.value)) return false; if (this.unknownDatapoints != rhs.unknownDatapoints) return false; if (this.lastCheckpointValue != rhs.lastCheckpointValue) return false; return true; } }