Mercurial > dive4elements > river
view flys-backend/src/main/java/de/intevation/flys/model/Gauge.java @ 5779:ebec12def170
Datacage: Add a pool of builders to make it multi threadable.
XML DOM is not thread safe. Therefore the old implementation only allowed one thread
to use the builder at a time. As the complexity of the configuration
has increased over time this has become a bottleneck of the whole application
because it took quiet some time to build a result. Furthermore the builder code path
is visited very frequent. So many concurrent requests were piled up
resulting in long waits for the users.
To mitigate this problem a round robin pool of builders is used now.
Each of the pooled builders has an independent copy of the XML template
and can be run in parallel.
The number of builders is determined by the system property
'flys.datacage.pool.size'. It defaults to 4.
author | Sascha L. Teichmann <teichmann@intevation.de> |
---|---|
date | Sun, 21 Apr 2013 12:48:09 +0200 |
parents | 0ff0ed6bd340 |
children |
line wrap: on
line source
package de.intevation.flys.model; import java.math.BigDecimal; import java.io.Serializable; import java.util.List; import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.Table; import javax.persistence.GeneratedValue; import javax.persistence.Column; import javax.persistence.SequenceGenerator; import javax.persistence.GenerationType; import javax.persistence.JoinColumn; import javax.persistence.OneToOne; import javax.persistence.OneToMany; import org.hibernate.Session; import org.hibernate.Query; import de.intevation.flys.backend.SessionHolder; /** Database-mapped Gauge with all info about it. */ @Entity @Table(name = "gauges") public class Gauge implements Serializable, Comparable<Gauge> { public static final int DEFAULT_SCALE = 100; public static final int MASTER_DISCHARGE_TABLE = 0; private Integer id; private String name; private River river; private BigDecimal station; private BigDecimal aeo; private BigDecimal datum; private Long officialNumber; private Range range; private List<DischargeTable> dischargeTables; /** MainValues at this Gauge. */ protected List<MainValue> mainValues; public Gauge() { } public Gauge( String name, River river, BigDecimal station, BigDecimal aeo, BigDecimal datum, Long officialNumber, Range range ) { this.name = name; this.river = river; this.station = station; this.aeo = aeo; this.datum = datum; this.officialNumber = officialNumber; this.range = range; } @Id @SequenceGenerator( name = "SEQUENCE_GAUGES_ID_SEQ", sequenceName = "GAUGES_ID_SEQ", allocationSize = 1) @GeneratedValue( strategy = GenerationType.SEQUENCE, generator = "SEQUENCE_GAUGES_ID_SEQ") @Column(name = "id") public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } @OneToOne @JoinColumn(name = "river_id" ) public River getRiver() { return river; } public void setRiver(River river) { this.river = river; } @Column(name = "name") public String getName() { return name; } public void setName(String name) { this.name = name; } @Column(name = "station") // FIXME: type mapping needed public BigDecimal getStation() { return station; } public void setStation(BigDecimal station) { this.station = station; } @Column(name = "aeo") // FIXME: type mapping needed public BigDecimal getAeo() { return aeo; } public void setAeo(BigDecimal aeo) { this.aeo = aeo; } @Column(name = "datum") // FIXME: type mapping needed public BigDecimal getDatum() { return datum; } public void setDatum(BigDecimal datum) { this.datum = datum; } @Column(name = "official_number") public Long getOfficialNumber() { return officialNumber; } public void setOfficialNumber(Long officialNumber) { this.officialNumber = officialNumber; } @OneToOne @JoinColumn(name = "range_id" ) public Range getRange() { return range; } public void setRange(Range range) { this.range = range; } @OneToMany @JoinColumn(name = "gauge_id") public List<DischargeTable> getDischargeTables() { return dischargeTables; } public void setDischargeTables(List<DischargeTable> dischargeTables) { this.dischargeTables = dischargeTables; } /** * Returns min and max W values of this gauge based with a DEFAULT_SCALE. * * @return min and max W value of this gauge [min,max]. */ public double[] determineMinMaxW() { return determineMinMaxW(DEFAULT_SCALE); } /** * Returns min and max W values of this gauge. * * @return the min and max W value of this gauge [min,max]. */ public double[] determineMinMaxW(int scale) { Session session = SessionHolder.HOLDER.get(); List<DischargeTable> tables = getDischargeTables(); DischargeTable dischargeTable = null; for (DischargeTable tmp: tables) { if (tmp.getKind() == 0) { dischargeTable = tmp; break; } } if (dischargeTable == null) { return null; } Query query = session.createQuery( "select min(w) as min, max(w) as max from DischargeTableValue " + "where table_id =:table"); query.setParameter("table", dischargeTable.getId()); List results = query.list(); Object[] result = (Object[]) results.get(0); return result != null ? new double[] { ((BigDecimal) result[0]).doubleValue() * scale, ((BigDecimal) result[1]).doubleValue() * scale} : null; } @OneToMany @JoinColumn(name = "gauge_id") public List<MainValue> getMainValues() { return mainValues; } public void setMainValues(List<MainValue> mainValues) { this.mainValues = mainValues; } public static Gauge getGaugeByOfficialNumber(long number) { Session session = SessionHolder.HOLDER.get(); Query query = session.createQuery( "from Gauge where officialNumber=:number"); query.setParameter("number", number); List<Gauge> results = query.list(); return results.isEmpty() ? null : results.get(0); } public DischargeTable fetchMasterDischargeTable() { for (DischargeTable dt: dischargeTables) { if (dt.getKind() == MASTER_DISCHARGE_TABLE) { return dt; } } return null; } /** * Returns an array of [days, qs] necessary to create duration curves. * * @return a 2dim array of [days, qs] where days is an int[] and qs is * an double[]. */ public Object[] fetchDurationCurveData() { Session session = SessionHolder.HOLDER.get(); Query query = session.createQuery( "select cast(nmv.name as integer) as days, mv.value as q " + "from MainValue as mv " + "join mv.mainValue as nmv " + "join nmv.type mvt " + "where mvt.name = 'D' and mv.gauge.id = :gauge_id " + "order by days"); query.setParameter("gauge_id", getId()); List<Object> results = query.list(); int[] days = new int[results.size()]; double[] qs = new double[results.size()]; int idx = 0; for (Object obj: results) { Object[] arr = (Object[]) obj; try { int day = ((Integer) arr[0]).intValue(); double q = ((BigDecimal) arr[1]).doubleValue(); days[idx] = day; qs[idx++] = q; } catch (NumberFormatException nfe) { } } return new Object[] { days, qs }; } /** * Calculates the maximum and minimum W and Q values * * @return the MaxMinWQ object representing the calculated values */ public MinMaxWQ fetchMaxMinWQ() { Session session = SessionHolder.HOLDER.get(); Query query = session.createQuery( "select max(mv.value) as max, min(mv.value) as min " + "from MainValue as mv " + "join mv.mainValue as nmv " + "join nmv.type mvt " + "where mvt.name in ('W', 'Q') " + "and mv.gauge.id = :gauge_id " + "group by mvt.name order by mvt.name" ); query.setParameter("gauge_id", getId()); List<Object> results = query.list(); if (results.isEmpty()) { // No values found return new MinMaxWQ(); } Object[] arr = (Object[]) results.get(0); BigDecimal maxw = (BigDecimal)arr[0]; BigDecimal minw = (BigDecimal)arr[1]; BigDecimal maxq = null; BigDecimal minq = null; if (results.size() > 1) { arr = (Object[]) results.get(1); maxq = (BigDecimal)arr[0]; minq = (BigDecimal)arr[1]; } return new MinMaxWQ(minw, maxw, minq, maxq); } @Override public int compareTo(Gauge o) { return getName().compareTo(o.getName()); } } // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :