github.com/NVIDIA/aistore@v1.3.23-0.20240517131212-7df6609be51d/transport/header.go (about)

     1  // Package transport provides long-lived http/tcp connections for
     2  // intra-cluster communications (see README for details and usage example).
     3  /*
     4   * Copyright (c) 2018-2023, NVIDIA CORPORATION. All rights reserved.
     5   */
     6  package transport
     7  
     8  import (
     9  	"encoding/binary"
    10  	"fmt"
    11  	"math"
    12  
    13  	"github.com/NVIDIA/aistore/cmn"
    14  	"github.com/NVIDIA/aistore/cmn/atomic"
    15  	"github.com/NVIDIA/aistore/cmn/cos"
    16  	"github.com/NVIDIA/aistore/cmn/debug"
    17  	"github.com/NVIDIA/aistore/cmn/xoshiro256"
    18  )
    19  
    20  // proto header
    21  const (
    22  	// flags
    23  	msgFl       = uint64(1 << (63 - iota)) // message vs object demux
    24  	pduFl                                  // is PDU
    25  	pduLastFl                              // is last PDU
    26  	pduStreamFl                            // PDU-based stream
    27  
    28  	// NOTE: update when adding/changing flags :NOTE
    29  	allFlags = msgFl | pduFl | pduLastFl | pduStreamFl
    30  
    31  	// all 3 headers
    32  	sizeProtoHdr = cos.SizeofI64 * 2
    33  )
    34  
    35  ////////////////////////////////
    36  // proto header serialization //
    37  ////////////////////////////////
    38  
    39  func insObjHeader(hbuf []byte, hdr *ObjHdr, usePDU bool) (off int) {
    40  	debug.Assert(usePDU || !hdr.IsUnsized())
    41  	off = sizeProtoHdr
    42  	off = insString(off, hbuf, hdr.SID)
    43  	off = insUint16(off, hbuf, hdr.Opcode)
    44  	off = insString(off, hbuf, hdr.Bck.Name)
    45  	off = insString(off, hbuf, hdr.Bck.Provider)
    46  	off = insString(off, hbuf, hdr.Bck.Ns.Name)
    47  	off = insString(off, hbuf, hdr.Bck.Ns.UUID)
    48  	off = insString(off, hbuf, hdr.ObjName)
    49  	off = insBytes(off, hbuf, hdr.Opaque)
    50  	off = insAttrs(off, hbuf, &hdr.ObjAttrs)
    51  	word1 := uint64(off - sizeProtoHdr)
    52  	if usePDU {
    53  		word1 |= pduStreamFl
    54  	}
    55  	insUint64(0, hbuf, word1)
    56  	checksum := xoshiro256.Hash(word1)
    57  	insUint64(cos.SizeofI64, hbuf, checksum)
    58  	return
    59  }
    60  
    61  func (pdu *spdu) insHeader() {
    62  	buf, plen := pdu.buf, pdu.plength()
    63  	word1 := uint64(plen) | pduFl
    64  	if pdu.last {
    65  		word1 |= pduLastFl
    66  	}
    67  	insUint64(0, buf, word1)
    68  	checksum := xoshiro256.Hash(word1)
    69  	insUint64(cos.SizeofI64, buf, checksum)
    70  	pdu.done = true
    71  }
    72  
    73  func insString(off int, to []byte, str string) int {
    74  	return insBytes(off, to, []byte(str))
    75  }
    76  
    77  func insBytes(off int, to, b []byte) int {
    78  	l := len(b)
    79  	debug.Assert(l <= 65535, "the field is uint16")
    80  	binary.BigEndian.PutUint16(to[off:], uint16(l))
    81  	off += cos.SizeofI16
    82  	n := copy(to[off:], b)
    83  	debug.Assert(n == l)
    84  	return off + l
    85  }
    86  
    87  func insUint16(off int, to []byte, i int) int {
    88  	debug.Assert(i >= 0 && i < math.MaxUint16)
    89  	binary.BigEndian.PutUint16(to[off:], uint16(i))
    90  	return off + cos.SizeofI16
    91  }
    92  
    93  func insInt64(off int, to []byte, i int64) int {
    94  	return insUint64(off, to, uint64(i))
    95  }
    96  
    97  func insUint64(off int, to []byte, i uint64) int {
    98  	binary.BigEndian.PutUint64(to[off:], i)
    99  	return off + cos.SizeofI64
   100  }
   101  
   102  func insAttrs(off int, to []byte, attr *cmn.ObjAttrs) int {
   103  	off = insInt64(off, to, attr.Size)
   104  	off = insInt64(off, to, attr.Atime)
   105  	if cksum := attr.Checksum(); cksum == nil {
   106  		off = insString(off, to, "")
   107  		off = insString(off, to, "")
   108  	} else {
   109  		off = insString(off, to, cksum.Ty())
   110  		off = insString(off, to, cksum.Val())
   111  	}
   112  	off = insString(off, to, attr.Ver)
   113  	custom := attr.GetCustomMD()
   114  	for k, v := range custom {
   115  		debug.Assert(k != "")
   116  		off = insString(off, to, k)
   117  		off = insString(off, to, v)
   118  	}
   119  	off = insString(off, to, "") // term
   120  	return off
   121  }
   122  
   123  //////////////////////////////////
   124  // proto header deserialization //
   125  //////////////////////////////////
   126  
   127  func extProtoHdr(hbuf []byte, loghdr string) (hlen int, flags uint64, err error) {
   128  	off, word1 := extUint64(0, hbuf)
   129  	hlen = int(word1 & ^allFlags)
   130  	flags = word1 & allFlags
   131  	// validate checksum
   132  	_, checksum := extUint64(0, hbuf[off:])
   133  	chc := xoshiro256.Hash(word1)
   134  	if checksum != chc {
   135  		err = fmt.Errorf("sbrk %s: bad checksum %x != %x (hlen=%d)", loghdr, checksum, chc, hlen)
   136  	}
   137  	return
   138  }
   139  
   140  func ExtObjHeader(body []byte, hlen int) (hdr ObjHdr) {
   141  	var off int
   142  	off, hdr.SID = extString(0, body)
   143  	off, hdr.Opcode = extUint16(off, body)
   144  	off, hdr.Bck.Name = extString(off, body)
   145  	off, hdr.Bck.Provider = extString(off, body)
   146  	off, hdr.Bck.Ns.Name = extString(off, body)
   147  	off, hdr.Bck.Ns.UUID = extString(off, body)
   148  	off, hdr.ObjName = extString(off, body)
   149  	off, hdr.Opaque = extBytes(off, body)
   150  	off, hdr.ObjAttrs = extAttrs(off, body)
   151  	debug.Assertf(off == hlen, "off %d, hlen %d", off, hlen)
   152  	return
   153  }
   154  
   155  func ExtMsg(body []byte, hlen int) (msg Msg) {
   156  	var off int
   157  	off, msg.SID = extString(0, body)
   158  	off, msg.Opcode = extUint16(off, body)
   159  	off, msg.Body = extBytes(off, body)
   160  	debug.Assertf(off == hlen, "off %d, hlen %d", off, hlen)
   161  	return
   162  }
   163  
   164  func extString(off int, from []byte) (int, string) {
   165  	off, bt := extBytes(off, from)
   166  	return off, string(bt)
   167  }
   168  
   169  func extBytes(off int, from []byte) (int, []byte) {
   170  	l := int(binary.BigEndian.Uint16(from[off:]))
   171  	off += cos.SizeofI16
   172  	return off + l, from[off : off+l]
   173  }
   174  
   175  func extUint16(off int, from []byte) (int, int) {
   176  	val := binary.BigEndian.Uint16(from[off:])
   177  	off += cos.SizeofI16
   178  	return off, int(val)
   179  }
   180  
   181  func extInt64(off int, from []byte) (int, int64) {
   182  	off, val := extUint64(off, from)
   183  	return off, int64(val)
   184  }
   185  
   186  func extUint64(off int, from []byte) (int, uint64) {
   187  	val := binary.BigEndian.Uint64(from[off:])
   188  	off += cos.SizeofI64
   189  	return off, val
   190  }
   191  
   192  func extAttrs(off int, from []byte) (n int, attr cmn.ObjAttrs) {
   193  	var cksumTyp, cksumVal, k, v string
   194  	off, attr.Size = extInt64(off, from)
   195  	off, attr.Atime = extInt64(off, from)
   196  	off, cksumTyp = extString(off, from)
   197  	off, cksumVal = extString(off, from)
   198  	attr.SetCksum(cksumTyp, cksumVal)
   199  	off, attr.Ver = extString(off, from)
   200  	for {
   201  		off, k = extString(off, from)
   202  		if k == "" {
   203  			break
   204  		}
   205  		off, v = extString(off, from)
   206  		attr.SetCustomKey(k, v)
   207  	}
   208  	return off, attr
   209  }
   210  
   211  ////////////////////
   212  // Obj and ObjHdr //
   213  ////////////////////
   214  
   215  func (obj *Obj) IsHeaderOnly() bool { return obj.Hdr.IsHeaderOnly() }
   216  func (obj *Obj) IsUnsized() bool    { return obj.Hdr.IsUnsized() }
   217  
   218  func (obj *Obj) Size() int64 { return obj.Hdr.ObjSize() }
   219  
   220  func (obj *Obj) String() string {
   221  	s := "sobj-" + obj.Hdr.Cname()
   222  	if obj.IsHeaderOnly() {
   223  		return s
   224  	}
   225  	return fmt.Sprintf("%s(size=%d)", s, obj.Hdr.ObjAttrs.Size)
   226  }
   227  
   228  func (obj *Obj) SetPrc(n int) {
   229  	obj.prc = atomic.NewInt64(int64(n))
   230  }
   231  
   232  func (hdr *ObjHdr) Cname() string { return hdr.Bck.Cname(hdr.ObjName) } // see also: lom.Cname()
   233  
   234  func (hdr *ObjHdr) IsUnsized() bool    { return hdr.ObjAttrs.Size == SizeUnknown }
   235  func (hdr *ObjHdr) IsHeaderOnly() bool { return hdr.ObjAttrs.Size == 0 }
   236  func (hdr *ObjHdr) ObjSize() int64     { return hdr.ObjAttrs.Size }
   237  
   238  // reserved opcodes
   239  func (hdr *ObjHdr) isFin() bool      { return hdr.Opcode == opcFin }
   240  func (hdr *ObjHdr) isIdleTick() bool { return hdr.Opcode == opcIdleTick }
   241  
   242  ////////////////////
   243  // Msg and MsgHdr //
   244  ////////////////////
   245  
   246  func (*Msg) IsHeaderOnly() bool { return true }
   247  
   248  func (msg *Msg) String() string {
   249  	if msg.isFin() {
   250  		return "smsg-last"
   251  	}
   252  	if msg.isIdleTick() {
   253  		return "smsg-tick"
   254  	}
   255  	l := min(len(msg.Body), 16)
   256  	return fmt.Sprintf("smsg-[%s](len=%d)", msg.Body[:l], l)
   257  }
   258  
   259  // reserved opcodes
   260  func (msg *Msg) isFin() bool      { return msg.Opcode == opcFin }
   261  func (msg *Msg) isIdleTick() bool { return msg.Opcode == opcIdleTick }