Use transaction per operation in indexeddb.js, fix broken async tests in fs.stats.spec.js
Fixing for review comments Switch to RW or RO transaction per get/put/delete/clear, better error handling for try/catch cases Switch back to transaction-per-context for better atomic fs operations. Move _getObjectStore onto prototype
This commit is contained in:
parent
6d3cec89ee
commit
3650b798ed
|
@ -11,43 +11,57 @@ var indexedDB = global.indexedDB ||
|
||||||
global.msIndexedDB;
|
global.msIndexedDB;
|
||||||
|
|
||||||
function IndexedDBContext(db, mode) {
|
function IndexedDBContext(db, mode) {
|
||||||
var transaction = db.transaction(FILE_STORE_NAME, mode);
|
this.db = db;
|
||||||
this.objectStore = transaction.objectStore(FILE_STORE_NAME);
|
this.mode = mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IndexedDBContext.prototype._getObjectStore = function() {
|
||||||
|
if(this.objectStore) {
|
||||||
|
return this.objectStore;
|
||||||
|
}
|
||||||
|
|
||||||
|
var transaction = this.db.transaction(FILE_STORE_NAME, this.mode);
|
||||||
|
this.objectStore = transaction.objectStore(FILE_STORE_NAME);
|
||||||
|
return this.objectStore;
|
||||||
|
};
|
||||||
|
|
||||||
IndexedDBContext.prototype.clear = function(callback) {
|
IndexedDBContext.prototype.clear = function(callback) {
|
||||||
try {
|
try {
|
||||||
var request = this.objectStore.clear();
|
var objectStore = this._getObjectStore();
|
||||||
request.onsuccess = function(event) {
|
var request = objectStore.clear();
|
||||||
|
request.onsuccess = function() {
|
||||||
callback();
|
callback();
|
||||||
};
|
};
|
||||||
request.onerror = function(error) {
|
request.onerror = function(event) {
|
||||||
callback(error);
|
event.preventDefault();
|
||||||
|
callback(event.error);
|
||||||
};
|
};
|
||||||
} catch(e) {
|
} catch(err) {
|
||||||
callback(e);
|
callback(err);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
function _get(objectStore, key, callback) {
|
IndexedDBContext.prototype._get = function(key, callback) {
|
||||||
try {
|
try {
|
||||||
|
var objectStore = this._getObjectStore();
|
||||||
var request = objectStore.get(key);
|
var request = objectStore.get(key);
|
||||||
request.onsuccess = function onsuccess(event) {
|
request.onsuccess = function onsuccess(event) {
|
||||||
var result = event.target.result;
|
var result = event.target.result;
|
||||||
callback(null, result);
|
callback(null, result);
|
||||||
};
|
};
|
||||||
request.onerror = function onerror(error) {
|
request.onerror = function(event) {
|
||||||
callback(error);
|
event.preventDefault();
|
||||||
|
callback(event.error);
|
||||||
};
|
};
|
||||||
} catch(e) {
|
} catch(err) {
|
||||||
callback(e);
|
callback(err);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
IndexedDBContext.prototype.getObject = function(key, callback) {
|
IndexedDBContext.prototype.getObject = function(key, callback) {
|
||||||
_get(this.objectStore, key, callback);
|
this._get(key, callback);
|
||||||
};
|
};
|
||||||
IndexedDBContext.prototype.getBuffer = function(key, callback) {
|
IndexedDBContext.prototype.getBuffer = function(key, callback) {
|
||||||
_get(this.objectStore, key, function(err, arrayBuffer) {
|
this._get(key, function(err, arrayBuffer) {
|
||||||
if(err) {
|
if(err) {
|
||||||
return callback(err);
|
return callback(err);
|
||||||
}
|
}
|
||||||
|
@ -55,22 +69,24 @@ IndexedDBContext.prototype.getBuffer = function(key, callback) {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
function _put(objectStore, key, value, callback) {
|
IndexedDBContext.prototype._put = function(key, value, callback) {
|
||||||
try {
|
try {
|
||||||
|
var objectStore = this._getObjectStore();
|
||||||
var request = objectStore.put(value, key);
|
var request = objectStore.put(value, key);
|
||||||
request.onsuccess = function onsuccess(event) {
|
request.onsuccess = function onsuccess(event) {
|
||||||
var result = event.target.result;
|
var result = event.target.result;
|
||||||
callback(null, result);
|
callback(null, result);
|
||||||
};
|
};
|
||||||
request.onerror = function onerror(error) {
|
request.onerror = function(event) {
|
||||||
callback(error);
|
event.preventDefault();
|
||||||
|
callback(event.error);
|
||||||
};
|
};
|
||||||
} catch(e) {
|
} catch(err) {
|
||||||
callback(e);
|
callback(err);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
IndexedDBContext.prototype.putObject = function(key, value, callback) {
|
IndexedDBContext.prototype.putObject = function(key, value, callback) {
|
||||||
_put(this.objectStore, key, value, callback);
|
this._put(key, value, callback);
|
||||||
};
|
};
|
||||||
IndexedDBContext.prototype.putBuffer = function(key, uint8BackedBuffer, callback) {
|
IndexedDBContext.prototype.putBuffer = function(key, uint8BackedBuffer, callback) {
|
||||||
var buf;
|
var buf;
|
||||||
|
@ -79,21 +95,23 @@ IndexedDBContext.prototype.putBuffer = function(key, uint8BackedBuffer, callback
|
||||||
} else {
|
} else {
|
||||||
buf = uint8BackedBuffer.buffer;
|
buf = uint8BackedBuffer.buffer;
|
||||||
}
|
}
|
||||||
_put(this.objectStore, key, buf, callback);
|
this._put(key, buf, callback);
|
||||||
};
|
};
|
||||||
|
|
||||||
IndexedDBContext.prototype.delete = function(key, callback) {
|
IndexedDBContext.prototype.delete = function(key, callback) {
|
||||||
try {
|
try {
|
||||||
var request = this.objectStore.delete(key);
|
var objectStore = this._getObjectStore();
|
||||||
|
var request = objectStore.delete(key);
|
||||||
request.onsuccess = function onsuccess(event) {
|
request.onsuccess = function onsuccess(event) {
|
||||||
var result = event.target.result;
|
var result = event.target.result;
|
||||||
callback(null, result);
|
callback(null, result);
|
||||||
};
|
};
|
||||||
request.onerror = function(error) {
|
request.onerror = function(event) {
|
||||||
callback(error);
|
event.preventDefault();
|
||||||
|
callback(event.error);
|
||||||
};
|
};
|
||||||
} catch(e) {
|
} catch(err) {
|
||||||
callback(e);
|
callback(err);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -114,32 +132,35 @@ IndexedDB.prototype.open = function(callback) {
|
||||||
return callback();
|
return callback();
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: we're not using versioned databases.
|
try {
|
||||||
var openRequest = indexedDB.open(that.name);
|
// NOTE: we're not using versioned databases.
|
||||||
|
var openRequest = indexedDB.open(that.name);
|
||||||
|
|
||||||
// If the db doesn't exist, we'll create it
|
// If the db doesn't exist, we'll create it
|
||||||
openRequest.onupgradeneeded = function onupgradeneeded(event) {
|
openRequest.onupgradeneeded = function onupgradeneeded(event) {
|
||||||
var db = event.target.result;
|
var db = event.target.result;
|
||||||
|
|
||||||
if(db.objectStoreNames.contains(FILE_STORE_NAME)) {
|
if(db.objectStoreNames.contains(FILE_STORE_NAME)) {
|
||||||
db.deleteObjectStore(FILE_STORE_NAME);
|
db.deleteObjectStore(FILE_STORE_NAME);
|
||||||
}
|
}
|
||||||
db.createObjectStore(FILE_STORE_NAME);
|
db.createObjectStore(FILE_STORE_NAME);
|
||||||
};
|
};
|
||||||
|
|
||||||
openRequest.onsuccess = function onsuccess(event) {
|
openRequest.onsuccess = function onsuccess(event) {
|
||||||
that.db = event.target.result;
|
that.db = event.target.result;
|
||||||
callback();
|
callback();
|
||||||
};
|
};
|
||||||
openRequest.onerror = function onerror(error) {
|
openRequest.onerror = function onerror(event) {
|
||||||
callback(new Errors.EINVAL('IndexedDB cannot be accessed. If private browsing is enabled, disable it.'));
|
event.preventDefault();
|
||||||
};
|
callback(event.error);
|
||||||
|
};
|
||||||
|
} catch(err) {
|
||||||
|
callback(err);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
IndexedDB.prototype.getReadOnlyContext = function() {
|
IndexedDB.prototype.getReadOnlyContext = function() {
|
||||||
// Due to timing issues in Chrome with readwrite vs. readonly indexeddb transactions
|
return new IndexedDBContext(this.db, IDB_RO);
|
||||||
// always use readwrite so we can make sure pending commits finish before callbacks.
|
|
||||||
// See https://github.com/js-platform/filer/issues/128
|
|
||||||
return new IndexedDBContext(this.db, IDB_RW);
|
|
||||||
};
|
};
|
||||||
IndexedDB.prototype.getReadWriteContext = function() {
|
IndexedDB.prototype.getReadWriteContext = function() {
|
||||||
return new IndexedDBContext(this.db, IDB_RW);
|
return new IndexedDBContext(this.db, IDB_RW);
|
||||||
|
|
|
@ -25,7 +25,7 @@ describe('sh.ls and deep directory trees', function() {
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
}).timeout(15000);
|
||||||
|
|
||||||
it('should not crash when calling sh.ls() on wide directory layouts', function(done) {
|
it('should not crash when calling sh.ls() on wide directory layouts', function(done) {
|
||||||
var fs = util.fs();
|
var fs = util.fs();
|
||||||
|
@ -55,5 +55,5 @@ describe('sh.ls and deep directory trees', function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
}).timeout(15000);
|
||||||
});
|
});
|
||||||
|
|
|
@ -23,20 +23,26 @@ function IndexedDBTestProvider(name) {
|
||||||
return callback();
|
return callback();
|
||||||
}
|
}
|
||||||
|
|
||||||
// We have to force any other connections to close
|
|
||||||
// before we can delete a db.
|
|
||||||
if(that.provider.db) {
|
|
||||||
that.provider.db.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
var request = indexedDB.deleteDatabase(name);
|
|
||||||
function finished() {
|
function finished() {
|
||||||
that.provider = null;
|
that.provider = null;
|
||||||
_done = true;
|
_done = true;
|
||||||
callback();
|
callback();
|
||||||
}
|
}
|
||||||
request.onsuccess = finished;
|
|
||||||
request.onerror = finished;
|
try {
|
||||||
|
// We have to force any other connections to close
|
||||||
|
// before we can delete a db.
|
||||||
|
if(that.provider.db) {
|
||||||
|
that.provider.db.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
var request = indexedDB.deleteDatabase(name);
|
||||||
|
request.onsuccess = finished;
|
||||||
|
request.onerror = finished;
|
||||||
|
} catch(e) {
|
||||||
|
console.log("Failed to delete test database", e);
|
||||||
|
finished();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function init() {
|
function init() {
|
||||||
|
|
|
@ -7,11 +7,12 @@ describe('fs.stats', function() {
|
||||||
beforeEach(util.setup);
|
beforeEach(util.setup);
|
||||||
afterEach(util.cleanup);
|
afterEach(util.cleanup);
|
||||||
|
|
||||||
it('should be a function', function() {
|
it('should be a function', function(done) {
|
||||||
var fs = util.fs();
|
var fs = util.fs();
|
||||||
fs.stat('/', function(error, stats) {
|
fs.stat('/', function(error, stats) {
|
||||||
if(error) throw error;
|
if(error) throw error;
|
||||||
expect(stats.isFile).to.be.a('function');
|
expect(stats.isFile).to.be.a('function');
|
||||||
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -60,11 +61,12 @@ describe('fs.stats', function() {
|
||||||
beforeEach(util.setup);
|
beforeEach(util.setup);
|
||||||
afterEach(util.cleanup);
|
afterEach(util.cleanup);
|
||||||
|
|
||||||
it('should be a function', function() {
|
it('should be a function', function(done) {
|
||||||
var fs = util.fs();
|
var fs = util.fs();
|
||||||
fs.stat('/', function(error, stats) {
|
fs.stat('/', function(error, stats) {
|
||||||
if(error) throw error;
|
if(error) throw error;
|
||||||
expect(stats.isDirectory).to.be.a('function');
|
expect(stats.isDirectory).to.be.a('function');
|
||||||
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -113,19 +115,21 @@ describe('fs.stats', function() {
|
||||||
beforeEach(util.setup);
|
beforeEach(util.setup);
|
||||||
afterEach(util.cleanup);
|
afterEach(util.cleanup);
|
||||||
|
|
||||||
it('should be a function', function() {
|
it('should be a function', function(done) {
|
||||||
var fs = util.fs();
|
var fs = util.fs();
|
||||||
fs.stat('/', function(error, stats) {
|
fs.stat('/', function(error, stats) {
|
||||||
if(error) throw error;
|
if(error) throw error;
|
||||||
expect(stats.isBlockDevice).to.be.a('function');
|
expect(stats.isBlockDevice).to.be.a('function');
|
||||||
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return false', function() {
|
it('should return false', function(done) {
|
||||||
var fs = util.fs();
|
var fs = util.fs();
|
||||||
fs.stat('/', function(error, stats) {
|
fs.stat('/', function(error, stats) {
|
||||||
if(error) throw error;
|
if(error) throw error;
|
||||||
expect(stats.isBlockDevice()).to.be.false;
|
expect(stats.isBlockDevice()).to.be.false;
|
||||||
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -134,19 +138,21 @@ describe('fs.stats', function() {
|
||||||
beforeEach(util.setup);
|
beforeEach(util.setup);
|
||||||
afterEach(util.cleanup);
|
afterEach(util.cleanup);
|
||||||
|
|
||||||
it('should be a function', function() {
|
it('should be a function', function(done) {
|
||||||
var fs = util.fs();
|
var fs = util.fs();
|
||||||
fs.stat('/', function(error, stats) {
|
fs.stat('/', function(error, stats) {
|
||||||
if(error) throw error;
|
if(error) throw error;
|
||||||
expect(stats.isCharacterDevice).to.be.a('function');
|
expect(stats.isCharacterDevice).to.be.a('function');
|
||||||
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return false', function() {
|
it('should return false', function(done) {
|
||||||
var fs = util.fs();
|
var fs = util.fs();
|
||||||
fs.stat('/', function(error, stats) {
|
fs.stat('/', function(error, stats) {
|
||||||
if(error) throw error;
|
if(error) throw error;
|
||||||
expect(stats.isCharacterDevice()).to.be.false;
|
expect(stats.isCharacterDevice()).to.be.false;
|
||||||
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -155,11 +161,12 @@ describe('fs.stats', function() {
|
||||||
beforeEach(util.setup);
|
beforeEach(util.setup);
|
||||||
afterEach(util.cleanup);
|
afterEach(util.cleanup);
|
||||||
|
|
||||||
it('should be a function', function() {
|
it('should be a function', function(done) {
|
||||||
var fs = util.fs();
|
var fs = util.fs();
|
||||||
fs.stat('/', function(error, stats) {
|
fs.stat('/', function(error, stats) {
|
||||||
if(error) throw error;
|
if(error) throw error;
|
||||||
expect(stats.isSymbolicLink).to.be.a('function');
|
expect(stats.isSymbolicLink).to.be.a('function');
|
||||||
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -208,19 +215,21 @@ describe('fs.stats', function() {
|
||||||
beforeEach(util.setup);
|
beforeEach(util.setup);
|
||||||
afterEach(util.cleanup);
|
afterEach(util.cleanup);
|
||||||
|
|
||||||
it('should be a function', function() {
|
it('should be a function', function(done) {
|
||||||
var fs = util.fs();
|
var fs = util.fs();
|
||||||
fs.stat('/', function(error, stats) {
|
fs.stat('/', function(error, stats) {
|
||||||
if(error) throw error;
|
if(error) throw error;
|
||||||
expect(stats.isFIFO).to.be.a('function');
|
expect(stats.isFIFO).to.be.a('function');
|
||||||
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return false', function() {
|
it('should return false', function(done) {
|
||||||
var fs = util.fs();
|
var fs = util.fs();
|
||||||
fs.stat('/', function(error, stats) {
|
fs.stat('/', function(error, stats) {
|
||||||
if(error) throw error;
|
if(error) throw error;
|
||||||
expect(stats.isFIFO()).to.be.false;
|
expect(stats.isFIFO()).to.be.false;
|
||||||
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -229,19 +238,21 @@ describe('fs.stats', function() {
|
||||||
beforeEach(util.setup);
|
beforeEach(util.setup);
|
||||||
afterEach(util.cleanup);
|
afterEach(util.cleanup);
|
||||||
|
|
||||||
it('should be a function', function() {
|
it('should be a function', function(done) {
|
||||||
var fs = util.fs();
|
var fs = util.fs();
|
||||||
fs.stat('/', function(error, stats) {
|
fs.stat('/', function(error, stats) {
|
||||||
if(error) throw error;
|
if(error) throw error;
|
||||||
expect(stats.isSocket).to.be.a('function');
|
expect(stats.isSocket).to.be.a('function');
|
||||||
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return false', function() {
|
it('should return false', function(done) {
|
||||||
var fs = util.fs();
|
var fs = util.fs();
|
||||||
fs.stat('/', function(error, stats) {
|
fs.stat('/', function(error, stats) {
|
||||||
if(error) throw error;
|
if(error) throw error;
|
||||||
expect(stats.isSocket()).to.be.false;
|
expect(stats.isSocket()).to.be.false;
|
||||||
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue