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 }