The other day I compiled Firefox 3.5-beta4, and, apart from many improvements, I noticed that I am now affected by the infamous ‘hiccups’. Firefox will stall for seconds at a time on my poor netbook. Details on how this relates to the many fsync() calls made by the persistance layer (SQLite) can be found all over the net.
But I don’t want Firefox to stall and I don’t want to keep my harddisk awake with all these writes when I’m on battery power.
Luckily, both these problems go away if you put your Firefox profile on a ramdisk. There are numerous guides out there that save you from working out the details; I used this one from the Gentoo forums.
The guide uses cron to sync the (presumably) modified contents of the ramdisk – bookmarks, cookies, whatever – back to permanent storage (harddisk). You and I both know that while it’s often convenient to use cron, it’s not always the Right Way of Doing Things®. Why sync if nothing’s changed? I wrote a script that employs the inotify system to do the syncing only when necessary. You’ll find it in the forum thread I linked to earlier, but I post it here “ter lering ende vermaeck”. Depending on your browser there might be a vertical scrollbar at the bottom which lets you read up to the EOL’s ;-)
You can find the latest version at my public repo.
#!/bin/bash # Packfox, a tool to facilitate running Firefox with its profile stored # in RAM (tmpfs). Copyright 2008-2009 Wicher Minnaard, wicher@gavagai.eu . # Distributed under the WTFPL, http://smormedia.gavagai.nl/dist/packfox/COPYING # Latest version available at http://smormedia.gavagai.nl/dist/packfox/ # Change this to match your profile PROFILE=$(hostname) PFDIR="${HOME}/.mozilla/firefox" # Tar every .. seconds (regardless of changes) TMOUT="1800" # But not more often than every .. seconds (regardless of changes) TMMIN="60" # Regex for which files not to act on when they're changed. # Use inotifywait -m -e modify -e move -e create -e delete --exclude '(/Cache/)' -r your_profile_dir # and watch the output while browsing to determine which regex will be right for YOU. IEXCL="(.sqlite-journal$)|(\-log.txt$)|(cookies.sqlite$)|(sessionstore\-[0-9].js$)|(/weave/)|(/Cache/)" # Have you read everything and have you made the necessary adjustments? Then remove the line below ;-) echo "I should read the README and adjust the script variables before running this." && exit 2 # No user servicable parts below this line. TGT="${PFDIR}/${PROFILE}" # Global vars INOTYPID="" SLEEPPID="" PACKLOCK="" # Cleanup function terminate(){ # If we are the daemon and we get SIGINTed/SIGTERMed, kill our children # and if not already packing, do one last round of packing. if [ "$(basename ${0})" == "packfox-daemon" ] then if [ -n "${INOTYPID}" ]; then kill ${INOTYPID}; fi if [ -n "${SLEEPPID}" ]; then kill ${SLEEPPID}; fi if [ -z "${PACKLOCK}" ];then packup; fi exit fi } # For cleaning up trap terminate SIGINT SIGTERM # Suicide with goodbye note. If gxmessage is installed, use that. seppuku(){ echo "${1}" 1>&2 which gxmessage > /dev/null 2>&1 && gxmessage -nofocus -title "$(basename ${0})" "${1}" || xmessage "${1}" exit 2 } # Checks and setup test -d "${PFDIR}" || seppuku "Profile dir doesn't exist" if [ -z "$(mount -t tmpfs | grep -F "${TGT}" )" ] then mount "${PFDIR}/${PROFILE}" || seppuku "Mounting of profile's tmpfs failed. Check /etc/fstab and the output of 'dmesg'." fi test -f "${TGT}/.unpacked" || tar -xpf "${PFDIR}/${PROFILE}.packed.tar" -C "${PFDIR}" \ && touch "${TGT}/.unpacked" || seppuku "Error unpacking the profile tarball. You might want to use the backup tarball located in ${PFDIR}." # This tars up the profile packup(){ PACKLOCK="locked" cd "${PFDIR}" tar --exclude '.unpacked' -cpf "${PFDIR}/${PROFILE}.packed.tmp.tar" "${PROFILE}" mv "${PFDIR}/${PROFILE}.packed.tar" "${PFDIR}/${PROFILE}.packed.tar.old" mv "${PFDIR}/${PROFILE}.packed.tmp.tar" "${PFDIR}/${PROFILE}.packed.tar" PACKLOCK="" } # No daemon, just packing if [ "$(basename ${0})" == "packfox" ]; then packup; fi # The daemon loop if [ "$(basename ${0})" == "packfox-daemon" ] then which inotifywait >/dev/null 2>&1 || seppuku " You'll need the 'inotify-tools' package for this script. Get it at http://inotify-tools.sourceforge.net or from your distro's repos". while true do inotifywait -q -q -t ${TMOUT} -e modify -e move -e create -e delete --exclude "${IEXCL}" \ -r "${PFDIR}/${PROFILE}" & INOTYPID=${!} wait ${INOTYPID}; INOTIFYPID="" packup sleep ${TMMIN} & SLEEPPID=${!} wait ${SLEEPPID}; SLEEPPID="" done exit fi
Tags: code, en_GB, firefox, inotify, tmpfs —


thanks for the script.
here are a few problems I ran into:
gxmessage needs to be installed (it is not installed by default on Debian).
The title of the message could be set, like:
gxmessage -nofocus -title “$(basename ${0})” -center “${1}”
then I have huge (450M) google gears directory inside my profile.. this is my gmail for offline usage, and I cannot divert that path :(
argh, fixed gears moving it and putting back a symbolic link to its new location.
no hiccups anymore, yay!!!
thanks
Thanks for the tip on gxmessage, I’ll add that (soonish).
You might consider to exclude your gears directory with tar’s and inotify’s exclude options. Or maybe you’ve already done so ;-)
yes, tar and inotify was the easy part, but gears did not want to fit into tmpfs mount of 128M ;-)
btw, script also relies that the tar archive is there from the begining — this is not the case for the first time. The script would be more robust if it checked that instead of seppuku :)
Thanks for the feedback, Marius!
I’ve made a 0.2 (repo) in which I added some setup documentation so people don’t have to browse the topic in the Gentoo forums for clues.
And I added xmessage as a fallback for those who do not have gxmessage installed. And there was a bug in 0.1 caused by a typo in a variable (that’s what you get for programming in Bash).