精华内容
参与话题
问答
  • Buffer Manager

    2017-05-06 04:28:33
    As a part of the team you will be responsible for the Buffer Manager. Data blocks being read by DBMS from the hard drive are stored in the main memory in a fixed number of pre-allocated buffers. Each...
  • 习惯用 Json、XML 数据存储格式的你们,相信大多都没听过Protocol Buffer Protocol Buffer 其实 是 Google出品的一种轻量 & 高效的结构化数据存储格式,性能比 Json、XML 真的强!太!多! 由于 Google出品,我相信...

    前言

    • 习惯用 Json、XML 数据存储格式的你们,相信大多都没听过Protocol Buffer
    • Protocol Buffer 其实 是 Google出品的一种轻量 & 高效的结构化数据存储格式,性能比 Json、XML 真的强!太!多!

    由于 Google出品,我相信Protocol Buffer已经具备足够的吸引力

    • 今天,我将讲解为什么Protocol Buffer的性能如此的好:
      a. 序列化速度 & 反序列化速度快
      b. 数据压缩效果好,即序列化后的数据量体积小

    阅读本文前请先阅读:

    1. 快来看看Google出品的Protocol Buffer,别只会用Json和XML了
    2. 手把手教你如何安装Protocol Buffer
    3. 这是一份很有诚意的 Protocol Buffer 语法详解

    目录

    目录


    1. 定义

    一种 结构化数据 的数据存储格式(类似于 XML、Json

    1. Google 出品 (开源)
    2. Protocol Buffer 目前有两个版本:proto2proto3
    3. 因为proto3 还是beta 版,所以本次讲解是 proto2

    2. 作用

    通过将 结构化的数据 进行 串行化(序列化),从而实现 数据存储 / RPC 数据交换的功能

    1. 序列化: 将 数据结构或对象 转换成 二进制串 的过程
    2. 反序列化:将在序列化过程中所生成的二进制串 转换成 数据结构或者对象 的过程

    3. 特点

    • 对比于 常见的 XML、Json 数据存储格式,Protocol Buffer有如下特点:

    Protocol Buffer 特点


    4. 应用场景

    传输数据量大 & 网络环境不稳定 的数据存储、RPC 数据交换 的需求场景

    如 即时IM (QQ、微信)的需求场景


    总结

    传输数据量较大的需求场景下,Protocol BufferXML、Json 更小、更快、使用 & 维护更简单!


    5. 使用流程

    关于 Protocol Buffer 的使用流程,具体请看我写的文章:快来看看Google出品的Protocol Buffer,别只会用Json和XML了


    6. 知识基础

    6.1 网络通信协议

    • 序列化 & 反序列化 属于通讯协议的一部分
    • 通讯协议采用分层模型:TCP/IP模型(四层) & OSI 模型 (七层)

    通信协议结构

    • 序列化 / 反序列化 属于 TCP/IP模型 应用层 和 OSI`模型 展示层的主要功能:

      1. (序列化)把 应用层的对象 转换成 二进制串
      2. (反序列化)把 二进制串 转换成 应用层的对象
    • 所以, Protocol Buffer属于 TCP/IP模型的应用层 & OSI模型的展示层

    6.2 数据结构、对象与二进制串

    不同的计算机语言中,数据结构,对象以及二进制串的表示方式并不相同。

    a. 对于数据结构和对象

    • 对于面向对象的语言(如Java):对象 = Object = 类的实例化;在Java中最接近数据结构 即 POJOPlain Old Java Object),或Javabean(只有 setter/getter 方法的类)

    • 对于半面向对象的语言(如C++),对象 = class,数据结构 = struct

    b. 二进制串

    • 对于C++,因为具有内存操作符,所以 二进制串 容易理解:C++的字符串可以直接被传输层使用,因为其本质上就是以 '\0' 结尾的存储在内存中的二进制串
    • 对于 Java,二进制串 = 字节数组 =byte[]
    1. byte 属于 Java 的八种基本数据类型
    2. 二进制串 容易和 String混淆:String 一种特殊对象(Object)。对于跨语言间的通讯,序列化后的数据当然不能是某种语言的特殊数据类型。

    6.3 T - L - V 的数据存储方式

    • 定义
      Tag - Length - Value标识 - 长度 - 字段值 存储方式

    • 作用
      标识 - 长度 - 字段值 表示单个数据,最终将所有数据拼接成一个 字节流,从而 实现 数据存储 的功能

    其中 Length可选存储,如 储存Varint编码数据就不需要存储Length

    • 示意图

    最终存储的字节流

    • 优点
      从上图可知,T - L - V 存储方式的优点是
      1. 不需要分隔符 就能 分隔开字段,减少了 分隔符 的使用
      2. 各字段 存储得非常紧凑,存储空间利用率非常高
      3. 若 字段没有被设置字段值,那么该字段在序列化时的数据中是完全不存在的,即不需要编码

    相应字段在解码时才会被设置为默认值


    7. 序列化原理解析

    请记住Protocol Buffer三个关于数据存储 的重要结论:

    • 结论1: Protocol Buffer将 消息里的每个字段 进行编码后,再利用T - L - V 存储方式 进行数据的存储,最终得到的是一个 二进制字节流

    序列化 = 对数据进行编码 + 存储

    • 结论2:Protocol Buffer对于不同数据类型 采用不同的 序列化方式(编码方式 & 数据存储方式),如下图:
      数据类型 对应的编码方式

    从上表可以看出:

    1. 对于存储Varint编码数据,就不需要存储字节长度 Length,所以实际上Protocol Buffer的存储方式是 T - V
    2. Protocol Buffer采用其他编码方式(如LENGTH_DELIMITED)则采用T - L - V
    • 结论3:因为 Protocol Buffer对于数据字段值的 独特编码方式 & T - L - V数据存储方式,使得 Protocol Buffer序列化后数据量体积如此小

    下面,我将对不同的编码方式 & 数据存储方式进行逐一讲解。


    7.1 Wire Type = 0时的编码 & 数据存储方式

    Wire Type = 0时的编码 & 数据存储方式

    7.1.1 编码方式: Varint & Zigzag

    A. Varint编码方式介绍

    i. 简介

    • 定义:一种变长的编码方式
    • 原理:用字节 表示 数字:值越小的数字,使用越少的字节数表示
    • 作用:通过减少 表示数字 的字节数 从而进行数据压缩

    如:

    • 对于 int32 类型的数字,一般需要 4个字节 表示;
    1. 若采用 Varint编码,对于很小的 int32 类型 数字,则可以用 1个字节 来表示
    2. 虽然大的数字会需要 5 个 字节 来表示,但大多数情况下,消息都不会有很大的数字,所以采用 Varint方法总是可以用更少的字节数来表示数字

    ii. 原理介绍

    • 源码分析
    private void writeVarint32(int n) {                                                                                    
      int idx = 0;  
      while (true) {  
        if ((n & ~0x7F) == 0) {  
          i32buf[idx++] = (byte)n;  
          break;  
        } else {  
          i32buf[idx++] = (byte)((n & 0x7F) | 0x80);  
          // 步骤1:取出字节串末7位
          // 对于上述取出的7位:在最高位添加1构成一个字节
          // 如果是最后一次取出,则在最高位添加0构成1个字节
    
          n >>>= 7;  
          // 步骤2:通过将字节串整体往右移7位,继续从字节串的末尾选取7位,直到取完为止。
        }  
      }  
      trans_.write(i32buf, 0, idx); 
          // 步骤3: 将上述形成的每个字节 按序拼接 成一个字节串
          // 即该字节串就是经过Varint编码后的字节
    }   
    
    

    从上面可看出:Varint 中每个 字节 的最高位 都有特殊含义:

    • 如果是 1,表示后续的 字节 也是该数字的一部分
    • 如果是 0,表示这是最后一个字节,且剩余 7位 都用来表示数字

    所以,当使用Varint解码时时,只要读取到最高位为0的字节时,就表示已经是Varint的最后一个字节

    因此:

    • 小于 128 的数字 都可以用 1个字节 表示;
    • 大于 128 的数字,比如 300,会用两个字节来表示:10101100 00000010

    下面,我将用两个个例子来说明Varint编码方式的使用

    • 目的:对 数据类型为Int32 的 字段值为296 和字段值为104 进行Varint编码
    • 以下是编码过程

    Varint编码过程

    从上面可以看出:

    • 对于 int32 类型的数字,一般需要 4 个字节 来表示;
    • 但采用 Varint 方法,对于很小的 Int32 类型 数字(小于256),则可以用 1个字节 来表示;

    以此类推,比如300也只需要2个字节

    • 虽然大的数字会需要 5 个字节 来表示,但大多数情况下,消息都不会有很大的数字
    • 所以采用 Varint 方法总是可以用更少的字节数来表示数字,从而更好地实现数据压缩

    下面继续看如何解析经过Varint 编码的字节

    Varint 编码方式的不足

    • 背景:在计算机内,负数一般会被表示为很大的整数

    因为计算机定义负数的符号位为数字的最高位

    • 问题:如果采用 Varint编码方式 表示一个负数,那么一定需要 5 个 byte(因为负数的最高位是1,会被当做很大的整数去处理)
    • 解决方案: Protocol Buffer 定义了 sint32 / sint64 类型表示负数,通过先采用 Zigzag 编码(将 有符号数 转换成 无符号数),再采用 Varint编码,从而用于减少编码后的字节数
      表示负数时采用Zigzag编码
    1. 对于int32 / int64 类型的字段值(正数),Protocol Buffer直接采用 Varint编码
    2. 对于sint32 / sint64 类型的字段值(负数),Protocol Buffer会先采用 Zigzag 编码,再采用 Varint编码
    • 总结:为了更好地减少 表示负数时 的字节数,Protocol BufferVarint编码上又增加了Zigzag 编码方式进行编码
    • 下面将详细介绍 Zigzag编码方式

    B. Zigzag编码方式详解

    i. 简介

    • 定义:一种变长的编码方式
    • 原理:使用 无符号数 来表示 有符号数字;
    • 作用:使得绝对值小的数字都可以采用较少 字节 来表示;

    特别是对 表示负数的数据 能更好地进行数据压缩

    b. 原理

    • 源码分析
    
    public int int_to_zigzag(int n)
    // 传入的参数n = 传入字段值的二进制表示(此处以负数为例)
    // 负数的二进制 = 符号位为1,剩余的位数为 该数绝对值的原码按位取反;然后整个二进制数+1
    {
            return (n <<1) ^ (n >>31);   
            // 对于sint 32 数据类型,使用Zigzag编码过程如下:
            // 1. 将二进制表示数 左移1位(左移 = 整个二进制左移,低位补0)
            // 2. 将二进制表示数 右移31位 
                  // 对于右移:
                  // 首位是1的二进制(有符号数),是算数右移,即右移后左边补1
                  // 首位是0的二进制(无符号数),是逻辑左移,即右移后左边补0
            // 3. 将上述二者进行异或
    
            // 对于sint 64 数据类型 则为: return  (n << 1> ^ (n >> 63) ;
    }
    
    
    // 附:将Zigzag值解码为整型值
    public int zigzag_to_int(int n) 
    {
            return(n >>> 1) ^ -(n & 1);
    // 右移时,需要用不带符号的移动,否则如果第一位数据位是1的话,就会补1
    }
     
    
    
    • 实例说明:将 -2进行 Zigzag编码:

    Zigzag编码

    • Zigzag 编码 是补充 Varint编码在 表示负数 的不足,从而更好的帮助 Protocol Buffer进行数据的压缩
    • 所以,如果提前预知字段值是可能取负数的时候,记得采用sint32 / sint64 数据类型

    总结

    Protocol Buffer 通过VarintZigzag编码后大大减少了字段值占用字节数。

    7.1.2 存储方式:T - V

    • 消息字段的标识号、数据类型 & 字段值经过 Protocol Buffer采用 Varint & Zigzag 编码后,以 T - V 方式进行数据存储

    对于 Varint & Zigzag 编码,省略了T - L - V中的字节长度Length

    Varint & Zigzag数据存储方式

    下面将详细介绍T - V 存储方式中的存储细节:Tag & Value

    1. Tag

    • 定义:经过 Protocol Buffer采用Varint & Zigzag编码后 的消息字段 标识号 & 数据类型 的值
    • 作用:标识 字段
    1. 存储了字段的标识号(field_number)和 数据类型(wire_type),即Tag = 字段数据类型(wire_type) + 标识号(field_number
    2. 占用 一个字节 的长度(如果标识号超过了16,则占用多一个字节的位置)
    3. 解包时,Protocol Buffer根据 TagValue 对应于消息中的 字段
    • 具体使用
    // Tag 的具体表达式如下
     Tag  = (field_number << 3) | wire_type
    // 参数说明:
    // field_number:对应于 .proto文件中消息字段的标识号,表示这是消息里的第几个字段
    // field_number << 3:表示 field_number = 将 Tag的二进制表示 右移三位 后的值 
    // field_num左移3位不会导致数据丢失,因为表示范围还是足够大地去表示消息里的字段数目
    
    //  wire_type:表示 字段 的数据类型
    //  wire_type = Tag的二进制表示 的最低三位值
    //   wire_type的取值
     enum WireType { 
          WIRETYPE_VARINT = 0, 
          WIRETYPE_FIXED64 = 1, 
          WIRETYPE_LENGTH_DELIMITED = 2, 
          WIRETYPE_START_GROUP = 3, 
          WIRETYPE_END_GROUP = 4, 
          WIRETYPE_FIXED32 = 5
       };
    
    // 从上面可以看出,`wire_type`最多占用 3位 的内存空间(因为 3位 足以表示 0-5 的二进制)
    
    //  以下是 wire_type 对应的 数据类型 表
    

    wire_type对应数据类型

    • 实例说明
    // 消息对象
     message person
     { 
        required int32     id = 1;  
        // wire type = 0,field_number =1 
        required string    name = 2;  
        // wire type = 2,field_number =2 
      }
    
    //  如果一个Tag的二进制 = 0001 0010
    标识号 = field_number = field_number  << 3 =右移3位 =  0000 0010 = 2
    数据类型 = wire_type = 最低三位表示 = 010 = 2
    

    2. Value

    经过 Protocol Buffer采用Varint & Zigzag编码后 的消息字段的值

    7.1.3 实例说明

    下面通过一个实例进行整个编码过程的说明:

    • 消息说明
    message Test
    {
    
    required int32 id1 = 1;
    
    required int32 id2 = 2;
    }
    
    // 在代码中给id1 附上1个字段值:296
    // 在代码中给id2 附上1个字段值:296
    Test.setId1(300);
    Test.setId2(296);
    
    // 编码结果为:二进制字节流 = [8,-84,2,16, -88, 2]
    
    • 整个编码过程如下

    编码过程


    7.2 Wire Type = 1& 5时的编码&数据存储方式

    Wire Type = 1& 5时的编码&数据存储方式

    • 64(32)-bit编码方式较简单:编码后的数据具备固定大小 = 64位(8字节) / 32位(4字节)

    两种情况下,都是高位在后,低位在前

    • 采用T - V方式进行数据存储,同上。

    7.3 Wire Type = 2时的 编码 & 数据存储方式

    Wire Type = 2时的编码&数据存储方式

    • 对于编码方式:

    编码方式

    • 数据存储方式: T - L - V

    数据存储示意图

    此处主要讲解三种数据类型:

    • String类型
    • 嵌套消息类型(Message
    • 通过packed修饰的 repeat 字段(即packed repeated fields

    1. String类型

    字段值(即V) 采用UTF-8编码

    编码 & 存储方式

    • 例子:
    message Test2
    {
        required string str = 2;
    }
    
    // 将str设置为:testing
    Test2.setStr(“testing”)
    
    // 经过protobuf编码序列化后的数据以二进制的方式输出
    // 输出为:18, 7, 116, 101, 115, 116, 105, 110, 103
    
    

    实例

    2. 嵌套消息类型(Message)

    • 存储方式:T - L - V
    1. 外部消息的 V即为 嵌套消息的字段
    2. T - L -V 里嵌套了一系列的 T - L -V
    • 编码方式:字段值(即V) 根据字段的数据类型采用不同编码方式

    编码 & 存储方式

    • 实例
      定义如下嵌套消息:
    message Test2
    {
        required string str = 1;
        required int32 id1 = 2;
    
        
    }
    
    message Test3 {
      required Test2 c = 1;
    }
    
    // 将Test2中的字段str设置为:testing
    // 将Test2中的字段id1设置为:296
    // 编码后的字节为:10 ,12 ,18,7,116, 101, 115, 116, 105, 110, 103,16,-88,2
    

    编码 & 存储方式如下

    编码 & 存储方式

    3. 通过packed修饰的 repeat 字段

    repeated 修饰的字段有两种表达方式:

    message Test
    {
        repeated int32 Car = 4 ;
        // 表达方式1:不带packed=true
    
        repeated int32 Car = 4 [packed=true];
        // 表达方式2:带packed=true
        // proto 2.1 开始可使用
    
    // 区别在于:是否连续存储repeated类型数据
    }
    
    
    // 在代码中给`repeated int32 Car`附上3个字段值:3、270、86942
    
    Test.setCar(3);
    Test.setCar(270);
    Test.setCar(86942);
    
    • 背景:对于同一个 repeated字段、多个字段值来说,他们的Tag都是相同的,即数据类型 & 标识号都相同

    repeated类型可以看成是数组

    • 问题:若以传统的多个 T - V对存储(不带packed=true),则会导致Tag的冗余,即相同的Tag存储多次;

    不带pack的存储方式

    • 解决方案:采用带packed=truerepeated 字段存储方式,即将相同的 Tag 只存储一次、添加 repeated 字段下所有字段值的长度Length、连续存储 repeated 字段值,组成一个大的Tag - Length - Value -Value -Value对,即T - L - V - V - V对。

    带pack的存储方式

    通过采用带packed=truerepeated 字段存储方式,从而更好地压缩序列化后的数据长度。

    特别注意

    • Protocol Bufferpacked修饰只用于repeated字段 或 基本类型的repeated字段
    • 用在其他字段,编译 .proto 文件时会报错

    8. 特别注意

    • 注意1:若 required字段没有被设置字段值,那么在IsInitialized()进行初始化检查会报错并提示失败

    所以 required字段必须要被设置字段值

    • 注意2:序列化顺序 是根据 Tag标识号 从小到大 进行编码

    .proto文件内 字段定义的数据无关

    • 注意3:T - V的数据存储方式保证了Protobuf的版本兼容:高<->低 或 低<->高都可以适配

    若新版本 增加了 required 字段, 旧版本 在数据解码时会认为IsInitialized() 失败,所以慎用 required字段


    9. 使用建议

    根据上面的序列化原理分析,我总结出以下Protocol Buffer的使用建议

    通过下面建议能有效降低序列化后数据量的大小

    • 建议1:多用 optionalrepeated修饰符
      因为若optionalrepeated 字段没有被设置字段值,那么该字段在序列化时的数据中是完全不存在的,即不需要进行编码

    相应的字段在解码时才会被设置为默认值

    • 建议2:字段标识号(Field_Number)尽量只使用 1-15,且不要跳动使用
      因为Tag里的Field_Number是需要占字节空间的。如果Field_Number>16时,Field_Number的编码就会占用2个字节,那么Tag在编码时也就会占用更多的字节;如果将字段标识号定义为连续递增的数值,将获得更好的编码和解码性能

    • 建议3:若需要使用的字段值出现负数,请使用 sint32 / sint64,不要使用int32 / int64
      因为采用sint32 / sint64数据类型表示负数时,会先采用Zigzag编码再采用Varint编码,从而更加有效压缩数据

    • 建议4:对于repeated字段,尽量增加packed=true修饰
      因为加了packed=true修饰repeated字段采用连续数据存储方式,即T - L - V - V -V方式


    10. 序列化 & 反序列化过程

    • Protocol Buffer除了序列化 & 反序列化后的数据体积小,序列化 & 反序列化的速度也非常快
    • 下面我将讲解序列化 & 反序列化的序列化过程

    10.1 Protocol Buffer的序列化 & 反序列化过程

    序列化过程如下:

    1. 判断每个字段是否有设置值,有值才进行编码
    2. 根据 字段标识号&数据类型 将 字段值 通过不同的编码方式进行编码

    由于:
    a. 编码方式简单(只需要简单的数学运算 = 位移等等)
    b. 采用 Protocol Buffer 自身的框架代码 和 编译器 共同完成

    所以Protocol Buffer的序列化速度非常快。

    反序列化过程如下:

    1. 调用 消息类的 parseFrom(input) 解析从输入流读入的二进制字节数据流

    从上面可知,Protocol Buffer解析过程只需要通过简单的解码方式即可完成,无需复杂的词法语法分析,因此 解析速度非常快。

    1. 将解析出来的数据 按照指定的格式读取到 JavaC++Phyton 对应的结构类型中

    由于:
    a. 解码方式简单(只需要简单的数学运算 = 位移等等)
    b. 采用 Protocol Buffer 自身的框架代码 和 编译器 共同完成

    所以Protocol Buffer的反序列化速度非常快。

    10.2 对比于XML 的序列化 & 反序列化过程

    XML的反序列化过程如下:

    1. 从文件中读取出字符串
    2. 将字符串转换为 XML 文档对象结构模型
    3. XML 文档对象结构模型中读取指定节点的字符串
    4. 将该字符串转换成指定类型的变量

    上述过程非常复杂,其中,将 XML 文件转换为文档对象结构模型的过程通常需要完成词法文法分析等大量消耗 CPU 的复杂计算。

    因为序列化 & 反序列化过程简单,所以序列化 & 反序列化过程速度非常快,这也是 Protocol Buffer效率高的原因


    11.总结

    • Protocol Buffer的序列化 & 反序列化简单 & 速度快的原因是:
      a. 编码 / 解码 方式简单(只需要简单的数学运算 = 位移等等)
      b. 采用 Protocol Buffer 自身的框架代码 和 编译器 共同完成

    • Protocol Buffer的数据压缩效果好(即序列化后的数据量体积小)的原因是:
      a. 采用了独特的编码方式,如VarintZigzag编码方式等等
      b. 采用T - L - V 的数据存储方式:减少了分隔符的使用 & 数据存储得紧凑


    接下来我会讲解Protocol Buffer的源码分析,感兴趣的同学可以继续关注carson_ho的微信公众号
    示意图
    示意图


    请帮顶 / 评论点赞!因为你的鼓励是我写作的最大动力!

    展开全文
  • 求助代码 import urllib2 import re import os headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64;...TypeError: expected string or buffer Process finished with exit code 1
  • 文章目录前言Heap-buffer-overflowHeap-use-after-freeStack-buffer-overflowGlobal-buffer-overflow 前言 在做LeetCode题时发现一个有趣的事情。 对于C语言来说,如果直接访问超出Index的数组,会报错: int main...

    此文首发于我的个人博客:LeetCode 报错解决 heap-buffer-overflow Heap-use-after-free Stack-buffer-overflow Global-buffer-overflow — zhang0peter的个人博客


    LeetCode题解文章分类:LeetCode题解
    LeetCode 所有题目总结:LeetCode 所有题目总结


    前言

    在做LeetCode题时发现一个有趣的事情。
    对于C语言来说,如果直接访问超出Index的数组,会报错:

    int main(int argc, char **argv) {
        int array  [100];
        array[101] = -1;
        int res = array[-1];  
        return res;
    }
    

    报错如下:

    Runtime Error:
    Line 3: Char 10: runtime error: index 101 out of bounds for type 'int [100]' (solution.c)
    

    但是如果你使用malloc分配空间给int数组,index的越界访问是不会直接报错的

    Heap-buffer-overflow

    但是LeetCode 使用了AddressSanitizer检查是否存在内存非法访问

    #include <stdlib.h>
    int main(int argc, char **argv) {
        int *array = (int*)malloc(100 * sizeof(int));
        array[0] = -1;
        int res = array[-1];  // BOOM
        return res;
    }
    

    LeetCode 报错如下:

    =================================================================
    ==30==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x60300000000c at pc 0x000000401749 bp 0x7ffc91bd0570 sp 0x7ffc91bd0568
    WRITE of size 4 at 0x60300000000c thread T0
        #3 0x7ff2c35d42e0 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x202e0)
    
    0x60300000000c is located 4 bytes to the left of 20-byte region [0x603000000010,0x603000000024)
    allocated by thread T0 here:
        #0 0x7ff2c4a5e2b0 in malloc (/usr/local/lib64/libasan.so.5+0xe82b0)
        #4 0x7ff2c35d42e0 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x202e0)
    
    Shadow bytes around the buggy address:
      0x0c067fff7fb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
      0x0c067fff7fc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
      0x0c067fff7fd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
      0x0c067fff7fe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
      0x0c067fff7ff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    =>0x0c067fff8000: fa[fa]00 00 04 fa fa fa fa fa fa fa fa fa fa fa
      0x0c067fff8010: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
      0x0c067fff8020: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
      0x0c067fff8030: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
      0x0c067fff8040: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
      0x0c067fff8050: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
    Shadow byte legend (one shadow byte represents 8 application bytes):
      Addressable:           00
      Partially addressable: 01 02 03 04 05 06 07 
      Heap left redzone:       fa
      Freed heap region:       fd
      Stack left redzone:      f1
      Stack mid redzone:       f2
      Stack right redzone:     f3
      Stack after return:      f5
      Stack use after scope:   f8
      Global redzone:          f9
      Global init order:       f6
      Poisoned by user:        f7
      Container overflow:      fc
      Array cookie:            ac
      Intra object redzone:    bb
      ASan internal:           fe
      Left alloca redzone:     ca
      Right alloca redzone:    cb
    ==30==ABORTING
    

    其实这是AddressSanitizer 这个工具的内存损坏检查报的错。
    可以在Linux上运行如下命令,检查程序是否存在内存非法访问:

    gcc -O -g -fsanitize=address  test.c
    ./a.out
    

    Linux下运行报错如下:

    allocated by thread T0 here:
        #0 0x7f8eb21bfd28 in malloc (/usr/lib/x86_64-linux-gnu/libasan.so.3+0xc1d28)
        #1 0x563aa79a68bd in main /root/test4.c:3
    
    SUMMARY: AddressSanitizer: heap-buffer-overflow /root/test4.c:5 in main
    Shadow bytes around the buggy address:
      0x0c287fff9f70: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
      0x0c287fff9f80: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
      0x0c287fff9f90: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
      0x0c287fff9fa0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
      0x0c287fff9fb0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
    =>0x0c287fff9fc0: fa fa fa fa fa fa fa[fa]00 00 00 00 00 00 00 00
      0x0c287fff9fd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
      0x0c287fff9fe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
      0x0c287fff9ff0: 00 00 00 00 00 00 00 00 00 00 fa fa fa fa fa fa
      0x0c287fffa000: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
      0x0c287fffa010: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
    Shadow byte legend (one shadow byte represents 8 application bytes):
      Addressable:           00
      Partially addressable: 01 02 03 04 05 06 07 
      Heap left redzone:       fa
      Heap right redzone:      fb
      Freed heap region:       fd
      Stack left redzone:      f1
      Stack mid redzone:       f2
      Stack right redzone:     f3
      Stack partial redzone:   f4
      Stack after return:      f5
      Stack use after scope:   f8
      Global redzone:          f9
      Global init order:       f6
      Poisoned by user:        f7
      Container overflow:      fc
      Array cookie:            ac
      Intra object redzone:    bb
      ASan internal:           fe
      Left alloca redzone:     ca
      Right alloca redzone:    cb
    ==7489==ABORTING
    
    

    Heap-use-after-free

    同时,AddressSanitizer也可以检查Heap-use-after-free的错:

    int main(int argc, char **argv) {
      int *array = new int[100];
      delete [] array;
      return array[argc];  // BOOM
    }
    
    g++ -O -g -fsanitize=address heap-use-after-free.c
    ./a.out
    

    报错如下:

    =================================================================
    ==7849==ERROR: AddressSanitizer: heap-use-after-free on address 0x61400000fe44 at pc 0x56282de47977 bp 0x7fff9cfc65e0 sp 0x7fff9cfc65d8
    READ of size 4 at 0x61400000fe44 thread T0
        #0 0x56282de47976 in main /root/heap-use-after-free.c:4
        #1 0x7fabfddb72e0 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x202e0)
        #2 0x56282de47819 in _start (/root/a.out+0x819)
    
    0x61400000fe44 is located 4 bytes inside of 400-byte region [0x61400000fe40,0x61400000ffd0)
    freed by thread T0 here:
        #0 0x7fabfea96370 in operator delete[](void*) (/usr/lib/x86_64-linux-gnu/libasan.so.3+0xc3370)
        #1 0x56282de47941 in main /root/heap-use-after-free.c:3
    
    previously allocated by thread T0 here:
        #0 0x7fabfea95d70 in operator new[](unsigned long) (/usr/lib/x86_64-linux-gnu/libasan.so.3+0xc2d70)
        #1 0x56282de47931 in main /root/heap-use-after-free.c:2
    
    SUMMARY: AddressSanitizer: heap-use-after-free /root/heap-use-after-free.c:4 in main
    Shadow bytes around the buggy address:
      0x0c287fff9f70: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
      0x0c287fff9f80: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
      0x0c287fff9f90: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
      0x0c287fff9fa0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
      0x0c287fff9fb0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
    =>0x0c287fff9fc0: fa fa fa fa fa fa fa fa[fd]fd fd fd fd fd fd fd
      0x0c287fff9fd0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
      0x0c287fff9fe0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
      0x0c287fff9ff0: fd fd fd fd fd fd fd fd fd fd fa fa fa fa fa fa
      0x0c287fffa000: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
      0x0c287fffa010: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
    Shadow byte legend (one shadow byte represents 8 application bytes):
      Addressable:           00
      Partially addressable: 01 02 03 04 05 06 07 
      Heap left redzone:       fa
      Heap right redzone:      fb
      Freed heap region:       fd
      Stack left redzone:      f1
      Stack mid redzone:       f2
      Stack right redzone:     f3
      Stack partial redzone:   f4
      Stack after return:      f5
      Stack use after scope:   f8
      Global redzone:          f9
      Global init order:       f6
      Poisoned by user:        f7
      Container overflow:      fc
      Array cookie:            ac
      Intra object redzone:    bb
      ASan internal:           fe
      Left alloca redzone:     ca
      Right alloca redzone:    cb
    ==7849==ABORTING
    

    Stack-buffer-overflow

    int main(int argc, char **argv) {
      int stack_array[100];
      stack_array[1] = 0;
      return stack_array[argc + 100];  // BOOM
    }
    
    gcc -O -g -fsanitize=address  test.c
    ./a.out
    

    报错如下:

    =================================================================
    ==8078==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7fffe55a7b04 at pc 0x555dec997a0e bp 0x7fffe55a7940 sp 0x7fffe55a7938
    READ of size 4 at 0x7fffe55a7b04 thread T0
        #0 0x555dec997a0d in main /root/test6.c:4
        #1 0x7f903bdab2e0 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x202e0)
        #2 0x555dec997819 in _start (/root/a.out+0x819)
    
    Address 0x7fffe55a7b04 is located in stack of thread T0 at offset 436 in frame
        #0 0x555dec99792f in main /root/test6.c:1
    
      This frame has 1 object(s):
        [32, 432) 'stack_array' <== Memory access at offset 436 overflows this variable
    HINT: this may be a false positive if your program uses some custom stack unwind mechanism or swapcontext
          (longjmp and C++ exceptions *are* supported)
    SUMMARY: AddressSanitizer: stack-buffer-overflow /root/test6.c:4 in main
    Shadow bytes around the buggy address:
      0x10007caacf10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
      0x10007caacf20: 00 00 00 00 00 00 00 00 00 00 f1 f1 f1 f1 00 00
      0x10007caacf30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
      0x10007caacf40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
      0x10007caacf50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    =>0x10007caacf60:[f4]f4 f3 f3 f3 f3 00 00 00 00 00 00 00 00 00 00
      0x10007caacf70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
      0x10007caacf80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
      0x10007caacf90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
      0x10007caacfa0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
      0x10007caacfb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    Shadow byte legend (one shadow byte represents 8 application bytes):
      Addressable:           00
      Partially addressable: 01 02 03 04 05 06 07 
      Heap left redzone:       fa
      Heap right redzone:      fb
      Freed heap region:       fd
      Stack left redzone:      f1
      Stack mid redzone:       f2
      Stack right redzone:     f3
      Stack partial redzone:   f4
      Stack after return:      f5
      Stack use after scope:   f8
      Global redzone:          f9
      Global init order:       f6
      Poisoned by user:        f7
      Container overflow:      fc
      Array cookie:            ac
      Intra object redzone:    bb
      ASan internal:           fe
      Left alloca redzone:     ca
      Right alloca redzone:    cb
    ==8078==ABORTING
    
    

    Global-buffer-overflow

    int global_array[100] = {-1};
    int main(int argc, char **argv) {
      return global_array[argc + 100];  // BOOM
    }
    
    gcc -O -g -fsanitize=address  test.c
    ./a.out
    

    报错如下:

    SUMMARY: AddressSanitizer: global-buffer-overflow /root/test6.c:3 in main
    Shadow bytes around the buggy address:
      0x0ab033158fe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
      0x0ab033158ff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
      0x0ab033159000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
      0x0ab033159010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
      0x0ab033159020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    =>0x0ab033159030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00[f9]f9
      0x0ab033159040: f9 f9 f9 f9 00 00 00 00 00 00 00 00 00 00 00 00
      0x0ab033159050: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
      0x0ab033159060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
      0x0ab033159070: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
      0x0ab033159080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    Shadow byte legend (one shadow byte represents 8 application bytes):
      Addressable:           00
      Partially addressable: 01 02 03 04 05 06 07 
      Heap left redzone:       fa
      Heap right redzone:      fb
      Freed heap region:       fd
      Stack left redzone:      f1
      Stack mid redzone:       f2
      Stack right redzone:     f3
      Stack partial redzone:   f4
      Stack after return:      f5
      Stack use after scope:   f8
      Global redzone:          f9
      Global init order:       f6
      Poisoned by user:        f7
      Container overflow:      fc
      Array cookie:            ac
      Intra object redzone:    bb
      ASan internal:           fe
      Left alloca redzone:     ca
      Right alloca redzone:    cb
    ==8158==ABORTING
    
    展开全文
  • 对于pubsub client,如果client-output-buffer一旦超过32mb,又或者超过8mb持续60秒,那么服务器就会立即断开客户端连接。如果设置reids参数为client-output-buffer-limit pubsub 0 0 0的话,对于服务器会产生什么...
  • 代码如下: ``` JsonObject jsonObject = new JsonParser...是不是和这个方法的两个重载方法有关 buffer(distance, quadrantSegments)和buffer(distance, quadrantSegments, endCapStyle) 网上实在找不到相关api
  • Node之使用Buffer类处理二进制数据

    千次阅读 2019-12-26 20:34:38
    创建Buffer对象 调用new Buffer(size),size为缓存区大小 new Buffer(10) fill()方法来初始化缓存区中的所有内容 buf.fill(value, [offset], [end]) //value:为需要被写入的数值 //offset:用于指定从第几个字节处...

    创建Buffer对象

    调用new Buffer(size),size为缓存区大小

    new Buffer(10)
    

    fill()方法来初始化缓存区中的所有内容

    buf.fill(value, [offset], [end])
    //value:为需要被写入的数值
    //offset:用于指定从第几个字节处开始写入被指定的数值
    //end:用于指定将数值一直写入到第几字节处
    

    直接使用一个数组来初始化缓存区

    new Buffer(array)
    

    在这种形式的构造函数中,使用一个存放了需要被指定数值的数组来作为构造函数的参数。

    直接使用一个字符串来初始化缓存区

    new Buffer(str,[encoding]
    

    在这种形式的构造函数中,使用两个参数,其中第一个参数为必须指定的参数,参数值为用于初始化缓存区的字符串,第二个参数值为一个用于指定文字编码格式的字符串,默认值为“utf8”。

    在Node.js中,可以使用的编码格式如下

    编码 说明
    ascii ASCII字符串
    utf8 UTF-8字符串
    utf16le UTF-16LE字符串
    ucs2 UCS2字符串
    base64 经过BASE64编码后的字符串
    binary 二进制数据(不推荐使用)
    hex 使用十六进制数值表示的字符串

    字符串长度和缓存区的长度

    在Node.js中,一个字符串的长度与根据该字符串所创建的缓存区的长度并不相同。因为在计算字符串的长度时,以文字作为一个单位,而在计算缓存区的长度时,以字节作为一个单位。

    Buffer对象的slice方法与该数据共享内存区域,如果修改使用slice方法取出的数据,则缓存区中保存的数据也将被修改。

    Buffer对象的toString方法

    可以使用Buffer对象的toString方法将Buffer对象中保存的数据转换为字符串

    buf.toString([encoding], [start], [end])
    

    在Buffer对象的toString方法中,可以使用三个可选参数,其中第一个参数用于指定Buffer对象中保存的文字编码格式,默认参数值为utf8。第二及第三个参数用于指定被转换数据的起始位置与终止位置,以字节为单位。toString方法返回经
    过转换后的字符串。

    Buffer对象的write方法

    如果要将字符串当作二进制数据来使用,只需将该字符串作为Buffer类的构造函数的参数来创建Buffer对象即可。但是有时我们需要向已经创建的Buffer对象中写入字符串,这时可以使用该Buffer对象的write方法

    buf.write(string, [offset], [length], [encoding])
    

    在Buffer对象的write方法中,可以使用四个参数,其中第一个参数为必须指定参数,后三个参数为可选参数。第一个参数用于指定需要写入的字符串,第二个参数offset与第三个参数length用于指定字符串转换为字节数据后的写入位置。字节数据的书写位置为从第1+offset个字节开始到offset+length个字节为止(例如offset为3,length为6,写入位置为从第4字节开始到第9字节为止,包括第4字节与第9字节)。第四个参数用于指定写入字符串时使用的编码格式,默认为utf8格
    式。

    StringDecoder对象

    在使用StringDecoder对象时,首先需要加载Node.js中的string_decoder模块

    var StringDecoder = require('string_decoder').StringDecoder;
    

    在加载了string_decoder模块之后,可以创建一个StringDecoder对象,在StringDecoder类的构造函数中,可以使用一个可选参数,该参数用于指定转换字符串时所使用的编码格式,默认参数值为utf8。

    var decoder = new StringDecoder([encoding]);
    

    要将Buffer对象中的数据转换为字符串时,可以使用StringDecoder对象的write方法

    decoder.write(buffer)
    

    Buffer对象与JSON对象之间的相互转换

    在Node.js中,可以使用JSON.stringify方法将Buffer对象中保存的数据转换为一个字符串,也可以使用JSON.parse方法将一个经过转换后的字符串还原为一个数组。

    复制缓存数据

    当需要将Buffer对象中保存的二进制数据复制到另一个Buffer对象中时,可以使用Buffer对象的copy方法,copy方法的使用方法如下所示。

    buf.copy(targetBuffer, [targetStart], [sourceStart], [sourceEnd])
    

    在Buffer对象的copy方法中,使用四个参数,其中第一个参数为必须指定的参数,其余三个参数均为可选参数。第一个参数用于指定复制的目标Buffer对象。第二个参数用于指定目标Buffer对象中从第几个字节开始写入数据,参数值为一个小
    于目标Buffer对象长度的整数值,默认值为0(从开始处写入数据)。第三个参数用于指定从复制源Buffer对象中获取数据时的开始位置,默认值为0,即从复制源Buffer对象中的第一个字节开始获取数据,第四个参数用于指定从复制源Buffer对象中获取数据时的结束位置,默认值为复制源Buffer对象的长度,即一直获取完毕复制源Buffer对象中的所有剩余数据。

    isBuffer方法用于判断一个对象是否为一个Buffer对象

    Buffer.isBuffer(obj)
    

    byteLength方法计算一个指定字符串的字节数

    Buffer.byteLength(string, [encoding])
    

    在byteLength方法中,使用两个参数,其中第一个参数为必须输入参数,用于指定需要计算字节数的字符串,第二个参数为可选参数,用于指定按什么编码方式来计算字节数,默认值为utf8。

    concat方法用于将几个Buffer对象结合创建为一个新的Buffer对象

    Buffer.concat(list,[totalLength])
    

    在concat方法中,使用两个参数,其中第一个参数为必须指定的参数,参数值为一个存放了多个Buffer对象的数组,concat方法将把其中的所有Buffer对象联结创建为一个Buffer对象;第二个参数为可选参数,用于指定被创建的Buffer对象的总长度,当省略该参数时,被创建的Buffer对象为第一个参数数组中所有Buffer对象的长度的合计值。

    isEncoding方法用于检测一个字符串是否为一个有效的编码格式字符串

    Buffer.isEncoding(encoding)
    
    展开全文
  • MySQL 之 InnoDB引擎 Change Buffer

    千次阅读 多人点赞 2019-04-22 21:00:08
    Change Buffer Change Buffer是一种特殊的数据结构,缓存对二级索引页面的更改并且这些页面不在Buffer Pool中。缓存的changes可能由 Insert 、Delete 和 Update的结果导致。稍后在页面被其他读取操作加载到Buffer ...

    Change Buffer

    Change Buffer是一种特殊的数据结构,缓存对二级索引页面的更改并且这些页面不在Buffer Pool中。缓存的changes可能由 Insert 、Delete 和 Update的结果导致。稍后在页面被其他读取操作加载到Buffer Pool的时候合并。

    Buffer Pool的研究在我的这篇里有:https://blog.csdn.net/qq_36652619/article/details/88953065

    简而言之:Change buffer的主要目的是将对二级索引的数据操作缓存下来,以此减少二级索引的随机IO,并达到操作合并的效果。

    与聚簇索引(ps:默认是InnoDB里的主键,主键是聚集存储的)不同,二级索引通常不是唯一的,并且插入二级索引的顺序相对随机。删除和更新可能会影响不在索引树中相邻的二级索引页。当受影响的页面被其他操作读入缓冲池时,合并缓存的更改,避免了从磁盘读取二级索引页到缓冲池所需的大量随机访问I / O。

    在MySQL5.5之前的版本中,由于只支持缓存insert操作,所以最初叫做insert buffer,只是后来的版本中支持了更多的操作类型缓存,才改叫change buffer,所以本文是基于MySQL5.5之后的版本。

    (Secondary Index(二级索引)

        ◦ 也可以称为 非聚集索引

        ◦ 叶子节点存储的是 索引 和 主键 信息

        ◦ 在找到索引后,得到对应的主键,再 回到聚集索引 中找主键对应的记录(row data))

    放出二级索引的解释可能还是懵,什么时候算作二级索引,所有主键以外的索引都是二级索引(innodb默认),官方文档说的:

    ps:所以说根据主键访问数据(永远是效果最好的方式),原因看上方括号内二级索引介绍

     

    为何需要Change Buffer

    上面的结构图可能有些迷,看下面的图解:

    表的索引存于该表的ibd文件中,数据也存于此文件。表数据更新的同时也会更新对应的表的索引数据,所以:例如对表进行insert时,很可能会产生大量的物理读(物理读索引数据页),insert一个表,对应的表上面的索引会变动,索引不常使用,产生物理读,索引顺序和表不一致耗时。

    (物理读(Physical Reads):从磁盘读取数据块到内存的操作叫物理读,当缓存不存在这些数据块的时候就会产生物理读,物理读过大表现为磁盘 I/O 较高)

    所以将对索引的更新记录存入Change Buffer中,而不是直接调入索引页进行更新;选择时机进行merge insert buffer的操作,将insert buffer中的记录合并(merge)到真正的辅助索引中。

    系统大部分空闲时或在慢速关闭期间运行的清除(purge)操作会定期将更新的索引页写入磁盘。与每个值立即写入磁盘相比,purge操作可以更有效地为一系列索引值写入磁盘块。

    当有许多受影响的行和许多要更新的二级索引时,Change Buffer合并可能需要几个小时。在此期间,磁盘I / O会增加,这会导致磁盘绑定查询显着减慢。在提交事务之后,甚至在服务器关闭并重新启动之后,更改缓冲区合并也可能继续发生

    在内存中,Change Buffer占用Buffer Pool的一部分。在磁盘上,Change Buffer是系统表空间的一部分,其中的索引会在关闭数据库服务器时更改。

     

    配置Change Buffer

    对表执行 INSERT,UPDATE和 DELETE操作时, 索引列的值(尤其是secondary keys的值)通常按未排序顺序排列,需要大量I / O才能使二级索引更新。Change Buffer会缓存这个更新当相关页面不在Buffer Pool中,从而磁盘上的相关页面不会立即被读避免了昂贵的I / O操作。当页面加载到缓冲池中时,将合并缓冲的更改,稍后将更新的页面刷新到磁盘。该InnoDB主线程在服务器几乎空闲时以及在慢速关闭期间合并缓冲的更改 。

     

    为方便理解:来了一个关于二级索引页面的DML操作,并且这个页面没有在Buffer Pool内,那么把这个操作存入Change Buffer(MySQL5.5之前的版本叫Insert Buffer),ok,那么下一次需要加载这个页面的时候,也就是这个页面有需求的时候,会将Change Buffer内的更改合并到Buffer Pool,随后当服务器在空闲的时候,这个更改会刷到disk(磁盘)上。所以一开始那张很难读的图的流程就清晰了:(黄色箭头这样的走势)

    因为它可以减少磁盘读取和写入,所以更改缓冲区功能对于I / O绑定的工作负载最有价值,例如具有大量DML操作的应用程序(如批量插入)。

     

    但是,Change Buffer占用Buffer Pool的一部分,从而减少了可用于缓存数据页的内存。如果工作集几乎适合Buffer Pool,或者您的表具有相对较少的二级索引,则禁用Change Buffer可能很有用。

    毕竟Change Buffer只适用于Buffer Pool外的页面嘛。

     

    可以使用innodb_change_buffering 配置参数

    允许的innodb_change_buffering 值包括:

    • all

      默认值:所有操作

    • none

      不要缓冲任何操作。

    • inserts

      缓冲插入操作。

    • deletes

      缓冲区删除标记操作。

    • changes

      缓冲插入和删除标记操作。

    • purges

      缓冲在后台发生的物理删除操作。

     

    Change Pool内部结构

    下面是一张来自云栖社区的图:

    图中的ibuf代表Insert Buffer,可以直接将其看成Change Buffer,为MySQL 5.5 之前Change Buffer就叫Insert Buffer

    ibuf btree最大默认为buffer pool size的25%,当超过25%时,可能触发用户线程同步缩减ibuf btree。为何要将ibuf btree的大小和buffer pool大小相关联呢 ? 一个比较重要的原因是防止ibuf本身占用过多的buffer pool资源。

     

    配置Change Pool最大大小

    该innodb_change_buffer_max_size 变量允许将Change Buffer的最大大小配置为缓冲池总大小的百分比。默认情况下, innodb_change_buffer_max_size设置为25.最大设置为50。

    使用测试不同的设置的业务性能以确定最佳配置。该 innodb_change_buffer_max_size 设置是动态的,允许在不重新启动服务器的情况下修改设置。类似innodb_buffer_pool_size也可以在线更改那种。

     

    以上是对InnoDB引擎Change Buffer的一些粗浅认识

     

    转载请注明出处:

    https://blog.csdn.net/qq_36652619

     

     

     

    展开全文
  • var imgData = new Buffer(body,'binary'); resolve(imgData); console.log(imgData); }else{ reject(error); } }); }); } url打开后就是一个图片(微信头像) console.log(imgData) <Buffer fd fd fd...
  • Android MediaPlayer buffer大小

    千次阅读 2018-07-18 16:24:36
    Android MediaPlayer buffer 前几天用VideoView (MediaPlayer+SurfaceView) 做一个类似于抖音APP的短视频Demo(测试机型 Android8.0 小米6),发现MediaPlayer onPrepared的时间非常长,好像把一个不到10M的视频全部...
  • Golang bytes.Buffer 用法精述

    千次阅读 2019-07-02 16:58:42
    bytes.Buffer 是 Golang 标准库中的缓冲区,具有读写方法和可变大小的字节存储功能。缓冲区的零值是一个待使用的空缓冲区。定义如下: type Buffer struct { buf []byte // contents are the bytes buf[off : len...
  • 我在decoder中解析数据并处理粘包的问题,模拟到了一种情况就是收到的是断包,且这段断包为一段完整数据包的后半段(实际上就是无用的了),想去除这段数据,也就是清空IoBuffer。看了一下api貌似没有彻底清空的...
  • Nodejs Buffer拼接

    千次阅读 2019-09-25 20:21:39
    本文记录下最近遇到的buffer拼接问题。如果需要知道如何拼接 直接点击第二节 文章目录1 背景2 buffer拼接3 buffer 截取 1 背景 最近有一个需求需要将缩略图和视频文件合并到一起用HTTP POST 发送给服务器,服务器...
  • GO语言之bytes.buffer

    千次阅读 2019-04-28 14:26:51
    bytes.Buffer bytes.Buffer是一个缓冲byte类型的缓冲器存放着都是byte。 Buffer 是 bytes 包中的一个type Buffer struct{…}。 A buffer is a variable-sized buffer of bytes with Read and Write methods. The...
  • NIO之旅Buffer

    千次阅读 2020-08-18 22:38:45
    在上一篇文章中聊了一下Channel,这篇文章聊一下Java NIO中的另一个重要的组件:BufferBuffer的概念 首先我们先看一下Buffer的类图,Buffer在java.nio中被定义为抽象类: Buffer被称为内存缓冲区,本质上也是...
  • 很多小伙伴不知道 RT-Thread 为我们提供了一个 ringbuffer 数据结构,代码位于: components/drivers/src/ringbuffer.c components/drivers/include/ipc/ringbuffer.h RingBuffer 其实就是先进先出(FIFO)的循环...
  • 1) 当数据没有汉字,则完全等价 ...var buf = Buffer.allocUnsafe(data.length); // for(var i = 0; i &lt; data.length; i++){ // buf[i] = data.charCodeAt(i); // } buf.fill(data, 0); console.log(buf...

空空如也

1 2 3 4 5 ... 20
收藏数 91,512
精华内容 36,604
关键字:

buffer