github.com/treeverse/lakefs@v1.24.1-0.20240520134607-95648127bfb0/pkg/graveler/committed/manager.go (about)

     1  package committed
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"errors"
     7  	"fmt"
     8  	"sort"
     9  
    10  	"github.com/treeverse/lakefs/pkg/graveler"
    11  	"github.com/treeverse/lakefs/pkg/logging"
    12  )
    13  
    14  type committedManager struct {
    15  	metaRangeManager MetaRangeManager
    16  	RangeManager     RangeManager
    17  	params           *Params
    18  }
    19  
    20  func NewCommittedManager(m MetaRangeManager, r RangeManager, p Params) graveler.CommittedManager {
    21  	return &committedManager{
    22  		metaRangeManager: m,
    23  		RangeManager:     r,
    24  		params:           &p,
    25  	}
    26  }
    27  
    28  func (c *committedManager) Exists(ctx context.Context, ns graveler.StorageNamespace, id graveler.MetaRangeID) (bool, error) {
    29  	return c.metaRangeManager.Exists(ctx, ns, id)
    30  }
    31  
    32  func (c *committedManager) Get(ctx context.Context, ns graveler.StorageNamespace, rangeID graveler.MetaRangeID, key graveler.Key) (*graveler.Value, error) {
    33  	it, err := c.metaRangeManager.NewMetaRangeIterator(ctx, ns, rangeID)
    34  	if err != nil {
    35  		return nil, err
    36  	}
    37  	valIt := NewValueIterator(it)
    38  	defer valIt.Close()
    39  	valIt.SeekGE(key)
    40  	// return the next value
    41  	if !valIt.Next() {
    42  		// error or not found
    43  		if err := valIt.Err(); err != nil {
    44  			return nil, err
    45  		}
    46  		return nil, graveler.ErrNotFound
    47  	}
    48  	// compare the key we found
    49  	rec := valIt.Value()
    50  	if !bytes.Equal(rec.Key, key) {
    51  		return nil, graveler.ErrNotFound
    52  	}
    53  	return rec.Value, nil
    54  }
    55  
    56  func (c *committedManager) List(ctx context.Context, ns graveler.StorageNamespace, rangeID graveler.MetaRangeID) (graveler.ValueIterator, error) {
    57  	it, err := c.metaRangeManager.NewMetaRangeIterator(ctx, ns, rangeID)
    58  	if err != nil {
    59  		return nil, err
    60  	}
    61  	return NewValueIterator(it), nil
    62  }
    63  
    64  func (c *committedManager) WriteRange(ctx context.Context, ns graveler.StorageNamespace, it graveler.ValueIterator) (*graveler.RangeInfo, error) {
    65  	writer, err := c.RangeManager.GetWriter(ctx, Namespace(ns), nil)
    66  	if err != nil {
    67  		return nil, fmt.Errorf("failed creating range writer: %w", err)
    68  	}
    69  	writer.SetMetadata(MetadataTypeKey, MetadataRangesType)
    70  
    71  	defer func() {
    72  		if err := writer.Abort(); err != nil {
    73  			logging.FromContext(ctx).WithError(err).Error("Aborting write to range")
    74  		}
    75  	}()
    76  
    77  	for it.Next() {
    78  		record := it.Value()
    79  		// skip nil value (kv can hold value nil) and tombstones
    80  		if record == nil || record.Value == nil {
    81  			continue
    82  		}
    83  		v, err := MarshalValue(record.Value)
    84  		if err != nil {
    85  			return nil, err
    86  		}
    87  
    88  		if err := writer.WriteRecord(Record{Key: Key(record.Key), Value: v}); err != nil {
    89  			return nil, fmt.Errorf("writing record: %w", err)
    90  		}
    91  		if writer.ShouldBreakAtKey(record.Key, c.params) {
    92  			break
    93  		}
    94  	}
    95  	if err := it.Err(); err != nil {
    96  		return nil, fmt.Errorf("getting value from iterator: %w", err)
    97  	}
    98  
    99  	info, err := writer.Close()
   100  	if err != nil {
   101  		return nil, fmt.Errorf("closing writer: %w", err)
   102  	}
   103  
   104  	return &graveler.RangeInfo{
   105  		ID:                      graveler.RangeID(info.RangeID),
   106  		MinKey:                  graveler.Key(info.First),
   107  		MaxKey:                  graveler.Key(info.Last),
   108  		Count:                   info.Count,
   109  		EstimatedRangeSizeBytes: info.EstimatedRangeSizeBytes,
   110  	}, nil
   111  }
   112  
   113  func (c *committedManager) WriteMetaRange(ctx context.Context, ns graveler.StorageNamespace, ranges []*graveler.RangeInfo) (*graveler.MetaRangeInfo, error) {
   114  	writer := c.metaRangeManager.NewWriter(ctx, ns, nil)
   115  	defer func() {
   116  		if err := writer.Abort(); err != nil {
   117  			logging.FromContext(ctx).WithError(err).Error("Aborting write to meta range")
   118  		}
   119  	}()
   120  
   121  	sort.Slice(ranges, func(i, j int) bool {
   122  		return bytes.Compare(ranges[i].MinKey, ranges[j].MinKey) < 0
   123  	})
   124  
   125  	for _, r := range ranges {
   126  		if err := writer.WriteRange(Range{
   127  			ID:            ID(r.ID),
   128  			MinKey:        Key(r.MinKey),
   129  			MaxKey:        Key(r.MaxKey),
   130  			EstimatedSize: r.EstimatedRangeSizeBytes,
   131  			Count:         int64(r.Count),
   132  			Tombstone:     false,
   133  		}); err != nil {
   134  			logging.FromContext(ctx).WithError(err).Error("Aborting writing range to meta range")
   135  			return nil, fmt.Errorf("writing range: %w", err)
   136  		}
   137  	}
   138  
   139  	id, err := writer.Close(ctx)
   140  	if err != nil {
   141  		return nil, fmt.Errorf("closing metarange: %w", err)
   142  	}
   143  
   144  	return &graveler.MetaRangeInfo{
   145  		ID: *id,
   146  	}, nil
   147  }
   148  
   149  func (c *committedManager) WriteMetaRangeByIterator(ctx context.Context, ns graveler.StorageNamespace, it graveler.ValueIterator, metadata graveler.Metadata) (*graveler.MetaRangeID, error) {
   150  	writer := c.metaRangeManager.NewWriter(ctx, ns, metadata)
   151  	defer func() {
   152  		if err := writer.Abort(); err != nil {
   153  			logging.FromContext(ctx).WithError(err).Error("Aborting write to meta range")
   154  		}
   155  	}()
   156  
   157  	for it.Next() {
   158  		if err := writer.WriteRecord(*it.Value()); err != nil {
   159  			return nil, fmt.Errorf("writing record: %w", err)
   160  		}
   161  	}
   162  	if err := it.Err(); err != nil {
   163  		return nil, fmt.Errorf("getting value from iterator: %w", err)
   164  	}
   165  	id, err := writer.Close(ctx)
   166  	if err != nil {
   167  		return nil, fmt.Errorf("closing writer: %w", err)
   168  	}
   169  
   170  	return id, nil
   171  }
   172  
   173  func (c *committedManager) Diff(ctx context.Context, ns graveler.StorageNamespace, left, right graveler.MetaRangeID) (graveler.DiffIterator, error) {
   174  	leftIt, err := c.metaRangeManager.NewMetaRangeIterator(ctx, ns, left)
   175  	if err != nil {
   176  		return nil, err
   177  	}
   178  	rightIt, err := c.metaRangeManager.NewMetaRangeIterator(ctx, ns, right)
   179  	if err != nil {
   180  		return nil, err
   181  	}
   182  	return NewDiffValueIterator(ctx, leftIt, rightIt), nil
   183  }
   184  
   185  func (c *committedManager) Import(ctx context.Context, ns graveler.StorageNamespace, destination, source graveler.MetaRangeID, prefixes []graveler.Prefix, _ ...graveler.SetOptionsFunc) (graveler.MetaRangeID, error) {
   186  	destIt, err := c.metaRangeManager.NewMetaRangeIterator(ctx, ns, destination)
   187  	if err != nil {
   188  		return "", fmt.Errorf("get destination iterator: %w", err)
   189  	}
   190  	destIt = NewSkipPrefixIterator(prefixes, destIt)
   191  	defer destIt.Close()
   192  	mctx := mergeContext{
   193  		destIt:        destIt,
   194  		strategy:      graveler.MergeStrategyNone,
   195  		ns:            ns,
   196  		destinationID: destination,
   197  		sourceID:      source,
   198  		baseID:        "",
   199  	}
   200  	return c.merge(ctx, mctx)
   201  }
   202  
   203  func (c *committedManager) Merge(ctx context.Context, ns graveler.StorageNamespace, destination, source, base graveler.MetaRangeID, strategy graveler.MergeStrategy, _ ...graveler.SetOptionsFunc) (graveler.MetaRangeID, error) {
   204  	if source == base {
   205  		// no changes on source
   206  		return "", graveler.ErrNoChanges
   207  	}
   208  	if destination == base {
   209  		// changes introduced only on source
   210  		return source, nil
   211  	}
   212  	mctx := mergeContext{
   213  		strategy:      strategy,
   214  		ns:            ns,
   215  		destinationID: destination,
   216  		sourceID:      source,
   217  		baseID:        base,
   218  	}
   219  	return c.merge(ctx, mctx)
   220  }
   221  
   222  type mergeContext struct {
   223  	destIt        Iterator
   224  	srcIt         Iterator
   225  	baseIt        Iterator
   226  	strategy      graveler.MergeStrategy
   227  	ns            graveler.StorageNamespace
   228  	destinationID graveler.MetaRangeID
   229  	sourceID      graveler.MetaRangeID
   230  	baseID        graveler.MetaRangeID
   231  }
   232  
   233  func (c *committedManager) merge(ctx context.Context, mctx mergeContext) (graveler.MetaRangeID, error) {
   234  	var err error = nil
   235  	baseIt := mctx.baseIt
   236  	if baseIt == nil {
   237  		baseIt, err = c.metaRangeManager.NewMetaRangeIterator(ctx, mctx.ns, mctx.baseID)
   238  		if err != nil {
   239  			return "", fmt.Errorf("get base iterator: %w", err)
   240  		}
   241  		defer baseIt.Close()
   242  	}
   243  
   244  	destIt := mctx.destIt
   245  	if destIt == nil {
   246  		destIt, err = c.metaRangeManager.NewMetaRangeIterator(ctx, mctx.ns, mctx.destinationID)
   247  		if err != nil {
   248  			return "", fmt.Errorf("get destination iterator: %w", err)
   249  		}
   250  		defer destIt.Close()
   251  	}
   252  
   253  	srcIt := mctx.srcIt
   254  	if srcIt == nil {
   255  		srcIt, err = c.metaRangeManager.NewMetaRangeIterator(ctx, mctx.ns, mctx.sourceID)
   256  		if err != nil {
   257  			return "", fmt.Errorf("get source iterator: %w", err)
   258  		}
   259  		defer srcIt.Close()
   260  	}
   261  
   262  	mwWriter := c.metaRangeManager.NewWriter(ctx, mctx.ns, nil)
   263  	defer func() {
   264  		err = mwWriter.Abort()
   265  		if err != nil {
   266  			logging.FromContext(ctx).WithError(err).Error("Abort failed after Merge")
   267  		}
   268  	}()
   269  
   270  	err = Merge(ctx, mwWriter, baseIt, srcIt, destIt, mctx.strategy)
   271  	if err != nil {
   272  		if !errors.Is(err, graveler.ErrUserVisible) {
   273  			err = fmt.Errorf("merge ns=%s id=%s: %w", mctx.ns, mctx.destinationID, err)
   274  		}
   275  		return "", err
   276  	}
   277  	newID, err := mwWriter.Close(ctx)
   278  	if newID == nil {
   279  		return "", fmt.Errorf("close writer ns=%s id=%s: %w", mctx.ns, mctx.destinationID, err)
   280  	}
   281  	return *newID, err
   282  }
   283  
   284  func (c *committedManager) Commit(ctx context.Context, ns graveler.StorageNamespace, baseMetaRangeID graveler.MetaRangeID, changes graveler.ValueIterator, allowEmpty bool, _ ...graveler.SetOptionsFunc) (graveler.MetaRangeID, graveler.DiffSummary, error) {
   285  	mwWriter := c.metaRangeManager.NewWriter(ctx, ns, nil)
   286  	defer func() {
   287  		err := mwWriter.Abort()
   288  		if err != nil {
   289  			logging.FromContext(ctx).WithError(err).Error("Abort failed after Commit")
   290  		}
   291  	}()
   292  	metaRangeIterator, err := c.metaRangeManager.NewMetaRangeIterator(ctx, ns, baseMetaRangeID)
   293  	summary := graveler.DiffSummary{
   294  		Count: map[graveler.DiffType]int{},
   295  	}
   296  	if err != nil {
   297  		return "", summary, fmt.Errorf("get metarange ns=%s id=%s: %w", ns, baseMetaRangeID, err)
   298  	}
   299  	defer metaRangeIterator.Close()
   300  	summary, err = Commit(ctx, mwWriter, metaRangeIterator, changes, &CommitOptions{AllowEmpty: allowEmpty})
   301  	if err != nil {
   302  		if !errors.Is(err, graveler.ErrUserVisible) {
   303  			err = fmt.Errorf("commit ns=%s id=%s: %w", ns, baseMetaRangeID, err)
   304  		}
   305  		return "", summary, err
   306  	}
   307  	newID, err := mwWriter.Close(ctx)
   308  	if newID == nil {
   309  		return "", summary, fmt.Errorf("close writer ns=%s metarange id=%s: %w", ns, baseMetaRangeID, err)
   310  	}
   311  	return *newID, summary, err
   312  }
   313  
   314  func (c *committedManager) Compare(ctx context.Context, ns graveler.StorageNamespace, destination, source, base graveler.MetaRangeID) (graveler.DiffIterator, error) {
   315  	diffIt, err := c.Diff(ctx, ns, destination, source)
   316  	if err != nil {
   317  		return nil, fmt.Errorf("diff: %w", err)
   318  	}
   319  	baseIt, err := c.metaRangeManager.NewMetaRangeIterator(ctx, ns, base)
   320  	if err != nil {
   321  		diffIt.Close()
   322  		return nil, fmt.Errorf("get base iterator: %w", err)
   323  	}
   324  	return NewCompareValueIterator(ctx, NewDiffIteratorWrapper(diffIt), baseIt), nil
   325  }
   326  
   327  func (c *committedManager) GetMetaRange(ctx context.Context, ns graveler.StorageNamespace, id graveler.MetaRangeID) (graveler.MetaRangeAddress, error) {
   328  	uri, err := c.metaRangeManager.GetMetaRangeURI(ctx, ns, id)
   329  	return graveler.MetaRangeAddress(uri), err
   330  }
   331  
   332  func (c *committedManager) GetRange(ctx context.Context, ns graveler.StorageNamespace, id graveler.RangeID) (graveler.RangeAddress, error) {
   333  	uri, err := c.metaRangeManager.GetRangeURI(ctx, ns, id)
   334  	return graveler.RangeAddress(uri), err
   335  }
   336  
   337  func (c *committedManager) GetRangeIDByKey(ctx context.Context, ns graveler.StorageNamespace, id graveler.MetaRangeID, key graveler.Key) (graveler.RangeID, error) {
   338  	if id == "" {
   339  		return "", graveler.ErrNotFound
   340  	}
   341  	r, err := c.metaRangeManager.GetRangeByKey(ctx, ns, id, key)
   342  	if err != nil {
   343  		return "", fmt.Errorf("get range for key: %w", err)
   344  	}
   345  	return graveler.RangeID(r.ID), nil
   346  }