Closed
Bug 837141
Opened 12 years ago
Closed 5 months ago
horrible performance storing indexeddb blobs
Categories
(Core :: Storage: IndexedDB, defect, P5)
Tracking
()
RESOLVED
INCOMPLETE
People
(Reporter: ygutfreund, Unassigned)
References
()
Details
(Whiteboard: dom-lws-bugdash-triage)
Attachments
(2 files, 1 obsolete file)
User Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:18.0) Gecko/20100101 Firefox/18.0
Build ID: 20130116073211
Steps to reproduce:
This is a FYI, I am not demanding a fix (even if I could :-)
I have been doing some performance testing of indexedDB blobs. Backround: I a creating an offline map, that using PNG image tiles for a SLIPPY map.
Actual results:
FireFox is getting much worse performance than IE or Chrome
Results Offline blob cache for PNG slippy maps
Testing
171 PNG files (total of 3.2MB)
Platforms tested: Chrome v24, FireFox 18, IE 10
Should also work with Chrome & FF for Android
Fetch from web server
using XHR2 (supported on almost all browsers) for blob download from web server
I went with XHR2-Lib by Phil Parsons, which is very much like JQUERY .ajax()
https://github.com/p-m-p/xhr2-lib
Storage
IndexedDB for IE and FireFox
Chrome: Polyfill (blob stored using FileSystem API, reference kept in IndexedDB) polyfill
A Must read article on "How the browsers store IndexedDB data"
http://www.aaron-powell.com/web/indexeddb-storage
Note: FireFox uses SQLlite for the NOSQL IndexedDB. That might be the reason for the slow performance. (blobs stored separately)
Note: Microsoft IE uses the extensible storage engine:
http://en.wikipedia.org/wiki/Extensible_Storage_Engine
Note: Chrome uses LevelDB http://code.google.com/p/leveldb/
Display
I am using Leaflet http://leafletjs.com/ to show the map tiles
I used the functional tile layer plugin by Ishmael Smyrnow for fetching the tile layer from the DB
https://github.com/ismyrnow/Leaflet.functionaltilelayer
I compared the DB-based tiles layer with a purely local (localhost://) storage
There is no noticeable difference in performance! between using IndexedDB and local files!
Results
Chrome: Fetch (6.551s), Store (8.247s), Total Elapsed Time: (13.714s)
FireFox: Fetch (0.422s), Store (31.519s), Total Elapsed Time: (32.836s)
IE 10: Fetch (0.668s), Store: (0.896s), Total Elapsed Time: (3.758s)
Expected results:
I would expect at least as good performance as Chrome, since both are storing the files outside of the DB in a filestore, and then placing a reference in the DB to the blob path.
But I am only providing this as a FYI for your aid. I am not looking for resolution.
Updated•12 years ago
|
Component: Untriaged → DOM: IndexedDB
Product: Firefox → Core
Comment 1•12 years ago
|
||
My first guess is that those files are not stored outside of SQLite database in Firefox .
Could you please send a code snippet how you store those blobs ?
Comment 2•12 years ago
|
||
I created a simple test, it creates 171 blobs (each 19623 bytes) and stores them in one transaction. Actual storing is instant on my computer (around 125 ms)
Comment 3•12 years ago
|
||
Ok, I also added storing of array buffers (stored in SQLite database) to the test and storing of buffers and blobs in separate transactions.
Storing of buffers in one transaction: 99ms
Storing of blobs in one transaction: 108ms
Storing of buffers in separate transactions: 721ms
Storing of blobs in separate transactions: 896ms
Note, I have an SSD disk
Slowness could also relate to handling of queued transactions, bug 776800
But 172 transactions seem not so many.
Attachment #709271 -
Attachment is obsolete: true
Comment 4•12 years ago
|
||
I ran those tests on Aurora 20.0a2
I'll try it with nigthly and Kyle's fix for bug 776800.
Comment 5•12 years ago
|
||
(In reply to Jan Varga [:janv] from comment #4)
> I ran those tests on Aurora 20.0a2
>
> I'll try it with nigthly and Kyle's fix for bug 776800.
Storing of buffers in one transaction: 112ms
Storing of blobs in one transaction: 122ms
Storing of buffers in separate transactions: 667ms
Storing of blobs in separate transactions: 824ms
So Kyle's patch doesn't helper here, numbers are similar and the difference is probably just a noise
Reporter | ||
Comment 6•12 years ago
|
||
I apologize for not following up on this. I was on travel with just an iPhone.
I am using identical code on FF, IE10, and Chrome. (the only hack is that Chrome does not handle a IndexedDB PUT of a binary blob (in my case a PNG). So I catch that and store it to the Chrome FileSystemAPI. But then FF does pretty much the same. It creates an entry in the SQLLite DB and then stores the blob as a file. (not visible to me).
All my PNGs are first fetched with an XHR2 request, and on the async completetion callback, I create a new transaction (for each PNG) and then do the put. In the code below, you will see that I first fetch a manifest (JSON file) which has the list of all the PNG files. It then does the XHR2 for each PNG file, and then does an transaction with a single PUT.
NOTE: the server is LOCALHOST. Which is a IIS 7.5 webserver running on the same Win7 box as the browser running Firefox.
What I am trying to understand is why FF is so much slower than IE10 or Chrome.
// executed when all js and css is loaded (i.e. document ready event)
var baseURL = "http://localhost/Poland/";
var fileList = null;
var blobList = [];
var loadTime = null;
var storeTime = null;
var ImageStore = null;
var ChromeFlag = false;
var DBVersion = 1;
var DBNAME = "BlobDB";
var DB = null;
var ImageStoreCnt = 0;
var showID = "12-2274-1388";
window.indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
function startDB() {
if (!window.indexedDB) {
window.alert("Your browser doesn't support a stable version of IndexedDB. Such and such feature will not be available.");
}
testXHR();
setup();
getManifest();
}
function testXHR() {
if ($xhr.supported()) {
$("#support").text("XHR2 Supported");
} else {
$("#support").text("XHR2 Missing");
}
}
function setup() {
$("#deleteDB").click(deleteDB);
$("#openDB").click(openDB);
$("#refillDB").click(clearStores);
ChromeFlag = navigator.userAgent.toLowerCase().indexOf('chrome') > -1;
$("#FSFlag").text(ChromeFlag.toString());
$xhr.defaultError(function (text, code) {
console.log("xhr error: " + code + ": ", text);
console.log("xhr url: ", this.xhr2data.url);
});
}
function getManifest() {
$xhr.ajax({
url: baseURL + "manifest.json",
dataType: "json",
success: parseManifest
});
}
function parseManifest(data) {
fileList = data.files;
$("#status").text("manifest loaded");
}
function openDB() {
var request = indexedDB.open(DBNAME, DBVersion);
request.onerror = function (event) {
console.log("Error opening database");
};
request.onsuccess = function (event) {
console.log("Success opening database");
DB = event.target.result;
DB.onerror = function (e) {
console.log("DB error: " + e.target.errorCode);
};
DB.onversionchange = function (e) {
e.target.close();
};
};
request.onupgradeneeded = function (event) {
console.log("VersionUpgrade: Adding Object Stores to Database");
DB = event.target.result;
DB.createObjectStore("Images");
};
if (ChromeFlag) openFS();
}
function deleteDB() {
if (DB != null) {
DB.close();
}
if (ChromeFlag) deleteImageDir();
var request = indexedDB.deleteDatabase(DBNAME);
request.onerror = function (event) {
console.log("Error deleting database");
};
request.onsuccess = function (event) {
console.log("Success deleting database");
};
}
function dbErrors(event) {
console.log("DB error: " + event.target.errorCode);
}
function clearStores() {
console.log("Clearing and Refilling Object Stores");
var trans, store;
trans = DB.transaction(["Images"], "readwrite");
store = trans.objectStore("Images");
store.clear();
trans.oncomplete = saveManifest;
}
function saveManifest() {
var trans, store, req;
loadTime = new Date();
trans = DB.transaction(["Images"], "readwrite");
store = trans.objectStore("Images");
req = store.put(fileList, "Manifest");
req.onsucess = getBlobs();
}
function getBlobs() {
console.log("starting to fetch blobs");
$.each(fileList, function (i, val) {
var path = baseURL + val.path;
$xhr.ajax({
url: path,
dataType: "blob",
success: function (data) { saveBlob(data, val.size, val.id); }
});
});
}
function saveBlob(blob, length, id) {
if (blob.size != length) {
console.log("Blob Length found: " + blob.size + " expected: " + length);
}
if (blobList.length == 0) {
storeTime = new Date();
}
blobList.push(id);
storeBlob(blob, id);
if (blobList.length == fileList.length) {
loadingComplete();
}
}
function storeBlob(blob, id) {
console.log("storing blob: " + id);
var trans, store, req;
trans = DB.transaction(["Images"], "readwrite");
store = trans.objectStore("Images");
var record = { id: id, blobFile: false };
if (ChromeFlag) {
record.blobFile = true;
record.path = id;
fileBlob(blob, id);
} else {
record.blob = blob;
}
req = store.put(record, id);
req.onsuccess = function (event) {
console.log("stored blob: " + id);
ImageStoreCnt++;
if (ImageStoreCnt == fileList.length) {
storeComplete();
}
};
}
function loadingComplete() {
var elapsed = new Date() - loadTime;
$("#totalTime").text((elapsed / 1000).toString() + " Get");
}
function storeComplete() {
console.log("Done Storing Tiles");
var elapsed = new Date() - loadTime;
$("#totalTime").text((elapsed / 1000).toString());
}
Reporter | ||
Comment 7•12 years ago
|
||
One other point. I have no doubt your test case works. But I think what I am trying to do is more realisitic. Which is to sync the data from a cloud "DB" to the local web based DB.
I can also tell you that the XHR2 requests finish just as fast on FireFox as they do on Chrome and IE10. (in fact FF is faster at .44s). What this points to is the overlapping IDB transactions.
But who would just generate artificial data in the browser and store it. More likely it comes from the web?
I am just trying to give input and feedback here. I am not making a political stand. I am hoping this is useful for your development.
Comment 8•12 years ago
|
||
Sure, that's all ok.
Could you take a look at https://developer.mozilla.org/en-US/docs/Performance/Profiling_with_the_Built-in_Profiler
Would you be able to do the profiling ?
Reporter | ||
Comment 9•12 years ago
|
||
Here is one profile log
Reporter | ||
Comment 10•12 years ago
|
||
I grabbed the nightly build as suggested, and then ran the profiler. I have a second log that is about 4.2MB which is too large to attach, but if you give me an email address I will send that also. (we have no way to post things for public urls).
Comment 11•12 years ago
|
||
jan dot varga at gmail dot com
Reporter | ||
Comment 12•12 years ago
|
||
sent.
Reporter | ||
Updated•12 years ago
|
Version: 18 Branch → 21 Branch
Reporter | ||
Comment 13•12 years ago
|
||
I have been doing some more work on this. I have created demo in CodePen (similar to jsFiddle, but nicer):
http://codepen.io/DrYSG/pen/hpqoD
Here is the write-up on what this demo does, and how to use it. Try it out on the latest FF builds. https://groups.google.com/forum/#!topic/pouchdb/RG6wUsAi2R0
You can see that even the latest version of FireFox have very poor performance for blob storage in indexedDB. This latest demo is using the PouchDB library to create a friendly API for indexedDB. But I don't see PouchDB as the issue. (see earlier comments on this issue).
Reporter | ||
Updated•12 years ago
|
Reporter | ||
Updated•11 years ago
|
Summary: performance of indexeddb blobs → horrible performance storing indexeddb blobs
Reporter | ||
Comment 14•11 years ago
|
||
I updated the title, to be more specific. It is specifically the save blob to IDB that is performing very poor compared to IE10 and Chrome. The Fetch is not that bad. If you go to http://gis.stackexchange.com/questions/62070/offline-slippy-map-tiles-database-for-leaflet/62073#62073 I describe in detail the system and the tests. You will see that after I store the blobs, I then display these blobs on a map. That seems to have fine performance (the fetch from IDB). I can also tell you that the XHR2 fetches for FireFox are slower than IE10 or Chrome, which you can also work at.
Comment 15•11 years ago
|
||
I don't think Chrome has support for storing files in IDB. AFAIK they are still working on it and the current implementation only stores a reference to the file or something like that. So you can't use Chrome for performance comparison.
Hm, maybe IE10 doesn't wait for files/blobs to be fully copied before the transaction is finished.
Reporter | ||
Comment 16•11 years ago
|
||
Chromium developers are actively working on Binary Blob support in IDB: http://code.google.com/p/chromium/issues/detail?id=108012 . But right now my demo uses PouchDB, which transforms to Base64, and then stores it in IDB (not a reference). So the size and performance for Chrome should be worse and binary blobs. It is not.
My timing and debug for IE10 shows that it is fully XHR2 and saving the blobs. (a different demo than the one mentioned above). IE10 has superb XHR2 and IDB performance (much better than Chrome), and I am working with the PouchDB folks to get it fully supported in PouchDB. See my prior tests with IE10 and raw IDB:
http://stackoverflow.com/questions/14113278/storing-image-data-for-offline-web-application-client-side-storage-database (last answer in the list).
Comment 17•11 years ago
|
||
Hm, could you change your code to use array buffers, so it won't be stored in Firefox as separate standalone files ?
I'm curious if it will make any difference.
Reporter | ||
Comment 18•11 years ago
|
||
It is a possibility. I would prefer this to be done either at the FF or PouchDB level. So that sort of experimentation is not my highest priority. Right now, I am thinking of deprecating FF support and focusing on Chrome.
Reporter | ||
Comment 19•11 years ago
|
||
Actually Jan, there is something slightly disturbing in what I reading here. But perhaps I am reading this entirely wrong.
Is what you are saying that JavaScript developers should be aware of the internals of how FF stores binary blobs?
Should they be writing javascript code that is customized for Chrome, Opera, IE10, and webkit? Or should they expect that since W3C says that binary blobs in IDB is part of the spec, that the browser should "do the right thing" and store the binary blob either as separate stand-alone files or as internal array buffers as a implementation decision.
Should these dependencies be written into the JavaScript code, what would happen when browsers change?
Or is the idea just to fork the CodePen and try something out? Which anyone can do?
Jan is asking you to test that and see if it makes any difference. That information may help us narrow down the bug. Nobody is expecting web developers to familiarize themselves with the implementation details of our blob storage code.
Comment 21•11 years ago
|
||
What Kyle said. I'm curious if the perf problem is mostly related to how we store blobs or if it is something else.
Reporter | ||
Comment 22•11 years ago
|
||
So, I did misunderstand. My apoligizes.
I will be on biz travel next week, so if anyone wants to FORK the CodePen and try that, feel free.
Reporter | ||
Updated•11 years ago
|
Version: 21 Branch → 23 Branch
Reporter | ||
Comment 23•11 years ago
|
||
I was able to hack PouchDB so that it will save the blobs as Base64 rather than as binary blobs. Performance is not any better. So it is not about how you store blobs alone. A re-write of PouchDB to use ArrayBuffers is beyond the scope of my funding.
At this point I am pretty well ready to declare FireFox broken for our customers, and since IE11 is vastly imporoved, I think that both it and Chrome will be sufficient.
Bye Bye FF
Blob Version:
http://codepen.io/DrYSG/pen/kdzft
Base64 version:
Reporter | ||
Comment 24•11 years ago
|
||
Oh yes, if you get xhr errors when the loop hits after about 40 good xhr fetch, IDB save interations, the source of the problem is most likely the fact that IE11 and Chrome both support SPDY (Google Drive) but Chrome does not.
I had to force all the xhr requests to run serially on FF. Another reason for my current displeasure with FF, in addition to the lack of a true non-sql IDB. I wish you folks well, but I for this app, I am telling our customers to use Chrome or IE.
(In reply to ygutfreund from comment #23)
> At this point I am pretty well ready to declare FireFox broken for our
> customers, and since IE11 is vastly imporoved, I think that both it and
> Chrome will be sufficient.
>
> Bye Bye FF
Sorry, childish statements like this is not helping you get attention to this bug. I understand if you feel the need to drop Firefox support, but that can certainly be done without unhelpful comments like the one above.
That said, it'd be great to have an actual testcase as an attachment here. The code in comment 6 looks great, but isn't a full testcase which can be run directly.
Also, you really should wait for the "commit" event on the transaction rather than the "success" event for each request. The data isn't guaranteed to have been written to disk when the request finishes, but it will have been written to disk when the "commit" event is fired. Though it's quite likely that this is *not* the problem and that there is a real Firefox issue here.
Comment 26•10 years ago
|
||
The profile (attachment 712950 [details]) seems not a correct one, how about the one sent offline at comment 12?
Updated•7 years ago
|
Priority: -- → P5
Updated•2 years ago
|
Severity: normal → S3
Updated•5 months ago
|
Status: UNCONFIRMED → RESOLVED
Closed: 5 months ago
Resolution: --- → INCOMPLETE
Whiteboard: dom-lws-bugdash-triage
You need to log in
before you can comment on or make changes to this bug.
Description
•