/**
*
*/
package fr.inria.soctrace.framesoc.ui.eventtable.view;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import fr.inria.soctrace.framesoc.ui.eventtable.model.EventTableRow;
import fr.inria.soctrace.framesoc.ui.model.TimeInterval;
/**
* Event table row cache. It is used concurrently by the virtual table listener for new item
* retrieval and the drawer thread, which populates it.
*
* The filter thread, which re-index the cache, cannot update the index concurrently to the loading.
*
* The rows are supposed to be stored sorted by timestamp. The sorting is done externally to this
* cache.
*
* @author "Generoso Pagano <generoso.pagano@inria.fr>"
*/
public class EventTableCache {
/**
* Largest requested interval so far
*/
private TimeInterval fRequestedInterval;
/**
* Active interval
*/
private TimeInterval fActiveInterval;
/**
* Cached event table rows
*/
private ArrayList<EventTableRow> fRows;
/**
* Map between the table index and the row
*/
private Map<Integer, EventTableRow> fIndex;
/**
* Current value for the index, while indexing
*/
private int fCurrentIndex;
public EventTableCache() {
internalClear();
}
/**
* Get the table row for the given index
*
* @param index
* table index
* @return the table row corresponding to the index
*/
public synchronized EventTableRow get(int index) {
return fIndex.get(index);
}
/**
* Put a new row in the cache, assigning a new index.
*
* @param row
* the row to put in the cache
*/
public synchronized void put(EventTableRow row) {
updateInterval(row.getTimestamp(), fActiveInterval);
fRows.add(row);
fIndex.put(fCurrentIndex, row);
fCurrentIndex++;
}
/**
* Re-map an existing row in the cache to the given index.
*
* @param row
* the row to put in the cache
*/
public synchronized void remap(EventTableRow row, int index) {
fIndex.put(index, row);
}
/**
* Remove all the entry of the index starting from the passed value.
*
* @param index
* the the last index to keep
*/
public synchronized void cleanIndex(int index) {
int removeIndex = index;
while (fIndex.containsKey(removeIndex)) {
fIndex.remove(removeIndex);
removeIndex++;
}
}
/**
* Check if the passed intervals is contained in the currently largest requested interval. Note
* that a requested interval can be larger than the loaded one, since the loaded one correspond
* to the actual events actually present in the requested interval.
*
* @param interval
* interval to check
* @return true if the passed interval has already been loaded
*/
public synchronized boolean contains(TimeInterval interval) {
if (interval.startTimestamp >= fRequestedInterval.startTimestamp
&& interval.endTimestamp <= fRequestedInterval.endTimestamp)
return true;
return false;
}
/**
* Re-index the cache, considering the new interval.
*
* @param interval
*/
public synchronized void index(TimeInterval interval) {
fActiveInterval = new TimeInterval(interval);
index();
}
/**
* Re-index the cache, considering all the active rows.
*/
public synchronized void index() {
fIndex = new HashMap<>();
fCurrentIndex = 0;
for (EventTableRow row : fRows) {
if (row.getTimestamp() < fActiveInterval.startTimestamp)
continue;
if (row.getTimestamp() > fActiveInterval.endTimestamp)
continue;
fIndex.put(fCurrentIndex, row);
fCurrentIndex++;
}
}
/**
* Get the total number of indexed rows
*
* @return the number of indexed rows
*/
public synchronized int getIndexedRowCount() {
return fIndex.size();
}
/**
* @return the requestedInterval
*/
public synchronized TimeInterval getRequestedInterval() {
return fRequestedInterval;
}
/**
* @param requestedInterval
* the requestedInterval to set
*/
public synchronized void setRequestedInterval(TimeInterval requestedInterval) {
fRequestedInterval = requestedInterval;
}
/**
* Clear the cache
*/
public synchronized void clear() {
internalClear();
}
/*
* Utils
*/
private void internalClear() {
fRows = new ArrayList<>();
fIndex = new HashMap<>();
fCurrentIndex = 0;
fRequestedInterval = new TimeInterval(Long.MAX_VALUE, Long.MIN_VALUE);
fActiveInterval = new TimeInterval(Long.MAX_VALUE, Long.MIN_VALUE);
}
private void updateInterval(long timestamp, TimeInterval interval) {
if (timestamp < interval.startTimestamp) {
interval.startTimestamp = timestamp;
}
if (timestamp > interval.endTimestamp) {
interval.endTimestamp = timestamp;
}
}
}