@@ -1024,6 +1024,16 @@ func (db *DB) copyToShadowWAL(filename string) (newSize int64, err error) {
1024
1024
return 0 , fmt .Errorf ("last checksum: %w" , err )
1025
1025
}
1026
1026
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
+
1027
1037
// Seek to correct position on real wal.
1028
1038
if _ , err := r .Seek (origSize , io .SeekStart ); err != nil {
1029
1039
return 0 , fmt .Errorf ("real wal seek: %w" , err )
@@ -1034,7 +1044,6 @@ func (db *DB) copyToShadowWAL(filename string) (newSize int64, err error) {
1034
1044
// Read through WAL from last position to find the page of the last
1035
1045
// committed transaction.
1036
1046
frame := make ([]byte , db .pageSize + WALFrameHeaderSize )
1037
- var buf bytes.Buffer
1038
1047
offset := origSize
1039
1048
lastCommitSize := origSize
1040
1049
for {
@@ -1064,32 +1073,54 @@ func (db *DB) copyToShadowWAL(filename string) (newSize int64, err error) {
1064
1073
break
1065
1074
}
1066
1075
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
+ }
1069
1080
1070
1081
Tracef ("%s: copy-shadow: ok %s offset=%d salt=%x %x" , db .path , filename , offset , salt0 , salt1 )
1071
1082
offset += int64 (len (frame ))
1072
1083
1073
- // Flush to shadow WAL if commit record.
1084
+ // Update new size if written frame was a commit record.
1074
1085
newDBSize := binary .BigEndian .Uint32 (frame [4 :])
1075
1086
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 ()
1080
1087
lastCommitSize = offset
1081
1088
}
1082
1089
}
1083
1090
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.
1085
1116
if err := w .Sync (); err != nil {
1086
1117
return 0 , err
1087
1118
} else if err := w .Close (); err != nil {
1088
1119
return 0 , err
1089
1120
}
1090
1121
1091
1122
// Track total number of bytes written to WAL.
1092
- db .totalWALBytesCounter .Add (float64 (lastCommitSize - origSize ))
1123
+ db .totalWALBytesCounter .Add (float64 (walByteN ))
1093
1124
1094
1125
return lastCommitSize , nil
1095
1126
}
0 commit comments