站在巨人的肩膀上

C++高性能分布式服务器框架

从零开始重写sylar C++高性能分布式服务器框架

概述

二进制数组(序列化/反序列化)模块。

字节数组容器,提供基础类型的序列化与反序列化功能。

ByteArray 的底层存储是固定大小的块,以链表形式组织。每次写入数据时,将数据写入到链表最后一个块中,如果最后一个块不足以容纳数据,则分配一个新的块并添加到链表结尾,再写入数据。ByteArray 会记录当前的操作位置,每次写入数据时,该操作位置按写入大小往后偏移,如果要读取数据,则必须调用 setPosition 重新设置当前的操作位置。

ByteArray 支持基础类型的序列化与反序列化功能,并且支持将序列化的结果写入文件,以及从文件中读取内容进行反序列化。

ByteArray 支持以下类型的序列化与反序列化:

  • 固定长度的有符号/无符号8位、16位、32位、64位整数。
  • 不固定长度的有符号/无符号32位、64位整数。
  • float、double 类型。
  • 字符串,包含字符串长度,长度范围支持16位、32位、64位。
  • 字符串,不包含长度。
  • 以上所有的类型都支持读写。
  • ByteArray 还支持设置序列化时的大小端顺序。

ByteArray

  • 二进制数组,提供基础类型的序列化,反序列化功能。
  • 内含一个 Node 类,作为 ByteArray 的存储节点。
  • 相当于一个链表的数据结构。

其他说明

  • ByteArray 在序列化不固定长度的有符号/无符号32位、64位整数时使用了 zigzag 算法。zigzag 算法参考: 小而巧的数字压缩算法:zigzag
  • ByteArray 在序列化字符串时使用 TLV 编码结构中的 Length 和 Value。TLV编码结构用于序列化和消息传递,指 Tag(类型),Length(长度),Value(值),参考:TLV编码通信协议设计

待完善

  • 感觉这个模块有两个地方有bug。
  • ByteArray::getReadBuffers 方法:
uint64_t ByteArray::getReadBuffers(std::vector<iovec>& buffers, uint64_t len, uint64_t position) const
{
// 这里的判断好像没啥用,因为下面用的position是外面传进来的,
// 与m_position是没有关系的,bug???
len = len > getReadSize() ? getReadSize() : len;
...
}
  • ByteArray::writeToFile 方法:
bool ByteArray::writeToFile(const std::string& name) const
{
...
int64_t read_size = getReadSize();
int64_t pos = m_position;
Node* cur = m_cur;
while(read_size > 0)
{
    int diff = pos % m_baseSize;    // 当前块不可读(已经读完)的字节数

    // 1、要读的内容比一整块要大,则读完一整块剩下的那些
    // 2、要读的内容比一整块少,则读???
    // 假设一块10字节,可读9字节,不可读是3字节,则读9-3=6字节,bug???
    // 假设一块10字节,可读1字节,不可读是3字节,则读1-3=-5字节,bug???
    // 应该是:
    // int64_t len = 0;
    // if(read_size > (int64_t)m_baseSize - diff)
    //      len = (int64_t)m_baseSize - diff;
    // else
    //      len = read_size;
    int64_t len = (read_size > (int64_t)m_baseSize ? m_baseSize : read_size) - diff;
    ofs.write(cur->ptr + diff, len);
    cur = cur->next;
    pos += len;
    read_size -= len;
}

return true;
}

部分相关代码

/**
 * @filename    bytearray.h
 * @brief   ByteArray 模块
 * @author  L-ge
 * @version 0.1
 * @modify  2022-07-10
 */
#ifndef __SYLAR_BYTEARRAY_H__
#define __SYLAR_BYTEARRAY_H__

#include <memory>
#include <string>
#include <vector>
#include <stdint.h>
#include <sys/types.h>
#include <sys/socket.h>

namespace sylar
{

/**
 * @brief   二进制数组,提供基础类型的序列化和反序列化功能
 */
class ByteArray
{
public:
    typedef std::shared_ptr<ByteArray> ptr;

    /**
     * @brief  存储节点 
     */
    struct Node
    {
        /**
         * @brief  构造指定大小的内存块 
         *
         * @param   s   内存块字节数
         */
        Node(size_t s);
        Node();
        ~Node();

        /// 内存块地址指针
        char* ptr;
        /// 下一个内存块地址
        Node* next;
        /// 内存块大小
        size_t size;
    };

    /**
     * @brief   按指定大小的内存块构造
     *
     * @param   base_size   内存块大小
     */
    ByteArray(size_t base_size = 4096);
    ~ByteArray();

    /**
     * @brief  写入固定长度类型的整型数据 
     */
    void writeFint8(int8_t value);
    void writeFuint8(uint8_t value);
    void writeFint16(int16_t value);
    void writeFuint16(uint16_t value);
    void writeFint32(int32_t value);
    void writeFuint32(uint32_t value);
    void writeFint64(int64_t value);
    void writeFuint64(uint64_t value);

    /**
     * @brief  写入可压缩(Zigzag算法)的字符串数据 
     */
    void writeInt32(int32_t value);
    void writeUint32(uint32_t value);
    void writeInt64(int64_t value);
    void writeUint64(uint64_t value);
    
    void writeFloat(float value);
    void writeDouble(double value);

    /**
     * @brief  写入前面带长度(长度所占字节数固定)的字符串数据(长度+实际数据) 
     */
    void writeStringF16(const std::string& value);
    void writeStringF32(const std::string& value);
    void writeStringF64(const std::string& value);
    
    /**
     * @brief  写入前面带长度的数据(实际长度+实际数据) 
     *         长度所占字节数为可压缩的uint64的实际大小
     */
    void writeStringVint(const std::string& value);

    /**
     * @brief   写入不带长度的字符串数据
     */
    void writeStringWithoutLength(const std::string& value);

    int8_t readFint8();
    uint8_t readFuint8();
    int16_t readFint16();
    uint16_t readFuint16();
    int32_t readFint32();
    uint32_t readFuint32();
    int64_t readFint64();
    uint64_t readFuint64();
    
    int32_t readInt32();
    uint32_t readUint32();
    int64_t readInt64();
    uint64_t readUint64();

    float readFloat();
    double readDouble();

    std::string readStringF16();
    std::string readStringF32();
    std::string readStringF64();
    std::string readStringVint();

    void clear();
    void write(const void* buf, size_t size);
    void read(void* buf, size_t size);

    /**
     * @brief  读取size长度的数据 
     *
     * @param   position    读取开始的位置
     */
    void read(void* buf, size_t size, size_t position) const;
    
    /**
     * @brief  返回ByteArray的当前位置 
     */
    size_t getPosition() const { return m_position; }
    void setPosition(size_t v);
    
    /**
     * @brief  把ByteArray的数据写入到文件中 
     */
    bool writeToFile(const std::string& name) const;
    bool readFromFile(const std::string& name);
    
    /**
     * @brief  返回内存块的大小 
     */
    size_t getBaseSize() const { return m_baseSize; }
    
    /**
     * @brief   返回可读取数据的大小
     */
    size_t getReadSize() const { return m_size - m_position; }

    bool isLittleEndian() const;
    void setIsLittleEndian(bool val);

    std::string toString() const;
    std::string toHexString() const;

    /**
     * @brief   获取可读取的缓存,保存到iovec数组中 
     */
    uint64_t getReadBuffers(std::vector<iovec>& buffers, uint64_t len = ~0ull) const;
  
    /**
     * @brief   获取可读取的缓存,保存到iovec数组中,从position位置开始
     */
    uint64_t getReadBuffers(std::vector<iovec>& buffers, uint64_t len, uint64_t position) const;
    
    /**
     * @brief   获取可写入的缓存,保存到iovec数组中
     */
    uint64_t getWriteBuffers(std::vector<iovec>& buffers, uint64_t len);

    /**
     * @brief   返回数据的长度(当前总数据量)
     */
    size_t getSize() const { return m_size; }

private:
    /**
     * @brief   扩容ByteArray,使其可以容纳size个数据 
     */
    void addCapacity(size_t size);
    
    /**
     * @brief   获取当前的可写入容量
     */
    size_t getCapacity() const { return m_capacity - m_position; }

private:
    /// 内存块的大小 
    size_t m_baseSize;
    /// 当前操作位置
    size_t m_position;
    /// 当前的总容量
    size_t m_capacity;
    /// 当前总数据量
    size_t m_size;
    /// 字节序,默认大端
    int8_t m_endian;
    /// 第一个内存块的指针
    Node* m_root;
    /// 当前操作内存块的指针
    Node* m_cur;
};

}
#endif


#include "bytearray.h"
#include <fstream>
#include <sstream>
#include <string.h>
#include <iomanip>
#include <math.h>
#include "log.h"
#include "endian.h"

namespace sylar
{
static sylar::Logger::ptr g_logger = SYLAR_LOG_NAME("system");

ByteArray::Node::Node(size_t s)
    : ptr(new char[s])
    , next(nullptr)
    , size(s)
{

}

ByteArray::Node::Node()
    : ptr(nullptr)
    , next(nullptr)
    , size(0)
{

}

ByteArray::Node::~Node()
{
    if(ptr)
    {
        delete[] ptr;
    }
}

ByteArray::ByteArray(size_t base_size)
    : m_baseSize(base_size)
    , m_position(0)
    , m_capacity(base_size)
    , m_size(0)
    , m_endian(SYLAR_BIG_ENDIAN)
    , m_root(new Node(base_size))
    , m_cur(m_root)
{

}

ByteArray::~ByteArray()
{
    Node* tmp = m_root;
    while(tmp)
    {
        m_cur = tmp;
        tmp = tmp->next;
        delete m_cur;   // 调用Node的析构函数,里面再delete掉一个节点所占的char数组
    }
}

void ByteArray::writeFint8(int8_t value)
{
    write(&value, sizeof(value));
}

void ByteArray::writeFuint8(uint8_t value)
{
    write(&value, sizeof(value));
}

void ByteArray::writeFint16(int16_t value)
{
    if(m_endian != SYLAR_BYTE_ORDER)
    {
        value = byteswap(value);
    }
    write(&value, sizeof(value));
}

void ByteArray::writeFuint16(uint16_t value)
{
    if(m_endian != SYLAR_BYTE_ORDER)
    {
        value = byteswap(value);
    }
    write(&value, sizeof(value));
}

void ByteArray::writeFint32(int32_t value)
{
    if(m_endian != SYLAR_BYTE_ORDER)
    {
        value = byteswap(value);
    }
    write(&value, sizeof(value));
}

void ByteArray::writeFuint32(uint32_t value)
{
    if(m_endian != SYLAR_BYTE_ORDER)
    {
        value = byteswap(value);
    }
    write(&value, sizeof(value));
}

void ByteArray::writeFint64(int64_t value)
{
    if(m_endian != SYLAR_BYTE_ORDER)
    {
        value = byteswap(value);
    }
    write(&value, sizeof(value));
}

void ByteArray::writeFuint64(uint64_t value)
{
    if(m_endian != SYLAR_BYTE_ORDER)
    {
        value = byteswap(value);
    }
    write(&value, sizeof(value));
}

static uint32_t EncodeZigzag32(const int32_t& v)
{
    if(v < 0)
    {
        return ((uint32_t)(-v)) * 2 - 1;
    }
    else
    {
        return v * 2;
    }
}

static uint64_t EncodeZigzag64(const int64_t& v)
{
    if(v < 0)
    {
        return ((uint64_t)(-v)) * 2 - 1;
    }
    else
    {
        return v * 2;
    }
}

static int32_t DecodeZigzag32(const uint32_t& v)
{
    return (v >> 1) ^ -(v & 1);
}

static int64_t DecodeZigzag64(const uint64_t& v)
{
    return (v >> 1) ^ -(v & 1);
}

void ByteArray::writeInt32(int32_t value)
{
    writeUint32(EncodeZigzag32(value));
}

void ByteArray::writeUint32(uint32_t value)
{
    uint8_t tmp[5];
    uint8_t i = 0;
    while(value >= 0x80)
    {
        tmp[i++] = (value & 0x7F) | 0x80;
        value >>= 7;
    }
    tmp[i++] = value;
    write(tmp, i);
}

void ByteArray::writeInt64(int64_t value)
{
    writeUint64(EncodeZigzag64(value));
}

void ByteArray::writeUint64(uint64_t value)
{
    uint8_t tmp[10];
    uint8_t i = 0;
    while(value >= 0x80)
    {
        tmp[i++] = (value & 0x7F) | 0x80;
        value >>= 7;
    }
    tmp[i++] = value;
    write(tmp, i);
}

void ByteArray::writeFloat(float value)
{
    uint32_t v;
    memcpy(&v, &value, sizeof(value));  // 当作固定长度的uint32_t写入
    writeFuint32(v);
}

void ByteArray::writeDouble(double value)
{
    uint64_t v;
    memcpy(&v, &value, sizeof(value));  // 当作固定长度的uint64_t写入
    writeFuint64(v);
}

void ByteArray::writeStringF16(const std::string& value)
{
    writeFuint16(value.size());
    write(value.c_str(), value.size());
}

void ByteArray::writeStringF32(const std::string& value)
{
    writeFuint32(value.size());
    write(value.c_str(), value.size());
}

void ByteArray::writeStringF64(const std::string& value)
{
    writeFuint64(value.size());
    write(value.c_str(), value.size());
}

void ByteArray::writeStringVint(const std::string& value)
{
    writeUint64(value.size());
    write(value.c_str(), value.size());
}

void ByteArray::writeStringWithoutLength(const std::string& value)
{
    write(value.c_str(), value.size());
}

int8_t ByteArray::readFint8()
{
    int8_t v;
    read(&v, sizeof(v));
    return v;
}

uint8_t ByteArray::readFuint8()
{
    uint8_t v;
    read(&v, sizeof(v));
    return v;
}

#define XX(type) \
    type v; \
    read(&v, sizeof(v)); \
    if(m_endian == SYLAR_BYTE_ORDER) \
    { \
        return v; \
    } \
    else \
    { \
        return byteswap(v); \
    }

int16_t ByteArray::readFint16()
{
    XX(int16_t);
}

uint16_t ByteArray::readFuint16()
{
    XX(uint16_t);
}

int32_t ByteArray::readFint32()
{
    XX(int32_t);
}

uint32_t ByteArray::readFuint32()
{
    XX(uint32_t);
}

int64_t ByteArray::readFint64()
{
    XX(int64_t);
}

uint64_t ByteArray::readFuint64()
{
    XX(uint64_t);
}

#undef XX

int32_t ByteArray::readInt32()
{
    return DecodeZigzag32(readUint32());
}

uint32_t ByteArray::readUint32()
{
    uint32_t result = 0;
    for(int i=0; i<32; i+=7)
    {
        uint8_t b = readFuint8();
        if(b < 0x80)
        {
            result |= ((uint32_t)b) << i;
            break;
        }
        else
        {
            result |= (((uint32_t)(b & 0x7f)) << i);
        }
    }
    return result;
}

int64_t ByteArray::readInt64()
{
    return DecodeZigzag64(readUint64());
}

uint64_t ByteArray::readUint64()
{
    uint64_t result = 0;
    for(int i=0; i<64; i+=7)
    {
        uint8_t b = readFuint8();
        if(b < 0x80)
        {
            result |= ((uint64_t)b) << i;
            break;
        }
        else
        {
            result |= (((uint64_t)(b & 0x7f)) << i);
        }
    }
    return result;
}

float ByteArray::readFloat()
{
    uint32_t v = readFuint32();
    float value;
    memcpy(&value, &v, sizeof(v));
    return value;
}

double ByteArray::readDouble()
{
    uint64_t v = readFuint64();
    double value;
    memcpy(&value, &v, sizeof(v));
    return value;
}

std::string ByteArray::readStringF16()
{
    uint16_t len = readFuint16();    // 先把长度读出来,再读实际数据(字符串)
    std::string buff;
    buff.resize(len);
    read(&buff[0], len);
    return buff;
}

std::string ByteArray::readStringF32()
{
    uint32_t len = readFuint32();
    std::string buff;
    buff.resize(len);
    read(&buff[0], len);
    return buff;
}

std::string ByteArray::readStringF64()
{
    uint64_t len = readFuint64();
    std::string buff;
    buff.resize(len);
    read(&buff[0], len);
    return buff;
}

std::string ByteArray::readStringVint()
{
    uint64_t len = readUint64();
    std::string buff;
    buff.resize(len);
    read(&buff[0], len);
    return buff;
}

void ByteArray::clear()
{
    m_position = m_size = 0;
    m_capacity = m_baseSize;
    Node* tmp = m_root->next;   // 保留根节点
    while(tmp)
    {
        m_cur = tmp;
        tmp = tmp->next;
        delete m_cur;
    }
    m_cur = m_root;
    m_root->next = NULL;
}

void ByteArray::write(const void* buf, size_t size)
{
    if(size == 0)
    {
        return;
    }
    addCapacity(size);      // 先根据需要扩充容量

    size_t npos = m_position % m_baseSize;  // 当前内存块所用的字节数
    size_t ncap = m_cur->size - npos;       // 当前内存块所剩下的字节数
    size_t bpos = 0;            // 已经分给使用者的内存字节数
    while(size > 0)
    {
        if(ncap >= size)  // 当前内存块所剩下的内存够用
        {
            memcpy(m_cur->ptr + npos, (const char*)buf + bpos, size);
            if(m_cur->size == (npos + size)) // 当前内存块已用完,更新当前可用内存块位置
            {
                m_cur = m_cur->next;
            }
            m_position += size;     // 当前位置变更
            bpos += size;           // 分配给buf的位置更新
            size = 0;               // 所要的内存字节数变0,也就是满足需求了
        }
        else
        {
            memcpy(m_cur->ptr + npos, (const char*)buf + bpos, ncap); // 先分完当前的内存块
            m_position += ncap;     // 当前位置变更,加上已经分的字节数
            bpos += ncap;           // 已经分给使用者ncap个字节
            size -= ncap;           // 需求量减少ncap个字节
            m_cur = m_cur->next;    // 当前内存块已经用完,更新当前可用内存块
            ncap = m_cur->size;     // 下一个内存块的所剩下字节数,也就是下一块内存块的大小
            npos = 0;               // 下一个内存块是刚刚才next到的,所用字节数肯定是0
        }
    }

    // 当前位置比当前使用内存量大,则更新当前内存使用量
    if(m_position > m_size)
    {
        m_size = m_position;
    }
}

void ByteArray::read(void* buf, size_t size)
{
    // 需要读取的比可读取的还要大,则认为异常
    if(size > getReadSize())
    {
        throw std::out_of_range("not enough len");
    }

    // 下面读取的代码和写入的代码的区别只是在memcpy的时候,
    // 读取时 memcpy源地址和目的地址 与 写入时调转
    size_t npos = m_position % m_baseSize;
    size_t ncap = m_cur->size - npos;
    size_t bpos = 0;
    while(size > 0)
    {
        if(ncap >= size)
        {
            memcpy((char*)buf + bpos, m_cur->ptr + npos, size);
            if(m_cur->size == (npos + size))
            {
                m_cur = m_cur->next;
            }
            m_position += size;
            bpos += size;
            size = 0;
        }
        else
        {
            memcpy((char*)buf + bpos, m_cur->ptr + npos, ncap);
            m_position += ncap;
            bpos += ncap;
            size -= ncap;
            m_cur = m_cur->next;
            ncap = m_cur->size;
            npos = 0;
        }
    }
}

void ByteArray::read(void* buf, size_t size, size_t position) const
{
    // 总使用量减去要读取的位置,也就是能读到的字节数。
    // 需要读取的比能读到的要大,则认为异常。
    if(size > (m_size - position))
    {
        throw std::out_of_range("not enough len");
    }

    // 下面代码和不指定位置读取的代码的区别是:
    // 1、不使用m_position;2、没有副作用,不直接改m_cur
    size_t npos = position % m_baseSize;    
    size_t ncap = m_cur->size - npos;
    size_t bpos = 0;
    Node* cur = m_cur;      // 无副作用,不影响原有数据结构
    while(size > 0)
    {
        if(ncap >= size)
        {
            memcpy((char*)buf + bpos, cur->ptr + npos, size);
            if(cur->size == (npos + size))
            {
                cur = cur->next;
            }
            position += size;
            bpos += size;
            size = 0;
        }
        else
        {
            memcpy((char*)buf + bpos, cur->ptr + npos, ncap);
            position += ncap;
            bpos += ncap;
            size -= ncap;
            cur = cur->next;
            ncap = cur->size;
            npos = 0;
        }
    }
}

void ByteArray::setPosition(size_t v)
{
    // 要设置的当前位置比容量还大,则认为异常
    if(v > m_capacity)
    {
        throw std::out_of_range("set_position out of range");
    }
    m_position = v;
    
    if(m_position > m_size)
    {
        m_size = m_position;
    }

    // 因为当前位置变了,那么指向当前内存块的指针也要变
    m_cur = m_root;
    while(v > m_cur->size)
    {
        v -= m_cur->size;
        m_cur = m_cur->next;
    }
    if(v == m_cur->size)
    {
        m_cur = m_cur->next;
    }
}

bool ByteArray::writeToFile(const std::string& name) const
{
    std::ofstream ofs;
    // trunc覆盖写,binary以二进制模式打开
    ofs.open(name, std::ios::trunc | std::ios::binary);
    if(!ofs)
    {
        SYLAR_LOG_ERROR(g_logger) << "writeToFile name=" << name
            << " error, errno=" << errno << " errstr=" << strerror(errno);
        return false;
    }

    int64_t read_size = getReadSize();
    int64_t pos = m_position;
    Node* cur = m_cur;
    while(read_size > 0)
    {
        int diff = pos % m_baseSize;    // 当前块不可读(已经读完)的字节数

        // 1、要读的内容比一整块要大,则读完一整块剩下的那些
        // 2、要读的内容比一整块少,则读???
        // 假设一块10字节,可读9字节,不可读是3字节,则读9-3=6字节,bug???
        // 假设一块10字节,可读1字节,不可读是3字节,则读1-3=-5字节,bug???
        // 应该是:
        // int64_t len = 0;
        // if(read_size > (int64_t)m_baseSize - diff)
        //      len = (int64_t)m_baseSize - diff;
        // else
        //      len = read_size;
        int64_t len = (read_size > (int64_t)m_baseSize ? m_baseSize : read_size) - diff;
        ofs.write(cur->ptr + diff, len);
        cur = cur->next;
        pos += len;
        read_size -= len;
    }

    return true;
}

bool ByteArray::readFromFile(const std::string& name)
{
    std::ifstream ifs;
    ifs.open(name, std::ios::binary);
    if(!ifs)
    {
        SYLAR_LOG_ERROR(g_logger) << "readFromFile name=" << name
            << " error, errno=" << errno << " errstr=" << strerror(errno);
        return false;
    }

    std::shared_ptr<char> buff(new char[m_baseSize], [](char* ptr) { delete[] ptr; });
    while(!ifs.eof())
    {
        ifs.read(buff.get(), m_baseSize);   // 每次读取一块
        write(buff.get(), ifs.gcount());    // gcount()返回最近无格式输入操作所提取的字符数
    }
    return true;
}

bool ByteArray::isLittleEndian() const
{
    return m_endian == SYLAR_LITTLE_ENDIAN;
}

void ByteArray::setIsLittleEndian(bool val)
{
    if(val)
    {
        m_endian = SYLAR_LITTLE_ENDIAN;
    }
    else
    {
        m_endian = SYLAR_BIG_ENDIAN;
    }
}

std::string ByteArray::toString() const
{
    std::string str;
    str.resize(getReadSize());
    if(str.empty())
    {
        return str;
    }
    read(&str[0], str.size(), m_position);
    return str;
}

std::string ByteArray::toHexString() const
{
    std::string str = toString();
    std::stringstream ss;
    for(size_t i=0; i<str.size(); ++i)
    {
        if(i > 0 && i % 32 == 0)
        {
            ss << std::endl;
        }
        ss << std::setw(2) << std::setfill('0') << std::hex
           << (int)(uint8_t)str[i] << " ";
    }
    return ss.str();
}

uint64_t ByteArray::getReadBuffers(std::vector<iovec>& buffers, uint64_t len) const
{
    len = len > getReadSize() ? getReadSize() : len;
    if(len == 0)
    {
        return 0;
    }

    uint64_t size = len;
    size_t npos = m_position % m_baseSize;
    size_t ncap = m_cur->size - npos;
    struct iovec iov;
    Node* cur = m_cur;

    while(len > 0)
    {
        if(ncap >= len)
        {
            iov.iov_base = cur->ptr + npos;
            iov.iov_len = len;
            len = 0;
        }
        else
        {
            iov.iov_base = cur->ptr + npos;
            iov.iov_len = ncap;
            len -= ncap;
            cur = cur->next;
            ncap = cur->size;
            npos = 0;
        }
        buffers.push_back(iov);
    }
    return size;
}

uint64_t ByteArray::getReadBuffers(std::vector<iovec>& buffers, uint64_t len, uint64_t position) const
{
    // 这里的判断好像没啥用,因为下面用的position是外面传进来的,
    // 与m_position是没有关系的,bug???
    len = len > getReadSize() ? getReadSize() : len;
    if(len == 0)
    {
        return 0;
    }

    uint64_t size = len;
    size_t npos = position % m_baseSize;
    size_t count = position / m_baseSize;
    Node* cur = m_root;
    while(count > 0)
    {
        cur = cur->next;
        --count;
    }
    
    size_t ncap = cur->size - npos;
    struct iovec iov;
    while(len > 0)
    {
        if(ncap >= len)
        {
            iov.iov_base = cur->ptr + npos;
            iov.iov_len = len;
            len = 0;
        }
        else
        {
            iov.iov_base = cur->ptr + npos;
            iov.iov_len = ncap;
            len -= ncap;
            cur = cur->next;
            ncap = cur->size;
            npos = 0;
        }
        buffers.push_back(iov);
    }
    return size;
}

uint64_t ByteArray::getWriteBuffers(std::vector<iovec>& buffers, uint64_t len)
{
    if(len == 0)
    {
        return 0;
    }
    addCapacity(len);

    uint64_t size = len;
    size_t npos = m_position % m_baseSize;
    size_t ncap = m_cur->size - npos;
    struct iovec iov;
    Node* cur = m_cur;

    while(len > 0)
    {
        if(ncap >= len)
        {
            iov.iov_base = cur->ptr + npos;
            iov.iov_len = len;
            len = 0;
        }
        else
        {
            iov.iov_base = cur->ptr + npos;
            iov.iov_len = ncap;
            len -= ncap;
            cur = cur->next;
            ncap = cur->size;
            npos = 0;
        }
        buffers.push_back(iov);
    }
    return size;
}

void ByteArray::addCapacity(size_t size)
{
    if(size == 0)
    {
        return;
    }

    size_t old_cap = getCapacity();
    if(old_cap >= size)     // 剩余容量还够,无需扩充
    {
        return;
    }

    size = size - old_cap;  // 得到需要扩充的容量大小
    // ceil(x) 返回大于或者等于x的最小整数
    size_t count = ceil(1.0 * size / m_baseSize);   // 得到需要扩充的块数
    
    // 遍历得到最后一个节点
    Node* tmp = m_root;
    while(tmp->next)
    {
        tmp = tmp->next;
    }

    Node* first = NULL;     // 记录扩充的第一块内存块的位置
    for(size_t i=0; i<count; ++i)
    {
        tmp->next = new Node(m_baseSize);
        if(first == NULL)
        {
            first = tmp->next;
        }
        tmp = tmp->next;
        m_capacity += m_baseSize;   // 容量加上一个内存块
    }

    // 如果剩余容量已经是0了,那么扩充的第一块内容块就是当前可用内存块所在的位置
    if(old_cap == 0)        
    {
        m_cur = first;
    }
}

}

广告时间:基于sylar框架实现的小demo(希望给个star)

基于redis的参数查询服务