ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

0041-Bytes-bytes源码阅读

2022-08-30 08:31:11  阅读:217  来源: 互联网

标签:KIND 0041 clone bytes len 源码 usize shared 共享


环境

  • Time 2022-05-29
  • Rust 1.61.0
  • Bytes 1.1.0

前言

说明

参考:

  1. https://github.com/tokio-rs/bytes
  2. https://zhuanlan.zhihu.com/p/109977513

目标

之前阅读的部分,都是关于静态的字节,后面开始涉及到动态。其中有很多关于原子类型的操作,来实现无锁并发。
这里不深入,先简单理解,之后有机会单独学原子操作和无锁数据结构和并发。
实现 bytes.rs 中的动态字节部分的方法。
前面实现了共享的 Vtable,还有一种复杂的是独占,并且在 clone 时转为共享。

Shared

保证指向 Shared 的指针能被 2 整除,因为会使用指针的奇偶性来判断底层字节当前时共享还是独占的。

const _: [(); 0 - mem::align_of::<Shared>() % 2] = [];

奇偶性

// 偶数表示共享
const KIND_ARC: usize = 0b0;
// 奇数表示不共享
const KIND_VEC: usize = 0b1;
const KIND_MASK: usize = 0b1;

Vtable

定义了两个 Vtable,一个奇数,一个偶数的。

static PROMOTABLE_EVEN_VTABLE: Vtable = Vtable {
    clone: promotable_even_clone,
    drop: promotable_even_drop,
};

static PROMOTABLE_ODD_VTABLE: Vtable = Vtable {
    clone: promotable_odd_clone,
    drop: promotable_odd_drop,
};

promotable_even_clone

对指向 u8 的偶数地址 Vtable 实现 clone

unsafe fn promotable_even_clone(data: &AtomicPtr<()>, ptr: *const u8, len: usize) -> Bytes {
    let shared = data.load(Ordering::Acquire);
    let kind = shared as usize & KIND_MASK;

    if kind == KIND_ARC {
        // 如果是共享的,直接走之前看的共享的增加引用计数的逻辑
        shallow_clone_arc(shared as _, ptr, len)
    } else {
        // 非共享的,需要转成共享
        debug_assert_eq!(kind, KIND_VEC);
        // 创建 share 指针的时候,加上了1,所以这里需要减去1,得到字节的起始地址
        let buf = (shared as usize & !KIND_MASK) as *mut u8;
        shallow_clone_vec(data, shared, buf, ptr, len)
    }
}

shallow_clone_vec

unsafe fn shallow_clone_vec(atom: &AtomicPtr<()>, ptr: *const (),
    buf: *mut u8, offset: *const u8, len: usize,
) -> Bytes {

    let vec = rebuild_boxed_slice(buf, offset, len).into_vec();
    let shared = Box::new(Shared {
        _vec: vec,
        // 原始的一个,clone的一个引用,所以现在是两个
        ref_cnt: AtomicUsize::new(2),
    });

    let shared = Box::into_raw(shared);
    // 如果有的话,需要将其它Bytes的data指向shared指针,无锁进行修改
    match atom.compare_exchange(ptr as _, shared as _, Ordering::AcqRel, Ordering::Acquire) {
        Ok(actual) => {
            Bytes {
                // ptr 指向的是字节的起始地址
                ptr: offset,
                len,
                // 指向 share,需要保证share指针是偶数,表示已经共享
                data: AtomicPtr::new(shared as _),
                vtable: &SHARED_VTABLE,
            }
        }
        Err(actual) => {
            let shared = Box::from_raw(shared);
            mem::forget(*shared);
            // 已经转成共享的了,直接增加引用计数
            shallow_clone_arc(actual as _, offset, len)
        }
    }
}

rebuild_boxed_slice

unsafe fn rebuild_boxed_slice(buf: *mut u8, offset: *const u8, len: usize) -> Box<[u8]> {
    let cap = (offset as usize - buf as usize) + len;
    Box::from_raw(slice::from_raw_parts_mut(buf, cap))
}

promotable_even_drop

unsafe fn promotable_even_drop(data: &mut AtomicPtr<()>, ptr: *const u8, len: usize) {
    data.with_mut(|shared| {
        let shared = *shared;
        let kind = shared as usize & KIND_MASK;

        if kind == KIND_ARC {
            // 共享的继续走共享的逻辑
            release_shared(shared as *mut Shared);
        } else {
            // 不共享的直接删除数据
            debug_assert_eq!(kind, KIND_VEC);
            let buf = (shared as usize & !KIND_MASK) as *mut u8;
            drop(rebuild_boxed_slice(buf, ptr, len));
        }
    });
}

总结

了解了 Bytes 中对于共享的字节的处理方法,包括共享和非共享的。

附录

标签:KIND,0041,clone,bytes,len,源码,usize,shared,共享
来源: https://www.cnblogs.com/jiangbo4444/p/16638039.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有