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  }