- 论坛徽章:
- 9
|
本帖最后由 wlmqgzm 于 2016-05-11 16:37 编辑
存储层的整体数据规划思路已经全部完成:
整体流程在脑海中完整的过了一遍.
块数据的整体设计思路已经完成, 正在书写当中, 基本上确定, 存储层的数据格式完整支持MVCC和数据库SQL标准的全部四个隔离级别: 即read uncommited, read commit, repeatable read,serializable.
比最早的想法又进了一步, 最早没有打算实现这些, 随着数据规划, 发现 在数据层的定义中 只需要修改少量关键字节, 就可以实现与innodb格式完全一致的功能.
因此, 初步计划出2个版本;
2个版本在硬盘存储格式上完全一致, 只是软件功能上做了扩展.
第一个版本1.00 按照KV数据库的标准做, 实质是实现read uncommited的SQL隔离级别版本. 先做这个版本.
第二个版本2.00 按照SQL数据库的标准做, 再陆续增加read commit, repeatable read,serializable这三个SQL隔离级别版本,
其中repeatable read 在目前的数据规划中, 与innodb类似, 实现了幻读保护, 即 repeatable read=serializable,
准确的说, 将实现两个SQL隔离级别. 在性能上, repeatable read将与read commit很接近, 主要的差别在于缓存中有效数据的多少,
我的规划实现中 repeatable read 将利用空间保护(offset隔离), 实现幻读保护, 没有像innodb一样使用间隙锁, 因此性能将更好一些.
今天心情比较高兴,自己也很意外,基本上按照KV数据库的标准,实现了SQL数据库的全部功能点的设计,而且全部是高性能设计,做完的话,会有比较好的性能
主要的技术难题的突破在MVCC的设计,找到了一条覆盖各类情况的模型.
设计压缩块/标准块的结构:
// 1) 块的位置号, 就是块的唯一标志, 位置号就是offset, 4字节整数, 位置号==实际存储的offset, 即该位置上读到的4字节数据==该位置的offset
// 2) 块的压缩格式及压缩率: 1字节, 0=不压缩, 1-9=lz4压缩, 21-29=gzip压缩, 31-39=bzip2, 先只做lz4, 其他备用
// 3) 块内部记录数:1字节. 每个数据块可存放1-240条记录, 标准块是一条记录一个块, 压缩块是1-240个记录一个块
这里保留了241-255的编号, 这些编号主要是为了未来(第2个版本)预留,
这些编号对应的内存结构, 在硬盘空间中没有使用,
在内存空间中使用, 将以特殊的方式, 提供高性能虚拟锁
每个编号将在主键上以特殊方式(类似于MVCC)提供4M个锁空间, 一共可以提供60M个锁空间,即每个table可提供最大6000万个锁空间
将用于 存储层的行锁--更新锁内部使用, 这部分代码还没有做, 但是计划在第2个版本中使用, 使用行锁以后, 将提供完整MVCC和READ COMMIT等数据库标准功能
第2个版本将实现完整的MVCC, 读取是没有任何锁, 可提供高的性能. MVCC在第一个版本中做好预留, 但是不占数据内存空间, 以便提供最好的性能
行锁是写锁,即更新锁, 正在考虑 不过都是第2个版本的事情, 这个版本只是做好预留, 按最简单的方式实现
这个字节的关键设计在于它定位于内存中8字节长整数offset的最高位,对于1-240的值将直接掩码转换为8bit全零的offset+1-240两个参数,对于241-255这个部分+3字节将转化为一个最大60M的整数,这个整数用atomic表示,依次循环使用这个参数,最大可表示60M个正在更新中的数据,实现最大6000万个虚拟锁,对于超过用户自身offset中的数据, 用户级别的MVCC是不可见的, 因此,任何在此位置上的更新,将不会被任何用户读取.
说了半天,其实就是一句话, 在没有增加新字节的情况下,实现了与MVCC以及事务处理的全兼容功能.所以,就是高效的实现.
一种激进的思路:所有的更新是MVCC的,这样每个线程都可以提交请求更新数据,但是最终的Commit是单写线程的,这样可以实现最大化的并发,考虑中.......
// 3) 块的大小, 1-5字节整数, 压缩编码整数, 表示未压缩的长度
// 4) 块的大小, 1-5字节整数, 压缩编码整数 表示压缩后实际的长度,如果不压缩,同上一个值
// 5) 块的内容 0K--3.999G
// 6) 块的校验码: 8字节, 块内容crc64校验
// 7) 块的同步码 8字节
// 块的管理用掉 4+1+1+3+3+8+8=28字节 , 对于4K字节的压缩块, 大约不到1%的开销,
|
|