Update of /cvsroot/jrobin/src/org/jrobin/core In directory sc8-pr-cvs1:/tmp/cvs-serv31519 Modified Files: ArcState.java Archive.java Datasource.java Header.java Robin.java RrdDb.java Sample.java Log Message: Added option to change Min/Max values for datasource and fix archived values accordingly. Added option to change heartbeat, xff etc... Index: ArcState.java =================================================================== RCS file: /cvsroot/jrobin/src/org/jrobin/core/ArcState.java,v retrieving revision 1.4 retrieving revision 1.5 diff -C2 -d -r1.4 -r1.5 *** ArcState.java 27 Nov 2003 14:15:11 -0000 1.4 --- ArcState.java 30 Nov 2003 08:14:07 -0000 1.5 *************** *** 1,133 **** ! /* ============================================================ ! * JRobin : Pure java implementation of RRDTool's functionality ! * ============================================================ ! * ! * Project Info: http://www.jrobin.org ! * Project Lead: Sasa Markovic (sa...@jr...); ! * ! * (C) Copyright 2003, by Sasa Markovic. ! * ! * Developers: Sasa Markovic (sa...@jr...) ! * Arne Vandamme (cob...@jr...) ! * ! * This library 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 library 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 ! * library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, ! * Boston, MA 02111-1307, USA. ! */ ! ! package org.jrobin.core; ! ! import java.io.IOException; ! ! /** ! * Class to represent internal RRD archive state for a single datasource. Objects of this ! * class are never manipulated directly, it's up to JRobin framework to manage ! * internal arcihve states.<p> ! * ! * @author <a href="mailto:sa...@jr...">Sasa Markovic</a> ! */ ! public class ArcState implements RrdUpdater { ! private Archive parentArc; ! ! private RrdDouble accumValue; ! private RrdLong nanSteps; ! ! ArcState(Archive parentArc) throws IOException { ! this.parentArc = parentArc; ! if(getRrdFile().getMode() == RrdFile.MODE_CREATE) { ! // should initialize ! Header header = parentArc.getParentDb().getHeader(); ! long step = header.getStep(); ! long lastUpdateTime = header.getLastUpdateTime(); ! long arcStep = parentArc.getArcStep(); ! long nan = (Util.normalize(lastUpdateTime, step) - ! Util.normalize(lastUpdateTime, arcStep)) / step; ! accumValue = new RrdDouble(Double.NaN, this); ! nanSteps = new RrdLong(nan, this); ! } ! else { ! accumValue = new RrdDouble(this); ! nanSteps = new RrdLong(this); ! } ! } ! ! /** ! * Returns the underlying RrdFile object. ! * @return Underlying RrdFile object. ! */ ! public RrdFile getRrdFile() { ! return parentArc.getParentDb().getRrdFile(); ! } ! ! String dump() throws IOException { ! return "accumValue:" + accumValue.get() + " nanSteps:" + nanSteps.get() + "\n"; ! } ! ! void setNanSteps(long value) throws IOException { ! nanSteps.set(value); ! } ! ! /** ! * Returns the number of currently accumulated NaN steps. ! * ! * @return Number of currently accumulated NaN steps. ! * @throws IOException Thrown in case of IO specific error ! */ ! public long getNanSteps() throws IOException { ! return nanSteps.get(); ! } ! ! void setAccumValue(double value) throws IOException { ! accumValue.set(value); ! } ! ! /** ! * Returns the value accumulated so far. ! * ! * @return Accumulated value ! * @throws IOException Thrown in case of IO specific error ! */ ! public double getAccumValue() throws IOException { ! return accumValue.get(); ! } ! ! /** ! * Returns the Archive object to which this ArcState object belongs. ! * ! * @return Parent Archive object. ! */ ! public Archive getParent() { ! return parentArc; ! } ! ! void appendXml(XmlWriter writer) throws IOException { ! writer.startTag("ds"); ! writer.writeTag("value", accumValue.get()); ! writer.writeTag("unknown_datapoints", nanSteps.get()); ! writer.closeTag(); // ds ! } ! ! /** ! * Copies object's internal state to another ArcState object. ! * @param other New ArcState object to copy state to ! * @throws IOException Thrown in case of I/O error ! * @throws RrdException Thrown if supplied argument is not an ArcState object ! */ ! public void copyStateTo(RrdUpdater other) throws IOException, RrdException { ! if(!(other instanceof ArcState)) { ! throw new RrdException( ! "Cannot copy ArcState object to " + other.getClass().getName()); ! } ! ArcState arcState = (ArcState) other; ! arcState.accumValue.set(accumValue.get()); ! arcState.nanSteps.set(nanSteps.get()); ! } ! } --- 1,131 ---- ! /* ============================================================ ! * JRobin : Pure java implementation of RRDTool's functionality ! * ============================================================ ! * ! * Project Info: http://www.jrobin.org ! * Project Lead: Sasa Markovic (sa...@jr...); ! * ! * (C) Copyright 2003, by Sasa Markovic. ! * ! * Developers: Sasa Markovic (sa...@jr...) ! * Arne Vandamme (cob...@jr...) ! * ! * This library 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 library 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 ! * library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, ! * Boston, MA 02111-1307, USA. ! */ ! ! package org.jrobin.core; ! ! import java.io.IOException; ! ! /** ! * Class to represent internal RRD archive state for a single datasource. Objects of this ! * class are never manipulated directly, it's up to JRobin framework to manage ! * internal arcihve states.<p> ! * ! * @author <a href="mailto:sa...@jr...">Sasa Markovic</a> ! */ ! public class ArcState implements RrdUpdater { ! private Archive parentArc; ! ! private RrdDouble accumValue; ! private RrdLong nanSteps; ! ! ArcState(Archive parentArc) throws IOException { ! this.parentArc = parentArc; ! if(getRrdFile().getMode() == RrdFile.MODE_CREATE) { ! // should initialize ! Header header = parentArc.getParentDb().getHeader(); ! long step = header.getStep(); ! long lastUpdateTime = header.getLastUpdateTime(); ! long arcStep = parentArc.getArcStep(); ! long nan = (Util.normalize(lastUpdateTime, step) - ! Util.normalize(lastUpdateTime, arcStep)) / step; ! accumValue = new RrdDouble(Double.NaN, this); ! nanSteps = new RrdLong(nan, this); ! } ! else { ! accumValue = new RrdDouble(this); ! nanSteps = new RrdLong(this); ! } ! } ! ! /** ! * Returns the underlying RrdFile object. ! * @return Underlying RrdFile object. ! */ ! public RrdFile getRrdFile() { ! return parentArc.getParentDb().getRrdFile(); ! } ! ! String dump() { ! return "accumValue:" + accumValue.get() + " nanSteps:" + nanSteps.get() + "\n"; ! } ! ! void setNanSteps(long value) throws IOException { ! nanSteps.set(value); ! } ! ! /** ! * Returns the number of currently accumulated NaN steps. ! * ! * @return Number of currently accumulated NaN steps. ! */ ! public long getNanSteps() { ! return nanSteps.get(); ! } ! ! void setAccumValue(double value) throws IOException { ! accumValue.set(value); ! } ! ! /** ! * Returns the value accumulated so far. ! * ! * @return Accumulated value ! */ ! public double getAccumValue() { ! return accumValue.get(); ! } ! ! /** ! * Returns the Archive object to which this ArcState object belongs. ! * ! * @return Parent Archive object. ! */ ! public Archive getParent() { ! return parentArc; ! } ! ! void appendXml(XmlWriter writer) throws IOException { ! writer.startTag("ds"); ! writer.writeTag("value", accumValue.get()); ! writer.writeTag("unknown_datapoints", nanSteps.get()); ! writer.closeTag(); // ds ! } ! ! /** ! * Copies object's internal state to another ArcState object. ! * @param other New ArcState object to copy state to ! * @throws IOException Thrown in case of I/O error ! * @throws RrdException Thrown if supplied argument is not an ArcState object ! */ ! public void copyStateTo(RrdUpdater other) throws IOException, RrdException { ! if(!(other instanceof ArcState)) { ! throw new RrdException( ! "Cannot copy ArcState object to " + other.getClass().getName()); ! } ! ArcState arcState = (ArcState) other; ! arcState.accumValue.set(accumValue.get()); ! arcState.nanSteps.set(nanSteps.get()); ! } ! } Index: Archive.java =================================================================== RCS file: /cvsroot/jrobin/src/org/jrobin/core/Archive.java,v retrieving revision 1.7 retrieving revision 1.8 diff -C2 -d -r1.7 -r1.8 *** Archive.java 28 Nov 2003 13:24:46 -0000 1.7 --- Archive.java 30 Nov 2003 08:14:09 -0000 1.8 *************** *** 1,419 **** ! /* ============================================================ ! * JRobin : Pure java implementation of RRDTool's functionality ! * ============================================================ ! * ! * Project Info: http://www.jrobin.org ! * Project Lead: Sasa Markovic (sa...@jr...); ! * ! * (C) Copyright 2003, by Sasa Markovic. ! * ! * Developers: Sasa Markovic (sa...@jr...) ! * Arne Vandamme (cob...@jr...) ! * ! * This library 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 library 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 ! * library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, ! * Boston, MA 02111-1307, USA. ! */ ! ! package org.jrobin.core; ! ! import java.io.IOException; ! ! /** ! * Class to represent single RRD archive in a RRD file with its internal state. ! * Normally, you don't need methods to manipulate archive objects directly ! * because JRobin framework does it automatically for you.<p> ! * ! * Each archive object consists of three parts: archive definition, archive state objects ! * (one state object for each datasource) and round robin archives (one round robin for ! * each datasource). API (read-only) is provided to access each of theese parts.<p> ! * ! * @author <a href="mailto:sa...@jr...">Sasa Markovic</a> ! */ ! public class Archive implements RrdUpdater { ! private RrdDb parentDb; ! // definition ! private RrdString consolFun; ! private RrdDouble xff; ! private RrdInt steps, rows; ! // state ! private Robin[] robins; ! private ArcState[] states; ! ! // first time creation ! Archive(RrdDb parentDb, ArcDef arcDef) throws IOException { ! this.parentDb = parentDb; ! consolFun = new RrdString(arcDef.getConsolFun(), this); ! xff = new RrdDouble(arcDef.getXff(), this); ! steps = new RrdInt(arcDef.getSteps(), this); ! rows = new RrdInt(arcDef.getRows(), this); ! int n = parentDb.getHeader().getDsCount(); ! robins = new Robin[n]; ! states = new ArcState[n]; ! for(int i = 0; i < n; i++) { ! states[i] = new ArcState(this); ! robins[i] = new Robin(this, rows.get()); ! } ! } ! ! // read from file ! Archive(RrdDb parentDb) throws IOException { ! this.parentDb = parentDb; ! consolFun = new RrdString(this); ! xff = new RrdDouble(this); ! steps = new RrdInt(this); ! rows = new RrdInt(this); ! int n = parentDb.getHeader().getDsCount(); ! states = new ArcState[n]; ! robins = new Robin[n]; ! for(int i = 0; i < n; i++) { ! states[i] = new ArcState(this); ! robins[i] = new Robin(this, rows.get()); ! } ! } ! ! Archive(RrdDb parentDb, XmlReader reader, int arcIndex) throws IOException, RrdException { ! this.parentDb = parentDb; ! consolFun = new RrdString(reader.getConsolFun(arcIndex), this); ! xff = new RrdDouble(reader.getXff(arcIndex), this); ! steps = new RrdInt(reader.getSteps(arcIndex), this); ! rows = new RrdInt(reader.getRows(arcIndex), this); ! int dsCount = reader.getDsCount(); ! states = new ArcState[dsCount]; ! robins = new Robin[dsCount]; ! for(int dsIndex = 0; dsIndex < dsCount; dsIndex++) { ! // restore state ! states[dsIndex] = new ArcState(this); ! states[dsIndex].setAccumValue(reader.getStateAccumValue(arcIndex, dsIndex)); ! states[dsIndex].setNanSteps(reader.getStateNanSteps(arcIndex, dsIndex)); ! // restore robins ! robins[dsIndex] = new Robin(this, rows.get()); ! double[] values = reader.getValues(arcIndex, dsIndex); ! for(int j = 0; j < values.length; j++) { ! robins[dsIndex].store(values[j]); ! } ! } ! } ! ! /** ! * Returns archive time step in seconds. Archive step is equal to RRD file step ! * multiplied with the number of archive steps. ! * ! * @return Archive time step in seconds ! * @throws IOException Thrown in case of IO error ! */ ! public long getArcStep() throws IOException { ! long step = parentDb.getHeader().getStep(); ! return step * steps.get(); ! } ! ! String dump() throws IOException { ! StringBuffer buffer = new StringBuffer("== ARCHIVE ==\n"); ! buffer.append("RRA:" + consolFun.get() + ":" + xff.get() + ":" + ! steps.get() + ":" + rows.get() + "\n"); ! buffer.append("interval [" + getStartTime() + ", " + getEndTime() + "]" + "\n"); ! for(int i = 0; i < robins.length; i++) { ! buffer.append(states[i].dump()); ! buffer.append(robins[i].dump()); ! } ! return buffer.toString(); ! } ! ! RrdDb getParentDb() { ! return parentDb; ! } ! ! /** ! * Returns the underlying RrdFile object. ! * @return Underlying RrdFile object ! */ ! public RrdFile getRrdFile() { ! return parentDb.getRrdFile(); ! } ! ! void archive(int dsIndex, double value, long numUpdates) throws IOException { ! Robin robin = robins[dsIndex]; ! ArcState state = states[dsIndex]; ! long step = parentDb.getHeader().getStep(); ! long lastUpdateTime = parentDb.getHeader().getLastUpdateTime(); ! long updateTime = Util.normalize(lastUpdateTime, step) + step; ! long arcStep = getArcStep(); ! // finish current step ! while(numUpdates > 0) { ! accumulate(state, value); ! numUpdates--; ! if(updateTime % arcStep == 0) { ! finalizeStep(state, robin); ! break; ! } ! else { ! updateTime += step; ! } ! } ! // update robin in bulk ! long bulkUpdates = Math.min(numUpdates / steps.get(), (long) rows.get()); ! for(long i = 0; i < bulkUpdates; i++) { ! robin.store(value); ! } ! // update remaining steps ! long remainingUpdates = numUpdates % steps.get(); ! for(long i = 0; i < remainingUpdates; i++) { ! accumulate(state, value); ! } ! } ! ! private void accumulate(ArcState state, double value) throws IOException { ! if(Double.isNaN(value)) { ! state.setNanSteps(state.getNanSteps() + 1); ! } ! else { ! if(consolFun.get().equals("MIN")) { ! state.setAccumValue(Util.min(state.getAccumValue(), value)); ! } ! else if(consolFun.get().equals("MAX")) { ! state.setAccumValue(Util.max(state.getAccumValue(), value)); ! } ! else if(consolFun.get().equals("LAST")) { ! state.setAccumValue(value); ! } ! else if(consolFun.get().equals("AVERAGE")) { ! state.setAccumValue(Util.sum(state.getAccumValue(), value)); ! } ! } ! } ! ! private void finalizeStep(ArcState state, Robin robin) throws IOException { ! // should store ! long arcSteps = steps.get(); ! long nanSteps = state.getNanSteps(); ! double nanPct = (double) nanSteps / (double) arcSteps; ! double accumValue = state.getAccumValue(); ! if(nanPct <= xff.get() && !Double.isNaN(accumValue)) { ! if(consolFun.get().equals("AVERAGE")) { ! accumValue /= (arcSteps - nanSteps); ! } ! robin.store(accumValue); ! } ! else { ! robin.store(Double.NaN); ! } ! state.setAccumValue(Double.NaN); ! state.setNanSteps(0); ! } ! ! /** ! * Returns archive consolidation function (AVERAGE, MIN, MAX or LAST). ! * @return Archive consolidation function. ! * @throws IOException Thrown in case of IO related error ! */ ! public String getConsolFun() throws IOException { ! return consolFun.get(); ! } ! ! /** ! * Returns archive X-files factor. ! * @return Archive X-files factor (between 0 and 1). ! * @throws IOException Thrown in case of IO related error ! */ ! public double getXff() throws IOException { ! return xff.get(); ! } ! ! /** ! * Returns the number of archive steps. ! * @return Number of archive steps. ! * @throws IOException Thrown in case of IO related error ! */ ! public int getSteps() throws IOException { ! return steps.get(); ! } ! ! /** ! * Returns the number of archive rows. ! * @return Number of archive rows. ! * @throws IOException Thrown in case of IO related error ! */ ! public int getRows() throws IOException{ ! return rows.get(); ! } ! ! /** ! * Returns current starting timestamp. This value is not constant. ! * @return Timestamp corresponding to the first archive row ! * @throws IOException Thrown in case of IO related error ! */ ! public long getStartTime() throws IOException { ! long endTime = getEndTime(); ! long arcStep = getArcStep(); ! long numRows = rows.get(); ! return endTime - (numRows - 1) * arcStep; ! } ! ! /** ! * Returns current ending timestamp. This value is not constant. ! * @return Timestamp corresponding to the last archive row ! * @throws IOException Thrown in case of IO related error ! */ ! public long getEndTime() throws IOException { ! long arcStep = getArcStep(); ! long lastUpdateTime = parentDb.getHeader().getLastUpdateTime(); ! return Util.normalize(lastUpdateTime, arcStep); ! } ! ! /** ! * Returns the underlying archive state object. Each datasource has its ! * corresponding ArcState object (archive states are managed independently ! * for each RRD datasource). ! * @param dsIndex Datasource index ! * @return Underlying archive state object ! */ ! public ArcState getArcState(int dsIndex) { ! return states[dsIndex]; ! } ! ! /** ! * Returns the underlying round robin archive. Robins are used to store actual ! * archive values on a per-datasource basis. ! * @param dsIndex Index of the datasource in the RRD file. ! * @return Underlying round robin archive for the given datasource. ! */ ! public Robin getRobin(int dsIndex) { ! return robins[dsIndex]; ! } ! ! FetchPoint[] fetch(FetchRequest request) throws IOException, RrdException { ! if(request.getFilter() != null) { ! throw new RrdException("fetch() method does not support filtered datasources." + ! " Use fetchData() to get filtered fetch data."); ! } ! long arcStep = getArcStep(); ! long fetchStart = Util.normalize(request.getFetchStart(), arcStep); ! long fetchEnd = Util.normalize(request.getFetchEnd(), arcStep); ! if(fetchEnd < request.getFetchEnd()) { ! fetchEnd += arcStep; ! } ! long startTime = getStartTime(); ! long endTime = getEndTime(); ! int dsCount = robins.length; ! int ptsCount = (int) ((fetchEnd - fetchStart) / arcStep + 1); ! FetchPoint[] points = new FetchPoint[ptsCount]; ! for(int i = 0; i < ptsCount; i++) { ! long time = fetchStart + i * arcStep; ! FetchPoint point = new FetchPoint(time, dsCount); ! if(time >= startTime && time <= endTime) { ! int robinIndex = (int)((time - startTime) / arcStep); ! for(int j = 0; j < dsCount; j++) { ! point.setValue(j, robins[j].getValue(robinIndex)); ! } ! } ! points[i] = point; ! } ! return points; ! } ! ! FetchData fetchData(FetchRequest request) throws IOException, RrdException { ! long arcStep = getArcStep(); ! long fetchStart = Util.normalize(request.getFetchStart(), arcStep); ! long fetchEnd = Util.normalize(request.getFetchEnd(), arcStep); ! if(fetchEnd < request.getFetchEnd()) { ! fetchEnd += arcStep; ! } ! long startTime = getStartTime(); ! long endTime = getEndTime(); ! String[] dsToFetch = request.getFilter(); ! if(dsToFetch == null) { ! dsToFetch = parentDb.getDsNames(); ! } ! int dsCount = dsToFetch.length; ! int ptsCount = (int) ((fetchEnd - fetchStart) / arcStep + 1); ! long[] timestamps = new long[ptsCount]; ! double[][] values = new double[dsCount][ptsCount]; ! for(int ptIndex = 0; ptIndex < ptsCount; ptIndex++) { ! long time = fetchStart + ptIndex * arcStep; ! timestamps[ptIndex] = time; ! if(time >= startTime && time <= endTime) { ! // inbound time ! int robinIndex = (int)((time - startTime) / arcStep); ! for(int i = 0; i < dsCount; i++) { ! int dsIndex = parentDb.getDsIndex(dsToFetch[i]); ! values[i][ptIndex] = robins[dsIndex].getValue(robinIndex); ! } ! } ! else { ! // time out of bounds ! for(int i = 0; i < dsCount; i++) { ! values[i][ptIndex] = Double.NaN; ! } ! } ! } ! FetchData fetchData = new FetchData(this, request); ! fetchData.setTimestamps(timestamps); ! fetchData.setValues(values); ! return fetchData; ! } ! ! void appendXml(XmlWriter writer) throws IOException { ! writer.startTag("rra"); ! writer.writeTag("cf", consolFun.get()); ! writer.writeComment(getArcStep() + " seconds"); ! writer.writeTag("pdp_per_row", steps.get()); ! writer.writeTag("xff", xff.get()); ! writer.startTag("cdp_prep"); ! for(int i = 0; i < states.length; i++) { ! states[i].appendXml(writer); ! } ! writer.closeTag(); // cdp_prep ! writer.startTag("database"); ! long startTime = getStartTime(); ! for(int i = 0; i < rows.get(); i++) { ! long time = startTime + i * getArcStep(); ! writer.writeComment(Util.getDate(time) + " / " + time); ! writer.startTag("row"); ! for(int j = 0; j < robins.length; j++) { ! writer.writeTag("v", robins[j].getValue(i)); ! } ! writer.closeTag(); // row ! } ! writer.closeTag(); // database ! writer.closeTag(); // rra ! } ! ! /** ! * Copies object's internal state to another Archive object. ! * @param other New Archive object to copy state to ! * @throws IOException Thrown in case of I/O error ! * @throws RrdException Thrown if supplied argument is not an Archive object ! */ ! public void copyStateTo(RrdUpdater other) throws IOException, RrdException { ! if(!(other instanceof Archive)) { ! throw new RrdException( ! "Cannot copy Archive object to " + other.getClass().getName()); ! } ! Archive arc = (Archive) other; ! if(!arc.consolFun.get().equals(consolFun.get())) { ! throw new RrdException("Incompatible consolidation functions"); ! } ! if(arc.steps.get() != steps.get()) { ! throw new RrdException("Incompatible number of steps"); ! } ! if(arc.rows.get() != rows.get()) { ! throw new RrdException("Incompatible number of rows"); ! } ! int count = parentDb.getHeader().getDsCount(); ! for(int i = 0; i < count; i++) { ! int j = Util.getMatchingDatasourceIndex(parentDb, i, arc.parentDb); ! if(j >= 0) { ! states[i].copyStateTo(arc.states[j]); ! robins[i].copyStateTo(arc.robins[j]); ! } ! } ! } ! } --- 1,426 ---- ! /* ============================================================ ! * JRobin : Pure java implementation of RRDTool's functionality ! * ============================================================ ! * ! * Project Info: http://www.jrobin.org ! * Project Lead: Sasa Markovic (sa...@jr...); ! * ! * (C) Copyright 2003, by Sasa Markovic. ! * ! * Developers: Sasa Markovic (sa...@jr...) ! * Arne Vandamme (cob...@jr...) ! * ! * This library 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 library 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 ! * library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, ! * Boston, MA 02111-1307, USA. ! */ ! ! package org.jrobin.core; ! ! import java.io.IOException; ! ! /** ! * Class to represent single RRD archive in a RRD file with its internal state. ! * Normally, you don't need methods to manipulate archive objects directly ! * because JRobin framework does it automatically for you.<p> ! * ! * Each archive object consists of three parts: archive definition, archive state objects ! * (one state object for each datasource) and round robin archives (one round robin for ! * each datasource). API (read-only) is provided to access each of theese parts.<p> ! * ! * @author <a href="mailto:sa...@jr...">Sasa Markovic</a> ! */ ! public class Archive implements RrdUpdater { ! private RrdDb parentDb; ! // definition ! private RrdString consolFun; ! private RrdDouble xff; ! private RrdInt steps, rows; ! // state ! private Robin[] robins; ! private ArcState[] states; ! ! // first time creation ! Archive(RrdDb parentDb, ArcDef arcDef) throws IOException { ! this.parentDb = parentDb; ! consolFun = new RrdString(arcDef.getConsolFun(), this); ! xff = new RrdDouble(arcDef.getXff(), this); ! steps = new RrdInt(arcDef.getSteps(), this); ! rows = new RrdInt(arcDef.getRows(), this); ! int n = parentDb.getHeader().getDsCount(); ! robins = new Robin[n]; ! states = new ArcState[n]; ! for(int i = 0; i < n; i++) { ! states[i] = new ArcState(this); ! robins[i] = new Robin(this, rows.get()); ! } ! } ! ! // read from file ! Archive(RrdDb parentDb) throws IOException { ! this.parentDb = parentDb; ! consolFun = new RrdString(this); ! xff = new RrdDouble(this); ! steps = new RrdInt(this); ! rows = new RrdInt(this); ! int n = parentDb.getHeader().getDsCount(); ! states = new ArcState[n]; ! robins = new Robin[n]; ! for(int i = 0; i < n; i++) { ! states[i] = new ArcState(this); ! robins[i] = new Robin(this, rows.get()); ! } ! } ! ! // read from XML ! Archive(RrdDb parentDb, XmlReader reader, int arcIndex) throws IOException, RrdException { ! this.parentDb = parentDb; ! consolFun = new RrdString(reader.getConsolFun(arcIndex), this); ! xff = new RrdDouble(reader.getXff(arcIndex), this); ! steps = new RrdInt(reader.getSteps(arcIndex), this); ! rows = new RrdInt(reader.getRows(arcIndex), this); ! int dsCount = reader.getDsCount(); ! states = new ArcState[dsCount]; ! robins = new Robin[dsCount]; ! for(int dsIndex = 0; dsIndex < dsCount; dsIndex++) { ! // restore state ! states[dsIndex] = new ArcState(this); ! states[dsIndex].setAccumValue(reader.getStateAccumValue(arcIndex, dsIndex)); ! states[dsIndex].setNanSteps(reader.getStateNanSteps(arcIndex, dsIndex)); ! // restore robins ! robins[dsIndex] = new Robin(this, rows.get()); ! double[] values = reader.getValues(arcIndex, dsIndex); ! for(int j = 0; j < values.length; j++) { ! robins[dsIndex].store(values[j]); ! } ! } ! } ! ! /** ! * Returns archive time step in seconds. Archive step is equal to RRD file step ! * multiplied with the number of archive steps. ! * ! * @return Archive time step in seconds ! */ ! public long getArcStep() { ! long step = parentDb.getHeader().getStep(); ! return step * steps.get(); ! } ! ! String dump() throws IOException { ! StringBuffer buffer = new StringBuffer("== ARCHIVE ==\n"); ! buffer.append("RRA:" + consolFun.get() + ":" + xff.get() + ":" + ! steps.get() + ":" + rows.get() + "\n"); ! buffer.append("interval [" + getStartTime() + ", " + getEndTime() + "]" + "\n"); ! for(int i = 0; i < robins.length; i++) { ! buffer.append(states[i].dump()); ! buffer.append(robins[i].dump()); ! } ! return buffer.toString(); ! } ! ! RrdDb getParentDb() { ! return parentDb; ! } ! ! /** ! * Returns the underlying RrdFile object. ! * @return Underlying RrdFile object ! */ ! public RrdFile getRrdFile() { ! return parentDb.getRrdFile(); ! } ! ! void archive(int dsIndex, double value, long numUpdates) throws IOException { ! Robin robin = robins[dsIndex]; ! ArcState state = states[dsIndex]; ! long step = parentDb.getHeader().getStep(); ! long lastUpdateTime = parentDb.getHeader().getLastUpdateTime(); ! long updateTime = Util.normalize(lastUpdateTime, step) + step; ! long arcStep = getArcStep(); ! // finish current step ! while(numUpdates > 0) { ! accumulate(state, value); ! numUpdates--; ! if(updateTime % arcStep == 0) { ! finalizeStep(state, robin); ! break; ! } ! else { ! updateTime += step; ! } ! } ! // update robin in bulk ! long bulkUpdates = Math.min(numUpdates / steps.get(), (long) rows.get()); ! for(long i = 0; i < bulkUpdates; i++) { ! robin.store(value); ! } ! // update remaining steps ! long remainingUpdates = numUpdates % steps.get(); ! for(long i = 0; i < remainingUpdates; i++) { ! accumulate(state, value); ! } ! } ! ! private void accumulate(ArcState state, double value) throws IOException { ! if(Double.isNaN(value)) { ! state.setNanSteps(state.getNanSteps() + 1); ! } ! else { ! if(consolFun.get().equals("MIN")) { ! state.setAccumValue(Util.min(state.getAccumValue(), value)); ! } ! else if(consolFun.get().equals("MAX")) { ! state.setAccumValue(Util.max(state.getAccumValue(), value)); ! } ! else if(consolFun.get().equals("LAST")) { ! state.setAccumValue(value); ! } ! else if(consolFun.get().equals("AVERAGE")) { ! state.setAccumValue(Util.sum(state.getAccumValue(), value)); ! } ! } ! } ! ! private void finalizeStep(ArcState state, Robin robin) throws IOException { ! // should store ! long arcSteps = steps.get(); ! long nanSteps = state.getNanSteps(); ! double nanPct = (double) nanSteps / (double) arcSteps; ! double accumValue = state.getAccumValue(); ! if(nanPct <= xff.get() && !Double.isNaN(accumValue)) { ! if(consolFun.get().equals("AVERAGE")) { ! accumValue /= (arcSteps - nanSteps); ! } ! robin.store(accumValue); ! } ! else { ! robin.store(Double.NaN); ! } ! state.setAccumValue(Double.NaN); ! state.setNanSteps(0); ! } ! ! /** ! * Returns archive consolidation function (AVERAGE, MIN, MAX or LAST). ! * @return Archive consolidation function. ! */ ! public String getConsolFun() { ! return consolFun.get(); ! } ! ! /** ! * Returns archive X-files factor. ! * @return Archive X-files factor (between 0 and 1). ! */ ! public double getXff() { ! return xff.get(); ! } ! ! /** ! * Returns the number of archive steps. ! * @return Number of archive steps. ! */ ! public int getSteps() { ! return steps.get(); ! } ! ! /** ! * Returns the number of archive rows. ! * @return Number of archive rows. ! */ ! public int getRows() { ! return rows.get(); ! } ! ! /** ! * Returns current starting timestamp. This value is not constant. ! * @return Timestamp corresponding to the first archive row ! */ ! public long getStartTime() { ! long endTime = getEndTime(); ! long arcStep = getArcStep(); ! long numRows = rows.get(); ! return endTime - (numRows - 1) * arcStep; ! } ! ! /** ! * Returns current ending timestamp. This value is not constant. ! * @return Timestamp corresponding to the last archive row ! */ ! public long getEndTime() { ! long arcStep = getArcStep(); ! long lastUpdateTime = parentDb.getHeader().getLastUpdateTime(); ! return Util.normalize(lastUpdateTime, arcStep); ! } ! ! /** ! * Returns the underlying archive state object. Each datasource has its ! * corresponding ArcState object (archive states are managed independently ! * for each RRD datasource). ! * @param dsIndex Datasource index ! * @return Underlying archive state object ! */ ! public ArcState getArcState(int dsIndex) { ! return states[dsIndex]; ! } ! ! /** ! * Returns the underlying round robin archive. Robins are used to store actual ! * archive values on a per-datasource basis. ! * @param dsIndex Index of the datasource in the RRD file. ! * @return Underlying round robin archive for the given datasource. ! */ ! public Robin getRobin(int dsIndex) { ! return robins[dsIndex]; ! } ! ! FetchPoint[] fetch(FetchRequest request) throws IOException, RrdException { ! if(request.getFilter() != null) { ! throw new RrdException("fetch() method does not support filtered datasources." + ! " Use fetchData() to get filtered fetch data."); ! } ! long arcStep = getArcStep(); ! long fetchStart = Util.normalize(request.getFetchStart(), arcStep); ! long fetchEnd = Util.normalize(request.getFetchEnd(), arcStep); ! if(fetchEnd < request.getFetchEnd()) { ! fetchEnd += arcStep; ! } ! long startTime = getStartTime(); ! long endTime = getEndTime(); ! int dsCount = robins.length; ! int ptsCount = (int) ((fetchEnd - fetchStart) / arcStep + 1); ! FetchPoint[] points = new FetchPoint[ptsCount]; ! for(int i = 0; i < ptsCount; i++) { ! long time = fetchStart + i * arcStep; ! FetchPoint point = new FetchPoint(time, dsCount); ! if(time >= startTime && time <= endTime) { ! int robinIndex = (int)((time - startTime) / arcStep); ! for(int j = 0; j < dsCount; j++) { ! point.setValue(j, robins[j].getValue(robinIndex)); ! } ! } ! points[i] = point; ! } ! return points; ! } ! ! FetchData fetchData(FetchRequest request) throws IOException, RrdException { ! long arcStep = getArcStep(); ! long fetchStart = Util.normalize(request.getFetchStart(), arcStep); ! long fetchEnd = Util.normalize(request.getFetchEnd(), arcStep); ! if(fetchEnd < request.getFetchEnd()) { ! fetchEnd += arcStep; ! } ! long startTime = getStartTime(); ! long endTime = getEndTime(); ! String[] dsToFetch = request.getFilter(); ! if(dsToFetch == null) { ! dsToFetch = parentDb.getDsNames(); ! } ! int dsCount = dsToFetch.length; ! int ptsCount = (int) ((fetchEnd - fetchStart) / arcStep + 1); ! long[] timestamps = new long[ptsCount]; ! double[][] values = new double[dsCount][ptsCount]; ! for(int ptIndex = 0; ptIndex < ptsCount; ptIndex++) { ! long time = fetchStart + ptIndex * arcStep; ! timestamps[ptIndex] = time; ! if(time >= startTime && time <= endTime) { ! // inbound time ! int robinIndex = (int)((time - startTime) / arcStep); ! for(int i = 0; i < dsCount; i++) { ! int dsIndex = parentDb.getDsIndex(dsToFetch[i]); ! values[i][ptIndex] = robins[dsIndex].getValue(robinIndex); ! } ! } ! else { ! // time out of bounds ! for(int i = 0; i < dsCount; i++) { ! values[i][ptIndex] = Double.NaN; ! } ! } ! } ! FetchData fetchData = new FetchData(this, request); ! fetchData.setTimestamps(timestamps); ! fetchData.setValues(values); ! return fetchData; ! } ! ! void appendXml(XmlWriter writer) throws IOException { ! writer.startTag("rra"); ! writer.writeTag("cf", consolFun.get()); ! writer.writeComment(getArcStep() + " seconds"); ! writer.writeTag("pdp_per_row", steps.get()); ! writer.writeTag("xff", xff.get()); ! writer.startTag("cdp_prep"); ! for(int i = 0; i < states.length; i++) { ! states[i].appendXml(writer); ! } ! writer.closeTag(); // cdp_prep ! writer.startTag("database"); ! long startTime = getStartTime(); ! for(int i = 0; i < rows.get(); i++) { ! long time = startTime + i * getArcStep(); ! writer.writeComment(Util.getDate(time) + " / " + time); ! writer.startTag("row"); ! for(int j = 0; j < robins.length; j++) { ! writer.writeTag("v", robins[j].getValue(i)); ! } ! writer.closeTag(); // row ! } ! writer.closeTag(); // database ! writer.closeTag(); // rra ! } ! ! /** ! * Copies object's internal state to another Archive object. ! * @param other New Archive object to copy state to ! * @throws IOException Thrown in case of I/O error ! * @throws RrdException Thrown if supplied argument is not an Archive object ! */ ! public void copyStateTo(RrdUpdater other) throws IOException, RrdException { ! if(!(other instanceof Archive)) { ! throw new RrdException( ! "Cannot copy Archive object to " + other.getClass().getName()); ! } ! Archive arc = (Archive) other; ! if(!arc.consolFun.get().equals(consolFun.get())) { ! throw new RrdException("Incompatible consolidation functions"); ! } ! if(arc.steps.get() != steps.get()) { ! throw new RrdException("Incompatible number of steps"); ! } ! if(arc.rows.get() != rows.get()) { ! throw new RrdException("Incompatible number of rows"); ! } ! int count = parentDb.getHeader().getDsCount(); ! for(int i = 0; i < count; i++) { ! int j = Util.getMatchingDatasourceIndex(parentDb, i, arc.parentDb); ! if(j >= 0) { ! states[i].copyStateTo(arc.states[j]); ! robins[i].copyStateTo(arc.robins[j]); ! } ! } ! } ! ! /** ! * Sets X-files factor to a new value. ! * @param xff New X-files factor value. Must be >= 0 and < 1. ! * @throws RrdException Thrown if invalid value is supplied ! * @throws IOException Thrown in case of I/O error ! */ ! public void setXff(double xff) throws RrdException, IOException { ! if(xff < 0D || xff >= 1D) { ! throw new RrdException("Invalid xff supplied (" + xff + "), must be >= 0 and < 1"); ! } ! this.xff.set(xff); ! } ! } Index: Datasource.java =================================================================== RCS file: /cvsroot/jrobin/src/org/jrobin/core/Datasource.java,v retrieving revision 1.3 retrieving revision 1.4 diff -C2 -d -r1.3 -r1.4 *** Datasource.java 27 Nov 2003 14:15:11 -0000 1.3 --- Datasource.java 30 Nov 2003 08:14:09 -0000 1.4 *************** *** 1,315 **** ! /* ============================================================ ! * JRobin : Pure java implementation of RRDTool's functionality ! * ============================================================ ! * ! * Project Info: http://www.jrobin.org ! * Project Lead: Sasa Markovic (sa...@jr...); ! * ! * (C) Copyright 2003, by Sasa Markovic. ! * ! * Developers: Sasa Markovic (sa...@jr...) ! * Arne Vandamme (cob...@jr...) ! * ! * This library 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 library 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 ! * library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, ! * Boston, MA 02111-1307, USA. ! */ ! ! package org.jrobin.core; ! ! import java.io.IOException; ! ! /** ! * Class to represent single datasource within RRD file. Each datasource object holds the ! * following information: datasource definition (once set, never changed) and ! * datasource state variables (changed whenever RRD file gets updated).<p> ! * ! * Normally, you don't need to manipluate Datasource objects directly, it's up to ! * JRobin framework to do it for you. ! * ! * @author <a href="mailto:sa...@jr...">Sasa Markovic</a> ! */ ! public class Datasource implements RrdUpdater { ! private RrdDb parentDb; ! // definition ! private RrdString dsName, dsType; ! private RrdLong heartbeat; ! private RrdDouble minValue, maxValue; ! // state variables ! private RrdDouble lastValue; ! private RrdLong nanSeconds; ! private RrdDouble accumValue; ! ! Datasource(RrdDb parentDb, DsDef dsDef) throws IOException { ! this.parentDb = parentDb; ! dsName = new RrdString(dsDef.getDsName(), this); ! dsType = new RrdString(dsDef.getDsType(), this); ! heartbeat = new RrdLong(dsDef.getHeartbeat(), this); ! minValue = new RrdDouble(dsDef.getMinValue(), this); ! maxValue = new RrdDouble(dsDef.getMaxValue(), this); ! lastValue = new RrdDouble(Double.NaN, this); ! accumValue = new RrdDouble(0.0, this); ! Header header = parentDb.getHeader(); ! nanSeconds = new RrdLong(header.getLastUpdateTime() % header.getStep(), this); ! } ! ! Datasource(RrdDb parentDb) throws IOException { ! this.parentDb = parentDb; ! dsName = new RrdString(this); ! dsType = new RrdString(this); ! heartbeat = new RrdLong(this); ! minValue = new RrdDouble(this); ! maxValue = new RrdDouble(this); ! lastValue = new RrdDouble(this); ! accumValue = new RrdDouble(this); ! nanSeconds = new RrdLong(this); ! } ! ! Datasource(RrdDb parentDb, XmlReader reader, int dsIndex) throws IOException, RrdException { ! this.parentDb = parentDb; ! dsName = new RrdString(reader.getDsName(dsIndex), this); ! dsType = new RrdString(reader.getDsType(dsIndex), this); ! heartbeat = new RrdLong(reader.getHeartbeat(dsIndex), this); ! minValue = new RrdDouble(reader.getMinValue(dsIndex), this); ! maxValue = new RrdDouble(reader.getMaxValue(dsIndex), this); ! lastValue = new RrdDouble(reader.getLastValue(dsIndex), this); ! accumValue = new RrdDouble(reader.getAccumValue(dsIndex), this); ! nanSeconds = new RrdLong(reader.getNanSeconds(dsIndex), this); ! } ! ! String dump() throws IOException { ! return "== DATASOURCE ==\n" + ! "DS:" + dsName.get() + ":" + dsType.get() + ":" + ! heartbeat.get() + ":" + minValue.get() + ":" + ! maxValue.get() + "\nlastValue:" + lastValue.get() + ! " nanSeconds:" + nanSeconds.get() + ! " accumValue:" + accumValue.get() + "\n"; ! } ! ! /** ! * Returns the underlying RrdFile object. ! * @return Underlying RrdFile object. ! */ ! public RrdFile getRrdFile() { ! return parentDb.getRrdFile(); ! } ! ! /** ! * Returns datasource name. ! * @return Datasource name ! * @throws IOException Thrown in case of IO related error ! */ ! public String getDsName() throws IOException { ! return dsName.get(); ! } ! ! /** ! * Returns datasource type (GAUGE, COUNTER, DERIVE, ABSOLUTE). ! * ! * @return Datasource type. ! * @throws IOException Thrown in case of IO related error ! */ ! public String getDsType() throws IOException { ! return dsType.get(); ! } ! ! /** ! * Returns datasource heartbeat ! * ! * @return Datasource heartbeat ! * @throws IOException Thrown in case of IO related error ! */ ! public long getHeartbeat() throws IOException { ! return heartbeat.get(); ! } ! ! /** ! * Returns mimimal allowed value of the datasource. ! * ! * @return Minimal value allowed. ! * @throws IOException Thrown in case of IO related error ! */ ! public double getMinValue() throws IOException { ! return minValue.get(); ! } ! ! /** ! * Returns maximal allowed value of the datasource. ! * ! * @return Maximal value allowed. ! * @throws IOException Thrown in case of IO related error ! */ ! public double getMaxValue() throws IOException { ! return maxValue.get(); ! } ! ! /** ! * Returns last known value of the datasource. ! * ! * @return Last datasource value. ! * @throws IOException Thrown in case of IO related error ! */ ! public double getLastValue() throws IOException { ! return lastValue.get(); ! } ! ! /** ! * Returns value this datasource accumulated so far. ! * ! * @return Accumulated datasource value. ! * @throws IOException Thrown in case of IO related error ! */ ! public double getAccumValue() throws IOException { ! return accumValue.get(); ! } ! ! /** ! * Returns the number of accumulated NaN seconds. ! * ! * @return Accumulated NaN seconds. ! * @throws IOException Thrown in case of IO related error ! */ ! public long getNanSeconds() throws IOException { ! return nanSeconds.get(); ! } ! ! void process(long newTime, double newValue) throws IOException, RrdException { ! Header header = parentDb.getHeader(); ! long step = header.getStep(); ! long oldTime = header.getLastUpdateTime(); ! long startTime = Util.normalize(oldTime, step); ! long endTime = startTime + step; ! double oldValue = lastValue.get(); ! double updateValue = calculateUpdateValue(oldTime, oldValue, newTime, newValue); ! if(newTime < endTime) { ! accumulate(oldTime, newTime, updateValue); ! } ! else { ! // should store something ! long boundaryTime = Util.normalize(newTime, step); ! accumulate(oldTime, boundaryTime, updateValue); ! double value = calculateTotal(startTime, boundaryTime); ! // how many updates? ! long numSteps= (boundaryTime - endTime) / step + 1L; ! // ACTION! ! parentDb.archive(this, value, numSteps); ! // cleanup ! nanSeconds.set(0); ! accumValue.set(0.0); ! accumulate(boundaryTime, newTime, updateValue); ! } ! } ! ! private double calculateUpdateValue(long oldTime, double oldValue, ! long newTime, double newValue) throws IOException { ! double updateValue = Double.NaN; ! if(newTime - oldTime <= heartbeat.get()) { ! String type = dsType.get(); ! if(type.equals("GAUGE")) { ! updateValue = newValue; ! } ! else if(type.equals("ABSOLUTE")) { ! if(!Double.isNaN(newValue)) { ! updateValue = newValue / (newTime - oldTime); ! } ! } ! else if(type.equals("DERIVE")) { ! if(!Double.isNaN(newValue) && !Double.isNaN(oldValue)) { ! updateValue = (newValue - oldValue) / (newTime - oldTime); ! } ! } ! else if(type.equals("COUNTER")) { ! if(!Double.isNaN(newValue) && !Double.isNaN(oldValue)) { ! double diff = newValue - oldValue; ! double max32bit = Math.pow(2, 32); ! double max64bit = Math.pow(2, 64); ! if(diff < 0) { ! diff += max32bit; ! } ! if(diff < 0) { ! diff += max64bit - max32bit; ! } ! if(diff >= 0) { ! updateValue = diff / (newTime - oldTime); ! } ! } ! } ! if(!Double.isNaN(updateValue)) { ! double minVal = minValue.get(); ! double maxVal = maxValue.get(); ! if(!Double.isNaN(minVal) && updateValue < minVal) { ! updateValue = Double.NaN; ! } ! if(!Double.isNaN(maxVal) && updateValue > maxVal) { ! updateValue = Double.NaN; ! } ! } ! } ! lastValue.set(newValue); ! return updateValue; ! } ! ! private void accumulate(long oldTime, long newTime, double updateValue) throws IOException { ! if(Double.isNaN(updateValue)) { ! nanSeconds.set(nanSeconds.get() + (newTime - oldTime)); ! } ! else { ! accumValue.set(accumValue.get() + updateValue * (newTime - oldTime)); ! } ! } ! ! private double calculateTotal(long startTime, long boundaryTime) { ! double totalValue = Double.NaN; ! long validSeconds = boundaryTime - startTime - nanSeconds.get(); ! if(nanSeconds.get() <= heartbeat.get() && validSeconds > 0) { ! totalValue = accumValue.get() / validSeconds; ! } ! return totalValue; ! } ! ! void appendXml(XmlWriter writer) throws IOException { ! writer.startTag("ds"); ! writer.writeTag("name", dsName.get()); ! writer.writeTag("type", dsType.get()); ! writer.writeTag("minimal_heartbeat", heartbeat.get()); ! writer.writeTag("min", minValue.get()); ! writer.writeTag("max", maxValue.get()); ! writer.writeComment("PDP Status"); ! writer.writeTag("last_ds", lastValue.get(), "UNKN"); ! writer.writeTag("value", accumValue.get()); ! writer.writeTag("unknown_sec", nanSeconds.get()); ! writer.closeTag(); // ds ! } ! ! /** ! * Copies object's internal state to another Datasource object. ! * @param other New Datasource object to copy state to ! * @throws IOException Thrown in case of I/O error ! * @throws RrdException Thrown if supplied argument is not a Datasource object ! */ ! public void copyStateTo(RrdUpdater other) throws IOException, RrdException { ! if(!(other instanceof Datasource)) { ! throw new RrdException( ! "Cannot copy Datasource object to " + other.getClass().getName()); ! } ! Datasource datasource = (Datasource) other; ! if(!datasource.dsName.get().equals(dsName.get())) { ! throw new RrdException("Incomaptible datasource names"); ! } ! if(!datasource.dsType.get().equals(dsType.get())) { ! throw new RrdException("Incomaptible datasource types"); ! } ! datasource.lastValue.set(lastValue.get()); ! datasource.nanSeconds.set(nanSeconds.get()); ! datasource.accumValue.set(accumValue.get()); ! } ! ! } --- 1,415 ---- ! /* ============================================================ ! * JRobin : Pure java implementation of RRDTool's functionality ! * ============================================================ ! * ! * Project Info: http://www.jrobin.org ! * Project Lead: Sasa Markovic (sa...@jr...); ! * ! * (C) Copyright 2003, by Sasa Markovic. ! * ! * Developers: Sasa Markovic (sa...@jr...) ! * Arne Vandamme (cob...@jr...) ! * ! * This library 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 library 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 ! * library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, ! * Boston, MA 02111-1307, USA. ! */ ! ! package org.jrobin.core; ! ! import java.io.IOException; ! ! /** ! * Class to represent single datasource within RRD file. Each datasource object holds the ! * following information: datasource definition (once set, never changed) and ! * datasource state variables (changed whenever RRD file gets updated).<p> ! * ! * Normally, you don't need to manipluate Datasource objects directly, it's up to ! * JRobin framework to do it for you. ! * ! * @author <a href="mailto:sa...@jr...">Sasa Markovic</a> ! */ ! public class Datasource implements RrdUpdater { ! private RrdDb parentDb; ! // definition ! private RrdString dsName, dsType; ! private RrdLong heartbeat; ! private RrdDouble minValue, maxValue; ! // state variables ! private RrdDouble lastValue; ! private RrdLong nanSeconds; ! private RrdDouble accumValue; ! ! Datasource(RrdDb parentDb, DsDef dsDef) throws IOException { ! this.parentDb = parentDb; ! dsName = new RrdString(dsDef.getDsName(), this); ! dsType = new RrdString(dsDef.getDsType(), this); ! heartbeat = new RrdLong(dsDef.getHeartbeat(), this); ! minValue = new RrdDouble(dsDef.getMinValue(), this); ! maxValue = new RrdDouble(dsDef.getMaxValue(), this); ! lastValue = new RrdDouble(Double.NaN, this); ! accumValue = new RrdDouble(0.0, this); ! Header header = parentDb.getHeader(); ! nanSeconds = new RrdLong(header.getLastUpdateTime() % header.getStep(), this); ! } ! ! Datasource(RrdDb parentDb) throws IOException { ! this.parentDb = parentDb; ! dsName = new RrdString(this); ! dsType = new RrdString(this); ! heartbeat = new RrdLong(this); ! minValue = new RrdDouble(this); ! maxValue = new RrdDouble(this); ! lastValue = new RrdDouble(this); ! accumValue = new RrdDouble(this); ! nanSeconds = new RrdLong(this); ! } ! ! Datasource(RrdDb parentDb, XmlReader reader, int dsIndex) throws IOException, RrdException { ! this.parentDb = parentDb; ! dsName = new RrdString(reader.getDsName(dsIndex), this); ! dsType = new RrdString(reader.getDsType(dsIndex), this); ! heartbeat = new RrdLong(reader.getHeartbeat(dsIndex), this); ! minValue = new RrdDouble(reader.getMinValue(dsIndex), this); ! maxValue = new RrdDouble(reader.getMaxValue(dsIndex), this); ! lastValue = new RrdDouble(reader.getLastValue(dsIndex), this); ! accumValue = new RrdDouble(reader.getAccumValue(dsIndex), this); ! nanSeconds = new RrdLong(reader.getNanSeconds(dsIndex), this); ! } ! ! String dump() { ! return "== DATASOURCE ==\n" + ! "DS:" + dsName.get() + ":" + dsType.get() + ":" + ! heartbeat.get() + ":" + minValue.get() + ":" + ! maxValue.get() + "\nlastValue:" + lastValue.get() + ! " nanSeconds:" + nanSeconds.get() + ! " accumValue:" + accumValue.get() + "\n"; ! } ! ! /** ! * Returns the underlying RrdFile object. ! * @return Underlying RrdFile object. ! */ ! public RrdFile getRrdFile() { ! return parentDb.getRrdFile(); ! } ! ! /** ! * Returns datasource name. ! * @return Datasource name ! */ ! public String getDsName() { ! return dsName.get(); ! } ! ! /** ! * Returns datasource type (GAUGE, COUNTER, DERIVE, ABSOLUTE). ! * ! * @return Datasource type. ! */ ! public String getDsType() { ! return dsType.get(); ! } ! ! /** ! * Returns datasource heartbeat ! * ! * @return Datasource heartbeat ! */ ! public long getHeartbeat() { ! return heartbeat.get(); ! } ! ! /** ! * Returns mimimal allowed value of the datasource. ! * ! * @return Minimal value allowed. ! */ ! public double getMinValue() { ! return minValue.get(); ! } ! ! /** ! * Returns maximal allowed value of the datasource. ! * ! * @return Maximal value allowed. ! */ ! public double getMaxValue() { ! return maxValue.get(); ! } ! ! /** ! * Returns last known value of the datasource. ! * ! * @return Last datasource value. ! */ ! public double getLastValue() { ! return lastValue.get(); ! } ! ! /** ! * Returns value this datasource accumulated so far. ! * ! * @return Accumulated datasource value. ! */ ! public double getAccumValue() { ! return accumValue.get(); ! } ! ! /** ! * Returns the number of accumulated NaN seconds. ! * ! * @return Accumulated NaN seconds. ! */ ! public long getNanSeconds() { ! return nanSeconds.get(); ! } ! ! void process(long newTime, double newValue) throws IOException, RrdException { ! Header header = parentDb.getHeader(); ! long step = header.getStep(); ! long oldTime = header.getLastUpdateTime(); ! long startTime = Util.normalize(oldTime, step); ! long endTime = startTime + step; ! double oldValue = lastValue.get(); ! double updateValue = calculateUpdateValue(oldTime, oldValue, newTime, newValue); ! if(newTime < endTime) { ! accumulate(oldTime, newTime, updateValue); ! } ! else { ! // should store something ! long boundaryTime = Util.normalize(newTime, step); ! accumulate(oldTime, boundaryTime, updateValue); ! double value = calculateTotal(startTime, boundaryTime); ! // how many updates? ! long numSteps= (boundaryTime - endTime) / step + 1L; ! // ACTION! ! parentDb.archive(this, value, numSteps); ! // cleanup ! nanSeconds.set(0); ! accumValue.set(0.0); ! accumulate(boundaryTime, newTime, updateValue); ! } ! } ! ! private double calculateUpdateValue(long oldTime, double oldValue, ! long newTime, double newValue) throws IOException { ! double updateValue = Double.NaN; ! if(newTime - oldTime <= heartbeat.get()) { ! String type = dsType.get(); ! if(type.equals("GAUGE")) { ! updateValue = newValue; ! } ! else if(type.equals("ABSOLUTE")) { ! if(!Double.isNaN(newValue)) { ! updateValue = newValue / (newTime - oldTime); ! } ! } ! else if(type.equals("DERIVE")) { ! if(!Double.isNaN(newValue) && !Double.isNaN(oldValue)) { ! updateValue = (newValue - oldValue) / (newTime - oldTime); ! } ! } ! else if(type.equals("COUNTER")) { ! if(!Double.isNaN(newValue) && !Double.isNaN(oldValue)) { ! double diff = newValue - oldValue; ! double max32bit = Math.pow(2, 32); ! double max64bit = Math.pow(2, 64); ! if(diff < 0) { ! diff += max32bit; ! } ! if(diff < 0) { ! diff += max64bit - max32bit; ! } ! if(diff >= 0) { ! updateValue = diff / (newTime - oldTime); ! } ! } ! } ! if(!Double.isNaN(updateValue)) { ! double minVal = minValue.get(); ! double maxVal = maxValue.get(); ! if(!Double.isNaN(minVal) && updateValue < minVal) { ! updateValue = Double.NaN; ! } ! if(!Double.isNaN(maxVal) && updateValue > maxVal) { ! updateValue = Double.NaN; ! } ! } ! } ! lastValue.set(newValue); ! return updateValue; ! } ! ! private void accumulate(long oldTime, long newTime, double updateValue) throws IOException { ! if(Double.isNaN(updateValue)) { ! nanSeconds.set(nanSeconds.get() + (newTime - oldTime)); ! } ! else { ! accumValue.set(accumValue.get() + updateValue * (newTime - oldTime)); ! } ! } ! ! private double calculateTotal(long startTime, long boundaryTime) { ! double totalValue = Double.NaN; ! long validSeconds = boundaryTime - startTime - nanSeconds.get(); ! if(nanSeconds.get() <= heartbeat.get() && validSeconds > 0) { ! totalValue = accumValue.get() / validSeconds; ! } ! return totalValue; ! } ! ! void appendXml(XmlWriter writer) throws IOException { ! writer.startTag("ds"); ! writer.writeTag("name", dsName.get()); ! writer.writeTag("type", dsType.get()); ! writer.writeTag("minimal_heartbeat", heartbeat.get()); ! writer.writeTag("min", minValue.get()); ! writer.writeTag("max", maxValue.get()); ! writer.writeComment("PDP Status"); ! writer.writeTag("last_ds", lastValue.get(), "UNKN"); ! writer.writeTag("value", accumValue.get()); ! writer.writeTag("unknown_sec", nanSeconds.get()); ! writer.closeTag(); // ds ! } ! ! /** ! * Copies object's internal state to another Datasource object. ! * @param other New Datasource object to copy state to ! * @throws IOException Thrown in case of I/O error ! * @throws RrdException Thrown if supplied argument is not a Datasource object ! */ ! public void copyStateTo(RrdUpdater other) throws IOException, RrdException { ! if(!(other instanceof Datasource)) { ! throw new RrdException( ! "Cannot copy Datasource object to " + other.getClass().getName()); ! } ! Datasource datasource = (Datasource) other; ! if(!datasource.dsName.get().equals(dsName.get())) { ! throw new RrdException("Incomaptible datasource names"); ! } ! if(!datasource.dsType.get().equals(dsType.get())) { ! throw new RrdException("Incomaptible datasource types"); ! } ! datasource.lastValue.set(lastValue.get()); ! datasource.nanSeconds.set(nanSeconds.get()); ! datasource.accumValue.set(accumValue.get()); ! } ! ! /** ! * Returns index of this Datasource obj... [truncated message content] |