UNPKG

fd

Version:
101 lines (80 loc) 2.89 kB
const fs = require('fs') var totalOpenFds = 0 // across all instances // the reason we use a combination of path+fd to store references // in this._fds is that it is possible to have multiple fds // for the same file simultaneously. Particularly in the situation // where an fd is pending for a close but hasn't been checked back // in by all clients , key = function (path, fd) { return fd + ':' + path } , cleanupFd = function (path, fd) { // clear the use counter & close if pending delete this._fds[key(path, fd)] delete this._fds[path] if (this._pendingClose[key(path, fd)]) { fs.close(fd, function () {}) totalOpenFds-- delete this._pendingClose[key(path, fd)] } } , close = function (path, fd) { // dispose of this fd when possible this._pendingClose[key(path, fd)] = fd // nextTick needed to match the nextTick in an async-cache otherwise we may // close it in the tick prior to it being actually needed process.nextTick(function () { if (!this._fds[key(path, fd)]) cleanupFd.call(this, path, fd) }.bind(this)) } , open = function (path, cb) { // open a new fd // if the file is already open and in use but not with a close pending // then just use that. if (this._fds[path] && !this._pendingClose[key(path, this._fds[path])]) return cb(null, this._fds[path]) fs.open(path, 'r', function (er, fd) { if (!er) { totalOpenFds++ this._fds[path] = fd this._fds[key(path, fd)] = 0 } cb(er, fd) }.bind(this)) } , checkout = function (path, fd) { // call whenever you *may* be about to use the fd, to ensure it's not cleaned up this._fds[path] = fd this._fds[key(path, fd)] = (this._fds[key(path, fd)] || 0) + 1 } , checkin = function (path, fd) { // call sometime after checkout() when you know you're not using it if (this._fds[path] && --this._fds[key(path, fd)] === 0) cleanupFd.call(this, path, fd) } , checkinfn = function (path, fd) { // make a checkin function that can be safely called multiple times var called = false return function () { if (!called) { this.checkin(path, fd) called = true } }.bind(this) } , FDManager = { open : open , close : close , checkout : checkout , checkin : checkin , checkinfn : checkinfn } , create = function () { return Object.create(FDManager, { _fds : { value: Object.create(null) } , _pendingClose : { value: Object.create(null) } }) } module.exports = create module.exports._totalOpenFds = totalOpenFds