/*
* Copyright (C) 2014 Mark Clarke
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package za.co.jumpingbean.gcexplorer.model;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.chart.XYChart;
import javafx.scene.chart.XYChart.Data;
/**
*
* @author mark
*/
public abstract class MemoryPool {
protected final ObservableList<XYChart.Series<Number, Number>> freeCommittedSeriesList;
protected final ObservableList<XYChart.Series<Number, Number>> usedFreeSeriesList;
protected final DataItem max;
protected final DataItem used;
protected final DataItem committed;
protected final DataItem free;
protected int numDataPoints = 40;
protected final ReentrantReadWriteLock lock;
protected final Timestamp startTime;
public MemoryPool(int numDataPoints, Timestamp startTime) {
this.startTime = startTime;
this.numDataPoints = numDataPoints;
this.max = new DataItem("Max", 0);
this.used = new DataItem("Used", 0);
this.committed = new DataItem("Committed", 0);
this.free = new DataItem("Free", 0);
freeCommittedSeriesList = FXCollections.observableArrayList(new ArrayList<XYChart.Series<Number, Number>>());
usedFreeSeriesList = FXCollections.observableArrayList(new ArrayList<XYChart.Series<Number, Number>>());
lock = new ReentrantReadWriteLock();
//create empty data series
for (int i = 0; i < 2; i++) {
XYChart.Series<Number, Number> freeCommittedSeries = new XYChart.Series();
freeCommittedSeries.setData(FXCollections.observableArrayList(new LinkedList<Data<Number, Number>>()));
freeCommittedSeriesList.add(freeCommittedSeries);
if (i == 0) {
freeCommittedSeries.setName("Used");
} else {
freeCommittedSeries.setName("Committed");
}
XYChart.Series<Number, Number> usedFreeSeries = new XYChart.Series();
//Initiaise usedFree series to prevent AreaGraph crashing on empty data set
List<Data<Number, Number>> tmpList = new LinkedList<>();
tmpList.add(new Data(0, 0));
usedFreeSeries.setData(FXCollections.observableArrayList(tmpList));
usedFreeSeriesList.add(usedFreeSeries);
String name = this.getClass().getSimpleName();
name = name.substring(0, name.indexOf("MemoryPool"));
if (i == 0) {
usedFreeSeries.setName(name + " Used");
} else {
usedFreeSeries.setName(name + " Free");
}
}
}
public int getNumDataPoints() {
return numDataPoints;
}
public Timestamp getStartTime() {
return startTime;
}
public void setNumDataPoints(int numDataPoints) {
lock.writeLock().lock();
try {
this.numDataPoints = numDataPoints;
} finally {
lock.writeLock().unlock();
}
}
public ObservableList<XYChart.Series<Number, Number>> getFreeCommittedSeries() {
return freeCommittedSeriesList;
}
public ObservableList<XYChart.Series<Number, Number>> getUsedFreeSeries() {
return usedFreeSeriesList;
}
public DataItem getMax() {
return max;
}
public DataItem getUsed() {
return used;
}
public DataItem getCommitted() {
return committed;
}
public DataItem getFree() {
return free;
}
public void setMaxValue(Double num) {
this.max.setMeasure(num);
}
public void setUsedValue(Double num) {
this.used.setMeasure(num);
}
public void setCommittedValue(Double num) {
this.committed.setMeasure(num);
}
public void setFreeValue(Double num) {
this.free.setMeasure(num);
}
//TODO: Remove or reimplement locking. Data read by JavaFX and no read lock
public void addDataPoint(Timestamp ts, Number used, Number committed, Number free) {
ObservableList<Data<Number, Number>> fcList1 = freeCommittedSeriesList.get(0).getData();
ObservableList<Data<Number, Number>> ufList1 = usedFreeSeriesList.get(0).getData();
ObservableList<Data<Number, Number>> fcList2 = freeCommittedSeriesList.get(1).getData();
ObservableList<Data<Number, Number>> ufList2 = usedFreeSeriesList.get(1).getData();
lock.writeLock().lock();
try {
//TODO Make conversion of milliseconds accomodate changes in sampling time.
this.addData(fcList1, new Data((ts.getTime() - startTime.getTime()) / 1000, used),"used");
this.addData(ufList1, new Data((ts.getTime() - startTime.getTime()) / 1000, used),"used");
this.addData(fcList2, new Data((ts.getTime() - startTime.getTime()) / 1000, committed),"committed");
this.addData(ufList2, new Data((ts.getTime() - startTime.getTime()) / 1000, free),"free");
if (fcList1.size() > this.numDataPoints) {
int over = fcList1.size() - this.numDataPoints;
this.removeExcessDataItems(fcList1, over,"used");
this.removeExcessDataItems(fcList2, over,"used");
}
if (ufList1.size() > this.numDataPoints) {
int over = ufList1.size() - this.numDataPoints;
this.removeExcessDataItems(ufList1, over,"committed");
this.removeExcessDataItems(ufList2, over,"free");
}
} finally {
lock.writeLock().unlock();
}
}
//Sometime get null pointer exceptions when adding points and points have been removed.
private void addData(ObservableList<Data<Number, Number>> list, Data data,String type) {
try {
list.add(data);
} catch(NullPointerException ex){
//Weird null pointer exception from XYChart.Series complaining about
//chart pointer being null for PermGen and EmptySurvivorSpace
//Following up with JavaFX team.
//ex.printStackTrace();
}
}
private void removeExcessDataItems(ObservableList<Data<Number, Number>> list, int numItems,String type) {
try {
list.remove(0);
} catch(NullPointerException ex){
// System.out.println("Remove Data Null Pointer: size=" + list.size()+" over="+numItems);
// ex.printStackTrace();
} catch(UnsupportedOperationException ex){
//At some point JavaFX deciceds to add the removed element to a unmodifiable list.
//for PermGen and EmptySurvivorSpace
// ex.printStackTrace();
}
}
}