Skip to content

Instantly share code, notes, and snippets.

@kencoba
Created October 16, 2020 09:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kencoba/c3f3bc337c70323cbb7da037ee914ebb to your computer and use it in GitHub Desktop.
Save kencoba/c3f3bc337c70323cbb7da037ee914ebb to your computer and use it in GitHub Desktop.
Transaction simulator with Python.
class Request:
pass
class Read(Request):
def __init__(self, var):
self.var = var
class Write(Request):
def __init__(self, var, val):
self.var = var
self.val = val
class Insert(Request):
def __init__(self, var, val):
self.var = var
self.val = val
class Delete(Request):
def __init__(self, var):
self.var = var
class Lock(Request):
def __init__(self, tr, var, lock_type):
self.tr = tr
self.var = var
self.lock_type = lock_type
class Unlock(Request):
def __init__(self, tr, var):
self.tr = tr
self.var = var
class Begin(Request):
def __init__(self):
pass
class Rollback(Request):
def __init__(self):
pass
class Commit(Request):
def __init__(self):
pass
class Database:
def __init__(self):
self.vars = {}
self.locks = []
def read(self, tr, var):
if len(list(filter(lambda l: l.tr != tr and l.var == var and l.lock_type == "exclusive", self.locks))) == 0:
return "success", self.vars[var]
else:
return "failure", None
def write(self, tr, var, val):
if len(list(filter(lambda l: l.tr != tr and l.var == var, self.locks))) == 0:
self.vars[var] = val
return "success"
else:
return "failure", None
def insert(self, tr, var, val):
self.write(tr, var, val)
def delete(self, tr, var):
if len(list(filter(lambda l: l.tr != tr and l.var == var, self.locks))) == 0:
self.unlock(tr, var)
del self.vars[var]
return "success"
else:
return "failure", None
def lock(self, tr, var, lock_type):
if lock_type == "exclusive":
if len(list(filter(lambda l: l.tr != tr and l.var == var, self.locks))) == 0:
self.locks.append(Lock(tr, var, lock_type))
return "success"
else:
return "failure"
else:
if len(list(filter(lambda l: l.tr != tr and l.var == var and l.lock_type == "exclusive", self.locks))) == 0:
self.locks.append(Lock(tr, var, lock_type))
return "success"
else:
return "failure"
def unlock(self, tr, var):
self.locks = list(filter(lambda l: not(
l.tr == tr and l.var == var), self.locks))
return "success"
def unlock_all(self, tr):
self.locks = list(filter(lambda l: l.tr != tr, self.locks))
return "success"
def begin(self, tr):
self.unlock_all(tr)
return "success"
def rollback(self, tr):
self.unlock_all(tr)
return "success"
def commit(self, tr):
self.unlock_all(tr)
return "success"
class Transaction:
def __init__(self, db, name, reqs):
self.db = db
self.name = name
self.reqs = reqs
self.counter = 0
self.status = "running"
def next(self):
req = self.reqs[self.counter]
if type(req) is Read:
status, val = self.db.read(self.name, req.var)
if status == "success":
self.status = "running"
self.counter += 1
print('{:6d}: Read({},{}) => val={}'.format(
self.counter, self.name, req.var, val))
else:
self.status = "waiting"
print('{:6d}: Read({},{}) => fail'.format(
self.counter, self.name, req.var))
elif type(req) is Write:
status = self.db.write(self.name, req.var, req.val)
if status == "success":
self.status = "running"
self.counter += 1
print('{:6d}: Write({},{},{}) => success'.format(
self.counter, self.name, req.var, req.val))
else:
self.status = "waiting"
print('{:6d}: Write({},{},{}) => fail'.format(
self.counter, self.name, req.var, req.val))
elif type(req) is Insert:
status = self.db.insert(self.name, req.var, req.val)
if status == "success":
self.status = "running"
self.counter += 1
print('{:6d}: Insert({},{},{}) => success'.format(
self.counter, self.name, req.var, req.val))
else:
self.status = "waiting"
print('{:6d}: Insert({},{},{}) => fail'.format(
self.counter, self.name, req.var, req.val))
elif type(req) is Delete:
status = self.db.delete(self.name, req.var)
if status == "success":
self.status = "running"
self.counter += 1
print('{:6d}: Delete({},{}) => success'.format(
self.counter, self.name, req.var))
else:
self.status = "waiting"
print('{:6d}: Delete({},{}) => fail'.format(
self.counter, self.name, req.var))
elif type(req) is Lock:
status = self.db.lock(self.name, req.var, req.lock_type)
if status == "success":
self.status = "running"
self.counter += 1
print('{:6d}: Lock({},{},{}) => success'.format(
self.counter, self.name, req.var, req.lock_type))
else:
self.status = "waiting"
print('{:6d}: Lock({},{},{}) => fail'.format(
self.counter, self.name, req.var, req.lock_type))
elif type(req) is Unlock:
status = self.db.unlock(self.name, req.var)
if status == "success":
self.status = "running"
self.counter += 1
print('{:6d}: Unlock({},{}) => success'.format(
self.counter, self.name, req.var))
else:
self.status = "waiting"
print('{:6d}: Unlock({},{}) => fail'.format(
self.counter, self.name, req.var))
elif type(req) is Begin:
status = self.db.begin(self.name)
if status == "success":
self.status = "running"
self.counter += 1
print('{:6d}: Begin({}) => success'.format(
self.counter, self.name))
else:
self.status = "waiting"
print('{:6d}: Begin({}) => fail'.format(
self.counter, self.name))
elif type(req) is Rollback:
status = self.db.rollback(self.name)
if status == "success":
self.status = "running"
self.counter += 1
print('{:6d}: Rollback({}) => success'.format(
self.counter, self.name))
else:
self.status = "waiting"
print('{:6d}: Rollback({}) => fail'.format(
self.counter, self.name))
elif type(req) is Commit:
status = self.db.commit(self.name)
if status == "success":
self.status = "running"
self.counter += 1
print('{:6d}: Commit({}) => success'.format(
self.counter, self.name))
else:
self.status = "waiting"
print('{:6d}: Commit({}) => fail'.format(
self.counter, self.name))
else:
pass
class Scheduler:
def __init__(self, trs, schedule):
self.schedule = schedule
self.trs = trs
self.counter = 0
def next(self):
if any(self.trs[tr].status == "waiting" for tr in self.trs.keys()):
print('Dead lock')
for tr_name in self.trs.keys():
if self.trs[tr_name].status == "waiting":
self.trs[tr_name].next()
self.trs[self.schedule[self.counter]].next()
self.counter += 1
tr_a_reqs = [
Begin(),
Write("X",10),
Lock("tr_a","X","exclusive"),
Read("X"),
Commit()]
tr_b_reqs = [
Begin(),
Read("X"),
Commit()]
schedule = [
"tr_a",
"tr_b",
"tr_a",
"tr_a",
"tr_a",
"tr_b",
"tr_a",
"tr_b"]
db = Database()
tr_a = Transaction(db, "tr_a", tr_a_reqs)
tr_b = Transaction(db, "tr_b", tr_b_reqs)
trs = {
"tr_a": tr_a,
"tr_b": tr_b
}
master = Scheduler(trs, schedule)
for i in schedule:
print()
master.next()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment