SlideShare una empresa de Scribd logo
1 de 116
Descargar para leer sin conexión
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

Más contenido relacionado

La actualidad más candente

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
 

La actualidad más candente (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 a 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 a 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
 

Más de 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
 

Más de 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
 

Último

UWB Technology for Enhanced Indoor and Outdoor Positioning in Physiological M...
UWB Technology for Enhanced Indoor and Outdoor Positioning in Physiological M...UWB Technology for Enhanced Indoor and Outdoor Positioning in Physiological M...
UWB Technology for Enhanced Indoor and Outdoor Positioning in Physiological M...UbiTrack UK
 
The Data Metaverse: Unpacking the Roles, Use Cases, and Tech Trends in Data a...
The Data Metaverse: Unpacking the Roles, Use Cases, and Tech Trends in Data a...The Data Metaverse: Unpacking the Roles, Use Cases, and Tech Trends in Data a...
The Data Metaverse: Unpacking the Roles, Use Cases, and Tech Trends in Data a...Aggregage
 
20230202 - Introduction to tis-py
20230202 - Introduction to tis-py20230202 - Introduction to tis-py
20230202 - Introduction to tis-pyJamie (Taka) Wang
 
Designing A Time bound resource download URL
Designing A Time bound resource download URLDesigning A Time bound resource download URL
Designing A Time bound resource download URLRuncy Oommen
 
Artificial Intelligence & SEO Trends for 2024
Artificial Intelligence & SEO Trends for 2024Artificial Intelligence & SEO Trends for 2024
Artificial Intelligence & SEO Trends for 2024D Cloud Solutions
 
Machine Learning Model Validation (Aijun Zhang 2024).pdf
Machine Learning Model Validation (Aijun Zhang 2024).pdfMachine Learning Model Validation (Aijun Zhang 2024).pdf
Machine Learning Model Validation (Aijun Zhang 2024).pdfAijun Zhang
 
9 Steps For Building Winning Founding Team
9 Steps For Building Winning Founding Team9 Steps For Building Winning Founding Team
9 Steps For Building Winning Founding TeamAdam Moalla
 
Introduction to Matsuo Laboratory (ENG).pptx
Introduction to Matsuo Laboratory (ENG).pptxIntroduction to Matsuo Laboratory (ENG).pptx
Introduction to Matsuo Laboratory (ENG).pptxMatsuo Lab
 
Connector Corner: Extending LLM automation use cases with UiPath GenAI connec...
Connector Corner: Extending LLM automation use cases with UiPath GenAI connec...Connector Corner: Extending LLM automation use cases with UiPath GenAI connec...
Connector Corner: Extending LLM automation use cases with UiPath GenAI connec...DianaGray10
 
Comparing Sidecar-less Service Mesh from Cilium and Istio
Comparing Sidecar-less Service Mesh from Cilium and IstioComparing Sidecar-less Service Mesh from Cilium and Istio
Comparing Sidecar-less Service Mesh from Cilium and IstioChristian Posta
 
How Accurate are Carbon Emissions Projections?
How Accurate are Carbon Emissions Projections?How Accurate are Carbon Emissions Projections?
How Accurate are Carbon Emissions Projections?IES VE
 
Bird eye's view on Camunda open source ecosystem
Bird eye's view on Camunda open source ecosystemBird eye's view on Camunda open source ecosystem
Bird eye's view on Camunda open source ecosystemAsko Soukka
 
Crea il tuo assistente AI con lo Stregatto (open source python framework)
Crea il tuo assistente AI con lo Stregatto (open source python framework)Crea il tuo assistente AI con lo Stregatto (open source python framework)
Crea il tuo assistente AI con lo Stregatto (open source python framework)Commit University
 
ADOPTING WEB 3 FOR YOUR BUSINESS: A STEP-BY-STEP GUIDE
ADOPTING WEB 3 FOR YOUR BUSINESS: A STEP-BY-STEP GUIDEADOPTING WEB 3 FOR YOUR BUSINESS: A STEP-BY-STEP GUIDE
ADOPTING WEB 3 FOR YOUR BUSINESS: A STEP-BY-STEP GUIDELiveplex
 
AI Fame Rush Review – Virtual Influencer Creation In Just Minutes
AI Fame Rush Review – Virtual Influencer Creation In Just MinutesAI Fame Rush Review – Virtual Influencer Creation In Just Minutes
AI Fame Rush Review – Virtual Influencer Creation In Just MinutesMd Hossain Ali
 
Cybersecurity Workshop #1.pptx
Cybersecurity Workshop #1.pptxCybersecurity Workshop #1.pptx
Cybersecurity Workshop #1.pptxGDSC PJATK
 
COMPUTER 10: Lesson 7 - File Storage and Online Collaboration
COMPUTER 10: Lesson 7 - File Storage and Online CollaborationCOMPUTER 10: Lesson 7 - File Storage and Online Collaboration
COMPUTER 10: Lesson 7 - File Storage and Online Collaborationbruanjhuli
 
UiPath Studio Web workshop series - Day 8
UiPath Studio Web workshop series - Day 8UiPath Studio Web workshop series - Day 8
UiPath Studio Web workshop series - Day 8DianaGray10
 
Computer 10: Lesson 10 - Online Crimes and Hazards
Computer 10: Lesson 10 - Online Crimes and HazardsComputer 10: Lesson 10 - Online Crimes and Hazards
Computer 10: Lesson 10 - Online Crimes and HazardsSeth Reyes
 

Último (20)

UWB Technology for Enhanced Indoor and Outdoor Positioning in Physiological M...
UWB Technology for Enhanced Indoor and Outdoor Positioning in Physiological M...UWB Technology for Enhanced Indoor and Outdoor Positioning in Physiological M...
UWB Technology for Enhanced Indoor and Outdoor Positioning in Physiological M...
 
The Data Metaverse: Unpacking the Roles, Use Cases, and Tech Trends in Data a...
The Data Metaverse: Unpacking the Roles, Use Cases, and Tech Trends in Data a...The Data Metaverse: Unpacking the Roles, Use Cases, and Tech Trends in Data a...
The Data Metaverse: Unpacking the Roles, Use Cases, and Tech Trends in Data a...
 
20230202 - Introduction to tis-py
20230202 - Introduction to tis-py20230202 - Introduction to tis-py
20230202 - Introduction to tis-py
 
Designing A Time bound resource download URL
Designing A Time bound resource download URLDesigning A Time bound resource download URL
Designing A Time bound resource download URL
 
Artificial Intelligence & SEO Trends for 2024
Artificial Intelligence & SEO Trends for 2024Artificial Intelligence & SEO Trends for 2024
Artificial Intelligence & SEO Trends for 2024
 
Machine Learning Model Validation (Aijun Zhang 2024).pdf
Machine Learning Model Validation (Aijun Zhang 2024).pdfMachine Learning Model Validation (Aijun Zhang 2024).pdf
Machine Learning Model Validation (Aijun Zhang 2024).pdf
 
9 Steps For Building Winning Founding Team
9 Steps For Building Winning Founding Team9 Steps For Building Winning Founding Team
9 Steps For Building Winning Founding Team
 
Introduction to Matsuo Laboratory (ENG).pptx
Introduction to Matsuo Laboratory (ENG).pptxIntroduction to Matsuo Laboratory (ENG).pptx
Introduction to Matsuo Laboratory (ENG).pptx
 
Connector Corner: Extending LLM automation use cases with UiPath GenAI connec...
Connector Corner: Extending LLM automation use cases with UiPath GenAI connec...Connector Corner: Extending LLM automation use cases with UiPath GenAI connec...
Connector Corner: Extending LLM automation use cases with UiPath GenAI connec...
 
Comparing Sidecar-less Service Mesh from Cilium and Istio
Comparing Sidecar-less Service Mesh from Cilium and IstioComparing Sidecar-less Service Mesh from Cilium and Istio
Comparing Sidecar-less Service Mesh from Cilium and Istio
 
20230104 - machine vision
20230104 - machine vision20230104 - machine vision
20230104 - machine vision
 
How Accurate are Carbon Emissions Projections?
How Accurate are Carbon Emissions Projections?How Accurate are Carbon Emissions Projections?
How Accurate are Carbon Emissions Projections?
 
Bird eye's view on Camunda open source ecosystem
Bird eye's view on Camunda open source ecosystemBird eye's view on Camunda open source ecosystem
Bird eye's view on Camunda open source ecosystem
 
Crea il tuo assistente AI con lo Stregatto (open source python framework)
Crea il tuo assistente AI con lo Stregatto (open source python framework)Crea il tuo assistente AI con lo Stregatto (open source python framework)
Crea il tuo assistente AI con lo Stregatto (open source python framework)
 
ADOPTING WEB 3 FOR YOUR BUSINESS: A STEP-BY-STEP GUIDE
ADOPTING WEB 3 FOR YOUR BUSINESS: A STEP-BY-STEP GUIDEADOPTING WEB 3 FOR YOUR BUSINESS: A STEP-BY-STEP GUIDE
ADOPTING WEB 3 FOR YOUR BUSINESS: A STEP-BY-STEP GUIDE
 
AI Fame Rush Review – Virtual Influencer Creation In Just Minutes
AI Fame Rush Review – Virtual Influencer Creation In Just MinutesAI Fame Rush Review – Virtual Influencer Creation In Just Minutes
AI Fame Rush Review – Virtual Influencer Creation In Just Minutes
 
Cybersecurity Workshop #1.pptx
Cybersecurity Workshop #1.pptxCybersecurity Workshop #1.pptx
Cybersecurity Workshop #1.pptx
 
COMPUTER 10: Lesson 7 - File Storage and Online Collaboration
COMPUTER 10: Lesson 7 - File Storage and Online CollaborationCOMPUTER 10: Lesson 7 - File Storage and Online Collaboration
COMPUTER 10: Lesson 7 - File Storage and Online Collaboration
 
UiPath Studio Web workshop series - Day 8
UiPath Studio Web workshop series - Day 8UiPath Studio Web workshop series - Day 8
UiPath Studio Web workshop series - Day 8
 
Computer 10: Lesson 10 - Online Crimes and Hazards
Computer 10: Lesson 10 - Online Crimes and HazardsComputer 10: Lesson 10 - Online Crimes and Hazards
Computer 10: Lesson 10 - Online Crimes and Hazards
 

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!