brpc源码:工具类FlatMap

源码路径

src\butil\containers\flat_map.h

src\butil\containers\flat_map_inl.h

FlatMap 是brpc的一个容器类,在server管理添加的服务时用到

 

基本成员

    size_t _size;
    size_t _nbucket;  // 桶数量
    Bucket* _buckets;  // 桶数组
    uint64_t* _thumbnail; // 用bit存放,每个下标表示桶是否有效
    u_int _load_factor; // 负载因子
    hasher _hashfn;  // 哈希方法
    key_equal _eql; // 相等判断方法
    SingleThreadedPool<sizeof(Bucket), 1024, 16> _pool; // 分配桶空间的内存池

 

初始化

template <typename _K, typename _T, typename _H, typename _E, bool _S>
int FlatMap<_K, _T, _H, _E, _S>::init(size_t nbucket, u_int load_factor) {
    if (initialized()) { // 桶数组 _buckets 不为空则已经初始化
        LOG(ERROR) << "Already initialized";
        return -1;
    }
    if (load_factor < 10 || load_factor > 100) {
        LOG(ERROR) << "Invalid load_factor=" << load_factor;
        return -1;
    }
    _size = 0;
    _nbucket = flatmap_round(nbucket); // 将入参桶数量变为最近的一个素数或2的幂
    _load_factor = load_factor;
                                
    _buckets = (Bucket*)malloc(sizeof(Bucket) * (_nbucket + 1));
    if (NULL == _buckets) {
        LOG(ERROR) << "Fail to new _buckets";
        return -1;
    }
    for (size_t i = 0; i < _nbucket; ++i) {
        _buckets[i].set_invalid(); // 将每个桶元素的next指针置为-1
    }
    _buckets[_nbucket].next = NULL;

    if (_S) {
        _thumbnail = bit_array_malloc(_nbucket); // 以8字节为单位分配空间,详见bit_array.h
        if (NULL == _thumbnail) {
            LOG(ERROR) << "Fail to new _thumbnail";
            return -1;
        }
        bit_array_clear(_thumbnail, _nbucket);
    }
    return 0;
}

 

 

插入元素

template <typename _K, typename _T, typename _H, typename _E, bool _S>
_T* FlatMap<_K, _T, _H, _E, _S>::insert(const key_type& key,
                                        const mapped_type& value) {
    mapped_type *p = &operator[](key);
    *p = value;
    return p;
}

 

 

删除元素

template <typename _K, typename _T, typename _H, typename _E, bool _S>
template <typename K2>
size_t FlatMap<_K, _T, _H, _E, _S>::erase(const K2& key, _T* old_value) {
    if (!initialized()) {
        return 0;
    }
    const size_t index = flatmap_mod(_hashfn(key), _nbucket); // 对key求哈希然后对桶数量取模
    Bucket& first_node = _buckets[index];
    if (!first_node.is_valid()) {
        return 0;
    }
    if (_eql(first_node.element().first_ref(), key)) {
        if (old_value) { // 返回删除节点的值
            *old_value = first_node.element().second_ref();
        }
        if (first_node.next == NULL) { // 对该节点元素调用析构
            first_node.element().~Element();
            first_node.set_invalid();
            if (_S) {
                bit_array_unset(_thumbnail, index); // _thumbnail 数组第index个bit置零
            }
        } else {
            Bucket* p = first_node.next; // 待删节点后还有元素next,把next删掉,然后将next的值拷贝到当前节点。
            first_node.next = p->next;
            const_cast<_K&>(first_node.element().first_ref()) =
                p->element().first_ref();
            first_node.element().second_ref() = p->element().second_ref();
            p->element().~Element();
            _pool.back(p); // 还给内存池?
        }
        --_size;
        return 1UL;
    }
 
    // 这里说明待删节点不是桶第一个元素,找到后直接将节点前缀的next指向节点后缀即可
    Bucket *p = first_node.next;
    Bucket *last_p = &first_node;
    while (p) {
        if (_eql(p->element().first_ref(), key)) {
            if (old_value) {
                *old_value = p->element().second_ref();
            }
            last_p->next = p->next;
            p->element().~Element();
            _pool.back(p);
            --_size;
            return 1UL;
        }
        last_p = p;
        p = p->next;
    }
    return 0;
}

过程基本是求哈希值,找到对应的桶,如果要删的是首元素且只有一个,直接删除;是首元素但不止一个,则将第二个元素删了,然后它的值拷贝到首元素中;不是首元素,则直接将待删节点的前缀节点next指向节点后缀。

 

清空元素

template <typename _K, typename _T, typename _H, typename _E, bool _S>
void FlatMap<_K, _T, _H, _E, _S>::clear() {
    if (0 == _size) {
        return;
    }
    _size = 0;
    if (NULL != _buckets) {
        for (size_t i = 0; i < _nbucket; ++i) {
            Bucket& first_node = _buckets[i]; // 对每个桶每个元素调用析构
            if (first_node.is_valid()) {
                first_node.element().~Element();
                Bucket* p = first_node.next;
                while (p) {
                    Bucket* next_p = p->next;
                    p->element().~Element();
                    _pool.back(p);
                    p = next_p;
                }
                first_node.set_invalid();
            }
        }
    }
    if (NULL != _thumbnail) {
        bit_array_clear(_thumbnail, _nbucket); // 对每个桶表示的bit置零
    }
}

对每个桶每个元素调用析构,并对_thumbnail 每个桶代表的big置零

 

寻找元素

template <typename _K, typename _T, typename _H, typename _E, bool _S>
template <typename K2>
_T* FlatMap<_K, _T, _H, _E, _S>::seek(const K2& key) const {
    if (!initialized()) {
        return NULL;
    }
    Bucket& first_node = _buckets[flatmap_mod(_hashfn(key), _nbucket)];
    if (!first_node.is_valid()) {
        return NULL;
    }
    if (_eql(first_node.element().first_ref(), key)) {
        return &first_node.element().second_ref();
    }
    Bucket *p = first_node.next;
    while (p) {
        if (_eql(p->element().first_ref(), key)) {
            return &p->element().second_ref();
        }
        p = p->next;
    }
    return NULL;
}

 

寻找元素没有则添加

template <typename _K, typename _T, typename _H, typename _E, bool _S>
_T& FlatMap<_K, _T, _H, _E, _S>::operator[](const key_type& key) {
    const size_t index = flatmap_mod(_hashfn(key), _nbucket);
    Bucket& first_node = _buckets[index];
    if (!first_node.is_valid()) { // 桶位置未占用
        ++_size;
        if (_S) {
            bit_array_set(_thumbnail, index); // 置位
        }
        new (&first_node) Bucket(key); // placement new,直接在元素上构建
        return first_node.element().second_ref();
    }
    if (_eql(first_node.element().first_ref(), key)) { //是首元素则返回
        return first_node.element().second_ref();
    }
    Bucket *p = first_node.next;
    if (NULL == p) { // 只有首元素
        if (is_too_crowded(_size)) {
            if (resize(_nbucket + 1)) { // 扩容后添加元素
                return operator[](key);
            }
            // fail to resize is OK
        }
        ++_size;
        Bucket* newp = new (_pool.get()) Bucket(key); // 从内存池分配并初始化
        first_node.next = newp;
        return newp->element().second_ref();
    }

    // 不止首元素
    while (1) {
        if (_eql(p->element().first_ref(), key)) {
            return p->element().second_ref();
        }
        if (NULL == p->next) {
            if (is_too_crowded(_size)) {
                if (resize(_nbucket + 1)) {
                    return operator[](key);
                }
                // fail to resize is OK
            }
            ++_size;
            Bucket* newp = new (_pool.get()) Bucket(key);
            p->next = newp;
            return newp->element().second_ref();
        }
        p = p->next;
    }
}

这里与seek的区别在于不存在则创建、扩容判断

 

扩容

template <typename _K, typename _T, typename _H, typename _E, bool _S>
bool FlatMap<_K, _T, _H, _E, _S>::resize(size_t nbucket2) {
    nbucket2 = flatmap_round(nbucket2); // 找最近的素数或2的幂
    if (_nbucket == nbucket2) {
        return false;
    }

    FlatMap new_map;
    if (new_map.init(nbucket2, _load_factor) != 0) {
        LOG(ERROR) << "Fail to init new_map, nbucket=" << nbucket2;
        return false;
    }
    for (iterator it = begin(); it != end(); ++it) {
        new_map[Element::first_ref_from_value(*it)] = 
            Element::second_ref_from_value(*it); // first_ref_from_value 获取key,second_ref_from_value 获取value
    }
    new_map.swap(*this); // 替换成新的map
    return true;
}

 

brpc

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值