CMU 15-445 Ⅱ Buffer Pool
Buffer Pool
每当要读取一些不在buffer pool中的数据时,数据库就会先访问磁盘,然后把数据放到buffer pool中,再对buffer pool进行操作,最后落盘。很明显buffer pool中数据的排列肯定是和磁盘中的存储形式不是一一对应的,这就需要一个indirection层来指示特定的Page在buffer pool的哪个位置。
Page Table本质上就是一个hash表,用来追踪在内存中有哪些Page,如果我们想找一个特定的Page,通过Page Table和Page id就可以知道这个Page在哪个frame中。由于事务的原因,数据库必须维护一些额外的元数据,以此来追踪当前buffer pool中发生了什么。
Dirty Flag:用于指示从磁盘读取到Page后,这个Page是否被修改
Pin/Reference Counter(引用计数):用于追踪想要使用该Page的当前线程数量或者正在查询该Page的线程数量。这也意味着我现在还不想把该Page落盘,因为可能还有线程在对该Page进行更新。
正因为需要数据库自己维护这些东西,所以说mmap是 ...
读源码-Redis Ⅰ SDS实现
Redis中的字符串Redis没有使用原生的C字符数组,它通过自己的SDS(simple dynamic string)来作为默认的字符串表示
123456789101112131415//sds.h/* * 保存字符串对象的结构 */struct sdshdr { // buf 中已占用空间的长度 int len; // buf 中剩余可用空间的长度 int free; // 数据空间 char buf[];};
封装这个数据结构的好处在于
在O(1)时间里得到字符串长度
避免缓冲区溢出
缓冲区溢出这个问题的出现是因为没有预先分配足够的内存,然后新数据覆写了原数据后面的内容,在Redis中SDS的API需要对SDS进行修改时,API会先检查SDS的空间是否满足修改所需的要求,如果不满足的话API会先将SDS扩容到执行修改所需的大小,然后再执行具体的操作。也就规避的数据覆写的问题。
12345678910111213141516171819202122232425262728293031323334353637383 ...
CS144 Ⅱ TCP
TCP服务模型
TCP提供可靠的连接,为确保这一点它提供了四种机制:
当收到数据后,它将发送ACK来告知发送端已经接收方已经正确收到数据。
利用校验和(根据报头和数据生成)来检测损坏的数据。
序列号检测丢失的数据。双方将标记包的序列号,如果丢失了某一段序列号,就意味着失去了相应的数据,该段数据将被重传。
拥塞控制,一端发送的速度远大于另一端处理的速度时,落后的一端将会告知发送端减慢发送速率直到数据被处理完毕。
TCP报文
Sequence:指示字节流中第一个字节在TCP字节流中的位置
Acknowledgment Sequence:指示接下来要接收的是哪个字节
Checksum:由报头和数据计算得来
HLEN:报头长度
ACK:表示正在确认序列号有效
SYN:表示正在发送同步信号
FIN:表示连接的一个方向关闭
PSH:告知另一端TCP层立即传送数据,而不是等待更多的数据到来
TCP连接断开
当要断开TCP连接时,A端先发送一个FIN(Finish)请求,B端确认A端没有新的数据要发送了,并停止接收新数据,B端关闭来自A to B的数据流,但是B端可能仍有数据要发送给A端 ...
Go的内存模型与并发 (未完)
Do not communicate by sharing memory; instead, share memory by communicating.
不要通过共享内存来通信,而应通过通信来共享内存。
并发与并行并发指的是在同一时间段内多个线程同时执行,而并行指的是同一时间点上多个线程同时执行。也即并发的程序其实完全可以顺序执行,只有在真正多核心的CPU上程序才能并行执行。并行更关注的是程序的运行层面,并行一般是简单的大量重复,例如GPU中对图像处理都会有大量的并行运算。
Go与并发编程在并发编程汇中,对共享资源的正确访问需要精确的控制,多数语言采用的加锁的方式来实现线程同步,而Go则采用Channel来在不同的Goroutine中传递共享资源,在任意给定的时刻,最好只有一个Goroutine能够拥有该资源,使得数据竞争从设计层面被杜绝。这也是开篇词所表现的编程哲学的一种具体实现。
互斥锁考虑以下代码
12345678910func main() { var mu sync.Mutex go func() { fmt.Println("X") mu.Lo ...
CS144 Ⅰ 网络层次模型 大端小端 ARP 子网掩码
网络的层次模型
现行的网络是层次模型的。
应用层:负责使用特定于两个应用程序之间可读的字节流来进行数据传输。
传输层:保证正确、有序的端到端传输数据并控制拥塞。
网络层:只使用IP协议,尽可能地提供端到端的数据传输。
链路层:通过终端主机和路由器之间的单个链接来传输数据
此外,在现行的网络模型是“瘦腰”的因为如果要是用Internet就必须使用Internet Protocol也即IP协议
除了四层模型外,在1980年国际标准组织还提出了OSI七层模型,不过这个模型基本只存在于标准文书中,现行的网络采取的是四层模型。
IP服务模型
Internet Protocol 具有以下属性:
不维护与数据报相关联的每个流状态。
当它发送数据时会创建一个数据报并将数据放入其中,数据报将根据它携带的头信息,来各自独立的经由Router来传输。
IP不可靠,它不保证将数据报传到目的地它可能会延迟交付,不按顺序交付,或者丢失。
高效。
IP是面向无连接的。
之所以将IP协议设计的如此简单,一方面是为了能高效传递信息,另一方面则是为了解耦,方便在顶层构建各种可靠或者不可靠的服务。
...
CMU 15-445 Ⅰ 数据库存储
数据库存储计算机的存储层次如图所示,由上至下速度越来越慢 ,容量越来越大。而CMU 15-445主要在非易失型存储中构建DBMS
面向磁盘的DBMS
磁盘存储着数据文件,并把它们封装成不同的块或者页面来表示它们,buffer pool在内存中,执行引擎向buffer pool进行请求读取某一页的文件,然后buffer pool将其装载进来,然后执行引擎对buffer pool进行操作。
在这个架构与其他软件架构的不同之处就在于内存由DBMS自己来管理而不是交给操作系统来管理。
mmap
mmap指的是从磁盘中获取文件,然后告知操作系统将文件页面映射到进程的地址空间,然后进程可以对这些内存地址进行读写,此时操作系统没有将数据存入内存,但仍能对其写入,具体的方法是借由操作系统,而不是进程自己来写,它通过执行一个Sync来把数据写回磁盘。简单说就是不借助内存,而是进程和操作系统直接通过交换磁盘文件的地址来实现数据的读写。
但由于操作系统只能看到内存在不断的刷新,它不知道数据库在做什么,所以操作系统可能会频繁的读盘(因为它不知道哪些数据是热点,是内存满时哪些数据不应被优 ...
RocksDB安装
Debian/Ubuntu操作如下:
12apt install libsnappy-dev zlib1g-dev libbz2-dev liblz4-dev libzstd-dev libgflags-dev1
下载,编译,安装:
123456wget https://github.com/facebook/rocksdb/archive/v6.6.4.zip #6.6.4 (2020-01-31)unzip v6.6.4.zip cd rocksdb-6.6.4/make static_lib && sudo make install-staticmake shared_lib && sudo make install-shared12345
CentOS操作如下:
12yum install snappy snappy-devel zlib zlib-devel bzip2 bzip2-devel lz4-devel libasan1
安装gflags:
12345git clone https://github.com/gflags/gf ...
23 个问题 TCP 疑难杂症全解析
23 个问题 TCP 疑难杂症全解析转自:高性能服务器开发微信公众号
以下文章来源于yes的练级攻略 ,作者是Yes呀
yes的练级攻略会分享一些后端技术或写一些想写的。
在进入今天主题之前我先抛几个问题,这篇文章一共提出 23 个问题。
TCP 握手一定是三次?TCP 挥手一定是四次?
为什么要有快速重传,超时重传不够用?为什么要有 SACK,为什么要有 D-SACK?
都知道有滑动窗口,那由于接收方的太忙了滑动窗口降为了 0 怎么办?发送方就永远等着了?
Silly Window 又是什么?
为什么有滑动窗口流控还需要拥塞控制?
快速重传一定要依赖三次重复 ACK ?
这篇文章我想由浅到深地过一遍 TCP,不是生硬的搬出各个知识点,从问题入手,然后从发展、演进的角度来看 TCP。
起初我在学计算机网络的时候就有非常非常多的疑问,脑子里简直充满了十万个为什么,而网络又非常的复杂,发展了这么多年东西真的太多了,今天我就大致的浅显地说一说我对 TCP 这些要点的理解。
好了,废话不多说,开始上正菜。
TCP 是用来解决什么问题?TCP 即 Transmission Control P ...
不经意间,你可能正过着一种二手人生 | 100个生活大问题
转自:http://www.qdaily.com/articles/58601.html
王朝靖2018 年 11 月 23 日
当你发现,你生活里的所有问题,在网上都能找到答案,这也就意味着,你的整个生活,别人已经过过了。
二手人生是这样一种处境:你发现你在生活里遇到的所有问题,在搜索引擎里都能找到答案。
比如说,怎么搭配衣服才低调优雅,去哪吃饭便宜又美味,买哪款耳机更划算,工作还是考研,要不要入手比特币,都有人替你解答了。你还发现有一批人用照片、视频、段子、广告为你提供了一个精心加工过的世界,这个世界常常比你自个儿的世界要美丽有趣深刻好笑有品位得多。如果把当代生活比作一场开卷考,比起你自己慢慢找答案,达人们已经为你提供了一套高分答案放到你面前让你参考。
注意,你很有可能连这些高分答案也看不上,但那多半建立在你已经对生活的这些乱七八糟的细节有所思虑的基础上,只不过你还没得出属于自己的明确结论。更有可能的是,你觉得思虑本身就乱七八糟的,所以毫无警惕地接受了高分答案。
或者不是高分答案也没关系。反正“关于这件事他们都是这样说的”。
让我们假设一种听起来有点悲伤的状况:你买的东西是点评分数 ...
Go 捕获循环变量
捕获迭代变量
现在假设有一个程序必须创建一系列的目录之后又会删除它们。可以用一个包含函数变量的slice进行清理操作
1234567891011121314var rmdirs []func()for _, d := range tempDirs() { dir := d os.MkdirAll(dir, 0755) rmdirs = append(rmdirs, func() { os.RemoveAll(dir) })}//...for _, rmdir := range rmdirs { rmdir() //清理}
在这段代码里循环变量d被赋值给新的局部变量dir,而不是直接去使用循环变量d,以下是错误示例
1234567var rmdirs[] func()for _, dir := range tempDirs() { os.MkdirAll(dir, 0755) rmdirs = append(rmdirs, func(){ ...