Oren Eini

CEO of RavenDB

a NoSQL Open Source Document Database

Get in touch with me:

oren@ravendb.net +972 52-548-6969

Posts: 7,565
|
Comments: 51,185
Privacy Policy · Terms
filter by tags archive
time to read 1 min | 178 words

Originally posted at 4/12/2011

Can you spot the NRE hiding in the code?

if (parentObject!= null)
{
    lock (parentObject)
    {
        if (parentObject != null)
        {
            properties = properties.Clone();
            parentObject[parentKey] = this;
            parentObject = null;
        }
    }
}
time to read 1 min | 136 words

Originally posted at 4/11/2011

I was trying to take a backup of my blog to see if I can do some fancy stuff there, when I realized that the blog backup was 2 GB (!) in size. Now, I know that I post a lot, but I don’t think that I post that much.

As it turns out, the problem was with unbounded logs that started taking up most of the space in the database:

image

In general, when building applications that are meant to run over long periods of time without attention, it is better to have some way of getting rid of unimportant information automatically.

time to read 2 min | 288 words

One of the interesting aspects of build RavenDB was that it opened up my mind to the way we can use the very nature of the server to open up additional information about the server operations.

One thing that I noticed recently is that if I need to debug a test for RavenDB, I often need to stop the current thread (the Test thread) and then literally go to the server test instance and look at what is actually going on in there.

The fun part is that this is really nice, because I can go an inspect the running test instance, see what is going on, modify things to see how they affect the behavior, etc. The only problem is that this is actually quite complex to setup manually (stop on debugger, freeze the appropriate thread, resume run, inspect server – modify stuff there, stop on debugger, thaw thread, continue run, etc).

What occurred to me, however, is that I can codify this behavior, and end up with this:

image

This method will only operate while a debugger is attached, but it is going to save me a long time.  Once I am done, I need to delete the marker document:

image

This is especially important if you are running in and in memory mode, since the moment the test is over, the database is completely wiped out.

time to read 1 min | 63 words

Originally posted at 4/4/2011

One of the advantages of RavenDB is that the documents format is highly human readable. Except for one thing. Can you tell me what date is represented by this value:

/Date(1224043200000+0300)/

I thought not :-)

We have recently moved toward this format instead:

2011-04-04T11:28:46.0404749+03:00

Which it both machine and human readable.

This make figuring out what something is so much easier.

time to read 5 min | 813 words

Originally posted at 3/22/2011

This time, taking on Who Can Help Me, I found some really interesting things there.

For one thing, we got this little guy:

image

I was all ready to discover INewsRepository –<> NewsRepository : Repository<NewsItem>, etc. What I found, instead was a real service:

image

That is how it is supposed to be, to be frank. There is a need to abstract something, and we write just enough code to make it work. I would argue with the implementation of this, however, because the approach for multi threading is wrong headed. We shouldn’t spin out a new thread pool work item just to execute the request when the FluentTwitter API already contains async version that can do quite well for us, but the overall concept is sound. And I was relieved not to find nested repositories in my first few steps there.

Of course, I then discovered that this nice service has some friends from the left side of the blanket:

image

I think that I expressed my opinion about code such as this:

image

A waste of keystrokes, and highly inefficient to boot. You don’t make queries by Id in NHibernate, you use Get or Load instead.

Overloading the infrastructure – After reviewing the code, I was surprised to see so much of it dedicated for caching:

image

What surprised me more is that in the entire application there were exactly two locations where a cache was used. In both cases, it led to the same service. Implementing a much simpler solution in that service would have chopped quite a bit of code out of this project.

And then there was this:

image

Luckily, this is dead code, but I was quite amused by this code, in a “shake you head in disbelief” fashion.

First, for a code that is obviously meant to be used in a multi threaded fashion, it is not thread safe. Second, it is actually a memory leak waiting to happen, more than anything else. If you call that method, your items will never freed.

The next is a personal opinion, but I can’t help feeling that this is pretty heavy weight:

image

Well, that is true whenever you are looking at an XSD, but in this case, we just need to expose two properties, and I think that it would have been perfectly fine to stick that into the <appSettings/> section. There are actually several places where similar approach has been tried, but I don’t see this of any value if you aren’t writing a library that might require special configuration. If you are writing an app, using the default modes is usually more than enough.

Reading the controllers code wasn’t a real surprise. One thing that did bother me is the amount of mapping that is going on there, and how much of that I was simply unable to follow. For example:

image

Which is then calling;

image

Which then goes into additional custom implementations and convention based ones.

The reason that this is important is that this is a prime location for Select N+1 issues, and indeed, we have several such occurrences of the problem just in this piece of code.

time to read 2 min | 297 words

Originally posted at 3/31/2011

I am currently sitting with 3 guys in the pub, and the discussion naturally turned to performance. I asked all three the following question: “How many CLR objects can you create in one second?”

I got the following replies:

  • 2,000 objects per second
  • 50,000 objects per second
  • 100,000 objects per second

Then I sat down to check:

class Program
{
    static void Main(string[] args)
    {
        var sp = Stopwatch.StartNew();

        int i = 0;
        while(sp.ElapsedMilliseconds < 1000)
        {
            new MyClass();
            i++;
        }
        sp.Stop();
        Console.WriteLine("Created {0} in {1}", i, sp.Elapsed);
    }
}

public class MyClass
{
    public string A;
    public int B;
    public DateTime C;
}

The result?

Created 7,715,305 in 00:00:01

time to read 2 min | 354 words

Originally posted at 3/30/2011
I have seen all of those in production code…
  1. throw new NullReferenceException();
  2. public class AbstractController : Controller
    // or 
    // public class AbstractPag : Page
    {
        public static bool IsAdmin { get;set; }
    }
  3. public static class BlogMgr
    {
        public static void AddPostToBlog(Blog blog, Post post)
        {
                blog.Posts.Add(post);
                post.Blog = blog;
        }
    }

* I could only think of three, but I didn’t want to modify the title. Can you complete the list?

time to read 3 min | 536 words

Originally posted at 3/30/2011

One thing that we haven’t done so far is manage transactions. I am strongly against having automatic transactions that wrap the entire request. However, I do like automatic transactions that wrap a single action. We can implement this as:

 

public class NHibernateActionFilter : ActionFilterAttribute
{
    private static readonly ISessionFactory sessionFactory = BuildSessionFactory();

    private static ISessionFactory BuildSessionFactory()
    {
        return new Configuration()
            .Configure()
            .BuildSessionFactory();
    }

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        var sessionController = filterContext.Controller as SessionController;

        if (sessionController == null)
            return;

        sessionController.Session = sessionFactory.OpenSession();
        sessionController.Session.BeginTransaction();
    }

    public override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        var sessionController = filterContext.Controller as SessionController;

        if (sessionController == null)
            return;

        using (var session = sessionController.Session)
        {
            if (session == null)
                return;

            if (!session.Transaction.IsActive) 
                return;

            if (filterContext.Exception != null)
                session.Transaction.Rollback();
            else
                session.Transaction.Commit();
        }
    }
}

This one is pretty simple, except that you should note that we are checking if the transaction is active before trying something. That is important because we might have got here because of an error in the opening the transaction, we would get a second error which would mask the first.

time to read 5 min | 847 words

Originally posted at 3/30/2011

While I don’t really mind having global state, it tends to bite you on the ass eventually, so let us try to deal with this guy, shall we?

public class NHibernateActionFilter : ActionFilterAttribute
{
    private static readonly ISessionFactory sessionFactory = BuildSessionFactory();

    public static ISession CurrentSession
    {
        get { return HttpContext.Current.Items["NHibernateSession"] as ISession; }
        set { HttpContext.Current.Items["NHibernateSession"] = value; }
    }

    private static ISessionFactory BuildSessionFactory()
    {
        return new Configuration()
            .Configure()
            .BuildSessionFactory();
    }

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        CurrentSession = sessionFactory.OpenSession();
    }

    public override void OnActionExecuted(ActionExecutedContext filterContext)
    {

        var session = CurrentSession;
        if (session != null)
        {
            session.Dispose();
        }
    }
}

One easy way to do so would be to put the session directly where we want it to be, in the controller. We already have an extension point for that, the SessionController. Instead of referencing the global session, it can just hold its own:

public class SessionController : Controller
{
    public HttpSessionStateBase HttpSession
    {
        get { return base.Session; }
    }

    public new ISession Session { get; set; }
}

Which leads us to:

public class NHibernateActionFilter : ActionFilterAttribute
{
    private static readonly ISessionFactory sessionFactory = BuildSessionFactory();

    private static ISessionFactory BuildSessionFactory()
    {
        return new Configuration()
            .Configure()
            .BuildSessionFactory();
    }

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        var sessionController = filterContext.Controller as SessionController;

        if (sessionController == null)
            return;

        sessionController.Session = sessionFactory.OpenSession();
    }

    public override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        var sessionController = filterContext.Controller as SessionController;

        if (sessionController == null)
            return;
        
        var session = sessionController.Session;
        if (session == null) 
            return;

        session.Dispose();
    }
}

Now we have absolutely no global state, and yet we have a very easy access to the current session.

There are still a few things missing, can you see them?

FUTURE POSTS

No future posts left, oh my!

RECENT SERIES

  1. Production Postmortem (52):
    07 Apr 2025 - The race condition in the interlock
  2. RavenDB (13):
    02 Apr 2025 - .NET Aspire integration
  3. RavenDB 7.1 (6):
    18 Mar 2025 - One IO Ring to rule them all
  4. RavenDB 7.0 Released (4):
    07 Mar 2025 - Moving to NLog
  5. Challenge (77):
    03 Feb 2025 - Giving file system developer ulcer
View all series

RECENT COMMENTS

Syndication

Main feed Feed Stats
Comments feed   Comments Feed Stats
}