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 }