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