动态规划问题思维导图
附图一张
Redis设计与实现(1-字符串)
每个sds.h/sdshdr结构表示一个SDS值:
struct sdshdr{ //记录buf数组重已使用字节的数量,等于SDS所保存字符串的长度 int len; //记录buf数组中未使用字节的数量 int free; //字节数组,用来保存字符串 char buf[];}
free属性的值为0,表示这个SDS没有分配任何未使用空间。
len属性的值为5,表示这个SDS保存了一个五字节长的字符串。
buf属性是一个char类型的数组,最后一个字节保存空字符’\0’。
SDS遵循C字符串以空字符结尾的惯例,保存空字符的1字节空间不计算在SDS的len属性里面。
示例:
SDS遵循C字符串以空字符结尾的惯例,保存空字符的1字节空间不计算在SDS的len属性里面。
通过 len 属性,SDS 获取字符串长度时,其时间复杂度为 O(1) 。
通过检查SDS的空间是否满足修改所需的要求,杜绝了缓冲区溢出的可能性。
当 SDS API 需要对SDS进行修改时,API 会先检查SDS的空间是否满足修改所需的要求,如果不满 ...
Redis设计与实现(2-链表)
链表是Redis底层用非常广泛的数据结构。使用范围包含但不限于:列表键,发布与订阅、慢查询、监视器、客户端状态信息等
链表节点实现每个链表节点使用一个adlist.h/listNode结构来表示:
typedef struct listNode{ //前置节点 struct listNode * prev; //后置节点 struct listNode * next; //节点值 void * value;}listNode;
使用多个listNode结构就可以组成链表,但使用adlist.h/list来持有链表的话,操作起来会更方便:
typedef struct list{ //头节点 listNode * head; //尾节点 listNode * tail; //链表节点数量 unsigned long len; //节点值复制函数 void *(*dup)(void *ptr); //节点值释放函数 void *(*free)( ...
Redis 设计与实现(3-字典)
字典:用于保存键值对(key-value pair)的抽象数据结构。
字典是Redis的数据库的底层实现,也是哈希的底层实现之一,但由于C语言没有字典这一数据结构,所以Redis自己构建了该数据结构。
字典的实现Redis的字典使用哈希表作为底层实现,一个哈希表里面可以有多个哈希表节点,而每个哈希表节点就保存了字典中的一个键值对。
Redis的哈希表实现Redis字典所使用的哈希表由dict.h/dictht结构定义:
typedef struct dictht{ //哈希表数组 dictEntry **table; //哈希表大小 unsigned long size; //哈希表大小掩码。用于计算索引值,总是等于size - 1 unsigned long sizemask; //哈希表已有节点的数量 unsigned long used;} dictht;
table属性是一个数组,数组中的每个元素都是一个指向dict.h/dictEntry结构的指针,每个dictEntry结构保存着一个 ...
CentOS7 安装Redis6.0
今天给一台崭新的服务器(CentOS 7.7)安装Redis时才发现,Redis已经更新到了6.0(手动滑稽),抱着用心不用旧的心态,立马喜滋滋地下载,上传到服务器上面开始安装,结果刚开始就碰壁了。再次记录一下安装的小坑。本文不讨论Redis6.0的新特性,仅记录安装踩到的坑。
下载Redis6.0
使用linux wget命令:
wget http://download.redis.io/releases/redis-6.0.1.tar.gz
前往官网下载,使用文件传输工具传输至服务器。
安装依赖安装Redis需要安装依赖,命令如下:
yum install gcc gcc-c++ -y
需要注意的是,Redis6.0需要gcc版本不能过低,最好5.0版本以上,否则会编译出错。
升级系统gcc命令如下:
安装centos-release-scl。
yum install centos-release-scl
安装devtoolset,注意,如果想安装7.版本的,就改成devtoolset-7-gcc。
yum install devtoolset-8-gc ...
深入 dict 机制,转化类变量
前言
一般情况下,我们在初始化 dict (字典)时会直接 {key: value} 这么定义,亦或是使用 dict(key=value) 定义使用。而当处理对象变成了在一个类,在使用 obj.__dict__ 魔法函数时,我们拿到的将会是这个类的实例变量,定义在类体中的类变量,我们是无法直接获取到的。
纷争开始
要想实现以 dict 的方式读取类/实例变量,我们duck不必使用库或其他依赖。下面我们看个例子:
上述代码在实际运行时,将会得到 TypeError: ‘A’ object is not iterable 的错误。这是因为 dict 对象是需要可迭代的,也就是需要属于 iter,或者实现其所有方法。
我们再看一个例子:
当我们在 keys 这个方法上打上断点,以断点调试的方法运行程序时会发现,程序将会停在这一行代码上。这是因为,在默认情况下,我们在将对象直接传给 dict 的时候,dict 将会去这个类里寻找 keys 方法,以期望拿到字典的所有键。而这些键是由我们自己定义并返回的。再看下面的例子:
运行上述代码我们将会得到 Type ...
自建博客,关于建站方式的一些事儿
关于博客自建,网上已经有很多详细的教程了,但看到这些教程的前提是咱自个儿得知道博客的搭建方式是什么。是自有服务器搭建?还是挂载第三方搭建?是自己写代码还是别的方式等等。
本文将会列出几种常用的博客搭建的方式,下面正文开始。
WordPress
这是每一个博主都跳不过的搭建方法。
目前大多数的博客网站都是基于WordPress来搭建的。通过它我们可以很方便的搭建属于自己的博客网站。
一方面,它很重,需要进行繁多的配置。另一方面,自有服务器是基础。
得益于Docker容器化,现在可以很方便的部署WordPress程序,不再需要我们自己手动安装PHP以及其他依赖来部署。
写作 - 部署方式
点击 文章标签,新建文章。
输入文章内容,选择号分类和标签。
发布。
网站截图:
前端:
博客后台:
Vuepress/Vitepress
这是现在很流行的一种搭建方法。
现在有很多博主选择使用这种方式来搭建自己的博客,简洁,轻便。许多公司的技术、接口等文档也都是基于这种方式。
它需要我们有点代码基础。
它可以部署在自己的服务器上,也可以挂载到第三方服务(Github Pages等。)
挂 ...
Redis 设计与实现(11-事件)
Redis 服务器是一个 事件驱动程序,服务器需要处理以下两类事件:
文件事件(file event):Redis服务器通过套接字与客户端进行连接,而文件事件就是服务器对 套接字操作 的抽象。服务器与客户端的通信会产生相应的文件事件,而服务器则通过监听并处理这些事件来完成一系列网络通信操作。
时间事件(time event):Redis服务器中的一些操作(比如serverCron函数)需要在给定的时间点执行,而时间事件就是服务器对这类 定时操作 的抽象。
文件事件Redis 基于 Reactor 模式开发了自己的网络事件处理器:这个处理器被称为 文件事件处理器(fileevent handler):
文件事件处理器使用 I/O 多路复用(multiplexing)来同时监听多个套接字,并根据套接字目前执行的任务来为套接字关联不同的事件处理器。
当被监听的套接字准备好执行连接应答(accept)、读取(read)、写入(write)、关闭(close)等操作时,与操作相对应的文件事件就会产生,这时文件事件处理器就会调用套接字之前关联好的事件处理器来处理这些事件。
虽然文 ...
Redis 设计与实现(10-AOF持久化)
与RDB持久化通过保存数据库中的键值对来记录数据库状态不同,AOF持久化是通过保存Redis服务器所执行的写命令来记录数据库状态的。
AOF持久化保存数据库状态的方法是将服务器执行的SET、SADD、RPUSH三个命令保存到AOF文件中。被写入AOF文件的所有命令以Redis的命令请求协议格式保存。
持久化的实现AOF持久化功能的实现可以分为命令追加(append)、文件写入、文件同步(sync)三个步骤。
命令追加当AOF持久化功能打开时,服务器在执行完一个写命令之后,会以协议格式将被执行的写命令追加到服务器状态的aof_buf缓冲区的末尾:
struct redisServer{ //AOF 缓冲区 sds aof_buf;};
文件的写入与同步Redis的服务器进程就是一个事件循环(loop),循环中的文件事件负责接收客户端的命令请求,以及向客户端发送命令回复,时间事件则负责执行像serverCron函数这样需要定时运行的函数。
由于服务器在处理文件事件时可能会执行写命令,使得命令被追加到aof_buf缓冲区里面,所以服务器每次结束一个事件循环之前,都 ...
Redis 设计与实现(9-RDB持久化)
目的为了方便起见,将服务器中的非空数据库以及它们的键值对统称为数据库状态。
为了解决服务器进程退出,数据库状态也会消失不见的问题,Redis提供了RDB持久化功能,这个功能可以将Redis在内存中的数据库状态保存到磁盘里面,避免数据意外丢失。
RDB持久化既可以手动执行,也可以根据服务器配置选项定期执行,该功能可以将某个时间点上的数据库状态保存到一个RDB文件中。
RDB持久化功能所生成的RDB文件是一个经过压缩的二进制文件,通过该文件可以还原生成RDB文件时的数据库状态。
RDB文件的创建与载入有两个Redis命令可以用于生成RDB文件,一个是SAVE,另一个是BGSAVE。
SAVE:阻塞Redis服务器进程,直到RDB文件创建完毕为止。
BGSAVE:派生出一个子进程,由子进程负责创建RDB文件,服务器进程(父进程)继续处理命令请求。
创建RDB文件的实际工作由rdb.c/rdbSave函数完成,SAVE命令和BGSAVE命令会以不同的方式调用这个函数,两个方法的区别如下伪代码所示:
def save(): rdbSave()def bgsave(): ...