RocksDB - BlockBasedTable 分析
请注意,此文章尚未完成。
当此文章完结时,此声明将被删除。
参考链接:https://github.com/facebook/rocksdb/wiki/Rocksdb-BlockBasedTable-Format
- BlockBasedTable 是 RocksDB 默认的表类型。- 在 BlockBasedTable 中,数据被存储到固定大小的块,每个块依次存储数据条目。- 当我们把数据存储到块中时,数据可以被高效的压缩或编码,也就是说,最终存储到块中的数据大小,往往是远小于原始数据大小的。- 当读取一条记录时,我们首先定位这个记录所在的块,然后把这个块读到内存中,最后在这个块中查找要读取的记录。- 为了避免频繁读取一个相同的块,RocksDB 引入了块缓存将加载的块保存在内存中。
文件格式123456789101112131415<beginning_of_file>[data block 1][data block 2]...[data block N][meta block 1: filter block] ...
优雅地断开套接字连接
本篇博客将讨论如何优雅地断开相互连接的套接字。之前的方法不够优雅是因为,我们是调用 close 函数单方面断开连接的。
基于 TCP 的半关闭TCP 的断开连接过程比建立连接过程更重要,因为连接过程中一般不会出现大的变数,但断开过程有可能发生预想不到的情况,因此应准确掌控。只有掌握了下面要讲解的半关闭(Half-close),才能明确断开过程。
单方面断开连接带来的问题Linux 的 close 函数意味着完全断开连接。完全断开不仅指无法传输数据,而且也不能接收数据。因此,在某些情况下,通信一方调用 close 函数断开连接就显得不太优雅。如下图。
上图描述的是 2 台主机正在进行双向通信。主机 A 发送完最后的数据后,调用 close 函数断开了连接,之后主机 A 无法再接收主机 B 传输的数据。实际上,是完全无法调用与接收数据相关的函数。最终,由主机 B 传输的、主机 A 必须接收的数据也销毁了。
为了解决这类问题,“只关闭一部分数据交换中使用的流”(Half-close)的方法应运而生。断开一部分连接是指,可以传输数据但无法接收,或可以接收数据但无法传输。顾名思义就是只关闭流 ...
基于 TCP/IP 的服务器/客户端实现数值运算
下面编写程序以体验应用层协议的定义过程。该程序中,服务器端从客户端获得多个数字和运算符信息。服务器端收到数字后对其进行加减乘运算,然后把结果传回客户端。例如,向服务器端传递3、5、9的同时请求加法运算,则客户端收到3+5+9的运算结果;若请求做乘法运算,则客户端收到3x5x9的运算结果。而如果向服务器端传递4、3、2的同时要求做减法,则客户端将收到4-3-2的运算结果,即第一个参数成为被减数。
下面的代码与前面的服务器/客户端编程代码总体是一样的。区别在于对发送、接收数据的处理。
服务器端代码12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912 ...
实现迭代服务器端/客户端
此篇博客编写回声(echo)服务器端/客户端。顾名思义,服务器端将客户端传输的字符串数据原封不动地传回客户端,就像回声一样。在此之前,需要先解释一下迭代服务器端。
实现迭代服务器端之前讨论过的服务器端处理完 1 个客户端连接请求即退出,连接请求等待队列实际没有太大意义。但这并非我们想象的服务器端。设置好等待队列的大小后,应想所有客户端提供服务。如果想继续受理后续的客户端连接请求,应怎样扩展代码?最简单的办法就是插入循环语句反复调用 accept 函数,如下图所示。
从上图可以看出,调用 accept 函数后,紧接着调用 I/O 相关的 read、write 函数,然后调用 close 函数。这并非针对服务器端套接字,而是针对 accept 函数调用时创建的套接字。
调用 close 函数就意味着结束了针对某一客户端的服务。此时如果还想服务于其他客户端,就要重新调用 accept 函数。
目前,我们实现的服务器,同一时刻只能服务于一个客户端。将来学完进程和线程后,就可以编写同时服务多个客户端的服务器端了。
迭代回声服务器端/客户端前面讲的就是迭代服务器端。即使服务器端以迭代方式运转, ...
实现基于 TCP 的服务器端/客户端
此篇博客将在 Linux 下实现完整的 TCP 服务器端,在此过程中大家将理解套接字使用方法及数据传输方法。
TCP 服务器端TCP 服务器端的默认函数调用顺序下图给出了 TCP 服务器端默认的函数调用顺序,绝大部分 TCP 服务器端都按照该顺序调用。
调用 socket 函数创建套接字,声明并初始化地址信息结构体变量,调用 bind 函数向套接字分配地址。这 2 个阶段之前都已讨论过(参见Linux 下 C 语言网络地址初始化),下面讲解之后的几个过程。
进入等待连接请求状态我们已调用 bind 函数给套接字分配了地址,接下来就要通过调用 listen 函数进入等待连接请求状态。只有调用了 listen 函数,客户端才能进入可发出链接请求的状态。换言之,这时客户端才能调用 connect 函数(若提前调用将发生错误)。
1234#include <sys/socket.h>int listen(int sock, int backlog);// 成功时返回 0,失败时返回 -1。
sock: 希望进入等待连接请求状态的套接字文件描述符,传递的描述符套接字参数成为服务器端 ...
Linux 下 C 语言网络地址初始化
这里介绍套接字创建过程中常见的网络地址信息初始化方法。1234567struct sockaddr_in addr;char* serv_ip = "211.217.168.13"; // 声明 ID 地址字符串char* serv_port = "9190"; // 声明端口号字符串memset(&addr, 0, sizeof(addr)); // 结构体变量 addr 的所有成员初始化为 0addr.sin_family = AF_INET; // 指定地址族addr.sin_addr.s_addr = inet_addr(serv_ip); // 基于字符串的 IP 地址初始化addr.sin_port = htons(atoi(serv_port)); // 基于字符串的端口号初始化
123456struct sockaddr_in addr;char* serv_port = "9190"; // 声明端口号字符串memset( ...
套接字协议及其数据传输特性
创建套接字123#include <sys/socket.h>int socket(int domain, int type, int protocol);
domain: 套接字中使用的协议族(Protocol Family)信息。
type: 套接字数据传输类型信息。
protocol: 计算机间通信中使用的协议信息。
协议族(Protocol Family)套接字通信中的协议具有一些分类。通过 socket 函数的第一个参数传递套接字中使用的协议分类信息。此协议分类信息称为协议族,可分为如下几类。|名称|协议族||-|-||PF_INET|IPv4 互联网协议族||PF_INET6|IPv6 互联网协议族||PF_LOCAL|本地通信的 UNIX 协议族||PF_PACKET|底层套接字的协议族||PF_IPX|IPX Novell 协议族|
本博客将着重讲解上表中的 PF_INET 对应的 IPv4 互联网协议族。其他协议族并不常用或尚未普及,因此本博客将重点放在 PF_INET 协议族上。另外,套接字中实际采用的最终信息是通过 socket 函数的第三个参数 ...
Linux 下的 ANSI 标准 I/O 函数
打开文件 fopen()用于文件和终端的输入输出,类似于系统调用 open。1234#include <stdio.h>FILE * fopen(const char *filename, const char *mode);// 成功时返回一个 FILE * 指针,失败时返回 NULL。
filename: 要打开的文件。
mode: 打开文件的方式,有一些取值。
关于 FILE 的结构,如下:1234567typedef struct _iobuf { int cnt; // 剩余字符数 char *ptr; // 下一个字符的位置 char *base; // 缓冲区的位置 int flag; // 文件访问模式 int fd; // 文件描述符} FILE;
关于 mode 参数的取值如下:|值(字符串)|含义||-|-||”r”, “rb”|以只读方式打开文件。||”w”, “wb”|以写方式打开文件,并把文件长度截断为0。||”a”, “ab”|以写方式打开文件, ...
Linux 下的底层文件 I/O 函数
打开文件首先介绍打开文件以及读写数据的函数。调用此函数时需传递两个参数:第一个参数是打开的目标文件名及路径信息,第二个参数是文件打开模式(文件特性信息)。:spider:
123456#include <sys/type.h>#include <sys/stat.h>#include <fcntl.h>int open(const char* path, int flag);// 成功时返回文件描述符,失败时返回 -1。
path: 文件名的字符串地址。
flag: 文件打开模式信息。
此函数第二个参数 flag 可能的常量值如下:
打开模式
含义
O_CREAT
必要时创建文件
O_TRUNC
删除全部现有数据
O_APPEND
维持现有数据,保存到其后面
O_RDONLY
只读打开
O_WRONLY
只写打开
O_RDWR
读写打开
如需传递多个参数,则应通过位或运算(OR)符组合传递。
关闭文件使用文件后必须关闭。下面介绍关闭文件时调用的函数。
1234#include <unistd.h& ...
macOS 下配置 SSH 免密登录
1. 检查是否已存在公私钥对打开终端,输入 cd ~/.ssh,然后输入 ls,看看有哪些公私钥文件。在输出的文件中,带有 .pub 后缀的是公钥,不带的是私钥。
如果系统中已有公私钥对,那么可以什么都不做。
如果系统中没有公私钥对,输入 ssh-keygen,根据交互,创建一个新的公私钥对,创建完后可通过 ls 命令查看。
2. 上传公钥到服务器将公钥文件从本地上传到服务器指定目录。在终端中输入 ssh-copy-id -i [公钥文件] [user]@[host],其中公钥文件就是前面 ls 看到的,带有 .pub 后缀的文件,user 是服务器的用户名,host 是服务器 IP 地址。这里会要求输入密码。例如,我输入的是 ssh-copy-id -i id_rsa.pub root@49.232.2.120。
现在,通过 ssh 连接我们的服务器,就不再需要密码啦!
3. ssh-add (不一定需要)如果通过上面的两个步骤,已经实现了免密,则忽略此步骤。如果没有实现免密,输入 ssh-add -K [你的私钥文件],私钥文件就是后缀没有 .pub 的那个。例如,ssh-ad ...