zoukankan      html  css  js  c++  java
  • ByteView和Sink

    久违啦米娜桑!!!

    最近有点忙,一月有余没有更新了,实在对不起大家!!!

    上线后看到不少朋友发的私信,感谢大家的赞许与信任,后面我会尽最大的努力按时更新,不断推出更优质的文章!!!

    本来计划最后花1讲的篇幅写完groupcache的源码分析的,今天刷了一下发现量还是有点多,可能得分两三讲;不过不会等到两三周才讲完的,预计趁着这个中秋假期刷完,一天一篇结束这个项目。

    之前我们已经看完了groupcache项目的各个子包,今天要真正开始欣赏groupcache的漂亮代码了!(剧透一下,groupcache.go里面还是发现了一些写的很“漂亮”的代码,几行的内容够琢磨小半天的)

    先看一下groupcache这个package的uml图吧:

    从图中我们可以看到一个很重要的interface:Sink和一个很重要的struct:ByteView,为什么说重要呢,我也不知道。。。不过看连线嘛,一堆的struct都与这2个类型产生了关系,于是今天我们围绕着这2个类型展开源码透析!

     

    1、byteview.go

    可以看到这个go文件中只有一个类型ByteView,这个类型有2个属性和一堆绑定的方法,下面我们逐个来看:

    ByteView的定义很简单,存着一个[]byte类型的b和string类型的s,这个需要牢记,因为其他很多地方都是围绕着这个类型展开的编码!这个文件中涉及的方法总体看还是比较简洁简单,大家参照着中英文注释浏览一遍应该很容易理解:

    // Len returns the view's length.
    //【返回一个view的长度】
    func (v ByteView) Len() int {
        if v.b != nil {
            return len(v.b)
        }
        return len(v.s)
    }

    // ByteSlice returns a copy of the data as a byte slice.
    //【获取一份[]byte类型的view值的拷贝】
    func (v ByteView) ByteSlice() []byte {
        if v.b != nil {
            return cloneBytes(v.b)
        }
        return []byte(v.s)
    }

    // String returns the data as a string, making a copy if necessary.
    //【上一个是返回[]byte类型,这里是string类型】
    func (v ByteView) String() string {
        if v.b != nil {
            return string(v.b)
        }
        return v.s
    }

    // At returns the byte at index i.
    //【返回第i个byte】
    func (v ByteView) At(i int) byte {
        if v.b != nil {
            return v.b[i]
        }
        //【字符串索引获取到的值是byte类型】
        return v.s[i]
    }

    // Slice slices the view between the provided from and to indices.
    //【返回从索引from到to的view的切分结果】
    func (v ByteView) Slice(from, to int) ByteView {
        if v.b != nil {
            return ByteView{b: v.b[from:to]}
        }
        return ByteView{s: v.s[from:to]}
    }

    // SliceFrom slices the view from the provided index until the end.
    //【相当于上面的to为len(b)】
    func (v ByteView) SliceFrom(from int) ByteView {
        if v.b != nil {
            return ByteView{b: v.b[from:]}
        }
        return ByteView{s: v.s[from:]}
    }

    // Copy copies b into dest and returns the number of bytes copied.
    //【拷贝一份view到dest】
    func (v ByteView) Copy(dest []byte) int {
        if v.b != nil {
            return copy(dest, v.b)
        }
        return copy(dest, v.s)
    }

    // Equal returns whether the bytes in b are the same as the bytes in
    // b2.
    //【相等判断,具体比较的实现在下面】
    func (v ByteView) Equal(b2 ByteView) bool {
        if b2.b == nil {
            return v.EqualString(b2.s)
        }
        return v.EqualBytes(b2.b)
    }

    // EqualString returns whether the bytes in b are the same as the bytes
    // in s.
    func (v ByteView) EqualString(s string) bool {
        if v.b == nil {
            //【如果b为nil,则比较s是否相等】
            return v.s == s
        }
        //【l为view的长度,实现在上面】
        l := v.Len()
        //【长度不同直接返回false】
        if len(s) != l {
            return false
        }
        //【判断[]byte中的每一个byte是否和string的每一个字符相等】
        for i, bi := range v.b {
            if bi != s[i] {
                return false
            }
        }
        return true
    }

    // EqualBytes returns whether the bytes in b are the same as the bytes
    // in b2.
    func (v ByteView) EqualBytes(b2 []byte) bool {
        //【b不为空,直接通过Equal方法比较】
        if v.b != nil {
            return bytes.Equal(v.b, b2)
        }
        l := v.Len()
        //【长度不等直接返回false】
        if len(b2) != l {
            return false
        }
        //【与上一个方法类似,比较字符串和[]byte每一个byte是否相等】
        for i, bi := range b2 {
            if bi != v.s[i] {
                return false
            }
        }
        return true
    }

    // Reader returns an io.ReadSeeker for the bytes in v.
    //【返回值其实是bytes包或者strings包中的*Reader类型,这是个struct
    // 实现了io.ReadSeeker等接口】
    func (v ByteView) Reader() io.ReadSeeker {
        if v.b != nil {
            return bytes.NewReader(v.b)
        }
        return strings.NewReader(v.s)
    }

    // ReadAt implements io.ReaderAt on the bytes in v.
    func (v ByteView) ReadAt(p []byte, off int64) (n int, err error) {
        if off < 0 {
            return 0, errors.New("view: invalid offset")
        }
        if off >= int64(v.Len()) {
            return 0, io.EOF
        }
        //【从off开始拷贝一份数据到p】
        n = v.SliceFrom(int(off)).Copy(p)
        if n < len(p) {
            err = io.EOF
        }
        return
    }

    // WriteTo implements io.WriterTo on the bytes in v.
    //【将v写入w】
    func (v ByteView) WriteTo(w io.Writer) (n int64, err error) {
        var m int
        if v.b != nil {
            m, err = w.Write(v.b)
        } else {
            m, err = io.WriteString(w, v.s)
        }
        if err == nil && m < v.Len() {
            err = io.ErrShortWrite
        }
        n = int64(m)
        return
    }

    ByteView这个struct需要记住,下面我们看Sink,其中很多地方会操作ByteView。

     

    2、sinks.go

    前面在uml图中已经看到有5个类型实现了Sink接口,我们先看一下sink.go的结构:

    粗看是1个接口5个结构体和一堆函数,我们从Sink入手:

    可以看到实现了Sink的结构体应该是用来存储某种数据的,存的时候需要调用到SetXxx()方法,可以通过view()方法获取到一些东西,返回值是上面介绍的ByteView类型的。

    先看个简单的struct:stringSink

    如上图,stringSink只包含2个成员,初始化函数也特别简单,接收一个*string类型的sp,返回值注意一下,是Sink接口类型的。

    stringSink有4个方法,刚好实现了Sink接口

     

    每个方法都挺好理解的,名字不同是因为接收的参数不同,但不管接收到什么类型的参数,都是用于设置stringSink的2个成员。

    再看2个函数:

    这个太简单了,就是克隆一个byte切片,不多说了,下面一个函数,,,可就没那么简洁了:

    这个函数内部定义了一个叫做viewSetter的interface类型,这个类型有个setView(v ByteView) error方法,参数还是ByteView类型的。前面我们看过各种Set方法或多或少或操作到ByteView类型的数据,不过一般是分开处理ByteView中的b或者s,这里明显是不需要区分了,直接设置整个ByteView。第一个if判断参数s是否实现了viewSetter接口,如果实现了,则直接调用setView设置v,如果没有实现,则通过Sink的SetXxx()方法设置ByteView。下面贴一波剩下几个struct及绑定方法的代码,每个struct的逻辑大同小异,大家对这注释理解一下,注意上面介绍到的setView方法在下面的部分struct中是如何实现的:

    // ByteViewSink returns a Sink that populates a ByteView.
    //【根据参数dst构造byteViewSink结构体实例】
    func ByteViewSink(dst *ByteView) Sink {
        if dst == nil {
            panic("nil dst")
        }
        return &byteViewSink{dst: dst}
    }

    //【属性dst为一个ByteView指针】
    type byteViewSink struct {
        dst *ByteView

        // if this code ever ends up tracking that at least one set*
        // method was called, don't make it an error to call set
        // methods multiple times. Lorry's payload.go does that, and
        // it makes sense. The comment at the top of this file about
        // "exactly one of the Set methods" is overly strict. We
        // really care about at least once (in a handler), but if
        // multiple handlers fail (or multiple functions in a program
        // using a Sink), it's okay to re-use the same one.
    }

    func (s *byteViewSink) setView(v ByteView) error {
        *s.dst = v
        return nil
    }

    func (s *byteViewSink) view() (ByteView, error) {
        return *s.dst, nil
    }

    //【设置byteViewSink中ByteView的b】
    func (s *byteViewSink) SetProto(m proto.Message) error {
        b, err := proto.Marshal(m)
        if err != nil {
            return err
        }
        *s.dst = ByteView{b: b}
        return nil
    }

    //【复制b,初始化byteViewSink的dst】
    func (s *byteViewSink) SetBytes(b []byte) error {
        *s.dst = ByteView{b: cloneBytes(b)}
        return nil
    }
    //【通过使用string类型的v初始化一个ByteView后初始化byteViewSink的dst】
    func (s *byteViewSink) SetString(v string) error {
        *s.dst = ByteView{s: v}
        return nil
    }

    // ProtoSink returns a sink that unmarshals binary proto values into m.
    //【使用proto.Message类型的m初始化protoSink的dst】
    func ProtoSink(m proto.Message) Sink {
        return &protoSink{
            dst: m,
        }
    }

    //【3个属性】
    type protoSink struct {
        dst proto.Message // authoritative value
        typ string

        v ByteView // encoded
    }

    //【返回protoSink的ByteView类型的v】
    func (s *protoSink) view() (ByteView, error) {
        return s.v, nil
    }

    //【将s.dst反序列化后丢给b,并且复制一份丢给protoSink中ByteView的b】
    func (s *protoSink) SetBytes(b []byte) error {
        err := proto.Unmarshal(b, s.dst)
        if err != nil {
            return err
        }
        s.v.b = cloneBytes(b)
        s.v.s = ""
        return nil
    }
    //【将b解码后写入s.dst】
    func (s *protoSink) SetString(v string) error {
        b := []byte(v)
        err := proto.Unmarshal(b, s.dst)
        if err != nil {
            return err
        }
        s.v.b = b
        s.v.s = ""
        return nil
    }

    //【将m写入protoSink的dst】
    func (s *protoSink) SetProto(m proto.Message) error {
        b, err := proto.Marshal(m)
        if err != nil {
            return err
        }
        // TODO(bradfitz): optimize for same-task case more and write
        // right through? would need to document ownership rules at
        // the same time. but then we could just assign *dst = *m
        // here. This works for now:
        err = proto.Unmarshal(b, s.dst)
        if err != nil {
            return err
        }
        s.v.b = b
        s.v.s = ""
        return nil
    }

    // AllocatingByteSliceSink returns a Sink that allocates
    // a byte slice to hold the received value and assigns
    // it to *dst. The memory is not retained by groupcache.
    //【分配一个字节切片来保存接收到的数据】
    func AllocatingByteSliceSink(dst *[]byte) Sink {
        return &allocBytesSink{dst: dst}
    }

    //【有一个字节切片指针类型的属性dst】
    type allocBytesSink struct {
        dst *[]byte
        v   ByteView
    }

    func (s *allocBytesSink) view() (ByteView, error) {
        return s.v, nil
    }

    //【设置allocBytesSink的v,同时复制v中的b或者s丢给dst】
    func (s *allocBytesSink) setView(v ByteView) error {
        if v.b != nil {
            *s.dst = cloneBytes(v.b)
        } else {
            *s.dst = []byte(v.s)
        }
        s.v = v
        return nil
    }

    //【这个得从下面的setBytesOwned开始往上看】
    func (s *allocBytesSink) SetProto(m proto.Message) error {
        b, err := proto.Marshal(m)
        if err != nil {
            return err
        }
        return s.setBytesOwned(b)
    }

    //【复制一份b,然后调用setBytesOwned】
    func (s *allocBytesSink) SetBytes(b []byte) error {
        return s.setBytesOwned(cloneBytes(b))
    }

    //【使用b设置allocBytesSink的dst和ByteView】
    func (s *allocBytesSink) setBytesOwned(b []byte) error {
        if s.dst == nil {
            return errors.New("nil AllocatingByteSliceSink *[]byte dst")
        }
        *s.dst = cloneBytes(b) // another copy, protecting the read-only s.v.b view
        s.v.b = b
        s.v.s = ""
        return nil
    }

    //【字符串转成[]byte后进行和上面类似的操作】
    func (s *allocBytesSink) SetString(v string) error {
        if s.dst == nil {
            return errors.New("nil AllocatingByteSliceSink *[]byte dst")
        }
        *s.dst = []byte(v)
        s.v.b = nil
        s.v.s = v
        return nil
    }

    // TruncatingByteSliceSink returns a Sink that writes up to len(*dst)
    // bytes to *dst. If more bytes are available, they're silently
    // truncated. If fewer bytes are available than len(*dst), *dst
    // is shrunk to fit the number of bytes available.
    //【截面字节切片Sink,写入len(*dst)个字节到dst,如果长度超了会被截断,
    //少了则dst会收缩长度来适配】
    func TruncatingByteSliceSink(dst *[]byte) Sink {
        return &truncBytesSink{dst: dst}
    }

    type truncBytesSink struct {
        dst *[]byte
        v   ByteView
    }

    func (s *truncBytesSink) view() (ByteView, error) {
        return s.v, nil
    }

    //【从下面的setBytesOwned开始看】
    func (s *truncBytesSink) SetProto(m proto.Message) error {
        b, err := proto.Marshal(m)
        if err != nil {
            return err
        }
        return s.setBytesOwned(b)
    }

    func (s *truncBytesSink) SetBytes(b []byte) error {
        return s.setBytesOwned(cloneBytes(b))
    }

    func (s *truncBytesSink) setBytesOwned(b []byte) error {
        if s.dst == nil {
            return errors.New("nil TruncatingByteSliceSink *[]byte dst")
        }
        n := copy(*s.dst, b)
        //【收缩】
        if n < len(*s.dst) {
            *s.dst = (*s.dst)[:n]
        }
        s.v.b = b
        s.v.s = ""
        return nil
    }

    func (s *truncBytesSink) SetString(v string) error {
        if s.dst == nil {
            return errors.New("nil TruncatingByteSliceSink *[]byte dst")
        }
        n := copy(*s.dst, v)
        //【收缩】
        if n < len(*s.dst) {
            *s.dst = (*s.dst)[:n]
        }
        s.v.b = nil
        s.v.s = v
        return nil
    }

     

    ok,这次先介绍到这里,下一讲我们来看peers.go和http.go中都写了些什么。

     

     

     

     

     

    久违啦米娜桑!!!

    最近有点忙,一月有余没有更新了,实在对不起大家!!!

    上线后看到不少朋友发的私信,感谢大家的赞许与信任,后面我会尽最大的努力按时更新,不断推出更优质的文章!!!

    本来计划最后花1讲的篇幅写完groupcache的源码分析的,今天刷了一下发现量还是有点多,可能得分两三讲;不过不会等到两三周才讲完的,预计趁着这个中秋假期刷完,一天一篇结束这个项目。

    之前我们已经看完了groupcache项目的各个子包,今天要真正开始欣赏groupcache的漂亮代码了!(剧透一下,groupcache.go里面还是发现了一些写的很“漂亮”的代码,几行的内容够琢磨小半天的)

    先看一下groupcache这个package的uml图吧:

    从图中我们可以看到一个很重要的interface:Sink和一个很重要的struct:ByteView,为什么说重要呢,我也不知道。。。不过看连线嘛,一堆的struct都与这2个类型产生了关系,于是今天我们围绕着这2个类型展开源码透析!

     

    1、byteview.go

    可以看到这个go文件中只有一个类型ByteView,这个类型有2个属性和一堆绑定的方法,下面我们逐个来看:

    ByteView的定义很简单,存着一个[]byte类型的b和string类型的s,这个需要牢记,因为其他很多地方都是围绕着这个类型展开的编码!这个文件中涉及的方法总体看还是比较简洁简单,大家参照着中英文注释浏览一遍应该很容易理解:

    // Len returns the view's length.
    //【返回一个view的长度】
    func (v ByteView) Len() int {
        if v.b != nil {
            return len(v.b)
        }
        return len(v.s)
    }

    // ByteSlice returns a copy of the data as a byte slice.
    //【获取一份[]byte类型的view值的拷贝】
    func (v ByteView) ByteSlice() []byte {
        if v.b != nil {
            return cloneBytes(v.b)
        }
        return []byte(v.s)
    }

    // String returns the data as a string, making a copy if necessary.
    //【上一个是返回[]byte类型,这里是string类型】
    func (v ByteView) String() string {
        if v.b != nil {
            return string(v.b)
        }
        return v.s
    }

    // At returns the byte at index i.
    //【返回第i个byte】
    func (v ByteView) At(i int) byte {
        if v.b != nil {
            return v.b[i]
        }
        //【字符串索引获取到的值是byte类型】
        return v.s[i]
    }

    // Slice slices the view between the provided from and to indices.
    //【返回从索引from到to的view的切分结果】
    func (v ByteView) Slice(from, to int) ByteView {
        if v.b != nil {
            return ByteView{b: v.b[from:to]}
        }
        return ByteView{s: v.s[from:to]}
    }

    // SliceFrom slices the view from the provided index until the end.
    //【相当于上面的to为len(b)】
    func (v ByteView) SliceFrom(from int) ByteView {
        if v.b != nil {
            return ByteView{b: v.b[from:]}
        }
        return ByteView{s: v.s[from:]}
    }

    // Copy copies b into dest and returns the number of bytes copied.
    //【拷贝一份view到dest】
    func (v ByteView) Copy(dest []byte) int {
        if v.b != nil {
            return copy(dest, v.b)
        }
        return copy(dest, v.s)
    }

    // Equal returns whether the bytes in b are the same as the bytes in
    // b2.
    //【相等判断,具体比较的实现在下面】
    func (v ByteView) Equal(b2 ByteView) bool {
        if b2.b == nil {
            return v.EqualString(b2.s)
        }
        return v.EqualBytes(b2.b)
    }

    // EqualString returns whether the bytes in b are the same as the bytes
    // in s.
    func (v ByteView) EqualString(s string) bool {
        if v.b == nil {
            //【如果b为nil,则比较s是否相等】
            return v.s == s
        }
        //【l为view的长度,实现在上面】
        l := v.Len()
        //【长度不同直接返回false】
        if len(s) != l {
            return false
        }
        //【判断[]byte中的每一个byte是否和string的每一个字符相等】
        for i, bi := range v.b {
            if bi != s[i] {
                return false
            }
        }
        return true
    }

    // EqualBytes returns whether the bytes in b are the same as the bytes
    // in b2.
    func (v ByteView) EqualBytes(b2 []byte) bool {
        //【b不为空,直接通过Equal方法比较】
        if v.b != nil {
            return bytes.Equal(v.b, b2)
        }
        l := v.Len()
        //【长度不等直接返回false】
        if len(b2) != l {
            return false
        }
        //【与上一个方法类似,比较字符串和[]byte每一个byte是否相等】
        for i, bi := range b2 {
            if bi != v.s[i] {
                return false
            }
        }
        return true
    }

    // Reader returns an io.ReadSeeker for the bytes in v.
    //【返回值其实是bytes包或者strings包中的*Reader类型,这是个struct
    // 实现了io.ReadSeeker等接口】
    func (v ByteView) Reader() io.ReadSeeker {
        if v.b != nil {
            return bytes.NewReader(v.b)
        }
        return strings.NewReader(v.s)
    }

    // ReadAt implements io.ReaderAt on the bytes in v.
    func (v ByteView) ReadAt(p []byte, off int64) (n int, err error) {
        if off < 0 {
            return 0, errors.New("view: invalid offset")
        }
        if off >= int64(v.Len()) {
            return 0, io.EOF
        }
        //【从off开始拷贝一份数据到p】
        n = v.SliceFrom(int(off)).Copy(p)
        if n < len(p) {
            err = io.EOF
        }
        return
    }

    // WriteTo implements io.WriterTo on the bytes in v.
    //【将v写入w】
    func (v ByteView) WriteTo(w io.Writer) (n int64, err error) {
        var m int
        if v.b != nil {
            m, err = w.Write(v.b)
        } else {
            m, err = io.WriteString(w, v.s)
        }
        if err == nil && m < v.Len() {
            err = io.ErrShortWrite
        }
        n = int64(m)
        return
    }

    ByteView这个struct需要记住,下面我们看Sink,其中很多地方会操作ByteView。

     

    2、sinks.go

    前面在uml图中已经看到有5个类型实现了Sink接口,我们先看一下sink.go的结构:

    粗看是1个接口5个结构体和一堆函数,我们从Sink入手:

    可以看到实现了Sink的结构体应该是用来存储某种数据的,存的时候需要调用到SetXxx()方法,可以通过view()方法获取到一些东西,返回值是上面介绍的ByteView类型的。

    先看个简单的struct:stringSink

    如上图,stringSink只包含2个成员,初始化函数也特别简单,接收一个*string类型的sp,返回值注意一下,是Sink接口类型的。

    stringSink有4个方法,刚好实现了Sink接口

    每个方法都挺好理解的,名字不同是因为接收的参数不同,但不管接收到什么类型的参数,都是用于设置stringSink的2个成员。

    再看2个函数:

    这个太简单了,就是克隆一个byte切片,不多说了,下面一个函数,,,可就没那么简洁了:

    这个函数内部定义了一个叫做viewSetter的interface类型,这个类型有个setView(v ByteView) error方法,参数还是ByteView类型的。前面我们看过各种Set方法或多或少或操作到ByteView类型的数据,不过一般是分开处理ByteView中的b或者s,这里明显是不需要区分了,直接设置整个ByteView。第一个if判断参数s是否实现了viewSetter接口,如果实现了,则直接调用setView设置v,如果没有实现,则通过Sink的SetXxx()方法设置ByteView。下面贴一波剩下几个struct及绑定方法的代码,每个struct的逻辑大同小异,大家对这注释理解一下,注意上面介绍到的setView方法在下面的部分struct中是如何实现的:

    // ByteViewSink returns a Sink that populates a ByteView.
    //【根据参数dst构造byteViewSink结构体实例】
    func ByteViewSink(dst *ByteView) Sink {
        if dst == nil {
            panic("nil dst")
        }
        return &byteViewSink{dst: dst}
    }

    //【属性dst为一个ByteView指针】
    type byteViewSink struct {
        dst *ByteView

        // if this code ever ends up tracking that at least one set*
        // method was called, don't make it an error to call set
        // methods multiple times. Lorry's payload.go does that, and
        // it makes sense. The comment at the top of this file about
        // "exactly one of the Set methods" is overly strict. We
        // really care about at least once (in a handler), but if
        // multiple handlers fail (or multiple functions in a program
        // using a Sink), it's okay to re-use the same one.
    }

    func (s *byteViewSink) setView(v ByteView) error {
        *s.dst = v
        return nil
    }

    func (s *byteViewSink) view() (ByteView, error) {
        return *s.dst, nil
    }

    //【设置byteViewSink中ByteView的b】
    func (s *byteViewSink) SetProto(m proto.Message) error {
        b, err := proto.Marshal(m)
        if err != nil {
            return err
        }
        *s.dst = ByteView{b: b}
        return nil
    }

    //【复制b,初始化byteViewSink的dst】
    func (s *byteViewSink) SetBytes(b []byte) error {
        *s.dst = ByteView{b: cloneBytes(b)}
        return nil
    }
    //【通过使用string类型的v初始化一个ByteView后初始化byteViewSink的dst】
    func (s *byteViewSink) SetString(v string) error {
        *s.dst = ByteView{s: v}
        return nil
    }

    // ProtoSink returns a sink that unmarshals binary proto values into m.
    //【使用proto.Message类型的m初始化protoSink的dst】
    func ProtoSink(m proto.Message) Sink {
        return &protoSink{
            dst: m,
        }
    }

    //【3个属性】
    type protoSink struct {
        dst proto.Message // authoritative value
        typ string

        v ByteView // encoded
    }

    //【返回protoSink的ByteView类型的v】
    func (s *protoSink) view() (ByteView, error) {
        return s.v, nil
    }

    //【将s.dst反序列化后丢给b,并且复制一份丢给protoSink中ByteView的b】
    func (s *protoSink) SetBytes(b []byte) error {
        err := proto.Unmarshal(b, s.dst)
        if err != nil {
            return err
        }
        s.v.b = cloneBytes(b)
        s.v.s = ""
        return nil
    }
    //【将b解码后写入s.dst】
    func (s *protoSink) SetString(v string) error {
        b := []byte(v)
        err := proto.Unmarshal(b, s.dst)
        if err != nil {
            return err
        }
        s.v.b = b
        s.v.s = ""
        return nil
    }

    //【将m写入protoSink的dst】
    func (s *protoSink) SetProto(m proto.Message) error {
        b, err := proto.Marshal(m)
        if err != nil {
            return err
        }
        // TODO(bradfitz): optimize for same-task case more and write
        // right through? would need to document ownership rules at
        // the same time. but then we could just assign *dst = *m
        // here. This works for now:
        err = proto.Unmarshal(b, s.dst)
        if err != nil {
            return err
        }
        s.v.b = b
        s.v.s = ""
        return nil
    }

    // AllocatingByteSliceSink returns a Sink that allocates
    // a byte slice to hold the received value and assigns
    // it to *dst. The memory is not retained by groupcache.
    //【分配一个字节切片来保存接收到的数据】
    func AllocatingByteSliceSink(dst *[]byte) Sink {
        return &allocBytesSink{dst: dst}
    }

    //【有一个字节切片指针类型的属性dst】
    type allocBytesSink struct {
        dst *[]byte
        v   ByteView
    }

    func (s *allocBytesSink) view() (ByteView, error) {
        return s.v, nil
    }

    //【设置allocBytesSink的v,同时复制v中的b或者s丢给dst】
    func (s *allocBytesSink) setView(v ByteView) error {
        if v.b != nil {
            *s.dst = cloneBytes(v.b)
        } else {
            *s.dst = []byte(v.s)
        }
        s.v = v
        return nil
    }

    //【这个得从下面的setBytesOwned开始往上看】
    func (s *allocBytesSink) SetProto(m proto.Message) error {
        b, err := proto.Marshal(m)
        if err != nil {
            return err
        }
        return s.setBytesOwned(b)
    }

    //【复制一份b,然后调用setBytesOwned】
    func (s *allocBytesSink) SetBytes(b []byte) error {
        return s.setBytesOwned(cloneBytes(b))
    }

    //【使用b设置allocBytesSink的dst和ByteView】
    func (s *allocBytesSink) setBytesOwned(b []byte) error {
        if s.dst == nil {
            return errors.New("nil AllocatingByteSliceSink *[]byte dst")
        }
        *s.dst = cloneBytes(b) // another copy, protecting the read-only s.v.b view
        s.v.b = b
        s.v.s = ""
        return nil
    }

    //【字符串转成[]byte后进行和上面类似的操作】
    func (s *allocBytesSink) SetString(v string) error {
        if s.dst == nil {
            return errors.New("nil AllocatingByteSliceSink *[]byte dst")
        }
        *s.dst = []byte(v)
        s.v.b = nil
        s.v.s = v
        return nil
    }

    // TruncatingByteSliceSink returns a Sink that writes up to len(*dst)
    // bytes to *dst. If more bytes are available, they're silently
    // truncated. If fewer bytes are available than len(*dst), *dst
    // is shrunk to fit the number of bytes available.
    //【截面字节切片Sink,写入len(*dst)个字节到dst,如果长度超了会被截断,
    //少了则dst会收缩长度来适配】
    func TruncatingByteSliceSink(dst *[]byte) Sink {
        return &truncBytesSink{dst: dst}
    }

    type truncBytesSink struct {
        dst *[]byte
        v   ByteView
    }

    func (s *truncBytesSink) view() (ByteView, error) {
        return s.v, nil
    }

    //【从下面的setBytesOwned开始看】
    func (s *truncBytesSink) SetProto(m proto.Message) error {
        b, err := proto.Marshal(m)
        if err != nil {
            return err
        }
        return s.setBytesOwned(b)
    }

    func (s *truncBytesSink) SetBytes(b []byte) error {
        return s.setBytesOwned(cloneBytes(b))
    }

    func (s *truncBytesSink) setBytesOwned(b []byte) error {
        if s.dst == nil {
            return errors.New("nil TruncatingByteSliceSink *[]byte dst")
        }
        n := copy(*s.dst, b)
        //【收缩】
        if n < len(*s.dst) {
            *s.dst = (*s.dst)[:n]
        }
        s.v.b = b
        s.v.s = ""
        return nil
    }

    func (s *truncBytesSink) SetString(v string) error {
        if s.dst == nil {
            return errors.New("nil TruncatingByteSliceSink *[]byte dst")
        }
        n := copy(*s.dst, v)
        //【收缩】
        if n < len(*s.dst) {
            *s.dst = (*s.dst)[:n]
        }
        s.v.b = nil
        s.v.s = v
        return nil
    }

    ok,这次先介绍到这里,下一讲我们来看peers.go和http.go中都写了些什么。

     

     

     

     

     

  • 相关阅读:
    夺命雷公狗---Thinkphp----16之首页的完成及全站的完成
    夺命雷公狗---Thinkphp----15之遍历出来的栏目页的完成
    夺命雷公狗---Thinkphp----14之前台的首页完善
    夺命雷公狗-----tp中遇到数据乘积的问题的遇见
    夺命雷公狗---Thinkphp----13之前台的头尾分离和导航分离
    夺命雷公狗---Thinkphp----12之文章的增删改查(图片上传和关联查询)
    夺命雷公狗TP下关联查询
    夺命雷公狗---Thinkphp----11之管理员的增删改查的完善
    夺命雷公狗---Thinkphp----10之后台登录.注销一条龙
    夺命雷公狗---Thinkphp----9之中间层的创建,防止跨目录访问
  • 原文地址:https://www.cnblogs.com/cloudgeek/p/9693725.html
Copyright © 2011-2022 走看看