github.com/ethersphere/bee/v2@v2.2.0/pkg/file/redundancy/level.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 redundancy
     6  
     7  import (
     8  	"context"
     9  	"errors"
    10  	"fmt"
    11  
    12  	"github.com/ethersphere/bee/v2/pkg/swarm"
    13  )
    14  
    15  // Level is the redundancy level
    16  // which carries information about how much redundancy should be added to data to remain retrievable with a 1-10^(-6) certainty
    17  // in different groups of expected chunk retrieval error rates (level values)
    18  type Level uint8
    19  
    20  const (
    21  	// no redundancy will be added
    22  	NONE Level = iota
    23  	// expected 1% chunk retrieval error rate
    24  	MEDIUM
    25  	// expected 5% chunk retrieval error rate
    26  	STRONG
    27  	// expected 10% chunk retrieval error rate
    28  	INSANE
    29  	// expected 50% chunk retrieval error rate
    30  	PARANOID
    31  )
    32  
    33  // GetParities returns number of parities based on appendix F table 5
    34  func (l Level) GetParities(shards int) int {
    35  	et, err := l.getErasureTable()
    36  	if err != nil {
    37  		return 0
    38  	}
    39  	return et.getParities(shards)
    40  }
    41  
    42  // GetMaxShards returns back the maximum number of effective data chunks
    43  func (l Level) GetMaxShards() int {
    44  	p := l.GetParities(swarm.Branches)
    45  	return swarm.Branches - p
    46  }
    47  
    48  // GetEncParities returns number of parities for encrypted chunks based on appendix F table 6
    49  func (l Level) GetEncParities(shards int) int {
    50  	et, err := l.getEncErasureTable()
    51  	if err != nil {
    52  		return 0
    53  	}
    54  	return et.getParities(shards)
    55  }
    56  
    57  func (l Level) getErasureTable() (erasureTable, error) {
    58  	switch l {
    59  	case NONE:
    60  		return erasureTable{}, errors.New("redundancy: level NONE does not have erasure table")
    61  	case MEDIUM:
    62  		return mediumEt, nil
    63  	case STRONG:
    64  		return strongEt, nil
    65  	case INSANE:
    66  		return insaneEt, nil
    67  	case PARANOID:
    68  		return paranoidEt, nil
    69  	default:
    70  		return erasureTable{}, fmt.Errorf("redundancy: level value %d is not a legit redundancy level", l)
    71  	}
    72  }
    73  
    74  func (l Level) getEncErasureTable() (erasureTable, error) {
    75  	switch l {
    76  	case NONE:
    77  		return erasureTable{}, errors.New("redundancy: level NONE does not have erasure table")
    78  	case MEDIUM:
    79  		return encMediumEt, nil
    80  	case STRONG:
    81  		return encStrongEt, nil
    82  	case INSANE:
    83  		return encInsaneEt, nil
    84  	case PARANOID:
    85  		return encParanoidEt, nil
    86  	default:
    87  		return erasureTable{}, fmt.Errorf("redundancy: level value %d is not a legit redundancy level", l)
    88  	}
    89  }
    90  
    91  // GetMaxEncShards returns back the maximum number of effective encrypted data chunks
    92  func (l Level) GetMaxEncShards() int {
    93  	p := l.GetEncParities(swarm.EncryptedBranches)
    94  	return (swarm.Branches - p) / 2
    95  }
    96  
    97  // GetReplicaCount returns back the dispersed replica number
    98  func (l Level) GetReplicaCount() int {
    99  	return replicaCounts[int(l)]
   100  }
   101  
   102  // Decrement returns a weaker redundancy level compare to the current one
   103  func (l Level) Decrement() Level {
   104  	return Level(uint8(l) - 1)
   105  }
   106  
   107  // TABLE INITS
   108  
   109  var mediumEt = newErasureTable(
   110  	[]int{95, 69, 47, 29, 15, 6, 2, 1},
   111  	[]int{9, 8, 7, 6, 5, 4, 3, 2},
   112  )
   113  var encMediumEt = newErasureTable(
   114  	[]int{47, 34, 23, 14, 7, 3, 1},
   115  	[]int{9, 8, 7, 6, 5, 4, 3},
   116  )
   117  
   118  var strongEt = newErasureTable(
   119  	[]int{105, 96, 87, 78, 70, 62, 54, 47, 40, 33, 27, 21, 16, 11, 7, 4, 2, 1},
   120  	[]int{21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4},
   121  )
   122  var encStrongEt = newErasureTable(
   123  	[]int{52, 48, 43, 39, 35, 31, 27, 23, 20, 16, 13, 10, 8, 5, 3, 2, 1},
   124  	[]int{21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5},
   125  )
   126  
   127  var insaneEt = newErasureTable(
   128  	[]int{93, 88, 83, 78, 74, 69, 64, 60, 55, 51, 46, 42, 38, 34, 30, 27, 23, 20, 17, 14, 11, 9, 6, 4, 3, 2, 1},
   129  	[]int{31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5},
   130  )
   131  var encInsaneEt = newErasureTable(
   132  	[]int{46, 44, 41, 39, 37, 34, 32, 30, 27, 25, 23, 21, 19, 17, 15, 13, 11, 10, 8, 7, 5, 4, 3, 2, 1},
   133  	[]int{31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 6},
   134  )
   135  
   136  var paranoidEt = newErasureTable(
   137  	[]int{
   138  		37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18,
   139  		17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1,
   140  	},
   141  	[]int{
   142  		89, 87, 86, 84, 83, 81, 80, 78, 76, 75, 73, 71, 70, 68, 66, 65, 63, 61, 59, 58,
   143  		56, 54, 52, 50, 48, 47, 45, 43, 40, 38, 36, 34, 31, 29, 26, 23, 19,
   144  	},
   145  )
   146  var encParanoidEt = newErasureTable(
   147  	[]int{
   148  		18, 17, 16, 15, 14, 13, 12, 11, 10, 9,
   149  		8, 7, 6, 5, 4, 3, 2, 1,
   150  	},
   151  	[]int{
   152  		87, 84, 81, 78, 75, 71, 68, 65, 61, 58,
   153  		54, 50, 47, 43, 38, 34, 29, 23,
   154  	},
   155  )
   156  
   157  // GetReplicaCounts returns back the ascending dispersed replica counts for all redundancy levels
   158  func GetReplicaCounts() [5]int {
   159  	c := replicaCounts
   160  	return c
   161  }
   162  
   163  // the actual number of replicas needed to keep the error rate below 1/10^6
   164  // for the five levels of redundancy are 0, 2, 4, 5, 19
   165  // we use an approximation as the successive powers of 2
   166  var replicaCounts = [5]int{0, 2, 4, 8, 16}
   167  
   168  type levelKey struct{}
   169  
   170  // SetLevelInContext sets the redundancy level in the context
   171  func SetLevelInContext(ctx context.Context, level Level) context.Context {
   172  	return context.WithValue(ctx, levelKey{}, level)
   173  }
   174  
   175  // GetLevelFromContext is a helper function to extract the redundancy level from the context
   176  func GetLevelFromContext(ctx context.Context) Level {
   177  	rlevel := PARANOID
   178  	if val := ctx.Value(levelKey{}); val != nil {
   179  		rlevel = val.(Level)
   180  	}
   181  	return rlevel
   182  }