Skip to content

Commit

Permalink
hide a lot of complexity inside Consensus type class
Browse files Browse the repository at this point in the history
  • Loading branch information
haaase committed Sep 25, 2024
1 parent 6050059 commit e38c3fb
Show file tree
Hide file tree
Showing 6 changed files with 35 additions and 47 deletions.
6 changes: 0 additions & 6 deletions Modules/RDTs/.jvm/src/test/scala/MembershipSuite.scala
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,6 @@ class MembershipSpec[A: Arbitrary, C[_]: Consensus, D[_]: Consensus](
writeFreq: Int,
addMemberFreq: Int,
removeMemberFreq: Int
)(using
Bottom[C[Set[Uid]]],
Bottom[D[A]],
Lattice[C[Set[Uid]]],
Lattice[D[A]],
Lattice[Membership[A, C, D]]
) extends CommandsARDTs[Membership[A, C, D]] {
// given logger: Logger = Logger(level = Level.Info)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package rdts.datatypes.experiments.protocols

import rdts.base.{LocalUid, Uid}
import rdts.base.{Bottom, Lattice, LocalUid, Uid}

// Type class for consensus algorithms
trait Consensus[C[_]] {
Expand All @@ -10,9 +10,15 @@ trait Consensus[C[_]] {
def init[A](members: Set[Uid]): C[A]
def reset[A](newMembers: Set[Uid]): C[A] = init(newMembers)
extension [A](c: C[A]) def upkeep()(using LocalUid): C[A]
def empty[A]: C[A]
def lattice[A]: Lattice[C[A]]
}

object Consensus {
given lattice[A, C[_]: Consensus]: Lattice[C[A]] = Consensus[C].lattice
given bottom[A, C[_]: Consensus]: Bottom[C[A]] with
override def empty: C[A] = Consensus[C].empty

given syntax: {} with
extension [A, C[_]: Consensus](c: C[A])
def reset(newMembers: Set[Uid]): C[A] = Consensus[C].reset(newMembers)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package rdts.datatypes.experiments.protocols

import rdts.base.LocalUid.replicaId
import rdts.base.{Bottom, Lattice, LocalUid, Uid}
import rdts.datatypes.experiments.protocols.Consensus.syntax
import rdts.base.{Lattice, LocalUid, Uid}
import rdts.datatypes.experiments.protocols.Consensus.{syntax, given}
import rdts.time.Time

class LogHack(on: Boolean) {
Expand All @@ -16,14 +16,15 @@ case class Membership[A, C[_], D[_]](
log: List[A],
membershipChanging: Boolean = false
)(using
Bottom[C[Set[Uid]]],
Bottom[D[A]],
Consensus[C],
Consensus[D],
Lattice[C[Set[Uid]]],
Lattice[D[A]]
Consensus[D]
) {
private def unchanged = Membership.empty[A, C, D].copy(counter = counter)
private def unchanged: Membership[A, C, D] = Membership(
counter = counter,
membersConsensus = Consensus[C].empty,
innerConsensus = Consensus[D].empty,
log = List()
)

override def toString: String =
s"Membership(counter: $counter, members: $currentMembers,log: $log, membershipChanging: $membershipChanging)".stripMargin
Expand Down Expand Up @@ -95,42 +96,20 @@ case class Membership[A, C[_], D[_]](
object Membership {

def init[A, C[_], D[_]](initialMembers: Set[Uid])(using
Bottom[C[Set[Uid]]],
Bottom[D[A]],
Consensus[C],
Consensus[D],
Lattice[C[Set[Uid]]],
Lattice[D[A]],
Consensus[D]
): Membership[A, C, D] =
require(initialMembers.nonEmpty, "initial members can't be empty")
val unchanged = Membership.empty[A, C, D]
unchanged.copy(
membersConsensus = unchanged.membersConsensus.reset(initialMembers),
innerConsensus = unchanged.innerConsensus.reset(initialMembers)
)

def empty[A, C[_], D[_]](using
Bottom[C[Set[Uid]]],
Bottom[D[A]],
Consensus[C],
Consensus[D],
Lattice[C[Set[Uid]]],
Lattice[D[A]],
): Membership[A, C, D] =
Membership(
0,
Bottom[C[Set[Uid]]].empty,
Bottom[D[A]].empty,
Consensus[C].init[Set[Uid]](initialMembers),
Consensus[D].init[A](initialMembers),
List()
)

given lattice[A, C[_], D[_]](using
Bottom[C[Set[Uid]]],
Bottom[D[A]],
Consensus[C],
Consensus[D],
Lattice[C[Set[Uid]]],
Lattice[D[A]],
Consensus[D]
): Lattice[Membership[A, C, D]] with
override def merge(left: Membership[A, C, D], right: Membership[A, C, D]): Membership[A, C, D] =
if left.counter > right.counter then left
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package rdts.datatypes.experiments.protocols

import rdts.base.Lattice.setLattice
import rdts.base.LocalUid.replicaId
import rdts.base.{Bottom, Lattice, LocalUid, Uid}
import rdts.datatypes.GrowOnlySet
import rdts.datatypes.GrowOnlySet.*
import LocalUid.replicaId

import scala.compiletime.{constValue, summonFrom}

Expand Down Expand Up @@ -200,6 +200,10 @@ object Paxos {
override def upkeep()(using LocalUid): Paxos[A] = c.upkeep()
override def init[A](members: GrowOnlySet[Uid]): Paxos[A] = Paxos.init(members = members)

override def empty[A]: Paxos[A] = Paxos.unchanged

override def lattice[A]: Lattice[Paxos[A]] = Paxos.lattice

given bottom[A]: Bottom[Paxos[A]] with
override def empty: Paxos[A] = unchanged[A]
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import rdts.base.{Bottom, Lattice, LocalUid, Uid}
import rdts.datatypes.experiments.protocols.Consensus
import rdts.datatypes.experiments.protocols.simplified.Paxos.given
import rdts.datatypes.{GrowOnlySet, LastWriterWins}

import scala.math.Ordering.Implicits.infixOrderingOps

// message types
Expand Down Expand Up @@ -76,7 +77,7 @@ case class Paxos[A](
.map((p, v) => v)
Paxos.unchanged.copy(
accepts = accepts + Accept(proposal, acceptedValue.getOrElse(v)),
accepted = accepted + Accepted(proposal, replicaId), // I can safely accept my own proposal
accepted = accepted + Accepted(proposal, replicaId), // I can safely accept my own proposal
members = members.updated(replicaId, Some(LastWriterWins.now(v))) // remember proposed value
)
else
Expand Down Expand Up @@ -122,7 +123,7 @@ object Paxos:
else if x.number == y.number then Ordering[Uid].compare(x.proposer, y.proposer)
else -1

given [A]: Lattice[Paxos[A]] = Lattice.derived
given lattice[A]: Lattice[Paxos[A]] = Lattice.derived

given consensus: Consensus[Paxos] with
extension [A](c: Paxos[A])
Expand Down Expand Up @@ -191,5 +192,9 @@ object Paxos:

override def init[A](members: GrowOnlySet[Uid]): Paxos[A] = Paxos.init(members = members)

given bottom[A]: Bottom[Paxos[A]] with
override def empty: Paxos[A] = unchanged[A]
override def empty[A]: Paxos[A] = Paxos.unchanged

override def lattice[A]: Lattice[Paxos[A]] = Paxos.lattice

given bottom: Bottom[Paxos[?]] with
override def empty: Paxos[?] = unchanged
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package test.rdts.protocols

import rdts.base.LocalUid
import rdts.datatypes.experiments.protocols.{LogHack, Membership}
import rdts.datatypes.experiments.protocols.simplified.{MultiRoundVoting, Paxos, SimpleVoting}
import rdts.datatypes.experiments.protocols.{LogHack, Membership}

class MembershipTest extends munit.FunSuite {

Expand Down

0 comments on commit e38c3fb

Please sign in to comment.