Fix #258 - Queued fs calls hang when fs goes into error state due to provider.open error
This commit is contained in:
parent
3e9b77a37a
commit
84112410ba
|
@ -223,8 +223,8 @@ function FileSystem(options, callback) {
|
||||||
fs.readyState = FS_ERROR;
|
fs.readyState = FS_ERROR;
|
||||||
} else {
|
} else {
|
||||||
fs.readyState = FS_READY;
|
fs.readyState = FS_READY;
|
||||||
runQueued();
|
|
||||||
}
|
}
|
||||||
|
runQueued();
|
||||||
callback(error, fs);
|
callback(error, fs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -301,6 +301,13 @@ FileSystem.providers = providers;
|
||||||
var error = fs.queueOrRun(function() {
|
var error = fs.queueOrRun(function() {
|
||||||
var context = fs.provider.openReadWriteContext();
|
var context = fs.provider.openReadWriteContext();
|
||||||
|
|
||||||
|
// Fail early if the filesystem is in an error state (e.g.,
|
||||||
|
// provider failed to open.
|
||||||
|
if(FS_ERROR === fs.readyState) {
|
||||||
|
var err = new Errors.EFILESYSTEMERROR('filesystem unavailable, operation canceled');
|
||||||
|
return callback.call(fs, err);
|
||||||
|
}
|
||||||
|
|
||||||
// Wrap the callback so we can explicitly close the context
|
// Wrap the callback so we can explicitly close the context
|
||||||
function complete() {
|
function complete() {
|
||||||
context.close();
|
context.close();
|
||||||
|
|
|
@ -0,0 +1,89 @@
|
||||||
|
var Filer = require('../..');
|
||||||
|
var util = require('../lib/test-utils.js');
|
||||||
|
var expect = require('chai').expect;
|
||||||
|
var setImmediate = require('../../lib/async.js').setImmediate;
|
||||||
|
|
||||||
|
describe('Queued operations should error when fs is in error state, issue 258', function() {
|
||||||
|
var provider;
|
||||||
|
|
||||||
|
// Provider that does nothing but fail on open.
|
||||||
|
function FailingProviderContext(){}
|
||||||
|
FailingProviderContext.prototype.clear = function(callback) {
|
||||||
|
this.failCallback(callback);
|
||||||
|
};
|
||||||
|
FailingProviderContext.prototype.getObject =
|
||||||
|
FailingProviderContext.prototype.getBuffer = function(key, callback) {
|
||||||
|
this.failCallback(callback);
|
||||||
|
};
|
||||||
|
FailingProviderContext.prototype.putObject =
|
||||||
|
FailingProviderContext.prototype.putBuffer = function(key, value, callback) {
|
||||||
|
this.failCallback(callback);
|
||||||
|
};
|
||||||
|
FailingProviderContext.prototype.delete = function(key, callback) {
|
||||||
|
this.failCallback(callback);
|
||||||
|
};
|
||||||
|
|
||||||
|
function FailingProvider() {
|
||||||
|
var self = this;
|
||||||
|
self.name = 'failure';
|
||||||
|
self.open = function(callback) {
|
||||||
|
// Wait until caller tells us to fail
|
||||||
|
self.failNow = function() {
|
||||||
|
self.failCallback(callback);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
self.failCallback = function(callback) {
|
||||||
|
setImmediate(function() {
|
||||||
|
callback(new Error);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
FailingProvider.prototype.getReadWriteContext =
|
||||||
|
FailingProvider.prototype.getReadWriteContext = function() {
|
||||||
|
return new FailingProviderContext();
|
||||||
|
};
|
||||||
|
|
||||||
|
beforeEach(function() {
|
||||||
|
provider = new FailingProvider();
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(function() {
|
||||||
|
provider = null;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should get EFILESYSTEMERROR errors on callbacks to queued operations on provider error', function(done) {
|
||||||
|
var errCount = 0;
|
||||||
|
var fs = new Filer.FileSystem({provider: provider});
|
||||||
|
|
||||||
|
function maybeDone(err) {
|
||||||
|
expect(err).to.exist;
|
||||||
|
expect(err.code).to.equal('EFILESYSTEMERROR');
|
||||||
|
errCount++;
|
||||||
|
|
||||||
|
if(errCount === 2) {
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Queue some fs operations, and expect them to fail
|
||||||
|
fs.mkdir('/tmp', maybeDone);
|
||||||
|
fs.writeFile('/file', 'data', maybeDone);
|
||||||
|
|
||||||
|
// Operations are queued, tell the provider to fail now.
|
||||||
|
provider.failNow();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should get EFILESYSTEMERROR errors on callbacks to queued operations after ready callback', function(done) {
|
||||||
|
var fs = new Filer.FileSystem({provider: provider}, function(err) {
|
||||||
|
expect(err).to.exist;
|
||||||
|
|
||||||
|
// Queue is drained, but new operations should also fail
|
||||||
|
fs.mkdir('/tmp', function(err) {
|
||||||
|
expect(err).to.exist;
|
||||||
|
expect(err.code).to.equal('EFILESYSTEMERROR');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
provider.failNow();
|
||||||
|
});
|
||||||
|
});
|
|
@ -72,4 +72,4 @@ require("./bugs/issue249");
|
||||||
require("./bugs/ls-depth-bug");
|
require("./bugs/ls-depth-bug");
|
||||||
require("./bugs/issue247.js");
|
require("./bugs/issue247.js");
|
||||||
require("./bugs/issue254.js");
|
require("./bugs/issue254.js");
|
||||||
|
require("./bugs/issue258.js");
|
||||||
|
|
Loading…
Reference in New Issue