github.com/ethersphere/bee/v2@v2.2.0/pkg/storer/internal/reserve/items.go (about)

     1  // Copyright 2023 The Swarm Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package reserve
     6  
     7  import (
     8  	"encoding/binary"
     9  	"errors"
    10  	"path"
    11  
    12  	"github.com/ethersphere/bee/v2/pkg/storage"
    13  	"github.com/ethersphere/bee/v2/pkg/swarm"
    14  )
    15  
    16  var (
    17  	errMarshalInvalidAddress = errors.New("marshal: invalid address")
    18  	errUnmarshalInvalidSize  = errors.New("unmarshal: invalid size")
    19  )
    20  
    21  // BatchRadiusItem allows iteration of the chunks with respect to bin and batchID.
    22  // Used for batch evictions of certain bins.
    23  type BatchRadiusItem struct {
    24  	Bin       uint8
    25  	BatchID   []byte
    26  	StampHash []byte
    27  	Address   swarm.Address
    28  	BinID     uint64
    29  }
    30  
    31  func (b *BatchRadiusItem) Namespace() string {
    32  	return "batchRadius"
    33  }
    34  
    35  // batchID/bin/ChunkAddr/stampHash
    36  func (b *BatchRadiusItem) ID() string {
    37  	return string(b.BatchID) + string(b.Bin) + b.Address.ByteString() + string(b.StampHash)
    38  }
    39  
    40  func (b *BatchRadiusItem) String() string {
    41  	return path.Join(b.Namespace(), b.ID())
    42  }
    43  
    44  func (b *BatchRadiusItem) Clone() storage.Item {
    45  	if b == nil {
    46  		return nil
    47  	}
    48  	return &BatchRadiusItem{
    49  		Bin:       b.Bin,
    50  		BatchID:   copyBytes(b.BatchID),
    51  		Address:   b.Address.Clone(),
    52  		BinID:     b.BinID,
    53  		StampHash: copyBytes(b.StampHash),
    54  	}
    55  }
    56  
    57  const batchRadiusItemSize = 1 + swarm.HashSize + swarm.HashSize + 8 + swarm.HashSize
    58  
    59  func (b *BatchRadiusItem) Marshal() ([]byte, error) {
    60  
    61  	if b.Address.IsZero() {
    62  		return nil, errMarshalInvalidAddress
    63  	}
    64  
    65  	buf := make([]byte, batchRadiusItemSize)
    66  
    67  	i := 0
    68  
    69  	buf[i] = b.Bin
    70  	i += 1
    71  
    72  	copy(buf[i:i+swarm.HashSize], b.BatchID)
    73  	i += swarm.HashSize
    74  
    75  	copy(buf[i:i+swarm.HashSize], b.Address.Bytes())
    76  	i += swarm.HashSize
    77  
    78  	binary.BigEndian.PutUint64(buf[i:i+8], b.BinID)
    79  	i += 8
    80  
    81  	copy(buf[i:i+swarm.HashSize], b.StampHash)
    82  	return buf, nil
    83  }
    84  
    85  func (b *BatchRadiusItem) Unmarshal(buf []byte) error {
    86  
    87  	if len(buf) != batchRadiusItemSize {
    88  		return errUnmarshalInvalidSize
    89  	}
    90  
    91  	i := 0
    92  	b.Bin = buf[i]
    93  	i += 1
    94  
    95  	b.BatchID = copyBytes(buf[i : i+swarm.HashSize])
    96  	i += swarm.HashSize
    97  
    98  	b.Address = swarm.NewAddress(buf[i : i+swarm.HashSize]).Clone()
    99  	i += swarm.HashSize
   100  
   101  	b.BinID = binary.BigEndian.Uint64(buf[i : i+8])
   102  	i += 8
   103  
   104  	b.StampHash = copyBytes(buf[i : i+swarm.HashSize])
   105  	return nil
   106  }
   107  
   108  // ChunkBinItem allows for iterating on ranges of bin and binIDs for chunks.
   109  // BinIDs come in handy when syncing the reserve contents with other peers.
   110  type ChunkBinItem struct {
   111  	Bin       uint8
   112  	BinID     uint64
   113  	Address   swarm.Address
   114  	BatchID   []byte
   115  	StampHash []byte
   116  	ChunkType swarm.ChunkType
   117  }
   118  
   119  func (c *ChunkBinItem) Namespace() string {
   120  	return "chunkBin"
   121  }
   122  
   123  // bin/binID
   124  func (c *ChunkBinItem) ID() string {
   125  	return binIDToString(c.Bin, c.BinID)
   126  }
   127  
   128  func binIDToString(bin uint8, binID uint64) string {
   129  	binIDBytes := make([]byte, 8)
   130  	binary.BigEndian.PutUint64(binIDBytes, binID)
   131  	return string(bin) + string(binIDBytes)
   132  }
   133  
   134  func (c *ChunkBinItem) String() string {
   135  	return path.Join(c.Namespace(), c.ID())
   136  }
   137  
   138  func (c *ChunkBinItem) Clone() storage.Item {
   139  	if c == nil {
   140  		return nil
   141  	}
   142  	return &ChunkBinItem{
   143  		Bin:       c.Bin,
   144  		BinID:     c.BinID,
   145  		Address:   c.Address.Clone(),
   146  		BatchID:   copyBytes(c.BatchID),
   147  		StampHash: copyBytes(c.StampHash),
   148  		ChunkType: c.ChunkType,
   149  	}
   150  }
   151  
   152  const chunkBinItemSize = 1 + 8 + swarm.HashSize + swarm.HashSize + 1 + swarm.HashSize
   153  
   154  func (c *ChunkBinItem) Marshal() ([]byte, error) {
   155  
   156  	if c.Address.IsZero() {
   157  		return nil, errMarshalInvalidAddress
   158  	}
   159  
   160  	buf := make([]byte, chunkBinItemSize)
   161  	i := 0
   162  
   163  	buf[i] = c.Bin
   164  	i += 1
   165  
   166  	binary.BigEndian.PutUint64(buf[i:i+8], c.BinID)
   167  	i += 8
   168  
   169  	copy(buf[i:i+swarm.HashSize], c.Address.Bytes())
   170  	i += swarm.HashSize
   171  
   172  	copy(buf[i:i+swarm.HashSize], c.BatchID)
   173  	i += swarm.HashSize
   174  
   175  	buf[i] = uint8(c.ChunkType)
   176  	i += 1
   177  
   178  	copy(buf[i:i+swarm.HashSize], c.StampHash)
   179  	return buf, nil
   180  }
   181  
   182  func (c *ChunkBinItem) Unmarshal(buf []byte) error {
   183  
   184  	if len(buf) != chunkBinItemSize {
   185  		return errUnmarshalInvalidSize
   186  	}
   187  
   188  	i := 0
   189  	c.Bin = buf[i]
   190  	i += 1
   191  
   192  	c.BinID = binary.BigEndian.Uint64(buf[i : i+8])
   193  	i += 8
   194  
   195  	c.Address = swarm.NewAddress(buf[i : i+swarm.HashSize]).Clone()
   196  	i += swarm.HashSize
   197  
   198  	c.BatchID = copyBytes(buf[i : i+swarm.HashSize])
   199  	i += swarm.HashSize
   200  
   201  	c.ChunkType = swarm.ChunkType(buf[i])
   202  	i += 1
   203  
   204  	c.StampHash = copyBytes(buf[i : i+swarm.HashSize])
   205  	return nil
   206  }
   207  
   208  // BinItem stores the latest binIDs for each bin between 0 and swarm.MaxBins
   209  type BinItem struct {
   210  	Bin   uint8
   211  	BinID uint64
   212  }
   213  
   214  func (b *BinItem) Namespace() string {
   215  	return "binID"
   216  }
   217  
   218  func (b *BinItem) ID() string {
   219  	return string(b.Bin)
   220  }
   221  
   222  func (c *BinItem) String() string {
   223  	return path.Join(c.Namespace(), c.ID())
   224  }
   225  func (b *BinItem) Clone() storage.Item {
   226  	if b == nil {
   227  		return nil
   228  	}
   229  	return &BinItem{
   230  		Bin:   b.Bin,
   231  		BinID: b.BinID,
   232  	}
   233  }
   234  
   235  const binItemSize = 8
   236  
   237  func (c *BinItem) Marshal() ([]byte, error) {
   238  	buf := make([]byte, binItemSize)
   239  	binary.BigEndian.PutUint64(buf, c.BinID)
   240  	return buf, nil
   241  }
   242  
   243  func (c *BinItem) Unmarshal(buf []byte) error {
   244  	if len(buf) != binItemSize {
   245  		return errUnmarshalInvalidSize
   246  	}
   247  	c.BinID = binary.BigEndian.Uint64(buf)
   248  	return nil
   249  }
   250  
   251  // EpochItem stores the timestamp in seconds of the initial creation of the reserve.
   252  type EpochItem struct {
   253  	Timestamp uint64
   254  }
   255  
   256  func (e *EpochItem) Namespace() string   { return "epochItem" }
   257  func (e *EpochItem) ID() string          { return "" }
   258  func (e *EpochItem) String() string      { return e.Namespace() }
   259  func (e *EpochItem) Clone() storage.Item { return &EpochItem{e.Timestamp} }
   260  
   261  const epochItemSize = 8
   262  
   263  func (e *EpochItem) Marshal() ([]byte, error) {
   264  	buf := make([]byte, epochItemSize)
   265  	binary.BigEndian.PutUint64(buf, e.Timestamp)
   266  	return buf, nil
   267  }
   268  
   269  func (e *EpochItem) Unmarshal(buf []byte) error {
   270  	if len(buf) != epochItemSize {
   271  		return errUnmarshalInvalidSize
   272  	}
   273  	e.Timestamp = binary.BigEndian.Uint64(buf)
   274  	return nil
   275  }
   276  
   277  // radiusItem stores the current storage radius of the reserve.
   278  type radiusItem struct {
   279  	Radius uint8
   280  }
   281  
   282  func (r *radiusItem) Namespace() string {
   283  	return "radius"
   284  }
   285  
   286  func (r *radiusItem) ID() string {
   287  	return ""
   288  }
   289  
   290  func (r *radiusItem) String() string {
   291  	return r.Namespace()
   292  }
   293  
   294  func (r *radiusItem) Clone() storage.Item {
   295  	if r == nil {
   296  		return nil
   297  	}
   298  	return &radiusItem{
   299  		Radius: r.Radius,
   300  	}
   301  }
   302  
   303  func (r *radiusItem) Marshal() ([]byte, error) {
   304  	return []byte{r.Radius}, nil
   305  }
   306  
   307  func (r *radiusItem) Unmarshal(buf []byte) error {
   308  	if len(buf) != 1 {
   309  		return errUnmarshalInvalidSize
   310  	}
   311  	r.Radius = buf[0]
   312  	return nil
   313  }
   314  
   315  func copyBytes(src []byte) []byte {
   316  	if src == nil {
   317  		return nil
   318  	}
   319  	dst := make([]byte, len(src))
   320  	copy(dst, src)
   321  	return dst
   322  }