Python模拟Undo操作

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

以上例子需要看成一个整体,看作一个事务,事务分解为以下流程

ActionTMem AMem BDisk ADisk BLog
<START T>
INPUT(A)888
READ(A,t)8888
t:=t*216888
WRITE(A,t)161688<T,A,8>
INPUT(B)1616888
READ(B,t)816888
t:=t*21616888
WRITE(B,t)16161688<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=A2
    B = B ∗ 2 B = B*2 B=B2
    – 事务2
    B = B ∗ 2 B = B*2 B=B2
    C = C + 2 C = C+2 C=C+2

程序实现思路和顺序:

  1. 模拟action函数
  2. 定义事务(Transaction)类,利用动态编译实现action的执行
  3. 通过读取日志实现UNDO日志数据恢复的模拟
  4. 实现命令行的执行与追踪

实现

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()

结果预览

结果太长,图片中删除了部分打印信息方便查看
在这里插入图片描述

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值