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  }