@@ -855,23 +855,52 @@ func DB(sqlconn SQLConn, fn func(sqliteh.DB) error) error {
855855 })
856856}
857857
858- // Backup backups the specified database from srcConn to dstConn.
859- func Backup (dstConn SQLConn , dstSchema string , srcConn SQLConn , srcSchema string ) error {
860- return DB (dstConn , func (dst sqliteh.DB ) error {
858+ type Backup struct {
859+ backup sqliteh.Backup
860+ src sqliteh.DB
861+ dst sqliteh.DB
862+ }
863+
864+ // NewBackup starts a new backup operation that will read from the SQLite
865+ // database srcConn, schema srcSchema, and write to the database dstConn, schema
866+ // dstSchema. SQLite backups can be efficient as long as `srcConn` is the only
867+ // writer to the database, if there are other writers the backup process will
868+ // restart on the next Step() after a write. Finish must be called on the
869+ // returned backup object in order to free resources consumed by the backup
870+ // operation, even if errors occur during steps of the backup process.
871+ func NewBackup (dstConn SQLConn , dstSchema string , srcConn SQLConn , srcSchema string ) (* Backup , error ) {
872+ var b Backup
873+ err := DB (dstConn , func (dst sqliteh.DB ) error {
861874 return DB (srcConn , func (src sqliteh.DB ) error {
862- b , err := dst .BackupInit (dstSchema , src , srcSchema )
863- if err != nil {
864- return errWithMsg (dst , err , "Backup" )
865- }
866- more := true
867- for more {
868- more , err = b .Step (1024 )
869- if err != nil {
870- b .Finish ()
871- return errWithMsg (dst , err , "Step" )
872- }
873- }
874- return errWithMsg (dst , b .Finish (), "Finish" )
875+ var err error
876+ b .src = src
877+ b .dst = dst
878+ b .backup , err = dst .BackupInit (dstSchema , src , srcSchema )
879+ return errWithMsg (dst , err , "Backup" )
875880 })
876881 })
882+ return & b , err
883+ }
884+
885+ // Step must be called repeatedly until it returns more=false. It may return
886+ // non-fatal busy or locked errors, which the applicaiton may wish to record for
887+ // tracking purposes. The SQLite docs suggest sleeping between calls to Step in
888+ // order to allow the application to make forward progress on other work.
889+ // numPages controls the desired amount of work performed per step. `remaining`
890+ // is the number of outstanding pages to be copied, and `pageCount` is the total
891+ // number of pages in the source database.
892+ func (b * Backup ) Step (numPages int ) (more bool , remaining , pageCount int , err error ) {
893+ more , remaining , pageCount , err = b .backup .Step (numPages )
894+ err = errWithMsg (b .dst , err , "Step" )
895+ return
896+ }
897+
898+ // Finish frees up the backup object and any resources it consumes. It must be
899+ // called even if errors occured calling Step. If Step reports a fatal error,
900+ // Finish will also return the same error. Finish can be called at any time to
901+ // abort a backup operation early.
902+ func (b * Backup ) Finish () error {
903+ err := b .backup .Finish ()
904+ err = errWithMsg (b .dst , err , "Finish" )
905+ return err
877906}
0 commit comments