diff --git a/benchmark/pom.xml b/benchmark/pom.xml
new file mode 100644
index 000000000..62ae817df
--- /dev/null
+++ b/benchmark/pom.xml
@@ -0,0 +1,496 @@
+
+ 4.0.0
+
+
+ org.finos.vuu
+ vuu-parent
+ 0.4.65-SNAPSHOT
+
+
+
+ 8.11.0
+ benchmarks
+
+
+ benchmark
+ benchmark
+ benchmark
+ 2023
+ jar
+
+
+
+ org.finos.vuu
+ vuu
+ 0.4.65-SNAPSHOT
+
+
+
+
+
+ org.scala-lang
+ scala-library
+ ${scala.version}
+
+
+
+ org.scala-lang
+ scala-reflect
+ ${scala.version}
+
+
+
+ junit
+ junit
+ 4.13.2
+ test
+
+
+
+ org.scalatest
+ scalatest_2.13
+ ${scalatest.version}
+ test
+
+
+ org.scala-lang
+ scala-library
+
+
+ org.scala-lang
+ scala-reflect
+
+
+
+
+
+
+
+
+ org.openjdk.jmh
+ jmh-core
+ ${jmh.version}
+
+
+ org.openjdk.jmh
+ jmh-generator-annprocess
+ ${jmh.version}
+
+
+
+
+
+
+ sign-it
+
+
+ sign
+ true
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-gpg-plugin
+ 3.0.1
+
+
+ sign-artifacts
+ verify
+
+ sign
+
+
+
+ --pinentry-mode
+ loopback
+
+
+
+
+
+
+
+
+
+ legal-report
+
+
+
+ org.scala-tools
+ maven-scala-plugin
+ ${maven.scala.plugin}
+
+
+ **/*.scala
+
+
+
+
+
+
+
+
+
+ src/main/java
+ src/test/java
+
+
+
+
+ org.apache.maven.plugins
+ maven-source-plugin
+
+
+
+ compile
+
+ jar
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-release-plugin
+
+
+
+
+ org.apache.maven.plugins
+ maven-javadoc-plugin
+
+
+ attach-javadocs
+
+ jar
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.8.0
+
+
+ ${maven.compiler.target}
+
+
+ org.openjdk.jmh
+ jmh-generator-annprocess
+ ${jmh.version}
+
+
+
+
+
+ org.ow2.asm
+ asm
+ 6.2
+
+
+
+
+
+
+ org.scala-tools
+ maven-scala-plugin
+ ${maven.scala.plugin}
+
+
+
+ compile
+ testCompile
+
+
+
+
+ src/main/scala
+ src/test/scala
+
+ -Xms64m
+ -Xmx1024m
+
+
+
+
+
+ org.codehaus.mojo
+ build-helper-maven-plugin
+ 3.2.0
+
+
+ generate-sources
+
+ add-source
+
+
+
+
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-shade-plugin
+ 3.2.1
+
+
+ package
+
+ shade
+
+
+ ${uberjar.name}
+
+
+ org.openjdk.jmh.Main
+
+
+
+
+
+
+ *:*
+
+ META-INF/*.SF
+ META-INF/*.DSA
+ META-INF/*.RSA
+
+
+
+
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+ 3.1.2
+
+
+
+ test-jar
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+ 2.7
+
+
+
+
+
+
+ org.scalatest
+ scalatest-maven-plugin
+ 2.0.2
+
+ ${project.build.directory}/surefire-reports
+ .
+ test-reports.txt
+
+
+
+ test
+
+ test
+
+
+
+
+
+
+
+
+
+
+
+
+ org.scala-tools
+ maven-scala-plugin
+ ${maven.scala.plugin}
+
+ ${scala.version}
+
+
+
+
+
\ No newline at end of file
diff --git a/benchmark/src/main/java/org/finos/vuu/benchmark/SortBenchmark2.java b/benchmark/src/main/java/org/finos/vuu/benchmark/SortBenchmark2.java
new file mode 100644
index 000000000..c2c09ff89
--- /dev/null
+++ b/benchmark/src/main/java/org/finos/vuu/benchmark/SortBenchmark2.java
@@ -0,0 +1,27 @@
+package org.finos.vuu.benchmark;
+
+import org.openjdk.jmh.annotations.*;
+
+import java.io.IOException;
+import java.util.concurrent.TimeUnit;
+
+@State(Scope.Benchmark)
+public class SortBenchmark2 {
+
+ private SortBenchmark benchmark;
+
+ @Setup
+ public void setup(){
+ benchmark = new SortBenchmark();
+ benchmark.setup();
+ }
+
+ @Benchmark
+ @OutputTimeUnit(TimeUnit.MILLISECONDS)
+ @Warmup(iterations = 3)
+ @Measurement(iterations = 2)
+ @BenchmarkMode(Mode.AverageTime)
+ public void sortLargeTable() throws IOException {
+ benchmark.sortLargeTable();
+ }
+}
diff --git a/benchmark/src/main/java/org/finos/vuu/benchmark/SortExample.java b/benchmark/src/main/java/org/finos/vuu/benchmark/SortExample.java
new file mode 100644
index 000000000..ae8387a79
--- /dev/null
+++ b/benchmark/src/main/java/org/finos/vuu/benchmark/SortExample.java
@@ -0,0 +1,66 @@
+package org.finos.vuu.benchmark;
+
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.Random;
+
+public class SortExample {
+
+ private static void print(Object[][] arr){
+ for(int c=0; c() {
+ @Override
+ public int compare(Object[] o1, Object[] o2) {
+ int res = 0;
+
+ int i1 = (int)o1[1];
+ int i2 = (int)o2[1];
+
+ int i3 = (int)o1[2];
+ int i4 = (int)o2[2];
+
+ if(i1 < i2){
+ res = -1;
+ }else if(i2 < i1){
+ res = 1;
+ }else {
+ if(i3 < i4){
+ res = -1;
+ }else if(i4 < i3){
+ res = 1;
+ }
+ }
+
+ return res;
+ }
+ });
+
+ //print(values);
+ }
+
+
+
+}
diff --git a/benchmark/src/main/scala/org/finos/vuu/benchmark/SortBenchmark.scala b/benchmark/src/main/scala/org/finos/vuu/benchmark/SortBenchmark.scala
new file mode 100644
index 000000000..c7fc1a80e
--- /dev/null
+++ b/benchmark/src/main/scala/org/finos/vuu/benchmark/SortBenchmark.scala
@@ -0,0 +1,62 @@
+package org.finos.vuu.benchmark
+
+import org.finos.toolbox.collection.array.ImmutableArray
+import org.finos.toolbox.time.{Clock, DefaultClock}
+import org.finos.vuu.core.sort.{GenericSort, GenericSort2}
+import org.finos.vuu.core.table.{SimpleDataTable, ViewPortColumnCreator}
+import org.finos.vuu.net.{SortDef, SortSpec}
+import org.openjdk.jmh.annotations._
+import org.openjdk.jmh.runner.Runner
+import org.openjdk.jmh.runner.options.OptionsBuilder
+
+import java.io.IOException
+import java.util.concurrent.TimeUnit
+
+@State(Scope.Benchmark)
+class SortBenchmark {
+
+ import SortBenchmarkHelper._
+
+ var table: SimpleDataTable = null
+
+ @Setup(Level.Invocation)
+ def setup(): Unit = {
+ table = createBigTable(2_000_000)
+ }
+
+ def doSort(table: SimpleDataTable, sort: GenericSort2): ImmutableArray[String] = {
+ val viewPortColumns = ViewPortColumnCreator.create(table, table.columns().filter(_.name.equals("exchange")).map(_.name).toList)
+ sort.doSort(table, table.primaryKeys, viewPortColumns)
+ }
+
+ @Benchmark
+ @OutputTimeUnit(TimeUnit.MILLISECONDS)
+ @Warmup(iterations = 5)
+ @Measurement(iterations = 10)
+ @BenchmarkMode(Array(Mode.AverageTime))
+ @throws[IOException]
+ def sortLargeTable(): Unit = {
+ implicit val clock: Clock = new DefaultClock
+ val sort = GenericSort2(SortSpec(List(SortDef("exchange", 'A'))), table.getTableDef.columns.filter(_.name == "exchange").toList)
+ doSort(table, sort)
+ }
+
+ def main(args: Array[String]): Unit = {
+ val opts = new OptionsBuilder()
+ .include(classOf[SortBenchmark].getSimpleName)
+ .warmupIterations(5)
+ .measurementIterations(5)
+ //.forks(1)
+ .build
+ new Runner(opts).run
+ }
+
+}
+
+object SortRun {
+ def main(args: Array[String]): Unit = {
+ val benchmark = new SortBenchmark()
+ benchmark.setup()
+ benchmark.sortLargeTable()
+ }
+}
\ No newline at end of file
diff --git a/benchmark/src/main/scala/org/finos/vuu/benchmark/SortBenchmarkHelper.scala b/benchmark/src/main/scala/org/finos/vuu/benchmark/SortBenchmarkHelper.scala
new file mode 100644
index 000000000..447d24165
--- /dev/null
+++ b/benchmark/src/main/scala/org/finos/vuu/benchmark/SortBenchmarkHelper.scala
@@ -0,0 +1,51 @@
+package org.finos.vuu.benchmark
+
+import org.finos.toolbox.jmx.MetricsProviderImpl
+import org.finos.toolbox.lifecycle.LifecycleContainer
+import org.finos.toolbox.time.{Clock, DefaultClock}
+import org.finos.vuu.api.{Index, Indices, TableDef}
+import org.finos.vuu.core.table.{Columns, DataTable, RowWithData, SimpleDataTable, TableContainer}
+import org.finos.vuu.provider.JoinTableProviderImpl
+
+object SortBenchmarkHelper {
+
+ def createBigTable(rows: Int): SimpleDataTable = {
+ implicit val clock: Clock = new DefaultClock
+ implicit val lifecycle: LifecycleContainer = new LifecycleContainer
+ implicit val metrics: MetricsProviderImpl = new MetricsProviderImpl
+
+ val joinProvider = JoinTableProviderImpl() // new EsperJoinTableProviderImpl()
+
+ val tableContainer = new TableContainer(joinProvider)
+
+ // val outQueue = new OutboundRowPublishQueue()
+ // val highPriorityQueue = new OutboundRowPublishQueue()
+ // val viewPortContainer = new ViewPortContainer(tableContainer)
+
+ val pricesDef = TableDef(
+ "prices", "ric",
+ Columns.fromNames("ric:String", "bid:Double", "ask:Double", "last:Double", "open:Double", "close:Double", "exchange:String"),
+ indices = Indices(
+ Index("exchange")
+ ),
+ "ric"
+ )
+
+ val table = new SimpleDataTable(pricesDef, joinProvider)
+
+ (1 to rows).foreach(i => {
+
+ val ric = "TST-" + i
+
+ val exchange = if (i % 2 == 0) "A"
+ else if (i % 3 == 0) "B"
+ else if (i % 4 == 0) "C"
+ else "D"
+
+ val row = RowWithData(ric, Map("ask" -> 100, "bid" -> 101, "last" -> 105, "exchange" -> exchange))
+
+ table.processUpdate(ric, row, 1l)
+ })
+ table
+ }
+}
diff --git a/pom.xml b/pom.xml
index 2c9838058..a375541fd 100644
--- a/pom.xml
+++ b/pom.xml
@@ -75,12 +75,14 @@
4.4.1
1.4.2
1.2.9
+ 1.36
toolbox
vuu
vuu-ui
+ benchmark
diff --git a/toolbox/src/main/scala/org/finos/toolbox/collection/array/ImmutableArray.scala b/toolbox/src/main/scala/org/finos/toolbox/collection/array/ImmutableArray.scala
index 8e2f2d5a3..c707a87c8 100644
--- a/toolbox/src/main/scala/org/finos/toolbox/collection/array/ImmutableArray.scala
+++ b/toolbox/src/main/scala/org/finos/toolbox/collection/array/ImmutableArray.scala
@@ -7,7 +7,7 @@ object ImmutableArray{
def empty[T](implicit c: ClassTag[T]): ImmutableArray[T] = {
new ChunkedUniqueImmutableArraySet[T](Set(), Array(), chunkSize = 5000)
}
- def from[T](array: Array[T])(implicit c: ClassTag[T]) = {
+ def from[T](array: Array[T])(implicit c: ClassTag[T]): ImmutableArray[T] = {
empty[T].addAll(new NaiveImmutableArray[T](array))
}
}
diff --git a/vuu/pom.xml b/vuu/pom.xml
index 69c1eefae..93243431a 100644
--- a/vuu/pom.xml
+++ b/vuu/pom.xml
@@ -187,6 +187,18 @@
${typesafe.conf.version}
+
+ org.openjdk.jmh
+ jmh-core
+ ${jmh.version}
+
+
+ org.openjdk.jmh
+ jmh-generator-annprocess
+ ${jmh.version}
+
+
+
diff --git a/vuu/src/main/resources/runconfigurations/SimulMain.run.xml b/vuu/src/main/resources/runconfigurations/SimulMain.run.xml
index f522f2982..e978597db 100644
--- a/vuu/src/main/resources/runconfigurations/SimulMain.run.xml
+++ b/vuu/src/main/resources/runconfigurations/SimulMain.run.xml
@@ -1,6 +1,6 @@
-
+
diff --git a/vuu/src/main/scala/org/finos/vuu/core/sort/SortCompares.scala b/vuu/src/main/scala/org/finos/vuu/core/sort/SortCompares.scala
new file mode 100644
index 000000000..1545994c4
--- /dev/null
+++ b/vuu/src/main/scala/org/finos/vuu/core/sort/SortCompares.scala
@@ -0,0 +1,133 @@
+package org.finos.vuu.core.sort
+
+import org.finos.vuu.core.table.{Column, DataType, RowData}
+
+import scala.annotation.tailrec
+
+object SortCompares {
+
+ @tailrec
+ def compare(o1: RowData, o2: RowData, columns: List[Column], sortDirections: List[Char], columnIndex: Int): Int = {
+
+ val activeColumn = columns(columnIndex)
+ val direction = sortDirections(columnIndex)
+
+ val compareValue = if(activeColumn.dataType.equals(DataType.StringDataType)){
+ compareString(o1, o2, activeColumn, direction)
+ }else if(activeColumn.dataType.equals(DataType.charDataType)){
+ compareChar(o1, o2, activeColumn, direction)
+ } else if (activeColumn.dataType.equals(DataType.IntegerDataType)) {
+ compareInt(o1, o2, activeColumn, direction)
+ } else if (activeColumn.dataType.equals(DataType.BooleanDataType)) {
+ compareBoolean(o1, o2, activeColumn, direction)
+ } else if (activeColumn.dataType.equals(DataType.DoubleDataType)) {
+ compareDouble(o1, o2, activeColumn, direction)
+ } else if (activeColumn.dataType.equals(DataType.LongDataType)) {
+ compareLong(o1, o2, activeColumn, direction)
+ }else {
+ throw new Exception("have field but don't know what it is....")
+ }
+
+ if(compareValue != 0){
+ compareValue
+ }else if(columnIndex == (columns.length - 1)){
+ compareValue
+ }else{
+ compare(o1, o2, columns, sortDirections, columnIndex + 1)
+ }
+ }
+
+ def compareChar(o1: RowData, o2: RowData, column: Column, direction: Char): Int = {
+
+ val c1 = o1.get(column).asInstanceOf[Int]
+ val c2 = o2.get(column).asInstanceOf[Int]
+
+ val lessThan = if(direction == 'A') 1 else -1
+ val greaterThan = if(direction == 'A') -1 else 1
+
+ if(c1 < c2){
+ lessThan
+ }else if(c1 > c2){
+ greaterThan
+ }else{
+ 0
+ }
+ }
+
+ def compareString(o1: RowData, o2: RowData, column: Column, direction: Char): Int = {
+ val c1 = o1.get(column).asInstanceOf[String]
+ val c2 = o2.get(column).asInstanceOf[String]
+
+ val multiplier = if(direction == 'A'){
+ -1
+ }else{
+ 1
+ }
+
+ c1.compareToIgnoreCase(c2) * multiplier
+ }
+
+ def compareDouble(o1: RowData, o2: RowData, column: Column, direction: Char): Int = {
+ val c1 = o1.get(column).asInstanceOf[Double]
+ val c2 = o2.get(column).asInstanceOf[Double]
+
+ val lessThan = if (direction == 'A') 1 else -1
+ val greaterThan = if (direction == 'A') -1 else 1
+
+ if (c1 < c2) {
+ lessThan
+ } else if (c1 > c2) {
+ greaterThan
+ } else {
+ 0
+ }
+ }
+
+ def compareBoolean(o1: RowData, o2: RowData, column: Column, direction: Char): Int = {
+ val c1 = o1.get(column).asInstanceOf[Boolean]
+ val c2 = o2.get(column).asInstanceOf[Boolean]
+
+ val lessThan = if (direction == 'A') 1 else -1
+ val greaterThan = if (direction == 'A') -1 else 1
+
+ if (c1 == true && c2 == false) {
+ lessThan
+ } else if (c1 == false && c2 == true) {
+ greaterThan
+ } else {
+ 0
+ }
+ }
+
+ def compareInt(o1: RowData, o2: RowData, column: Column, direction: Char): Int = {
+ val c1 = o1.get(column).asInstanceOf[Int]
+ val c2 = o2.get(column).asInstanceOf[Int]
+
+ val lessThan = if (direction == 'A') 1 else -1
+ val greaterThan = if (direction == 'A') -1 else 1
+
+ if (c1 < c2) {
+ lessThan
+ } else if (c1 > c2) {
+ greaterThan
+ } else {
+ 0
+ }
+ }
+
+ def compareLong(o1: RowData, o2: RowData, column: Column, direction: Char): Int = {
+ val c1 = o1.get(column).asInstanceOf[Long]
+ val c2 = o2.get(column).asInstanceOf[Long]
+
+ val lessThan = if (direction == 'A') 1 else -1
+ val greaterThan = if (direction == 'A') -1 else 1
+
+ if (c1 < c2) {
+ lessThan
+ } else if (c1 > c2) {
+ greaterThan
+ } else {
+ 0
+ }
+ }
+}
diff --git a/vuu/src/main/scala/org/finos/vuu/core/sort/SortImpl.scala b/vuu/src/main/scala/org/finos/vuu/core/sort/SortImpl.scala
new file mode 100644
index 000000000..3447e2a16
--- /dev/null
+++ b/vuu/src/main/scala/org/finos/vuu/core/sort/SortImpl.scala
@@ -0,0 +1,11 @@
+package org.finos.vuu.core.sort
+
+import org.finos.toolbox.time.Clock
+import org.finos.vuu.core.table.Column
+import org.finos.vuu.net.SortSpec
+
+object SortImpl {
+ def apply(spec: SortSpec, columns: List[Column])(implicit clock: Clock): Sort = {
+ GenericSort2(spec, columns)
+ }
+}
diff --git a/vuu/src/main/scala/org/finos/vuu/core/sort/Sorts.scala b/vuu/src/main/scala/org/finos/vuu/core/sort/Sorts.scala
index fd155fb33..7e963d102 100644
--- a/vuu/src/main/scala/org/finos/vuu/core/sort/Sorts.scala
+++ b/vuu/src/main/scala/org/finos/vuu/core/sort/Sorts.scala
@@ -5,7 +5,11 @@ import org.finos.vuu.core.table.{Column, DataType, RowData, ViewPortColumnCreato
import org.finos.vuu.net.SortSpec
import org.finos.vuu.viewport.{RowSource, ViewPortColumns}
import org.finos.toolbox.collection.array.ImmutableArray
+import org.finos.toolbox.time.Clock
+import org.finos.toolbox.time.TimeIt.timeIt
+import java.util
+import java.util.Comparator
import scala.annotation.tailrec
trait Sort {
@@ -51,7 +55,7 @@ case class NumericSort(direction: SortDirection.TYPE, column: Column) extends So
}
}
-case class GenericSort(spec: SortSpec, columns: List[Column]) extends Sort with StrictLogging {
+case class GenericSort2(spec: SortSpec, columns: List[Column])(implicit clock: Clock) extends Sort with StrictLogging {
val sortColumns = spec.sortDefs.map(sdef => sdef.column)
@@ -66,15 +70,67 @@ case class GenericSort(spec: SortSpec, columns: List[Column]) extends Sort with
//val vpColumns = ViewPortColumnCreator.create(source.asTable, columns.map(_.name))
- val snapshot = primaryKeys.toArray.map(key => (key -> source.pullRow(key, vpColumns))).toMap
+ logger.debug("Starting map")
+
+ val (millisToArray, snapshot) = timeIt {
+ primaryKeys.toArray.map(key => source.pullRow(key, vpColumns))
+ }
+
+ logger.debug("Starting sort")
+
+ val (millisSort, _ ) = timeIt {
+
+ util.Arrays.sort(snapshot, new Comparator[RowData] {
+ override def compare(o1: RowData, o2: RowData): Int = {
+ SortCompares.compare(o1, o2, columns, sortDirections, 0)
+ }
+ })
+ }
+
+ logger.debug("Starting build imm arr")
+
+ val (millisImmArray, immutableArray) = timeIt {
+ ImmutableArray.from(snapshot.map(_.key()))
+ }
+
+ logger.info(s"[SORT]: DataToArray: ${millisToArray}ms, Sort: ${millisSort}ms, ImmutArr: ${millisImmArray}ms")
+
+ immutableArray
+ }
+}
+
+case class GenericSort(spec: SortSpec, columns: List[Column])(implicit clock: Clock) extends Sort with StrictLogging {
+
+ val sortColumns = spec.sortDefs.map(sdef => sdef.column)
+
+ val sortDirections = spec.sortDefs.map(sdef => sdef.sortType)
+
+ val sortFn = SortFunctions.sortByFields(columns, sortDirections, _: Map[String, RowData], _: String, _: String)
+
+
+ //val sortFunc =
+
+ override def doSort(source: RowSource, primaryKeys: ImmutableArray[String], vpColumns: ViewPortColumns): ImmutableArray[String] = {
+
+ //val vpColumns = ViewPortColumnCreator.create(source.asTable, columns.map(_.name))
+
+ val (millisToArray, snapshot) = timeIt {
+ primaryKeys.toArray.map(key => (key -> source.pullRow(key, vpColumns))).toMap
+ }
val curried = sortFn(snapshot, _: String, _: String)
- logger.debug(s"sorting ${primaryKeys.length} keys")
+ val (millisSort, sortedArray) = timeIt {
+ primaryKeys.toArray.sortWith(curried)
+ }
+
+ val (millisImmArray, immutableArray) = timeIt {
+ ImmutableArray.from(sortedArray)
+ }
- val sortedArray = primaryKeys.toArray.sortWith(curried)
+ logger.info(s"[SORT]: DataToArray: ${millisToArray}ms, Sort: ${millisSort}ms, ImmutArr: ${millisImmArray}ms")
- ImmutableArray.from(sortedArray)
+ immutableArray
}
}
@@ -143,11 +199,11 @@ object SortFunctions extends StrictLogging {
}
protected def stringSort(a: Any, b: Any, direction: Char): Boolean = {
- if(a == null && b == null){
+ if (a == null && b == null) {
false
- } else if(a == null && b != null){
+ } else if (a == null && b != null) {
true
- }else if(a != null && b == null){
+ } else if (a != null && b == null) {
false
} else if (direction == 'A')
a.asInstanceOf[String] > b.asInstanceOf[String]
diff --git a/vuu/src/main/scala/org/finos/vuu/core/table/Column.scala b/vuu/src/main/scala/org/finos/vuu/core/table/Column.scala
index 7f1441830..e1d98a718 100644
--- a/vuu/src/main/scala/org/finos/vuu/core/table/Column.scala
+++ b/vuu/src/main/scala/org/finos/vuu/core/table/Column.scala
@@ -5,21 +5,22 @@ import org.finos.vuu.core.table.column.CalculatedColumnClause
object DataType {
- val StringDataType: Class[String] = classOf[String]
- val BooleanDataType: Class[Boolean] = classOf[Boolean]
- val IntegerDataType: Class[Int] = classOf[Int]
- val LongDataType: Class[Long] = classOf[Long]
- val DoubleDataType: Class[Double] = classOf[Double]
- val NoDataType: Class[AnyRef] = classOf[AnyRef]
+ final val charDataType: Class[Char] = classOf[Char]
+ final val StringDataType: Class[String] = classOf[String]
+ final val BooleanDataType: Class[Boolean] = classOf[Boolean]
+ final val IntegerDataType: Class[Int] = classOf[Int]
+ final val LongDataType: Class[Long] = classOf[Long]
+ final val DoubleDataType: Class[Double] = classOf[Double]
+ final val NoDataType: Class[AnyRef] = classOf[AnyRef]
def fromString(s: String): Class[_] = {
s.trim.toLowerCase match {
- case "char" => classOf[Char]
- case "string" => classOf[String]
- case "double" => classOf[Double]
- case "boolean" => classOf[Boolean]
- case "int" => classOf[Int]
- case "long" => classOf[Long]
+ case "char" => charDataType
+ case "string" => StringDataType
+ case "double" => DoubleDataType
+ case "boolean" => BooleanDataType
+ case "int" => IntegerDataType
+ case "long" => LongDataType
}
}
diff --git a/vuu/src/main/scala/org/finos/vuu/core/table/SimpleDataTable.scala b/vuu/src/main/scala/org/finos/vuu/core/table/SimpleDataTable.scala
index 6a14a3531..c7c7fded4 100644
--- a/vuu/src/main/scala/org/finos/vuu/core/table/SimpleDataTable.scala
+++ b/vuu/src/main/scala/org/finos/vuu/core/table/SimpleDataTable.scala
@@ -84,6 +84,7 @@ case class RowKeyUpdate(key: String, source: RowSource, isDelete: Boolean = fals
}
trait RowData {
+ def key(): String
def get(field: String): Any
def get(column: Column): Any
def getFullyQualified(column: Column): Any
@@ -141,6 +142,8 @@ case class RowWithData(key: String, data: Map[String, Any]) extends RowData {
object EmptyRowData extends RowData {
+ override def key(): String = null
+
override def size(): Int = 0
override def toArray(columns: List[Column]): Array[Any] = Array()
@@ -201,6 +204,7 @@ case class SimpleDataTableData(data: ConcurrentHashMap[String, RowData], primary
SimpleDataTableData(data, ImmutableArray.empty)
}
}
+
}
diff --git a/vuu/src/main/scala/org/finos/vuu/viewport/ViewPortContainer.scala b/vuu/src/main/scala/org/finos/vuu/viewport/ViewPortContainer.scala
index 0cbca4a2d..b421be1a8 100644
--- a/vuu/src/main/scala/org/finos/vuu/viewport/ViewPortContainer.scala
+++ b/vuu/src/main/scala/org/finos/vuu/viewport/ViewPortContainer.scala
@@ -287,7 +287,7 @@ class ViewPortContainer(val tableContainer: TableContainer, val providerContaine
private def parseSort(sort: SortSpec, vpColumns: ViewPortColumns): Sort = {
if (sort.sortDefs.nonEmpty)
- GenericSort(sort, sort.sortDefs.map(sd => vpColumns.getColumnForName(sd.column).get))
+ SortImpl(sort, sort.sortDefs.map(sd => vpColumns.getColumnForName(sd.column).get))
else
NoSort
}
@@ -614,7 +614,8 @@ class ViewPortContainer(val tableContainer: TableContainer, val providerContaine
case action: BuildEntireTree =>
val oldTree = action.table.getTree
val tree = timeItThen[Tree](
- {TreeBuilder.create(action.table, viewPort.getGroupBy, viewPort.filterSpec, viewPort.getColumns, latestNodeState, action.oldTreeOption, Option(viewPort.getStructure.filtAndSort.sort), action).buildEntireTree()},
+ {
+ TreeBuilder.create(action.table, viewPort.getGroupBy, viewPort.filterSpec, viewPort.getColumns, latestNodeState, action.oldTreeOption, Option(viewPort.getStructure.filtAndSort.sort), action).buildEntireTree()},
(millis, tree) => { updateHistogram(viewPort, treeBuildHistograms, "tree.build.", millis)}
)
val keys = timeItThen[ImmutableArray[String]](
diff --git a/vuu/src/main/scala/org/finos/vuu/viewport/tree/TreeBuildOptimizer.scala b/vuu/src/main/scala/org/finos/vuu/viewport/tree/TreeBuildOptimizer.scala
index e8e4d070c..e7cf956e3 100644
--- a/vuu/src/main/scala/org/finos/vuu/viewport/tree/TreeBuildOptimizer.scala
+++ b/vuu/src/main/scala/org/finos/vuu/viewport/tree/TreeBuildOptimizer.scala
@@ -76,6 +76,7 @@ object TreeBuildOptimizer extends StrictLogging {
val rebuildTree = shouldRebuildTree(viewPort, currentStructureHash, currentUpdateCount)
val recalcKeys = shouldRecalcKeys(latestNodeState, table.getTree.nodeState)
+ //get the previously built tree...
table.getTree match {
//if we have no aggregations initially we don't have to build the whole tree
case EmptyTree if viewPort.getGroupBy.aggregations.isEmpty =>
@@ -87,6 +88,8 @@ object TreeBuildOptimizer extends StrictLogging {
tree.buildAction match {
case Some(action:FastBuildBranchesOfTree) =>
BuildEntireTree(table, Some(tree))
+ case Some(action: OnlyRecalculateTreeKeys) if rebuildTree =>
+ BuildEntireTree(table, Some(tree))
case Some(action:BuildEntireTree) if rebuildTree =>
BuildEntireTree(table, Some(tree))
case Some(action:BuildEntireTree) if !rebuildTree =>
diff --git a/vuu/src/main/scala/org/finos/vuu/viewport/tree/TreeUtils.scala b/vuu/src/main/scala/org/finos/vuu/viewport/tree/TreeUtils.scala
index 8744871af..53de47487 100644
--- a/vuu/src/main/scala/org/finos/vuu/viewport/tree/TreeUtils.scala
+++ b/vuu/src/main/scala/org/finos/vuu/viewport/tree/TreeUtils.scala
@@ -10,6 +10,9 @@ object TreeUtils extends StrictLogging {
if(oldNode.childRowsHash() != newNode.childRowsHash()
|| (NotNull(newState) && (newState != oldState))
|| (NotNull(oldState) && (newState != oldState))
+ //this is a hack to allow the optimization of the tree build,
+ //the first time the tree is built, the child size will be 0, subsequent builds it will be correct
+ || oldNode.getChildren.size() != newNode.getChildren.size()
){
true
}else{
diff --git a/vuu/src/test/scala/org/finos/vuu/core/sort/FilterAndSortFixture.scala b/vuu/src/test/scala/org/finos/vuu/core/sort/FilterAndSortFixture.scala
index 096e77c29..03dc5a54e 100644
--- a/vuu/src/test/scala/org/finos/vuu/core/sort/FilterAndSortFixture.scala
+++ b/vuu/src/test/scala/org/finos/vuu/core/sort/FilterAndSortFixture.scala
@@ -56,7 +56,7 @@ object FilterAndSortFixture {
|""".stripMargin
}
- def doSort(table: SimpleDataTable, sort: GenericSort): List[(String, RowWithData)] = {
+ def doSort(table: SimpleDataTable, sort: Sort): List[(String, RowWithData)] = {
val viewPortColumns = ViewPortColumnCreator.create(table, table.columns().map(_.name).toList)
val result = sort.doSort(table, table.primaryKeys, viewPortColumns)
val vpColumns = ViewPortColumnCreator.create(table, table.columns().map(_.name).toList)
diff --git a/vuu/src/test/scala/org/finos/vuu/core/sort/GenericSortTest.scala b/vuu/src/test/scala/org/finos/vuu/core/sort/GenericSortTest.scala
index 80811caaa..8aae4d7d8 100644
--- a/vuu/src/test/scala/org/finos/vuu/core/sort/GenericSortTest.scala
+++ b/vuu/src/test/scala/org/finos/vuu/core/sort/GenericSortTest.scala
@@ -1,6 +1,7 @@
package org.finos.vuu.core.sort
-import org.finos.vuu.core.table.RowWithData
+import org.finos.toolbox.time.{Clock, TestFriendlyClock}
+import org.finos.vuu.core.table.{Column, RowWithData}
import org.finos.vuu.net.{SortDef, SortSpec}
import org.scalatest.featurespec.AnyFeatureSpec
import org.scalatest.matchers.should.Matchers
@@ -13,9 +14,15 @@ class GenericSortTest extends AnyFeatureSpec with Matchers {
Scenario("test a numeric scala sort") {
+// def sort(spec: SortSpec, columns: List[Column])(implicit clock: Clock) = {
+// SortImpl(spec, columns)
+// }
+
+ implicit val clock: Clock = new TestFriendlyClock(1000)
+
val table = setupTable
- expectRows(doSort(table, GenericSort(SortSpec(List(SortDef("quantity", 'A'), SortDef("orderId", 'D'))), table.columnsForNames("quantity", "orderId")))) {
+ expectRows(doSort(table, SortImpl(SortSpec(List(SortDef("quantity", 'A'), SortDef("orderId", 'D'))), table.columnsForNames("quantity", "orderId")))) {
List(
RowWithData("NYC-0004", Map("tradeTime" -> 5l, "quantity" -> 500.0d, "ric" -> "AAPL.L", "orderId" -> "NYC-0004", "onMkt" -> false, "trader" -> "chris", "ccyCross" -> "GBPUSD")),
RowWithData("LDN-0001", Map("tradeTime" -> 2l, "quantity" -> 100.0d, "ric" -> "VOD.L", "orderId" -> "LDN-0001", "onMkt" -> true, "trader" -> "chris", "ccyCross" -> "GBPUSD")),
@@ -27,7 +34,7 @@ class GenericSortTest extends AnyFeatureSpec with Matchers {
)
}
- expectRows(doSort(table, GenericSort(SortSpec(List(SortDef("trader", 'A'), SortDef("tradeTime", 'D'))), table.columnsForNames("trader", "tradeTime")))) {
+ expectRows(doSort(table, SortImpl(SortSpec(List(SortDef("trader", 'A'), SortDef("tradeTime", 'D'))), table.columnsForNames("trader", "tradeTime")))) {
List(
RowWithData("LDN-0002",Map("tradeTime" -> 1l,"quantity" -> 100.0d,"ric" -> "BT.L","orderId" -> "LDN-0002","onMkt" -> true,"trader" -> "steve","ccyCross" -> "GBPUSD")),
RowWithData("NYC-0002",Map("tradeTime" -> 6l,"quantity" -> 100.0d,"ric" -> "VOD.L","orderId" -> "NYC-0002","onMkt" -> false,"trader" -> "steve","ccyCross" -> "GBPUSD")),
@@ -39,7 +46,7 @@ class GenericSortTest extends AnyFeatureSpec with Matchers {
)
}
- expectRows(doSort(table, GenericSort(SortSpec(List(SortDef("trader", 'D'), SortDef("tradeTime", 'A'))), table.columnsForNames("trader", "tradeTime")))) {
+ expectRows(doSort(table, SortImpl(SortSpec(List(SortDef("trader", 'D'), SortDef("tradeTime", 'A'))), table.columnsForNames("trader", "tradeTime")))) {
List(
RowWithData("NYC-0004",Map("tradeTime" -> 5l,"quantity" -> 500.0d,"ric" -> "AAPL.L","orderId" -> "NYC-0004","onMkt" -> false,"trader" -> "chris","ccyCross" -> "GBPUSD")),
RowWithData("LDN-0008",Map("tradeTime" -> 5l,"quantity" -> 100.0d,"ric" -> "BT.L","orderId" -> "LDN-0008","onMkt" -> true,"trader" -> "chris","ccyCross" -> "GBPUSD")),
@@ -52,7 +59,7 @@ class GenericSortTest extends AnyFeatureSpec with Matchers {
}
- expectRows(doSort(table, GenericSort(SortSpec(List(SortDef("tradeTime", 'D') )), table.columnsForNames("tradeTime")))) {
+ expectRows(doSort(table, SortImpl(SortSpec(List(SortDef("tradeTime", 'D') )), table.columnsForNames("tradeTime")))) {
List(
RowWithData("LDN-0002",Map("tradeTime" -> 1l,"quantity" -> 100.0d,"ric" -> "BT.L","orderId" -> "LDN-0002","onMkt" -> true,"trader" -> "steve","ccyCross" -> "GBPUSD")),
RowWithData("LDN-0001",Map("tradeTime" -> 2l,"quantity" -> 100.0d,"ric" -> "VOD.L","orderId" -> "LDN-0001","onMkt" -> true,"trader" -> "chris","ccyCross" -> "GBPUSD")),
@@ -66,7 +73,7 @@ class GenericSortTest extends AnyFeatureSpec with Matchers {
val table2 = setupTable2
- expectRows(doSort(table2, GenericSort(SortSpec(List(SortDef("quantity", 'D') )), table2.columnsForNames("quantity")))) {
+ expectRows(doSort(table2, SortImpl(SortSpec(List(SortDef("quantity", 'D') )), table2.columnsForNames("quantity")))) {
List(
RowWithData("NYC-0004",Map("ric" -> "AAPL.L","orderId" -> "NYC-0004","onMkt" -> false,"trader" -> "chris","ccyCross" -> "GBPUSD","tradeTime" -> 5l,"quantity" -> null)),
RowWithData("LDN-0003",Map("ric" -> "VOD.L","orderId" -> "LDN-0003","onMkt" -> true,"trader" -> "chris","ccyCross" -> "GBPUSD","tradeTime" -> 3l,"quantity" -> null)),
diff --git a/vuu/src/test/scala/org/finos/vuu/viewport/AmendViewPortToTreeTest.scala b/vuu/src/test/scala/org/finos/vuu/viewport/AmendViewPortToTreeTest.scala
index 0eaa3d9f4..5e1ec8e7a 100644
--- a/vuu/src/test/scala/org/finos/vuu/viewport/AmendViewPortToTreeTest.scala
+++ b/vuu/src/test/scala/org/finos/vuu/viewport/AmendViewPortToTreeTest.scala
@@ -103,7 +103,7 @@ class AmendViewPortToTreeTest extends AnyFeatureSpec with ViewPortSetup {
assertVpEq(filterByVpId(combineQs(viewPort), viewPort)) {
Table(
("_depth", "_isOpen", "_treeKey", "_isLeaf", "_isOpen", "_caption", "_childCount", "orderId", "trader", "ric", "tradeTime", "quantity", "bid", "ask", "last", "open"),
- (1, false, "$root|chris", false, false, "chris", 2, "", "chris", "", "", "", "", "", "", "")
+ (1, false, "$root|chris", false, false, "chris", 0, "", "chris", "", "", "", "", "", "", "")
)
}
@@ -125,8 +125,8 @@ class AmendViewPortToTreeTest extends AnyFeatureSpec with ViewPortSetup {
Table(
("_depth", "_isOpen", "_treeKey", "_isLeaf", "_isOpen", "_caption", "_childCount", "orderId", "trader", "ric", "tradeTime", "quantity", "bid", "ask", "last", "open"),
//(0, true, "$root", false, true, "", 2, "", "", "", "", "", "", "", "", ""),
- (1, false, "$root|VOD.L", false, false, "VOD.L", 1, "", "", "VOD.L", "", "", "", "", "", ""),
- (1, false, "$root|BT.L", false, false, "BT.L", 1, "", "", "BT.L", "", "", "", "", "", "")
+ (1, false, "$root|VOD.L", false, false, "VOD.L", 0, "", "", "VOD.L", "", "", "", "", "", ""),
+ (1, false, "$root|BT.L", false, false, "BT.L", 0, "", "", "BT.L", "", "", "", "", "", "")
)
}
@@ -226,8 +226,8 @@ class AmendViewPortToTreeTest extends AnyFeatureSpec with ViewPortSetup {
assertVpEq(filterByVpId(combineQs(viewPort), viewPort)) {
Table(
("_depth" ,"_isOpen" ,"_treeKey","_isLeaf" ,"_isOpen" ,"_caption","_childCount","orderId" ,"trader" ,"ric" ,"tradeTime","quantity","bid" ,"ask" ,"last" ,"open" ),
- (1 ,false ,"$root|chris",false ,false ,"chris" ,3 ,"" ,"chris" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ),
- (1 ,false ,"$root|steve",false ,false ,"steve" ,2 ,"" ,"steve" ,"" ,"" ,"" ,"" ,"" ,"" ,"" )
+ (1 ,false ,"$root|chris",false ,false ,"chris" ,0 ,"" ,"chris" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ),
+ (1 ,false ,"$root|steve",false ,false ,"steve" ,0 ,"" ,"steve" ,"" ,"" ,"" ,"" ,"" ,"" ,"" )
)
}
@@ -277,6 +277,7 @@ class AmendViewPortToTreeTest extends AnyFeatureSpec with ViewPortSetup {
(2 ,true ,"$root|BT.L|chris",false ,true ,"chris" ,2 ,"" ,"chris" ,"BT.L" ,"" ,"" ,"" ,"" ,"" ,"" ),
(2 ,false ,"$root|BT.L|steve",false ,false ,"steve" ,2 ,"" ,"steve" ,"BT.L" ,"" ,"" ,"" ,"" ,"" ,"" ),
(1 ,true ,"$root|BT.L",false ,true ,"BT.L" ,2 ,"" ,"" ,"BT.L" ,"" ,"" ,"" ,"" ,"" ,"" ),
+ (1 ,false ,"$root|VOD.L",false ,false ,"VOD.L" ,1 ,"" ,"" ,"VOD.L" ,"" ,"" ,"" ,"" ,"" ,"" ),
(3 ,false ,"$root|BT.L|chris|NYC-0002",true ,false ,"NYC-0002",0 ,"NYC-0002","chris" ,"BT.L" ,1437728400000L,100 ,499.0 ,501.0 ,40 ,null ),
(3 ,false ,"$root|BT.L|chris|NYC-0003",true ,false ,"NYC-0003",0 ,"NYC-0003","chris" ,"BT.L" ,1437728400000L,100 ,499.0 ,501.0 ,40 ,null )
)
diff --git a/vuu/src/test/scala/org/finos/vuu/viewport/ChangeViewPortTest.scala b/vuu/src/test/scala/org/finos/vuu/viewport/ChangeViewPortTest.scala
index 37cb04421..36e5a7ef2 100644
--- a/vuu/src/test/scala/org/finos/vuu/viewport/ChangeViewPortTest.scala
+++ b/vuu/src/test/scala/org/finos/vuu/viewport/ChangeViewPortTest.scala
@@ -116,7 +116,7 @@ class ChangeViewPortTest extends AnyFeatureSpec{
)
}
- val viewPort3 = viewPortContainer.change(RequestId.oneNew(), session, viewPort.id, DefaultRange, vpcolumns2, filterSpec = FilterSpec("ric = VOD.L") )
+ val viewPort3 = viewPortContainer.change(RequestId.oneNew(), session, viewPort.id, DefaultRange, vpcolumns2, filterSpec = FilterSpec("ric = \"VOD.L\"") )
viewPortContainer.runOnce()
diff --git a/vuu/src/test/scala/org/finos/vuu/viewport/VisualLinkedTreeViewPortTest.scala b/vuu/src/test/scala/org/finos/vuu/viewport/VisualLinkedTreeViewPortTest.scala
index 638e487e3..bb454475c 100644
--- a/vuu/src/test/scala/org/finos/vuu/viewport/VisualLinkedTreeViewPortTest.scala
+++ b/vuu/src/test/scala/org/finos/vuu/viewport/VisualLinkedTreeViewPortTest.scala
@@ -58,9 +58,9 @@ class VisualLinkedTreeViewPortTest extends AbstractViewPortTestCase with Matcher
assertVpEqWithMeta(priceUpdates) {
Table(
("sel" ,"_isOpen" ,"_depth" ,"_treeKey","_isLeaf" ,"_childCount","_caption","ric" ,"bid" ,"ask" ,"last" ,"open" ,"exchange"),
- (0 ,false ,1 ,"$root|XLON",false ,1 ,"XLON" ,"" ,"" ,"" ,"" ,"" ,"XLON" ),
- (0 ,false ,1 ,"$root|NYSE",false ,1 ,"NYSE" ,"" ,"" ,"" ,"" ,"" ,"NYSE" ),
- (0 ,false ,1 ,"$root|XAMS",false ,1 ,"XAMS" ,"" ,"" ,"" ,"" ,"" ,"XAMS" )
+ (0 ,false ,1 ,"$root|XLON",false ,0 ,"XLON" ,"" ,"" ,"" ,"" ,"" ,"XLON" ),
+ (0 ,false ,1 ,"$root|NYSE",false ,0 ,"NYSE" ,"" ,"" ,"" ,"" ,"" ,"NYSE" ),
+ (0 ,false ,1 ,"$root|XAMS",false ,0 ,"XAMS" ,"" ,"" ,"" ,"" ,"" ,"XAMS" )
)
}