Download - Pellucid stm

Transcript
Page 1: Pellucid stm

SOFTWARE TRANSACTIONAL MEMORY@DUSTINWHITNEY

Page 2: Pellucid stm

Alternative to lock-based synchronization

Analogous to database transactions

ACI (ACID with out the ‘D’)

Simple! (well… simplier)

WHAT IS STM?

Page 3: Pellucid stm

libraryDependencies += ("org.scala-stm" %% "scala-stm" %

"0.7")

import scala.concurrent.stm._

val protectedInt = Ref(0)

atomic{ implicit transaction=> val currentValue = protectedInt.get protectedInt.set(currentValue + 1)}

WHAT DOES IT LOOK LIKE?

Page 4: Pellucid stm

ATOMIC

val protectedInt = Ref(0)val anotherProtectedInt = Ref(0)

atomic{ implicit transaction => val currentValue = protectedInt.get protectedInt.set(currentValue + 1) val anotherCurrentValue = anotherProtectedInt.get anotherProtectedInt.set(anotherCurrentValue + 1)}

Page 5: Pellucid stm

CONSISTENT

val protectedInt = Ref(0)

atomic{ transaction => val currentValue = protectedInt.get(transaction) protectedInt.set(currentValue + 1)(transaction)}

Page 6: Pellucid stm

val protectedInt = Ref(0)

atomic{ implicit transaction => val currentValue = protectedInt.get protectedInt.set(currentValue + 1)}

ISOLATED

Page 7: Pellucid stm

STM is not Durable

DURABLE

Page 8: Pellucid stm

ADVANTAGES: DEADLOCK / LIVELOCK

val protectedInt = Ref(0)

atomic{ implicit transaction => val currentValue = protectedInt.get protectedInt.set(currentValue + 1)}

Page 9: Pellucid stm

ADVANTAGES: PRIORITY INVERSION

val protectedInt = Ref(0)

atomic{ implicit transaction => val currentValue = protectedInt.get protectedInt.set(currentValue + 1)}

Page 10: Pellucid stm

ADVANTAGES: COMPOSABILITY

val protectedInt = Ref(0)val anotherProtedtedInt = Ref(0)

atomic{ implicit transaction => val currentValue = protectedInt.get protectedInt.set(currentValue + 1) atomic{ implicit transaction => val anotherCurrentValue = anotherProtectedInt.get val anotherProctedInt.set(anotherCurrentValue + 1) }

}

Page 11: Pellucid stm

GOTCHAS: IMMUTABILITY!

// bad!val badMap= Ref(new java.util.HashMap[String, Int]())val mutableMap = atomic{ implicit transaction => badMap.get }mutableMap.put(“Wrong!”, 666)

// goodval goodMap = Ref(Map(“Good” -> 7))atomic{ implicit transaction => val tempMap = goodMap.get goodMap.set(tempMap + (“Good” -> 777))}

Page 12: Pellucid stm

GOTCHAS: REFERENTIAL TRANSPARENCY

//badval protectedString = Ref("This is a string")val time = System.currentTimeMillisatomic{ implicit transaction => if(time % 2 == 0) protectedString.set("Time was even") else protectedString.set("Time was odd")}

//goodatomic{ implicit transaction => val time = System.currentTimeMillis if(time % 2 == 0) protectedString.set("Time was even") else protectedString.set("Time was odd")}

Page 13: Pellucid stm

EXTENDED EXAMPLE: STM

case class Account(number: Int, balance: Int)

val accounts = Ref(Map( 1 -> Account(1, 100), 2 -> Account(2, 100) ))

def transfer(to: Int, from: Int, amount: Int){ atomic{ implicit transaction => val map = accounts.get val toAccount = map(to) val fromAccount = map(from) accounts.set( map + (to -> (toAccount.copy(balance = toAccount.balance + amount))) + (from -> (fromAccount.copy(balance = fromAccount.balance - amount))) ) } }

Page 14: Pellucid stm

EXTENDED EXAMPLE: SYNCHRONIZED

import java.util._private val accounts = new HashMap[Int, Account]()accounts.put(1, Account(1, 100))accounts.put(2, Account(2, 100))

def transfer(to: Int, from: Int, amount: Int){ accounts.synchronized{ val toAccount = accounts.get(to) val fromAccount = accounts.get(from) accounts.put(to, (toAccount.copy(balance = toAccount.balance + amount))) accounts.put(from, (fromAccount.copy(balance = fromAccount.balance - amount))) }}

Page 15: Pellucid stm

EXTENDED EXAMPLE: SYNCHRONIZED2

import java.util.concurrent._private val accounts = ConcurrentHashMap[Int, Account]()accounts.put(1, Account(1, 100))accounts.put(2, Account(2, 100))

def transfer(to: Int, from: Int, amount: Int){ val toAccount = accounts.get(to) val fromAccount = accounts.get(from) toAccount.synchronized{ fromAccount.synchronized{ accounts.put(to, (toAccount.copy(balance = toAccount.balance + amount))) accounts.put(from, (fromAccount.copy(balance = fromAccount.balance - amount))) } }}

Page 16: Pellucid stm

EXTENDED EXAMPLE: SYNCHRONIZED3

import java.util.concurrent._private val accounts = ConcurrentHashMap[Int, Account]()accounts.put(1, Account(1, 100))accounts.put(2, Account(2, 100))

def transfer(to: Int, from: Int, amount: Int){ val toAccount = accounts.get(to) val fromAccount = accounts.get(from) val (firstLock, secondLock) = if(to > from) (toAccount, fromAccount) else (fromAccount, toAccount) firstLock.synchronized{ secondLock.synchronized{ accounts.put(to, (toAccount.copy(balance = toAccount.balance + amount))) accounts.put(from, (fromAccount.copy(balance = fromAccount.balance - amount))) } }}

Page 17: Pellucid stm

Questions?