github.com/hasnat/dolt/go@v0.0.0-20210628190320-9eb5d843fbb7/libraries/doltcore/merge/merge.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 package merge 16 17 import ( 18 "context" 19 "errors" 20 "fmt" 21 "strings" 22 23 "golang.org/x/sync/errgroup" 24 25 "github.com/dolthub/dolt/go/libraries/doltcore/diff" 26 "github.com/dolthub/dolt/go/libraries/doltcore/doltdb" 27 "github.com/dolthub/dolt/go/libraries/doltcore/env" 28 "github.com/dolthub/dolt/go/libraries/doltcore/row" 29 "github.com/dolthub/dolt/go/libraries/doltcore/schema" 30 "github.com/dolthub/dolt/go/libraries/doltcore/table/editor" 31 "github.com/dolthub/dolt/go/libraries/utils/valutil" 32 "github.com/dolthub/dolt/go/store/atomicerr" 33 "github.com/dolthub/dolt/go/store/hash" 34 "github.com/dolthub/dolt/go/store/types" 35 ) 36 37 var ErrFastForward = errors.New("fast forward") 38 var ErrSameTblAddedTwice = errors.New("table with same name added in 2 commits can't be merged") 39 40 type Merger struct { 41 root *doltdb.RootValue 42 mergeRoot *doltdb.RootValue 43 ancRoot *doltdb.RootValue 44 vrw types.ValueReadWriter 45 } 46 47 // NewMerger creates a new merger utility object. 48 func NewMerger(ctx context.Context, root, mergeRoot, ancRoot *doltdb.RootValue, vrw types.ValueReadWriter) *Merger { 49 return &Merger{root, mergeRoot, ancRoot, vrw} 50 } 51 52 // MergeTable merges schema and table data for the table tblName. 53 func (merger *Merger) MergeTable(ctx context.Context, tblName string, sess *editor.TableEditSession) (*doltdb.Table, *MergeStats, error) { 54 tbl, ok, err := merger.root.GetTable(ctx, tblName) 55 if err != nil { 56 return nil, nil, err 57 } 58 59 var h hash.Hash 60 var tblSchema schema.Schema 61 if ok { 62 h, err = tbl.HashOf() 63 if err != nil { 64 return nil, nil, err 65 } 66 tblSchema, err = tbl.GetSchema(ctx) 67 if err != nil { 68 return nil, nil, err 69 } 70 } 71 72 mergeTbl, mergeOk, err := merger.mergeRoot.GetTable(ctx, tblName) 73 if err != nil { 74 return nil, nil, err 75 } 76 77 var mh hash.Hash 78 var mergeTblSchema schema.Schema 79 if mergeOk { 80 mh, err = mergeTbl.HashOf() 81 if err != nil { 82 return nil, nil, err 83 } 84 mergeTblSchema, err = mergeTbl.GetSchema(ctx) 85 if err != nil { 86 return nil, nil, err 87 } 88 } 89 90 ancTbl, ancOk, err := merger.ancRoot.GetTable(ctx, tblName) 91 if err != nil { 92 return nil, nil, err 93 } 94 95 var anch hash.Hash 96 var ancTblSchema schema.Schema 97 var ancRows types.Map 98 if ancOk { 99 anch, err = ancTbl.HashOf() 100 if err != nil { 101 return nil, nil, err 102 } 103 ancTblSchema, err = ancTbl.GetSchema(ctx) 104 if err != nil { 105 return nil, nil, err 106 } 107 ancRows, err = ancTbl.GetRowData(ctx) 108 if err != nil { 109 return nil, nil, err 110 } 111 } 112 113 { // short-circuit logic 114 if ancOk && schema.IsKeyless(ancTblSchema) { 115 if ok && mergeOk && ancOk && h == mh && h == anch { 116 return tbl, &MergeStats{Operation: TableUnmodified}, nil 117 } 118 } else { 119 if ok && mergeOk && h == mh { 120 return tbl, &MergeStats{Operation: TableUnmodified}, nil 121 } 122 } 123 124 if !ancOk { 125 if mergeOk && ok { 126 if schema.SchemasAreEqual(tblSchema, mergeTblSchema) { 127 // hackity hack 128 ancTblSchema, ancTbl = tblSchema, tbl 129 ancRows, _ = types.NewMap(ctx, merger.vrw) 130 } else { 131 return nil, nil, ErrSameTblAddedTwice 132 } 133 } else if ok { 134 // fast-forward 135 return tbl, &MergeStats{Operation: TableUnmodified}, nil 136 } else { 137 // fast-forward 138 return mergeTbl, &MergeStats{Operation: TableAdded}, nil 139 } 140 } 141 142 if h == anch { 143 // fast-forward 144 ms := MergeStats{Operation: TableModified} 145 if h != mh { 146 ms, err = calcTableMergeStats(ctx, tbl, mergeTbl) 147 if err != nil { 148 return nil, nil, err 149 } 150 } 151 // force load the table editor since this counts as a change 152 _, err := sess.GetTableEditor(ctx, tblName, nil) 153 if err != nil { 154 return nil, nil, err 155 } 156 return mergeTbl, &ms, nil 157 } else if mh == anch { 158 // fast-forward 159 return tbl, &MergeStats{Operation: TableUnmodified}, nil 160 } 161 } 162 163 postMergeSchema, schConflicts, err := SchemaMerge(tblSchema, mergeTblSchema, ancTblSchema, tblName) 164 if err != nil { 165 return nil, nil, err 166 } 167 if schConflicts.Count() != 0 { 168 // error on schema conflicts for now 169 return nil, nil, schConflicts.AsError() 170 } 171 172 rows, err := tbl.GetRowData(ctx) 173 if err != nil { 174 return nil, nil, err 175 } 176 177 mergeRows, err := mergeTbl.GetRowData(ctx) 178 if err != nil { 179 return nil, nil, err 180 } 181 182 updatedTbl, err := tbl.UpdateSchema(ctx, postMergeSchema) 183 if err != nil { 184 return nil, nil, err 185 } 186 187 // If any indexes were added during the merge, then we need to generate their row data to add to our updated table. 188 addedIndexesSet := make(map[string]string) 189 for _, index := range postMergeSchema.Indexes().AllIndexes() { 190 addedIndexesSet[strings.ToLower(index.Name())] = index.Name() 191 } 192 for _, index := range tblSchema.Indexes().AllIndexes() { 193 delete(addedIndexesSet, strings.ToLower(index.Name())) 194 } 195 for _, addedIndex := range addedIndexesSet { 196 newIndexData, err := editor.RebuildIndex(ctx, updatedTbl, addedIndex) 197 if err != nil { 198 return nil, nil, err 199 } 200 updatedTbl, err = updatedTbl.SetIndexRowData(ctx, addedIndex, newIndexData) 201 if err != nil { 202 return nil, nil, err 203 } 204 } 205 206 err = sess.UpdateRoot(ctx, func(ctx context.Context, root *doltdb.RootValue) (*doltdb.RootValue, error) { 207 return root.PutTable(ctx, tblName, updatedTbl) 208 }) 209 if err != nil { 210 return nil, nil, err 211 } 212 213 updatedTblEditor, err := sess.GetTableEditor(ctx, tblName, nil) 214 if err != nil { 215 return nil, nil, err 216 } 217 218 resultTbl, conflicts, stats, err := mergeTableData(ctx, merger.vrw, tblName, postMergeSchema, rows, mergeRows, ancRows, updatedTblEditor, sess) 219 if err != nil { 220 return nil, nil, err 221 } 222 223 if conflicts.Len() > 0 { 224 225 asr, err := ancTbl.GetSchemaRef() 226 if err != nil { 227 return nil, nil, err 228 } 229 230 sr, err := tbl.GetSchemaRef() 231 if err != nil { 232 return nil, nil, err 233 } 234 235 msr, err := mergeTbl.GetSchemaRef() 236 if err != nil { 237 return nil, nil, err 238 } 239 240 schemas := doltdb.NewConflict(asr, sr, msr) 241 resultTbl, err = resultTbl.SetConflicts(ctx, schemas, conflicts) 242 if err != nil { 243 return nil, nil, err 244 } 245 } 246 247 resultTbl, err = mergeAutoIncrementValues(ctx, tbl, mergeTbl, resultTbl) 248 if err != nil { 249 return nil, nil, err 250 } 251 252 return resultTbl, stats, nil 253 } 254 255 func calcTableMergeStats(ctx context.Context, tbl *doltdb.Table, mergeTbl *doltdb.Table) (MergeStats, error) { 256 rows, err := tbl.GetRowData(ctx) 257 258 if err != nil { 259 return MergeStats{}, err 260 } 261 262 mergeRows, err := mergeTbl.GetRowData(ctx) 263 264 if err != nil { 265 return MergeStats{}, err 266 } 267 268 ae := atomicerr.New() 269 ch := make(chan diff.DiffSummaryProgress) 270 go func() { 271 defer close(ch) 272 err := diff.Summary(ctx, ch, rows, mergeRows) 273 274 ae.SetIfError(err) 275 }() 276 277 ms := MergeStats{Operation: TableModified} 278 for p := range ch { 279 if ae.IsSet() { 280 break 281 } 282 283 ms.Adds += int(p.Adds) 284 ms.Deletes += int(p.Removes) 285 ms.Modifications += int(p.Changes) 286 } 287 288 if err := ae.Get(); err != nil { 289 return MergeStats{}, err 290 } 291 292 return ms, nil 293 } 294 295 type rowMerger func(ctx context.Context, nbf *types.NomsBinFormat, sch schema.Schema, r, mergeRow, baseRow types.Value) (types.Value, bool, error) 296 297 type applicator func(ctx context.Context, sch schema.Schema, tableEditor editor.TableEditor, rowData types.Map, stats *MergeStats, change types.ValueChanged) error 298 299 func mergeTableData(ctx context.Context, vrw types.ValueReadWriter, tblName string, sch schema.Schema, rows, mergeRows, ancRows types.Map, tblEdit editor.TableEditor, sess *editor.TableEditSession) (*doltdb.Table, types.Map, *MergeStats, error) { 300 var rowMerge rowMerger 301 var applyChange applicator 302 if schema.IsKeyless(sch) { 303 rowMerge = keylessRowMerge 304 applyChange = applyKeylessChange 305 } else { 306 rowMerge = pkRowMerge 307 applyChange = applyPkChange 308 } 309 310 changeChan, mergeChangeChan := make(chan types.ValueChanged, 32), make(chan types.ValueChanged, 32) 311 312 eg, ctx := errgroup.WithContext(ctx) 313 314 eg.Go(func() error { 315 defer close(changeChan) 316 return rows.Diff(ctx, ancRows, changeChan) 317 }) 318 eg.Go(func() error { 319 defer close(mergeChangeChan) 320 return mergeRows.Diff(ctx, ancRows, mergeChangeChan) 321 }) 322 323 conflictValChan := make(chan types.Value) 324 sm := types.NewStreamingMap(ctx, vrw, conflictValChan) 325 stats := &MergeStats{Operation: TableModified} 326 327 eg.Go(func() error { 328 defer close(conflictValChan) 329 330 var change, mergeChange types.ValueChanged 331 for { 332 // Get the next change from both a and b. If either diff(a, parent) or diff(b, parent) is 333 // complete, aChange or bChange will get an empty types.ValueChanged containing a nil Value. 334 // Generally, though, this allows us to proceed through both diffs in (key) order, considering 335 // the "current" change from both diffs at the same time. 336 if change.Key == nil { 337 select { 338 case change = <-changeChan: 339 break 340 case <-ctx.Done(): 341 return ctx.Err() 342 } 343 } 344 if mergeChange.Key == nil { 345 select { 346 case mergeChange = <-mergeChangeChan: 347 break 348 case <-ctx.Done(): 349 return ctx.Err() 350 } 351 } 352 353 key, mergeKey := change.Key, mergeChange.Key 354 355 // Both channels are producing zero values, so we're done. 356 if key == nil && mergeKey == nil { 357 break 358 } 359 360 var err error 361 var processed bool 362 if key != nil { 363 mkNilOrKeyLess := mergeKey == nil 364 if !mkNilOrKeyLess { 365 mkNilOrKeyLess, err = key.Less(vrw.Format(), mergeKey) 366 if err != nil { 367 return err 368 } 369 } 370 371 if mkNilOrKeyLess { 372 // change will already be in the map 373 // we apply changes directly to "ours" 374 // instead of to ancestor 375 change = types.ValueChanged{} 376 processed = true 377 } 378 } 379 380 if !processed && mergeKey != nil { 381 keyNilOrMKLess := key == nil 382 if !keyNilOrMKLess { 383 keyNilOrMKLess, err = mergeKey.Less(vrw.Format(), key) 384 if err != nil { 385 return err 386 } 387 } 388 389 if keyNilOrMKLess { 390 err = applyChange(ctx, sch, tblEdit, rows, stats, mergeChange) 391 if err != nil { 392 return err 393 } 394 mergeChange = types.ValueChanged{} 395 processed = true 396 } 397 } 398 399 if !processed { 400 r, mergeRow, ancRow := change.NewValue, mergeChange.NewValue, change.OldValue 401 mergedRow, isConflict, err := rowMerge(ctx, vrw.Format(), sch, r, mergeRow, ancRow) 402 if err != nil { 403 return err 404 } 405 406 if isConflict { 407 stats.Conflicts++ 408 conflictTuple, err := doltdb.NewConflict(ancRow, r, mergeRow).ToNomsList(vrw) 409 if err != nil { 410 return err 411 } 412 413 err = addConflict(conflictValChan, sm.Done(), key, conflictTuple) 414 if err != nil { 415 return err 416 } 417 } else { 418 vc := types.ValueChanged{ChangeType: change.ChangeType, Key: key, OldValue: ancRow, NewValue: mergedRow} 419 err = applyChange(ctx, sch, tblEdit, rows, stats, vc) 420 if err != nil { 421 return err 422 } 423 } 424 425 change = types.ValueChanged{} 426 mergeChange = types.ValueChanged{} 427 } 428 } 429 430 return nil 431 }) 432 433 if err := eg.Wait(); err != nil { 434 return nil, types.EmptyMap, nil, err 435 } 436 437 conflicts, err := sm.Wait() 438 if err != nil { 439 return nil, types.EmptyMap, nil, err 440 } 441 newRoot, err := sess.Flush(ctx) 442 if err != nil { 443 return nil, types.EmptyMap, nil, err 444 } 445 446 mergedTable, ok, err := newRoot.GetTable(ctx, tblName) 447 if err != nil { 448 return nil, types.EmptyMap, nil, err 449 } 450 if !ok { 451 return nil, types.EmptyMap, nil, fmt.Errorf("updated mergedTable `%s` has disappeared", tblName) 452 } 453 454 return mergedTable, conflicts, stats, nil 455 } 456 457 func addConflict(conflictChan chan types.Value, done <-chan struct{}, key types.Value, value types.Tuple) error { 458 select { 459 case conflictChan <- key: 460 case <-done: 461 return context.Canceled 462 } 463 select { 464 case conflictChan <- value: 465 case <-done: 466 return context.Canceled 467 } 468 return nil 469 } 470 471 func applyPkChange(ctx context.Context, sch schema.Schema, tableEditor editor.TableEditor, rowData types.Map, stats *MergeStats, change types.ValueChanged) error { 472 switch change.ChangeType { 473 case types.DiffChangeAdded: 474 newRow, err := row.FromNoms(sch, change.Key.(types.Tuple), change.NewValue.(types.Tuple)) 475 if err != nil { 476 return err 477 } 478 // TODO(andy): because we apply changes to "ours" instead of ancestor 479 // we have to check for duplicate primary key errors here. 480 val, ok, err := rowData.MaybeGet(ctx, change.Key) 481 if err != nil { 482 return err 483 } else if ok { 484 oldRow, err := row.FromNoms(sch, change.Key.(types.Tuple), val.(types.Tuple)) 485 if err != nil { 486 return err 487 } 488 err = tableEditor.UpdateRow(ctx, oldRow, newRow, nil) 489 if err != nil { 490 return err 491 } 492 } else { 493 err = tableEditor.InsertRow(ctx, newRow, nil) 494 if err != nil { 495 return err 496 } 497 } 498 stats.Adds++ 499 case types.DiffChangeModified: 500 oldRow, err := row.FromNoms(sch, change.Key.(types.Tuple), change.OldValue.(types.Tuple)) 501 if err != nil { 502 return err 503 } 504 newRow, err := row.FromNoms(sch, change.Key.(types.Tuple), change.NewValue.(types.Tuple)) 505 if err != nil { 506 return err 507 } 508 err = tableEditor.UpdateRow(ctx, oldRow, newRow, nil) 509 if err != nil { 510 return err 511 } 512 stats.Modifications++ 513 case types.DiffChangeRemoved: 514 oldRow, err := row.FromNoms(sch, change.Key.(types.Tuple), change.OldValue.(types.Tuple)) 515 if err != nil { 516 return err 517 } 518 err = tableEditor.DeleteRow(ctx, oldRow) 519 if err != nil { 520 return err 521 } 522 stats.Deletes++ 523 } 524 525 return nil 526 } 527 528 func applyKeylessChange(ctx context.Context, sch schema.Schema, tableEditor editor.TableEditor, _ types.Map, stats *MergeStats, change types.ValueChanged) (err error) { 529 apply := func(ch types.ValueChanged) error { 530 switch ch.ChangeType { 531 case types.DiffChangeAdded: 532 newRow, err := row.FromNoms(sch, ch.Key.(types.Tuple), ch.NewValue.(types.Tuple)) 533 if err != nil { 534 return err 535 } 536 err = tableEditor.InsertRow(ctx, newRow, nil) 537 if err != nil { 538 return err 539 } 540 stats.Adds++ 541 case types.DiffChangeModified: 542 oldRow, err := row.FromNoms(sch, ch.Key.(types.Tuple), ch.OldValue.(types.Tuple)) 543 if err != nil { 544 return err 545 } 546 newRow, err := row.FromNoms(sch, ch.Key.(types.Tuple), ch.NewValue.(types.Tuple)) 547 if err != nil { 548 return err 549 } 550 err = tableEditor.UpdateRow(ctx, oldRow, newRow, nil) 551 if err != nil { 552 return err 553 } 554 stats.Modifications++ 555 case types.DiffChangeRemoved: 556 oldRow, err := row.FromNoms(sch, ch.Key.(types.Tuple), ch.OldValue.(types.Tuple)) 557 if err != nil { 558 return err 559 } 560 err = tableEditor.DeleteRow(ctx, oldRow) 561 if err != nil { 562 return err 563 } 564 stats.Deletes++ 565 } 566 return nil 567 } 568 569 var card uint64 570 change, card, err = convertValueChanged(change) 571 if err != nil { 572 return err 573 } 574 575 for card > 0 { 576 if err = apply(change); err != nil { 577 return err 578 } 579 card-- 580 } 581 return nil 582 } 583 584 func convertValueChanged(vc types.ValueChanged) (types.ValueChanged, uint64, error) { 585 var oldCard uint64 586 if vc.OldValue != nil { 587 v, err := vc.OldValue.(types.Tuple).Get(row.KeylessCardinalityValIdx) 588 if err != nil { 589 return vc, 0, err 590 } 591 oldCard = uint64(v.(types.Uint)) 592 } 593 594 var newCard uint64 595 if vc.NewValue != nil { 596 v, err := vc.NewValue.(types.Tuple).Get(row.KeylessCardinalityValIdx) 597 if err != nil { 598 return vc, 0, err 599 } 600 newCard = uint64(v.(types.Uint)) 601 } 602 603 switch vc.ChangeType { 604 case types.DiffChangeRemoved: 605 return vc, oldCard, nil 606 607 case types.DiffChangeAdded: 608 return vc, newCard, nil 609 610 case types.DiffChangeModified: 611 delta := int64(newCard) - int64(oldCard) 612 if delta > 0 { 613 vc.ChangeType = types.DiffChangeAdded 614 vc.OldValue = nil 615 return vc, uint64(delta), nil 616 } else if delta < 0 { 617 vc.ChangeType = types.DiffChangeRemoved 618 vc.NewValue = nil 619 return vc, uint64(-delta), nil 620 } else { 621 panic(fmt.Sprintf("diff with delta = 0 for key: %s", vc.Key.HumanReadableString())) 622 } 623 default: 624 return vc, 0, fmt.Errorf("unexpected DiffChange type %d", vc.ChangeType) 625 } 626 } 627 628 func pkRowMerge(ctx context.Context, nbf *types.NomsBinFormat, sch schema.Schema, r, mergeRow, baseRow types.Value) (types.Value, bool, error) { 629 var baseVals row.TaggedValues 630 if baseRow == nil { 631 if r.Equals(mergeRow) { 632 // same row added to both 633 return r, false, nil 634 } 635 } else if r == nil && mergeRow == nil { 636 // same row removed from both 637 return nil, false, nil 638 } else if r == nil || mergeRow == nil { 639 // removed from one and modified in another 640 return nil, true, nil 641 } else { 642 var err error 643 baseVals, err = row.ParseTaggedValues(baseRow.(types.Tuple)) 644 645 if err != nil { 646 return nil, false, err 647 } 648 } 649 650 rowVals, err := row.ParseTaggedValues(r.(types.Tuple)) 651 if err != nil { 652 return nil, false, err 653 } 654 655 mergeVals, err := row.ParseTaggedValues(mergeRow.(types.Tuple)) 656 if err != nil { 657 return nil, false, err 658 } 659 660 processTagFunc := func(tag uint64) (resultVal types.Value, isConflict bool) { 661 baseVal, _ := baseVals.Get(tag) 662 val, _ := rowVals.Get(tag) 663 mergeVal, _ := mergeVals.Get(tag) 664 665 if valutil.NilSafeEqCheck(val, mergeVal) { 666 return val, false 667 } else { 668 modified := !valutil.NilSafeEqCheck(val, baseVal) 669 mergeModified := !valutil.NilSafeEqCheck(mergeVal, baseVal) 670 switch { 671 case modified && mergeModified: 672 return nil, true 673 case modified: 674 return val, false 675 default: 676 return mergeVal, false 677 } 678 } 679 680 } 681 682 resultVals := make(row.TaggedValues) 683 684 var isConflict bool 685 err = sch.GetNonPKCols().Iter(func(tag uint64, _ schema.Column) (stop bool, err error) { 686 var val types.Value 687 val, isConflict = processTagFunc(tag) 688 resultVals[tag] = val 689 690 return isConflict, nil 691 }) 692 693 if err != nil { 694 return nil, false, err 695 } 696 697 if isConflict { 698 return nil, true, nil 699 } 700 701 tpl := resultVals.NomsTupleForNonPKCols(nbf, sch.GetNonPKCols()) 702 v, err := tpl.Value(ctx) 703 704 if err != nil { 705 return nil, false, err 706 } 707 708 return v, false, nil 709 } 710 711 func keylessRowMerge(ctx context.Context, nbf *types.NomsBinFormat, sch schema.Schema, val, mergeVal, ancVal types.Value) (types.Value, bool, error) { 712 // both sides of the merge produced a diff for this key, 713 // so we always throw a conflict 714 return nil, true, nil 715 } 716 717 func mergeAutoIncrementValues(ctx context.Context, tbl, otherTbl, resultTbl *doltdb.Table) (*doltdb.Table, error) { 718 // only need to check one table, no PK changes yet 719 sch, err := tbl.GetSchema(ctx) 720 if err != nil { 721 return nil, err 722 } 723 auto := false 724 _ = sch.GetAllCols().Iter(func(tag uint64, col schema.Column) (stop bool, err error) { 725 if col.AutoIncrement { 726 auto, stop = true, true 727 } 728 return 729 }) 730 if !auto { 731 return resultTbl, nil 732 } 733 734 autoVal, err := tbl.GetAutoIncrementValue(ctx) 735 if err != nil { 736 return nil, err 737 } 738 mergeAutoVal, err := otherTbl.GetAutoIncrementValue(ctx) 739 if err != nil { 740 return nil, err 741 } 742 less, err := autoVal.Less(tbl.Format(), mergeAutoVal) 743 if err != nil { 744 return nil, err 745 } 746 if less { 747 autoVal = mergeAutoVal 748 } 749 return resultTbl.SetAutoIncrementValue(autoVal) 750 } 751 752 func MergeCommits(ctx context.Context, commit, mergeCommit *doltdb.Commit) (*doltdb.RootValue, map[string]*MergeStats, error) { 753 ancCommit, err := doltdb.GetCommitAncestor(ctx, commit, mergeCommit) 754 755 if err != nil { 756 return nil, nil, err 757 } 758 759 ourRoot, err := commit.GetRootValue() 760 761 if err != nil { 762 return nil, nil, err 763 } 764 765 theirRoot, err := mergeCommit.GetRootValue() 766 767 if err != nil { 768 return nil, nil, err 769 } 770 771 ancRoot, err := ancCommit.GetRootValue() 772 773 if err != nil { 774 return nil, nil, err 775 } 776 777 return MergeRoots(ctx, ourRoot, theirRoot, ancRoot) 778 } 779 780 func MergeRoots(ctx context.Context, ourRoot, theirRoot, ancRoot *doltdb.RootValue) (*doltdb.RootValue, map[string]*MergeStats, error) { 781 merger := NewMerger(ctx, ourRoot, theirRoot, ancRoot, ourRoot.VRW()) 782 783 tblNames, err := doltdb.UnionTableNames(ctx, ourRoot, theirRoot) 784 785 if err != nil { 786 return nil, nil, err 787 } 788 789 tblToStats := make(map[string]*MergeStats) 790 791 newRoot := ourRoot 792 tableEditSession := editor.CreateTableEditSession(ourRoot, editor.TableEditSessionProps{ 793 ForeignKeyChecksDisabled: true, 794 }) 795 // need to validate merges can be done on all tables before starting the actual merges. 796 for _, tblName := range tblNames { 797 mergedTable, stats, err := merger.MergeTable(ctx, tblName, tableEditSession) 798 799 if err != nil { 800 return nil, nil, err 801 } 802 803 if mergedTable != nil { 804 tblToStats[tblName] = stats 805 806 err = tableEditSession.UpdateRoot(ctx, func(ctx context.Context, root *doltdb.RootValue) (*doltdb.RootValue, error) { 807 return root.PutTable(ctx, tblName, mergedTable) 808 }) 809 if err != nil { 810 return nil, nil, err 811 } 812 newRoot, err = tableEditSession.Flush(ctx) 813 if err != nil { 814 return nil, nil, err 815 } 816 } else if has, err := newRoot.HasTable(ctx, tblName); err != nil { 817 return nil, nil, err 818 } else if has { 819 tblToStats[tblName] = &MergeStats{Operation: TableRemoved} 820 err = tableEditSession.UpdateRoot(ctx, func(ctx context.Context, root *doltdb.RootValue) (*doltdb.RootValue, error) { 821 return root.RemoveTables(ctx, tblName) 822 }) 823 if err != nil { 824 return nil, nil, err 825 } 826 newRoot, err = tableEditSession.Flush(ctx) 827 if err != nil { 828 return nil, nil, err 829 } 830 } else { 831 panic("?") 832 } 833 } 834 835 err = tableEditSession.UpdateRoot(ctx, func(ctx context.Context, root *doltdb.RootValue) (value *doltdb.RootValue, err error) { 836 mergedFKColl, conflicts, err := ForeignKeysMerge(ctx, root, ourRoot, theirRoot, ancRoot) 837 if err != nil { 838 return nil, err 839 } 840 if len(conflicts) > 0 { 841 return nil, fmt.Errorf("foreign key conflicts") 842 } 843 844 root, err = root.PutForeignKeyCollection(ctx, mergedFKColl) 845 if err != nil { 846 return nil, err 847 } 848 849 return root.UpdateSuperSchemasFromOther(ctx, tblNames, theirRoot) 850 }) 851 if err != nil { 852 return nil, nil, err 853 } 854 855 newRoot, err = tableEditSession.Flush(ctx) 856 if err != nil { 857 return nil, nil, err 858 } 859 860 return newRoot, tblToStats, nil 861 } 862 863 func GetTablesInConflict(ctx context.Context, ddb *doltdb.DoltDB, rsr env.RepoStateReader) (workingInConflict, stagedInConflict, headInConflict []string, err error) { 864 var headRoot, stagedRoot, workingRoot *doltdb.RootValue 865 866 headRoot, err = env.HeadRoot(ctx, ddb, rsr) 867 868 if err != nil { 869 return nil, nil, nil, err 870 } 871 872 stagedRoot, err = env.StagedRoot(ctx, ddb, rsr) 873 874 if err != nil { 875 return nil, nil, nil, err 876 } 877 878 workingRoot, err = env.WorkingRoot(ctx, ddb, rsr) 879 880 if err != nil { 881 return nil, nil, nil, err 882 } 883 884 headInConflict, err = headRoot.TablesInConflict(ctx) 885 886 if err != nil { 887 return nil, nil, nil, err 888 } 889 890 stagedInConflict, err = stagedRoot.TablesInConflict(ctx) 891 892 if err != nil { 893 return nil, nil, nil, err 894 } 895 896 workingInConflict, err = workingRoot.TablesInConflict(ctx) 897 898 if err != nil { 899 return nil, nil, nil, err 900 } 901 902 return workingInConflict, stagedInConflict, headInConflict, err 903 } 904 905 func GetDocsInConflict(ctx context.Context, ddb *doltdb.DoltDB, rsr env.RepoStateReader, drw env.DocsReadWriter) (*diff.DocDiffs, error) { 906 docs, err := drw.GetDocsOnDisk() 907 if err != nil { 908 return nil, err 909 } 910 911 workingRoot, err := env.WorkingRoot(ctx, ddb, rsr) 912 if err != nil { 913 return nil, err 914 } 915 916 return diff.NewDocDiffs(ctx, workingRoot, nil, docs) 917 }