New faster localStorage in Firefox 22

LocalStorage, simple web API to store persistent key/value pairs, is very favorite among web developers for its simplicity of use thanks its synchronous design.  But in current versions of Firefox is one of most serious culprits of UI janks.  The browser UI may simply stop reacting for a short time when localStorage data is written as well as read, mainly on mobile devices with poor flash memory performance.

A month ago I started rewrite of the DOM storage code in the Mozilla Platform from scratch.   Except the performance and memory consumption problems other motivation for it is simply a strong need for code cleanup.  The work on the new implementation is currently in stage of a pending review to get it into to the tree in mozilla bug 600307.  It's planned to land for Firefox 22, since 21 soon transits to the Aurora channel.

The main difference in the new implementation is that writes, but also reads, are completely moved to a background thread so it will not freeze your browser.  When a web content script touches localStorage it only works with a memory cache and UI then cannot be blocked on waiting for disk writes to complete.  All data changes are posted to and flushed in regular short intervals on the background I/O thread.

However, before localStorage can be used, data for the page origin has to be there - loaded into the memory cache.  I implemented an early pre-load of the data when we start navigation to a web page.  This is so far trivial:  when prefetch doesn't make it on time to load all data quickly enough, we block UI on access to localStorage until it is done.  There are obvious and less obvious reasons to load all the data:  if you want to read a key it simply needs to load from your disk first, but there is also quota usage checking when data are added or modified and StorageEvent providing the previous key value before modification.

So, there is still a room for more optimizations here I plan as a followup work to the core patch.  To shortly explain, prefetch on the background thread pushes localStorage keys and its values one by one to the cache.  Access to localStorage is blocked until all data is loaded.  To make that time as short as possible I plan following further optimizations:

  • Obviously, when reading a single key and that key is already in the cache, just provide it without waiting for the rest of the data to load.
  • However, when a key is not in the cache, we have two options: wait just for that one key to get loaded or, when WAL mode on the SQLite database connection is enabled, read just that one key synchronously from the database.  Both approaches, however, have to block the UI.  Fortunately, our telemetry data (that I must thank you all for submitting it!) shows that reads from the database are generally very fast even for a whole domain data.
  • When a key is about to write, we don't need to block, yet quota checking is the enemy here.  We must lower our demands on its precision slightly.  Other complication is the StorageEvent that has to fire after a data modification.  The event has to report the previous value of a modified key.  Fortunately, the StorageEvent can be asynchronous.  Hence, we can just fire it later after the key value has loaded from the database.

Before I jump to write these more changes I first want to collect telemetry data on which operation and for how long we still may block.

I wrote a fairly technical overview of how the whole new implementation works at this MDC document.

I want to thank Vladan Djeric for his help with this work.  He is the one to review that huge patch and he also gave me inspiration for some aspects of the new implementation, like WAL usage and task batching, through his work on intermediate localStorage optimization in bug 807021.

I've made an experimental Firefox Nightly build with my patch.  I intend to use it to get some first telemetry data.  If anyone is brave enough and wants to help improve, then feel free to install it as well, enable telemetry in about:telemetry and report any crashes that may happen.  I will sync these builds with latest Firefox Nightlies from time to time and expose links to them here.

Disclaimer: the patch didn't go though a code or security review, only through mozilla automated testing.  Any data loss is at your own risk!

The latest (updated fifth time) experimental builds based on Mar 15 2013 mozilla-central code can be found here: for Windows, Linux (64) and Mac.

Offline Application Cache Update console logs introduced in Firefox 19

Asking why your offline application cache manifest doesn't work in Firefox and have no way to figure out?  Not any more.  Now you can look in to the Error Console (the old fashion one) you open with Shift-Ctrl-J and check for logs I've recently added in bug 807501.  All these logs are under the Messages section.  When an update is internally invoked, there is always at least one message related to the processed cache manifest.

When an error during cache update occurs you can now see the reason:

 

When all goes well, i.e. Firefox has downloaded or updated your offline cache, you get:

  • Offline cache update done, URL=http://example.com/cache.manifest

And when you are sure you've changed your manifest to a new version, but offline cache doesn't update in Firefox, you can check for the following line:

  • Offline cache doesn't need to update, URL=http://example.com/cache.manifest

This means the manifest hasn't changed since the last time or that you didn't serve it with Cache-control: no-cache header.

Firefox can now upload files larger then 2GB!

Today I finished work from Makato Kato on patching Firefox (actually, the Gecko platform) to be able to upload files of an unlimited size.  The patch has today successfully landed on the mozilla-inbound integration branch.

This feature will be available in Firefox Nightly, which is in version 17 now, in one or two days, if, of course, nothing wrong happens.  Enjoy!

The patch was tested on a 64-bit Fedora Core 16 box running Apache x64 and PHP x64 with this 2GB limit patch applied.

Some technical notes, mainly for extension developers: the core change is in nsIInputStream and nsIScriptableInputStream.  In both result of the available() method has changed from long  to long long.

Offline Application Cache in Firefox

As the maintainer, I was asked to summarize issues with famous Offline Application Cache, so here it is.

Current status of how application cache is implemented in Firefox isn't perfect.  From both the user's point of view as well as developer's point of view.  Except web content, that didn't adopt this technology very widely, there are new consumers: Boot2Gecko and Open Web Apps support.  Time to return and improve.

The most important issues that may imply a spec update:

The prompt.

Most people (both users and developers) hate the prompt that pops up and needs to be accepted when a page or an app (I'll use the word "app" in the following text) wants to cache it self.  This is not that simple to remove because:

- If we accept automatically, we open potential for DoS attack on user's storage.  The limits for offline content are wider and there is a poor way of automatic eviction of offline cache from one's disk if we want to behave by the spec.

- Accepting allows persistent cookies.  In my opinion, more of a problem.

Deleting the cache is hard.

Until you visit the app's main page again, the cache has no chance to get off of your disk.  It can of course be deleted by Clear Recent History command (Shift-Ctrl-Del) and also somewhere deep in the Options dialog, but who does it?  So the cache may easily just waste disk capacity.

The space on user's disk dedicated to offline apps is large, so apps can pile.  We'd like to lower the space limit down, mainly on mobile.  It means to throw long time unused offline apps silently away sometimes.

Recently there had been introduced app "pinning".  "Pinned" apps are not removed automatically and have a separate (larger) disk space.  That sounds opposite, right?  But this opens space to turn common (unpinned) web apps to an intermediate layer.  To explain:

- Layer 1 - Web content HTTP cache (this is not offline app cache):  makes your browsing faster.  Quickly flows, old content is silently threw away, replaced with more recent and current.   The most recent news articles are cached here along with CSS of the page.

- Layer 2 - Offline application cache:  intended to cache only the "code", simpler said, persists "the machine", not the data flowing through it.  Design flaws prevent use of this level to improve caching to be more effective on usual web sites dayly used.  I believe the "make this available when browser is offline" bit haven't hit the target well.  This level should just behave closer to how HTTP cache works - i.e. automatically.

- Layer 3 - Pinned applications cache:  actually what the current spec for offline application cache is about, but even more persistent.  It can, because it will have a full user's consent - a prompt or some other obvious UX path such as an OWA installation.  This will be used for critical applications that need to be available also offline.

To sum: change the default offline application cache behavior to be more like a "flow" then a "room for old boxes".

(Not only) user's data saved by apps.

DOM storage (window.localStorage) and IndexedDB content written by an offline app is not deleted along with cookies when history is deleted.  The storage used by an app is understood as a storage for user's critical data, like documents, email concepts, calendar entries, whatever, stored locally.  That obviously cannot be deleted just by removing cookies.

This could however, when not accepted explicitly, be misused by a malicious site to store a very persistent cookies.  Users delete their cookies to get rid of tracking or to log out, not to delete their work.  If you want to delete any of these "very persistent" cookies, you have to delete all the app cached content and also your potentially critical data.

We may either remove support for such user data (I vote against!) or, do something of this:

- Split the 'allow offline caching' and 'allow user's documents' privileges.  Simply: when an app defines a manifest, cache it automatically, no prompt.  When that app wants to use some data persistent storage to e.g. save your document concept, prompt to get user's consent.  This doesn't allow tracking more then today, but I assume the prompt will appear in 90% of cases anyway.  At least localStorage is widely used.

- Expose a new web content API that an app may use to ask for e.g. a new IndexedDB or localStorage instance to write and read critical data like documents that must not be deleted w/o user's knowledge, or at least that simply as e.g. cookies.  User may be prompted to let the app use this API.  It may be similar to a selection of a file.  Also we can bind to user's identity managed by the browser.  New open area to design.

(Not) being up to date.

Offline cache content of an app now updates only after you visit the app's main page.  Only then we check whether the manifest of the cache has changed on the server.  If so, we download a new version.  The whole page then has to refresh to use the newer version.

This behavior is by the spec.  And has usability and also security implications since on the visit user may see and use the old content.  It updates on next visit only or after an explicit refresh.  So, you may always be one version late.

We want to change this to periodically check the manifest on the server.  This will ensure that on next visit you won't be bothered with reload and also will be using up to date content with all security issue fixed and so.

 

Making Firefox faster - see what happens inside!

Mozilla puts a lot of effort to make Firefox faster and smoother.  There is a lot of work made to find and optimize places of the code.  However, I can see that sometimes developers are a bit guessing what to actually fix.  I'm also part of this effort, so I decided to create a tool that would help with performance optimizations - a visualizer of all internal operations.

Profilers are nice but cannot always tell you well why UI of your app has been stuck for 2 seconds without an obvious reason.

In software so complex as Mozilla Platform and Firefox are a traditional profiler may not be able to help at all.  Lot of events are being cross-posted between event queues and a lot of operations are asynchronous - i.e. w/o an immediate result.  To find out what is actually slow is then hard.

My tool, on the other hand, can show you a pretty timeline with all events that have happened during Firefox run, what allows you to see where Firefox waits for a result too long ... and also why.

All the work is tracked in Mozilla bug 729182.

Click the screen shot to open the visualization tool real-time example.

mozilla visual profiler

(The example log is a load of edition.cnn.com web site)