MongoDB and GridFS versioning

December 28th, 2011 by VvanGemert

A few months ago we would still use Amazon’s S3 service to store Floorplanner’s designs in a XML based file, which we call FML (Floorplanner Markup Language). There were a few big issues with using this method. First of all, what happens when S3 goes down? We don’t have access to the data and our whole application will be useless. Another problem with S3 is that it’s slow, especially when using it inside a Rails action, because it’s using HTTP GET to retrieve the data.

For the future of Floorplanner we needed another solution to store the design files. After a lot research and trying out multiple file stores, XML and Document databases, we decided to go for MongoDB and in our case GridFS. MongoDB is a NoSQL document database and GridFS is a filesystem based on the document database principle. The best scenario would be to store our XML based files in a JSON format in MongoDB, so we can actually query all our designs on specific things like; which assets are most used; how many rooms does each project have on average.

In our situation this didn’t work well, we needed to parse the JSON code back to XML and from XML to JSON which is quiet heavy on the servers. Another problem is our own format, which relies on some hacks to make it work properly. Fortunately MongoDB provides an alternative to use, which is called GridFS (Grid File System). This way we’re able to add our FML files to Mongo and it allows us to make use of all the benefits Mongo has to offer. Mongo helps us to make our lives easier by using versioning, replication and increased speeds over S3.

Currently we are good with a Master/Slave replication, which was incredibly easy to set up (take that MySQL!). We had over 4 million files in our database and the slave was completely sync’d within a couple of hours. Although I do not encourage to do Master/Slave replication, it’s better to use Replica Sets, but it seems fine for our situation.

Versioning is build into GridFS by default. Every time you write a file with the same filename into GridFS it will be created as a new file and will also keep the old ones. If you retrieve the file it will get the lastest one. Now that’s magnificent and helps us by being able to retrieve old versions of designs if a users by accident clears his design and saves it for example. Versioning works by using the uploadDate timestamp. The lastest version is the one with the newest timestamp.

There is a fantastic Rails gem that helps us to use GridFS in just a few lines of code. There is just one little problem with that Ruby MongoDB driver gem. It doesn’t allow us to keep a limited number of versions. You can keep all the old versions or none at all, those are the two options. To solve this little issue I’ve created a monkey patch that allows you to keep a number of versions. In our system we store the last 10 designs to make sure our database size doesn’t grow out of control. But I’ve made it possible to set your own number of versions you want to keep.

# Monkey Patch for handling X number of versions
module Mongo
  class GridFileSystem
 
    def open(filename, mode, opts={})
      opts = opts.dup
      opts.merge!(default_grid_io_opts(filename))
      if opts[:versions] && mode == 'w'
        versions = opts[:versions] - 1
        opts.delete(:versions)
      end
      file = GridIO.new(@files, @chunks, filename, mode, opts)
      return file unless block_given?
      result = nil
      begin
        result = yield file
      ensure
        id = file.close
        unless versions.nil?
          self.delete do
            @files.find({'filename' => filename, '_id' => {'$ne' => id}}, :fields => ['_id'], :sort => ['uploadDate', -1], :skip => versions)
          end
        end
      end
      result
    end
 
  end
end

To use this monkey patch the syntax changes a little bit. There used to be a delete_old option, which I removed because you can also do this with the new versions option, by specifying 1 version. Here’s an example of how to use the new option:

# Writing a new version
versions = 10
@grid = Mongo::GridFileSystem.new(Mongo::Connection.new)
@grid.open("filename", "w", {:versions => versions}) do |f|
  f.write "filecontent"
end
 
# Reading the lastest version
file = @grid.open("filename", "r") {|f| f.read }

That’s how easy it is. To put back an older version I use the Mongo console to update the timestamp of the version I want to set back. If you have any questions or remarks add a comment or send me a email at: vincent [at] floorplanner.com.

Wrong event scope in Raphael.js (and jQuery)

December 14th, 2011 by Gert-Jan van der Wel

Raphaël is a small JavaScript library that should simplify your work with vector graphics on the web.

While playing around with this nice SVG JavaScript library Raphaël.js, I stumbled upon an issue with the event scope. Raphael doesn’t allow event handlers to run in any specific scope.

This is a problem when you want to work with its event system ‘eve()’ in combination with classes. The problem is that ‘this’ inside the called method, doesn’t refer to the class instance.

There is an easy workaround for it, something I remembered from the good ol’ ActionScript2 days. Just store the scope and use it when the event is triggered.

MyClass.function() {
  var scope = this;
  eve.on("DoSomethingEvent", function(event) {
    scope.doSomething(event);
  }  
}
 
MyClass.prototype {
  doSomething: function(event) {
    // use original 'this'
  }
}

jQuery has the same issue. You can use the same workaround in jQuery, but you can also use the jQuery.proxy() method.

$("#button").click($.proxy(function () {
     // use original 'this'
 },this));

Zooming in Flash Builder 4.6

November 3rd, 2011 by Gert-Jan van der Wel

In most of the apps I make there is some kind of zooming. Now that I’m playing around with the latest Flex SDK release, Flex 4.6 SDK, I need it again. So to keep myself from reinventing the wheel over and over again, I’m posting my (conceptual) zoom code here.

It’s using the TransformGestureEvent which is available for Flex Mobile Projects in Flash Builder 4.6.

view.addListener(TransformGestureEvent.GESTURE_ZOOM, onZoom);
 
private function onZoom(e:TransformGestureEvent):void {
  var bounds1:Rectangle = view.content.getBounds(view.stage);
 
  // scale the view
  view.scaleX *= e.scaleX;
  view.scaleY *= e.scaleY;
 
  var bounds2:Rectangle = view.content.getBounds(view.stage);
  var dx:Number = bounds2.x - bounds1.x;
  var dy:Number = bounds2.y - bounds1.y;
  var dw:Number = bounds2.width - bounds1.width;
  var dh:Number = bounds2.height - bounds1.height;
 
  // move the view to keep it centered while zooming
  view.x -= dx + dw/2;
  view.y -= dy + dh/2;
}

Floorplanner.com is hiring!

April 11th, 2011 by Gert-Jan van der Wel

Floorplanner was founded in 2007 with a mission to be the easiest, quickest, and best looking way to create and share interactive floor plans online. We are a small and highly innovative company based in Rotterdam, The Netherlands with a no nonsense attitude. We have over 2.5 million registered users and we are currently growing with almost 5000 new users every day.

We are building the new version of our 2D application with the latest technologies like HTML5, Flash (Molehill), WebGL etc and we are looking someone to join our efforts. If you are interested in building applications that are used by millions of people, you can contact me at gertjan [at] floorplanner.com

Canvas vs Canvas vs SVG performance on iPad

March 15th, 2011 by Gert-Jan van der Wel

Last week I created two simple tests to get some insights on the performance of Canvas and SVG on iDevices. The test is a blue square bouncing from left to right and back again, it’s repositioned every frame. The faster a browser can render a frame, the better the performance is on the device. Well.. at least in this particular case.

In the Canvas test, the scene is cleared (by using clearRect) and the square is drawn (using fillRect) at the new position. The SVG test draws the square once and only updates its x-coordinate.  Thanks to Tim Knip I found another way to move the square in Canvas using CSS3 3D Transforms. Since these transforms are hardware accelerated on iDevices, it’s interesting to see how Canvas using 3D transforms performs.

Device OS Browser Canvas (redraw) Canvas (3D transforms) SVG
iPhone 3Gs iOS 4.2 Safari 45 90 90
iPhone 4 iOS 4.2 Safari 30 92 80
iPad 1 iOS 4.2 Safari 90 90 95
Nexus 1 Android 2.2 V8 75 99 -

On the phones it seems that Canvas using 3D transforms is 2x faster than redrawing the Canvas. That’s a huge performance difference! On the iPad there is little to no difference.

Canvas vs SVG performance on iPad

March 7th, 2011 by Gert-Jan van der Wel

I’m doing a bit of HTML5 performance testing, specifically on the iPhone and iPad. When doing interactive stuff, it seems that most of the resources are used for updating the scene (clearing and drawing), and not so much by doing calculations in JavaScript.

I created two very simple tests to see if the performance is different using Canvas or SVG. It’s a fabulous blue cube bouncing up and down as fast as possible. The number of updates (frames) per second tells something about the performance. The higher the number the better the performance. This is definitely no scientific method of performance testing. It’s just an indication, but it’s something.

Here are my two tests, Canvas and SVG. The Canvas test clears and draws the square on its new position every interval (frame) by using clearRect and fillRect. The SVG test works a little different. The square is drawn once and its x-coordinate is updated every interval.

These are my findings so far:

Device OS Browser Canvas SVG
MBP OSX Leopard Chrome 8 230 230
iPhone 3G iOS 4.2 Safari 19 73
iPhone 3Gs iOS 4.2 Safari 45 90
iPhone 4 iOS 4.2 Safari 30 80
iPad 1 iOS 4.2 Safari 90 95
iPad 2 iOS 4.3 Safari 42 96
Nexus 1 Android 2.2 V8 75 -
HTC Desire Android 2.2 V8 75 -

I think it’s quite remarkable that my SVG test is twice as fast as my Canvas test on the iPhone (3Gs and 4). It’s strange to see that the iPhone 3Gs performs better than the iPhone 4. However, on the iPad 1 there is almost no difference. I’d love to compare the results of Android devices too, but Android doesn’t support SVG (yet?).

Merge sort in JavaScript

November 11th, 2010 by Gert-Jan van der Wel

Whenever I have a couple of minutes of spare time, I’m trying to learn more about algorithms . The first two algorithms were selection sort and insertion sort. Next up is merge sort.

Merge sort is a bit different than selection and insertion sort. Selection and insertion sort are based on a loop inside a loop. That way you compare each value of a collection (one by one) to all the other values in the collection and sort them. Both in slightly different way. As you can imagine, sorting with a loop inside a loop isn’t very fast, Θ(n^2) to be precise.

Merge sort attacks the problem in a different way. You could say that it’s based on the divide and conquer principal. It divides the problem in a bunch of tiny sub-problems, solves those problems and then combines them to get a result.

The divide step isn’t that difficult. It takes a collection and splits it in two (equally sized) halves. This step is repeated until the smallest collection size is reached, 1. It uses a recursive function to accomplish this, a function that calls itself.

var collection = [5, 2, 4, 7, 1, 3, 2, 6];
 
divide(collection, 0, collection.length-1);
 
// a: collection, p: start index, r: end index
function divide(a, p, r) {
	if(p < r) {
		var q = Math.floor((p + r)/2); // calc middle of collection
		divide(a, p, q);
    		divide(a, q + 1, r);
		merge(a, p, q, r);
	}
}

The conquer step is a bit tricker. It’s based on a function that is able to merge two sorted collections into a new sorted collection.

function merge(a, p, q, r) {
	var n1 = q - p + 1;
	var left = [];
	for(var i = 0; i < n1; i++) {
		left.push(a[p + i]);
	}
        left.push(Infinity);
 
	var n2 = r - q;
	var right = [];
	for(var j = 0; j < n2; j++) {
		right.push(a[q + j + 1]);
	}
	right.push(Infinity);
 
	var i = 0;
	var j = 0;
	for(var k = p; k < r+1; k++) {
		if(left[i] <= right[j]) {
			a[k] = left[i];
			i++;
		}
		else {
			a[k] = right[j];
			j++;
		}
	}
}

So, the collection is first divided into sub-collections with the size of one. Those sub-collections are then merged together. That’s done, step by step, by merging and sorting the small collections into a bigger collection. Combine collections with a size of one into sorted collections of a size of two, then combine them into sorted collections of 4 etc. until all sub-collections are merged.

Instead of having a loop inside a loop, you have a recursive divide function and a combining loop function. This results in a faster sorting than insertion or selection sort: Θ(nlgn).

Server-side PNG rendering of SWF images using Gnash

November 2nd, 2010 by Valentine Bichkovsky

The problem

We need to display thumbnails for 2D images, which are SWF files.

Option 1. Use embedded Flash

Pros:

  • quick drop-in solution;

Cons:

  • requirement for clients to have Flash installed in their browsers;
  • thumbnail displaying logic depends on what we are displaying (2D, 3D, photo) = additional complexity;
  • requires additional markup for embedding Flash;
  • is slow to load and display;
  • (the most important) embedded Flash object is not regular HTML-element and it puts some constraints on UI design (e.g. other HTML elements cannot be placed on top of rendered image).

Option 2. Manual rendering

SWF files are loaded into desktop Adobe AIR app, which produces PNG thumbnails and saves them where the client app can get them (default Paperclip paths in our case). This process can be made to work in batch mode, so there is no need to manually load, render and save each file.

Pros:

  • thumbnails are PNG files, so they can be dealt with as any other regular images on client side;

Cons:

  • requires dedicated machine with the AIR app;
  • when a user uploads an SWF file, it is not rendered at once, so we have to show him something else for visual feedback as we don’t have rendered image yet.

Option 3. Server-side rendering

The most logical and architecturally right option. Unfortunately, Flash player is proprietary software and there are no libraries or tools for this task. Nevertheless, it is possible, and I’ll explain how it can be done.

Solution

We are going to use Gnash player. Gnash is the GNU SWF movie player, which can be run standalone on the desktop or an embedded device, as well as as a plugin for several browsers (from http://www.gnashdev.org). It it has a feature named “dump-gui”, which allows to dump player’s output as raw video file and doesn’t require X or any GUI libraries to run, what makes it a good candidate for our task.

Step 1. Get Gnash

Gnash player has a package in many popular distributions, but it is compiled without the ‘dump’ option. Therefore, we need to configure and compile it from source. You can read about it here and here.

wget http://ftp.gnu.org/pub/gnu/gnash/0.8.8/gnash-0.8.8.tar.gz
./configure --enable-gui=gtk,dump
make
sudo make install

Here I’m configuring and compiling Gnash with both gtk and dump GUIs so that I could quickly check rendering results using gtk player. You won’t need it on server, of course.

Step 2. Render 2D images using SWF file as a player (supplying Flash parameters)

This step can be skipped if your swf file is displayed correctly in the player. In our case, if we run

gnash image_2d.swf

we will see only a part of an image, because image’s origin (x=0, y=0) is in the center of the image. To display it correctly, we will use another swf file named preview.swf, which, in its turn, loads and displays our 2D image. We need to supply file’s location using flash parameter named “url”. As different 2D images have different sizes, we’ll also use -j (width) and -k (height) parameters to generate large fixed size picture.

gnash preview.swf \
-P "FlashVars=url=file:///some/dir/image_2d.swf" -j 500 -k 500

Step 3. Deal with security settings

By default, preview.swf can only access files which are in or under the same directory as preview.swf. As on server side processing will take place in /tmp directory, while preview.swf will be located in the application’s directory, we need to configure Gnash to allow access to local files in /tmp. Create ~/.gnashrc file with this line:

set localSandboxPath /tmp

Step 4. Get raw video file from player

By default, player will run endlessly. There are three parameters, which can be used to stop its execution:

  • –once – doesn’t work in our case (throws an error);
  • –timeout <sec> – should be set to some time (in seconds) after which player stops; it means, rendering will take at least 1 second (and generate 1 second of video) and we have to be sure that this time is enough to render any picture we have (or else it has to be 2, 3 seconds for all images) – not exactly what we would like;
  • –max-advances N – stops after N frame advances; was tested with N=1 and worked well – we are going to use this parameter.


dump-gnash preview.swf \
-P "FlashVars=url=file:///some/dir/image_2d.swf” \
-D output.raw --max-advances 1 -j 500 -k 500

Output:

# WARNING: Gnash was told to loop the movie
# Gnash created a raw dump file with the following properties:
COLORSPACE=BGRA32
NAME=output.raw
WIDTH=500
HEIGHT=500
INTERVAL=10
FPS_DESIRED=100
TIME=0.251716
FPS_ACTUAL=99.3183
FRAMECOUNT=26

As we see from the output, Gnash produced output.raw which is 500×500 pixels raw video file with colorspace BGRA32. There are 26 frames in the video and rendering took about 0.25 sec.

Step 5. Extracting an image from raw video file

According to output, we have 8-bit BGRA raw video. What does it mean? It is just a sequence of one-byte values for each of four channels (Blue, Green, Red, Alpha) for each pixel for each frame. If we open that file with mplayer, we’ll see that our image flickers. That’s because player produces blank frames while loading image_2d.swf. What we really need from this video is the last frame. As we set output size to 500×500 pixels and each pixel is 4 bytes, we need last 1000000 bytes from output.raw.

tail -c 1MB output.raw > last_frame.raw

Step 6. Converting raw image to PNG

Knowing the structure of the raw file, we could use some PNG library and write a few lines of code to produce PNG from raw. But, as our application uses Paperclip and, in its turn, Paperclip uses Imagemagick to make thumbnails, we are going to use Imagemagick, too.

convert -size 500x500 -depth 8 rgba:last_frame.raw \
-separate -swap 0,2 -combine -trim png:render.png

Size and depth options as well as rgba prefix give convert tool information about our raw file. Imagemagick doesn’t support brga colorspace, so we are using rgba and swapping channels that is just a little bit harder than swapping letters :) . Last parameter trims whitespace from the picture.

Step 7. Final script

This script is run by a subclass of Paperclip::Processor and produces source image for making thumbnails with Paperclip::Processor::Thumbnail. But this is another story :)

#!/bin/sh
raw=$(mktemp)
dump-gnash $1 -P "FlashVars=url=file://$2" \
-D $raw --max-advances 1 -j 500 -k 500
tail -c 1MB $raw | convert -size 500x500 -depth 8 rgba:- \
-separate -swap 0,2 -combine -trim png:$3
trap "rm $raw" EXIT

This script accepts three parameters:

  1. location of preview.swf;
  2. location of swf file to render;
  3. where to put the output

The second line creates temporary file for storing raw video and the last line removes that video file when the script finishes.

Issues

Although most of our 2D images were rendered correctly, a lot of them weren’t. Such Flash features as bitmap filters and blend modes are not yet implemented in Gnash, and are not trivial to implement. So, think about workarounds if you are using these features.

Selection sort in JavaScript

October 29th, 2010 by Gert-Jan van der Wel

In my quest to learn more about algorithms, I came across another sorting algorithm. This one is called Selection sort.

The collection is sorted from beginning to end. While looping over the elements, it first finds the smallest element between the current position and the end of the collection. Then the smallest element and the current element exchange places. This way all elements are sorted when the loop has finished.

In JavaScript it looks like this:

var collection = [5, 2, 4, 6, 1, 3];
 
var n = collection.length;
for(var j = 0; j < n; j++) {
	var index = j;
 
	var i = j + 1;
	for(i; i < n; i++) {
		if(collection[i] < collection[index]) {
			index = i;
		}
	}
	var temp = collection[j];
	collection[j] = collection[index];
	collection[index] = temp;
}

Insertion sort in JavaScript

October 27th, 2010 by Gert-Jan van der Wel

I started reading Introduction to Algorithms to educate myself on the subject.

There are books on algorithms that are rigorous but incomplete and others that cover masses of material but lack rigor. Introduction to Algorithms combines rigor and comprehensiveness.

In order to motivate myself reading it cover to cover, I thought it’d be a good idea to blog about my progress. Beside me being “forced” to write an update every now and then, I might help somebody else in the progress.

The first algorithm is solving a sorting problem. The technique is called Insertion sort. It’s suited for sorting a small number of elements and the idea is pretty simple. Insertion sort works the way many people sort a hand of playing cards.

The collection is sorted from beginning to end. While looping over the elements, it compares the current element to the ones before it in the collection. All the elements that are bigger than the current element are moved one place to the right. The current element is inserted after the first element that is smaller than itself. Have a look at the Wikipedia page if you want to know more about it.

In JavaScript it looks like this:

var collection = [5, 2, 4, 6, 1, 3];
 
for(var j = 1; j < collection.length; j++) {
	var key = collection[j];
	var i = j - 1;
 
	while(i >= 0 && collection[i] > key) {
		collection[i+1] = collection[i];
		i = i - 1;
	}
 
	collection[i+1] = key;
}