[Tutor] Starbucks does not use two-phase commit
Danny Yoo
dyoo at hkn.eecs.berkeley.edu
Fri Jan 20 20:34:42 CET 2006
On Fri, 20 Jan 2006, Bernard Lebel wrote:
> So have written a little test script. The fact is that I want to be able
> to manage the same queue from separate threads. Below is an example of
> what my real program is doing:
Hi Bernard,
One problem is that there's a single outputQueue being presented to get
results back from the Server.
A different approach is to use a lot of outputQueues. *grin*
The idea is that when we send a job submission, we immediately get back a
"ticket". We can then use this ticket to claim() our result. Each ticket
is unique to a job submission, so we shouldn't see any bleeding going on
between clients.
Here's some code that implements this idea. It's a little complex, so you
may want to read through it slowly:
################################################
from threading import Thread
from Queue import Queue
class Ticket:
"""A small token that we can use to claim our result."""
def __init__(self, q):
self.q = q
self.result = None
self.done = False
def claim(self):
if not self.done:
self.result = self.q.get()
self.done = True
return self.result
class Server:
_QUIT_JOB = ['Quit!']
def __init__(self):
"""A queue will contain 2-tuples of (job, outputQueue)
elements."""
self.queue = Queue()
def startServer(self):
"""Brings the server online."""
Thread(target=self._jobLoop).start()
def schedule(self, job):
"""Schedules a job to be done and returns a ticket that the
client can use later to claim the result of the job."""
outputQueue = Queue()
self.queue.put((job, outputQueue))
return Ticket(outputQueue)
def scheduleShutdown(self):
"""Add a 'job' that shuts the system down."""
self.queue.put((Server._QUIT_JOB, None))
def _jobLoop(self):
"""Continue looping through tasks."""
while True:
print "Looping..."
(nextJob, outputQueue) = self.queue.get()
if nextJob is Server._QUIT_JOB:
return
returnValue = self._doJob(nextJob)
outputQueue.put(returnValue)
def _doJob(self, job):
print "I'm doing", job
return job + job ## something to show that we're doing something
def separateCaller(server):
for i in range(1000, 1004 + 1):
print "--Separate caller asks %d" % i
ticket = server.schedule(str(i))
print "--Separate caller got %s" % ticket.claim()
if __name__ == '__main__':
server = Server()
server.startServer()
Thread(target=separateCaller, args=(server,)).start()
result1 = server.schedule("1")
print "result1: %s" % result1.claim()
result2 = server.schedule("2")
print "result2: %s" % result2.claim()
result3 = server.schedule("3")
print "result3: %s" % result3.claim()
server.scheduleShutdown()
#############################################################
Play around with this a bit and see if it makes sense to you. You might
also be interested in the amusing article "Starbucks Does Not Use
Two-Phase Commit":
http://www.eaipatterns.com/ramblings/18_starbucks.html
as it touches on concepts in the code.
If you have more questions, please feel free to ask!
More information about the Tutor
mailing list