| 258 | } |
| 259 | |
| 260 | func (lf *logFile) doneWriting(offset uint32) error { |
| 261 | // Sync before acquiring lock. (We call this from write() and thus know we have shared access |
| 262 | // to the fd.) |
| 263 | if err := lf.fd.Sync(); err != nil { |
| 264 | return errors.Wrapf(err, "Unable to sync value log: %q", lf.path) |
| 265 | } |
| 266 | |
| 267 | // Before we were acquiring a lock here on lf.lock, because we were invalidating the file |
| 268 | // descriptor due to reopening it as read-only. Now, we don't invalidate the fd, but unmap it, |
| 269 | // truncate it and remap it. That creates a window where we have segfaults because the mmap is |
| 270 | // no longer valid, while someone might be reading it. Therefore, we need a lock here again. |
| 271 | lf.lock.Lock() |
| 272 | defer lf.lock.Unlock() |
| 273 | |
| 274 | // Unmap file before we truncate it. Windows cannot truncate a file that is mmapped. |
| 275 | if err := lf.munmap(); err != nil { |
| 276 | return errors.Wrapf(err, "failed to munmap vlog file %s", lf.fd.Name()) |
| 277 | } |
| 278 | |
| 279 | // TODO: Confirm if we need to run a file sync after truncation. |
| 280 | // Truncation must run after unmapping, otherwise Windows would crap itself. |
| 281 | if err := lf.fd.Truncate(int64(offset)); err != nil { |
| 282 | return errors.Wrapf(err, "Unable to truncate file: %q", lf.path) |
| 283 | } |
| 284 | |
| 285 | // Reinitialize the log file. This will mmap the entire file. |
| 286 | if err := lf.init(); err != nil { |
| 287 | return errors.Wrapf(err, "failed to initialize file %s", lf.fd.Name()) |
| 288 | } |
| 289 | |
| 290 | // Previously we used to close the file after it was written and reopen it in read-only mode. |
| 291 | // We no longer open files in read-only mode. We keep all vlog files open in read-write mode. |
| 292 | return nil |
| 293 | } |
| 294 | |
| 295 | // You must hold lf.lock to sync() |
| 296 | func (lf *logFile) sync() error { |