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