WiredTiger是一种高性能的开源存储引擎,现已在MongoDB中作为内模式应用。WiredTiger支持行存储、列存储两种存储模式,采用LSM Tree方式进行索引记录
WiredTiger支持事务的ACID特性(原子性、一致性、隔离性、持久性)。对数据的存储方式可采用简易的key/value形式进行存储,也可以使用包含索引映射的数据模式层的方式进行存储。

WiredTiger存储引擎可应用于现代多核CPU架构之上。采用多种实现方式,如风险指针(hazard pointers)、无锁算法(lock-free algorithms)、快锁(fast latching)、消息传递(message passing)等方法。

风险指针(Hazard Pointers)

风险指针是一种内存管理的方法,允许内存被回收后任意重用。该内存管理方法是无等待的(wait-free)。核心操作仅需要单字的内存读取和写入访问。该方法同样提供了ABA问题的一个无锁解决方案。对于指针的管理,通常关注与如何回收已经删除掉的对象所占用的内存。在基于锁的对象的情形下,当线程从对象中删除一个节点时,在它被重用或者重新分配之前,很容易保证没有其他线程会在此后访问该节点的内存。但在无锁动态对象就出现了问题。为了保证无锁的对象的顺利执行,每个线程必须要有无限制的机会在任意时间操作该对象。

内存回收问题是如何允许被删除节点的内存被释放,同时还保证没有线程访问被释放的内存,以及如何以一种无锁的方式做到这一点。之前的用以动态无锁对象的节点重用方法主要有三种:

  1. IBM标签方法(更新计数)
  2. 无锁引用计数
  3. 基于总体引用计数或者每个线程的时间戳方法

风险指针,是一种以无锁对象的内存回收方法。它对每个被删除的节点的分摊时间是预期的常量。无论线程是失败还是延迟,它都能对不可重用的被删除节点的总数保持一个上界。其核心思想是:将一些被称为风险指针(hazard pointer)的单写者多读者的共享指针,与每个想要访问无锁对象的线程关联起来。一个风险指针要么是NULL,要么指向一个节点,该节点之后可能会被该线程访问,而不需要验证对该节点的这个引用是否有效。每个风险指针只能被其拥有者线程写入,但是可以被别的线程读取。

基础模型

基本计算模型是异步共享内存模型。在该模型中一组线程通过在一组共享内存位置上的内存访问操作原语来沟通。线程运行在任意速度,可以有任意延迟。线程对任何其他线程的速度或状态不做任何假设。

共享对象占有一组共享内存位置。对象是一个抽象的对象类型实现的实例,它定义了在对象上可以允许的操作的语义。

原子原语

除了读取和写入外,共享内存位置上的基本操作还包括CAS(compare-and-swap)和load-linked/store-conditional(LL/SC)。

CAS有三个参数:内存位置的地址、预期值、新值。当且仅当存储单元存储的是预期值的时候,新值才能原子地写入该存储单元。该操作返回一个布尔值,用以表示是否发生了写操作。

LL需要一个参数:内存位置的地址,该操作将返回其内容。SS有两个参数:一个内存位置的地址和一个新值。只有当前线程最后使用LL读取该位置之后,没有其他线程写入该内存位置,新值才会原子地写入到该内存位置的地址,并返回一个布尔值,指示自从当前线程最后使用LL读取该位置之后是否有任何其他线程写入过该内存位置。

ABA问题

问题描述如下:它发生在当一个线程从共享位置读取值A,然后其他线程改变该位置为不同的值,例如B。当该线程再次将A放回该共享位置处时,新的线程再次从该位置读取该共享位置处的值时,会误认为该值没有改变,从而错误的执行。

Hazard Pointer要解决的核心问题是如何安全释放内存,该问题解决在实现无锁算法时有两个关键的影响:

  1. 保证了关键节点的访问是合法的,不会导致程序尝试去读取已经释放了的内存。
  2. 保证了ABA问题不会出现,程序逻辑正确的前提。

无锁算法中释放内存的难点在于当线程释放了一块内存后,是无法获知是否有别的线程也同时持有该块内存的指针并需要访问。

解决方案

  1. 建立一个全局数组,数组容量为线程数目,每个线程只能修改自己的数组元素,而不允许修改其他的数组元素,但可以读别的数组元素。
  2. 当线程尝试访问一个关键数据节点时,先把该节点指针赋给自己的数组元素(即不要释放这个节点)。
  3. 每个线程自己维护一个私有链表,当线程准备释放掉某个节点时,将该节点放入到链表中。当链表内的数目达到一个设定的数目后,遍历该链表用于释放链表内所有节点。
  4. 当释放节点时,需要检查全局数组,确定没有任何一个线程的数组元素与当前指针相同时,就释放该节点。否则仍然滞留在自己的链表中。

Hazard Pointer主要应用在实现无锁队列上。

  1. 队列上的元素任何时候,只可能被其中一个线程成功地从队列上取下来,因此每个线程的链表中的元素肯定是唯一的。
  2. 线程在操作无锁队列时,任何时候基本只需要处理一个节点,如果有特殊需求,就需要有额外的扩展
  3. 对于某个节点,多线程同时持有该节点的指针的现象在时间上是非常短暂的。只有当这几个线程同时尝试取下该节点,它们才可能同时持有该节点的指针,一旦某线程成功将节点取下,其它线程很快就会发现,并尝试继续操作下一个节点。

风险指针(Hazard Pointer) 内存空间共享模型的更多相关文章

  1. 在64位系统下,指向int型的指针占的内存空间多大?

    不废话,请看代码演示如下: 注意使用的操作系统的位数,不同位数的操作系统,结果不一样! 我是用的是64位的操作系统! linux下示例代码如下: #include <stdio.h> in ...

  2. C语言指针及占据内存空间

    第一.了解内存空间 本文章文字有点多,会有点枯燥,配合图文一起看可以缓解枯燥,耐心阅读哦!!! 先了解内存地址,才更好的理解指针! 我们可以把内存想象为成一列很长很长的货运火车,有很多大小相同的车厢, ...

  3. C语言中指针占据内存空间问题

    以前一直有个疑问,指向不同类型的指针到底占用的内存空间是多大呢? 这个问题我多次问过老师,老师的答案是"指向不同类型的指针占据的内存空间大小不同",我一直很之一这个答案,今天我就做 ...

  4. 《C和指针(Pointer on c)》 学习笔记(转自:http://dsqiu.iteye.com/blog/1687944)

    首先本文是对参考中三个连接的博客进行的整理,非常感谢三位博主的努力,每次都感叹网友的力量实在太强大了…… 第一章 快速上手 1.  在C语言中用/*和*/来注释掉这段代码,这个实际上并不是十分的安全, ...

  5. 《C和指针(Pointer on c)》 学习笔记

    转载:http://dsqiu.iteye.com/blog/1687944 首先本文是对参考中三个连接的博客进行的整理,非常感谢三位博主的努力,每次都感叹网友的力量实在太强大了…… 第一章 快速上手 ...

  6. C++二级指针第二种内存模型(二维数组)

    C++二级指针第二种内存模型(二维数组) 二维数组 二维数组本质上是以数组作为数组元素的数组,即“数组的数组”. 定义 类型说明符 数组名[常量表达式][常量表达式] 例如: float a[3][4 ...

  7. lock free数据结构内存回收技术-hazard pointer

    lock free数据结构一般来说拥有比基于lock实现的数据结构更高的性能,但是其实现比基于lock的实现更为复杂,需要处理的难题包括预防ABA问题,内存如何重用和回收等.通常,最简单最有效的处理A ...

  8. C++二级指针第一种内存模型(指针数组)

    二级指针第一种内存模型(指针数组) 指针的输入特性:在主调函数里面分配内存,在被调用函数里面使用指针的输出特性:在被调用函数里面分配内存,主要是把运算结果甩出来 指针数组 在C语言和C++语言中,数组 ...

  9. C/C++ 错误笔记-在给结构体中的指针赋值时,要注意该指针是否已指向内存空间

    先来看下面的例子: #include <stdlib.h> #include <string.h> #include <stdio.h> #pragma warni ...

随机推荐

  1. SQL语句:Mac 下 处理myql 不能远程登录和本地登录问题

    mac下,mysql5.7.18连接出错,错误信息为:Access denied for user 'root'@'localhost' (using password: YES) ()里面的为she ...

  2. (转)如何入门 Python 爬虫

    “入门”是良好的动机,但是可能作用缓慢.如果你手里或者脑子里有一个项目,那么实践起来你会被目标驱动,而不会像学习模块一样慢慢学习. 另外如果说知识体系里的每一个知识点是图里的点,依赖关系是边的话,那么 ...

  3. Kafka消息存储原理

    kafka消息存储机制 (一)关键术语 复习一下几个基本概念,详见上面的基础知识文章. Broker:消息中间件处理结点,一个Kafka节点就是一个broker,多个broker能够组成一个Kafka ...

  4. Vue2.0-token权限处理

    token一种身份的验证,在大多数网站中,登录的时候都会携带token,去访问其他页面,token就想当于一种令牌.可以判断用户是否登录状态.本次页面是通过Element-ui搭建的登录界面 当用户登 ...

  5. 和我一起打造个简单搜索之ElasticSearch入门

    本文简单介绍了使用 Rest 接口,对 es 进行操作,更深入的学习,可以参考文末部分. 环境 本文以及后续 es 系列文章都基于 5.5.3 这个版本的 elasticsearch ,这个版本比较稳 ...

  6. Nginx配置资源下载目录

    访问我的博客 之前在网上找 CentOs 的镜像的时候,发现了阿里云的这个镜像源,速度蛮快的.今天也来搭建一个类似的站,使用 nginx 作为资源下载服务器. 图片详情: 安装 Nginx 参考这篇教 ...

  7. Tomcat学习总结(14)—— Tomcat常见面试题

    一.Tomcat的缺省是多少,怎么修改 Tomcat的缺省端口号是8080. 修改Tomcat端口号: 1.找到Tomcat目录下的conf文件夹 2.进入conf文件夹里面找到server.xml文 ...

  8. Java设计模式学习记录-抽象工厂模式

    前言 上篇博客介绍了简单工厂模式和工厂方法模式,这次介绍抽象工厂模式,抽象工厂模式和工厂方法模式的区别在于需要创建对象的复杂程度上. 抽象工厂模式 抽象工厂模式是围绕着一个超级工厂创建其他工厂.这个超 ...

  9. 下拉加载更多DEMO(js实现)

    项目的一个前端页面展示已购买商品时,要求能下拉加载更多.花了点时间研究这个功能,以前没做过. 首先需要给div加scroll事件,监听滚动条滚动动作.那何时触发加载动作呢?当滚动条滚到底的时候.如何判 ...

  10. textarea赋值时换行符无效的解决方法

    //替换字符串中的换行符为br var Content = JSON.stringify(txt); Content = Content.replace(/\\n/g, '<br />') ...