github.com/ethersphere/bee/v2@v2.2.0/pkg/manifest/mantaray/node.go (about) 1 // Copyright 2020 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 mantaray 6 7 import ( 8 "bytes" 9 "context" 10 "errors" 11 "fmt" 12 ) 13 14 const ( 15 PathSeparator = '/' // path separator 16 ) 17 18 var ( 19 ZeroObfuscationKey = make([]byte, 32) 20 ) 21 22 // Error used when lookup path does not match 23 var ( 24 ErrNotFound = errors.New("not found") 25 ErrEmptyPath = errors.New("empty path") 26 ErrMetadataTooLarge = errors.New("metadata too large") 27 ) 28 29 // Node represents a mantaray Node 30 type Node struct { 31 nodeType uint8 32 refBytesSize int 33 obfuscationKey []byte 34 ref []byte // reference to uninstantiated Node persisted serialised 35 entry []byte 36 metadata map[string]string 37 forks map[byte]*fork 38 } 39 40 type fork struct { 41 prefix []byte // the non-branching part of the subpath 42 *Node // in memory structure that represents the Node 43 } 44 45 const ( 46 nodeTypeValue = uint8(2) 47 nodeTypeEdge = uint8(4) 48 nodeTypeWithPathSeparator = uint8(8) 49 nodeTypeWithMetadata = uint8(16) 50 51 nodeTypeMask = uint8(255) 52 ) 53 54 func nodeTypeIsWithMetadataType(nodeType uint8) bool { 55 return nodeType&nodeTypeWithMetadata == nodeTypeWithMetadata 56 } 57 58 // NewNodeRef is the exported Node constructor used to represent manifests by reference 59 func NewNodeRef(ref []byte) *Node { 60 return &Node{ref: ref} 61 } 62 63 // New is the constructor for in-memory Node structure 64 func New() *Node { 65 return &Node{forks: make(map[byte]*fork)} 66 } 67 68 func notFound(path []byte) error { 69 return fmt.Errorf("entry on '%s' ('%x'): %w", path, path, ErrNotFound) 70 } 71 72 // IsValueType returns true if the node contains entry. 73 func (n *Node) IsValueType() bool { 74 return n.nodeType&nodeTypeValue == nodeTypeValue 75 } 76 77 // IsEdgeType returns true if the node forks into other nodes. 78 func (n *Node) IsEdgeType() bool { 79 return n.nodeType&nodeTypeEdge == nodeTypeEdge 80 } 81 82 // IsWithPathSeparatorType returns true if the node path contains separator character. 83 func (n *Node) IsWithPathSeparatorType() bool { 84 return n.nodeType&nodeTypeWithPathSeparator == nodeTypeWithPathSeparator 85 } 86 87 // IsWithMetadataType returns true if the node contains metadata. 88 func (n *Node) IsWithMetadataType() bool { 89 return n.nodeType&nodeTypeWithMetadata == nodeTypeWithMetadata 90 } 91 92 func (n *Node) makeValue() { 93 n.nodeType = n.nodeType | nodeTypeValue 94 } 95 96 func (n *Node) makeEdge() { 97 n.nodeType = n.nodeType | nodeTypeEdge 98 } 99 100 func (n *Node) makeWithPathSeparator() { 101 n.nodeType = n.nodeType | nodeTypeWithPathSeparator 102 } 103 104 func (n *Node) makeWithMetadata() { 105 n.nodeType = n.nodeType | nodeTypeWithMetadata 106 } 107 108 //nolint:unused 109 func (n *Node) makeNotValue() { 110 n.nodeType = (nodeTypeMask ^ nodeTypeValue) & n.nodeType 111 } 112 113 //nolint:unused 114 func (n *Node) makeNotEdge() { 115 n.nodeType = (nodeTypeMask ^ nodeTypeEdge) & n.nodeType 116 } 117 118 func (n *Node) makeNotWithPathSeparator() { 119 n.nodeType = (nodeTypeMask ^ nodeTypeWithPathSeparator) & n.nodeType 120 } 121 122 //nolint:unused 123 func (n *Node) makeNotWithMetadata() { 124 n.nodeType = (nodeTypeMask ^ nodeTypeWithMetadata) & n.nodeType 125 } 126 127 func (n *Node) SetObfuscationKey(obfuscationKey []byte) { 128 bytes := make([]byte, 32) 129 copy(bytes, obfuscationKey) 130 n.obfuscationKey = bytes 131 } 132 133 // Reference returns the address of the mantaray node if saved. 134 func (n *Node) Reference() []byte { 135 return n.ref 136 } 137 138 // Entry returns the value stored on the specific path. 139 func (n *Node) Entry() []byte { 140 return n.entry 141 } 142 143 // Metadata returns the metadata stored on the specific path. 144 func (n *Node) Metadata() map[string]string { 145 return n.metadata 146 } 147 148 // LookupNode finds the node for a path or returns error if not found 149 func (n *Node) LookupNode(ctx context.Context, path []byte, l Loader) (*Node, error) { 150 select { 151 case <-ctx.Done(): 152 return nil, ctx.Err() 153 default: 154 } 155 if n.forks == nil { 156 if err := n.load(ctx, l); err != nil { 157 return nil, err 158 } 159 } 160 if len(path) == 0 { 161 return n, nil 162 } 163 f := n.forks[path[0]] 164 if f == nil { 165 return nil, notFound(path) 166 } 167 c := common(f.prefix, path) 168 if len(c) == len(f.prefix) { 169 return f.Node.LookupNode(ctx, path[len(c):], l) 170 } 171 return nil, notFound(path) 172 } 173 174 // Lookup finds the entry for a path or returns error if not found 175 func (n *Node) Lookup(ctx context.Context, path []byte, l Loader) ([]byte, error) { 176 node, err := n.LookupNode(ctx, path, l) 177 if err != nil { 178 return nil, err 179 } 180 if !node.IsValueType() && len(path) > 0 { 181 return nil, notFound(path) 182 } 183 return node.entry, nil 184 } 185 186 // Add adds an entry to the path 187 func (n *Node) Add(ctx context.Context, path, entry []byte, metadata map[string]string, ls LoadSaver) error { 188 select { 189 case <-ctx.Done(): 190 return ctx.Err() 191 default: 192 } 193 if n.refBytesSize == 0 { 194 if len(entry) > 256 { 195 return fmt.Errorf("node entry size > 256: %d", len(entry)) 196 } 197 // empty entry for directories 198 if len(entry) > 0 { 199 n.refBytesSize = len(entry) 200 } 201 } else if len(entry) > 0 && n.refBytesSize != len(entry) { 202 return fmt.Errorf("invalid entry size: %d, expected: %d", len(entry), n.refBytesSize) 203 } 204 205 if len(path) == 0 { 206 n.entry = entry 207 n.makeValue() 208 if len(metadata) > 0 { 209 n.metadata = metadata 210 n.makeWithMetadata() 211 } 212 n.ref = nil 213 return nil 214 } 215 if n.forks == nil { 216 if err := n.load(ctx, ls); err != nil { 217 return err 218 } 219 n.ref = nil 220 } 221 f := n.forks[path[0]] 222 if f == nil { 223 nn := New() 224 if len(n.obfuscationKey) > 0 { 225 nn.SetObfuscationKey(n.obfuscationKey) 226 } 227 nn.refBytesSize = n.refBytesSize 228 // check for prefix size limit 229 if len(path) > nodePrefixMaxSize { 230 prefix := path[:nodePrefixMaxSize] 231 rest := path[nodePrefixMaxSize:] 232 err := nn.Add(ctx, rest, entry, metadata, ls) 233 if err != nil { 234 return err 235 } 236 nn.updateIsWithPathSeparator(prefix) 237 n.forks[path[0]] = &fork{prefix, nn} 238 n.makeEdge() 239 return nil 240 } 241 nn.entry = entry 242 if len(metadata) > 0 { 243 nn.metadata = metadata 244 nn.makeWithMetadata() 245 } 246 nn.makeValue() 247 nn.updateIsWithPathSeparator(path) 248 n.forks[path[0]] = &fork{path, nn} 249 n.makeEdge() 250 return nil 251 } 252 c := common(f.prefix, path) 253 rest := f.prefix[len(c):] 254 nn := f.Node 255 if len(rest) > 0 { 256 // move current common prefix node 257 nn = New() 258 if len(n.obfuscationKey) > 0 { 259 nn.SetObfuscationKey(n.obfuscationKey) 260 } 261 nn.refBytesSize = n.refBytesSize 262 f.Node.updateIsWithPathSeparator(rest) 263 nn.forks[rest[0]] = &fork{rest, f.Node} 264 nn.makeEdge() 265 // if common path is full path new node is value type 266 if len(path) == len(c) { 267 nn.makeValue() 268 } 269 } 270 // NOTE: special case on edge split 271 nn.updateIsWithPathSeparator(path) 272 // add new for shared prefix 273 err := nn.Add(ctx, path[len(c):], entry, metadata, ls) 274 if err != nil { 275 return err 276 } 277 n.forks[path[0]] = &fork{c, nn} 278 n.makeEdge() 279 return nil 280 } 281 282 func (n *Node) updateIsWithPathSeparator(path []byte) { 283 if bytes.IndexRune(path, PathSeparator) > 0 { 284 n.makeWithPathSeparator() 285 } else { 286 n.makeNotWithPathSeparator() 287 } 288 } 289 290 // Remove removes a path from the node 291 func (n *Node) Remove(ctx context.Context, path []byte, ls LoadSaver) error { 292 select { 293 case <-ctx.Done(): 294 return ctx.Err() 295 default: 296 } 297 if len(path) == 0 { 298 return ErrEmptyPath 299 } 300 if n.forks == nil { 301 if err := n.load(ctx, ls); err != nil { 302 return err 303 } 304 } 305 f := n.forks[path[0]] 306 if f == nil { 307 return ErrNotFound 308 } 309 prefixIndex := bytes.Index(path, f.prefix) 310 if prefixIndex != 0 { 311 return ErrNotFound 312 } 313 rest := path[len(f.prefix):] 314 if len(rest) == 0 { 315 // full path matched 316 delete(n.forks, path[0]) 317 return nil 318 } 319 return f.Node.Remove(ctx, rest, ls) 320 } 321 322 func common(a, b []byte) (c []byte) { 323 for i := 0; i < len(a) && i < len(b) && a[i] == b[i]; i++ { 324 c = append(c, a[i]) 325 } 326 return c 327 } 328 329 // HasPrefix tests whether the node contains prefix path. 330 func (n *Node) HasPrefix(ctx context.Context, path []byte, l Loader) (bool, error) { 331 select { 332 case <-ctx.Done(): 333 return false, ctx.Err() 334 default: 335 } 336 if n.forks == nil { 337 if err := n.load(ctx, l); err != nil { 338 return false, err 339 } 340 } 341 if len(path) == 0 { 342 return true, nil 343 } 344 f := n.forks[path[0]] 345 if f == nil { 346 return false, nil 347 } 348 c := common(f.prefix, path) 349 if len(c) == len(f.prefix) { 350 return f.Node.HasPrefix(ctx, path[len(c):], l) 351 } 352 if bytes.HasPrefix(f.prefix, path) { 353 return true, nil 354 } 355 return false, nil 356 }