Skip to content

Commit e9b9bef

Browse files
authored
Updated VP metrics table to use ScaledDecimal (#2086)
1 parent cd1ead6 commit e9b9bef

9 files changed

Lines changed: 100 additions & 36 deletions

File tree

vuu/src/main/scala/org/finos/vuu/core/module/DefaultModule.scala

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package org.finos.vuu.core.module
22

3+
import scala.language.implicitConversions
4+
35
class FieldDefString(str: String) {
46
def double(): String = {
57
str + ":Double"
@@ -25,9 +27,30 @@ class FieldDefString(str: String) {
2527
def string(): String = {
2628
str + ":String"
2729
}
30+
31+
def epochTimestamp(): String = {
32+
str + ":EpochTimestamp"
33+
}
34+
35+
def scaledDecimal2(): String = {
36+
str + ":ScaledDecimal2"
37+
}
38+
39+
def scaledDecimal4(): String = {
40+
str + ":ScaledDecimal4"
41+
}
42+
43+
def scaledDecimal6(): String = {
44+
str + ":ScaledDecimal6"
45+
}
46+
47+
def scaledDecimal8(): String = {
48+
str + ":ScaledDecimal8"
49+
}
50+
2851
}
2952

3053
abstract class DefaultModule {
31-
//pimped string impl for field definition
54+
//advanced string impl for field definition
3255
implicit def stringToFieldDef(s: String): FieldDefString = new FieldDefString(s)
3356
}

vuu/src/main/scala/org/finos/vuu/core/module/metrics/MetricsJVMProvider.scala

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ class MetricsJVMProvider(table: DataTable, viewPortContainer: ViewPortContainer)
1515
metrics: MetricsProvider) extends Provider with StrictLogging {
1616

1717
private val runner = new LifeCycleRunner("MetricsJVMProviderThread", () => runOnce(), minCycleTime = 2_000)
18+
private val bytesToMiB = 1.0 / (1024 * 1024)
1819

1920
lifecycleContainer(this).dependsOn(runner)
2021

@@ -30,16 +31,16 @@ class MetricsJVMProvider(table: DataTable, viewPortContainer: ViewPortContainer)
3031

3132
override val lifecycleId: String = "MetricsJVMProvider"
3233

33-
def toMb(bytes: Long): Double = {
34-
(bytes.toDouble / 1024) / 1024
34+
private def toMb(bytes: Long): Double = {
35+
bytes * bytesToMiB
3536
}
3637

37-
def buildMachineCores(): Map[String, Any] = {
38+
private def buildMachineCores(): Map[String, Any] = {
3839
val processors = Runtime.getRuntime.availableProcessors
3940
Map("cpu-cores" -> processors)
4041
}
4142

42-
def buildHeapData(heap: MemoryUsage): Map[String, Any] = {
43+
private def buildHeapData(heap: MemoryUsage): Map[String, Any] = {
4344
Map(
4445
"mem-type" -> "heap",
4546
"max_MB" -> toMb(heap.getMax),
@@ -49,7 +50,7 @@ class MetricsJVMProvider(table: DataTable, viewPortContainer: ViewPortContainer)
4950
)
5051
}
5152

52-
def buildNonHeapData(nonheap: MemoryUsage): Map[String, Any] = {
53+
private def buildNonHeapData(nonheap: MemoryUsage): Map[String, Any] = {
5354
Map(
5455
"mem-type" -> "nonheap",
5556
"max_MB" -> toMb(nonheap.getMax),

vuu/src/main/scala/org/finos/vuu/core/module/metrics/MetricsModule.scala

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
package org.finos.vuu.core.module.metrics
22

3-
import org.finos.vuu.api.{Indices, TableDef}
4-
import org.finos.vuu.core.module.{DefaultModule, ModuleFactory, TableDefContainer, ViewServerModule}
5-
import org.finos.vuu.core.table.Columns
63
import org.finos.toolbox.jmx.MetricsProvider
74
import org.finos.toolbox.lifecycle.LifecycleContainer
85
import org.finos.toolbox.time.Clock
6+
import org.finos.vuu.api.{Indices, TableDef}
97
import org.finos.vuu.core.module.metrics.MetricsSchema.MetricsTree.all_columns
8+
import org.finos.vuu.core.module.{DefaultModule, ModuleFactory, TableDefContainer, ViewServerModule}
9+
import org.finos.vuu.core.table.Columns
1010

1111
object MetricsSchema{
1212

@@ -92,7 +92,8 @@ object MetricsModule extends DefaultModule {
9292
TableDef(
9393
name = "metricsViewports",
9494
keyField = "id",
95-
columns = Columns.fromNames("id".string(), "table".string(), "structureHash".int(), "updateCount".long(), "keyBuildCount".long(), "mean".double(), "max".double(), "75Perc".double(), "99Perc".double(), "99_9Perc".double()),
95+
columns = Columns.fromNames("id".string(), "table".string(), "structureHash".int(), "updateCount".long(),
96+
"keyBuildCount".long(), "mean".scaledDecimal2(), "max".long(), "75Perc".scaledDecimal4(), "99Perc".scaledDecimal6(), "99_9Perc".scaledDecimal8()),
9697
indices = Indices(),
9798
joinFields = "id"
9899
),

vuu/src/main/scala/org/finos/vuu/core/module/metrics/MetricsTableProvider.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
package org.finos.vuu.core.module.metrics
22

33
import com.typesafe.scalalogging.StrictLogging
4-
import org.finos.vuu.core.table.{DataTable, RowWithData, TableContainer}
5-
import org.finos.vuu.provider.Provider
64
import org.finos.toolbox.jmx.MetricsProvider
75
import org.finos.toolbox.lifecycle.LifecycleContainer
86
import org.finos.toolbox.thread.LifeCycleRunner
97
import org.finos.toolbox.time.Clock
8+
import org.finos.vuu.core.table.{DataTable, RowWithData, TableContainer}
9+
import org.finos.vuu.provider.Provider
1010
import org.finos.vuu.viewport.ViewPortTable
1111

1212
class MetricsTableProvider(table: DataTable, tableContainer: TableContainer)(implicit clock: Clock, lifecycleContainer: LifecycleContainer,
@@ -34,7 +34,7 @@ class MetricsTableProvider(table: DataTable, tableContainer: TableContainer)(imp
3434
table.processUpdate(vpTable.table, RowWithData(vpTable.table, getMetricsData(vpTable)))
3535
)
3636
} catch {
37-
case e: Exception => logger.error("Error occured in metrics", e)
37+
case e: Exception => logger.error("Error occurred in metrics", e)
3838
}
3939
}
4040

vuu/src/main/scala/org/finos/vuu/core/module/metrics/MetricsViewPortProvider.scala

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import org.finos.toolbox.jmx.MetricsProvider
55
import org.finos.toolbox.lifecycle.LifecycleContainer
66
import org.finos.toolbox.thread.LifeCycleRunner
77
import org.finos.toolbox.time.Clock
8+
import org.finos.vuu.core.table.datatype.{Scale, ScaledDecimal}
89
import org.finos.vuu.core.table.{DataTable, RowWithData}
910
import org.finos.vuu.provider.Provider
1011
import org.finos.vuu.viewport.ViewPortContainer
@@ -46,8 +47,17 @@ class MetricsViewPortProvider(table: DataTable, viewPortContainer: ViewPortConta
4647
val snapshot = histogram.getSnapshot
4748
val vp = viewPortContainer.getViewPorts.find(f => f.id == key).orNull
4849
if (vp != null) {
49-
val upMap = Map("id" -> key, "table" -> vp.table.name, "mean" -> snapshot.getMean, "max" -> snapshot.getMax, "structureHash" -> vp.getStructuralHashCode(), "updateCount" -> vp.getTableUpdateCount(),
50-
"keyBuildCount" -> vp.keyBuildCount, "75Perc" -> snapshot.get75thPercentile(), "99Perc" -> snapshot.get99thPercentile(), "99_9Perc" -> snapshot.get999thPercentile()
50+
val upMap = Map(
51+
"id" -> key,
52+
"table" -> vp.table.name,
53+
"mean" -> ScaledDecimal(snapshot.getMean, Scale.Two),
54+
"max" -> snapshot.getMax,
55+
"structureHash" -> vp.getStructuralHashCode(),
56+
"updateCount" -> vp.getTableUpdateCount(),
57+
"keyBuildCount" -> vp.keyBuildCount,
58+
"75Perc" -> ScaledDecimal(snapshot.get75thPercentile(), Scale.Four),
59+
"99Perc" -> ScaledDecimal(snapshot.get99thPercentile(), Scale.Six),
60+
"99_9Perc" -> ScaledDecimal(snapshot.get999thPercentile(), Scale.Eight)
5161
)
5262
table.processUpdate(key, RowWithData(key, upMap))
5363
} else {

vuu/src/main/scala/org/finos/vuu/core/table/datatype/ScaledDecimal.scala

Lines changed: 27 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,33 +8,33 @@ import java.math.BigDecimal as JBigDecimal
88
* that are preserved when converting to a long-based representation.
99
* * @param precision The number of decimal places (e.g., 2 for Scale.Two).
1010
*/
11-
enum Scale(val precision: Int) {
12-
case Two extends Scale(2)
13-
case Four extends Scale(4)
14-
case Six extends Scale(6)
15-
case Eight extends Scale(8)
11+
enum Scale[T <: ScaledDecimal](val precision: Int, val createFunction: Long => T) {
12+
13+
case Two extends Scale[ScaledDecimal2](2, ScaledDecimal2.apply)
14+
case Four extends Scale[ScaledDecimal4](4, ScaledDecimal4.apply)
15+
case Six extends Scale[ScaledDecimal6](6, ScaledDecimal6.apply)
16+
case Eight extends Scale[ScaledDecimal8](8, ScaledDecimal8.apply)
1617

1718
/**
1819
* Creates a [[ScaledDecimal]] instance by shifting the decimal point of the
1920
* input value and truncating to a Long.
2021
* * @param value The Java BigDecimal to convert.
2122
* @return A specialized ScaledDecimal implementation (e.g., [[ScaledDecimal2]]).
2223
*/
23-
def create(value: JBigDecimal): ScaledDecimal = this match
24-
case Two => ScaledDecimal2(value.movePointRight(precision).longValue())
25-
case Four => ScaledDecimal4(value.movePointRight(precision).longValue())
26-
case Six => ScaledDecimal6(value.movePointRight(precision).longValue())
27-
case Eight => ScaledDecimal8(value.movePointRight(precision).longValue())
24+
def create(value: JBigDecimal): T = {
25+
createFunction(value.movePointRight(precision).longValue())
26+
}
27+
2828
}
2929

3030
/**
3131
* Static constants for [[Scale]] to provide idiomatic access for Java callers.
3232
*/
3333
object Scale {
34-
val TWO: Scale = Scale.Two
35-
val FOUR: Scale = Scale.Four
36-
val SIX: Scale = Scale.Six
37-
val EIGHT: Scale = Scale.Eight
34+
val TWO: Scale[ScaledDecimal2] = Scale.Two
35+
val FOUR: Scale[ScaledDecimal4] = Scale.Four
36+
val SIX: Scale[ScaledDecimal6] = Scale.Six
37+
val EIGHT: Scale[ScaledDecimal8] = Scale.Eight
3838
}
3939

4040
/**
@@ -52,19 +52,30 @@ sealed trait ScaledDecimal {
5252
*/
5353
object ScaledDecimal {
5454

55+
/**
56+
* Creates a ScaledDecimal from a Double.
57+
* @param value The value to scale.
58+
* @param scale The target precision.
59+
*/
60+
def apply[T <: ScaledDecimal](value: Double, scale: Scale[T]): T =
61+
scale.create(JBigDecimal.valueOf(value))
62+
5563
/**
5664
* Creates a ScaledDecimal from a Scala BigDecimal.
5765
* @param value The value to scale.
5866
* @param scale The target precision.
5967
*/
60-
def apply(value: BigDecimal, scale: Scale): ScaledDecimal = scale.create(value.underlying())
68+
def apply[T <: ScaledDecimal](value: BigDecimal, scale: Scale[T]): T =
69+
scale.create(value.underlying())
6170

6271
/**
6372
* Creates a ScaledDecimal from a Java BigDecimal.
6473
* @param value The value to scale.
6574
* @param scale The target precision.
6675
*/
67-
def apply(value: JBigDecimal, scale: Scale): ScaledDecimal = scale.create(value)
76+
def apply[T <: ScaledDecimal](value: JBigDecimal, scale: Scale[T]): T =
77+
scale.create(value)
78+
6879
}
6980

7081
/**

vuu/src/main/scala/org/finos/vuu/net/json/RowUpdateSerializer.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ class RowUpdateSerializer extends JsonSerializer[RowUpdate] with StrictLogging
5252
case (s: String, _) => gen.writeString(s)
5353
case (i: Int, _) => gen.writeNumber(i)
5454
case (d: Double, _) => gen.writeNumber(d)
55-
case (l: Long, _) => gen.writeNumber(l)
55+
case (l: Long, _) => gen.writeString(l.toString)
5656
case (b: Boolean, _) => gen.writeBoolean(b)
5757
case (c: Char, _) => gen.writeString(c.toString)
5858
case (epoch: EpochTimestamp, _) => gen.writeNumber(epoch.millis)

vuu/src/test/scala/org/finos/vuu/core/table/datatype/ScaledDecimalTest.scala

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,22 @@ class ScaledDecimalTest extends AnyFeatureSpec with Matchers with GivenWhenThen
5353
result.scaledValue shouldBe expected
5454
}
5555
}
56+
57+
Scenario("Handling Double inputs") {
58+
val javaTestCases = Table(
59+
("input", "scale", "expectedValue"),
60+
(10.50d, Scale.Two, 1050L),
61+
(1.1234d, Scale.Four, 11234L),
62+
(0.123456d, Scale.Six, 123456L),
63+
(0.01234567d, Scale.Eight, 1234567L),
64+
)
65+
66+
forAll(javaTestCases) { (jVal, scale, expected) =>
67+
val result = ScaledDecimal(jVal, scale)
68+
result.scaledValue shouldBe expected
69+
}
70+
}
71+
5672
}
5773

5874
Feature("Comparison and Ordering") {

vuu/src/test/scala/org/finos/vuu/net/json/RowUpdateSerializerTest.scala

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,9 @@ class RowUpdateSerializerTest extends AnyFeatureSpec with Matchers with StrictLo
2626
"bar",
2727
1,
2828
BigInt(123), //Unsupported by Vuu
29-
EpochTimestamp(456),
30-
ScaledDecimal2(567)
29+
EpochTimestamp(456L),
30+
ScaledDecimal2(567L),
31+
678L,
3132
)
3233
)
3334

@@ -41,7 +42,7 @@ class RowUpdateSerializerTest extends AnyFeatureSpec with Matchers with StrictLo
4142

4243
serialized shouldEqual "{\"viewPortId\":\"Vp1\",\"vpSize\":1,\"rowIndex\":0,\"rowKey\":\":KEY1\"," +
4344
"\"updateType\":\"U\",\"ts\":100,\"sel\":0,\"vpVersion\":\"Request1\"," +
44-
"\"data\":[\"foo\",\"bar\",1,\"\",456,\"567\"]}"
45+
"\"data\":[\"foo\",\"bar\",1,\"\",456,\"567\",\"678\"]}"
4546

4647
val deserialized = mapper.readValue(serialized, classOf[RowUpdate])
4748

@@ -54,13 +55,14 @@ class RowUpdateSerializerTest extends AnyFeatureSpec with Matchers with StrictLo
5455
deserialized.ts shouldEqual rowUpdate.ts
5556
deserialized.selected shouldEqual rowUpdate.selected
5657

57-
deserialized.data.length shouldEqual 6
58+
deserialized.data.length shouldEqual 7
5859
deserialized.data(0) shouldEqual "foo"
5960
deserialized.data(1) shouldEqual "bar"
6061
deserialized.data(2) shouldEqual "1"
6162
deserialized.data(3) shouldEqual ""
6263
deserialized.data(4) shouldEqual "456"
6364
deserialized.data(5) shouldEqual "567"
65+
deserialized.data(6) shouldEqual "678"
6466
}
6567

6668
}

0 commit comments

Comments
 (0)