github.com/fr-nvriep/migrate/v4@v4.3.2/migrate.go (about) 1 // Package migrate reads migrations from sources and runs them against databases. 2 // Sources are defined by the `source.Driver` and databases by the `database.Driver` 3 // interface. The driver interfaces are kept "dump", all migration logic is kept 4 // in this package. 5 package migrate 6 7 import ( 8 "errors" 9 "fmt" 10 "github.com/hashicorp/go-multierror" 11 "os" 12 "sync" 13 "time" 14 15 "github.com/fr-nvriep/migrate/v4/database" 16 "github.com/fr-nvriep/migrate/v4/source" 17 ) 18 19 // DefaultPrefetchMigrations sets the number of migrations to pre-read 20 // from the source. This is helpful if the source is remote, but has little 21 // effect for a local source (i.e. file system). 22 // Please note that this setting has a major impact on the memory usage, 23 // since each pre-read migration is buffered in memory. See DefaultBufferSize. 24 var DefaultPrefetchMigrations = uint(10) 25 26 // DefaultLockTimeout sets the max time a database driver has to acquire a lock. 27 var DefaultLockTimeout = 15 * time.Second 28 29 var ( 30 ErrNoChange = errors.New("no change") 31 ErrNilVersion = errors.New("no migration") 32 ErrInvalidVersion = errors.New("version must be >= -1") 33 ErrLocked = errors.New("database locked") 34 ErrLockTimeout = errors.New("timeout: can't acquire database lock") 35 ) 36 37 // ErrShortLimit is an error returned when not enough migrations 38 // can be returned by a source for a given limit. 39 type ErrShortLimit struct { 40 Short uint 41 } 42 43 // Error implements the error interface. 44 func (e ErrShortLimit) Error() string { 45 return fmt.Sprintf("limit %v short", e.Short) 46 } 47 48 type ErrDirty struct { 49 Version int 50 } 51 52 func (e ErrDirty) Error() string { 53 return fmt.Sprintf("Dirty database version %v. Fix and force version.", e.Version) 54 } 55 56 type Migrate struct { 57 sourceName string 58 sourceDrv source.Driver 59 databaseName string 60 databaseDrv database.Driver 61 62 // Log accepts a Logger interface 63 Log Logger 64 65 // GracefulStop accepts `true` and will stop executing migrations 66 // as soon as possible at a safe break point, so that the database 67 // is not corrupted. 68 GracefulStop chan bool 69 isLockedMu *sync.Mutex 70 71 isGracefulStop bool 72 isLocked bool 73 74 // PrefetchMigrations defaults to DefaultPrefetchMigrations, 75 // but can be set per Migrate instance. 76 PrefetchMigrations uint 77 78 // LockTimeout defaults to DefaultLockTimeout, 79 // but can be set per Migrate instance. 80 LockTimeout time.Duration 81 } 82 83 // New returns a new Migrate instance from a source URL and a database URL. 84 // The URL scheme is defined by each driver. 85 func New(sourceURL, databaseURL string) (*Migrate, error) { 86 m := newCommon() 87 88 sourceName, err := sourceSchemeFromURL(sourceURL) 89 if err != nil { 90 return nil, err 91 } 92 m.sourceName = sourceName 93 94 databaseName, err := databaseSchemeFromURL(databaseURL) 95 if err != nil { 96 return nil, err 97 } 98 m.databaseName = databaseName 99 100 sourceDrv, err := source.Open(sourceURL) 101 if err != nil { 102 return nil, err 103 } 104 m.sourceDrv = sourceDrv 105 106 databaseDrv, err := database.Open(databaseURL) 107 if err != nil { 108 return nil, err 109 } 110 m.databaseDrv = databaseDrv 111 112 return m, nil 113 } 114 115 // NewWithDatabaseInstance returns a new Migrate instance from a source URL 116 // and an existing database instance. The source URL scheme is defined by each driver. 117 // Use any string that can serve as an identifier during logging as databaseName. 118 // You are responsible for closing the underlying database client if necessary. 119 func NewWithDatabaseInstance(sourceURL string, databaseName string, databaseInstance database.Driver) (*Migrate, error) { 120 m := newCommon() 121 122 sourceName, err := schemeFromURL(sourceURL) 123 if err != nil { 124 return nil, err 125 } 126 m.sourceName = sourceName 127 128 m.databaseName = databaseName 129 130 sourceDrv, err := source.Open(sourceURL) 131 if err != nil { 132 return nil, err 133 } 134 m.sourceDrv = sourceDrv 135 136 m.databaseDrv = databaseInstance 137 138 return m, nil 139 } 140 141 // NewWithSourceInstance returns a new Migrate instance from an existing source instance 142 // and a database URL. The database URL scheme is defined by each driver. 143 // Use any string that can serve as an identifier during logging as sourceName. 144 // You are responsible for closing the underlying source client if necessary. 145 func NewWithSourceInstance(sourceName string, sourceInstance source.Driver, databaseURL string) (*Migrate, error) { 146 m := newCommon() 147 148 databaseName, err := schemeFromURL(databaseURL) 149 if err != nil { 150 return nil, err 151 } 152 m.databaseName = databaseName 153 154 m.sourceName = sourceName 155 156 databaseDrv, err := database.Open(databaseURL) 157 if err != nil { 158 return nil, err 159 } 160 m.databaseDrv = databaseDrv 161 162 m.sourceDrv = sourceInstance 163 164 return m, nil 165 } 166 167 // NewWithInstance returns a new Migrate instance from an existing source and 168 // database instance. Use any string that can serve as an identifier during logging 169 // as sourceName and databaseName. You are responsible for closing down 170 // the underlying source and database client if necessary. 171 func NewWithInstance(sourceName string, sourceInstance source.Driver, databaseName string, databaseInstance database.Driver) (*Migrate, error) { 172 m := newCommon() 173 174 m.sourceName = sourceName 175 m.databaseName = databaseName 176 177 m.sourceDrv = sourceInstance 178 m.databaseDrv = databaseInstance 179 180 return m, nil 181 } 182 183 func newCommon() *Migrate { 184 return &Migrate{ 185 GracefulStop: make(chan bool, 1), 186 PrefetchMigrations: DefaultPrefetchMigrations, 187 LockTimeout: DefaultLockTimeout, 188 isLockedMu: &sync.Mutex{}, 189 } 190 } 191 192 // Close closes the source and the database. 193 func (m *Migrate) Close() (source error, database error) { 194 databaseSrvClose := make(chan error) 195 sourceSrvClose := make(chan error) 196 197 m.logVerbosePrintf("Closing source and database\n") 198 199 go func() { 200 databaseSrvClose <- m.databaseDrv.Close() 201 }() 202 203 go func() { 204 sourceSrvClose <- m.sourceDrv.Close() 205 }() 206 207 return <-sourceSrvClose, <-databaseSrvClose 208 } 209 210 // Migrate looks at the currently active migration version, 211 // then migrates either up or down to the specified version. 212 func (m *Migrate) Migrate(version uint) error { 213 if err := m.lock(); err != nil { 214 return err 215 } 216 217 curVersion, dirty, err := m.databaseDrv.Version() 218 if err != nil { 219 return m.unlockErr(err) 220 } 221 222 if dirty { 223 return m.unlockErr(ErrDirty{curVersion}) 224 } 225 226 ret := make(chan interface{}, m.PrefetchMigrations) 227 go m.read(curVersion, int(version), ret) 228 229 return m.unlockErr(m.runMigrations(ret)) 230 } 231 232 // Steps looks at the currently active migration version. 233 // It will migrate up if n > 0, and down if n < 0. 234 func (m *Migrate) Steps(n int) error { 235 if n == 0 { 236 return ErrNoChange 237 } 238 239 if err := m.lock(); err != nil { 240 return err 241 } 242 243 curVersion, dirty, err := m.databaseDrv.Version() 244 if err != nil { 245 return m.unlockErr(err) 246 } 247 248 if dirty { 249 return m.unlockErr(ErrDirty{curVersion}) 250 } 251 252 ret := make(chan interface{}, m.PrefetchMigrations) 253 254 if n > 0 { 255 go m.readUp(curVersion, n, ret) 256 } else { 257 go m.readDown(curVersion, -n, ret) 258 } 259 260 return m.unlockErr(m.runMigrations(ret)) 261 } 262 263 // Up looks at the currently active migration version 264 // and will migrate all the way up (applying all up migrations). 265 func (m *Migrate) Up() error { 266 if err := m.lock(); err != nil { 267 return err 268 } 269 270 curVersion, dirty, err := m.databaseDrv.Version() 271 if err != nil { 272 return m.unlockErr(err) 273 } 274 275 if dirty { 276 return m.unlockErr(ErrDirty{curVersion}) 277 } 278 279 ret := make(chan interface{}, m.PrefetchMigrations) 280 281 go m.readUp(curVersion, -1, ret) 282 return m.unlockErr(m.runMigrations(ret)) 283 } 284 285 // Down looks at the currently active migration version 286 // and will migrate all the way down (applying all down migrations). 287 func (m *Migrate) Down() error { 288 if err := m.lock(); err != nil { 289 return err 290 } 291 292 curVersion, dirty, err := m.databaseDrv.Version() 293 if err != nil { 294 return m.unlockErr(err) 295 } 296 297 if dirty { 298 return m.unlockErr(ErrDirty{curVersion}) 299 } 300 301 ret := make(chan interface{}, m.PrefetchMigrations) 302 go m.readDown(curVersion, -1, ret) 303 return m.unlockErr(m.runMigrations(ret)) 304 } 305 306 // Drop deletes everything in the database. 307 func (m *Migrate) Drop() error { 308 if err := m.lock(); err != nil { 309 return err 310 } 311 if err := m.databaseDrv.Drop(); err != nil { 312 return m.unlockErr(err) 313 } 314 return m.unlock() 315 } 316 317 // Run runs any migration provided by you against the database. 318 // It does not check any currently active version in database. 319 // Usually you don't need this function at all. Use Migrate, 320 // Steps, Up or Down instead. 321 func (m *Migrate) Run(migration ...*Migration) error { 322 if len(migration) == 0 { 323 return ErrNoChange 324 } 325 326 if err := m.lock(); err != nil { 327 return err 328 } 329 330 curVersion, dirty, err := m.databaseDrv.Version() 331 if err != nil { 332 return m.unlockErr(err) 333 } 334 335 if dirty { 336 return m.unlockErr(ErrDirty{curVersion}) 337 } 338 339 ret := make(chan interface{}, m.PrefetchMigrations) 340 341 go func() { 342 defer close(ret) 343 for _, migr := range migration { 344 if m.PrefetchMigrations > 0 && migr.Body != nil { 345 m.logVerbosePrintf("Start buffering %v\n", migr.LogString()) 346 } else { 347 m.logVerbosePrintf("Scheduled %v\n", migr.LogString()) 348 } 349 350 ret <- migr 351 go func(migr *Migration) { 352 if err := migr.Buffer(); err != nil { 353 m.logErr(err) 354 } 355 }(migr) 356 } 357 }() 358 359 return m.unlockErr(m.runMigrations(ret)) 360 } 361 362 // Force sets a migration version. 363 // It does not check any currently active version in database. 364 // It resets the dirty state to false. 365 func (m *Migrate) Force(version int) error { 366 if version < -1 { 367 return ErrInvalidVersion 368 } 369 370 if err := m.lock(); err != nil { 371 return err 372 } 373 374 if err := m.databaseDrv.SetVersion(version, false); err != nil { 375 return m.unlockErr(err) 376 } 377 378 return m.unlock() 379 } 380 381 // Version returns the currently active migration version. 382 // If no migration has been applied, yet, it will return ErrNilVersion. 383 func (m *Migrate) Version() (version uint, dirty bool, err error) { 384 v, d, err := m.databaseDrv.Version() 385 if err != nil { 386 return 0, false, err 387 } 388 389 if v == database.NilVersion { 390 return 0, false, ErrNilVersion 391 } 392 393 return suint(v), d, nil 394 } 395 396 // read reads either up or down migrations from source `from` to `to`. 397 // Each migration is then written to the ret channel. 398 // If an error occurs during reading, that error is written to the ret channel, too. 399 // Once read is done reading it will close the ret channel. 400 func (m *Migrate) read(from int, to int, ret chan<- interface{}) { 401 defer close(ret) 402 403 // check if from version exists 404 if from >= 0 { 405 if err := m.versionExists(suint(from)); err != nil { 406 ret <- err 407 return 408 } 409 } 410 411 // check if to version exists 412 if to >= 0 { 413 if err := m.versionExists(suint(to)); err != nil { 414 ret <- err 415 return 416 } 417 } 418 419 // no change? 420 if from == to { 421 ret <- ErrNoChange 422 return 423 } 424 425 if from < to { 426 // it's going up 427 // apply first migration if from is nil version 428 if from == -1 { 429 firstVersion, err := m.sourceDrv.First() 430 if err != nil { 431 ret <- err 432 return 433 } 434 435 migr, err := m.newMigration(firstVersion, int(firstVersion)) 436 if err != nil { 437 ret <- err 438 return 439 } 440 441 ret <- migr 442 go func() { 443 if err := migr.Buffer(); err != nil { 444 m.logErr(err) 445 } 446 }() 447 448 from = int(firstVersion) 449 } 450 451 // run until we reach target ... 452 for from < to { 453 if m.stop() { 454 return 455 } 456 457 next, err := m.sourceDrv.Next(suint(from)) 458 if err != nil { 459 ret <- err 460 return 461 } 462 463 migr, err := m.newMigration(next, int(next)) 464 if err != nil { 465 ret <- err 466 return 467 } 468 469 ret <- migr 470 go func() { 471 if err := migr.Buffer(); err != nil { 472 m.logErr(err) 473 } 474 }() 475 476 from = int(next) 477 } 478 479 } else { 480 // it's going down 481 // run until we reach target ... 482 for from > to && from >= 0 { 483 if m.stop() { 484 return 485 } 486 487 prev, err := m.sourceDrv.Prev(suint(from)) 488 if os.IsNotExist(err) && to == -1 { 489 // apply nil migration 490 migr, err := m.newMigration(suint(from), -1) 491 if err != nil { 492 ret <- err 493 return 494 } 495 ret <- migr 496 go func() { 497 if err := migr.Buffer(); err != nil { 498 m.logErr(err) 499 } 500 }() 501 502 return 503 504 } else if err != nil { 505 ret <- err 506 return 507 } 508 509 migr, err := m.newMigration(suint(from), int(prev)) 510 if err != nil { 511 ret <- err 512 return 513 } 514 515 ret <- migr 516 go func() { 517 if err := migr.Buffer(); err != nil { 518 m.logErr(err) 519 } 520 }() 521 522 from = int(prev) 523 } 524 } 525 } 526 527 // readUp reads up migrations from `from` limitted by `limit`. 528 // limit can be -1, implying no limit and reading until there are no more migrations. 529 // Each migration is then written to the ret channel. 530 // If an error occurs during reading, that error is written to the ret channel, too. 531 // Once readUp is done reading it will close the ret channel. 532 func (m *Migrate) readUp(from int, limit int, ret chan<- interface{}) { 533 defer close(ret) 534 535 // check if from version exists 536 if from >= 0 { 537 if err := m.versionExists(suint(from)); err != nil { 538 ret <- err 539 return 540 } 541 } 542 543 if limit == 0 { 544 ret <- ErrNoChange 545 return 546 } 547 548 count := 0 549 for count < limit || limit == -1 { 550 if m.stop() { 551 return 552 } 553 554 // apply first migration if from is nil version 555 if from == -1 { 556 firstVersion, err := m.sourceDrv.First() 557 if err != nil { 558 ret <- err 559 return 560 } 561 562 migr, err := m.newMigration(firstVersion, int(firstVersion)) 563 if err != nil { 564 ret <- err 565 return 566 } 567 568 ret <- migr 569 go func() { 570 if err := migr.Buffer(); err != nil { 571 m.logErr(err) 572 } 573 }() 574 from = int(firstVersion) 575 count++ 576 continue 577 } 578 579 // apply next migration 580 next, err := m.sourceDrv.Next(suint(from)) 581 if os.IsNotExist(err) { 582 // no limit, but no migrations applied? 583 if limit == -1 && count == 0 { 584 ret <- ErrNoChange 585 return 586 } 587 588 // no limit, reached end 589 if limit == -1 { 590 return 591 } 592 593 // reached end, and didn't apply any migrations 594 if limit > 0 && count == 0 { 595 ret <- os.ErrNotExist 596 return 597 } 598 599 // applied less migrations than limit? 600 if count < limit { 601 ret <- ErrShortLimit{suint(limit - count)} 602 return 603 } 604 } 605 if err != nil { 606 ret <- err 607 return 608 } 609 610 migr, err := m.newMigration(next, int(next)) 611 if err != nil { 612 ret <- err 613 return 614 } 615 616 ret <- migr 617 go func() { 618 if err := migr.Buffer(); err != nil { 619 m.logErr(err) 620 } 621 }() 622 from = int(next) 623 count++ 624 } 625 } 626 627 // readDown reads down migrations from `from` limitted by `limit`. 628 // limit can be -1, implying no limit and reading until there are no more migrations. 629 // Each migration is then written to the ret channel. 630 // If an error occurs during reading, that error is written to the ret channel, too. 631 // Once readDown is done reading it will close the ret channel. 632 func (m *Migrate) readDown(from int, limit int, ret chan<- interface{}) { 633 defer close(ret) 634 635 // check if from version exists 636 if from >= 0 { 637 if err := m.versionExists(suint(from)); err != nil { 638 ret <- err 639 return 640 } 641 } 642 643 if limit == 0 { 644 ret <- ErrNoChange 645 return 646 } 647 648 // no change if already at nil version 649 if from == -1 && limit == -1 { 650 ret <- ErrNoChange 651 return 652 } 653 654 // can't go over limit if already at nil version 655 if from == -1 && limit > 0 { 656 ret <- os.ErrNotExist 657 return 658 } 659 660 count := 0 661 for count < limit || limit == -1 { 662 if m.stop() { 663 return 664 } 665 666 prev, err := m.sourceDrv.Prev(suint(from)) 667 if os.IsNotExist(err) { 668 // no limit or haven't reached limit, apply "first" migration 669 if limit == -1 || limit-count > 0 { 670 firstVersion, err := m.sourceDrv.First() 671 if err != nil { 672 ret <- err 673 return 674 } 675 676 migr, err := m.newMigration(firstVersion, -1) 677 if err != nil { 678 ret <- err 679 return 680 } 681 ret <- migr 682 go func() { 683 if err := migr.Buffer(); err != nil { 684 m.logErr(err) 685 } 686 }() 687 count++ 688 } 689 690 if count < limit { 691 ret <- ErrShortLimit{suint(limit - count)} 692 } 693 return 694 } 695 if err != nil { 696 ret <- err 697 return 698 } 699 700 migr, err := m.newMigration(suint(from), int(prev)) 701 if err != nil { 702 ret <- err 703 return 704 } 705 706 ret <- migr 707 go func() { 708 if err := migr.Buffer(); err != nil { 709 m.logErr(err) 710 } 711 }() 712 from = int(prev) 713 count++ 714 } 715 } 716 717 // runMigrations reads *Migration and error from a channel. Any other type 718 // sent on this channel will result in a panic. Each migration is then 719 // proxied to the database driver and run against the database. 720 // Before running a newly received migration it will check if it's supposed 721 // to stop execution because it might have received a stop signal on the 722 // GracefulStop channel. 723 func (m *Migrate) runMigrations(ret <-chan interface{}) error { 724 for r := range ret { 725 726 if m.stop() { 727 return nil 728 } 729 730 switch r := r.(type) { 731 case error: 732 return r 733 734 case *Migration: 735 migr := r 736 737 // set version with dirty state 738 if err := m.databaseDrv.SetVersion(migr.TargetVersion, true); err != nil { 739 return err 740 } 741 742 if migr.Body != nil { 743 m.logVerbosePrintf("Read and execute %v\n", migr.LogString()) 744 if err := m.databaseDrv.Run(migr.BufferedBody); err != nil { 745 return err 746 } 747 } 748 749 // set clean state 750 if err := m.databaseDrv.SetVersion(migr.TargetVersion, false); err != nil { 751 return err 752 } 753 754 endTime := time.Now() 755 readTime := migr.FinishedReading.Sub(migr.StartedBuffering) 756 runTime := endTime.Sub(migr.FinishedReading) 757 758 // log either verbose or normal 759 if m.Log != nil { 760 if m.Log.Verbose() { 761 m.logPrintf("Finished %v (read %v, ran %v)\n", migr.LogString(), readTime, runTime) 762 } else { 763 m.logPrintf("%v (%v)\n", migr.LogString(), readTime+runTime) 764 } 765 } 766 767 default: 768 return fmt.Errorf("unknown type: %T with value: %+v", r, r) 769 } 770 } 771 return nil 772 } 773 774 // versionExists checks the source if either the up or down migration for 775 // the specified migration version exists. 776 func (m *Migrate) versionExists(version uint) (result error) { 777 // try up migration first 778 up, _, err := m.sourceDrv.ReadUp(version) 779 if err == nil { 780 defer func() { 781 if errClose := up.Close(); errClose != nil { 782 result = multierror.Append(result, errClose) 783 } 784 }() 785 } 786 if os.IsExist(err) { 787 return nil 788 } else if !os.IsNotExist(err) { 789 return err 790 } 791 792 // then try down migration 793 down, _, err := m.sourceDrv.ReadDown(version) 794 if err == nil { 795 defer func() { 796 if errClose := down.Close(); errClose != nil { 797 result = multierror.Append(result, errClose) 798 } 799 }() 800 } 801 if os.IsExist(err) { 802 return nil 803 } else if !os.IsNotExist(err) { 804 return err 805 } 806 807 return os.ErrNotExist 808 } 809 810 // stop returns true if no more migrations should be run against the database 811 // because a stop signal was received on the GracefulStop channel. 812 // Calls are cheap and this function is not blocking. 813 func (m *Migrate) stop() bool { 814 if m.isGracefulStop { 815 return true 816 } 817 818 select { 819 case <-m.GracefulStop: 820 m.isGracefulStop = true 821 return true 822 823 default: 824 return false 825 } 826 } 827 828 // newMigration is a helper func that returns a *Migration for the 829 // specified version and targetVersion. 830 func (m *Migrate) newMigration(version uint, targetVersion int) (*Migration, error) { 831 var migr *Migration 832 833 if targetVersion >= int(version) { 834 r, identifier, err := m.sourceDrv.ReadUp(version) 835 if os.IsNotExist(err) { 836 // create "empty" migration 837 migr, err = NewMigration(nil, "", version, targetVersion) 838 if err != nil { 839 return nil, err 840 } 841 842 } else if err != nil { 843 return nil, err 844 845 } else { 846 // create migration from up source 847 migr, err = NewMigration(r, identifier, version, targetVersion) 848 if err != nil { 849 return nil, err 850 } 851 } 852 853 } else { 854 r, identifier, err := m.sourceDrv.ReadDown(version) 855 if os.IsNotExist(err) { 856 // create "empty" migration 857 migr, err = NewMigration(nil, "", version, targetVersion) 858 if err != nil { 859 return nil, err 860 } 861 862 } else if err != nil { 863 return nil, err 864 865 } else { 866 // create migration from down source 867 migr, err = NewMigration(r, identifier, version, targetVersion) 868 if err != nil { 869 return nil, err 870 } 871 } 872 } 873 874 if m.PrefetchMigrations > 0 && migr.Body != nil { 875 m.logVerbosePrintf("Start buffering %v\n", migr.LogString()) 876 } else { 877 m.logVerbosePrintf("Scheduled %v\n", migr.LogString()) 878 } 879 880 return migr, nil 881 } 882 883 // lock is a thread safe helper function to lock the database. 884 // It should be called as late as possible when running migrations. 885 func (m *Migrate) lock() error { 886 m.isLockedMu.Lock() 887 defer m.isLockedMu.Unlock() 888 889 if m.isLocked { 890 return ErrLocked 891 } 892 893 // create done channel, used in the timeout goroutine 894 done := make(chan bool, 1) 895 defer func() { 896 done <- true 897 }() 898 899 // use errchan to signal error back to this context 900 errchan := make(chan error, 2) 901 902 // start timeout goroutine 903 timeout := time.After(m.LockTimeout) 904 go func() { 905 for { 906 select { 907 case <-done: 908 return 909 case <-timeout: 910 errchan <- ErrLockTimeout 911 return 912 } 913 } 914 }() 915 916 // now try to acquire the lock 917 go func() { 918 if err := m.databaseDrv.Lock(); err != nil { 919 errchan <- err 920 } else { 921 errchan <- nil 922 } 923 }() 924 925 // wait until we either receive ErrLockTimeout or error from Lock operation 926 err := <-errchan 927 if err == nil { 928 m.isLocked = true 929 } 930 return err 931 } 932 933 // unlock is a thread safe helper function to unlock the database. 934 // It should be called as early as possible when no more migrations are 935 // expected to be executed. 936 func (m *Migrate) unlock() error { 937 m.isLockedMu.Lock() 938 defer m.isLockedMu.Unlock() 939 940 if err := m.databaseDrv.Unlock(); err != nil { 941 // BUG: Can potentially create a deadlock. Add a timeout. 942 return err 943 } 944 945 m.isLocked = false 946 return nil 947 } 948 949 // unlockErr calls unlock and returns a combined error 950 // if a prevErr is not nil. 951 func (m *Migrate) unlockErr(prevErr error) error { 952 if err := m.unlock(); err != nil { 953 return NewMultiError(prevErr, err) 954 } 955 return prevErr 956 } 957 958 // logPrintf writes to m.Log if not nil 959 func (m *Migrate) logPrintf(format string, v ...interface{}) { 960 if m.Log != nil { 961 m.Log.Printf(format, v...) 962 } 963 } 964 965 // logVerbosePrintf writes to m.Log if not nil. Use for verbose logging output. 966 func (m *Migrate) logVerbosePrintf(format string, v ...interface{}) { 967 if m.Log != nil && m.Log.Verbose() { 968 m.Log.Printf(format, v...) 969 } 970 } 971 972 // logErr writes error to m.Log if not nil 973 func (m *Migrate) logErr(err error) { 974 if m.Log != nil { 975 m.Log.Printf("error: %v", err) 976 } 977 }