Buffer Managers, production code and alternative implementations
We are porting RavenDB to Linux, and as such, we run into a lot of… interesting issues. Today we run into a really annoying one.
We make use of the BufferManager class inside RavenDB to reduce memory allocations. On the .Net side of things, everything works just fine, and we never really had any issues with it.
On the Mono side of things, we started getting all sort of weird errors. From ArgumentOutOfRangeException to NullReferenceException to just plain weird stuff. That was the time to dig in and look into what is going on.
On the .NET side of things, BufferManager implementation is based on a selection criteria between large (more than 85Kb) and small buffers. For large buffers, there is a single large pool that is shared among all the users of the pool. For small buffers, the BufferManager uses a pool per active thread as well as a global pool, etc. In fact, looking at the code we see that it is really nice, and a lot of effort has been made to harden it and make it work nicely for many scenarios.
The Mono implementation, on the other hand, decides to blithely discard the API contract by ignoring the maximum buffer pool size. It seems because “no user code is designed to cope with this”. Considering the fact that RavenDB is certainly dealing with that, I’m somewhat insulted, but it seems par the course for Linux, where “memory is infinite until we kill you”* is the way to go.
But what is far worse is that this class is absolutely not thread safe. That was a lot of fun to discover. Considering that this piece of code is pretty central for the entire WCF stack, I’m not really sure how that worked. We ended up writing our own BufferManager impl for Mono, to avoid those issues.
* Yes, somewhat bitter here, I’ll admit. The next post will discuss this in detail.
How's Core CLR vs mono?
The licensing costs for the Microsoft stack pay for themselves by saving time.
I fail to see how breaking the contract helps anyone though, even if most user code isn't designed to cope with the exception.
Now you're left with code wrote on Microsoft's implementation expecting an exception if they try and request too many buffers suffering a possible memory leak as they return these extra buffers to the pool.
While coming from the Mono side you're left with seemingly correct code that apparently worked throwing exceptions when running on Microsoft's implementation.
At least when sticking to the contract code that doesn't handle the exception is equally broken on both implementations.
When I last played with Linux, it seemed like I was constantly having to "recompile the kernel" to do pretty much anything.
15 years later, it appears that little has changed.
Hey you can't complain, that's why Linux is "free" after all!
Uri, Core CLR isn't real yet. It isn't something that we can actually use at the moment, so that isn't relevant
My understanding is that Microsoft released a large subset of the .NET Framework source under the MIT License. I also read that Mono was planning on replacing a bunch of their implemented classes with the Microsoft ones.
Unfortunately, it seems that if Mono "broke" the contract of the original, it would be difficult to replace without breaking existing Mono clients.
As more code is becoming cross-platform, it seems that Mono needs to bite the bullet and ensure API consistency.
Maybe just wait for core clr and put this project on a hold? Divert resources to other projects. No shame in that.
Edward, There is no indication when CoreCLR would be out, however. That is a problem if we want to actually get to run on Linux at some point
Ayende, Mono WCF stack is incomplete and buggy. They admit that. Good news is Miguel once said it will be straightforward to incorporate codes from opensourced .Net WCF stack. I think they will do it eventually.