All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jrobin.core.RrdToolkit Maven / Gradle / Ivy

Go to download

JRobin is a 100% pure Java alternative to RRDTool, with about exactly the same specifications. If you provide the same data to RRDTool and JRobin, you will get exactly the same results and graphs. All standard RRDTool operations are supported.

There is a newer version: 1.7.1
Show newest version
/*******************************************************************************
 * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor.
 * Copyright (c) 2011 The OpenNMS Group, Inc.
 *
 * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *******************************************************************************/

package org.jrobin.core;

import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.LinkedList;
import java.util.Arrays;

/**
 * Class used to perform various complex operations on RRD files. Use an instance of the
 * RrdToolkit class to:
 * 

*

    *
  • add datasource to a RRD file. *
  • add archive to a RRD file. *
  • remove datasource from a RRD file. *
  • remove archive from a RRD file. *
* All these operations can be performed on the copy of the original RRD file, or on the * original file itself (with possible backup file creation). *

* IMPORTANT: NEVER use methods found in this class on 'live' RRD files * (files which are currently in use). */ public class RrdToolkit { /** * Creates a new RRD file with one more datasource in it. RRD file is created based on the * existing one (the original RRD file is not modified at all). All data from * the original RRD file is copied to the new one. * * @param sourcePath path to a RRD file to import data from (will not be modified) * @param destPath path to a new RRD file (will be created) * @param newDatasource Datasource definition to be added to the new RRD file * @throws IOException Thrown in case of I/O error * @throws RrdException Thrown in case of JRobin specific error */ public static void addDatasource(String sourcePath, String destPath, DsDef newDatasource) throws IOException, RrdException { if (Util.sameFilePath(sourcePath, destPath)) { throw new RrdException("Source and destination paths are the same"); } RrdDb rrdSource = new RrdDb(sourcePath); try { RrdDef rrdDef = rrdSource.getRrdDef(); rrdDef.setPath(destPath); rrdDef.addDatasource(newDatasource); RrdDb rrdDest = new RrdDb(rrdDef); try { rrdSource.copyStateTo(rrdDest); } finally { rrdDest.close(); } } finally { rrdSource.close(); } } /** *

Adds one more datasource to a RRD file.

*

WARNING: This method is potentialy dangerous! It will modify your RRD file. * It is highly recommended to preserve the original RRD file (saveBackup * should be set to true). The backup file will be created in the same * directory as the original one with .bak extension added to the * original name.

*

Before applying this method, be sure that the specified RRD file is not in use * (not open)

* * @param sourcePath path to a RRD file to add datasource to. * @param newDatasource Datasource definition to be added to the RRD file * @param saveBackup true, if backup of the original file should be created; * false, otherwise * @throws IOException Thrown in case of I/O error * @throws RrdException Thrown in case of JRobin specific error */ public static void addDatasource(String sourcePath, DsDef newDatasource, boolean saveBackup) throws IOException, RrdException { String destPath = Util.getTmpFilename(); addDatasource(sourcePath, destPath, newDatasource); copyFile(destPath, sourcePath, saveBackup); } /** * Creates a new RRD file with one datasource removed. RRD file is created based on the * existing one (the original RRD file is not modified at all). All remaining data from * the original RRD file is copied to the new one. * * @param sourcePath path to a RRD file to import data from (will not be modified) * @param destPath path to a new RRD file (will be created) * @param dsName Name of the Datasource to be removed from the new RRD file * @throws IOException Thrown in case of I/O error * @throws RrdException Thrown in case of JRobin specific error */ public static void removeDatasource(String sourcePath, String destPath, String dsName) throws IOException, RrdException { if (Util.sameFilePath(sourcePath, destPath)) { throw new RrdException("Source and destination paths are the same"); } RrdDb rrdSource = new RrdDb(sourcePath); try { RrdDef rrdDef = rrdSource.getRrdDef(); rrdDef.setPath(destPath); rrdDef.removeDatasource(dsName); RrdDb rrdDest = new RrdDb(rrdDef); try { rrdSource.copyStateTo(rrdDest); } finally { rrdDest.close(); } } finally { rrdSource.close(); } } /** *

Removes single datasource from a RRD file.

*

WARNING: This method is potentialy dangerous! It will modify your RRD file. * It is highly recommended to preserve the original RRD file (saveBackup * should be set to true). The backup file will be created in the same * directory as the original one with .bak extension added to the * original name.

*

Before applying this method, be sure that the specified RRD file is not in use * (not open)

* * @param sourcePath path to a RRD file to remove datasource from. * @param dsName Name of the Datasource to be removed from the RRD file * @param saveBackup true, if backup of the original file should be created; * false, otherwise * @throws IOException Thrown in case of I/O error * @throws RrdException Thrown in case of JRobin specific error */ public static void removeDatasource(String sourcePath, String dsName, boolean saveBackup) throws IOException, RrdException { String destPath = Util.getTmpFilename(); removeDatasource(sourcePath, destPath, dsName); copyFile(destPath, sourcePath, saveBackup); } /** * Renames single datasource in the given RRD file. * * @param sourcePath Path to a RRD file * @param oldDsName Old datasource name * @param newDsName New datasource name * @throws IOException Thrown in case of I/O error * @throws RrdException Thrown in case of JRobin specific error (invalid path or datasource names, * for example) */ public static void renameDatasource(String sourcePath, String oldDsName, String newDsName) throws IOException, RrdException { RrdDb rrd = new RrdDb(sourcePath); try { if (rrd.containsDs(oldDsName)) { Datasource datasource = rrd.getDatasource(oldDsName); datasource.setDsName(newDsName); } else { throw new RrdException("Could not find datasource [" + oldDsName + "] in file " + sourcePath); } } finally { rrd.close(); } } /** * Updates single or all datasource names in the specified RRD file * by appending '!' (if not already present). Datasources with names ending with '!' * will never store NaNs in RRA archives (zero value will be used instead). Might be useful * from time to time * * @param sourcePath Path to a RRD file * @param dsName Datasource name or null if you want to rename all datasources * @return Number of datasources successfully renamed * @throws IOException Thrown in case of I/O error * @throws RrdException Thrown in case of JRobin specific error (invalid path or datasource name, * for example) */ public static int forceZerosForNans(String sourcePath, String dsName) throws IOException, RrdException { RrdDb rrd = new RrdDb(sourcePath); try { Datasource[] datasources; if (dsName == null) { datasources = rrd.getDatasources(); } else { if (rrd.containsDs(dsName)) { datasources = new Datasource[] {rrd.getDatasource(dsName)}; } else { throw new RrdException("Could not find datasource [" + dsName + "] in file " + sourcePath); } } int count = 0; for (Datasource datasource : datasources) { String currentDsName = datasource.getDsName(); if (!currentDsName.endsWith(DsDef.FORCE_ZEROS_FOR_NANS_SUFFIX)) { datasource.setDsName(currentDsName + DsDef.FORCE_ZEROS_FOR_NANS_SUFFIX); count++; } } return count; } finally { rrd.close(); } } /** * Creates a new RRD file with one more archive in it. RRD file is created based on the * existing one (the original RRD file is not modified at all). All data from * the original RRD file is copied to the new one. * * @param sourcePath path to a RRD file to import data from (will not be modified) * @param destPath path to a new RRD file (will be created) * @param newArchive Archive definition to be added to the new RRD file * @throws IOException Thrown in case of I/O error * @throws RrdException Thrown in case of JRobin specific error */ public static void addArchive(String sourcePath, String destPath, ArcDef newArchive) throws IOException, RrdException { if (Util.sameFilePath(sourcePath, destPath)) { throw new RrdException("Source and destination paths are the same"); } RrdDb rrdSource = new RrdDb(sourcePath); try { RrdDef rrdDef = rrdSource.getRrdDef(); rrdDef.setPath(destPath); rrdDef.addArchive(newArchive); RrdDb rrdDest = new RrdDb(rrdDef); try { rrdSource.copyStateTo(rrdDest); } finally { rrdDest.close(); } } finally { rrdSource.close(); } } /** *

Adds one more archive to a RRD file.

*

WARNING: This method is potentialy dangerous! It will modify your RRD file. * It is highly recommended to preserve the original RRD file (saveBackup * should be set to true). The backup file will be created in the same * directory as the original one with .bak extension added to the * original name.

*

Before applying this method, be sure that the specified RRD file is not in use * (not open)

* * @param sourcePath path to a RRD file to add datasource to. * @param newArchive Archive definition to be added to the RRD file * @param saveBackup true, if backup of the original file should be created; * false, otherwise * @throws IOException Thrown in case of I/O error * @throws RrdException Thrown in case of JRobin specific error */ public static void addArchive(String sourcePath, ArcDef newArchive, boolean saveBackup) throws IOException, RrdException { String destPath = Util.getTmpFilename(); addArchive(sourcePath, destPath, newArchive); copyFile(destPath, sourcePath, saveBackup); } /** * Creates a new RRD file with one archive removed. RRD file is created based on the * existing one (the original RRD file is not modified at all). All relevant data from * the original RRD file is copied to the new one. * * @param sourcePath path to a RRD file to import data from (will not be modified) * @param destPath path to a new RRD file (will be created) * @param consolFun Consolidation function of Archive which should be removed * @param steps Number of steps for Archive which should be removed * @throws IOException Thrown in case of I/O error * @throws RrdException Thrown in case of JRobin specific error */ public static void removeArchive(String sourcePath, String destPath, String consolFun, int steps) throws IOException, RrdException { if (Util.sameFilePath(sourcePath, destPath)) { throw new RrdException("Source and destination paths are the same"); } RrdDb rrdSource = new RrdDb(sourcePath); try { RrdDef rrdDef = rrdSource.getRrdDef(); rrdDef.setPath(destPath); rrdDef.removeArchive(consolFun, steps); RrdDb rrdDest = new RrdDb(rrdDef); try { rrdSource.copyStateTo(rrdDest); } finally { rrdDest.close(); } } finally { rrdSource.close(); } } /** *

Removes one archive from a RRD file.

*

WARNING: This method is potentialy dangerous! It will modify your RRD file. * It is highly recommended to preserve the original RRD file (saveBackup * should be set to true). The backup file will be created in the same * directory as the original one with .bak extension added to the * original name.

*

Before applying this method, be sure that the specified RRD file is not in use * (not open)

* * @param sourcePath path to a RRD file to add datasource to. * @param consolFun Consolidation function of Archive which should be removed * @param steps Number of steps for Archive which should be removed * @param saveBackup true, if backup of the original file should be created; * false, otherwise * @throws IOException Thrown in case of I/O error * @throws RrdException Thrown in case of JRobin specific error */ public static void removeArchive(String sourcePath, String consolFun, int steps, boolean saveBackup) throws IOException, RrdException { String destPath = Util.getTmpFilename(); removeArchive(sourcePath, destPath, consolFun, steps); copyFile(destPath, sourcePath, saveBackup); } private static void copyFile(String sourcePath, String destPath, boolean saveBackup) throws IOException { File source = new File(sourcePath); File dest = new File(destPath); if (saveBackup) { String backupPath = getBackupPath(destPath); File backup = new File(backupPath); deleteFile(backup); if (!dest.renameTo(backup)) { throw new IOException("Could not create backup file " + backupPath); } } deleteFile(dest); if (!source.renameTo(dest)) { throw new IOException("Could not create file " + destPath + " from " + sourcePath); } } private static String getBackupPath(String destPath) { StringBuffer sb = new StringBuffer(destPath); do { sb.append(".bak"); } while (Util.fileExists(sb.toString())); return sb.toString(); } /** * Sets datasource heartbeat to a new value. * * @param sourcePath Path to exisiting RRD file (will be updated) * @param datasourceName Name of the datasource in the specified RRD file * @param newHeartbeat New datasource heartbeat * @throws RrdException Thrown in case of JRobin specific error * @throws IOException Thrown in case of I/O error */ public static void setDsHeartbeat(String sourcePath, String datasourceName, long newHeartbeat) throws RrdException, IOException { RrdDb rrd = new RrdDb(sourcePath); try { Datasource ds = rrd.getDatasource(datasourceName); ds.setHeartbeat(newHeartbeat); } finally { rrd.close(); } } /** * Sets datasource heartbeat to a new value. * * @param sourcePath Path to exisiting RRD file (will be updated) * @param dsIndex Index of the datasource in the specified RRD file * @param newHeartbeat New datasource heartbeat * @throws RrdException Thrown in case of JRobin specific error * @throws IOException Thrown in case of I/O error */ public static void setDsHeartbeat(String sourcePath, int dsIndex, long newHeartbeat) throws RrdException, IOException { RrdDb rrd = new RrdDb(sourcePath); try { Datasource ds = rrd.getDatasource(dsIndex); ds.setHeartbeat(newHeartbeat); } finally { rrd.close(); } } /** * Sets datasource min value to a new value * * @param sourcePath Path to exisiting RRD file (will be updated) * @param datasourceName Name of the datasource in the specified RRD file * @param newMinValue New min value for the datasource * @param filterArchivedValues set to true if archived values less than * newMinValue should be set to NaN; set to false, otherwise. * @throws RrdException Thrown in case of JRobin specific error * @throws IOException Thrown in case of I/O error */ public static void setDsMinValue(String sourcePath, String datasourceName, double newMinValue, boolean filterArchivedValues) throws RrdException, IOException { RrdDb rrd = new RrdDb(sourcePath); try { Datasource ds = rrd.getDatasource(datasourceName); ds.setMinValue(newMinValue, filterArchivedValues); } finally { rrd.close(); } } /** * Sets datasource max value to a new value. * * @param sourcePath Path to exisiting RRD file (will be updated) * @param datasourceName Name of the datasource in the specified RRD file * @param newMaxValue New max value for the datasource * @param filterArchivedValues set to true if archived values greater than * newMaxValue should be set to NaN; set to false, otherwise. * @throws RrdException Thrown in case of JRobin specific error * @throws IOException Thrown in case of I/O error */ public static void setDsMaxValue(String sourcePath, String datasourceName, double newMaxValue, boolean filterArchivedValues) throws RrdException, IOException { RrdDb rrd = new RrdDb(sourcePath); try { Datasource ds = rrd.getDatasource(datasourceName); ds.setMaxValue(newMaxValue, filterArchivedValues); } finally { rrd.close(); } } /** * Updates valid value range for the given datasource. * * @param sourcePath Path to exisiting RRD file (will be updated) * @param datasourceName Name of the datasource in the specified RRD file * @param newMinValue New min value for the datasource * @param newMaxValue New max value for the datasource * @param filterArchivedValues set to true if archived values outside * of the specified min/max range should be replaced with NaNs. * @throws RrdException Thrown in case of JRobin specific error * @throws IOException Thrown in case of I/O error */ public static void setDsMinMaxValue(String sourcePath, String datasourceName, double newMinValue, double newMaxValue, boolean filterArchivedValues) throws RrdException, IOException { RrdDb rrd = new RrdDb(sourcePath); try { Datasource ds = rrd.getDatasource(datasourceName); ds.setMinMaxValue(newMinValue, newMaxValue, filterArchivedValues); } finally { rrd.close(); } } /** * Sets single archive's X-files factor to a new value. * * @param sourcePath Path to existing RRD file (will be updated) * @param consolFun Consolidation function of the target archive * @param steps Number of sptes of the target archive * @param newXff New X-files factor for the target archive * @throws RrdException Thrown in case of JRobin specific error * @throws IOException Thrown in case of I/O error */ public static void setArcXff(String sourcePath, String consolFun, int steps, double newXff) throws RrdException, IOException { RrdDb rrd = new RrdDb(sourcePath); try { Archive arc = rrd.getArchive(consolFun, steps); arc.setXff(newXff); } finally { rrd.close(); } } /** * Creates new RRD file based on the existing one, but with a different * size (number of rows) for a single archive. The archive to be resized * is identified by its consolidation function and the number of steps. * * @param sourcePath Path to the source RRD file (will not be modified) * @param destPath Path to the new RRD file (will be created) * @param consolFun Consolidation function of the archive to be resized * @param numSteps Number of steps of the archive to be resized * @param newRows New archive size (number of archive rows) * @throws IOException Thrown in case of I/O error * @throws RrdException Thrown in case of JRobin specific error */ public static void resizeArchive(String sourcePath, String destPath, String consolFun, int numSteps, int newRows) throws IOException, RrdException { if (Util.sameFilePath(sourcePath, destPath)) { throw new RrdException("Source and destination paths are the same"); } if (newRows < 2) { throw new RrdException("New arcihve size must be at least 2"); } RrdDb rrdSource = new RrdDb(sourcePath); try { RrdDef rrdDef = rrdSource.getRrdDef(); ArcDef arcDef = rrdDef.findArchive(consolFun, numSteps); if (arcDef.getRows() != newRows) { arcDef.setRows(newRows); rrdDef.setPath(destPath); RrdDb rrdDest = new RrdDb(rrdDef); try { rrdSource.copyStateTo(rrdDest); } finally { rrdDest.close(); } } } finally { rrdSource.close(); } } /** * Modifies existing RRD file, by resizing its chosen archive. The archive to be resized * is identified by its consolidation function and the number of steps. * * @param sourcePath Path to the RRD file (will be modified) * @param consolFun Consolidation function of the archive to be resized * @param numSteps Number of steps of the archive to be resized * @param newRows New archive size (number of archive rows) * @param saveBackup true, if backup of the original file should be created; * false, otherwise * @throws IOException Thrown in case of I/O error * @throws RrdException Thrown in case of JRobin specific error */ public static void resizeArchive(String sourcePath, String consolFun, int numSteps, int newRows, boolean saveBackup) throws IOException, RrdException { String destPath = Util.getTmpFilename(); resizeArchive(sourcePath, destPath, consolFun, numSteps, newRows); copyFile(destPath, sourcePath, saveBackup); } private static void deleteFile(File file) throws IOException { if (file.exists() && !file.delete()) { throw new IOException("Could not delete file: " + file.getCanonicalPath()); } } /** * Splits single RRD file with several datasources into a number of smaller RRD files * with a single datasource in it. All archived values are preserved. If * you have a RRD file named 'traffic.rrd' with two datasources, 'in' and 'out', this * method will create two files (with a single datasource, in the same directory) * named 'in-traffic.rrd' and 'out-traffic.rrd'. * * @param sourcePath Path to a RRD file with multiple datasources defined * @throws IOException Thrown in case of I/O error * @throws RrdException Thrown in case of JRobin specific error */ public static void split(String sourcePath) throws IOException, RrdException { RrdDb rrdSource = new RrdDb(sourcePath); try { String[] dsNames = rrdSource.getDsNames(); for (String dsName : dsNames) { RrdDef rrdDef = rrdSource.getRrdDef(); rrdDef.setPath(createSplitPath(dsName, sourcePath)); rrdDef.saveSingleDatasource(dsName); RrdDb rrdDest = new RrdDb(rrdDef); try { rrdSource.copyStateTo(rrdDest); } finally { rrdDest.close(); } } } finally { rrdSource.close(); } } /** * Returns list of canonical file names with the specified extension in the given directory. This * method is not RRD related, but might come handy to create a quick list of all RRD files * in the given directory. * * @param directory Source directory * @param extension File extension (like ".rrd", ".jrb", ".rrd.jrb") * @param resursive true if all subdirectories should be traversed for the same extension, false otherwise * @return Array of sorted canonical file names with the given extension * @throws IOException Thrown in case of I/O error */ public static String[] getCanonicalPaths(String directory, final String extension, boolean resursive) throws IOException { File baseDir = new File(directory); if (!baseDir.isDirectory()) { throw new IOException("Not a directory: " + directory); } List fileList = new LinkedList(); traverseDirectory(new File(directory), extension, resursive, fileList); String[] result = fileList.toArray(new String[fileList.size()]); Arrays.sort(result); return result; } private static void traverseDirectory(File directory, String extension, boolean recursive, List list) throws IOException { File[] files = directory.listFiles(); for (File file : files) { if (file.isDirectory() && recursive) { // traverse subdirectories only if recursive flag is specified traverseDirectory(file, extension, recursive, list); } else if (file.isFile() && file.getName().endsWith(extension)) { list.add(file.getCanonicalPath()); } } } private static String createSplitPath(String dsName, String sourcePath) { File file = new File(sourcePath); String newName = dsName + "-" + file.getName(); String path = file.getAbsolutePath(); String parentDir = path.substring(0, 1 + path.lastIndexOf(Util.getFileSeparator())); return parentDir + newName; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy