Python模拟Undo操作
程序说明
本程序是由于上某课模拟数据库的事务提交或未提交状态下的回滚(Undo)操作编写
Undo操作
【例】假设 A A A有8元奖金, B B B也有8元奖金,现在 A A A的奖金翻倍, B B B需要保持和 A A A一样的奖金。
(1) 开始事务 T (假设T是个事务的内部编号);
(2) A A A的奖金= A × 2 A \times 2 A×2 ;
(3) B B B的奖金= B × 2 B \times 2 B×2;
(4) 提交事务 T T T。
以上例子需要看成一个整体,看作一个事务,事务分解为以下流程
Action | T | Mem A | Mem B | Disk A | Disk B | Log |
---|---|---|---|---|---|---|
<START T> | ||||||
INPUT(A) | 8 | 8 | 8 | |||
READ(A,t) | 8 | 8 | 8 | 8 | ||
t:=t*2 | 16 | 8 | 8 | 8 | ||
WRITE(A,t) | 16 | 16 | 8 | 8 | <T,A,8> | |
INPUT(B) | 16 | 16 | 8 | 8 | 8 | |
READ(B,t) | 8 | 16 | 8 | 8 | 8 | |
t:=t*2 | 16 | 16 | 8 | 8 | 8 | |
WRITE(B,t) | 16 | 16 | 16 | 8 | 8 | <T,B,8> |
UNDO日志就是把所有没有COMMIT的事务回滚到事务开始之前的状态,对于已经COMMIT的事务不做任何处理。
程序介绍
程序模拟了三个变量执行两个事务的内存、磁盘、undo日志,并利用python动态编译实现了执行和undo操作,并配以命令行提示方便查看
- 变量 : A、B、C
- 磁盘 :一个字典(Key为变量名、Value为变量值的字典)
- 内存 :一个字典(Key为变量名、Value为变量值的字典)
- 缓存区(T) :一个变量
- 事务
– 事务1
A = A ∗ 2 A = A*2 A=A∗2
B = B ∗ 2 B = B*2 B=B∗2
– 事务2
B = B ∗ 2 B = B*2 B=B∗2
C = C + 2 C = C+2 C=C+2
程序实现思路和顺序:
- 模拟action函数
- 定义事务(Transaction)类,利用动态编译实现action的执行
- 通过读取日志实现UNDO日志数据恢复的模拟
- 实现命令行的执行与追踪
实现
import re
# 磁盘
Disk = {
'A' : 8,
'B' : 9,
'C' : 2,
}
# 内存
Memory = {}
# 缓冲区
T = 0
# undo日志
log = []
def INPUT(read_data):
Memory[read_data] = Disk[read_data]
def READ(read_data, t):
global T
T = Memory[read_data]
def WRITE(write_data, t):
log.append('recover(\'{}\', {})'.format(write_data, Disk[write_data]))
Memory[write_data] = T
def OUTPUT(write_data):
Disk[write_data] = Memory[write_data]
def recover(key, value):
''' undo日志记录的恢复函数 '''
Disk[key] = value
def print_now_status(ac):
''' 打印当前状态 '''
print('动作' + ' '*11 + 'T' + ' '*5 + '内存' + ' '*26 + '磁盘' + ' '*26 + 'LOG')
print('{: <15s}{: <6d}{: <30s}{: <30s}{}'.format(ac, T, str(Memory)[1:-1], str(Disk)[1:-1], log))
def print_now_disk_status():
''' 打印磁盘状态 '''
print('磁盘数据 : ', str(Disk)[1:-1])
def print_now_log_status():
''' 打印undo日志状态 '''
print('日志数据 : ', log)
def undo():
''' undo操作 '''
print('■ 开始回退')
while(len(log)):
undo_cmd = log.pop()
print('■ 执行指令 {}'.format(undo_cmd))
if undo_cmd == '<START T>' or undo_cmd == '<COMMIT T>':
break
exec(undo_cmd)
para_list = re.search('\(.*?\)', undo_cmd).group().split()
print('■ 回退变量 {} 到值 {}'.format(para_list[0], para_list[1]))
print('■ 回退结束, 当前磁盘情况:')
print_now_disk_status()
print(' 当前日志情况:')
print_now_log_status()
class Transaction:
''' 事务类
类实现模拟事务的存储、执行等操作
Auther: Gy
Attributes:
define : 类定义,用于打印解释信息
command : 存储事务的Action指令数组
'''
def __init__(self, df, cmd):
''' 初始化 '''
self.define = df
self.command = cmd
def print_cmd(self):
''' 打印事务信息 '''
print('\n■ 事务 {} ■\n指令'.format(self.define))
print('\n'.join(self.command) + '\n')
def pause(self):
''' 每步暂停和指令获取 '''
print('执行那个事务?')
print('执行一步 : 按n | 执行完事务:按c | 从此步开始回滚 : 按u')
c = input()
print(c)
while(c != 'n' and c != 'c' and c != 'u'):
print('输入错误')
c = input()
print(c)
return c
def excute(self):
''' 单步指令执行和控制 '''
self.print_cmd()
log.append('<START T>')
can_pause = True
for cmd in self.command:
print('■ 执行动作 {}'.format(cmd))
exc_cmd = cmd
# 注意! 此处在操作符指令,添加了global T去访问全局变量,如需定义其它事务操作符,需要斟酌此处是否需要访问全局变量
if '*' in cmd or '+' in cmd:
exc_cmd = 'global T\n'+ cmd
exec(exc_cmd)
print_now_status(cmd)
if can_pause:
c = self.pause()
if c == 'c':
can_pause = False
elif c == 'u':
undo()
return
log.append('<COMMIT T>')
def listFunction():
''' 询问执行事务 '''
print('■ 执行那个事务?')
print('■ 执行事务1 : 按1 ■ 执行事务2:按2 ■ 查看事务1 : 按3 ■ 查看事务2:按4')
c = input()
while(c != '1' and c != '2' and c != '3' and c != '4'):
print('输入错误')
c = input()
return c
if __name__ == "__main__":
# 定义事务 1
df1 = 'A*=2, B*=2'
command1= ['INPUT(\'A\')', 'READ(\'A\', T)', 'T=T*2', 'WRITE(\'A\',T)','INPUT(\'B\')','READ(\'B\', T)','T=T*2', 'WRITE(\'B\',T)', 'OUTPUT(\'A\')','OUTPUT(\'B\')']
Transaction1 = Transaction(df1, command1)
# 定义事务 2
df2 = 'B*=2, B+=2'
command2= ['INPUT(\'B\')', 'READ(\'B\', T)', 'T=T*2', 'WRITE(\'B\',T)','INPUT(\'C\')','READ(\'C\', T)','T=T+2', 'WRITE(\'C\',T)', 'OUTPUT(\'B\')','OUTPUT(\'C\')']
Transaction2 = Transaction(df2, command2)
TransactionList = [Transaction1, Transaction2]
print('初始磁盘情况')
print_now_disk_status()
c = listFunction()
while(True):
# 按输入指令执行
c = int(c)
if c == 1:
TransactionList[c-1].excute()
elif c == 2:
TransactionList[c-1].excute()
elif c == 3:
TransactionList[c-3].print_cmd()
elif c == 4:
TransactionList[c-3].print_cmd()
if c == '1' or c == '2':
print('事务执行完成')
print('现在磁盘情况')
print_now_disk_status()
print('现在日志情况')
print_now_log_status()
c = listFunction()
结果预览
结果太长,图片中删除了部分打印信息方便查看