github.com/NVIDIA/aistore@v1.3.23-0.20240517131212-7df6609be51d/reb/packed_struct.go (about) 1 // Package reb provides global cluster-wide rebalance upon adding/removing storage nodes. 2 /* 3 * Copyright (c) 2018-2023, NVIDIA CORPORATION. All rights reserved. 4 */ 5 package reb 6 7 import ( 8 "fmt" 9 10 "github.com/NVIDIA/aistore/cmn/cos" 11 "github.com/NVIDIA/aistore/ec" 12 ) 13 14 // Rebalance message types (for ACK or sending files) 15 const ( 16 rebMsgRegular = iota // regular rebalance: acknowledge/Object 17 rebMsgEC // EC rebalance: acknowledge/CT/Namespace 18 rebMsgStageNtfn // stage notification (of target transitioning to the next stage) 19 ) 20 const rebMsgKindSize = 1 21 const ( 22 rebActRebCT = iota // a CT moved to a correct target (regular rebalance) 23 rebActMoveCT // a CT moved from a target after slice conflict (a target received a CT and it had another CT) 24 rebActUpdateMD // a new MD to update existing local one 25 ) 26 27 type ( 28 regularAck struct { 29 daemonID string // sender's DaemonID 30 rebID int64 31 } 32 ecAck struct { 33 daemonID string // sender's DaemonID 34 rebID int64 35 sliceID uint16 36 } 37 38 // stage notification struct - a target sends it when it enters `stage` 39 stageNtfn struct { 40 md *ec.Metadata 41 daemonID string // sender's ID 42 rebID int64 // sender's rebalance ID 43 stage uint32 // stage the sender has just reached 44 action uint32 // see rebAct* constants 45 } 46 ) 47 48 // interface guard 49 var ( 50 _ cos.Unpacker = (*regularAck)(nil) 51 _ cos.Unpacker = (*ecAck)(nil) 52 _ cos.Packer = (*regularAck)(nil) 53 _ cos.Packer = (*ecAck)(nil) 54 _ cos.Packer = (*stageNtfn)(nil) 55 _ cos.Unpacker = (*stageNtfn)(nil) 56 ) 57 58 func (rack *regularAck) Unpack(unpacker *cos.ByteUnpack) (err error) { 59 if rack.rebID, err = unpacker.ReadInt64(); err != nil { 60 return 61 } 62 rack.daemonID, err = unpacker.ReadString() 63 return 64 } 65 66 func (rack *regularAck) Pack(packer *cos.BytePack) { 67 packer.WriteInt64(rack.rebID) 68 packer.WriteString(rack.daemonID) 69 } 70 71 func (rack *regularAck) NewPack() []byte { // TODO: consider adding as another cos.Packer interface 72 l := rebMsgKindSize + rack.PackedSize() 73 packer := cos.NewPacker(nil, l) 74 packer.WriteByte(rebMsgRegular) 75 packer.WriteAny(rack) 76 return packer.Bytes() 77 } 78 79 // rebID + length of DaemonID + Daemon 80 func (rack *regularAck) PackedSize() int { 81 return cos.SizeofI64 + cos.SizeofLen + len(rack.daemonID) 82 } 83 84 func (eack *ecAck) Unpack(unpacker *cos.ByteUnpack) (err error) { 85 if eack.rebID, err = unpacker.ReadInt64(); err != nil { 86 return 87 } 88 if eack.sliceID, err = unpacker.ReadUint16(); err != nil { 89 return 90 } 91 eack.daemonID, err = unpacker.ReadString() 92 return 93 } 94 95 func (eack *ecAck) Pack(packer *cos.BytePack) { 96 packer.WriteInt64(eack.rebID) 97 packer.WriteUint16(eack.sliceID) 98 packer.WriteString(eack.daemonID) 99 } 100 101 func (eack *ecAck) NewPack() []byte { 102 l := rebMsgKindSize + eack.PackedSize() 103 packer := cos.NewPacker(nil, l) 104 packer.WriteByte(rebMsgEC) 105 packer.WriteAny(eack) 106 return packer.Bytes() 107 } 108 109 func (eack *ecAck) PackedSize() int { 110 return cos.SizeofI64 + cos.SizeofI16 + cos.PackedStrLen(eack.daemonID) 111 } 112 113 func (ntfn *stageNtfn) PackedSize() int { 114 total := cos.SizeofI64 + cos.SizeofI32*2 + 115 cos.PackedStrLen(ntfn.daemonID) + 1 116 if ntfn.md != nil { 117 total += ntfn.md.PackedSize() 118 } 119 return total 120 } 121 122 func (ntfn *stageNtfn) Pack(packer *cos.BytePack) { 123 packer.WriteInt64(ntfn.rebID) 124 packer.WriteUint32(ntfn.action) 125 packer.WriteUint32(ntfn.stage) 126 packer.WriteString(ntfn.daemonID) 127 if ntfn.md == nil { 128 packer.WriteByte(0) 129 } else { 130 packer.WriteByte(1) 131 packer.WriteAny(ntfn.md) 132 } 133 } 134 135 func (ntfn *stageNtfn) NewPack(kind byte) []byte { 136 l := rebMsgKindSize + ntfn.PackedSize() 137 packer := cos.NewPacker(nil, l) 138 packer.WriteByte(kind) 139 packer.WriteAny(ntfn) 140 return packer.Bytes() 141 } 142 143 func (ntfn *stageNtfn) Unpack(unpacker *cos.ByteUnpack) (err error) { 144 if ntfn.rebID, err = unpacker.ReadInt64(); err != nil { 145 return 146 } 147 if ntfn.action, err = unpacker.ReadUint32(); err != nil { 148 return 149 } 150 if ntfn.stage, err = unpacker.ReadUint32(); err != nil { 151 return 152 } 153 if ntfn.daemonID, err = unpacker.ReadString(); err != nil { 154 return 155 } 156 157 var marker byte 158 if marker, err = unpacker.ReadByte(); err != nil { 159 return 160 } 161 if marker == 0 { 162 ntfn.md = nil 163 return 164 } 165 ntfn.md = ec.NewMetadata() 166 return unpacker.ReadAny(ntfn.md) 167 } 168 169 func (*Reb) encodeStageNtfn(ntfn *stageNtfn) []byte { 170 return ntfn.NewPack(rebMsgStageNtfn) 171 } 172 173 func (*Reb) decodeStageNtfn(buf []byte) (*stageNtfn, error) { 174 var ( 175 ntfn = &stageNtfn{} 176 unpacker = cos.NewUnpacker(buf) 177 act, err = unpacker.ReadByte() 178 ) 179 if err != nil { 180 return nil, err 181 } 182 // at the moment, there is only one kind of stage notifications (see above) 183 if act != rebMsgStageNtfn { 184 return nil, fmt.Errorf("expected %d (stage notification), got %d", rebMsgStageNtfn, act) 185 } 186 err = unpacker.ReadAny(ntfn) 187 return ntfn, err 188 }