Jump to content
We've recently updated our Privacy Statement, available here ×

My Idea to improve performance


NeO_GeO

Recommended Posts

This was my idea to improve performance.

 

I created a buffer queue with a maximum number of elements.

 

I have a Thread that executes and inserts the records in this buffer,it waits if the buffer is full and it sends a signal of "END" when it has finished.

Another Thread ,in the meantime, compiles the file jrxml, fills the record reading from this buffer and creates the report at run time when the buffer is empty and the signal 'END' is arrived.

This solution is very complicated because it requires a buffer synchronized (with the primitive wait () and notifyAll ()) and an additional synchronization between 2 Thread.

But allow me to reduce the execution time considerably and for those like me, that are working on millions of records, this method avoids Heap 's errors.

 

THIS IS AN EXAMPLE OF CODE :

 

********* CLASS NODE *********

 

public class Node {

 

private Node next,prev;

private Object obj;

 

public Node(Object obj){

this(null,null,obj);

}

 

public Node(Node next,Object obj){

this(next,null,obj);

}

 

public Node(Node next,Node prev,Object obj) {

this.next = next;

this.prev = prev;

this.obj = obj;

}

 

public Object getObject(){

return obj;

}

 

public Node getNext(){

return next;

}

 

public Node getPrev(){

return prev;

}

 

public void setObject(Object obj){

this.obj = obj;

}

 

public void setNext(Node next){

this.next = next;

}

 

public void setPrev(Node prev){

this.prev = prev;

}

 

******* CLASS QUEUE ********

 

public class Queue {

 

private Node head,tail;

private int size;

 

public Queue() {

head = tail = null;

size = 0;

}

 

public Object Pop(){

 

Object obj = null;

 

if(!isEmpty()){

 

obj = head.getObject();

 

if(head == tail){

head = tail = null;

}

else{

head = head.getNext();

head.setPrev(null);

}

size --;

}

 

return obj;

 

}

 

public void Push(Object obj){

 

Node node = new Node(obj);

 

if(isEmpty()){

head = tail = node;

}

else if (head == tail){

head.setNext(node);

tail = head.getNext();

tail.setPrev(head);

}

else{

tail.setNext(node);

tail.getNext().setPrev(tail);

tail = tail.getNext();

}

 

size ++;

}

 

public Object[] MultiPop(int n) throws IndexOutOfBoundsException{

 

Object[] obj = null;

 

if(n > getSize()){

throw new IndexOutOfBoundsException("IndexOutOfBoundsException : Superata la dimensione della Pila ");

}

else{

obj = new Object[n];

 

for(int i=0;i<n;i++){

obj= Pop();

}

}

 

return obj;

 

}

 

public void MultiPush(Object[] obj ){

for(int i=0;i<obj.length;i++){

Push(obj);

}

}

 

public boolean isEmpty(){

return (head == null);

}

 

public int getSize(){

return size;

}

 

}

******* CLASS BUFFER *******

 

public class Buffer extends Queue {

 

 

private int maxSize;

private boolean endMessage;

 

public Buffer(int maxSize) {

super();

this.maxSize = maxSize;

this.endMessage = false;

 

}

 

public synchronized Object Pop(){

 

while(isEmpty()){ // finchè coda = 0

try{

 

wait(); // attendi

 

}catch(InterruptedException ex){}

}

 

notifyAll();

 

return super.Pop();

 

}

 

public synchronized void Push(Object obj){

 

while(getSize()>maxSize){

try{

 

wait(); // attendi

 

}catch(InterruptedException ex){}

}

 

super.Push(obj);

 

notifyAll();

}

 

public synchronized Object[] MultiPop(int n){

 

while(getSize()<=n){ //( finchè coda <= n

try{

 

wait(); // attendi

 

}catch(InterruptedException ex){}

}

 

notifyAll();

 

return super.MultiPop(n);

}

 

public synchronized void MultiPush(Object[] obj){

 

while(getSize()+obj.length>maxSize){

try{

 

wait(); // attendi

 

}catch(InterruptedException ex){}

}

 

super.MultiPush(obj);

 

notifyAll();

 

}

 

public void setEndMessage(boolean endMessage){

this.endMessage = endMessage;

}

 

public boolean getEndMessage(){

return (endMessage && isEmpty());

}

 

public void setMaxSize(int maxSize){

this.maxSize = maxSize;

}

 

public int getMaxSize(){

return maxSize;

}

 

}

 

******** INTERFACE METADATA *********

 

public interface MetaData {

// Metodo che ritorna i nomi delle colonne

public void setColumnsLabel(String columns_label[]);

// Metodo che setta il columns_type

public void setColumnsType(String columns_type[]);

// Metodo che setta il columns_type_java

public void setColumnsTypeJava(String columns_type_java[]);

// Metodo che setta il columns_scale

public void setColumnsScale(int columns_scale[]);

// Metodo che setta il columns_precision

public void setColumnsPrecision(int columns_precision[]);

// Metodo che ritorna i campi

public String[] getColumnsLabel();

// Metodo che ritorna il tipo dei campi

public String[] getColumnsType();

// Metodo che ritorna il tipo java dei campi

public String[] getColumnsTypeJava();

// Metodo che ritorna la dimensione dei campi

public int[] getColumnsPrecision();

// Ritorna la scala dei campi

public int[] getColumnsScale();

// Ritorna dimensione dei campi

public int getColumsSize();

// Ritorna la posizione di un campo

public int getColumn(String field) throws IllegalArgumentException ;

 

}

 

******** CLASS SynchDatabaseBuffer **********

 

public class SynchDatabaseBuffer extends Buffer implements MetaData {

 

 

private String columns_label[]; // Array che contiene i nomi delle colonne

private String columns_type[]; // Array che contiene il tipo delle colonne

private String columns_type_java[];// Array che contiene i tipi java delle colonne

private int columns_precision[]; // Array che contiene la dimensione dei campi

private int columns_scale[]; // Array che contiene la scala dei campi numerici

private int columns_size; // Dimensione dei campi

 

/** Creates a new instance of SynchDatabaseBuffer */

public SynchDatabaseBuffer(int maxSize) {

 

this(maxSize,null,null,null,null,null);

 

}

/** Creates a new instance of SynchDatabaseBuffer */

public SynchDatabaseBuffer(int maxSize,String columns_label[],String columns_type[],String columns_type_java[],int columns_precision[],int columns_scale[]){

 

super(maxSize);

 

setColumnsLabel(columns_label);

setColumnsType(columns_type);

setColumnsTypeJava(columns_type_java);

setColumnsScale(columns_scale);

setColumnsPrecision(columns_precision);

setColumnsScale(columns_scale);

 

}

// Metodo che setta il columns label

public void setColumnsLabel(String columns_label[]){

 

this.columns_label = columns_label;

 

try{

this.columns_size = columns_label.length;

}

catch(NullPointerException ex){

this.columns_size = 0;

}

 

}

// Metodo che setta il columns_type

public void setColumnsType(String columns_type[]){

this.columns_type = columns_type;

}

// Metodo che setta il columns_type_java

public void setColumnsTypeJava(String columns_type_java[]){

this.columns_type_java = columns_type_java;

}

// Metodo che setta il columns_scale

public void setColumnsScale(int columns_scale[]){

this.columns_scale = columns_scale;

}

// Metodo che setta il columns_precision

public void setColumnsPrecision(int columns_precision[]){

this.columns_precision = columns_precision;

}

// Metodo che ritorna i campi

public String[] getColumnsLabel(){

return columns_label;

}

// Metodo che ritorna il tipo dei campi

public String[] getColumnsType(){

return columns_type;

}

// Metodo che ritorna il tipo java dei campi

public String[] getColumnsTypeJava(){

return columns_type_java;

}

// Metodo che ritorna la dimensione dei campi

public int[] getColumnsPrecision(){

return columns_precision;

}

// Ritorna la scala dei campi

public int[] getColumnsScale(){

return columns_scale;

}

// Ritorna dimensione dei campi

public int getColumsSize(){

return columns_size;

}

// Ritorna la posizione di un campo

public int getColumn(String field) throws IllegalArgumentException {

 

int idx = -1;

 

try{

for (int i=0; i<columns_label.length; i++) {

if (columns_label.equalsIgnoreCase(field)) {

idx = i;

break;

}

}

}catch(NullPointerException ex){}

 

 

if(idx == -1){

String exceptionMessage = "Field "+field+" not found !";

throw new IllegalArgumentException(exceptionMessage);

}

 

return idx;

}

 

}

 

 

************ METHOD TO INSERT RECORDS ***************

 

public void eseguiQuery(String query,SynchDatabaseBuffer buffer) throws SQLException {

 

String columns_label [] = null;

String columns_type [] = null;

String columns_type_java [] = null;

int columns_precision [] = null;

int columns_scale [] = null;

 

Object [] record;

int colonne = 0;

 

Statement stmt = db.createStatement(); // Creo lo Statement per l'esecuzione della query

ResultSet rs = stmt.executeQuery(query); // Ottengo il ResultSet dell'esecuzione della query

ResultSetMetaData rsmd = rs.getMetaData();

 

colonne = rsmd.getColumnCount();

 

columns_label = new String[colonne];

columns_type = new String[colonne];

columns_type_java = new String[colonne];

columns_precision = new int[colonne];

columns_scale = new int[colonne];

 

//Ciclo for che analizza i metadati

for (int i=0; i<colonne; i++){ //Creo l' array di stringhe scorrendo il metadata

columns_label = rsmd.getColumnLabel(i+1);

columns_type = rsmd.getColumnTypeName(i+1);

columns_type_java = rsmd.getColumnClassName(i+1);

columns_precision = rsmd.getPrecision(i+1);

columns_scale= rsmd.getScale(i+1);

}

 

buffer.setColumnsLabel(columns_label);

buffer.setColumnsType(columns_type);

buffer.setColumnsTypeJava(columns_type_java);

buffer.setColumnsPrecision(columns_precision);

buffer.setColumnsScale(columns_scale);

 

 

while(rs.next()) { // Creo il vettore risultato scorrendo tutto il ResultSet

record = new Object[colonne];

 

for (int i=0; i<colonne; i++){

record = rs.getObject(i+1);

}

 

buffer.Push(record);

}

 

buffer.setEndMessage(true);

 

rs.close(); // Chiudo il ResultSet

stmt.close(); // Chiudo lo Statement

 

}

Link to comment
Share on other sites

  • 3 months later...
  • Replies 4
  • Created
  • Last Reply

Top Posters In This Topic

Hello,

 

I looked at you idea. I have some questions on the same. I would appreciate if you could help me with the same.

 

When you are iterating the resultset and creating record objects, I assume that you are having your own implementation of JRDataSource where i think you will move record by record(Object) in the next method of the JRDataSource. So where is the difference ? The default implementation also iterates using reultset.next(). So instead of sending the whole resultset to JRResultSetDatasource, you are sending cnuks of smaller objects. But anyways the filling will be done calling object by object. So the point I am trying to clarify is when the rs.next() is done in the default implementation, why should it be done in our code and send Objects to be filled , since filling of the report is sequential.

 

 

I hope i am making sense.

 

Thank You very Much

Link to comment
Share on other sites

Sorry for my english i' m italian.

This is not only and idea....i' ve implemented it.

I post the code for implementing JRDataSource with the buffer up.

 

SIMPLE THREAD dedicated to the management of time-up errors.

 

Code:
/**
*
* @author  NeO GeO - Veltro Giordano
* @version 1.0
* 
*/


/**
 * This Class implements a stopwatch.
 * 
*/

package org.Report;



public class TimeUp extends Thread{
   private int sec;
   
   /**
   * Class constructor.
   * @param sec the second at wich to stop the count
   */
   public TimeUp(int sec){
       this.sec = sec;
   }
   
   @Override
   public void run(){
       
       int current = 0;
       while(current < sec){
           try {
               Thread.sleep(1000);
               current++;
           } catch (InterruptedException ex) {
               return;
           }
       }
       
   }
           

}


My JRDataSource


/**
*
* @author  NeO GeO - Veltro Giordano
* @version 1.0
* 
*/


/**
 * Class dedicated to the management of a possible Datasource for Jasper Reports.
 * This datasource is implemented with a buffer and it has the same configuration of an Iterator.
 * 
*/

package org.Report;


import net.sf.jasperreports.engine.JRDataSource;
import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JRField;
import org.Database.SynchDatabaseBuffer;

public class JRBufferCollection implements JRDataSource {

   private SynchDatabaseBuffer buffer;
   private TimeUp timeUp;
   private Object[] row ;
   private boolean timeUpError;

   
  /**
   * Class constructor.
   * 
   * @param  buffer  buffer for inserting records
   * @param  secTimeUp seconds for time-up time
   * @see SynchDatabaseBuffer
   */
   public JRBufferCollection (SynchDatabaseBuffer buffer,int secTimeUp) {       
       
       this.timeUp = new TimeUp(secTimeUp);
       
       this.buffer = buffer;        
       this.row = null;     
       
       this.timeUpError = false;
       
    }

  /**
   * Return the value present in the {@link JRField } parameter in the current record  analyzed
   * 
   * @param  jrField  JRField object to indicate a fieldcolumn of a record 
   * @return Object object that rappresent the value of field in the current record 
   * @see JRField
   */
   public Object getFieldValue(JRField jrField) throws JRException, IllegalArgumentException {
       String name = jrField.getName();       
       int column = buffer.getColumn(name);  
       return row[column];
   }

  /**
   * Return true if the buffer has another record to extract.
   * In the meanwhile a thread, that counts the seconds of time-up set in the constructor, starts. 
   * If there is no record and the time-up ending this method returns false.   
   * 
   * @return boolean value if the buffer has another recoord to extract
   * 
   */
   public synchronized boolean next() throws JRException {
      
       if (!(buffer.getEndMessage())) { // Se il buffer non riceve il messaggio di chiusura            
          
           while(buffer.isEmpty()){
               try {
                   
                   timeUp.start();
                   timeUp.join();             
               
                   if(buffer.isEmpty()){
                       
                       timeUpError = true;
                       return false;                
                   }
               } catch (InterruptedException ex) {
                   return false;
               }
           }        
           row = (Object[]) buffer.Pop();               
           return true;              
       }    
       
       return false;
   }
   
  /**
   * Return the current state of time-up error.  
   * 
   * @return boolean value if there is a time-up error
   * 
   */
   public boolean timeUpError (){
       return timeUpError;
   }
   

}

Link to comment
Share on other sites

Code:


/**
*
* @author NeO GeO - Veltro Giordano
* @version 1.0
*
*/


/**
* Class dedicated to the management of a possible Datasource for Jasper Reports.
* This datasource is implemented with a buffer and it has the same configuration of an Iterator.
*
*/

package org.Report;


import net.sf.jasperreports.engine.JRDataSource;
import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JRField;
import org.Database.SynchDatabaseBuffer;

public class JRBufferCollection implements JRDataSource {

private SynchDatabaseBuffer buffer;
private TimeUp timeUp;
private Object[] row ;
private boolean timeUpError;


/**
* Class constructor.
*
* @param buffer buffer for inserting records
* @param secTimeUp seconds for time-up time
* @see SynchDatabaseBuffer
*/
public JRBufferCollection (SynchDatabaseBuffer buffer,int secTimeUp) {

this.timeUp = new TimeUp(secTimeUp);

this.buffer = buffer;
this.row = null;

this.timeUpError = false;

}

/**
* Return the value present in the {@link JRField } parameter in the current record analyzed
*
* @param jrField JRField object to indicate a fieldcolumn of a record
* @return Object object that rappresent the value of field in the current record
* @see JRField
*/
public Object getFieldValue(JRField jrField) throws JRException, IllegalArgumentException {
String name = jrField.getName();
int column = buffer.getColumn(name);
return row[column];
}

/**
* Return true if the buffer has another record to extract.
* In the meanwhile a thread, that counts the seconds of time-up set in the constructor, starts.
* If there is no record and the time-up ending this method returns false.
*
* @return boolean value if the buffer has another recoord to extract
*
*/
public synchronized boolean next() throws JRException {

if (!(buffer.getEndMessage())) { // Se il buffer non riceve il messaggio di chiusura

while(buffer.isEmpty()){
try {

timeUp.start();
timeUp.join();

if(buffer.isEmpty()){

timeUpError = true;
return false;
}
} catch (InterruptedException ex) {
return false;
}
}
row = (Object[]) buffer.Pop();
return true;
}

return false;
}

/**
* Return the current state of time-up error.
*
* @return boolean value if there is a time-up error
*
*/
public boolean timeUpError (){
return timeUpError;
}


}

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×
×
  • Create New...