|
|
|
@ -50,15 +50,25 @@ storage.flushToStorage = (options, callback) => { |
|
|
|
|
flags = options.isDir ? 'r' : 'r+' |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Windows can't fsync (FlushFileBuffers) directories. We can live with this as it cannot cause 100% dataloss
|
|
|
|
|
// except in the very rare event of the first time database is loaded and a crash happens
|
|
|
|
|
if (flags === 'r' && (process.platform === 'win32' || process.platform === 'win64')) return callback(null) |
|
|
|
|
/** |
|
|
|
|
* Some OSes and/or storage backends (augmented node fs) do not support fsync (FlushFileBuffers) directories, |
|
|
|
|
* or calling open() on directories at all. Flushing fails silently in this case, supported by following heuristics: |
|
|
|
|
* + isDir === true |
|
|
|
|
* |-- open(<dir>) -> (err.code === 'EISDIR'): can't call open() on directories (eg. BrowserFS) |
|
|
|
|
* `-- fsync(<dir>) -> (errFS.code === 'EPERM' || errFS.code === 'EISDIR'): can't fsync directory: permissions are checked
|
|
|
|
|
* on open(); EPERM error should only occur on fsync incapability and not for general lack of permissions (e.g. Windows) |
|
|
|
|
* |
|
|
|
|
* We can live with this as it cannot cause 100% dataloss except in the very rare event of the first time |
|
|
|
|
* database is loaded and a crash happens. |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
fs.open(filename, flags, (err, fd) => { |
|
|
|
|
if (err) return callback(err) |
|
|
|
|
if (err) { |
|
|
|
|
return callback((err.code === 'EISDIR' && options.isDir) ? null : err) |
|
|
|
|
} |
|
|
|
|
fs.fsync(fd, errFS => { |
|
|
|
|
fs.close(fd, errC => { |
|
|
|
|
if (errFS || errC) { |
|
|
|
|
if ((errFS || errC) && !((errFS.code === 'EPERM' || errFS.code === 'EISDIR') && options.isDir)) { |
|
|
|
|
const e = new Error('Failed to flush to storage') |
|
|
|
|
e.errorOnFsync = errFS |
|
|
|
|
e.errorOnClose = errC |
|
|
|
|