Sunday, 10 June 2012

Stone Code Sober (also, don't use ConcurrentBag in Mono)

Ugh. Saturday night, sans alcohol, post-Prometheus. Sobriety on a weekend evening can only mean one thing... staying up till fucking 4am and writing code.

As it happens, I did have something to try and achieve. Namely, getting some prototype Spring.Net-based code working in Mono, running under XSP, running on an Ubuntu box.

The code itself is based on some of the same ideas as a current piece of work - a custom http handler and framework that is built for speed and simplicity. At the heart of it is a message bus with attached listeners waiting for commands and an application context to be delivered. The listeners act on the context and it ends up holding the output state ready for the response to be marshalled. It is quite straightforward and /very/ fast, utilising singleton objects from Spring.Net.

Now, I have an Ubuntu box (shard, a little ultra-small-form-factor Dell, bless it) and I've already been through the pain in the arse of getting Spring.Net working under Mono. Well, just Spring.Core really, but that's the only bit I'm interested in so fuck it, whatever. I'm using Mono 2.8 which gives me .Net 4 functionality. If you're interested in getting Mono/XSP working on Ubuntu or Fedora Linux then I highly recommend this page which has a comprehensive install script. I did have to do a little bit of make check; make install afterwards to bring my MonoDevelop stuff up to date, but aside from that it went smoothly (although it took about 45 minutes on shard!).

So, I have .Net 4 capability, a working Spring.Net/Common.Logging build, and that script gave me XSP version 4. I've never used XSP before but there are quite a few good pages on it, even if they do appear to be from 2006. Hell, I can't even remember if we had Google back in 2006. There followed a couple of bumps of a) remembering that I had to set up the custom http handler part of it in the web.config, and b) my .Net solution in MonoDevelop won't make an ASP.Net web application project that uses anything above version 3.5 for reasons best known to itself, which stops you referencing the projects directly from the web host. However, XSP and Mono are more than happy with it, so I made an empty library project that referenced the projects and now have a pre-XSP step that copies the latest DLLs into the web host application.

Alright. Now I have a working application. Almost. This happened:

This kept me going for over an hour, having to break bits of code by design in order to get a sensible answer out of Mono since I couldn't attach a debugger to it.

The problem occurred whenever the Store behaviour was called. Now it turns out that this behaviour happens to be the only one which refuses to do anything if the user isn't authenticated. Like so:

When the behaviour returns false, that signals that the command that is being delivered on the message bus has not been fully satisfied. So therefore it will move on to the next listener it has. Here is the delivery code:

Now what I couldn't fathom, is why this somehow breaks in Mono but runs fine under Windows. The bug is essentially implying that there is a listener in the collection which is null. I was feeling paranoid about this and so I made sure that there was a null check on the Add routine in the message bus.

Ok, so. All good, yeah?

No. Still fucked. In desperation, I added some code to show the listeners collection every time a message was being delivered. The result?

There were 2K of listeners in each of my two message buses listener collections. WTF?

The listener collection is pretty straightforward:

So just a ConcurrentBag of my interface type. That's absolutely fine and to my knowledge I had no reason to believe that it would spawn extra capacity.

I ran that particular test with an unmodified listeners collection on my Windows build and received the following result:

Which is correct behaviour. WTF?!? It turns out that there appears to be different behaviour for the System.Collections.Concurrent.ConcurrentBag in Microsoft.Net 4.0 and in Mono 2.8, where the Microsoft version enumerates correctly based on number of added items, and the Mono version seems to enumerate over an extended capacity.

Given that there is little practical difference in contention handling between locking on a System.Collections.Generic.List and using a ConcurrentBag, I started to use a List as it doesn't have the same retarded behaviour.

Yay! Working application... And now when running the upload tester...

Which gives me one of these...


At which point it was time for sleepz.

No comments:

Post a comment