位操作实现大小写转化

项目地址:

中文翻译
https://github.com/HT524/500LineorLess_CN

https://github.com/HT524/500LineorLess_CN/blob/master/DBDB:%20Dog%20Bed%20Database/DBDB:%E9%9D%9E%E5%85%B3%E7%B3%BB%E5%9E%8B%E6%95%B0%E6%8D%AE%E5%BA%93.md

英文版:

http://aosabook.org/en/500L/dbdb-dog-bed-database.html

github代码

1 the process of load file into binary tree

使用命令

python -m dbdb.tool DBNAME set KEY VALUE

首先看如何加载数据库

在interface.py中有DBDB这个类
init.py中设置了这个方法connect

db = dbdb.connect(dbname)

fd = os.open(dbname, os.O_RDWR | os.O_CREAT),进行创建成功

之后返回DBDB(f)

调用DBDB的init方法,有两个成员变量_storage 和_tree,分别用来存储和建树

self._storage = Storage(f)
self._tree = BinaryTree(self._storage)

Storage

self._f = f
self.locked = False
self._ensure_superblock() 设置最小为4096个字节存储空间

存储时可以发现root_address是设置在文件的最开始处的

def get_root_address(self):
    self._seek_superblock()
    root_address = self._read_integer()
    return root_address

BinaryTree的初始化:

首先是LogicalBase(self,storage),成员变量为_storage , 和_tree_ref(类型为BinaryNodeRef类型)

self._storage = storage
self._refresh_tree_ref()

_refresh_tree_ref()中,设置_tree_ref指向最新的root地址

self._tree_ref = self.node_ref_class(            address=self._storage.get_root_address())

之后是BinaryTree的初始化,没有init函数

到现在为止,系统初始化完毕

===================================================================

如何set一个值

python -m dbdb.tool DBNAME set KEY VALUE
(1)db[key] = value 
   db.commit()

(2)DBDB类中的_tree成员变量(BinaryTree类型,基类为LogicalBase)

def __setitem__(self, key, value):
    self._assert_not_closed()
    return self._tree.set(key, value)

(3)基类LogicalBase的set方法

def set(self, key, value):
    if self._storage.lock():
        self._refresh_tree_ref()
    self._tree_ref = self._insert(
        self._follow(self._tree_ref), key, self.value_ref_class(value))

基类的_follow(self,ref)方法返回ref指向的storage
BinaryNodeRef的get方法(BinaryTree._storage)

实际上是调用基类ValueRef的get方法

if self._referent is None and self._address:
    self._referent = self.string_to_referent(storage.read(self._address))
return self._referent

第一次的话,referent返回的是None

所以基类LogicalBase的set方法中self._tree_ref = self._insert(None, KEY, ValueRef(VALUE))

调用子类BinaryTree的_insert方法,执行

new_node = BinaryNode(
    self.node_ref_class(), key, value_ref, self.node_ref_class(), 1) 

返回 self.node_ref_class(referent=new_node),返回类型为BinaryNodeRef类型

到此,insert过程结束

==================================================

再看commit函数

首先基类的commit函数

self._tree_ref.store(self._storage)
self._storage.commit_root_address(self._tree_ref.address)

第一句调用BinaryNodeRef.store方法,即ValueRef.store方法,

def store(self, storage):
       if self._referent is not None and not self._address:
           self.prepare_to_store(storage)
           self._address = storage.write(self.referent_to_string(self._referent))

referent为insert新建的节点,节点类型为BinaryNodeRef,新创建的节点包含两个空的BinaryNodeRef,和一个ValueRef,但是没有address,因此执行self.prepare_to_store(storage)

python代码作为测试

from __future__ import print_function
import sys
class BaseA(object):
    def Afunc(self):
        print("Base");
    def fun(self):
        self.Afunc();

class DerivedA(BaseA):
    def Afunc(self):
        print("Derived");

if __name__ == '__main__':
    d = DerivedA();
    d = BaseA();
    d.fun();

因此,调用BinaryNodeRef的prepare_to_store,有所指,因此调用self._referent.store_refs(storage),因此调用BinaryNode的store_refs(storage),因此调用self.value_ref.store(storage)

self.left_ref.store(storage)
self.right_ref.store(storage)

每个store函数的调用过程如下:

value_ref类型为valueRef,prepare_to_store = pass #因此忽略了。(代码中有写)

直接存储self._address = storage.write(self.referent_to_string(self._referent)),可以直接存储value,并且获得address。存储的时候,存放的是value。存储的时候,是把superBlock空间空余出来,用来存放root_address。

之后是left_ref和right_ref调用store方法,referent = None,因此忽略了。

首先基类的commit函数,之后是commit_root_address函数,把root地址写在最开始的位置。

==================================================

现在再来执行一遍

set一个值

python -m dbdb.tool DBNAME set KEY VALUE

(2)DBDB类中的_tree成员变量(BinaryTree类型,基类为LogicalBase)
def __setitem__(self, key, value):
    self._assert_not_closed()
    return self._tree.set(key, value)

(3)基类LogicalBase的set方法

def set(self, key, value):
    if self._storage.lock():
        self._refresh_tree_ref()
    self._tree_ref = self._insert(
        self._follow(self._tree_ref), key, self.value_ref_class(value))

基类的_follow(self,ref)方法返回ref指向的storage
BinaryNodeRef的get方法(BinaryTree._storage)

实际上是调用基类ValueRef的get方法

if self._referent is None and self._address:
    self._referent = self.string_to_referent(storage.read(self._address))
return self._referent

这时,_referent与_address都不是空了。因此可以直接返回_referent,其类型为BinaryNodeRef类型。
调用子类BinaryTree的_insert方法,执行BinaryTree的下面这个方法

    def _insert(self, node, key, value_ref):
        if node is None:
            new_node = BinaryNode(
                self.node_ref_class(), key, value_ref, self.node_ref_class(), 1) 
                #comment 因为是一棵新树,所以它的左右分支两个self.node_ref_class()初始化时没有参数
        elif key < node.key:
            new_node = BinaryNode.from_node(
                node,
                left_ref=self._insert(
                    self._follow(node.left_ref), key, value_ref))
        elif node.key < key:
            new_node = BinaryNode.from_node(
                node,
                right_ref=self._insert(
                    self._follow(node.right_ref), key, value_ref))
        else:
            new_node = BinaryNode.from_node(node, value_ref=value_ref)
        return self.node_ref_class(referent=new_node)

执行的是递归过程。返回的是一个BinaryNodeRef对象,指向的是BinaryNode对象,BinaryNode包含一个ValueRef以及两个BinaryNodeRef对象。

插入过程结束以后,BinaryTree中的_tree_ref更新为node_ref_class,指向新的referent

(由于创建好了以后就是不可变的,因此会浪费很多内存空间,当然也会节省一部分内存,对于某些完全没有改变的节点来说)只要节点有一点改变,都会重新设置一个节点。

===============================================

总结

每次更改数据库,并且需要commit操作,才会真正写入磁盘。从而实现——————用不可变数据结构实现一个表面上可变的对象(implement an ostensibly mutable object with an immutable data structure)。主要的类:

physical:storage 负责存储,写入
binaryTree:BinaryNode, BinaryNodeRef, BinaryTree
logical:ValueRef, LogicalBase
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值