SlideShare a Scribd company logo
1 of 116
Download to read offline
atomically {
delete your actors
}
John A. De Goes — @jdegoes
Wiem Zine Elabidine — @wiemzin
The Bank Heist The Hero Become a Hero!
The Bank Heist
Atomically { Delete Your Actors }
Atomically { Delete Your Actors }
Atomically { Delete Your Actors }
The Bank
Atomically { Delete Your Actors }
Atomically { Delete Your Actors }
#1
#1
12
def transfer(from: Account, to: Account,
amount: Amount): Unit = {
if (from.balance >= amount) {
from.balance -= amount
to.balance += amount
} else {
Thread.sleep(100)
transfer(from, to, amount)
}
}
13
def transfer(from: Account, to: Account,
amount: Amount): Unit = {
if (from.balance >= amount) {
from.balance -= amount
to.balance += amount
} else {
Thread.sleep(100)
transfer(from, to, amount)
}
}
14
def transfer(from: Account, to: Account,
amount: Amount): Unit = {
if (from.balance >= amount) {
from.balance -= amount
to.balance += amount
} else {
Thread.sleep(100)
transfer(from, to, amount)
}
}
15
def transfer(from: Account, to: Account,
amount: Amount): Unit = {
if (from.balance >= amount) {
from.balance -= amount
to.balance += amount
} else {
Thread.sleep(100)
transfer(from, to, amount)
}
}
Double-Spend Exploits
$1 M
$1 M
$1 M $2 M
def transfer(from: Account, to: Account,
amount: Amount) = {
if (from.balance >= amount) {
from.balance -= amount
to.balance += amount
} else {
Thread.sleep(100)
transfer(from, to, amount)
}
}
def transfer(from: Account, to: Account,
amount: Amount) = {
if (from.balance >= amount) {
from.balance -= amount
to.balance += amount
} else {
Thread.sleep(100)
transfer(from, to, amount)
}
}
Thread 1 Thread 2
Race Condition Exploit
def transfer(from: Account, to: Account,
amount: Amount) = {
if (from.balance >= amount) {
from.balance -= amount
to.balance += amount
} else {
Thread.sleep(100)
transfer(from, to, amount)
}
}
def transfer(from: Account, to: Account,
amount: Amount) = {
if (from.balance >= amount) {
from.balance -= amount
to.balance += amount
} else {
Thread.sleep(100)
transfer(from, to, amount)
}
}
Thread 1 Thread 2
Race Condition Exploit
Atomically { Delete Your Actors }
20
class Account {
var balance : Amount
var accountID : AccountID
var name : String
val opened : Instant
val status : AccountStatus
val tpe : AccountType
}
balance 200,000
accountID 2816157231
... ...
Main Memory
balance 200,000
accountID 2816157231
... ...
Core 1 Cache
balance 200,000
accountID 2816157231
... ...
Core 2 Cache
def transfer(from: Account, to: Account,
amount: Amount) = {
if (from.balance >= amount) {
from.balance -= amount
to.balance += amount
} else {
Thread.sleep(100)
transfer(from, to, amount)
}
}
def transfer(from: Account, to: Account,
amount: Amount) = {
if (from.balance >= amount) {
from.balance -= amount
to.balance += amount
} else {
Thread.sleep(100)
transfer(from, to, amount)
}
}
Thread 1 Thread 2
Stale Cache Exploit
Atomically { Delete Your Actors }
from.balance -= amount
4: getfield #2
7: invokevirtual #3
10: aload_2
11: invokevirtual #3
14: isub
15: invokestatic #4
18: dup_x1
19: putfield #2
def transfer(from: Account, to: Account,
amount: Amount) = {
if (from.balance >= amount) {
from.balance -= amount
to.balance += amount
} else {
Thread.sleep(100)
transfer(from, to, amount)
}
}
def transfer(from: Account, to: Account,
amount: Amount) = {
if (from.balance >= amount) {
from.balance -= amount
to.balance += amount
} else {
Thread.sleep(100)
transfer(from, to, amount)
}
}
Thread 1 Thread 2
Nonatomic Instruction Exploit
Atomically { Delete Your Actors }
Atomically { Delete Your Actors }
Atomically { Delete Your Actors }
abstract class Account {
trait State {
@volatile var balance: BigDecimal = _
}
val state: State
def modify[A](f: State => A): A = this.synchronized {
val result = f(state)
this.notifyAll()
result
}
def await(): Unit = this.synchronized { this.wait() }
}
def transfer(from: Account, to: Account,
amount: Amount): Unit = {
var loop = true
while (loop) {
from.modify { state =>
if (state.balance >= amount.value) {
state.balance -= amount.value
to.modify(state => state.balance += amount.value)
loop = false
}
else from.await()
}
}
transfer(from, to, amount) transfer(to, from, amount)
Thread 1 Thread 2
Deadlock Exploit
Atomically { Delete Your Actors }
Atomically { Delete Your Actors }
Atomically { Delete Your Actors }
class Account extends Actor {
var balance = Amount.zero
var todos = List.empty[(ActorRef, Message)]
def receive = {
case Deposit(amount) =>
balance = balance + amount.value
sender ! Success(balance)
todos.foreach { case (s, m) => self ! m }
todos = Nil
case v @ Withdraw(amount) =>
if (balance >= amount.value) {
balance = balance - amount.value
sender ! Success(balance)
} else todos = (sender, v) :: todos
case Balance => sender ! Success(balance)
}
}
def transfer(from: ActorRef, to: ActorRef,
amount: Amount)(implicit garbage: Timeout): Unit =
(from ? Withdraw(amount)).flatMap { _ =>
to ? Deposit(amount)
}
Atomically { Delete Your Actors }
for {
john <- johnAccount ? Balance
wiem <- wiemAccount ? Balance
} yield
if (wiem.value > john.value)
transfer(wiem, cafe, amount)
else transfer(john, cafe, amount)
$70
$99
for {
john <- johnAccount ? Balance
wiem <- wiemAccount ? Balance
} yield
if (wiem.value > john.value)
transfer(wiem, cafe, amount)
else transfer(john, cafe, amount)
$70
$6,000,000 $99
for {
john <- johnAccount ? Balance
wiem <- wiemAccount ? Balance
} yield
if (wiem.value > john.value)
transfer(wiem, cafe, amount)
else transfer(john, cafe, amount)
$70
$6,000,000 $99
$70
~$6m
for {
john <- johnAccount ? Balance
wiem <- wiemAccount ? Balance
} yield
if (wiem.value > john.value)
transfer(wiem, cafe, amount)
else transfer(john, cafe, amount)
$10 $99
$70
-$60
for {
john <- johnAccount ? Balance
wiem <- wiemAccount ? Balance
} yield
if (wiem.value > john.value)
transfer(wiem, cafe, amount)
else transfer(john, cafe, amount)
$99
Atomically { Delete Your Actors }
Atomically { Delete Your Actors }
Atomically { Delete Your Actors }
46
def transfer(from : TRef[Account],
to : TRef[Account],
amount : Amount): UIO[Unit] =
atomically {
for {
balance <- from.get
_ <- check(balance >= amount)
_ <- from.update(_ - amount)
_ <- to.update(_ + amount)
} yield ()
}
47
def transfer(from : TRef[Account],
to : TRef[Account],
amount : Amount): UIO[Unit] =
atomically {
for {
balance <- from.get
_ <- check(balance >= amount)
_ <- from.update(_ - amount)
_ <- to.update(_ + amount)
} yield ()
}
48
def transfer(from : TRef[Account],
to : TRef[Account],
amount : Amount): UIO[Unit] =
atomically {
for {
balance <- from.get
_ <- check(balance >= amount)
_ <- from.update(_ - amount)
_ <- to.update(_ + amount)
} yield ()
}
49
def transfer(from : TRef[Account],
to : TRef[Account],
amount : Amount): UIO[Unit] =
atomically {
for {
balance <- from.get
_ <- check(balance >= amount)
_ <- from.update(_ - amount)
_ <- to.update(_ + amount)
} yield ()
}
50
def transfer(from : TRef[Account],
to : TRef[Account],
amount : Amount): UIO[Unit] =
atomically {
for {
balance <- from.get
_ <- check(balance >= amount)
_ <- from.update(_ - amount)
_ <- to.update(_ + amount)
} yield ()
}
51
def transfer(from : TRef[Account],
to : TRef[Account],
amount : Amount): UIO[Unit] =
atomically {
for {
balance <- from.get
_ <- check(balance >= amount)
_ <- from.update(_ - amount)
_ <- to.update(_ + amount)
} yield ()
}
Atomically { Delete Your Actors }
The Hero
STM: Software Transactional Memory
Provides the ability to atomically commit a series of
reads and writes to transactional memory when a set
of conditions is satisfied.
STM
STM
...Op 2Op 1 Op n
Final
State
Initial
State
commit
failure - rollback
retry - rollback
complete complete
STM
STM[E, A]
A transaction,
which models
reads & writes,
and can fail, retry,
or succeed.
TRef[A]
A transactional
reference, which
is read & written
inside STM
transactions.
STM[E, A]
Succeed with a
value of type A
Fail with an
error of type E
STM
STM
STM[E, A]
A transaction,
which models
reads & writes,
and can fail, retry,
or succeed.
TRef[A]
A transactional
reference, which
is read & written
inside STM
transactions.
TRef[A]
An immutable value
of type A
STM
STM
STM
STM
STM
Composable
trait TRef[A] {
val get: STM[Nothing, A]
def set(newValue: A): STM[Nothing, Unit]
def update(f: A => A): STM[Nothing, A]
def modify[B](f: A => (B, A)): STM[Nothing, B]
}
object TRef {
def make[A](a: A): STM[Nothing, TRef[A]]
}
TRef
trait TRef[A] {
val get: STM[Nothing, A]
def set(newValue: A): STM[Nothing, Unit]
def update(f: A => A): STM[Nothing, A]
def modify[B](f: A => (B, A)): STM[Nothing, B]
}
object TRef {
def make[A](a: A): STM[Nothing, TRef[A]]
}
TRef
trait TRef[A] {
val get: STM[Nothing, A]
def set(newValue: A): STM[Nothing, Unit]
def update(f: A => A): STM[Nothing, A]
def modify[B](f: A => (B, A)): STM[Nothing, B]
}
object TRef {
def make[A](a: A): STM[Nothing, TRef[A]]
}
TRef
trait TRef[A] {
val get: STM[Nothing, A]
def set(newValue: A): STM[Nothing, Unit]
def update(f: A => A): STM[Nothing, A]
def modify[B](f: A => (B, A)): STM[Nothing, B]
}
object TRef {
def make[A](a: A): STM[Nothing, TRef[A]]
}
TRef
trait TRef[A] {
val get: STM[Nothing, A]
def set(newValue: A): STM[Nothing, Unit]
def update(f: A => A): STM[Nothing, A]
def modify[B](f: A => (B, A)): STM[Nothing, B]
}
object TRef {
def make[A](a: A): STM[Nothing, TRef[A]]
}
TRef
trait STM[+E, +A] {
def commit: IO[E, A] = STM.atomically { this }
}
object STM {
def atomically[E, A](stm: STM[E, A]): IO[E, A]
}
STM - Commit
val hello: STM[Nothing, String] =
STM.succeed("Welcome to Scalar")
STM - Succeed
val sumBalances: STM[Nothing, Int] =
balance1.get.flatMap(a =>
balance2.get.map(b => a + b))
STM - map & flatMap
val sumBalances: STM[Nothing, Int] =
for {
a <- balance1.get
b <- balance2.get
} yield a + b
STM - map & flatMap
STM - Fail
def debit(sender: TRef[Amount], amount: Amount):
STM[String, Amount] =
for {
balance <- sender.update(_ - amount)
_ <- if (balance < 0) STM.fail("Insufficient funds")
else STM.succeed(())
} yield balance
def debitSuccess(sender: TRef[Amount],
amount: Amount): STM[Nothing, Boolean] =
debit(sender, amount).fold(_ => false, _ => true)
STM - Fold
def debitWithBalance(sender: TRef[Amount],
amount: Amount): STM[Nothing, Amount] =
debit(sender, amount)
.foldM(
_ => sender.get,
_ => sender.get)
STM - FoldM
def awaitTicket(tref: TRef[Option[Ticket]]): STM[Nothing, Ticket] =
for {
option <- tref.get
ticket <- option match {
case None => STM.retry
case Some(ticket) => STM.succeed(ticket)
}
} yield ticket
STM - Retry
def tripTickets: STM[Nothing, (Ticket, Ticket)] =
awaitTicket(toWarsaw) zip awaitTicket(toHome)
STM - Zip
def bid(price : Amount,
org : TRef[TravelCompany]): STM[Nothing, Ticket] =
for {
v <- org.get
_ <- STM.check(v.availTix.exists(_.price <= price))
ticket = findCheapest(v, price)
_ <- org.update(_.removeTix(ticket))
} yield ticket
STM - Check
STM - Filter
def bid(price : Amount,
org : TRef[TravelCompany]): STM[Nothing, Ticket] =
for {
v <- org.get.filter(_.availTix.exists(_.price <= price))
ticket = findCheapest(v, price)
_ <- org.update(_.removeTix(ticket))
} yield ticket
val trainOrAirplane: STM[Nothing, Ticket] =
bid(25.00, Railway) orElse bid(50.00, Airline)
STM - Choice
def checkIn(passengers: TRef[List[Person]]): STM[Nothing, Person] =
for {
head <- passengers.get.collect { case head :: tail => head }
_ <- passengers.update(_.drop(1))
} yield head
STM - Collect
STM
STM
STM
STM
Composable Easy to Reason About
def transfer(from : TRef[Account],
to : TRef[Account],
amount : Amount): UIO[Unit] =
atomically {
for {
balance <- from.get
_ <- check(balance >= amount)
_ <- from.update(_ - amount)
_ <- to.update(_ + amount)
} yield ()
}
Become a Hero
Semaphore
Thread #2 holds
1 permit
Thread #1 holds
2 permits
Thread #3 waits
for 4 permits
Semaphore
6 permits
Semaphore
7 contributors
11 months+
301 lines of code
Semaphore
type Semaphore = TRef[Int]
Semaphore
def makeSemaphore(n: Int): UIO[Semaphore] =
TRef.make(n).commit
Semaphore
def acquire(semaphore: Semaphore, n: Int): UIO[Unit] =
(for {
value <- semaphore.get
_ <- STM.check(value >= n)
_ <- semaphore.set(value - n)
} yield ()).commit
Semaphore
def acquire(semaphore: Semaphore, n: Int): UIO[Unit] =
(for {
value <- semaphore.get
_ <- STM.check(value >= n)
_ <- semaphore.set(value - n)
} yield ()).commit
Semaphore
def acquire(semaphore: Semaphore, n: Int): UIO[Unit] =
(for {
value <- semaphore.get
_ <- STM.check(value >= n)
_ <- semaphore.set(value - n)
} yield ()).commit
Semaphore
def acquire(semaphore: Semaphore, n: Int): UIO[Unit] =
(for {
value <- semaphore.get
_ <- STM.check(value >= n)
_ <- semaphore.set(value - n)
} yield ()).commit
Semaphore
def release(semaphore: Semaphore, n: Int): UIO[Unit] =
semaphore.update(_ + n).commit
Semaphore
1 author (you!)
10 minutes
8 lines of code
Your Semaphore using ZIO!
Promise
Unset Set
Wait Wait Continue Continue
Promise
7 contributors
11 months+
274 lines of code
Promise
type Promise[A] = TRef[Option[A]]
Promise
def makePromise[A]: UIO[Promise[A]] =
TRef.make(None).commit
Promise
def complete[A](promise: Promise[A], v: A): UIO[Boolean] =
(for {
value <- promise.get
change <- value match {
case Some(_) => STM.succeed(false)
case None => promise.set(Some(v)) *>
STM.succeed(true)
}
} yield change).commit
Promise
def complete[A](promise: Promise[A], v: A): UIO[Boolean] =
(for {
value <- promise.get
change <- value match {
case Some(_) => STM.succeed(false)
case None => promise.set(Some(v)) *>
STM.succeed(true)
}
} yield change).commit
Promise
def complete[A](promise: Promise[A], v: A): UIO[Boolean] =
(for {
value <- promise.get
change <- value match {
case Some(_) => STM.succeed(false)
case None => promise.set(Some(v)) *>
STM.succeed(true)
}
} yield change).commit
Promise
def complete[A](promise: Promise[A], v: A): UIO[Boolean] =
(for {
value <- promise.get
change <- value match {
case Some(_) => STM.succeed(false)
case None => promise.set(Some(v)) *>
STM.succeed(true)
}
} yield change).commit
Promise
def await[A](promise: Promise[A]): UIO[A] =
promise.get.collect { case Some(a) => a }.commit
Promise
1 author (you!)
10 minutes
8 lines of code
Your Promise using ZIO!
Queue
Empty Queue
Capacity: 6
Full Queue
Capacity: 6
Offer
(Continue)
Take
(Wait)
Offer
(Wait)
Take
(Continue)
Queue
4 contributors
9 months+
487 lines of code
Queue
case class Queue[A](
capacity : Int,
tref : TRef[ScalaQueue[A]])
Queue
def makeQueue[A](capacity: Int): UIO[Queue[A]] =
TRef.make(ScalaQueue.empty[A]).commit
.map(Queue(capacity, _))
Queue
def offer[A](queue: Queue[A], a: A): UIO[Unit] =
(for {
q <- queue.tref.get
_ <- STM.check(q.length < queue.capacity)
_ <- queue.tref.update(_ enqueue a)
} yield ()).commit
Queue
def offer[A](queue: Queue[A], a: A): UIO[Unit] =
(for {
q <- queue.tref.get
_ <- STM.check(q.length < queue.capacity)
_ <- queue.tref.update(_ enqueue a)
} yield ()).commit
Queue
def offer[A](queue: Queue[A], a: A): UIO[Unit] =
(for {
q <- queue.tref.get
_ <- STM.check(q.length < queue.capacity)
_ <- queue.tref.update(_ enqueue a)
} yield ()).commit
Queue
def offer[A](queue: Queue[A], a: A): UIO[Unit] =
(for {
q <- queue.tref.get
_ <- STM.check(q.length < queue.capacity)
_ <- queue.tref.update(_ enqueue a)
} yield ()).commit
Queue
def take[A](queue: Queue[A]): UIO[A] =
(for {
q <- queue.tref.get
a <- q.dequeueOption match {
case Some((a, as)) =>
queue.tref.set(as) *> STM.succeed(a)
case _ => STM.retry
}
} yield a).commit
Queue
def take[A](queue: Queue[A]): UIO[A] =
(for {
q <- queue.tref.get
a <- q.dequeueOption match {
case Some((a, as)) =>
queue.tref.set(as) *> STM.succeed(a)
case _ => STM.retry
}
} yield a).commit
Queue
def take[A](queue: Queue[A]): UIO[A] =
(for {
q <- queue.tref.get
a <- q.dequeueOption match {
case Some((a, as)) =>
queue.tref.set(as) *> STM.succeed(a)
case _ => STM.retry
}
} yield a).commit
Queue
def take[A](queue: Queue[A]): UIO[A] =
(for {
q <- queue.tref.get
a <- q.dequeueOption match {
case Some((a, as)) =>
queue.tref.set(as) *> STM.succeed(a)
case _ => STM.retry
}
} yield a).commit
Queue
1 author (you)
14 minutes
13 lines of code
Your Queue using ZIO!
Atomically { Delete Your Actors }
Wrap Up
THANK YOU!
LEARN MORE
github.com/scalaz/scalaz-zio
gitter.im/scalaz/scalaz-zio
FOLLOW US
@jdegoes @wiemzin

More Related Content

What's hot

Refactoring Functional Type Classes
Refactoring Functional Type ClassesRefactoring Functional Type Classes
Refactoring Functional Type ClassesJohn De Goes
 
Principled Error Handling with FP
Principled Error Handling with FPPrincipled Error Handling with FP
Principled Error Handling with FPLuka Jacobowitz
 
Testing in the World of Functional Programming
Testing in the World of Functional ProgrammingTesting in the World of Functional Programming
Testing in the World of Functional ProgrammingLuka Jacobowitz
 
Functor, Apply, Applicative And Monad
Functor, Apply, Applicative And MonadFunctor, Apply, Applicative And Monad
Functor, Apply, Applicative And MonadOliver Daff
 
ZIO: Powerful and Principled Functional Programming in Scala
ZIO: Powerful and Principled Functional Programming in ScalaZIO: Powerful and Principled Functional Programming in Scala
ZIO: Powerful and Principled Functional Programming in ScalaWiem Zine Elabidine
 
Advanced Tagless Final - Saying Farewell to Free
Advanced Tagless Final - Saying Farewell to FreeAdvanced Tagless Final - Saying Farewell to Free
Advanced Tagless Final - Saying Farewell to FreeLuka Jacobowitz
 
Scalaz 8: A Whole New Game
Scalaz 8: A Whole New GameScalaz 8: A Whole New Game
Scalaz 8: A Whole New GameJohn De Goes
 
Java 7, 8 & 9 - Moving the language forward
Java 7, 8 & 9 - Moving the language forwardJava 7, 8 & 9 - Moving the language forward
Java 7, 8 & 9 - Moving the language forwardMario Fusco
 
Post-Free: Life After Free Monads
Post-Free: Life After Free MonadsPost-Free: Life After Free Monads
Post-Free: Life After Free MonadsJohn De Goes
 
"Немного о функциональном программирование в JavaScript" Алексей Коваленко
"Немного о функциональном программирование в JavaScript" Алексей Коваленко"Немного о функциональном программирование в JavaScript" Алексей Коваленко
"Немного о функциональном программирование в JavaScript" Алексей КоваленкоFwdays
 
Flying Futures at the same sky can make the sun rise at midnight
Flying Futures at the same sky can make the sun rise at midnightFlying Futures at the same sky can make the sun rise at midnight
Flying Futures at the same sky can make the sun rise at midnightWiem Zine Elabidine
 
Monad Transformers In The Wild
Monad Transformers In The WildMonad Transformers In The Wild
Monad Transformers In The WildStackMob Inc
 
Quark: A Purely-Functional Scala DSL for Data Processing & Analytics
Quark: A Purely-Functional Scala DSL for Data Processing & AnalyticsQuark: A Purely-Functional Scala DSL for Data Processing & Analytics
Quark: A Purely-Functional Scala DSL for Data Processing & AnalyticsJohn De Goes
 
7 Habits For a More Functional Swift
7 Habits For a More Functional Swift7 Habits For a More Functional Swift
7 Habits For a More Functional SwiftJason Larsen
 

What's hot (20)

Refactoring Functional Type Classes
Refactoring Functional Type ClassesRefactoring Functional Type Classes
Refactoring Functional Type Classes
 
Hammurabi
HammurabiHammurabi
Hammurabi
 
Principled Error Handling with FP
Principled Error Handling with FPPrincipled Error Handling with FP
Principled Error Handling with FP
 
Testing in the World of Functional Programming
Testing in the World of Functional ProgrammingTesting in the World of Functional Programming
Testing in the World of Functional Programming
 
ZIO Queue
ZIO QueueZIO Queue
ZIO Queue
 
Berlin meetup
Berlin meetupBerlin meetup
Berlin meetup
 
Functor, Apply, Applicative And Monad
Functor, Apply, Applicative And MonadFunctor, Apply, Applicative And Monad
Functor, Apply, Applicative And Monad
 
ZIO: Powerful and Principled Functional Programming in Scala
ZIO: Powerful and Principled Functional Programming in ScalaZIO: Powerful and Principled Functional Programming in Scala
ZIO: Powerful and Principled Functional Programming in Scala
 
Advanced Tagless Final - Saying Farewell to Free
Advanced Tagless Final - Saying Farewell to FreeAdvanced Tagless Final - Saying Farewell to Free
Advanced Tagless Final - Saying Farewell to Free
 
Pure Future
Pure FuturePure Future
Pure Future
 
Scalaz 8: A Whole New Game
Scalaz 8: A Whole New GameScalaz 8: A Whole New Game
Scalaz 8: A Whole New Game
 
Java 7, 8 & 9 - Moving the language forward
Java 7, 8 & 9 - Moving the language forwardJava 7, 8 & 9 - Moving the language forward
Java 7, 8 & 9 - Moving the language forward
 
Post-Free: Life After Free Monads
Post-Free: Life After Free MonadsPost-Free: Life After Free Monads
Post-Free: Life After Free Monads
 
"Немного о функциональном программирование в JavaScript" Алексей Коваленко
"Немного о функциональном программирование в JavaScript" Алексей Коваленко"Немного о функциональном программирование в JavaScript" Алексей Коваленко
"Немного о функциональном программирование в JavaScript" Алексей Коваленко
 
Zio from Home
Zio from Home Zio from Home
Zio from Home
 
Flying Futures at the same sky can make the sun rise at midnight
Flying Futures at the same sky can make the sun rise at midnightFlying Futures at the same sky can make the sun rise at midnight
Flying Futures at the same sky can make the sun rise at midnight
 
Monad Transformers In The Wild
Monad Transformers In The WildMonad Transformers In The Wild
Monad Transformers In The Wild
 
Quark: A Purely-Functional Scala DSL for Data Processing & Analytics
Quark: A Purely-Functional Scala DSL for Data Processing & AnalyticsQuark: A Purely-Functional Scala DSL for Data Processing & Analytics
Quark: A Purely-Functional Scala DSL for Data Processing & Analytics
 
Fiber supervision in ZIO
Fiber supervision in ZIOFiber supervision in ZIO
Fiber supervision in ZIO
 
7 Habits For a More Functional Swift
7 Habits For a More Functional Swift7 Habits For a More Functional Swift
7 Habits For a More Functional Swift
 

Similar to Atomically { Delete Your Actors }

Monadologie
MonadologieMonadologie
Monadologieleague
 
Dip into Coroutines - KTUG Munich 202303
Dip into Coroutines - KTUG Munich 202303Dip into Coroutines - KTUG Munich 202303
Dip into Coroutines - KTUG Munich 202303Alex Semin
 
Functional Programming with Groovy
Functional Programming with GroovyFunctional Programming with Groovy
Functional Programming with GroovyArturo Herrero
 
ES6 patterns in the wild
ES6 patterns in the wildES6 patterns in the wild
ES6 patterns in the wildJoe Morgan
 
Functional programming techniques in real-world microservices
Functional programming techniques in real-world microservicesFunctional programming techniques in real-world microservices
Functional programming techniques in real-world microservicesAndrás Papp
 
Mutation testing: Too good to be true? (4Developers)
Mutation testing: Too good to be true? (4Developers)Mutation testing: Too good to be true? (4Developers)
Mutation testing: Too good to be true? (4Developers)Piotr Kubowicz
 
Swift, via "swift-2048"
Swift, via "swift-2048"Swift, via "swift-2048"
Swift, via "swift-2048"Austin Zheng
 
Mutation testing: Too good to be true? (Devoxx)
Mutation testing: Too good to be true? (Devoxx)Mutation testing: Too good to be true? (Devoxx)
Mutation testing: Too good to be true? (Devoxx)Piotr Kubowicz
 
A Playful Introduction to Rx
A Playful Introduction to RxA Playful Introduction to Rx
A Playful Introduction to RxAndrey Cheptsov
 
High-Performance Haskell
High-Performance HaskellHigh-Performance Haskell
High-Performance HaskellJohan Tibell
 
Concurrent Application Development using Scala
Concurrent Application Development using ScalaConcurrent Application Development using Scala
Concurrent Application Development using ScalaSiarhiej Siemianchuk
 
Are we ready to Go?
Are we ready to Go?Are we ready to Go?
Are we ready to Go?Adam Dudczak
 

Similar to Atomically { Delete Your Actors } (20)

Monadologie
MonadologieMonadologie
Monadologie
 
Dip into Coroutines - KTUG Munich 202303
Dip into Coroutines - KTUG Munich 202303Dip into Coroutines - KTUG Munich 202303
Dip into Coroutines - KTUG Munich 202303
 
Python Homework Help
Python Homework HelpPython Homework Help
Python Homework Help
 
Clojure workshop
Clojure workshopClojure workshop
Clojure workshop
 
Functional Programming with Groovy
Functional Programming with GroovyFunctional Programming with Groovy
Functional Programming with Groovy
 
Clojure functions examples
Clojure functions examplesClojure functions examples
Clojure functions examples
 
ES6 patterns in the wild
ES6 patterns in the wildES6 patterns in the wild
ES6 patterns in the wild
 
Functional programming techniques in real-world microservices
Functional programming techniques in real-world microservicesFunctional programming techniques in real-world microservices
Functional programming techniques in real-world microservices
 
Mutation testing: Too good to be true? (4Developers)
Mutation testing: Too good to be true? (4Developers)Mutation testing: Too good to be true? (4Developers)
Mutation testing: Too good to be true? (4Developers)
 
SDC - Einführung in Scala
SDC - Einführung in ScalaSDC - Einführung in Scala
SDC - Einführung in Scala
 
ddd+scala
ddd+scaladdd+scala
ddd+scala
 
Swift, via "swift-2048"
Swift, via "swift-2048"Swift, via "swift-2048"
Swift, via "swift-2048"
 
Python Tidbits
Python TidbitsPython Tidbits
Python Tidbits
 
Mutation testing: Too good to be true? (Devoxx)
Mutation testing: Too good to be true? (Devoxx)Mutation testing: Too good to be true? (Devoxx)
Mutation testing: Too good to be true? (Devoxx)
 
A Playful Introduction to Rx
A Playful Introduction to RxA Playful Introduction to Rx
A Playful Introduction to Rx
 
Python Homework Help
Python Homework HelpPython Homework Help
Python Homework Help
 
High-Performance Haskell
High-Performance HaskellHigh-Performance Haskell
High-Performance Haskell
 
Concurrent Application Development using Scala
Concurrent Application Development using ScalaConcurrent Application Development using Scala
Concurrent Application Development using Scala
 
Are we ready to Go?
Are we ready to Go?Are we ready to Go?
Are we ready to Go?
 
Advanced
AdvancedAdvanced
Advanced
 

More from John De Goes

Error Management: Future vs ZIO
Error Management: Future vs ZIOError Management: Future vs ZIO
Error Management: Future vs ZIOJohn De Goes
 
Scalaz Stream: Rebirth
Scalaz Stream: RebirthScalaz Stream: Rebirth
Scalaz Stream: RebirthJohn De Goes
 
Scalaz Stream: Rebirth
Scalaz Stream: RebirthScalaz Stream: Rebirth
Scalaz Stream: RebirthJohn De Goes
 
Orthogonal Functional Architecture
Orthogonal Functional ArchitectureOrthogonal Functional Architecture
Orthogonal Functional ArchitectureJohn De Goes
 
The Design of the Scalaz 8 Effect System
The Design of the Scalaz 8 Effect SystemThe Design of the Scalaz 8 Effect System
The Design of the Scalaz 8 Effect SystemJohn De Goes
 
Streams for (Co)Free!
Streams for (Co)Free!Streams for (Co)Free!
Streams for (Co)Free!John De Goes
 
Halogen: Past, Present, and Future
Halogen: Past, Present, and FutureHalogen: Past, Present, and Future
Halogen: Past, Present, and FutureJohn De Goes
 
All Aboard The Scala-to-PureScript Express!
All Aboard The Scala-to-PureScript Express!All Aboard The Scala-to-PureScript Express!
All Aboard The Scala-to-PureScript Express!John De Goes
 
Getting Started with PureScript
Getting Started with PureScriptGetting Started with PureScript
Getting Started with PureScriptJohn De Goes
 
SlamData - How MongoDB Is Powering a Revolution in Visual Analytics
SlamData - How MongoDB Is Powering a Revolution in Visual AnalyticsSlamData - How MongoDB Is Powering a Revolution in Visual Analytics
SlamData - How MongoDB Is Powering a Revolution in Visual AnalyticsJohn De Goes
 
The Next Great Functional Programming Language
The Next Great Functional Programming LanguageThe Next Great Functional Programming Language
The Next Great Functional Programming LanguageJohn De Goes
 
The Dark Side of NoSQL
The Dark Side of NoSQLThe Dark Side of NoSQL
The Dark Side of NoSQLJohn De Goes
 
First-Class Patterns
First-Class PatternsFirst-Class Patterns
First-Class PatternsJohn De Goes
 
Quirrel & R for Dummies
Quirrel & R for DummiesQuirrel & R for Dummies
Quirrel & R for DummiesJohn De Goes
 
In-Database Predictive Analytics
In-Database Predictive AnalyticsIn-Database Predictive Analytics
In-Database Predictive AnalyticsJohn De Goes
 
Analytics Maturity Model
Analytics Maturity ModelAnalytics Maturity Model
Analytics Maturity ModelJohn De Goes
 
Rise of the scientific database
Rise of the scientific databaseRise of the scientific database
Rise of the scientific databaseJohn De Goes
 

More from John De Goes (20)

Error Management: Future vs ZIO
Error Management: Future vs ZIOError Management: Future vs ZIO
Error Management: Future vs ZIO
 
Scalaz Stream: Rebirth
Scalaz Stream: RebirthScalaz Stream: Rebirth
Scalaz Stream: Rebirth
 
Scalaz Stream: Rebirth
Scalaz Stream: RebirthScalaz Stream: Rebirth
Scalaz Stream: Rebirth
 
ZIO Queue
ZIO QueueZIO Queue
ZIO Queue
 
Orthogonal Functional Architecture
Orthogonal Functional ArchitectureOrthogonal Functional Architecture
Orthogonal Functional Architecture
 
The Design of the Scalaz 8 Effect System
The Design of the Scalaz 8 Effect SystemThe Design of the Scalaz 8 Effect System
The Design of the Scalaz 8 Effect System
 
Streams for (Co)Free!
Streams for (Co)Free!Streams for (Co)Free!
Streams for (Co)Free!
 
MTL Versus Free
MTL Versus FreeMTL Versus Free
MTL Versus Free
 
Halogen: Past, Present, and Future
Halogen: Past, Present, and FutureHalogen: Past, Present, and Future
Halogen: Past, Present, and Future
 
All Aboard The Scala-to-PureScript Express!
All Aboard The Scala-to-PureScript Express!All Aboard The Scala-to-PureScript Express!
All Aboard The Scala-to-PureScript Express!
 
Getting Started with PureScript
Getting Started with PureScriptGetting Started with PureScript
Getting Started with PureScript
 
SlamData - How MongoDB Is Powering a Revolution in Visual Analytics
SlamData - How MongoDB Is Powering a Revolution in Visual AnalyticsSlamData - How MongoDB Is Powering a Revolution in Visual Analytics
SlamData - How MongoDB Is Powering a Revolution in Visual Analytics
 
The Next Great Functional Programming Language
The Next Great Functional Programming LanguageThe Next Great Functional Programming Language
The Next Great Functional Programming Language
 
The Dark Side of NoSQL
The Dark Side of NoSQLThe Dark Side of NoSQL
The Dark Side of NoSQL
 
First-Class Patterns
First-Class PatternsFirst-Class Patterns
First-Class Patterns
 
Quirrel & R for Dummies
Quirrel & R for DummiesQuirrel & R for Dummies
Quirrel & R for Dummies
 
In-Database Predictive Analytics
In-Database Predictive AnalyticsIn-Database Predictive Analytics
In-Database Predictive Analytics
 
Analytics Maturity Model
Analytics Maturity ModelAnalytics Maturity Model
Analytics Maturity Model
 
Rise of the scientific database
Rise of the scientific databaseRise of the scientific database
Rise of the scientific database
 
Fun with automata
Fun with automataFun with automata
Fun with automata
 

Recently uploaded

How to become a GDSC Lead GDSC MI AOE.pptx
How to become a GDSC Lead GDSC MI AOE.pptxHow to become a GDSC Lead GDSC MI AOE.pptx
How to become a GDSC Lead GDSC MI AOE.pptxKaustubhBhavsar6
 
TrustArc Webinar - How to Live in a Post Third-Party Cookie World
TrustArc Webinar - How to Live in a Post Third-Party Cookie WorldTrustArc Webinar - How to Live in a Post Third-Party Cookie World
TrustArc Webinar - How to Live in a Post Third-Party Cookie WorldTrustArc
 
Outage Analysis: March 5th/6th 2024 Meta, Comcast, and LinkedIn
Outage Analysis: March 5th/6th 2024 Meta, Comcast, and LinkedInOutage Analysis: March 5th/6th 2024 Meta, Comcast, and LinkedIn
Outage Analysis: March 5th/6th 2024 Meta, Comcast, and LinkedInThousandEyes
 
Q4 2023 Quarterly Investor Presentation - FINAL - v1.pdf
Q4 2023 Quarterly Investor Presentation - FINAL - v1.pdfQ4 2023 Quarterly Investor Presentation - FINAL - v1.pdf
Q4 2023 Quarterly Investor Presentation - FINAL - v1.pdfTejal81
 
Trailblazer Community - Flows Workshop (Session 2)
Trailblazer Community - Flows Workshop (Session 2)Trailblazer Community - Flows Workshop (Session 2)
Trailblazer Community - Flows Workshop (Session 2)Muhammad Tiham Siddiqui
 
GraphSummit Copenhagen 2024 - Neo4j Vision and Roadmap.pptx
GraphSummit Copenhagen 2024 - Neo4j Vision and Roadmap.pptxGraphSummit Copenhagen 2024 - Neo4j Vision and Roadmap.pptx
GraphSummit Copenhagen 2024 - Neo4j Vision and Roadmap.pptxNeo4j
 
Technical SEO for Improved Accessibility WTS FEST
Technical SEO for Improved Accessibility  WTS FESTTechnical SEO for Improved Accessibility  WTS FEST
Technical SEO for Improved Accessibility WTS FESTBillieHyde
 
Design and Modeling for MySQL SCALE 21X Pasadena, CA Mar 2024
Design and Modeling for MySQL SCALE 21X Pasadena, CA Mar 2024Design and Modeling for MySQL SCALE 21X Pasadena, CA Mar 2024
Design and Modeling for MySQL SCALE 21X Pasadena, CA Mar 2024Alkin Tezuysal
 
Stobox 4: Revolutionizing Investment in Real-World Assets Through Tokenization
Stobox 4: Revolutionizing Investment in Real-World Assets Through TokenizationStobox 4: Revolutionizing Investment in Real-World Assets Through Tokenization
Stobox 4: Revolutionizing Investment in Real-World Assets Through TokenizationStobox
 
Emil Eifrem at GraphSummit Copenhagen 2024 - The Art of the Possible.pptx
Emil Eifrem at GraphSummit Copenhagen 2024 - The Art of the Possible.pptxEmil Eifrem at GraphSummit Copenhagen 2024 - The Art of the Possible.pptx
Emil Eifrem at GraphSummit Copenhagen 2024 - The Art of the Possible.pptxNeo4j
 
The Importance of Indoor Air Quality (English)
The Importance of Indoor Air Quality (English)The Importance of Indoor Air Quality (English)
The Importance of Indoor Air Quality (English)IES VE
 
Key Trends Shaping the Future of Infrastructure.pdf
Key Trends Shaping the Future of Infrastructure.pdfKey Trends Shaping the Future of Infrastructure.pdf
Key Trends Shaping the Future of Infrastructure.pdfCheryl Hung
 
Flow Control | Block Size | ST Min | First Frame
Flow Control | Block Size | ST Min | First FrameFlow Control | Block Size | ST Min | First Frame
Flow Control | Block Size | ST Min | First FrameKapil Thakar
 
Planetek Italia Srl - Corporate Profile Brochure
Planetek Italia Srl - Corporate Profile BrochurePlanetek Italia Srl - Corporate Profile Brochure
Planetek Italia Srl - Corporate Profile BrochurePlanetek Italia Srl
 
Introduction to RAG (Retrieval Augmented Generation) and its application
Introduction to RAG (Retrieval Augmented Generation) and its applicationIntroduction to RAG (Retrieval Augmented Generation) and its application
Introduction to RAG (Retrieval Augmented Generation) and its applicationKnoldus Inc.
 
March Patch Tuesday
March Patch TuesdayMarch Patch Tuesday
March Patch TuesdayIvanti
 
From the origin to the future of Open Source model and business
From the origin to the future of  Open Source model and businessFrom the origin to the future of  Open Source model and business
From the origin to the future of Open Source model and businessFrancesco Corti
 
LF Energy Webinar - Unveiling OpenEEMeter 4.0
LF Energy Webinar - Unveiling OpenEEMeter 4.0LF Energy Webinar - Unveiling OpenEEMeter 4.0
LF Energy Webinar - Unveiling OpenEEMeter 4.0DanBrown980551
 
Scenario Library et REX Discover industry- and role- based scenarios
Scenario Library et REX Discover industry- and role- based scenariosScenario Library et REX Discover industry- and role- based scenarios
Scenario Library et REX Discover industry- and role- based scenariosErol GIRAUDY
 

Recently uploaded (20)

How to become a GDSC Lead GDSC MI AOE.pptx
How to become a GDSC Lead GDSC MI AOE.pptxHow to become a GDSC Lead GDSC MI AOE.pptx
How to become a GDSC Lead GDSC MI AOE.pptx
 
SheDev 2024
SheDev 2024SheDev 2024
SheDev 2024
 
TrustArc Webinar - How to Live in a Post Third-Party Cookie World
TrustArc Webinar - How to Live in a Post Third-Party Cookie WorldTrustArc Webinar - How to Live in a Post Third-Party Cookie World
TrustArc Webinar - How to Live in a Post Third-Party Cookie World
 
Outage Analysis: March 5th/6th 2024 Meta, Comcast, and LinkedIn
Outage Analysis: March 5th/6th 2024 Meta, Comcast, and LinkedInOutage Analysis: March 5th/6th 2024 Meta, Comcast, and LinkedIn
Outage Analysis: March 5th/6th 2024 Meta, Comcast, and LinkedIn
 
Q4 2023 Quarterly Investor Presentation - FINAL - v1.pdf
Q4 2023 Quarterly Investor Presentation - FINAL - v1.pdfQ4 2023 Quarterly Investor Presentation - FINAL - v1.pdf
Q4 2023 Quarterly Investor Presentation - FINAL - v1.pdf
 
Trailblazer Community - Flows Workshop (Session 2)
Trailblazer Community - Flows Workshop (Session 2)Trailblazer Community - Flows Workshop (Session 2)
Trailblazer Community - Flows Workshop (Session 2)
 
GraphSummit Copenhagen 2024 - Neo4j Vision and Roadmap.pptx
GraphSummit Copenhagen 2024 - Neo4j Vision and Roadmap.pptxGraphSummit Copenhagen 2024 - Neo4j Vision and Roadmap.pptx
GraphSummit Copenhagen 2024 - Neo4j Vision and Roadmap.pptx
 
Technical SEO for Improved Accessibility WTS FEST
Technical SEO for Improved Accessibility  WTS FESTTechnical SEO for Improved Accessibility  WTS FEST
Technical SEO for Improved Accessibility WTS FEST
 
Design and Modeling for MySQL SCALE 21X Pasadena, CA Mar 2024
Design and Modeling for MySQL SCALE 21X Pasadena, CA Mar 2024Design and Modeling for MySQL SCALE 21X Pasadena, CA Mar 2024
Design and Modeling for MySQL SCALE 21X Pasadena, CA Mar 2024
 
Stobox 4: Revolutionizing Investment in Real-World Assets Through Tokenization
Stobox 4: Revolutionizing Investment in Real-World Assets Through TokenizationStobox 4: Revolutionizing Investment in Real-World Assets Through Tokenization
Stobox 4: Revolutionizing Investment in Real-World Assets Through Tokenization
 
Emil Eifrem at GraphSummit Copenhagen 2024 - The Art of the Possible.pptx
Emil Eifrem at GraphSummit Copenhagen 2024 - The Art of the Possible.pptxEmil Eifrem at GraphSummit Copenhagen 2024 - The Art of the Possible.pptx
Emil Eifrem at GraphSummit Copenhagen 2024 - The Art of the Possible.pptx
 
The Importance of Indoor Air Quality (English)
The Importance of Indoor Air Quality (English)The Importance of Indoor Air Quality (English)
The Importance of Indoor Air Quality (English)
 
Key Trends Shaping the Future of Infrastructure.pdf
Key Trends Shaping the Future of Infrastructure.pdfKey Trends Shaping the Future of Infrastructure.pdf
Key Trends Shaping the Future of Infrastructure.pdf
 
Flow Control | Block Size | ST Min | First Frame
Flow Control | Block Size | ST Min | First FrameFlow Control | Block Size | ST Min | First Frame
Flow Control | Block Size | ST Min | First Frame
 
Planetek Italia Srl - Corporate Profile Brochure
Planetek Italia Srl - Corporate Profile BrochurePlanetek Italia Srl - Corporate Profile Brochure
Planetek Italia Srl - Corporate Profile Brochure
 
Introduction to RAG (Retrieval Augmented Generation) and its application
Introduction to RAG (Retrieval Augmented Generation) and its applicationIntroduction to RAG (Retrieval Augmented Generation) and its application
Introduction to RAG (Retrieval Augmented Generation) and its application
 
March Patch Tuesday
March Patch TuesdayMarch Patch Tuesday
March Patch Tuesday
 
From the origin to the future of Open Source model and business
From the origin to the future of  Open Source model and businessFrom the origin to the future of  Open Source model and business
From the origin to the future of Open Source model and business
 
LF Energy Webinar - Unveiling OpenEEMeter 4.0
LF Energy Webinar - Unveiling OpenEEMeter 4.0LF Energy Webinar - Unveiling OpenEEMeter 4.0
LF Energy Webinar - Unveiling OpenEEMeter 4.0
 
Scenario Library et REX Discover industry- and role- based scenarios
Scenario Library et REX Discover industry- and role- based scenariosScenario Library et REX Discover industry- and role- based scenarios
Scenario Library et REX Discover industry- and role- based scenarios
 

Atomically { Delete Your Actors }

  • 1. atomically { delete your actors } John A. De Goes — @jdegoes Wiem Zine Elabidine — @wiemzin
  • 2. The Bank Heist The Hero Become a Hero!
  • 10. #1
  • 11. #1
  • 12. 12 def transfer(from: Account, to: Account, amount: Amount): Unit = { if (from.balance >= amount) { from.balance -= amount to.balance += amount } else { Thread.sleep(100) transfer(from, to, amount) } }
  • 13. 13 def transfer(from: Account, to: Account, amount: Amount): Unit = { if (from.balance >= amount) { from.balance -= amount to.balance += amount } else { Thread.sleep(100) transfer(from, to, amount) } }
  • 14. 14 def transfer(from: Account, to: Account, amount: Amount): Unit = { if (from.balance >= amount) { from.balance -= amount to.balance += amount } else { Thread.sleep(100) transfer(from, to, amount) } }
  • 15. 15 def transfer(from: Account, to: Account, amount: Amount): Unit = { if (from.balance >= amount) { from.balance -= amount to.balance += amount } else { Thread.sleep(100) transfer(from, to, amount) } }
  • 17. def transfer(from: Account, to: Account, amount: Amount) = { if (from.balance >= amount) { from.balance -= amount to.balance += amount } else { Thread.sleep(100) transfer(from, to, amount) } } def transfer(from: Account, to: Account, amount: Amount) = { if (from.balance >= amount) { from.balance -= amount to.balance += amount } else { Thread.sleep(100) transfer(from, to, amount) } } Thread 1 Thread 2 Race Condition Exploit
  • 18. def transfer(from: Account, to: Account, amount: Amount) = { if (from.balance >= amount) { from.balance -= amount to.balance += amount } else { Thread.sleep(100) transfer(from, to, amount) } } def transfer(from: Account, to: Account, amount: Amount) = { if (from.balance >= amount) { from.balance -= amount to.balance += amount } else { Thread.sleep(100) transfer(from, to, amount) } } Thread 1 Thread 2 Race Condition Exploit
  • 20. 20 class Account { var balance : Amount var accountID : AccountID var name : String val opened : Instant val status : AccountStatus val tpe : AccountType }
  • 21. balance 200,000 accountID 2816157231 ... ... Main Memory balance 200,000 accountID 2816157231 ... ... Core 1 Cache balance 200,000 accountID 2816157231 ... ... Core 2 Cache
  • 22. def transfer(from: Account, to: Account, amount: Amount) = { if (from.balance >= amount) { from.balance -= amount to.balance += amount } else { Thread.sleep(100) transfer(from, to, amount) } } def transfer(from: Account, to: Account, amount: Amount) = { if (from.balance >= amount) { from.balance -= amount to.balance += amount } else { Thread.sleep(100) transfer(from, to, amount) } } Thread 1 Thread 2 Stale Cache Exploit
  • 24. from.balance -= amount 4: getfield #2 7: invokevirtual #3 10: aload_2 11: invokevirtual #3 14: isub 15: invokestatic #4 18: dup_x1 19: putfield #2
  • 25. def transfer(from: Account, to: Account, amount: Amount) = { if (from.balance >= amount) { from.balance -= amount to.balance += amount } else { Thread.sleep(100) transfer(from, to, amount) } } def transfer(from: Account, to: Account, amount: Amount) = { if (from.balance >= amount) { from.balance -= amount to.balance += amount } else { Thread.sleep(100) transfer(from, to, amount) } } Thread 1 Thread 2 Nonatomic Instruction Exploit
  • 29. abstract class Account { trait State { @volatile var balance: BigDecimal = _ } val state: State def modify[A](f: State => A): A = this.synchronized { val result = f(state) this.notifyAll() result } def await(): Unit = this.synchronized { this.wait() } }
  • 30. def transfer(from: Account, to: Account, amount: Amount): Unit = { var loop = true while (loop) { from.modify { state => if (state.balance >= amount.value) { state.balance -= amount.value to.modify(state => state.balance += amount.value) loop = false } else from.await() } }
  • 31. transfer(from, to, amount) transfer(to, from, amount) Thread 1 Thread 2 Deadlock Exploit
  • 35. class Account extends Actor { var balance = Amount.zero var todos = List.empty[(ActorRef, Message)] def receive = { case Deposit(amount) => balance = balance + amount.value sender ! Success(balance) todos.foreach { case (s, m) => self ! m } todos = Nil case v @ Withdraw(amount) => if (balance >= amount.value) { balance = balance - amount.value sender ! Success(balance) } else todos = (sender, v) :: todos case Balance => sender ! Success(balance) } }
  • 36. def transfer(from: ActorRef, to: ActorRef, amount: Amount)(implicit garbage: Timeout): Unit = (from ? Withdraw(amount)).flatMap { _ => to ? Deposit(amount) }
  • 38. for { john <- johnAccount ? Balance wiem <- wiemAccount ? Balance } yield if (wiem.value > john.value) transfer(wiem, cafe, amount) else transfer(john, cafe, amount) $70 $99
  • 39. for { john <- johnAccount ? Balance wiem <- wiemAccount ? Balance } yield if (wiem.value > john.value) transfer(wiem, cafe, amount) else transfer(john, cafe, amount) $70 $6,000,000 $99
  • 40. for { john <- johnAccount ? Balance wiem <- wiemAccount ? Balance } yield if (wiem.value > john.value) transfer(wiem, cafe, amount) else transfer(john, cafe, amount) $70 $6,000,000 $99
  • 41. $70 ~$6m for { john <- johnAccount ? Balance wiem <- wiemAccount ? Balance } yield if (wiem.value > john.value) transfer(wiem, cafe, amount) else transfer(john, cafe, amount) $10 $99
  • 42. $70 -$60 for { john <- johnAccount ? Balance wiem <- wiemAccount ? Balance } yield if (wiem.value > john.value) transfer(wiem, cafe, amount) else transfer(john, cafe, amount) $99
  • 46. 46 def transfer(from : TRef[Account], to : TRef[Account], amount : Amount): UIO[Unit] = atomically { for { balance <- from.get _ <- check(balance >= amount) _ <- from.update(_ - amount) _ <- to.update(_ + amount) } yield () }
  • 47. 47 def transfer(from : TRef[Account], to : TRef[Account], amount : Amount): UIO[Unit] = atomically { for { balance <- from.get _ <- check(balance >= amount) _ <- from.update(_ - amount) _ <- to.update(_ + amount) } yield () }
  • 48. 48 def transfer(from : TRef[Account], to : TRef[Account], amount : Amount): UIO[Unit] = atomically { for { balance <- from.get _ <- check(balance >= amount) _ <- from.update(_ - amount) _ <- to.update(_ + amount) } yield () }
  • 49. 49 def transfer(from : TRef[Account], to : TRef[Account], amount : Amount): UIO[Unit] = atomically { for { balance <- from.get _ <- check(balance >= amount) _ <- from.update(_ - amount) _ <- to.update(_ + amount) } yield () }
  • 50. 50 def transfer(from : TRef[Account], to : TRef[Account], amount : Amount): UIO[Unit] = atomically { for { balance <- from.get _ <- check(balance >= amount) _ <- from.update(_ - amount) _ <- to.update(_ + amount) } yield () }
  • 51. 51 def transfer(from : TRef[Account], to : TRef[Account], amount : Amount): UIO[Unit] = atomically { for { balance <- from.get _ <- check(balance >= amount) _ <- from.update(_ - amount) _ <- to.update(_ + amount) } yield () }
  • 54. STM: Software Transactional Memory Provides the ability to atomically commit a series of reads and writes to transactional memory when a set of conditions is satisfied. STM
  • 55. STM ...Op 2Op 1 Op n Final State Initial State commit failure - rollback retry - rollback complete complete
  • 56. STM STM[E, A] A transaction, which models reads & writes, and can fail, retry, or succeed. TRef[A] A transactional reference, which is read & written inside STM transactions.
  • 57. STM[E, A] Succeed with a value of type A Fail with an error of type E STM
  • 58. STM STM[E, A] A transaction, which models reads & writes, and can fail, retry, or succeed. TRef[A] A transactional reference, which is read & written inside STM transactions.
  • 61. trait TRef[A] { val get: STM[Nothing, A] def set(newValue: A): STM[Nothing, Unit] def update(f: A => A): STM[Nothing, A] def modify[B](f: A => (B, A)): STM[Nothing, B] } object TRef { def make[A](a: A): STM[Nothing, TRef[A]] } TRef
  • 62. trait TRef[A] { val get: STM[Nothing, A] def set(newValue: A): STM[Nothing, Unit] def update(f: A => A): STM[Nothing, A] def modify[B](f: A => (B, A)): STM[Nothing, B] } object TRef { def make[A](a: A): STM[Nothing, TRef[A]] } TRef
  • 63. trait TRef[A] { val get: STM[Nothing, A] def set(newValue: A): STM[Nothing, Unit] def update(f: A => A): STM[Nothing, A] def modify[B](f: A => (B, A)): STM[Nothing, B] } object TRef { def make[A](a: A): STM[Nothing, TRef[A]] } TRef
  • 64. trait TRef[A] { val get: STM[Nothing, A] def set(newValue: A): STM[Nothing, Unit] def update(f: A => A): STM[Nothing, A] def modify[B](f: A => (B, A)): STM[Nothing, B] } object TRef { def make[A](a: A): STM[Nothing, TRef[A]] } TRef
  • 65. trait TRef[A] { val get: STM[Nothing, A] def set(newValue: A): STM[Nothing, Unit] def update(f: A => A): STM[Nothing, A] def modify[B](f: A => (B, A)): STM[Nothing, B] } object TRef { def make[A](a: A): STM[Nothing, TRef[A]] } TRef
  • 66. trait STM[+E, +A] { def commit: IO[E, A] = STM.atomically { this } } object STM { def atomically[E, A](stm: STM[E, A]): IO[E, A] } STM - Commit
  • 67. val hello: STM[Nothing, String] = STM.succeed("Welcome to Scalar") STM - Succeed
  • 68. val sumBalances: STM[Nothing, Int] = balance1.get.flatMap(a => balance2.get.map(b => a + b)) STM - map & flatMap
  • 69. val sumBalances: STM[Nothing, Int] = for { a <- balance1.get b <- balance2.get } yield a + b STM - map & flatMap
  • 70. STM - Fail def debit(sender: TRef[Amount], amount: Amount): STM[String, Amount] = for { balance <- sender.update(_ - amount) _ <- if (balance < 0) STM.fail("Insufficient funds") else STM.succeed(()) } yield balance
  • 71. def debitSuccess(sender: TRef[Amount], amount: Amount): STM[Nothing, Boolean] = debit(sender, amount).fold(_ => false, _ => true) STM - Fold
  • 72. def debitWithBalance(sender: TRef[Amount], amount: Amount): STM[Nothing, Amount] = debit(sender, amount) .foldM( _ => sender.get, _ => sender.get) STM - FoldM
  • 73. def awaitTicket(tref: TRef[Option[Ticket]]): STM[Nothing, Ticket] = for { option <- tref.get ticket <- option match { case None => STM.retry case Some(ticket) => STM.succeed(ticket) } } yield ticket STM - Retry
  • 74. def tripTickets: STM[Nothing, (Ticket, Ticket)] = awaitTicket(toWarsaw) zip awaitTicket(toHome) STM - Zip
  • 75. def bid(price : Amount, org : TRef[TravelCompany]): STM[Nothing, Ticket] = for { v <- org.get _ <- STM.check(v.availTix.exists(_.price <= price)) ticket = findCheapest(v, price) _ <- org.update(_.removeTix(ticket)) } yield ticket STM - Check
  • 76. STM - Filter def bid(price : Amount, org : TRef[TravelCompany]): STM[Nothing, Ticket] = for { v <- org.get.filter(_.availTix.exists(_.price <= price)) ticket = findCheapest(v, price) _ <- org.update(_.removeTix(ticket)) } yield ticket
  • 77. val trainOrAirplane: STM[Nothing, Ticket] = bid(25.00, Railway) orElse bid(50.00, Airline) STM - Choice
  • 78. def checkIn(passengers: TRef[List[Person]]): STM[Nothing, Person] = for { head <- passengers.get.collect { case head :: tail => head } _ <- passengers.update(_.drop(1)) } yield head STM - Collect
  • 79. STM STM STM STM Composable Easy to Reason About def transfer(from : TRef[Account], to : TRef[Account], amount : Amount): UIO[Unit] = atomically { for { balance <- from.get _ <- check(balance >= amount) _ <- from.update(_ - amount) _ <- to.update(_ + amount) } yield () }
  • 81. Semaphore Thread #2 holds 1 permit Thread #1 holds 2 permits Thread #3 waits for 4 permits Semaphore 6 permits
  • 84. Semaphore def makeSemaphore(n: Int): UIO[Semaphore] = TRef.make(n).commit
  • 85. Semaphore def acquire(semaphore: Semaphore, n: Int): UIO[Unit] = (for { value <- semaphore.get _ <- STM.check(value >= n) _ <- semaphore.set(value - n) } yield ()).commit
  • 86. Semaphore def acquire(semaphore: Semaphore, n: Int): UIO[Unit] = (for { value <- semaphore.get _ <- STM.check(value >= n) _ <- semaphore.set(value - n) } yield ()).commit
  • 87. Semaphore def acquire(semaphore: Semaphore, n: Int): UIO[Unit] = (for { value <- semaphore.get _ <- STM.check(value >= n) _ <- semaphore.set(value - n) } yield ()).commit
  • 88. Semaphore def acquire(semaphore: Semaphore, n: Int): UIO[Unit] = (for { value <- semaphore.get _ <- STM.check(value >= n) _ <- semaphore.set(value - n) } yield ()).commit
  • 89. Semaphore def release(semaphore: Semaphore, n: Int): UIO[Unit] = semaphore.update(_ + n).commit
  • 90. Semaphore 1 author (you!) 10 minutes 8 lines of code Your Semaphore using ZIO!
  • 91. Promise Unset Set Wait Wait Continue Continue
  • 93. Promise type Promise[A] = TRef[Option[A]]
  • 95. Promise def complete[A](promise: Promise[A], v: A): UIO[Boolean] = (for { value <- promise.get change <- value match { case Some(_) => STM.succeed(false) case None => promise.set(Some(v)) *> STM.succeed(true) } } yield change).commit
  • 96. Promise def complete[A](promise: Promise[A], v: A): UIO[Boolean] = (for { value <- promise.get change <- value match { case Some(_) => STM.succeed(false) case None => promise.set(Some(v)) *> STM.succeed(true) } } yield change).commit
  • 97. Promise def complete[A](promise: Promise[A], v: A): UIO[Boolean] = (for { value <- promise.get change <- value match { case Some(_) => STM.succeed(false) case None => promise.set(Some(v)) *> STM.succeed(true) } } yield change).commit
  • 98. Promise def complete[A](promise: Promise[A], v: A): UIO[Boolean] = (for { value <- promise.get change <- value match { case Some(_) => STM.succeed(false) case None => promise.set(Some(v)) *> STM.succeed(true) } } yield change).commit
  • 99. Promise def await[A](promise: Promise[A]): UIO[A] = promise.get.collect { case Some(a) => a }.commit
  • 100. Promise 1 author (you!) 10 minutes 8 lines of code Your Promise using ZIO!
  • 101. Queue Empty Queue Capacity: 6 Full Queue Capacity: 6 Offer (Continue) Take (Wait) Offer (Wait) Take (Continue)
  • 103. Queue case class Queue[A]( capacity : Int, tref : TRef[ScalaQueue[A]])
  • 104. Queue def makeQueue[A](capacity: Int): UIO[Queue[A]] = TRef.make(ScalaQueue.empty[A]).commit .map(Queue(capacity, _))
  • 105. Queue def offer[A](queue: Queue[A], a: A): UIO[Unit] = (for { q <- queue.tref.get _ <- STM.check(q.length < queue.capacity) _ <- queue.tref.update(_ enqueue a) } yield ()).commit
  • 106. Queue def offer[A](queue: Queue[A], a: A): UIO[Unit] = (for { q <- queue.tref.get _ <- STM.check(q.length < queue.capacity) _ <- queue.tref.update(_ enqueue a) } yield ()).commit
  • 107. Queue def offer[A](queue: Queue[A], a: A): UIO[Unit] = (for { q <- queue.tref.get _ <- STM.check(q.length < queue.capacity) _ <- queue.tref.update(_ enqueue a) } yield ()).commit
  • 108. Queue def offer[A](queue: Queue[A], a: A): UIO[Unit] = (for { q <- queue.tref.get _ <- STM.check(q.length < queue.capacity) _ <- queue.tref.update(_ enqueue a) } yield ()).commit
  • 109. Queue def take[A](queue: Queue[A]): UIO[A] = (for { q <- queue.tref.get a <- q.dequeueOption match { case Some((a, as)) => queue.tref.set(as) *> STM.succeed(a) case _ => STM.retry } } yield a).commit
  • 110. Queue def take[A](queue: Queue[A]): UIO[A] = (for { q <- queue.tref.get a <- q.dequeueOption match { case Some((a, as)) => queue.tref.set(as) *> STM.succeed(a) case _ => STM.retry } } yield a).commit
  • 111. Queue def take[A](queue: Queue[A]): UIO[A] = (for { q <- queue.tref.get a <- q.dequeueOption match { case Some((a, as)) => queue.tref.set(as) *> STM.succeed(a) case _ => STM.retry } } yield a).commit
  • 112. Queue def take[A](queue: Queue[A]): UIO[A] = (for { q <- queue.tref.get a <- q.dequeueOption match { case Some((a, as)) => queue.tref.set(as) *> STM.succeed(a) case _ => STM.retry } } yield a).commit
  • 113. Queue 1 author (you) 14 minutes 13 lines of code Your Queue using ZIO!