!cdd #18328 optimize VersionVector for size 1 (typical dots)

AFTER:

[info] Benchmark                                  (set1Size)   Mode  Cnt     Score     Error   Units
[info] ORSetMergeBenchmark.mergeAddFromBothNodes           1  thrpt   10  2007.939 ±  74.673  ops/ms
[info] ORSetMergeBenchmark.mergeAddFromBothNodes          10  thrpt   10   337.110 ±  15.055  ops/ms
[info] ORSetMergeBenchmark.mergeAddFromBothNodes          20  thrpt   10   223.600 ±   8.403  ops/ms
[info] ORSetMergeBenchmark.mergeAddFromBothNodes         100  thrpt   10    46.697 ±   2.136  ops/ms
[info] ORSetMergeBenchmark.mergeAddFromOtherNode           1  thrpt   10  2542.537 ± 120.697  ops/ms
[info] ORSetMergeBenchmark.mergeAddFromOtherNode          10  thrpt   10   365.694 ±  17.571  ops/ms
[info] ORSetMergeBenchmark.mergeAddFromOtherNode          20  thrpt   10   216.323 ±   9.446  ops/ms
[info] ORSetMergeBenchmark.mergeAddFromOtherNode         100  thrpt   10    49.563 ±   2.725  ops/ms
[info] ORSetMergeBenchmark.mergeAddFromSameNode            1  thrpt   10  9883.186 ± 725.672  ops/ms
[info] ORSetMergeBenchmark.mergeAddFromSameNode           10  thrpt   10  3266.528 ± 189.993  ops/ms
[info] ORSetMergeBenchmark.mergeAddFromSameNode           20  thrpt   10  3206.017 ± 124.623  ops/ms
[info] ORSetMergeBenchmark.mergeAddFromSameNode          100  thrpt   10  2709.031 ± 162.182  ops/ms
[info] ORSetMergeBenchmark.mergeComplex                    1  thrpt   10   572.704 ±  21.504  ops/ms
[info] ORSetMergeBenchmark.mergeComplex                   10  thrpt   10   249.226 ±  12.324  ops/ms
[info] ORSetMergeBenchmark.mergeComplex                   20  thrpt   10   170.560 ±  10.320  ops/ms
[info] ORSetMergeBenchmark.mergeComplex                  100  thrpt   10    46.373 ±   1.800  ops/ms

BEFORE:

[info] Benchmark                                  (set1Size)   Mode  Cnt     Score     Error   Units
[info] ORSetMergeBenchmark.mergeAddFromBothNodes           1  thrpt   10   885.664 ±  99.718  ops/ms
[info] ORSetMergeBenchmark.mergeAddFromBothNodes          10  thrpt   10   304.617 ±   4.755  ops/ms
[info] ORSetMergeBenchmark.mergeAddFromBothNodes          20  thrpt   10   200.977 ±   3.708  ops/ms
[info] ORSetMergeBenchmark.mergeAddFromBothNodes         100  thrpt   10    47.879 ±   4.352  ops/ms
[info] ORSetMergeBenchmark.mergeAddFromOtherNode           1  thrpt   10  1586.848 ±  27.476  ops/ms
[info] ORSetMergeBenchmark.mergeAddFromOtherNode          10  thrpt   10   354.408 ±   4.772  ops/ms
[info] ORSetMergeBenchmark.mergeAddFromOtherNode          20  thrpt   10   210.563 ±  32.914  ops/ms
[info] ORSetMergeBenchmark.mergeAddFromOtherNode         100  thrpt   10    52.750 ±   0.698  ops/ms
[info] ORSetMergeBenchmark.mergeAddFromSameNode            1  thrpt   10  3915.817 ± 420.643  ops/ms
[info] ORSetMergeBenchmark.mergeAddFromSameNode           10  thrpt   10  2369.476 ± 250.336  ops/ms
[info] ORSetMergeBenchmark.mergeAddFromSameNode           20  thrpt   10  2378.924 ±  47.160  ops/ms
[info] ORSetMergeBenchmark.mergeAddFromSameNode          100  thrpt   10  2167.841 ±  20.339  ops/ms
[info] ORSetMergeBenchmark.mergeComplex                    1  thrpt   10   387.261 ±   8.820  ops/ms
[info] ORSetMergeBenchmark.mergeComplex                   10  thrpt   10   212.661 ±   4.802  ops/ms
[info] ORSetMergeBenchmark.mergeComplex                   20  thrpt   10   151.512 ±   2.627  ops/ms
[info] ORSetMergeBenchmark.mergeComplex                  100  thrpt   10    40.976 ±   2.014  ops/ms

* use subtype polymorphism for VersionVector

tmp
This commit is contained in:
Patrik Nordwall 2015-09-21 13:09:19 +02:00
parent 94294c74a7
commit c11b600cc1
9 changed files with 305 additions and 96 deletions

View file

@ -54,20 +54,28 @@ object ORSet {
remaining match {
case Nil acc
case (d @ (node, v1)) :: rest
vvector.versions.get(node) match {
case Some(v2) if v2 >= v1
// dot is dominated by version vector, drop it
dropDots(rest, acc)
case _
dropDots(rest, d :: acc)
}
val v2 = vvector.versionAt(node)
if (v2 >= v1)
// dot is dominated by version vector, drop it
dropDots(rest, acc)
else
dropDots(rest, d :: acc)
}
if (dot.versions.isEmpty)
if (dot.isEmpty)
VersionVector.empty
else {
val newDots = dropDots(dot.versions.toList, Nil)
new VersionVector(versions = VersionVector.emptyVersions ++ newDots)
dot match {
case OneVersionVector(node, v1)
// if dot is dominated by version vector, drop it
if (vvector.versionAt(node) >= v1) VersionVector.empty
else dot
case ManyVersionVector(vs)
val remaining = vs.toList
val newDots = dropDots(remaining, Nil)
VersionVector(newDots)
}
}
}
@ -82,24 +90,60 @@ object ORSet {
commonKeys.foldLeft(Map.empty[A, ORSet.Dot]) {
case (acc, k)
val lhsDots = lhs.elementsMap(k)
val lhsDotsVersions = lhsDots.versions
val rhsDotsVersions = rhs.elementsMap(k).versions
if (lhsDotsVersions.size == 1 && rhsDotsVersions.size == 1 && lhsDotsVersions.head == rhsDotsVersions.head) {
// one single common dot
acc.updated(k, lhsDots)
} else {
val commonDots = lhsDotsVersions.filter {
case (thisDotNode, v) rhsDotsVersions.get(thisDotNode).exists(_ == v)
}
val commonDotsKeys = commonDots.keys
val lhsUniqueDots = lhsDotsVersions -- commonDotsKeys
val rhsUniqueDots = rhsDotsVersions -- commonDotsKeys
val lhsKeep = ORSet.subtractDots(new VersionVector(lhsUniqueDots), rhs.vvector)
val rhsKeep = ORSet.subtractDots(new VersionVector(rhsUniqueDots), lhs.vvector)
val merged = lhsKeep.merge(rhsKeep).merge(new VersionVector(versions = commonDots))
// Perfectly possible that an item in both sets should be dropped
if (merged.versions.isEmpty) acc
else acc.updated(k, merged)
val rhsDots = rhs.elementsMap(k)
(lhsDots, rhsDots) match {
case (OneVersionVector(n1, v1), OneVersionVector(n2, v2))
if (n1 == n2 && v1 == v2)
// one single common dot
acc.updated(k, lhsDots)
else {
// no common, lhsUniqueDots == lhsDots, rhsUniqueDots == rhsDots
val lhsKeep = ORSet.subtractDots(lhsDots, rhs.vvector)
val rhsKeep = ORSet.subtractDots(rhsDots, lhs.vvector)
val merged = lhsKeep.merge(rhsKeep)
// Perfectly possible that an item in both sets should be dropped
if (merged.isEmpty) acc
else acc.updated(k, merged)
}
case (ManyVersionVector(lhsVs), ManyVersionVector(rhsVs))
val commonDots = lhsVs.filter {
case (thisDotNode, v) rhsVs.get(thisDotNode).exists(_ == v)
}
val commonDotsKeys = commonDots.keys
val lhsUniqueDots = lhsVs -- commonDotsKeys
val rhsUniqueDots = rhsVs -- commonDotsKeys
val lhsKeep = ORSet.subtractDots(VersionVector(lhsUniqueDots), rhs.vvector)
val rhsKeep = ORSet.subtractDots(VersionVector(rhsUniqueDots), lhs.vvector)
val merged = lhsKeep.merge(rhsKeep).merge(VersionVector(commonDots))
// Perfectly possible that an item in both sets should be dropped
if (merged.isEmpty) acc
else acc.updated(k, merged)
case (ManyVersionVector(lhsVs), OneVersionVector(n2, v2))
val commonDots = lhsVs.filter {
case (n1, v1) v1 == v2 && n1 == n2
}
val commonDotsKeys = commonDots.keys
val lhsUniqueDots = lhsVs -- commonDotsKeys
val rhsUnique = if (commonDotsKeys.isEmpty) rhsDots else VersionVector.empty
val lhsKeep = ORSet.subtractDots(VersionVector(lhsUniqueDots), rhs.vvector)
val rhsKeep = ORSet.subtractDots(rhsUnique, lhs.vvector)
val merged = lhsKeep.merge(rhsKeep).merge(VersionVector(commonDots))
// Perfectly possible that an item in both sets should be dropped
if (merged.isEmpty) acc
else acc.updated(k, merged)
case (OneVersionVector(n1, v1), ManyVersionVector(rhsVs))
val commonDots = rhsVs.filter {
case (n2, v2) v1 == v2 && n1 == n2
}
val commonDotsKeys = commonDots.keys
val lhsUnique = if (commonDotsKeys.isEmpty) lhsDots else VersionVector.empty
val rhsUniqueDots = rhsVs -- commonDotsKeys
val lhsKeep = ORSet.subtractDots(lhsUnique, rhs.vvector)
val rhsKeep = ORSet.subtractDots(VersionVector(rhsUniqueDots), lhs.vvector)
val merged = lhsKeep.merge(rhsKeep).merge(VersionVector(commonDots))
// Perfectly possible that an item in both sets should be dropped
if (merged.isEmpty) acc
else acc.updated(k, merged)
}
}
}
@ -199,7 +243,7 @@ final class ORSet[A] private[akka] (
*/
private[akka] def add(node: UniqueAddress, element: A): ORSet[A] = {
val newVvector = vvector + node
val newDot = new VersionVector(versions = TreeMap(node -> newVvector.versions(node)))
val newDot = VersionVector(node, newVvector.versionAt(node))
assignAncestor(new ORSet(elementsMap = elementsMap.updated(element, newDot), vvector = newVvector))
}