<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Shawn Wilsher &#187; fsync</title>
	<atom:link href="http://shawnwilsher.com/archives/tag/fsync/feed" rel="self" type="application/rss+xml" />
	<link>http://shawnwilsher.com</link>
	<description></description>
	<lastBuildDate>Mon, 26 Jul 2010 17:36:19 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<item>
		<title>Session Restore Now Writes to Disk Off of the Main Thread</title>
		<link>http://shawnwilsher.com/archives/294</link>
		<comments>http://shawnwilsher.com/archives/294#comments</comments>
		<pubDate>Mon, 17 Aug 2009 19:47:28 +0000</pubDate>
		<dc:creator>Shawn Wilsher</dc:creator>
				<category><![CDATA[Mozilla]]></category>
		<category><![CDATA[asynchronous]]></category>
		<category><![CDATA[Firefox]]></category>
		<category><![CDATA[fsync]]></category>
		<category><![CDATA[performance]]></category>
		<category><![CDATA[session restore]]></category>
		<category><![CDATA[write]]></category>

		<guid isPermaLink="false">http://shawnwilsher.com/?p=294</guid>
		<description><![CDATA[Last week I landed bug 485976 which moves the writing and subsequent fsync (or flush on windows) call to a background thread. This should benefit all of our users, especially those with slower hard drives. Paul O&#8217;Shannessey has filed another bug that will reduce the amount of disk activity substantially more that will benefit our [...]]]></description>
			<content:encoded><![CDATA[<p>Last week I landed <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=485976" title="Move writing sessionstore.js off the main thread">bug 485976</a> which moves the writing and subsequent fsync (or flush on windows) call to a background thread.  This should benefit all of our users, especially those with slower hard drives.  <a href="http://zpao.com/">Paul O&#8217;Shannessey</a> has <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=508740" title="Use mozStorage for SessionStore">filed another bug</a> that will reduce the amount of disk activity substantially more that will benefit our users even more.</p>
<h3>Background</h3>
<p>Session restore writes out to disk very frequently &#8211; every ten seconds, in fact.  This behavior is controllable by the preference <a href="http://kb.mozillazine.org/Browser.sessionstore.interval"><code>browser.sessionstore.interval</code></a> for those who want to reduce that, but then you run the risk of not having all your data saved if you crash.  We really don&#8217;t want to reduce that time for our users.</p>
<p>The amount of data that is written out to disk by session restore scales linearly with the number of tabs and windows you have open.  The more you have, the more data has to be written out to disk, and the longer it is going to take.</p>
<p>As <a href="http://shawnwilsher.com/archives/168">we learned in the past with Places</a>, writing to disk and calling fsync can be painfully slow.  In session restore code, we are doing this very often <em>and</em> on the main thread.  Clearly, this is a bad thing.</p>
<h3>Process and Solution</h3>
<p>This section is a bit technical, so feel free to skip it. The short answer is “do not block the main thread while writing and flushing data to the hard drive.”</p>
<p>We wanted to address this problem as much as we could for Firefox 3.6.  In order to actually reduce the number of writes and fsync calls, we would have to heavily modify how session restore manages and writes its data.  That is a big change that we were not comfortable doing this late in the 3.6 cycle.  On top of that, we do not really have the manpower to do that change since the people who know that code well are working on other performance improvements for this release.  The simple solution for now then is to move our write and fsync calls off of the main thread.</p>
<p>Luckily, <a href="http://weblogs.mozillazine.org/bz/">Boris Zbarsky</a> had recently <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=482310" title=" Add an API to asynchronously copy data to an output stream">written a new API for JS consumers</a> to asynchronously copy an input stream to an output stream.  This API would work great for session restore!  We had to <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=508605" title="NetUtil.asyncCopy does not handle nsISafeOutputStreams correctly">fix one minor issue with the underlying code</a> not properly handling nsISafeOutputStreams (which make sure we fsync properly), but once that was done, <a href="https://bugzilla.mozilla.org/attachment.cgi?id=393074&#038;action=diff">the fix</a> was incredibly simple.</p>
]]></content:encoded>
			<wfw:commentRss>http://shawnwilsher.com/archives/294/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>More fsync and write Reduction</title>
		<link>http://shawnwilsher.com/archives/242</link>
		<comments>http://shawnwilsher.com/archives/242#comments</comments>
		<pubDate>Tue, 03 Mar 2009 23:30:52 +0000</pubDate>
		<dc:creator>Shawn Wilsher</dc:creator>
				<category><![CDATA[Mozilla]]></category>
		<category><![CDATA[DTrace]]></category>
		<category><![CDATA[Firefox]]></category>
		<category><![CDATA[fsync]]></category>
		<category><![CDATA[performance]]></category>
		<category><![CDATA[places]]></category>
		<category><![CDATA[write]]></category>

		<guid isPermaLink="false">http://shawnwilsher.com/?p=242</guid>
		<description><![CDATA[As you may or may not be aware, my personal mission as of late is to reduce the number of writes and fsyncs that Firefox makes, and move the ones that we do have to make off of the main thread. The primary target here has been Places, and the work is still continuing. The [...]]]></description>
			<content:encoded><![CDATA[<p>As you may or may not be aware, my personal mission as of late is to reduce the number of writes and fsyncs that Firefox makes, and move the ones that we do have to make off of the main thread.  The primary target here has been Places, and the work is still continuing.</p>
<p>The Firefox team has been focusing on <a href="https://wiki.mozilla.org/Firefox3.1/Sprints">code sprints</a> to get some small well scoped things done for Firefox 3.1 since we&#8217;ve got a bit more time.  My <a href="https://wiki.mozilla.org/Firefox3.1/Sprints/Places_Expiration_Performance_Refactoring" title="Places Expiration Performance Refactoring">latest sprint</a> can be found over in <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=480211" title="Stop expiring history on every page visit">bug 480211</a>, where I&#8217;ve removed a write and fsync that we used to do after every page visited.  If we had enough pages in history that were old enough, we would remove them from history.  We now do this off of the main thread, asynchronously at the same time we flush data from our temporary tables to our permanent ones.  The net result is the same number of writes and one less fsync.  Additionally, the write is no longer done on the main thread.</p>
<p>Sadly, I couldn&#8217;t measure any real-world performance gains with my <a href="http://shawnwilsher.com/archives/178">DTrace scripts</a> &#8211; in fact I saw no change during several different runs of Tp3 with various places.sqlite files.  It&#8217;s quite possible I did not have the conditions setup correctly to have pages expiring, and I could have spent a few more hours generating just the right places.sqlite file to demonstrate wins in the real world, but the theory behind the patch is pretty simple.  The gain is pretty obvious.</p>
<p>Just another drop in the bucket of performance wins for Firefox.  Stay tuned, as there is more to come!</p>
]]></content:encoded>
			<wfw:commentRss>http://shawnwilsher.com/archives/242/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>DTrace Awesomeness</title>
		<link>http://shawnwilsher.com/archives/178</link>
		<comments>http://shawnwilsher.com/archives/178#comments</comments>
		<pubDate>Thu, 16 Oct 2008 20:35:17 +0000</pubDate>
		<dc:creator>Shawn Wilsher</dc:creator>
				<category><![CDATA[Mozilla]]></category>
		<category><![CDATA[DTrace]]></category>
		<category><![CDATA[fsync]]></category>
		<category><![CDATA[places]]></category>
		<category><![CDATA[write]]></category>

		<guid isPermaLink="false">http://shawnwilsher.com/?p=178</guid>
		<description><![CDATA[Yesterday dietrich was telling me he was seeing a lot of writes to places.sqlite and places.sqlite-journal. I wanted to get good, hard data to see what was writing, and how often we were doing it. I figured this was a good option for DTrace, but I've had mixed experiences with it in the past. I [...]]]></description>
			<content:encoded><![CDATA[<p>Yesterday <a href="http://whoisi.com/p/594">dietrich</a> was telling me he was seeing a lot of writes to <code>places.sqlite</codE> and <code>places.sqlite-journal</code>.  I wanted to get good, hard data to see what was writing, and how often we were doing it.  I figured this was a good option for DTrace, but I've had mixed experiences with it in the past.  I first turned to Instruments on OS X, but that can't give you stacks for calls, so I had to dump it.</p>
<p>I talked to <a href="http://blog.mozilla.com/dolske/">dolske</a>, who happens to be the resident DTrace expert around here.  With his help, I was able to put together <a href="http://files.shawnwilsher.com/2008/10/16/writestacks.d">this little D script</a> to track writes to the files in question, and give me user stack traces so we know who is writing and when.  With this, we've figured out what was writing, and are working on how to make it write less as we speak.</p>
<p>DTrace really is an awesome tool, even if it can be a bit awkward to use from time to time.</p>
]]></content:encoded>
			<wfw:commentRss>http://shawnwilsher.com/archives/178/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>How to solve the fsync problem</title>
		<link>http://shawnwilsher.com/archives/172</link>
		<comments>http://shawnwilsher.com/archives/172#comments</comments>
		<pubDate>Thu, 28 Aug 2008 23:09:59 +0000</pubDate>
		<dc:creator>Shawn Wilsher</dc:creator>
				<category><![CDATA[Mozilla]]></category>
		<category><![CDATA[fsync]]></category>
		<category><![CDATA[places]]></category>

		<guid isPermaLink="false">http://shawnwilsher.com/?p=172</guid>
		<description><![CDATA[This is part four in a continuing series about how we are working around the slow fsync issue in Mozilla. Part one can be found here, part two here, and part three here. Boy, some of the initial planning to solve this problem has changed. I found several bugs in my triggers, which made my [...]]]></description>
			<content:encoded><![CDATA[<p>This is part four in a continuing series about how we are working around the slow fsync issue in Mozilla. <a href="http://shawnwilsher.com/archives/168">Part one can be found here</a>, <a href="http://shawnwilsher.com/archives/169">part two here</a>, and <a href="http://shawnwilsher.com/archives/170">part three here</a>.</p>
<p>Boy, some of the initial planning to solve this problem has changed.  I found several bugs in my triggers, which made my life not so fun.  Now if you google the word fsync, my website is the first result returned (scary!).  Never fear, however!  I have good news.  The places team has put together an experimental build that should help greatly.  Before I link to the build though, I have a warning:<br />
<strong style="font-variant:small-caps">Do not use your normal profile &#8211; crate a copy of it to test this build.  This build will modify the places database schema, and if you go back to a normal build, you will experience some strange behavior.</strong></p>
<p>With that out of the way, the <a href="https://build.mozilla.org/tryserver-builds/2008-08-28_11:12-sdwilsh@shawnwilsher.com-try-df9b4f955b9/">builds can be found here</a> and will be available for the next seven days.</p>
<p>Feedback is not only welcomed, but wanted.  You can track the overall progress of this task in <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=442967">bug 442967</a></p>
]]></content:encoded>
			<wfw:commentRss>http://shawnwilsher.com/archives/172/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Issues Issues&#8230;</title>
		<link>http://shawnwilsher.com/archives/170</link>
		<comments>http://shawnwilsher.com/archives/170#comments</comments>
		<pubDate>Wed, 06 Aug 2008 01:21:51 +0000</pubDate>
		<dc:creator>Shawn Wilsher</dc:creator>
				<category><![CDATA[Mozilla]]></category>
		<category><![CDATA[fsync]]></category>
		<category><![CDATA[places]]></category>

		<guid isPermaLink="false">http://shawnwilsher.com/?p=170</guid>
		<description><![CDATA[This is part three in a continuing series about how we are working around the slow fsync issue in Mozilla. Part one can be found here, and part two here. You may find the schema diagram of places to be a bit helpful when reading this post. timeless found an interesting flaw to my previous [...]]]></description>
			<content:encoded><![CDATA[<p>This is part three in a continuing series about how we are working around the slow fsync issue in Mozilla. <a href="http://shawnwilsher.com/archives/168">Part one can be found here</a>, and <a href="http://shawnwilsher.com/archives/169">part two here</a>. You may find the <a href="http://dietrich.ganx4.com/mozilla/places-erd.png">schema diagram of places</a> to be a bit helpful when reading this post.</p>
<p><a href="http://viper.haque.net/~timeless/blog/">timeless</a> found an interesting flaw to my previous proposal.  If you were to visit a page, delete it, and then visit another page not yet seen before, you will never see it in any of your queries.  When you flush out all the &#8220;deleted&#8221; things, it will go away forever (unless the ordering was a bit different than what I expect, but that&#8217;s besides the point).  This is because of our id selection algorithm used in the insertion triggers.</p>
<p>I ended up talking to dietrich on irc about this, and we decided that deleting isn&#8217;t a common case, so we should feel free to do the write (with the needed fsyncs) at that point.  As a result, our <code>view</code>s change, as well as a few of our triggers.</p>
<p><code>moz_places_view</code> now looks like this:</p>
<pre lang="sql">SELECT *
FROM moz_places_temp
UNION ALL
SELECT *
FROM moz_places
WHERE id NOT IN (SELECT id FROM moz_places_temp)
</pre>
<p>And <code>moz_historyvisits_view</code> now looks like this:</p>
<pre lang="sql">SELECT *
FROM moz_historyvisits_temp
UNION ALL
SELECT *
FROM moz_historyvisits
WHERE id NOT IN (SELECT id FROM moz_historyvisits_temp)
</pre>
<p>The trigger for deletion on <code>moz_places_view</code> now looks like this:</p>
<pre lang="sql">CREATE TEMPORARY TRIGGER moz_places_view_delete_trigger
INSTEAD OF DELETE
ON moz_places_view
BEGIN
  DELETE FROM moz_places_temp
  WHERE id = OLD.id;
  DELETE FROM moz_places
  WHERE id = OLD.id;
END
</pre>
<p>Lastly, the trigger for deletion on <code>moz_historyvisits_view</code> now looks like this:</p>
<pre lang="sql">CREATE TEMPORARY TRIGGER moz_historyvisits_view_delete_trigger
INSTEAD OF DELETE
ON moz_historyvisits_view
BEGIN
  DELETE FROM moz_historyvisits_temp
  WHERE id = OLD.id;
  DELETE FROM moz_historyvisits
  WHERE id = OLD.id;
  UPDATE moz_places_view
  SET visit_count = visit_count - 1
  WHERE moz_places_view.id = OLD.place_id;
END
</pre>
<p>The net result is two fewer in-memory tables, and slightly less complicated view queries.  There isn&#8217;t much of a change with the triggers.</p>
<p>Many thanks to timeless for catching that.  If you have any other concerns or spot any issues, please let me know with a comment here, or feel free to <a href="mailto:me@shawnwilsher.com">send me an e-mail</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://shawnwilsher.com/archives/170/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>More details on the fsync solution</title>
		<link>http://shawnwilsher.com/archives/169</link>
		<comments>http://shawnwilsher.com/archives/169#comments</comments>
		<pubDate>Tue, 05 Aug 2008 16:58:38 +0000</pubDate>
		<dc:creator>Shawn Wilsher</dc:creator>
				<category><![CDATA[Mozilla]]></category>
		<category><![CDATA[fsync]]></category>
		<category><![CDATA[places]]></category>

		<guid isPermaLink="false">http://shawnwilsher.com/?p=169</guid>
		<description><![CDATA[This is part two in a continuing series about how we are working around the slow fsync issue in Mozilla. Part one can be found here. You may find the schema diagram of places to be a bit helpful when reading this post. Today I&#8217;d like to go over more details on how we plan [...]]]></description>
			<content:encoded><![CDATA[<p>This is part two in a continuing series about how we are working around the slow fsync issue in Mozilla.  <a href="http://shawnwilsher.com/archives/168">Part one can be found here</a>.  You may find the <a href="http://dietrich.ganx4.com/mozilla/places-erd.png">schema diagram of places</a> to be a bit helpful when reading this post.</p>
<p>Today I&#8217;d like to go over more details on how we plan to solve the fsync issue with regards to places.  This post is a bit heavy on technical details, but will go over how we plan to use views to abstract some of the hairier details out.  My goal is to get more eyes on the solution to spot any potential issues before I get too far along in the implementation.</p>
<p>In the last post, I mentioned that we&#8217;d need to setup tables to track deletions from the permanent tables that we have temporary tables for.  These are very straightforward, and only require one field each.  For <code>moz_places</code>, our table looks like this:</p>
<pre>moz_places_deleted
fk place_id</pre>
<p>And for <code>moz_historyvisits</code>, our table looks like this:</p>
<pre>moz_historyvisits_deleted
fk visit_id</pre>
<p>Now, I&#8217;ll take a look at our views.  The views will only be used for insertions, deletions, and updates.  We cannot use them for selection because the performance is quite bad.  The SQLite folks are working on this, but it will take some time before we can see that in release builds.  The <code>moz_places_view</code> looks like this:</p>
<pre lang="sql">SELECT *
FROM moz_places_temp
UNION ALL
SELECT *
FROM moz_places
WHERE id NOT IN (SELECT id FROM moz_places_temp)
AND id NOT IN (SELECT place_id FROM moz_places_deleted)
</pre>
<p>And <code>moz_historyvisits_view</code> looks very similar:</p>
<pre lang="sql">SELECT *
FROM moz_historyvisits_temp
UNION ALL
SELECT *
FROM moz_historyvisits
WHERE id NOT IN (SELECT id FROM moz_historyvisits_temp)
AND id NOT IN (SELECT visit_id FROM moz_historyvisits_deleted)
</pre>
<p>Each of these views has to have a few triggers created on it to allow for insertions, deletions, and updates.  The triggers for <code>moz_places_view</code> are a bit simpler, so we&#8217;ll start there.  Insertions are actually the easiest to manage.  All we have to do is add the data to the temp table, and we&#8217;ll be set:</p>
<pre lang="sql">CREATE TEMPORARY TRIGGER moz_places_view_insert_trigger
INSTEAD OF INSERT
ON moz_places_view
BEGIN
  INSERT INTO moz_places_temp
  VALUES (MAX((SELECT MAX(id) FROM moz_places_temp),
              (SELECT MAX(id) FROM moz_places)) + 1,
          NEW.url, NEW.title, NEW.user_title, NEW.rev_host,
          NEW.visit_count, NEW.hidden, NEW.typed, NEW.favicon_id);
END
</pre>
<p>However, when we do a deletion, we have a bit more work to do.  We have to cover the case where data was added to the temporary table, and the case where it only lives in the permanent table.  This isn&#8217;t terribly hard though, it turns out.  We just have to delete the record from the temporary table with the right <code>id</code>, and add that same <code>id</code> to <code>moz_places_deleted</code>:</p>
<pre lang="sql">CREATE TEMPORARY TRIGGER moz_places_view_delete_trigger
INSTEAD OF DELETE
ON moz_places_view
BEGIN
  DELETE FROM moz_places_temp
  WHERE id = OLD.id;
  INSERT INTO moz_places_deleted
  VALUES (OLD.id);
END
</pre>
<p>Updates are probably the most interesting.  If the data isn&#8217;t already in the temporary table, we need to get it there first.  However, we don&#8217;t want to overwrite any existing data in that table because it is more up-to-date than the data in the permanent one.  Regardless of Once we get that data into the temporary table, we can update it:</p>
<pre lang="sql">CREATE TEMPORARY TRIGGER moz_places_view_update_trigger
INSTEAD OF UPDATE
ON moz_places_view
BEGIN
  INSERT INTO moz_places_temp
  SELECT *
  FROM moz_places
  WHERE id = OLD.id
  AND id NOT IN (SELECT id FROM moz_places_temp);
  UPDATE moz_places_temp
  SET url = NEW.url,
      title = NEW.title,
      user_title = NEW.user_title,
      rev_host = NEW.rev_host,
      visit_count = NEW.visit_count,
      hidden = NEW.hidden,
      typed = NEW.typed,
      favicon_id = NEW.favicon_id;
END
</pre>
<p>Like <code>moz_places_view</code>, <code>moz_historyvisits_view</code>&#8216;s insertions aren&#8217;t terrible.  There is one additional thing we need to worry about though.  Currently, places uses a trigger on insertions and deletions from <code>moz_historyvisits</code> that updates <code>moz_places.visit_count</code>.  That would involve a write, however, so we don&#8217;t want to do that.  Instead, we update <code>moz_places_view.visit_count</code> and let the view handle the details:</p>
<pre lang="sql">CREATE TEMPORARY TRIGGER moz_historyvisits_view_insert_trigger
INSTEAD OF INSERT
ON moz_historyvisits_view
BEGIN
  INSERT INTO moz_historyvisits_temp
  VALUES (MAX((SELECT MAX(id) FROM moz_historyvisits_temp),
              (SELECT MAX(id) FROM moz_historyvisits)) + 1,
          from_visit = NEW.from_visit,
          place_id = NEW.place_id,
          visit_date = NEW.visit_date,
          visit_type = NEW.visit_type,
          session = NEW.session);
  UPDATE moz_places_view
  SET visit_count = visit_count + 1
  WHERE moz_places_view_id = NEW.place_id;
END
</pre>
<p>Deletions also have to worry about the trigger.  Once again, we update <code>moz_places_view.visit_count</code> accordingly:</p>
<pre lang="sql">CREATE TEMPORARY TRIGGER moz_historyvisits_view_delete_trigger
INSTEAD OF DELETE
ON moz_historyvisits_view
BEGIN
  DELETE FROM moz_historyvisits_temp
  WHERE id = OLD.id;
  INSERT INTO moz_historyvisits_deleted
  VALUES (OLD.id);
  UPDATE moz_places_view
  SET visit_count = visit_count - 1
  WHERE moz_places_view.id = OLD.place_id;
END
</pre>
<p>We only have one case where we update <code>moz_historyvisits</code>, and I&#8217;m not even sure if it&#8217;s valid yet.  As a result, this trigger may not actually be needed.  The update trigger looks nearly identical to the on used for <code>moz_places</code>:</p>
<pre lang="sql">CREATE TEMPORARY TRIGGER moz_historyvisits_view_update_trigger
INSTEAD OF UPDATE
ON moz_historyvisits_view
BEGIN
  INSERT INTO moz_historyvisits_temp
  SELECT *
  FROM moz_historyvisits
  WHERE id = OLD.id
  AND id NOT IN (SELECT id FROM moz_historyvisits_temp);
  UPDATE moz_historyvisits_temp
  SET from_visit = NEW.from_visit,
      place_id = NEW.place_id,
      visit_date = NEW.visit_date,
      visit_type = NEW.visit_type,
      session = NEW.session;
END
</pre>
<p>That&#8217;s the detail-heavy plan so far.  If you have any concerns or spot any issues, please let me know with a comment here, or feel free to <a href="mailto:me@shawnwilsher.com">send me an e-mail</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://shawnwilsher.com/archives/169/feed</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>More on fsync</title>
		<link>http://shawnwilsher.com/archives/168</link>
		<comments>http://shawnwilsher.com/archives/168#comments</comments>
		<pubDate>Sat, 02 Aug 2008 04:40:17 +0000</pubDate>
		<dc:creator>Shawn Wilsher</dc:creator>
				<category><![CDATA[Mozilla]]></category>
		<category><![CDATA[fsync]]></category>
		<category><![CDATA[places]]></category>

		<guid isPermaLink="false">http://shawnwilsher.com/?p=168</guid>
		<description><![CDATA[You know that &#8220;fun&#8221; fsync bug we had with Firefox 3 that primarily hurt Linux? Well, turns out that it also hurts us with applications on solid state drives (like, Portable Firefox), which makes it even more &#8220;fun&#8221;. For Firefox 3, we checked in a patch that allows for people to change the default synchronous [...]]]></description>
			<content:encoded><![CDATA[<p>You know that &#8220;fun&#8221; <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=421482">fsync bug</a> we had with Firefox 3 that primarily hurt Linux?  Well, turns out that it also hurts us with applications on solid state drives (like, <a href="http://portableapps.com/apps/internet/firefox_portable">Portable Firefox</a>), which makes it even more &#8220;fun&#8221;.  For Firefox 3, we checked in a patch that allows for people to change the default <a href="http://sqlite.org/pragma.html#pragma_synchronous">synchronous setting that SQLite uses</a> when a database connection is opened.  This was really just a stopgap measure.  I&#8217;ve spent the last month coming up with real solutions to the problem, and I think I&#8217;ve finally got one that will greatly help the issue, and not regress our current performance.</p>
<p>The basic idea of this plan is to reduce the number of times we write to the most active tables in places &#8211; <code>moz_places</code> and <code>moz_history_visits</code>.  In order to accomplish this, we need to set up temporary tables that live in memory (to avoid the writes) that shadow these two tables.  Every so often (time to be determined), we&#8217;ll need to write out the temporary tables to their permanent ones living on disk.  In order to prevent the UI from hanging, we&#8217;ll have to do this on a background thread.  I&#8217;ve already got patches up to <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=448476">make mozIStorageConnection threadsafe</a> so we can use a connection object on more than one thread, and to get a <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=429988">background thread setup for places to use</a>.</p>
<p>The solution is a bit more complicated than this, since we&#8217;ll also have to keep track of entries that we want to delete and flush those when we write everything out as well.  The table that keeps track of entries to delete would also have to live in memory so we don&#8217;t write and fsync.  The good news is that this only manages to regress performance by about 3.2 x 10<sup>-6</sup>% in my testing, which is something I think we can take.</p>
<p>There is a cost to this plan though.  Any query to the places database is going to get a lot hairier to accomplish to get the most recent data.  This is because you have to query against both the temporary and the permanent tables.  Essentially, any time you want to select from <code>moz_places</code>, you have to use a subselect instead of just the table name that looks something like this:</p>
<pre lang="sql">FROM (
  SELECT * FROM moz_places_tmp
  WHERE url IN (:test)
  UNION All
  SELECT * FROM moz_places
  WHERE url IN (:test)
  AND +id IN (SELECT id FROM moz_places_tmp)
) AS h</pre>
<p>That doesn&#8217;t even include the bits for deleting an entry, which complicates it a bit more still.</p>
<p>Some of this abstraction can sit behind a view with triggers setup so the code can be simple.  The trigger will handle all the details.  I&#8217;ve put enough thought into this to know that it&#8217;s doable, but haven&#8217;t figured out the exact triggers that are needed as of yet.</p>
<p>I&#8217;m ecstatic that I&#8217;ve finally got a viable solution to this issue.  I hope to get all the work done and reviewed in time for the next public release of Firefox 3.1 (be it an alpha, or a beta).  No bugs have been filed yet (other than the ones previously mentioned) since I haven&#8217;t figured out how I want to split the work up yet to make it easy to get reviewed.  That will all happen on Monday though, so stay tuned!</p>
]]></content:encoded>
			<wfw:commentRss>http://shawnwilsher.com/archives/168/feed</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
	</channel>
</rss>
