Created
May 30, 2010 03:03
-
-
Save ELLIOTTCABLE/418738 to your computer and use it in GitHub Desktop.
Solving the classic banking concurrency problem with Paws
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
bank.client ← list clone | |
heir.cache ← list clone | |
definition(‘heir.cache’) depth ← 0 ; “Heirs’ lookups will ‘overlook’ this `heir.cache` definition.” | |
“This will either retrieve the existing client object from the cache, or create a new one with its `id` set.” | |
clone ← routine { | |
result(heir.cache[argument] ⇤ up | |
id ← argument | |
client ← HTTP client clone | |
host ← ‘api.awesome-bank.co.uk’ | |
port ← 8088 | |
) | |
} | |
“Since this routine is declared as ‘atomic,’ it will never be scheduled for execution in parallel with any | |
other routines that conflict with its ownership at runtime.” | |
transfer ← routine { | |
available.from ← `from client get(‘/funds_available’, params: (account: `from id)) | |
if (available.from ≥ argument) | |
from ← `from client get(‘/funds’, params: (account: `from id)) | |
to ← `to client get(‘/funds’, params: (account: `to id)) | |
`from client post(‘/funds’, params: (account: `from id, funds: from − argument)) | |
`to client post(‘/funds’, params: (account: `to id, funds: to + argument)) | |
} | |
transfer atomic! | |
open.account ← routine { | |
id ← `client post(‘/open’, params: (account: `id)) | |
result(mint ← `clone(id)) | |
(from: this, to: mint)transfer(argument) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
“This is a basic example of how Paws makes concurrent applications easy to write. In this example, we have | |
shared resources (bank accounts) for which the order-of-access is critical. | |
In this example, if the HTTP requests were to happen out-of-order, then somebody would end up with more or less | |
money than they should have, which is a critical failure of the program. Paws prevents that.” | |
“To clarify what is going on, we’re going to have a little story problem (OMG YAY!) Specifically, we have five | |
people: Paul and Peter, Jasmine, and then Mark and Mindy. Paul and Peter will transfer money between one | |
another, and Jasmine will also transfer some money with Peter. Mark and Mindy, meanwhile, will transfer money | |
amongst eachother, without any relation or interaction with the other three. | |
In a non-concurrent system, this would be a series of safe operations; however, it would be slow. In an | |
improperly designed concurrent system, the reads and writes to the shared resources might become interleaved, | |
causing the critical failure described above. In a properly designed concurrent system, unrelated accesses will | |
have the opportunity to proceed concurrently, saving processing time, while still preventing dangerous forms of | |
simultaneous access to shared resources.” | |
“There are going to be three different real-world transactions going on here; we’re going to simulate this with | |
three separate routines (the `do` routine itself simply takes a block, and executes it—nothing special.) By | |
default, in Paws, these will all three run concurrently.” | |
“First, Paul is going to give Peter a small amount of money, and then realize he didn’t need quite that much.” | |
do { | |
“The `bank.client` is a fictional library, that provides a Paws interface to a bank’s HTTP database. It does | |
nothing magical, concurrency-wise; in this example, it simply sets up an object for us that has an account | |
number, and some methods to make authenticated HTTP requests to the bank’s HTTP API.” | |
Peter ← bank.client clone(800,223) | |
Paul ← bank.client clone(800,490) | |
“Now that we have handles for those accounts, we’re going to transfer some money.” | |
(from: Peter, to: Paul)transfer(100$) | |
“Since that was a bit too much, Paul is going to transfer a little back.” | |
(from: Paul, to: Peter)transfer(20$) | |
} | |
“Now, a related but separate operation: Peter is going to open an account for Jasmine, which involves depositing | |
a little of his money to get her started.” | |
do { | |
Peter ← bank.client clone(800,223) | |
Jasmine ← Peter open.account(with: 25$) | |
} | |
“Finally: In a completely unrelated operation, Mark and Mindy transfer some money.” | |
do { | |
Mark ← bank.client clone(796,724) | |
Mindy ← bank.client clone(424,634) | |
(from: Mark, to: Mindy)transfer(1,500$) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment