github.com/hasnat/dolt/go@v0.0.0-20210628190320-9eb5d843fbb7/store/merge/three_way_ordered_sequence.go (about)

     1  // Copyright 2019 Dolthub, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  //
    15  // This file incorporates work covered by the following copyright and
    16  // permission notice:
    17  //
    18  // Copyright 2016 Attic Labs, Inc. All rights reserved.
    19  // Licensed under the Apache License, version 2.0:
    20  // http://www.apache.org/licenses/LICENSE-2.0
    21  
    22  package merge
    23  
    24  import (
    25  	"context"
    26  	"fmt"
    27  
    28  	"golang.org/x/sync/errgroup"
    29  
    30  	"github.com/dolthub/dolt/go/store/d"
    31  	"github.com/dolthub/dolt/go/store/types"
    32  )
    33  
    34  type applyFunc func(candidate, types.ValueChanged, types.Value) (candidate, error)
    35  
    36  func (m *merger) threeWayOrderedSequenceMerge(ctx context.Context, a, b, parent candidate, apply applyFunc, path types.Path) (types.Value, error) {
    37  	aChangeChan, bChangeChan := make(chan types.ValueChanged), make(chan types.ValueChanged)
    38  
    39  	eg, ctx := errgroup.WithContext(ctx)
    40  	eg.Go(func() error {
    41  		defer close(aChangeChan)
    42  		return a.diff(ctx, parent, aChangeChan)
    43  	})
    44  	eg.Go(func() error {
    45  		defer close(bChangeChan)
    46  		return b.diff(ctx, parent, bChangeChan)
    47  	})
    48  
    49  	merged := parent
    50  	eg.Go(func() error {
    51  		aChange, bChange := types.ValueChanged{}, types.ValueChanged{}
    52  		for {
    53  			// Get the next change from both a and b. If either diff(a,
    54  			// parent) or diff(b, parent) is complete, aChange or bChange
    55  			// will get an empty types.ValueChanged containing a nil Value.
    56  			// Generally, though, this allows us to proceed through both
    57  			// diffs in (key) order, considering the "current" change from
    58  			// both diffs at the same time.
    59  			if aChange.Key == nil {
    60  				select {
    61  				case aChange = <-aChangeChan:
    62  				case <-ctx.Done():
    63  					return ctx.Err()
    64  				}
    65  			}
    66  			if bChange.Key == nil {
    67  				select {
    68  				case bChange = <-bChangeChan:
    69  				case <-ctx.Done():
    70  					return ctx.Err()
    71  				}
    72  			}
    73  
    74  			// Both channels are producing zero values, so we're done.
    75  			if aChange.Key == nil && bChange.Key == nil {
    76  				break
    77  			}
    78  
    79  			// Since diff generates changes in key-order, and we
    80  			// never skip over a change without processing it, we
    81  			// can simply compare the keys at which aChange and
    82  			// bChange occurred to determine if either is safe to
    83  			// apply to the merge result without further
    84  			// processing. This is because if, e.g.
    85  			// aChange.V.Less(bChange.V), we know that the diff of
    86  			// b will never generate a change at that key. If it
    87  			// was going to, it would have done so on an earlier
    88  			// iteration of this loop and been processed at that
    89  			// time.
    90  			//
    91  			// It's also obviously OK to apply a change if only one
    92  			// diff is generating any changes, e.g. aChange.V is
    93  			// non-nil and bChange.V is nil.
    94  			if aChange.Key != nil {
    95  				var err error
    96  				noBOrALessB := bChange.Key == nil
    97  				if !noBOrALessB {
    98  					noBOrALessB, err = aChange.Key.Less(m.vrw.Format(), bChange.Key)
    99  					if err != nil {
   100  						return err
   101  					}
   102  				}
   103  
   104  				if noBOrALessB {
   105  					v, _, err := a.get(ctx, aChange.Key)
   106  					if err != nil {
   107  						return err
   108  					}
   109  
   110  					merged, err = apply(merged, aChange, v)
   111  					if err != nil {
   112  						return err
   113  					}
   114  
   115  					aChange = types.ValueChanged{}
   116  					continue
   117  				}
   118  			}
   119  
   120  			if bChange.Key != nil {
   121  				var err error
   122  				noAOrBLessA := aChange.Key == nil
   123  
   124  				if !noAOrBLessA {
   125  					noAOrBLessA, err = bChange.Key.Less(m.vrw.Format(), aChange.Key)
   126  					if err != nil {
   127  						return err
   128  					}
   129  				}
   130  
   131  				if noAOrBLessA {
   132  					v, _, err := b.get(ctx, bChange.Key)
   133  					if err != nil {
   134  						return err
   135  					}
   136  
   137  					merged, err = apply(merged, bChange, v)
   138  					if err != nil {
   139  						return err
   140  					}
   141  
   142  					bChange = types.ValueChanged{}
   143  					continue
   144  				}
   145  			}
   146  
   147  			if !aChange.Key.Equals(bChange.Key) {
   148  				d.Panic("Diffs have skewed!") // Sanity check.
   149  			}
   150  
   151  			change, mergedVal, err := m.mergeChanges(ctx, aChange, bChange, a, b, parent, apply, path)
   152  			if err != nil {
   153  				return err
   154  			}
   155  			merged, err = apply(merged, change, mergedVal)
   156  			if err != nil {
   157  				return err
   158  			}
   159  
   160  			aChange, bChange = types.ValueChanged{}, types.ValueChanged{}
   161  		}
   162  		return nil
   163  	})
   164  
   165  	if err := eg.Wait(); err != nil {
   166  		return nil, err
   167  	}
   168  
   169  	return merged.getValue(), nil
   170  }
   171  
   172  func (m *merger) mergeChanges(ctx context.Context, aChange, bChange types.ValueChanged, a, b, p candidate, apply applyFunc, path types.Path) (change types.ValueChanged, mergedVal types.Value, err error) {
   173  	path, err = a.pathConcat(ctx, aChange, path)
   174  
   175  	if err != nil {
   176  		return types.ValueChanged{}, nil, err
   177  	}
   178  
   179  	aValue, _, err := a.get(ctx, aChange.Key)
   180  
   181  	if err != nil {
   182  		return types.ValueChanged{}, nil, err
   183  	}
   184  
   185  	bValue, _, err := b.get(ctx, bChange.Key)
   186  
   187  	if err != nil {
   188  		return types.ValueChanged{}, nil, err
   189  	}
   190  
   191  	// If the two diffs generate different kinds of changes at the same key, conflict.
   192  	if aChange.ChangeType != bChange.ChangeType {
   193  		if change, mergedVal, ok := m.resolve(aChange.ChangeType, bChange.ChangeType, aValue, bValue, path); ok {
   194  			// TODO: Correctly encode Old/NewValue with this change report. https://github.com/attic-labs/noms/issues/3467
   195  			return types.ValueChanged{ChangeType: change, Key: aChange.Key, OldValue: nil, NewValue: nil}, mergedVal, nil
   196  		}
   197  
   198  		aDesc, err := describeChange(aChange)
   199  
   200  		if err != nil {
   201  			return types.ValueChanged{}, nil, err
   202  		}
   203  
   204  		bDesc, err := describeChange(bChange)
   205  
   206  		if err != nil {
   207  			return types.ValueChanged{}, nil, err
   208  		}
   209  
   210  		return change, nil, newMergeConflict("Conflict:\n%s\nvs\n%s\n", aDesc, bDesc)
   211  	}
   212  
   213  	if aChange.ChangeType == types.DiffChangeRemoved || aValue.Equals(bValue) {
   214  		// If both diffs generated a remove, or if the new value is the same in both, merge is fine.
   215  		return aChange, aValue, nil
   216  	}
   217  
   218  	// There's one case that might still be OK even if aValue and bValue differ: different, but mergeable, compound values of the same type being added/modified at the same key, e.g. a Map being added to both a and b. If either is a primitive, or Values of different Kinds were added, though, we're in conflict.
   219  	if !unmergeable(aValue, bValue) {
   220  		v, _, err := p.get(ctx, aChange.Key)
   221  
   222  		if err != nil {
   223  			return types.ValueChanged{}, nil, err
   224  		}
   225  
   226  		// TODO: Add concurrency.
   227  		if mergedVal, err = m.threeWay(ctx, aValue, bValue, v, path); err == nil {
   228  			return aChange, mergedVal, nil
   229  		}
   230  		return change, nil, err
   231  	}
   232  
   233  	if change, mergedVal, ok := m.resolve(aChange.ChangeType, bChange.ChangeType, aValue, bValue, path); ok {
   234  		// TODO: Correctly encode Old/NewValue with this change report. https://github.com/attic-labs/noms/issues/3467
   235  		return types.ValueChanged{ChangeType: change, Key: aChange.Key, OldValue: nil, NewValue: nil}, mergedVal, nil
   236  	}
   237  
   238  	aStr, err := types.EncodedValue(ctx, aValue)
   239  
   240  	if err != nil {
   241  		return types.ValueChanged{}, nil, err
   242  	}
   243  
   244  	aDesc, err := describeChange(aChange)
   245  
   246  	if err != nil {
   247  		return types.ValueChanged{}, nil, err
   248  	}
   249  
   250  	bStr, err := types.EncodedValue(ctx, bValue)
   251  
   252  	if err != nil {
   253  		return types.ValueChanged{}, nil, err
   254  	}
   255  
   256  	bDesc, err := describeChange(bChange)
   257  
   258  	if err != nil {
   259  		return types.ValueChanged{}, nil, err
   260  	}
   261  
   262  	return change, nil, newMergeConflict("Conflict:\n%s = %s\nvs\n%s = %s", aDesc, aStr, bDesc, bStr)
   263  }
   264  
   265  func describeChange(change types.ValueChanged) (string, error) {
   266  	op := ""
   267  	switch change.ChangeType {
   268  	case types.DiffChangeAdded:
   269  		op = "added"
   270  	case types.DiffChangeModified:
   271  		op = "modded"
   272  	case types.DiffChangeRemoved:
   273  		op = "removed"
   274  	}
   275  
   276  	str, err := types.EncodedValue(context.Background(), change.Key)
   277  
   278  	if err != nil {
   279  		return "", err
   280  	}
   281  
   282  	return fmt.Sprintf("%s %s", op, str), nil
   283  }