The Problem Solver

Tell me and I will forget
Show me and I will remember
Involve me and I will understand
- Confucius -

Google Ads

This Blog

Syndication

Search

Tags

News





  • View Maurice De Beijer's profile on LinkedIn

Community

Email Notifications

Explore

Archives

January 2013 - Posts

Whatever database your are using, relational or document, there is one thing you can be certain of as soon as you get a second user of the system and that is concurrency conflicts. It may not happen often but eventually it will happen that two users load the same document, make some changes to it and save it back to the database.

There are several ways of dealing with these kind of concurrency problems:

  1. Just ignoring it and letting the second users changes overwrite the first ones
    While this isn’t advisable if the data is very important there are lots of cases where it could be an okay solution. Sure it offends the developer in us, as it should, because we are ignoring error situations. But for an end user it might not be that bad at all, specially considering that this is a really cheap option to build and the changes of it occurring are quite low. Just make sure to check with your stakeholder of this is acceptable.
  2. Using pessimistic locking of data
    This option worked quite well in the old days where a client app had a stateful connection to the database. These days that is usually not the case and with web applications that is completely impossible due to the stateless nature of the web. So this one is out.
  3. Using optimistic concurrency
    This basically means we remember the version of a document loaded and pass that along when we save the document. In SQL Server this is typically done using a rowversion. With document database we tend to interact with the database over an HTTP connection and turns out the HTTP protocol has an optimistic concurrency mechanism in the form of E-TAG’s. RavenDB can use these HTTP E-TAG’s to do optimistic concurrency checks for us.

 

Ignoring concurrency issues

This is the easy one and exactly what we get if we use RavenDB as is.

 

Consider the following code:

static void Main(string[] args)
{
    _store = new DocumentStore
    {
        Url = "http://localhost:8081/"
    };
 
    using (_store)
    {
        _store.Initialize();
 
        var id = CreateInitialDocument();
 
        var resetEvent = new ManualResetEvent(false);
 
        var tasks = new List<Task>();
        for (int i = 0; i < 2; i++)
        {
            tasks.Add(Task.Factory.StartNew(() =>
                SimpleUpdateDocument(id, resetEvent)));
        }
 
        Thread.Sleep(1000);
        resetEvent.Set();
        Task.WaitAll(tasks.ToArray());
 
 
        Console.WriteLine();
        Console.WriteLine("The result id:");
        using (var session = _store.OpenSession())
        {
            var theData = session.Load<TheData>(id);
            Console.WriteLine(theData.Data);
        }
    }
}

As you can see the code creates a new document and updates that same document in multiple threads. Then it reads it back in a prints the result.

A simple implementation of updating might look something like this:

private static void SimpleUpdateDocument(string id, ManualResetEvent resetEvent)
{
    using (var session = _store.OpenSession())
    {
        var theData = session.Load<TheData>(id);
        resetEvent.WaitOne();
        theData.Data = string.Format("Updated on thread: '{0}'", Thread.CurrentThread.ManagedThreadId);
        Console.WriteLine(theData.Data);
        session.SaveChanges();
    }
}

Basicaly we load the document, wait for each thread to have the document loaded, update it and save it back to the database. Clearly a concurrency problem arises because the last thread to save the document will try to save its changes and overwrite the others changes.

If we run the code we will see the following output. It appears that there was no error and the changes made in thread 5 where the ones that where ultimately saved.

image

Looking at the RavenDB server window you will see all interactions. Basically two post operations to save the same document right after each other.

image

Maybe this is good enough for your case and then again maybe not.

 

Using optimistic concurrency

Switching to optimistic concurrency is quite easy. All we need to do is set the UseOptimisticConcurrency property on the Advanced object of the session to true. As soon as we do this the second update, the one that would inadvertently overwrite the first one, will result in a HTTP Error 409 – Conflict. This is the result of RavenDB checking for changes using the E-TAG send with each record. If a HTTP Error 409 – Conflict is detected this surfaces in the C# code as a ConcurrencyException. By catching this ConcurrencyException we can decide what to do.

private static void ConcurantUpdateDocument(string id, ManualResetEvent resetEvent)
{
    using (var session = _store.OpenSession())
    {
        try
        {
            session.Advanced.UseOptimisticConcurrency = true;
            var theData = session.Load<TheData>(id);
            resetEvent.WaitOne();
            theData.Data = string.Format("Updated on thread: '{0}'", Thread.CurrentThread.ManagedThreadId);
            Console.WriteLine(theData.Data);
            session.SaveChanges();
        }
        catch (ConcurrencyException ex)
        {
            Console.WriteLine(ex.Message);
            Console.WriteLine("\tExpectedETag: {0}", ex.ExpectedETag);
            Console.WriteLine("\tActualETag:   {0}", ex.ActualETag);
        }
    }
}


using this new version of the update method we will guard against concurrency issues.


If we run the code now we will see the following output:

image

 

And the RavenDB sever will also clearly show the problem.

image

 

Conclusion

Concurrency handling in RavenDB is nice and simple. By default we just get the simple last user wins behavior. This may or may not be appropriate for your situation but is easy as it requires no additional code. If you want concurrency checking all you need to do is set the UseOptimisticConcurrency property on the session to true and that session will be checked.

Nice and simple.

 

Enjoy!

Posted by Maurice | with no comments
Filed under: , ,

RavenDB has a very nice feature in it being safe by default and returns just 128 documents. Now you can override these safe defaults but it is very unwise to do so. And even if you decide to do so are you really going to show a million customers to your user at the same time? I would guess not as the user would not be really happy with the response or the speed of it. In most cases using paging is a much better solution.

 

Paging through a RavenDB result set

It turns out that paging through a result set is really easy. Normally all you need to do is use the Skip() and Take() methods and filter the result set that way. Pretty easy right?

And suppose you want to display the total number of documents or pages to the user? No need to do a separate count. The RavenDB Query() function returns an IRavenQueryable instead of a plain IQueryable object. And this IRavenQueryable gives you two extra methods one of which is Statistics() with has an out argument of type RavenQueryStatistics.

This RavenQueryStatistics is interesting because it has a TotalResults property telling us how many results are returned from the query itself. There is a second useful property for paging, SkippedResults, which is needed in some cases where RavenDB will filter out duplicate results. See here for more information on when you need to use the SkippedResults property.

 

Paging in an ASP.NET MVC page

The following controller action lets us page though a large set of people with a page size.

public ActionResult Index(int pageNr = 1)
 {
     const int pageSize = 10;
     RavenQueryStatistics stats;
 
     using (var session = Global.DocumentStore.OpenSession())
     {
         var people = session.Query<Person>()
                                  .Statistics(out stats)
                                  .OrderBy(p => p.FirstName)
                                  .Skip((pageNr - 1) * pageSize)
                                  .Take(pageSize)
                                  .ToArray();
 
         ViewBag.PageNr = pageNr;
         ViewBag.PageCount = Math.Ceiling((double)stats.TotalResults / pageSize);
 
         return View(people);
     }
 }

And this is the related Razor view

@model IEnumerable<MvcApplication1.Models.Person>
 
@{
    ViewBag.Title = "People";
}
 
<h2>People</h2>
 
<h3>Page @ViewBag.PageNr of @ViewBag.PageCount</h3>
 
<ol>
    @foreach (var item in Model)
    {
        <li>
            @Html.DisplayFor(modelItem => item.FirstName)
            @Html.DisplayFor(modelItem => item.LastName)
        </li>
    }
</ol>
 
<a href="?pageNr=@(ViewBag.PageNr + 1)">Next</a>

 

Nice and simple, just the way I like it.

 

PS. Don’t like clicking on the next button button to load more data? Neither do I. One jQuery plugin that helps me there is infinite-scroll created by Paul Irish.

 

Enjoy!

Posted by Maurice | with no comments

The slides from my presentation on Practical use of HTML5 for the DotNed user group.

 

 

 

The source code can be found here.

 

There is an online demo version hosted on Azure websites here.

 

Enjoy!

In deze podcast praat Dennis Vroegop met Eric-Jan Wischmann, een certified scrum master, over de ins- en outs van Scrum. Wat is scrum? Wat betekent het voor je dagelijkse werk? Wat zijn de valkuilen?

Links:

Enjoy!

Posted by Maurice | with no comments
Filed under: ,

After installing RavenDB 2 the next step is to start saving data and load it again. Unlike SQL server we don’t need to go into the RavenDB Management Studio and create a database and tables with a schema. The database, optional but highly recommended, will be created when we first access it. And when it comes down to tables and schema RavenDB is much simpler, all it does is store documents. A document doesn’t have a schema enforced so we don’t need to define one up front. Instead we just save some data and load it again.

The document to store

Even though RavenDB doesn’t require us to define the document structure we are using C# at the front end and in C# we usually define our data structure using classes. In this example we are going to store people using the following C# class:

   1: class Person
   2: {
   3:     public string Id { get; set; }
   4:     public string FirstName { get; set; }
   5:     public string LastName { get; set; }
   6: }

We are going to provide the first and last name and the Id property is for use with RavenDB. In fact we could leave the Id out, RavenDB would not care, but it would be harder to load a single document if we did.

 

The RavenDB DocumentStore

Before we can start working with the RavenDB server we first need to create an instance of the RavenDB DocumentStore. This is a relatively expensive object to create and normally in an application you only create a single and keep a reference to it. It is thread safe so a singleton will work just fine even in an ASP.NET application. The minimum information the DocumentStore needs is the url of the RavenDB server, in this case the default location of http://localhost:8080/. Additionally we can specify a default database to use, in this case people. This database will be created automatically when needed.

   1: var store = new DocumentStore
   2: {
   3:     Url = "http://localhost:8080/",
   4:     DefaultDatabase = "people"
   5: };
   6: store.Initialize();


The RavenDB DocumentSession

When we start doing any actual work with the RavenDB database we need to do so in the scope of a session. To create a new session we can call the DocumentStore.OpenSession() function. This session needs to short lived and only be used on a single thread. With this session we can persist data to the database and load it again.

   1: using (var session = store.OpenSession())
   2: {
   3:     var person = new Person()
   4:     {
   5:         FirstName = "Maurice",
   6:         LastName = "de Beijer"
   7:     };
   8:     session.Store(person);
   9:     Console.WriteLine("Storing person with ID: {0}", person.Id);
  10:     session.SaveChanges();
  11:     id = person.Id;
  12: }

Note that we need to call SaveChanges for the data to be persisted. If we forget to do this the session object will be disposed and the new person will not be saved.

 

Loading the document again is simple. Just create a session and use the Load() with the document id.

   1: using (var session = store.OpenSession())
   2: {
   3:     var person = session.Load<Person>(id);
   4:     Console.WriteLine("Loaded: {0} {1} {2}",
   5:         person.Id, person.FirstName, person.LastName);
   6: }


If we don’t know the document id, or we just want to load multiple document we can also query the document store using the Query() function.

   1: using (var session = store.OpenSession())
   2: {
   3:     var people = session.Query<Person>();
   4:     foreach (var person in people)
   5:     {
   6:         Console.WriteLine("Loaded: {0} {1} {2}",
   7:             person.Id, person.FirstName, person.LastName);
   8:     }
   9: }


Running the application gives us the following output:

image

 

What does RavenDB store for us?

If we open the RavenDB Management Studio and navigate to the person stored we can see what data is actually stored. As you can see below the data is actually saved in a JSON format. The C# type isn’t used at all.

image

In fact we can load this document without the .NET client library with a simple HTTP get request:

 

http://localhost:8080/databases/people/docs/people/1

This will simply return the data as a JSON response in the browser.

image

 

It turns out RavenDB stores more than just the data we send, it also stores some metadata. The most important parts of metadata are the RavenDB entity name, the C# class name we used without the namespace, and the CLR type, the full type name for the C# class we created.

image

 

Enjoy!

Posted by Maurice | with no comments
Filed under: ,

Donderdag 24 januari 2013 doe ik weer een presentatie over HTML5 voor de DotNed gebruikersgroep.

 

Op dit moment is HTML5 een van de grote hypes. Door de HTML5 standaard te gebruiken gaan we alles anders doen op het web. Uiteraard gaat alles goed en vanaf nu werkt alles gewoon zoals verwacht op alle browsers hetzelfde. En zo zijn er nog wel meer fabeltjes.

Zoals iedereen, die al langer voor het web ontwikkelt, weet dat dit tot nu toe nog nooit het geval is geweest. En zelfs als dat in een wereld met perfecte browser leveranciers waar zou zijn dan zitten we nog met het feit dat niet iedere gebruiker zijn browser snel update. Zo gebruikt meer dan 10% van de gebruikers nog Internet Explorer 8.0 als hun browser en dat is nu niet echt een browser die de HTML5 standaard goed ondersteunt.

Betekent dit nu dat we helemaal niet met HTML5 aan de slag kunnen? Uiteraard kan dat wel, alleen moeten we goed kijken naar welke onderdelen we gebruiken. In deze sessie laat Maurice de Beijer zien hoe je een bestaande web applicatie kan vernieuwen met HTML5 onderdelen maar op een manier waarop oudere browsers toch gewoon blijven werken.

 

Ik hoop iedereen daar te zien :-)

Posted by Maurice | with no comments
Filed under: ,

Before we get started with RavenDB we need to install the required parts. There are several ways we can do this and one of the easiest is using the NuGet Package manager from within Visual Studio 2012 with the available RavenDB NuGet packages.

image

 

Which package to install?

As should be obvious from the screenshot above there are quite a few NuGet packages to choose from. It turns out we need to use two packages to get started, the client and server part. Adding them is easy, just open the NuGet Package Manager Console window from the Visual Studio Tools menu and issue the following two command:

 

   1: Install-Package RavenDB.Server
   2: Install-Package RavenDB.Client

 

What did we add to our solution?

The RavenDB.Server package added the server we need to store data. This package adds no references to the project but adds the required executable and its dependencies to a Tools folder in the RavenDB.Server.2.0.xxxx solution folder containing all the NuGet packages. In order to use the RavenDB server we need to navigate to this folder and double click the Raven.Server.exe. This will open a console window showing the server debug messages.

image

One important piece of output is the Server Url, in this case http://localhost:8080/. We need this when we start working with the server from our client code but we can also het to the RavenDB Management Studio using this URL.

 

The RavenDB Management Studio

If we open the a browser and navigate to the Server Url the RavenDB Management Studio. This Management Studio is a Silverlight application that will let us manage different aspects of the server. Doing so just after installing RavenDB.Server will take us to the following start screen.

image

Don’t worry about creating a database for now, this will be done automatically when we connect from the client application when needed.

 

What is next?

In the next post we will create a simple client console application to store some data in this server and then retrieve and display it.

 

Enjoy!

Posted by Maurice | with no comments
Filed under: ,