@@ -855,23 +855,73 @@ 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+ // Backup holds an in-progress backup context.
859+ type Backup struct {
860+ backup sqliteh.Backup
861+ src sqliteh.DB
862+ dst sqliteh.DB
863+ }
864+
865+ // NewBackup starts a new backup operation that will read from the SQLite
866+ // database srcConn, schema srcSchema, and write to the database dstConn, schema
867+ // dstSchema.
868+ // The database owned by dstConn will be locked for the duration, and must not
869+ // be modified by other connections or processes.
870+ // The database owned by srcConn will be read-locked during each call to Step,
871+ // but can otherwise be used normally. Applications must arrange to ensure that
872+ // there is mutual exclusion between queries and step calls on the source
873+ // connection.
874+ // If a different connection alters the source database during the backup, Step
875+ // will restart the backup process from the beginning, however if the source
876+ // connection alters the database, the backup can continue and will include
877+ // pages affected by the concurrent transactions.
878+ // Finish must be called on the returned backup object in order to free
879+ // resources consumed by the backup operation, even if errors occur during steps
880+ // of the backup process. Finish can also be called any time that Step is not
881+ // running in order to abort the backup.
882+ func NewBackup (dstConn SQLConn , dstSchema string , srcConn SQLConn , srcSchema string ) (* Backup , error ) {
883+ var b Backup
884+ err := DB (dstConn , func (dst sqliteh.DB ) error {
861885 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" )
886+ var err error
887+ b .src = src
888+ b .dst = dst
889+ b .backup , err = dst .BackupInit (dstSchema , src , srcSchema )
890+ return errWithMsg (dst , err , "Backup" )
875891 })
876892 })
893+ return & b , err
894+ }
895+
896+ // Step makes incremental progress toward a complete online backup. It performs
897+ // at most numPages of copies from the source database to the target database.
898+ //
899+ // Step may be called in between other queries on the source connection, so as
900+ // to concurrently to service traffic, however Step must not be called in
901+ // parallel with other queries on the source connection.
902+ //
903+ // Step may return more=true and non-fatal errors of either SQLITE_BUSY or
904+ // SQLITE_LOCKED, however either of these errors being returned likely indicate
905+ // that an external writer has modified the source database and there will be a
906+ // side effect that the backup will restart from the beginning on the next call
907+ // to Step.
908+ //
909+ // Progress is reported by the `remaining` and `pageCount` values. remaining is
910+ // the number of pages left to copy, and pageCount is the current number of
911+ // pages in total that must be copied. pageCount may change in size due to
912+ // writes that occur during the backup process.
913+ func (b * Backup ) Step (numPages int ) (more bool , remaining , pageCount int , err error ) {
914+ more , remaining , pageCount , err = b .backup .Step (numPages )
915+ err = errWithMsg (b .dst , err , "Step" )
916+ return
917+ }
918+
919+ // Finish frees up the backup object and any resources it consumes. It must be
920+ // called even if errors occured calling Step. If Step reports a fatal error,
921+ // Finish will also return the same error. Finish can be called at any time to
922+ // abort a backup operation early.
923+ func (b * Backup ) Finish () error {
924+ err := b .backup .Finish ()
925+ err = errWithMsg (b .dst , err , "Finish" )
926+ return err
877927}
0 commit comments