Look at this screenshot of the recently released Gobby 0.4.90. See that nice yellow arrow in the toolbar? Yes, this means we finally have Undo/Redo support. It was a really good feeling having closed bug #39
Gobby 0.4.90 is the first release in the 0.5 series, and 99% of the code have been rewritten from scratch. It is not yet 0.5.0 since it does not yet contain all the features that previous versions had (for example, it does not yet support self-hosting or password protection). However, removing the integrated chat was a design decision, since there are so many other possibilities for communication, including VoIP. As it supports removing documents, only use it with people you trust enough not to delete all your data.
Gobby 0.4.90 does no longer use obby or net6 as backend libraries doing the hard work, but libinfinity, implementing the Infinote protocol. libinfinity is not yet stable API and ABI wise, and probably will not be for still some time. libinfinity contains a dedicated server, called infinoted that Gobby 0.4.90 can connect to.
You can safely install the new version since it is parallel-installable to previous Gobby versions. But please consider everything as very experimental. Things may crash or otherwise behave badly. Report bugs if they do. We set up a playground server on dalaran.0x539.de if you want to test the new version without having to install server yourself.
I was curious where most time in libinfinity, Gobby's infinote implementation, is spent. Not because it was too slow or something, but just because I wanted to know. So I used valgrind's callgrind tool to gain some profile data while running libinfinity's main test for the concurrncy control algorithm. When I displayed the result in kcachegrind (there is still no GNOME equivalent, no?) everything looked as I would have expected, until I noticed this line:
This means that 14.5% of the overall program time is spent in g_type_instance_get_private(). This is because libinfinity uses g_type_class_add_private for every class to store its members into, so it is easy to extend functionality later without breaking ABI. However, this also means that for every function that needs to access a member, g_type_instance_get_private() is called. I didn't expect such a huge impact, though.
To fix this, I added a simple gpointer to the public instance struct, and let it point to the private field in the instance_init function. So this means one call to g_type_instance_get_private() per instance, instead of roughly one per call to a function operating on an instance of the class in question. After doing this for the five classes suffering most from this, g_type_instance_get_private does no longer show up anywhere near relevant in kcachegrind.
I'd like it if improving performance was always as easy as this.