<commit_before>/*
 * Copyright 2008-2010 by <NAME>
 *
 *     This file is part of Java Melody.
 *
 * Java Melody 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 3 of the License, or
 * (at your option) any later version.
 *
 * Java Melody 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 Java Melody.  If not, see <http://www.gnu.org/licenses/>.
 */
package net.bull.javamelody;

import java.awt.Color;
import java.awt.GradientPaint;
import java.awt.Paint;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Calendar;
import java.util.Timer;
import java.util.TimerTask;

import org.jrobin.core.RrdDb;
import org.jrobin.core.RrdDbPool;
import org.jrobin.core.RrdDef;
import org.jrobin.core.RrdException;
import org.jrobin.core.RrdNioBackend;
import org.jrobin.core.Sample;
import org.jrobin.core.Util;
import org.jrobin.graph.RrdGraph;
import org.jrobin.graph.RrdGraphDef;

/**
 * Stockage RRD et graphiques statistiques.
 * Cette classe utilise JRobin (http://www.jrobin.org/index.php/Main_Page)
 * qui est une librairie Java opensource (LGPL) similaire à RRDTool (http://oss.oetiker.ch/rrdtool/).
 * L'API et le tutorial JRobin sont à http://oldwww.jrobin.org/api/index.html
 * @author <NAME>
 */
final class JRobin {
	static final int SMALL_HEIGHT = 50;
	private static final Color LIGHT_RED = Color.RED.brighter().brighter();
	private static final Paint SMALL_GRADIENT = new GradientPaint(0, 0, LIGHT_RED, 0, SMALL_HEIGHT,
			Color.GREEN, false);
	private static final int HOUR = 60 * 60;
	private static final int DAY = 24 * HOUR;

	// pool of open RRD files
	private final RrdDbPool rrdPool = RrdDbPool.getInstance();
	private final String application;
	private final String name;
	private final String rrdFileName;
	private final int step;
	private final String requestName;

	private JRobin(String application, String name, File rrdFile, int step, String requestName)
			throws RrdException, IOException {
		super();
		assert application != null;
		assert name != null;
		assert rrdFile != null;
		assert step > 0;
		// requestName est null pour un compteur

		this.application = application;
		this.name = name;
		this.rrdFileName = rrdFile.getPath();
		this.step = step;
		this.requestName = requestName;

		init();
	}

	static void stop() throws IOException {
		getJRobinFileSyncTimer().cancel();
	}

	static void setJRobinThreadName(final String jrobinThreadName) throws IOException {
		final TimerTask threadNameTask = new TimerTask() {
			/** {@inheritDoc} */
			@Override
			public void run() {
				Thread.currentThread().setName(jrobinThreadName);
			}
		};
		getJRobinFileSyncTimer().schedule(threadNameTask, 0);
	}

	static Timer getJRobinFileSyncTimer() throws IOException {
		try {
			// on accède à ce timer par réflexion pour l'arrêter faute d'autre moyen
			final Field field = RrdNioBackend.class.getDeclaredField("fileSyncTimer");
			setFieldAccessible(field);
			return (Timer) field.get(null);
		} catch (final NoSuchFieldException e) {
			throw createIOException(e);
		} catch (final IllegalAccessException e) {
			throw createIOException(e);
		}
	}

	private static void setFieldAccessible(final Field field) {
		AccessController.doPrivileged(new PrivilegedAction<Object>() { // pour findbugs
					/** {@inheritDoc} */
					public Object run() {
						field.setAccessible(true);
						return null;
					}
				});
	}

	static JRobin createInstance(String application, String name, String requestName)
			throws IOException {
		final File dir = Parameters.getStorageDirectory(application);
		final File rrdFile = new File(dir, name + ".rrd");
		final int step = Parameters.getResolutionSeconds();
		try {
			return new JRobin(application, name, rrdFile, step, requestName);
		} catch (final RrdException e) {
			throw createIOException(e);
		}
	}

	private void init() throws IOException, RrdException {
		final File rrdFile = new File(rrdFileName);
		final File rrdDirectory = rrdFile.getParentFile();
		if (!rrdDirectory.mkdirs() && !rrdDirectory.exists()) {
			throw new IOException("JavaMelody directory can't be created: "
					+ rrdDirectory.getPath());
		}
		if (!rrdFile.exists()) {
			// create RRD file since it does not exist
			final RrdDef rrdDef = new RrdDef(rrdFileName, step);
			// "startTime" décalé de "step" pour éviter que addValue appelée juste
			// après ne lance l'exception suivante la première fois
			// "Bad sample timestamp x. Last update time was x, at least one second step is required"
			rrdDef.setStartTime(Util.getTime() - step);
			// single gauge datasource
			final String dsType = "GAUGE";
			// max time before "unknown value"
			final int heartbeat = step * 2;
			rrdDef.addDatasource(getDataSourceName(), dsType, heartbeat, 0, Double.NaN);
			// several archives
			final String average = "AVERAGE";
			final String max = "MAX";
			// 1 jour
			rrdDef.addArchive(average, 0.25, 1, DAY / step);
			rrdDef.addArchive(max, 0.25, 1, DAY / step);
			// 1 semaine
			rrdDef.addArchive(average, 0.25, HOUR / step, 7 * 24);
			rrdDef.addArchive(max, 0.25, HOUR / step, 7 * 24);
			// 1 mois
			rrdDef.addArchive(average, 0.25, 6 * HOUR / step, 31 * 4);
			rrdDef.addArchive(max, 0.25, 6 * HOUR / step, 31 * 4);
			// 2 ans (1 an pour période "1 an" et 2 ans pour période "tout")
			rrdDef.addArchive(average, 0.25, 8 * 6 * HOUR / step, 2 * 12 * 15);
			rrdDef.addArchive(max, 0.25, 8 * 6 * HOUR / step, 2 * 12 * 15);
			// create RRD file in the pool
			final RrdDb rrdDb = rrdPool.requestRrdDb(rrdDef);
			rrdPool.release(rrdDb);
		}<commit_msg>fix pour issue 141 : exception while collecting data java.io.IOException: Read failed, file xyz not mapped for I/O<commit_after>/*
 * Copyright 2008-2010 by <NAME>
 *
 *     This file is part of Java Melody.
 *
 * Java Melody 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 3 of the License, or
 * (at your option) any later version.
 *
 * Java Melody 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 Java Melody.  If not, see <http://www.gnu.org/licenses/>.
 */
package net.bull.javamelody;

import java.awt.Color;
import java.awt.GradientPaint;
import java.awt.Paint;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Calendar;
import java.util.Timer;
import java.util.TimerTask;

import org.jrobin.core.RrdDb;
import org.jrobin.core.RrdDbPool;
import org.jrobin.core.RrdDef;
import org.jrobin.core.RrdException;
import org.jrobin.core.RrdNioBackend;
import org.jrobin.core.Sample;
import org.jrobin.core.Util;
import org.jrobin.graph.RrdGraph;
import org.jrobin.graph.RrdGraphDef;

/**
 * Stockage RRD et graphiques statistiques.
 * Cette classe utilise JRobin (http://www.jrobin.org/index.php/Main_Page)
 * qui est une librairie Java opensource (LGPL) similaire à RRDTool (http://oss.oetiker.ch/rrdtool/).
 * L'API et le tutorial JRobin sont à http://oldwww.jrobin.org/api/index.html
 * @author <NAME>
 */
final class JRobin {
	static final int SMALL_HEIGHT = 50;
	private static final Color LIGHT_RED = Color.RED.brighter().brighter();
	private static final Paint SMALL_GRADIENT = new GradientPaint(0, 0, LIGHT_RED, 0, SMALL_HEIGHT,
			Color.GREEN, false);
	private static final int HOUR = 60 * 60;
	private static final int DAY = 24 * HOUR;

	// pool of open RRD files
	private final RrdDbPool rrdPool = RrdDbPool.getInstance();
	private final String application;
	private final String name;
	private final String rrdFileName;
	private final int step;
	private final String requestName;

	private JRobin(String application, String name, File rrdFile, int step, String requestName)
			throws RrdException, IOException {
		super();
		assert application != null;
		assert name != null;
		assert rrdFile != null;
		assert step > 0;
		// requestName est null pour un compteur

		this.application = application;
		this.name = name;
		this.rrdFileName = rrdFile.getPath();
		this.step = step;
		this.requestName = requestName;

		init();
	}

	static void stop() throws IOException {
		getJRobinFileSyncTimer().cancel();
	}

	static void setJRobinThreadName(final String jrobinThreadName) throws IOException {
		final TimerTask threadNameTask = new TimerTask() {
			/** {@inheritDoc} */
			@Override
			public void run() {
				Thread.currentThread().setName(jrobinThreadName);
			}
		};
		getJRobinFileSyncTimer().schedule(threadNameTask, 0);
	}

	static Timer getJRobinFileSyncTimer() throws IOException {
		try {
			// on accède à ce timer par réflexion pour l'arrêter faute d'autre moyen
			final Field field = RrdNioBackend.class.getDeclaredField("fileSyncTimer");
			setFieldAccessible(field);
			return (Timer) field.get(null);
		} catch (final NoSuchFieldException e) {
			throw createIOException(e);
		} catch (final IllegalAccessException e) {
			throw createIOException(e);
		}
	}

	private static void setFieldAccessible(final Field field) {
		AccessController.doPrivileged(new PrivilegedAction<Object>() { // pour findbugs
					/** {@inheritDoc} */
					public Object run() {
						field.setAccessible(true);
						return null;
					}
				});
	}

	static JRobin createInstance(String application, String name, String requestName)
			throws IOException {
		final File dir = Parameters.getStorageDirectory(application);
		final File rrdFile = new File(dir, name + ".rrd");
		final int step = Parameters.getResolutionSeconds();
		try {
			return new JRobin(application, name, rrdFile, step, requestName);
		} catch (final RrdException e) {
			throw createIOException(e);
		}
	}

	private void init() throws IOException, RrdException {
		final File rrdFile = new File(rrdFileName);
		final File rrdDirectory = rrdFile.getParentFile();
		if (!rrdDirectory.mkdirs() && !rrdDirectory.exists()) {
			throw new IOException("JavaMelody directory can't be created: "
					+ rrdDirectory.getPath());
		}
		// cf issue 41: rrdFile could have been created with length 0 if out of disk space
		// (fix IOException: Read failed, file xxx.rrd not mapped for I/O)
		if (!rrdFile.exists() || rrdFile.length() == 0) {
			// create RRD file since it does not exist (or is empty)
			final RrdDef rrdDef = new RrdDef(rrdFileName, step);
			// "startTime" décalé de "step" pour éviter que addValue appelée juste
			// après ne lance l'exception suivante la première fois
			// "Bad sample timestamp x. Last update time was x, at least one second step is required"
			rrdDef.setStartTime(Util.getTime() - step);
			// single gauge datasource
			final String dsType = "GAUGE";
			// max time before "unknown value"
			final int heartbeat = step * 2;
			rrdDef.addDatasource(getDataSourceName(), dsType, heartbeat, 0, Double.NaN);
			// several archives
			final String average = "AVERAGE";
			final String max = "MAX";
			// 1 jour
			rrdDef.addArchive(average, 0.25, 1, DAY / step);
			rrdDef.addArchive(max, 0.25, 1, DAY / step);
			// 1 semaine
			rrdDef.addArchive(average, 0.25, HOUR / step, 7 * 24);
			rrdDef.addArchive(max, 0.25, HOUR / step, 7 * 24);
			// 1 mois
			rrdDef.addArchive(average, 0.25, 6 * HOUR / step, 31 * 4);
			rrdDef.addArchive(max, 0.25, 6 * HOUR / step, 31 * 4);
			// 2 ans (1 an pour période "1 an" et 2 ans pour période "tout")
			rrdDef.addArchive(average, 0.25, 8 * 6 * HOUR / step, 2 * 12 * 15);
			rrdDef.addArchive(max, 0.25, 8 * 6 * HOUR / step, 2 * 12 * 15);
			// create RRD file in the pool
			final RrdDb rrdDb = rrdPool.requestRrdDb(rrdDef);
			rrdPool.release(rrdDb);
		}
{'fraction_non_alphanumeric': 0.10508474576271186, 'fraction_numerical': 0.014285714285714285, 'mean_word_length': 3.827035449941566, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 13, 'https://': 0, 'lorem ipsum': 0, 'www.': 6, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '13858', 'n_tokens_mistral': 4455, 'n_tokens_neox': 3926, 'n_words': 1281}