@@ -1024,6 +1024,16 @@ func (db *DB) copyToShadowWAL(filename string) (newSize int64, err error) {
10241024 return 0 , fmt .Errorf ("last checksum: %w" , err )
10251025 }
10261026
1027+ // Write to a temporary shadow file.
1028+ tempFilename := filename + ".tmp"
1029+ defer os .Remove (tempFilename )
1030+
1031+ f , err := internal .CreateFile (tempFilename , db .fileInfo )
1032+ if err != nil {
1033+ return 0 , fmt .Errorf ("create temp file: %w" , err )
1034+ }
1035+ defer f .Close ()
1036+
10271037 // Seek to correct position on real wal.
10281038 if _ , err := r .Seek (origSize , io .SeekStart ); err != nil {
10291039 return 0 , fmt .Errorf ("real wal seek: %w" , err )
@@ -1034,7 +1044,6 @@ func (db *DB) copyToShadowWAL(filename string) (newSize int64, err error) {
10341044 // Read through WAL from last position to find the page of the last
10351045 // committed transaction.
10361046 frame := make ([]byte , db .pageSize + WALFrameHeaderSize )
1037- var buf bytes.Buffer
10381047 offset := origSize
10391048 lastCommitSize := origSize
10401049 for {
@@ -1064,32 +1073,54 @@ func (db *DB) copyToShadowWAL(filename string) (newSize int64, err error) {
10641073 break
10651074 }
10661075
1067- // Add page to the new size of the shadow WAL.
1068- buf .Write (frame )
1076+ // Write page to temporary WAL file.
1077+ if _ , err := f .Write (frame ); err != nil {
1078+ return 0 , fmt .Errorf ("write temp shadow wal: %w" , err )
1079+ }
10691080
10701081 Tracef ("%s: copy-shadow: ok %s offset=%d salt=%x %x" , db .path , filename , offset , salt0 , salt1 )
10711082 offset += int64 (len (frame ))
10721083
1073- // Flush to shadow WAL if commit record.
1084+ // Update new size if written frame was a commit record.
10741085 newDBSize := binary .BigEndian .Uint32 (frame [4 :])
10751086 if newDBSize != 0 {
1076- if _ , err := buf .WriteTo (w ); err != nil {
1077- return 0 , fmt .Errorf ("write shadow wal: %w" , err )
1078- }
1079- buf .Reset ()
10801087 lastCommitSize = offset
10811088 }
10821089 }
10831090
1084- // Sync & close.
1091+ // If no WAL writes found, exit.
1092+ if origSize == lastCommitSize {
1093+ return origSize , nil
1094+ }
1095+
1096+ walByteN := lastCommitSize - origSize
1097+
1098+ // Move to beginning of temporary file.
1099+ if _ , err := f .Seek (0 , io .SeekStart ); err != nil {
1100+ return 0 , fmt .Errorf ("temp file seek: %w" , err )
1101+ }
1102+
1103+ // Copy from temporary file to shadow WAL.
1104+ if _ , err := io .Copy (w , & io.LimitedReader {R : f , N : walByteN }); err != nil {
1105+ return 0 , fmt .Errorf ("write shadow file: %w" , err )
1106+ }
1107+
1108+ // Close & remove temporary file.
1109+ if err := f .Close (); err != nil {
1110+ return 0 , err
1111+ } else if err := os .Remove (tempFilename ); err != nil {
1112+ return 0 , err
1113+ }
1114+
1115+ // Sync & close shadow WAL.
10851116 if err := w .Sync (); err != nil {
10861117 return 0 , err
10871118 } else if err := w .Close (); err != nil {
10881119 return 0 , err
10891120 }
10901121
10911122 // Track total number of bytes written to WAL.
1092- db .totalWALBytesCounter .Add (float64 (lastCommitSize - origSize ))
1123+ db .totalWALBytesCounter .Add (float64 (walByteN ))
10931124
10941125 return lastCommitSize , nil
10951126}
0 commit comments