概述

最近又开了一个新坑,CMU的15445,这是一门介绍数据库的课程。我follow的是2018年的课程,因为2018年官方停止了对外开放实验源码,所以我用的2017年的实验,但是问题不大,内容基本没有变化。想要获取实验源码的同学可以上github搜,或者直接clone我的代码,找到最早的commit就ok了,仓库地址在文末。课程配套教材是《

Database System Concepts》,https://book.douban.com/subject/4740662/ 最好看原版的,中文版的貌似页数和课程中的对不上。

言归正传,本lab将实现一个Buffer Pool Manager,又分为三个子任务:

  1. 实现一个Extendible Hash Table
  2. 实现一个LRU Page Replacement Policy
  3. 实现Buffer Pool Manager

Extendible Hash Table

Extendible Hash Table是动态hash的一种,动态是相对静态来说的。hash的原理是通过hash函数,f(key)->B,将key映射到一个Bucket地址集合中,如果B集合选的比较小,那么当key增多后,越来越多的key会落在同一个Bucket中,这样查找效率会下降。如果B集合一开始就选的很大,那么有很多Bucket处于未满状态,浪费空间。为了解决这个问题,就引入动态hash的概念。

静态hash存在上述问题主要是hash函数确定好后就不能再变了。动态hash就没有这个问题。

数据结构

Extendible Hash Table数据结构如下:

  1. bucket address table是一个数组,保存bucket的地址。
  2. global depth是一个整数值。
  3. 每个bucket都有一个local depth也是一个整数值,且小于等于global depth。每个bucket能装的键值对的最大值为bucketMaxSize。

查询

比如要查找key=1对应的value值,首先取h(1)对应的二进制前global depth位,作为bucket address table的下标,找到存放该key的bucket,然后在相应的bucket中查找。

插入

如上图,假设bucketMaxSize为2.

最开始的情况如figure1,我们插入[1, v], [2, v],因为这时global depth=0所以,全部落在bucket1中,也就是figure2。

在figure2基础上,再插入[3, v],这时还是应该插到bucket1中,但是bucket1已经满了,同时bucket1的local depth = global depth = 1。这时先将bucket address table扩大一倍,同时global depth加1。然后重新创建两个新的bucket a, bucket b,local depth在原来local depth基础上加1(由0变为1),再将bucket 1中的[1, v], [2, v]分配到新的两个bucket中,分配规则如下:

如果h(key)的第local depth(1)位是0,那么放到bucket a中,如果为1那么放到bucket b中。分配完毕后,重新调整bucket address table中指向原来bucket 1的指针指向,这里index 0和1的指针原来都指向bucket 1,所以都需要调整,调整规则如下:

index的第local depth(1)位为0的指向bucket a, 为1的指向bucket b。

最后在插入[3, v], 假设h(3)的前global depth为1,那么插入到bucket b中。最终的效果如figure3。

在figure3基础上再插入[4, v],算法和前面一样,假设[4, v]本应插入到bucket a中,但是bucket a满了,且global depth = bucket 1的local depth。所以先将bucket address table扩大一倍。然后重新创建两个新的bucket, bucket c和bucket d,再将bucket a中的[1, v], [2, v]重新分配到bucket c和bucket d中。在调整buckert address table指针指向,最后再插入[4, v]。最终效果如figure 4。

在figure4基础上,再插入[5, v], [6, v],假设都落在bucket b中,那么插入[5, v]后bucket b将满,再插入[6, v]的时候bucket b已经满了。这时和前面不一样,此时global depth(2) > bucket b的local depth(1)。所以不需要扩大bucket address table。只需要创建两个新的bucket, bucket e和bucket f。将原来bucket b中的[3, v], [5, v]分配到bucket e和bucket f中。然后调整原来指向bucket b的指针指向bucket e和bucket f。最后在插入[6, v]。最终效果如figure 5。

LRU PAGE REPLACEMENT POLICY

实现最近最少使用算法,说白了就是给你一些序列,比如1, 2, 3, 1,这时哪个是最近最少使用到的。可以画下图,越下面的越久没有使用到。先用了1,再用了2,那么2比1新,所以2在1上面,然后用了3,那么3应该在2的上面,最后用了1,那么把1从最下面调到最上面,同时2变到了最下面,至此2应该是最近最久没有使用的。

1            2            3            1
1 2 3
1 2

那么用什么数据结构来存储呢?

先看下有哪些操作:

void Insert(const T &value);
bool Victim(T &value);
bool Erase(const T &value);

Insert():将value加到最顶部,或者如果value已经在队列中,将其提取到最顶部。

Victim():提取最近最久没有使用的元素,将最底部的元素弹出。

Erase():删除某个元素。

首先想到的是单向链表。但是如果用单向链表的话,Victim()需要访问尾元素,单向链表每次都要从头到尾遍历一遍才能访问尾元素,性能可想而知。

用双向链表就可以解决这个问题,双向链表可以以O(1)的时间访问头尾元素。还有个问题,如果调用Insert(v),按照之前的算法,我先得知道v在不在这个双向链表中,如果不在直接插到头部,如果在的话,将其提取到头部。如果仅仅是双向链表,那么还是需要遍历一遍队列,查询v是不是已经在队列中了。

可以用一个map记录已经在队列中的元素到链表节点的键值对,这样就可以以O(1)的时间查询某个value是否已经在队列中。

最终确定数据结构如下:

BUFFER POOL MANAGER

为什么需要BUFFER POOL MANAGER

假设两种极端的情况:

  1. 没有缓冲池,那么数据都位于磁盘上,第一次访问一页数据,需要将其从磁盘读取到内存,第二次在访问相同的页时,还需要从磁盘读,非常耗时。
  2. 假设内存无限大,那么访问一页数据后,将该页数据直接保存到内存,下次再访问该页时,直接访问内存缓存就行。但是现实中内存比磁盘容量小得多,只能缓存有限个数据页,如下图内存只能缓存三个页,依次访问PAGE 1, 2, 3, 现在已经缓存了PAGE 1, 2, 3,假设想读取PAGE 4,那么得先清空一个内存缓存页,用来缓存PAGE 4的数据,那么清除谁呢?。这时候任务2的替换策略就派上用场了,根据LRU替换策略,PAGE 1是最近最久没有被使用过的,那么就将PAGE 1重新写回到磁盘,然后将PAGE 4读取到内存。

所以BUFFER POOL MANAGER的作用是加速数据的访问,同时对使用者来说是透明的。

具体代码就不贴了,可以参考我的实现:https://github.com/gatsbyd/cmu_15445_2018

CMU-15445 LAB1:Extendible Hash Table, LRU, BUFFER POOL MANAGER的更多相关文章

  1. CMU15445 (Fall 2019) 之 Project#2 - Hash Table 详解

    前言 该实验要求实现一个基于线性探测法的哈希表,但是与直接放在内存中的哈希表不同的是,该实验假设哈希表非常大,无法整个放入内存中,因此需要将哈希表进行分割,将多个键值对放在一个 Page 中,然后搭配 ...

  2. Spell checker using hash table

    Problem description Given a text file, show the spell errors from it.  (https://www.andrew.cmu.edu/c ...

  3. 算法与数据结构基础 - 哈希表(Hash Table)

    Hash Table基础 哈希表(Hash Table)是常用的数据结构,其运用哈希函数(hash function)实现映射,内部使用开放定址.拉链法等方式解决哈希冲突,使得读写时间复杂度平均为O( ...

  4. 散列表(hash table)——算法导论(13)

    1. 引言 许多应用都需要动态集合结构,它至少需要支持Insert,search和delete字典操作.散列表(hash table)是实现字典操作的一种有效的数据结构. 2. 直接寻址表 在介绍散列 ...

  5. 哈希表(Hash Table)

    参考: Hash table - Wiki Hash table_百度百科 从头到尾彻底解析Hash表算法 谈谈 Hash Table 我们身边的哈希,最常见的就是perl和python里面的字典了, ...

  6. Berkeley DB的数据存储结构——哈希表(Hash Table)、B树(BTree)、队列(Queue)、记录号(Recno)

    Berkeley DB的数据存储结构 BDB支持四种数据存储结构及相应算法,官方称为访问方法(Access Method),分别是哈希表(Hash Table).B树(BTree).队列(Queue) ...

  7. 几种常见 容器 比较和分析 hashmap, map, vector, list ...hash table

    list支持快速的插入和删除,但是查找费时; vector支持快速的查找,但是插入费时. map查找的时间复杂度是对数的,这几乎是最快的,hash也是对数的.  如果我自己写,我也会用二叉检索树,它在 ...

  8. PHP内核探索之变量(3)- hash table

    在PHP中,除了zval, 另一个比较重要的数据结构非hash table莫属,例如我们最常见的数组,在底层便是hash table.除了数组,在线程安全(TSRM).GC.资源管理.Global变量 ...

  9. php Hash Table(四) Hash Table添加和更新元素

    HashTable添加和更新的函数: 有4个主要的函数用于插入和更新HashTable的数据: int zend_hash_add(HashTable *ht, char *arKey, uint n ...

随机推荐

  1. python---redis管道(事务)和发布订阅

    管道:将数据操作放在内存中,只有成功后,才会一次性全部放入redis #管道(事务),要是都成功则成功,失败一个全部失败 #原理:将数据操作放在内存中,只有成功后,才会一次性全部放入redis pip ...

  2. [整理]IE11中的WebGL探秘:渲染速度超Chrome

    http://www.csdn.net/article/2013-12-19/2817854-IE11-WebGL-and-more 摘要:IE11开始支持WebGL,并且效果非常好,IE11的Web ...

  3. HTTP1.0 HTTP 1.1 HTTP 2.0主要区别

      HTTP1.0 HTTP 1.1主要区别 长连接 HTTP 1.0需要使用keep-alive参数来告知服务器端要建立一个长连接,而HTTP1.1默认支持长连接. HTTP是基于TCP/IP协议的 ...

  4. Python程序员之面试必回习题

    写在前面 近日恰逢学生毕业季,课程后期大家“期待+苦逼”的时刻莫过于每天早上内容回顾和面试题问答部分[临近毕业每天课前用40-60分钟对之前内容回顾.提问和补充,专挑班里不爱说话就的同学回答]. 期待 ...

  5. Wordpress页脚

    <?php /** * The template for displaying the footer */ ?> <?php if ( apply_filters( 'show_fl ...

  6. python 入门基础4 --数据类型及内置方法

    今日目录: 零.解压赋值+for循环 一. 可变/不可变和有序/无序 二.基本数据类型及内置方法 1.整型 int 2.浮点型float 3.字符串类型 4.列表类型 三.后期补充内容 零.解压赋值+ ...

  7. VS 多工程代码编写

    VS工作目录,输出目录 C++项目,解决方案总文件夹下就只包含解决方案配置文件sln和一个项目总文件夹和一个Debug文件夹以及一个Release文件夹(共四个东东,其中Debug和Release文件 ...

  8. 数据库优化之mysql【转】

    1. 优化流程图 mysql优化(主要增加数据库的select查询,让查询速度更快) 2. 优化mysql的方面 主要从以下四个方面去优化mysql ①存储层:如何选择一个数据库引擎,选择合适的字段列 ...

  9. C# 压缩文件 的创建

    using System;using System.IO.Compression; using System.Collections.Generic;using System.Linq;using S ...

  10. zabbix3.0.4安装趋势图集中显示插件graphtrees

    通过yum方式安装的zabbix 1.将/usr/share/zabbix目录修改权限,因此处我们使用的是apache,所以用户改为apache,如果是nginx需要改为nginx(是否需要修改可以参 ...