Skip to content
This repository has been archived by the owner on Feb 26, 2024. It is now read-only.

Commit

Permalink
fix:prevent hang during process exit due to tmp file cleanup (#542)
Browse files Browse the repository at this point in the history
* Remove extra graceful shutdown config

Fixes an issue introduced where graceful shutdown will
wait for all files to cleanup

* Fix issue where tmp has to clean up too many files

Co-authored-by: David Murdoch <davidmurdoch@users.noreply.github.com>
  • Loading branch information
davidmurdoch committed Jan 27, 2020
2 parents 9a4a991 + 80df7f8 commit c180f22
Showing 1 changed file with 40 additions and 21 deletions.
61 changes: 40 additions & 21 deletions lib/database/filedown.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ var async = require("async");
var fs = require("fs");
var path = require("path");
var tmp = require("tmp");
tmp.setGracefulCleanup();

util.inherits(FileDown, AbstractLevelDOWN);

Expand Down Expand Up @@ -37,6 +36,34 @@ const accessQueue = {
},
cache: {}
};

const fds = new Set();
const cleanup = (exit) => {
try {
fds.forEach((fdPath) => {
const [fd, path] = fdPath;
try {
fs.closeSync(fd);
} catch (e) {
// ignore
} finally {
try {
fs.unlinkSync(path);
} catch (e) {
// ignore
}
}
});
fds.clear();
} finally {
if (exit) {
process.exit(0);
}
}
};
process.on("SIGINT", cleanup);
process.on("exit", () => cleanup(false));

FileDown.prototype._put = function(key, value, options, callback) {
const lKey = path.join(this.location, key);
// This fixes an issue caused by writing AND reading the same key multiple times
Expand All @@ -52,46 +79,38 @@ FileDown.prototype._put = function(key, value, options, callback) {
// leveldb implementation that doesn't use a separate file for every key Soon(TM).
accessQueue.execute(lKey, () => {
// get a tmp file to write the contents to...
tmp.file((err, path, fd, cleanupTmpFile) => {
tmp.file({ keep: true }, (err, path, fd, cleanupTmpFile) => {
if (err) {
callback(err);
accessQueue.next(lKey);
return;
}
const pair = [fd, path];
fds.add(pair);
const cleanupAndCallback = (err) => {
err && cleanupTmpFile();
fds.delete(pair);
callback(err);
accessQueue.next(lKey);
};

// write the value to our temporary file
fs.writeFile(fd, value, "utf8", (err) => {
if (err) {
cleanupTmpFile();
callback(err);
accessQueue.next(lKey);
cleanupAndCallback(err);
return;
}

// It worked! Move the temporary file to its final destination
fs.rename(path, lKey, (err) => {
if (err) {
cleanupTmpFile();
callback(err);
accessQueue.next(lKey);
cleanupAndCallback(err);
return;
}

// make sure we close this file descriptor now that the file is no
// longer "temporary" (because we successfully moved it)
fs.close(fd, (err) => {
if (err) {
// at this point things seem to have worked, but juuuussttt in
// case `fs.close` fails, let's log some info so we can try to
// debug it
console.warn("An unexpected file descriptor close error occured: ", err);
cleanupTmpFile();
}
callback();

// if there is more work to be done on this key, do it.
accessQueue.next(lKey);
});
fs.close(fd, () => cleanupAndCallback());
});
});
});
Expand Down

0 comments on commit c180f22

Please sign in to comment.