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中都写了些什么。
ByteView和Sink的更多相关文章
- Flume(4)实用环境搭建:source(spooldir)+channel(file)+sink(hdfs)方式
一.概述: 在实际的生产环境中,一般都会遇到将web服务器比如tomcat.Apache等中产生的日志倒入到HDFS中供分析使用的需求.这里的配置方式就是实现上述需求. 二.配置文件: #agent1 ...
- Flume组件source,channel,sink源码分析
LifeCycleState: IDLE, START, STOP, ERROR [Source]: org.apache.flume.Source 继承LifeCycleAware{stop() + ...
- [bigdata] 使用Flume hdfs sink, hdfs文件未关闭的问题
现象: 执行mapreduce任务时失败 通过hadoop fsck -openforwrite命令查看发现有文件没有关闭. [root@com ~]# hadoop fsck -openforwri ...
- 二、Sink例程
1. Sink例程 CSR粗略的将audio蓝牙设备分为了两大类:sink和source设备,并分别提供了两类设备的例程,配置工具,说明文档.如对于sink设备,提供了sink app例程,SinkU ...
- 一、Stream,sink,source,transform
1. 蓝牙核心概述 2.Stream,sink,source,transform 在ADK的blueCore里面,Stream作为一个逻辑结构用来描述一个数据终点(data Endpoint).通常, ...
- Scalaz(49)- scalaz-stream: 深入了解-Sink/Channel
一个完整的scalaz-stream有以下几个部分组成:Source -> Transducer -> Sink,用直白文字来描述就是:“输入 -> 传换 -> 输出”.我们已 ...
- 泛函编程(36)-泛函Stream IO:IO数据源-IO Source & Sink
上期我们讨论了IO处理过程:Process[I,O].我们说Process就像电视信号盒子一样有输入端和输出端两头.Process之间可以用一个Process的输出端与另一个Process的输入端连接 ...
- 修改Flume-NG的hdfs sink解析时间戳源码大幅提高写入性能
Flume-NG中的hdfs sink的路径名(对应参数"hdfs.path",不允许为空)以及文件前缀(对应参数"hdfs.filePrefix")支持正则解 ...
- Flume简介与使用(三)——Kafka Sink消费数据之Kafka安装
前面已经介绍了如何利用Thrift Source生产数据,今天介绍如何用Kafka Sink消费数据. 其实之前已经在Flume配置文件里设置了用Kafka Sink消费数据 agent1.sinks ...
随机推荐
- 【bzoj 1407】【Noi2002】Savage
Description Input 第1行为一个整数N(1<=N<=15),即野人的数目. 第2行到第N+1每行为三个整数Ci, Pi, Li表示每个野人所住的初始洞穴编号,每年走过的洞穴 ...
- BZOJ_2594_[Wc2006]水管局长数据加强版_LCT
BZOJ_2594_[Wc2006]水管局长数据加强版_LCT Description SC省MY市有着庞大的地下水管网络,嘟嘟是MY市的水管局长(就是管水管的啦),嘟嘟作为水管局长的工作就是:每天供 ...
- BZOJ_1864_[Zjoi2006]三色二叉树_树形DP
BZOJ_1864_[Zjoi2006]三色二叉树_树形DP 题意: 分析:递归建树,然后DP,从子节点转移. 注意到红色和蓝色没有区别,因为我们可以将红蓝互换而方案是相同的.这样的话我们只需要知道当 ...
- Vue.js-11:第十一章 - Vue 中 ref 的使用
一.前言 在之前的前端开发中,为了实现我们的需求,通常采用的方案是通过 JS/Jquery 直接操纵页面的 DOM 元素,得益于 Jquery 对于 DOM 元素优异的操作能力,我们可以很轻易的对获取 ...
- 【转】超酷的 mip-infinitescroll 无限滚动(无限下拉)
写在前面 无限滚动技术(又叫做无限下拉技术)被广泛应用于新闻类,图片预览类网站.对用户来讲,使用无限滚动的页面有源源不断的信息可以预览,增加用户在页面的停留时长.技术上原理也很简单,在页面加载时加载一 ...
- python --- 快速排序算法
在快速排序中引入递归和分治的概念(关于递归和分治的概念会单独写一篇来进行介绍) 问的解决思路: 快速排序的基本思想本身就是分治法,通过分割,将无序序列分成两部分,其中前一部分的元素值都要小于后一部分的 ...
- 【坑】解决CentOS 7.1版本以上安装好zabbix 3.4 无法重启zabbix-server的问题
1. 问题所在 报错信息:zabbix_server[]: segfault at ip 00007f78842b4bd0 sp 00007fff1995a818 error ] 2. 产生原因 Ce ...
- Jenkins之Log Parse的使用
在初学使用Jenkins的同学们,应该都遇到过通过bash或者cmd命令执行输出的日志,没办法做到对error, warning等状态的分析和统计.在这里就给他介绍一款实现此功能的插件Log Pars ...
- 百度病了,必应挂了,Yandex疯了。
前天一篇<搜索引擎百度已死>的文章火遍了互联网圈.文中作者指出如今的百度搜索首页一大半都是百度自家的产品,比如你搜索特普朗,你会发现第一页的结果分别是:百度百科.贴吧.百家号.百家号.百家 ...
- 刨根问底:if 后怎么就可以跟对象,变量交换写法是语法糖吗?
1.万物皆可布尔 一般语言中的 if 语句语法是这样的: if (条件表达式){ 执行语句} 而在 Python 中,if 后面不仅可以是条件表达式,还可以是任意对象.例如: my_list = ...