github.com/scaleoutsean/fusego@v0.0.0-20220224074057-4a6429e46bb8/internal/buffer/out_message.go (about)

     1  // Copyright 2015 Google Inc. All Rights Reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package buffer
    16  
    17  import (
    18  	"fmt"
    19  	"log"
    20  	"reflect"
    21  	"unsafe"
    22  
    23  	"github.com/scaleoutsean/fusego/internal/fusekernel"
    24  )
    25  
    26  // OutMessageHeaderSize is the size of the leading header in every
    27  // properly-constructed OutMessage. Reset brings the message back to this size.
    28  const OutMessageHeaderSize = int(unsafe.Sizeof(fusekernel.OutHeader{}))
    29  
    30  // OutMessage provides a mechanism for constructing a single contiguous fuse
    31  // message from multiple segments, where the first segment is always a
    32  // fusekernel.OutHeader message.
    33  //
    34  // Must be initialized with Reset.
    35  type OutMessage struct {
    36  	// The offset into payload to which we're currently writing.
    37  	payloadOffset int
    38  
    39  	header  fusekernel.OutHeader
    40  	payload [MaxReadSize]byte
    41  }
    42  
    43  // Make sure that the header and payload are contiguous.
    44  func init() {
    45  	a := unsafe.Offsetof(OutMessage{}.header) + uintptr(OutMessageHeaderSize)
    46  	b := unsafe.Offsetof(OutMessage{}.payload)
    47  
    48  	if a != b {
    49  		log.Panicf(
    50  			"header ends at offset %d, but payload starts at offset %d",
    51  			a, b)
    52  	}
    53  }
    54  
    55  // Reset resets m so that it's ready to be used again. Afterward, the contents
    56  // are solely a zeroed fusekernel.OutHeader struct.
    57  func (m *OutMessage) Reset() {
    58  	// Ideally we'd like to write:
    59  	//
    60  	//     m.payloadOffset = 0
    61  	//     m.header = fusekernel.OutHeader{}
    62  	//
    63  	// But Go 1.8 beta 2 generates bad code for this
    64  	// (https://golang.org/issue/18370). Encourage it to generate the same code
    65  	// as Go 1.7.4 did.
    66  	if unsafe.Offsetof(m.payload) != 24 {
    67  		panic("unexpected OutMessage layout")
    68  	}
    69  
    70  	a := (*[3]uint64)(unsafe.Pointer(m))
    71  	a[0] = 0
    72  	a[1] = 0
    73  	a[2] = 0
    74  }
    75  
    76  // OutHeader returns a pointer to the header at the start of the message.
    77  func (m *OutMessage) OutHeader() *fusekernel.OutHeader {
    78  	return &m.header
    79  }
    80  
    81  // Grow grows m's buffer by the given number of bytes, returning a pointer to
    82  // the start of the new segment, which is guaranteed to be zeroed. If there is
    83  // insufficient space, it returns nil.
    84  func (m *OutMessage) Grow(n int) unsafe.Pointer {
    85  	p := m.GrowNoZero(n)
    86  	if p != nil {
    87  		jacobsa_fuse_memclr(p, uintptr(n))
    88  	}
    89  
    90  	return p
    91  }
    92  
    93  // GrowNoZero is equivalent to Grow, except the new segment is not zeroed. Use
    94  // with caution!
    95  func (m *OutMessage) GrowNoZero(n int) unsafe.Pointer {
    96  	// Will we overflow the buffer?
    97  	o := m.payloadOffset
    98  	if len(m.payload)-o < n {
    99  		return nil
   100  	}
   101  
   102  	p := unsafe.Pointer(uintptr(unsafe.Pointer(&m.payload)) + uintptr(o))
   103  	m.payloadOffset = o + n
   104  
   105  	return p
   106  }
   107  
   108  // ShrinkTo shrinks m to the given size. It panics if the size is greater than
   109  // Len() or less than OutMessageHeaderSize.
   110  func (m *OutMessage) ShrinkTo(n int) {
   111  	if n < OutMessageHeaderSize || n > m.Len() {
   112  		panic(fmt.Sprintf(
   113  			"ShrinkTo(%d) out of range (current Len: %d)",
   114  			n,
   115  			m.Len()))
   116  	}
   117  
   118  	m.payloadOffset = n - OutMessageHeaderSize
   119  }
   120  
   121  // Append is equivalent to growing by len(src), then copying src over the new
   122  // segment. Int panics if there is not enough room available.
   123  func (m *OutMessage) Append(src []byte) {
   124  	p := m.GrowNoZero(len(src))
   125  	if p == nil {
   126  		panic(fmt.Sprintf("Can't grow %d bytes", len(src)))
   127  	}
   128  
   129  	sh := (*reflect.SliceHeader)(unsafe.Pointer(&src))
   130  	jacobsa_fuse_memmove(p, unsafe.Pointer(sh.Data), uintptr(sh.Len))
   131  
   132  	return
   133  }
   134  
   135  // AppendString is like Append, but accepts string input.
   136  func (m *OutMessage) AppendString(src string) {
   137  	p := m.GrowNoZero(len(src))
   138  	if p == nil {
   139  		panic(fmt.Sprintf("Can't grow %d bytes", len(src)))
   140  	}
   141  
   142  	sh := (*reflect.StringHeader)(unsafe.Pointer(&src))
   143  	jacobsa_fuse_memmove(p, unsafe.Pointer(sh.Data), uintptr(sh.Len))
   144  
   145  	return
   146  }
   147  
   148  // Len returns the current size of the message, including the leading header.
   149  func (m *OutMessage) Len() int {
   150  	return OutMessageHeaderSize + m.payloadOffset
   151  }
   152  
   153  // Bytes returns a reference to the current contents of the buffer, including
   154  // the leading header.
   155  func (m *OutMessage) Bytes() []byte {
   156  	l := m.Len()
   157  	sh := reflect.SliceHeader{
   158  		Data: uintptr(unsafe.Pointer(&m.header)),
   159  		Len:  l,
   160  		Cap:  l,
   161  	}
   162  
   163  	return *(*[]byte)(unsafe.Pointer(&sh))
   164  }