﻿<?xml version="1.0" encoding="utf-8"?><rss version="2.0"><channel><title>Ayende @ Rahien</title><link>http://ayende.com/blog/</link><description>Ayende @ Rahien</description><copyright>Copyright (C) Ayende Rahien  2004 - 2012 (c) 2012</copyright><ttl>60</ttl><item><title>I think that I&amp;rsquo;ll ignore this test failure</title><description>&lt;p&gt;&lt;a href="http://ayende.com/blog/Images/Windows-Live-Writer/I-think-that-Ill-ignore-this-test-failur_14830/image_2.png"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://ayende.com/blog/Images/Windows-Live-Writer/I-think-that-Ill-ignore-this-test-failur_14830/image_thumb.png" width="829" height="191"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;This really sucks, because of this:&lt;/p&gt; &lt;p&gt;&lt;a href="http://ayende.com/blog/Images/Windows-Live-Writer/I-think-that-Ill-ignore-this-test-failur_14830/image_4.png"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://ayende.com/blog/Images/Windows-Live-Writer/I-think-that-Ill-ignore-this-test-failur_14830/image_thumb_1.png" width="550" height="67"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;This is part of the RavenDB release process, where we are actually hammering RavenDB and seeing if it breaks. And it usually takes about 24 hours to do a complete run.&lt;/p&gt;</description><link>http://ayende.com/blog/155745/i-think-that-irsquo-ll-ignore-this-test-failure?key=4bad89ac-f047-4047-8b8a-ba5d062e7bf7</link><guid>http://ayende.com/blog/155745/i-think-that-irsquo-ll-ignore-this-test-failure?key=4bad89ac-f047-4047-8b8a-ba5d062e7bf7</guid><pubDate>Thu, 24 May 2012 09:00:00 GMT</pubDate></item><item><title>The RavenDB Release Process</title><description>&lt;p&gt;We got several questions about this in the mailing list, so I thought that this would be a good time to discuss this in the blog. &lt;/p&gt; &lt;p&gt;One of the best part about RavenDB is that we are able to deliver quickly and continuously.&amp;nbsp; That means that we can deliver changes to the users very rapidly, often resulting in response times of less than an hour from “I have an issue” to “it is already fixed and you can download it”.&lt;/p&gt; &lt;p&gt;That is awesome on a lot of level, but it lack something very important, stability. In other words, by pushing things so rapidly, we are living on the bleeding edge. Which is great, except that you tend to bleed.&lt;/p&gt; &lt;p&gt;That is why we split the RavenDB release process into Unstable and Stable. Unstable builds are released on a “several times a day” basis, and only require that we will pass our internal test suite. This test suite is hefty, over 1,500 tests so far, but it is something that can be run in about 15 minutes or so on the developer machine to make sure that our changes didn’t break anything.&lt;/p&gt; &lt;p&gt;The release process for Stable version is much more involved. First, of course, we run the standard suite of tests. Then we have a separate set of tests, which are stress testing RavenDB by trying to see if there are any concurrency issues.&lt;/p&gt; &lt;p&gt;Next, we take the current bits and push them to our own internal production systems. For example, at the time of this writing, this blog (and all of our assets) are currently running on RavenDB build 726 and have been running that way for a few days. This allows us to test several things. That there are no breaking changes, that this build can survive running in production over extended period of time and that the overall performance remains excellent.&lt;/p&gt; &lt;p&gt;Finally, we ask users to take those builds for a spin, and they are usually far more rough on RavenDB than we are.&lt;/p&gt; &lt;p&gt;After all of that, we move to a set of performance tests, comparing the system behavior on a wide range of operations compared to the old version. &lt;/p&gt; &lt;p&gt;And then… we can do a stable release push. Phew!&lt;/p&gt;</description><link>http://ayende.com/blog/155713/the-ravendb-release-process?key=3694bc25-c5e5-45ab-93d8-d6f146ac86ac</link><guid>http://ayende.com/blog/155713/the-ravendb-release-process?key=3694bc25-c5e5-45ab-93d8-d6f146ac86ac</guid><pubDate>Wed, 23 May 2012 09:00:00 GMT</pubDate></item><item><title>RavenHQ goes out of beta</title><description>&lt;p&gt;&lt;img src="https://ravenhq.com/Content/css/images/logo.png"&gt;&lt;/p&gt; &lt;p&gt;After several months in public beta, I am proud to announce that &lt;a href="https://ravenhq.com/"&gt;RavenHQ&lt;/a&gt;, the RavenDB as a Service&amp;nbsp; on the cloud has dropped the beta label and is now ready for full production use.&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;That means that we now accept signups from the general public, you no longer need an AppHarbor account and you can use it directly. It also means that you can safely start using RavenHQ for production purposes.&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;RavenHQ is a fully-managed cloud of RavenDB servers and scalable plans, you’ll never have to worry about installation, updates, availability, performance, security or backups again.  &lt;p&gt;We offer both standard and high availability plans, and are the perfect fit for RavenDB users who can safely outsource all the operational support of your databases in the RavenHQ’s team capable hands.&lt;/p&gt;</description><link>http://ayende.com/blog/156289/ravenhq-goes-out-of-beta?key=25d64f6e-be22-419e-8aae-c2a9f670f81e</link><guid>http://ayende.com/blog/156289/ravenhq-goes-out-of-beta?key=25d64f6e-be22-419e-8aae-c2a9f670f81e</guid><pubDate>Tue, 22 May 2012 07:00:00 GMT</pubDate></item><item><title>Reviewing RavenDB app: ReleaseCandidateTracker</title><description>&lt;p&gt;&lt;a href="https://github.com/SzymonPobiega/ReleaseCandidateTracker"&gt;ReleaseCandidateTracker&lt;/a&gt; is a new RavenDB based application by Szymon Pobiega. I reviewed version 5f7e42e0fb1dea70e53bace63f3e18d95d2a62dd. At this point, I don’t know anything about this application, including what exactly it means, Release Tracking.&lt;/p&gt; &lt;p&gt;I downloaded the code and started VS, there is one project in the solution, which is already a Good Thing. I decided to randomize my review approach and go and check the Models directory first. &lt;/p&gt; &lt;p&gt;Here is how it looks:&lt;/p&gt; &lt;p&gt;&lt;a href="http://ayende.com/blog/Images/Windows-Live-Writer/Reviewing-RavenDB-app-ReleaseCandidateTr_A3DC/image_4.png"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://ayende.com/blog/Images/Windows-Live-Writer/Reviewing-RavenDB-app-ReleaseCandidateTr_A3DC/image_thumb_1.png" width="983" height="671"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;This is interesting for several reasons. First, it looks like it is meant to keep a record of all deployments to multiple environments, and that you can lookup the history of each deployment both on the environment side and on the release candidate side.&lt;/p&gt; &lt;p&gt;Note that we use rich models, which have collections in them. In fact, take a look at this method:&lt;/p&gt; &lt;p&gt;&lt;a href="http://ayende.com/blog/Images/Windows-Live-Writer/Reviewing-RavenDB-app-ReleaseCandidateTr_A3DC/image_6.png"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://ayende.com/blog/Images/Windows-Live-Writer/Reviewing-RavenDB-app-ReleaseCandidateTr_A3DC/image_thumb_2.png" width="1081" height="349"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;Which calls to this method:&lt;/p&gt; &lt;p&gt;&lt;a href="http://ayende.com/blog/Images/Windows-Live-Writer/Reviewing-RavenDB-app-ReleaseCandidateTr_A3DC/image_8.png"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://ayende.com/blog/Images/Windows-Live-Writer/Reviewing-RavenDB-app-ReleaseCandidateTr_A3DC/image_thumb_3.png" width="602" height="243"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;You know what the &lt;em&gt;really&lt;/em&gt; fun part about this? &lt;/p&gt; &lt;p&gt;It ain’t relational model. There is &lt;em&gt;no cost &lt;/em&gt;of actually making all of these calls!&lt;/p&gt; &lt;p&gt;Next, we move to the Infrastructure folder, where we have a couple of action results and the RavenDB management stuff. Here it how RCT uses RavenDB:&lt;/p&gt; &lt;blockquote&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; Database
{
    &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; IDocumentStore storeInstance;

    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; IDocumentStore Instance
    {
        get
        {
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (storeInstance == &lt;span class="kwrd"&gt;null&lt;/span&gt;)
            {
                &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; InvalidOperationException(&lt;span class="str"&gt;"Document store has not been initialized."&lt;/span&gt;);
            }
            &lt;span class="kwrd"&gt;return&lt;/span&gt; storeInstance;
        }
    }

    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Initialize()
    {
        var embeddableDocumentStore = &lt;span class="kwrd"&gt;new&lt;/span&gt; EmbeddableDocumentStore {DataDirectory = &lt;span class="str"&gt;@"~\App_Data\Database"&lt;/span&gt;};
        embeddableDocumentStore.Initialize();
        storeInstance = embeddableDocumentStore;
    }
}
&lt;/pre&gt;
&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
&lt;/style&gt;
&lt;/blockquote&gt;
&lt;p&gt;It is using an embedded database to do that, which makes it very easy to use the app. Just hit F5 and go. In fact, if we do, we see the fully functional website, which is quite awesome &lt;img style="border-bottom-style: none; border-left-style: none; border-top-style: none; border-right-style: none" class="wlEmoticon wlEmoticon-smile" alt="Smile" src="http://ayende.com/blog/Images/Windows-Live-Writer/Reviewing-RavenDB-app-ReleaseCandidateTr_A3DC/wlEmoticon-smile_2.png"&gt;.&lt;/p&gt;
&lt;p&gt;Let us move to seeing how we are managing the sessions:&lt;/p&gt;
&lt;blockquote&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; BaseController : Controller
{
    &lt;span class="kwrd"&gt;public&lt;/span&gt; IDocumentSession DocumentSession { get; &lt;span class="kwrd"&gt;private&lt;/span&gt; set; }
    &lt;span class="kwrd"&gt;public&lt;/span&gt; CandidateService CandidateService { get; &lt;span class="kwrd"&gt;private&lt;/span&gt; set; }
    &lt;span class="kwrd"&gt;public&lt;/span&gt; ScriptService ScriptService { get; &lt;span class="kwrd"&gt;private&lt;/span&gt; set; }

    &lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; OnActionExecuting(ActionExecutingContext filterContext)
    {
        &lt;span class="kwrd"&gt;if&lt;/span&gt; (filterContext.IsChildAction)
        {
            &lt;span class="kwrd"&gt;return&lt;/span&gt;;
        }
        DocumentSession = Database.Instance.OpenSession();
        CandidateService = &lt;span class="kwrd"&gt;new&lt;/span&gt; CandidateService(DocumentSession);
        ScriptService = &lt;span class="kwrd"&gt;new&lt;/span&gt; ScriptService(DocumentSession);
        &lt;span class="kwrd"&gt;base&lt;/span&gt;.OnActionExecuting(filterContext);
    }
    
    &lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; OnActionExecuted(ActionExecutedContext filterContext)
    {
        &lt;span class="kwrd"&gt;if&lt;/span&gt; (filterContext.IsChildAction)
        {
            &lt;span class="kwrd"&gt;return&lt;/span&gt;;
        }
        &lt;span class="kwrd"&gt;if&lt;/span&gt;(DocumentSession != &lt;span class="kwrd"&gt;null&lt;/span&gt;)
        {
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (filterContext.Exception == &lt;span class="kwrd"&gt;null&lt;/span&gt;)
            {
                DocumentSession.SaveChanges();
            }
            DocumentSession.Dispose();
        }
        &lt;span class="kwrd"&gt;base&lt;/span&gt;.OnActionExecuted(filterContext);
    }
}
&lt;/pre&gt;
&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
&lt;/style&gt;
&lt;/blockquote&gt;
&lt;p&gt;This is all handled inside the base controller, and it is very similar to how I am doing that in my own apps.&lt;/p&gt;
&lt;p&gt;However, ScriptService and CandidateService seems strange, let us explore them a bit.&lt;/p&gt;
&lt;blockquote&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; ScriptService
{
    &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;readonly&lt;/span&gt; IDocumentSession documentSession;

    &lt;span class="kwrd"&gt;public&lt;/span&gt; ScriptService(IDocumentSession documentSession)
    {
        &lt;span class="kwrd"&gt;this&lt;/span&gt;.documentSession = documentSession;
    }

    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; AttachScript(&lt;span class="kwrd"&gt;string&lt;/span&gt; versionNumber, Stream fileContents)
    {
        var metadata = &lt;span class="kwrd"&gt;new&lt;/span&gt; RavenJObject();
        documentSession.Advanced.DatabaseCommands.PutAttachment(versionNumber, &lt;span class="kwrd"&gt;null&lt;/span&gt;, fileContents, metadata);
    }

    &lt;span class="kwrd"&gt;public&lt;/span&gt; Stream GetScript(&lt;span class="kwrd"&gt;string&lt;/span&gt; versionNumber)
    {
        var attachment = documentSession.Advanced.DatabaseCommands.GetAttachment(versionNumber);
        &lt;span class="kwrd"&gt;return&lt;/span&gt; attachment != &lt;span class="kwrd"&gt;null&lt;/span&gt; 
            ? attachment.Data() 
            : &lt;span class="kwrd"&gt;null&lt;/span&gt;;
    }
}
&lt;/pre&gt;
&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
&lt;/style&gt;
&lt;/blockquote&gt;
&lt;p&gt;So this is using RavenDB attachment to store stuff, I am not quite sure what yet, so let us track it down.&lt;/p&gt;
&lt;p&gt;This is being used like this:&lt;/p&gt;
&lt;blockquote&gt;&lt;pre class="csharpcode"&gt;[HttpGet]
&lt;span class="kwrd"&gt;public&lt;/span&gt; ActionResult GetScript(&lt;span class="kwrd"&gt;string&lt;/span&gt; versionNumber)
{
    var candidate = CandidateService.FindOneByVersionNumber(versionNumber);
    var attachment = ScriptService.GetScript(versionNumber);
    &lt;span class="kwrd"&gt;if&lt;/span&gt; (attachment != &lt;span class="kwrd"&gt;null&lt;/span&gt;)
    {
        var result = &lt;span class="kwrd"&gt;new&lt;/span&gt; FileStreamResult(attachment, &lt;span class="str"&gt;"text/plain"&lt;/span&gt;);
        var version = candidate.VersionNumber;
        var product = candidate.ProductName;
        result.FileDownloadName = &lt;span class="kwrd"&gt;string&lt;/span&gt;.Format(&lt;span class="str"&gt;"deploy-{0}-{1}.ps1"&lt;/span&gt;, product, version);
        &lt;span class="kwrd"&gt;return&lt;/span&gt; result;
    }
    &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; HttpNotFoundResult(&lt;span class="str"&gt;"Deployment script missing."&lt;/span&gt;);
}
&lt;/pre&gt;
&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
&lt;/style&gt;
&lt;/blockquote&gt;
&lt;p&gt;So I am assuming that the scripts are deployment scripts for different versions, and that they get uploaded on every new release candidate.&lt;/p&gt;
&lt;p&gt;But look at the CandidateService, it looks like a traditional service wrapping RavenDB, and I have spoken against it multiple times.&lt;/p&gt;
&lt;p&gt;In particular, I dislike this bit of code:&lt;/p&gt;
&lt;blockquote&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; ReleaseCandidate FindOneByVersionNumber(&lt;span class="kwrd"&gt;string&lt;/span&gt; versionNumber)
{
    var result = documentSession.Query&amp;lt;ReleaseCandidate&amp;gt;()
        .Where(x =&amp;gt; x.VersionNumber == versionNumber)
        .FirstOrDefault();
    &lt;span class="kwrd"&gt;if&lt;/span&gt;(result == &lt;span class="kwrd"&gt;null&lt;/span&gt;)
    {
        &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; ReleaseCandidateNotFoundException(versionNumber);
    }
    &lt;span class="kwrd"&gt;return&lt;/span&gt; result;
}

&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Store(ReleaseCandidate candidate)
{
    var existing = documentSession.Query&amp;lt;ReleaseCandidate&amp;gt;()
        .Where(x =&amp;gt; x.VersionNumber == candidate.VersionNumber)
        .Any();
    &lt;span class="kwrd"&gt;if&lt;/span&gt; (existing)
    {
        &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; ReleaseCandidateAlreadyExistsException(candidate.VersionNumber);
    }
    documentSession.Store(candidate);
}&lt;/pre&gt;
&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
&lt;/style&gt;
&lt;/blockquote&gt;
&lt;p&gt;From looking at the code, it looks like the version number of the release candidate is the primary way to look it up. More than that, in the entire codebase, there is never a case where we load a document by id.&lt;/p&gt;
&lt;p&gt;When I see a VersionNumber, I think about things like “1.0.812.0”, but I think that in this case the version number is likely to include the product name as well, “RavenDB-1.0.812.0”, otherwise you couldn’t have two products with the same version.&lt;/p&gt;
&lt;p&gt;That said, the code above it wrong, because it doesn’t take into account RavenDB’s indexes BASE nature. Instead, the version number should actually be the ReleaseCandidate id. This way, because RavenDB’s document store is fully ACID, we don’t have to worry about index update times, and we can load things very efficiently.&lt;/p&gt;
&lt;p&gt;Pretty much all of the rest of the code in the CandidateService is only used in a single location, and I don’t really see a value in it being there.&lt;/p&gt;
&lt;p&gt;For example, let us look at this one:&lt;/p&gt;
&lt;blockquote&gt;&lt;pre class="csharpcode"&gt;[HttpPost]
&lt;span class="kwrd"&gt;public&lt;/span&gt; ActionResult MarkAsDeployed(&lt;span class="kwrd"&gt;string&lt;/span&gt; versionNumber, &lt;span class="kwrd"&gt;string&lt;/span&gt; environment, &lt;span class="kwrd"&gt;bool&lt;/span&gt; success)
{
    CandidateService.MarkAsDeployed(versionNumber, environment, success);
    &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; EmptyResult();
}&lt;/pre&gt;
&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
&lt;/style&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href="http://ayende.com/blog/Images/Windows-Live-Writer/Reviewing-RavenDB-app-ReleaseCandidateTr_A3DC/image_10.png"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://ayende.com/blog/Images/Windows-Live-Writer/Reviewing-RavenDB-app-ReleaseCandidateTr_A3DC/image_thumb_4.png" width="600" height="729"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;As you can see, it is merely loading the appropriate release candidate, and calling the MarkAsDeployed method on it.&lt;/p&gt;
&lt;p&gt;Instead of doing this needless, forwarding, and assuming that we have the VersionNumber as the id, I would write:&lt;/p&gt;
&lt;blockquote&gt;&lt;pre class="csharpcode"&gt;[HttpPost]
&lt;span class="kwrd"&gt;public&lt;/span&gt; ActionResult MarkAsDeployed(&lt;span class="kwrd"&gt;string&lt;/span&gt; versionNumber, &lt;span class="kwrd"&gt;string&lt;/span&gt; environment, &lt;span class="kwrd"&gt;bool&lt;/span&gt; success)
{
    var cadnidate = DocumentSession.Load&amp;lt;ReleaseCandidate&amp;gt;(versionNumber);
    &lt;span class="kwrd"&gt;if&lt;/span&gt; (cadnidate == &lt;span class="kwrd"&gt;null&lt;/span&gt;)
        &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; ReleaseCandidateNotFoundException(versionNumber);
    var env = DocumentSession.Load&amp;lt;DeploymentEnvironment&amp;gt;(environment);
    &lt;span class="kwrd"&gt;if&lt;/span&gt; (env == &lt;span class="kwrd"&gt;null&lt;/span&gt;)
        &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; InvalidOperationException(&lt;span class="kwrd"&gt;string&lt;/span&gt;.Format(&lt;span class="str"&gt;"Environment {0} not found"&lt;/span&gt;, environment));

    cadnidate.MarkAsDeployed(success, env);
    &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; EmptyResult();
}
&lt;/pre&gt;
&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
&lt;/style&gt;
&lt;/blockquote&gt;
&lt;p&gt;Finally, a word about the error handling, this is handled via:&lt;/p&gt;
&lt;blockquote&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; OnException(ExceptionContext filterContext)
{
    filterContext.Result = &lt;span class="kwrd"&gt;new&lt;/span&gt; ErrorResult(filterContext.Exception.Message);
    filterContext.ExceptionHandled = &lt;span class="kwrd"&gt;true&lt;/span&gt;;
}

&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; ErrorResult : ActionResult
{
    &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;readonly&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; message;

    &lt;span class="kwrd"&gt;public&lt;/span&gt; ErrorResult(&lt;span class="kwrd"&gt;string&lt;/span&gt; message)
    {
        &lt;span class="kwrd"&gt;this&lt;/span&gt;.message = message;
    }

    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; ExecuteResult(ControllerContext context)
    {
        context.HttpContext.Response.Write(message);
        context.HttpContext.Response.StatusCode = 500;
    }
}
&lt;/pre&gt;
&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
&lt;/style&gt;
&lt;/blockquote&gt;
&lt;p&gt;The crazy part is that OnException is overridden only on some of the controllers, rather than in the base controller, and even worse. This sort of code leads to error details loss.&lt;/p&gt;
&lt;p&gt;For example, let us say that I get a NullReferenceException. This code will dutifully tell me all about it, &lt;em&gt;but will not tell me where it happened&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;This sort of thing make debugging &lt;em&gt;extremely&lt;/em&gt; hard.&lt;/p&gt;</description><link>http://ayende.com/blog/155553/reviewing-ravendb-app-releasecandidatetracker?key=ebf8a35d-96b1-419c-be31-518497decac2</link><guid>http://ayende.com/blog/155553/reviewing-ravendb-app-releasecandidatetracker?key=ebf8a35d-96b1-419c-be31-518497decac2</guid><pubDate>Wed, 16 May 2012 09:00:00 GMT</pubDate></item><item><title>I hate this code</title><description>&lt;p&gt;I &lt;em&gt;really &lt;/em&gt;hate this code, it is so &lt;em&gt;stupid&lt;/em&gt; it makes my head hurt, and it have so much important factors in it. In particular, there is a lot of logic in here.&lt;/p&gt; &lt;p&gt;&lt;a href="http://ayende.com/blog/Images/Windows-Live-Writer/I-hate-this-code_F857/image_2.png"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://ayende.com/blog/Images/Windows-Live-Writer/I-hate-this-code_F857/image_thumb.png" width="1110" height="511"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;You might not see it as such, but a lot of this is actually &lt;em&gt;quite&lt;/em&gt; important, default values, config parsing, decisions. &lt;/p&gt; &lt;p&gt;This is important. And it is all handled in a a few methods that goes on forever and hide important details in the tediousness of parameter unpacking.&lt;/p&gt; &lt;p&gt;This approach works if you have 5 parameters, not when you have 50.&lt;/p&gt;</description><link>http://ayende.com/blog/154561/i-hate-this-code?key=da4fb8d4-69de-45f0-bfe4-1d9f61f58b0c</link><guid>http://ayende.com/blog/154561/i-hate-this-code?key=da4fb8d4-69de-45f0-bfe4-1d9f61f58b0c</guid><pubDate>Thu, 03 May 2012 09:00:00 GMT</pubDate></item><item><title>And sometimes Things Just Works</title><description>&lt;p&gt;I am in the process of writing an article about RavenDB, and I just wrote the following code to demonstrate RavenDB schema less nature:&lt;/p&gt; &lt;blockquote&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; (var session = documentStore.OpenSession())
{
    session.Store(&lt;span class="kwrd"&gt;new&lt;/span&gt; Customer
    {
        Name = &lt;span class="str"&gt;"Joe Smith"&lt;/span&gt;,
        Attributes =
            {
                {&lt;span class="str"&gt;"IsAnnoyingCustomer"&lt;/span&gt;, &lt;span class="kwrd"&gt;true&lt;/span&gt;},
                {&lt;span class="str"&gt;"SatisfactionLevel"&lt;/span&gt;, 8.7},
                {&lt;span class="str"&gt;"LicensePlate"&lt;/span&gt;, &lt;span class="str"&gt;"B7D-12JA"&lt;/span&gt;}
            }
    });

    session.SaveChanges();
}

&lt;span class="kwrd"&gt;using&lt;/span&gt; (var session = documentStore.OpenSession())
{
    var customers = session.Query&amp;lt;Customer&amp;gt;()
        .Where(x =&amp;gt; x.Attributes[&lt;span class="str"&gt;"IsAnnoyingCustomer"&lt;/span&gt;].Equals(&lt;span class="kwrd"&gt;true&lt;/span&gt;))
        .ToList();

    Console.WriteLine(customers.Count);

    session.SaveChanges();
}
&lt;/pre&gt;
&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
&lt;/style&gt;
&lt;/blockquote&gt;
&lt;p&gt;This &lt;em&gt;worked&lt;/em&gt;, flawlessly. &lt;/p&gt;
&lt;p&gt;The amount of work that we have put into RavenDB to make such things work is really scary when you sit down to think about it.&lt;/p&gt;
&lt;p&gt;But it works, it does what I expect it to do and it doesn’t get in my way, woohoo!&lt;/p&gt;</description><link>http://ayende.com/blog/152865/and-sometimes-things-just-works?key=e94ea6a3-4b80-4b2b-b1cd-85944875771e</link><guid>http://ayende.com/blog/152865/and-sometimes-things-just-works?key=e94ea6a3-4b80-4b2b-b1cd-85944875771e</guid><pubDate>Tue, 01 May 2012 09:00:00 GMT</pubDate></item><item><title>Relational searching sucks, don&amp;rsquo;t try to replicate it</title><description>&lt;p&gt;&lt;a href="http://stackoverflow.com/questions/10219183/ravendb-multimap-index"&gt;This question&lt;/a&gt; on Stack Overflow is a fairly common one. Here is the data:&lt;/p&gt; &lt;p&gt;&lt;a href="http://ayende.com/blog/Images/Windows-Live-Writer/Relational-searching-sucks-dont-try-to-r_11D52/image_2.png"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://ayende.com/blog/Images/Windows-Live-Writer/Relational-searching-sucks-dont-try-to-r_11D52/image_thumb.png" width="719" height="181"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;And the question was about how to get RavenDB to create an index that would have the following results:&lt;/p&gt; &lt;table border="0" cellspacing="0" cellpadding="2" width="400"&gt; &lt;tbody&gt; &lt;tr&gt; &lt;td valign="top" width="200"&gt;&lt;pre&gt;&lt;code&gt;{
   CarId: "cars/1",
   PersonId: "people/1235",
   UnitId: "units/4321",
   Make: "Toyota",
   Model: "Prius"
   FirstName: "Ayende",
   LastName: "Rahien"
   Address: "Komba 10, Hadera"
}&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td valign="top" width="200"&gt;&lt;pre&gt;&lt;code&gt;{
   CarId: "cars/2",
   PersonId: "people/1236",
   UnitId: "units/4321",
   Make: "Toyota",
   Model: "4runner"
   FirstName: "test",
   LastName: "test"
   Address: "blah blah"
}&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;
&lt;td valign="top" width="200"&gt;&amp;nbsp;&lt;/td&gt;
&lt;td valign="top" width="200"&gt;&lt;pre&gt;&lt;code&gt;same unit different person owns a different car&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Now, if you try really hard, you can probably try to get something like that, but that is the wrong way to go about this in RavenDB.&lt;/p&gt;
&lt;p&gt;Instead, we can write the following index:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://ayende.com/blog/Images/Windows-Live-Writer/Relational-searching-sucks-dont-try-to-r_11D52/image_4.png"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://ayende.com/blog/Images/Windows-Live-Writer/Relational-searching-sucks-dont-try-to-r_11D52/image_thumb_1.png" width="652" height="528"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Note that this index is a simple multi map index, it isn’t a multi map/reduce index. There is no need.&lt;/p&gt;
&lt;p&gt;This index can return one of three types. &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Car – just show the car to the user&lt;br&gt;&lt;a href="http://ayende.com/blog/Images/Windows-Live-Writer/Relational-searching-sucks-dont-try-to-r_11D52/image_6.png"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://ayende.com/blog/Images/Windows-Live-Writer/Relational-searching-sucks-dont-try-to-r_11D52/image_thumb_2.png" width="379" height="337"&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Person – now that we have a person, we have the id, and we can query for that:&lt;br&gt;&lt;a href="http://ayende.com/blog/Images/Windows-Live-Writer/Relational-searching-sucks-dont-try-to-r_11D52/image_8.png"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://ayende.com/blog/Images/Windows-Live-Writer/Relational-searching-sucks-dont-try-to-r_11D52/image_thumb_3.png" width="309" height="332"&gt;&lt;/a&gt;&amp;nbsp;&lt;a href="http://ayende.com/blog/Images/Windows-Live-Writer/Relational-searching-sucks-dont-try-to-r_11D52/image_10.png"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://ayende.com/blog/Images/Windows-Live-Writer/Relational-searching-sucks-dont-try-to-r_11D52/image_thumb_4.png" width="297" height="322"&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Unit – now that we have a unit, we have the id, and we can query for that:&lt;br&gt;&lt;a href="http://ayende.com/blog/Images/Windows-Live-Writer/Relational-searching-sucks-dont-try-to-r_11D52/image_12.png"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://ayende.com/blog/Images/Windows-Live-Writer/Relational-searching-sucks-dont-try-to-r_11D52/image_thumb_5.png" width="303" height="322"&gt;&lt;/a&gt;&amp;nbsp; &lt;a href="http://ayende.com/blog/Images/Windows-Live-Writer/Relational-searching-sucks-dont-try-to-r_11D52/image_14.png"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://ayende.com/blog/Images/Windows-Live-Writer/Relational-searching-sucks-dont-try-to-r_11D52/image_thumb_6.png" width="296" height="330"&gt;&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;This method means that we have to generate an additional query for some cases, but it has a lot of advantages. It is &lt;em&gt;simple. &lt;/em&gt;It requires very little work from both client and server and it doesn’t suffer from the usual issues that you run into when you attempt to query over multiple disjointed data sets.&lt;/p&gt;
&lt;p&gt;Now, the bad thing about this is that this won’t allow me to query for cross entity values, so it would be hard for me to query for the cars in Hadera owned by Ayende. But in most cases, that isn’t really a requirement. We just want to be able to search by &lt;em&gt;either&lt;/em&gt; one of those, not all of them. &lt;/p&gt;</description><link>http://ayende.com/blog/156225/relational-searching-sucks-donrsquo-t-try-to-replicate-it?key=3412f1a5-c407-4e81-8a0f-9736ec153e17</link><guid>http://ayende.com/blog/156225/relational-searching-sucks-donrsquo-t-try-to-replicate-it?key=3412f1a5-c407-4e81-8a0f-9736ec153e17</guid><pubDate>Fri, 27 Apr 2012 09:00:00 GMT</pubDate></item><item><title>As the user&amp;rsquo;s put it: Insight into the RavenDB design mindset</title><description>&lt;p&gt;I have been blogging for a long time now, and I am quite comfortable in expressing myself, but I was still blown away by &lt;a href="http://groups.google.com/group/ravendb/browse_thread/thread/5a90fc3a551e4e56/afa9c6fb0b17387a"&gt;this post to the RavenDB mailing list&lt;/a&gt;. Mostly because this thread sums up a lot of the core points that led me to design RavenDB the way it is today.&lt;/p&gt; &lt;p&gt;&lt;a href="http://blog.mindplay.dk/"&gt;Rasmus Schultz&lt;/a&gt; has been able to put a lot of the thought processes behind the RavenDB design into words.&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;Back when I took my education in systems development, basically, I was taught to build aggregates as large, as complete and as connected as possible. But that was 14 years ago, and I'm starting to think, what they taught me back then was based on the kind of thinking that works for single-user, typically desktop applications, where the entire model was assumed to be in-memory, and therefore had to be traversible, since there was no "engine" you could go back to and ask for another piece of the model. &lt;p&gt;I can see now why that doesn't make sense for concurrent applications with large models persisted in the background. It just never occurred to me, and looked extremely wrong to me, because that's not how I was taught to think.&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;&lt;em&gt;Yes&lt;/em&gt;. That is the exact problem that I see people run into over and over. The create highly connected object model, without regards to how they are persisted, and then they run into problems using them. And the assumption that everything is equally costly to read from memory is &lt;em&gt;hugely&lt;/em&gt; expensive.  &lt;blockquote&gt; &lt;p&gt;Furthermore, I'm starting to see why NHibernate doesn't really work well for me. So here's the main thing that's starting to dawn on me, and please confirm or correct me on this: &lt;p&gt;It seems that the idea behind NH is to configure the expected data-access strategies for the model itself. You write configuration-files that define the expected data-access strategies, but potentially, you're doing this based on assumptions about how you might access the data in this or that scenario. &lt;p&gt;The problem I'm starting to see, is that you're defining these assumptions statically - and while it is possible to deviate from these defined patterns, it's easy to think that once you've defined your access strategies, you're "done", and the model "just works" and you can focus on writing business logic, which too frequently turns out to be untrue in practice.&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;To be fair, you &lt;em&gt;can&lt;/em&gt; specify those things in place, with full context. And I have been recommending to do just that for years, but yeah, that is a very common issue. &lt;blockquote&gt; &lt;p&gt;This contrasts with RavenDB, where you formally define the access strategies for specific &lt;i&gt;scenarios&lt;/i&gt; - rather than for the &lt;i&gt;model &lt;/i&gt;itself. And of course the same access strategy may work in different scenarios, but you're not tempted to assume that a single access strategy is going to work for all scenarios. &lt;p&gt;You're encouraged to think and make choices about what you're accessing and updating in each scenario, rather than just defining one overriding strategy and charging ahead blindly on the assumption that it'll always just work, or always perform well, or always make updates that are sufficiently small to not cause concurrency problems. &lt;p&gt;Am I catching on?&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;Precisely. &lt;/p&gt;</description><link>http://ayende.com/blog/156193/as-the-userrsquo-s-put-it-insight-into-the-ravendb-design-mindset?key=fed19b58-ac2d-4684-9fc0-36f7f8416a6c</link><guid>http://ayende.com/blog/156193/as-the-userrsquo-s-put-it-insight-into-the-ravendb-design-mindset?key=fed19b58-ac2d-4684-9fc0-36f7f8416a6c</guid><pubDate>Thu, 26 Apr 2012 06:00:00 GMT</pubDate></item><item><title>Lazy&amp;rsquo;s Man comprehensive search with RavenDB</title><description>&lt;p&gt;
	RavenDB supports many types of searches, and in this case, I want to show something that belongs to the cool parts of the pile, but also on the &amp;ldquo;you probably don&amp;rsquo;t really want to do this&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;
	First, let me explain why this is cool, then we will talk about why you probably don&amp;rsquo;t want to do that (and finally, about scenarios where you actually do want this).&lt;/p&gt;
&lt;p&gt;
	Here is an index that will allow you to search over all of the values of all of the properties in the user entity:&lt;/p&gt;
&lt;blockquote&gt;
	&lt;pre class="csharpcode"&gt;
&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; Users_AllProperties : AbstractIndexCreationTask&amp;lt;User, Users_AllProperties.Result&amp;gt;
{
    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; Result
    {
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; Query { get; set; }
    }
    &lt;span class="kwrd"&gt;public&lt;/span&gt; Users_AllProperties()
    {
        Map = users =&amp;gt;
              from user &lt;span class="kwrd"&gt;in&lt;/span&gt; users
              select &lt;span class="kwrd"&gt;new&lt;/span&gt;
              {
                  Query = AsDocument(user).Select(x =&amp;gt; x.Value)
              };
        Index(x=&amp;gt;x.Query, FieldIndexing.Analyzed);
    }
}&lt;/pre&gt;
	&lt;style type="text/css"&gt;
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }	&lt;/style&gt;
&lt;/blockquote&gt;
&lt;p&gt;
	This can be easily query for things like:&lt;/p&gt;
&lt;blockquote&gt;
	&lt;pre class="csharpcode"&gt;
s.Query&amp;lt;Users_AllProperties.Result, Users_AllProperties&amp;gt;()
    .Where(x=&amp;gt;x.Query == &lt;span class="str"&gt;&amp;quot;Ayende&amp;quot;&lt;/span&gt;) &lt;span class="rem"&gt;// search first name&lt;/span&gt;
    .As&amp;lt;User&amp;gt;()
    .ToList()


s.Query&amp;lt;Users_AllProperties.Result, Users_AllProperties&amp;gt;()
    .Where(x=&amp;gt;x.Query == &lt;span class="str"&gt;&amp;quot;Rahien&amp;quot;&lt;/span&gt;) &lt;span class="rem"&gt;// search last name&lt;/span&gt;
    .As&amp;lt;User&amp;gt;()
    .ToList()&lt;/pre&gt;
	&lt;style type="text/css"&gt;
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }	&lt;/style&gt;
&lt;/blockquote&gt;
&lt;p&gt;
	The fun part is that because we are actually going to index all the properties values into the Query field, which then allow us to easily query for every one of the values without any trouble.&lt;/p&gt;
&lt;p&gt;
	The problem with that is that this is also quite wasteful and likely to lead to bad results down the road. Why?&lt;/p&gt;
&lt;p&gt;
	For two major reasons. First, because this is going to index &lt;em&gt;everything&lt;/em&gt;, and would result in larger index, more IO, etc. The second reason is that it is going to lead to bad results because you are now searching over everything, including the &amp;ldquo;last login date&amp;rdquo; and the &amp;ldquo;password hint&amp;rdquo;. That means that your search results relevancy is going to be poor.&lt;/p&gt;
&lt;p&gt;
	So why would you ever want to do something like that if it is bad?&lt;/p&gt;
&lt;p&gt;
	Well, there are a few scenarios where this is applicable. You need to do that if you want to be able to search over completely / mostly dynamic entities. And you want to do that if you have entities which are specifically generated for the purpose of being searched.&lt;/p&gt;
&lt;p&gt;
	Both cases are fairly rare (the first case is usually covered by dynamic indexing, anyway), so I wanted to point this out, and also point out that it is usually far better to just specify what are the fields that actually &lt;em&gt;matter&lt;/em&gt; for you.&lt;/p&gt;
</description><link>http://ayende.com/blog/153729/lazyrsquo-s-man-comprehensive-search-with-ravendb?key=e7a79ba5-c52a-4d96-a3ca-4c21d7f4e1d7</link><guid>http://ayende.com/blog/153729/lazyrsquo-s-man-comprehensive-search-with-ravendb?key=e7a79ba5-c52a-4d96-a3ca-4c21d7f4e1d7</guid><pubDate>Wed, 25 Apr 2012 09:00:00 GMT</pubDate></item><item><title>The RavenDB indexing process: Optimization&amp;ndash;Tuning? Why, we have auto tuning</title><description>&lt;p&gt;The final aspect of RavenDB’s x7 jump in indexing performance is the fact that we made it &lt;em&gt;freakishly smart&lt;/em&gt;.&lt;/p&gt; &lt;p&gt;During standard operation, most indexes only update when new information comes in, we are usually talking about a small number of documents for every indexing run. The problem is what happens when you have a sudden outpour of documents into RavenDB? For example, during nightly ETL batch, or just if you suddenly have a flood of users doing write operations.&lt;/p&gt; &lt;p&gt;The problem here is that we actually have to balance a lot of variable at the same time:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;The number of documents that we have to index*.&lt;/li&gt; &lt;li&gt;The current memory utilization**.&lt;/li&gt; &lt;li&gt;How any cores I have available to do the index work with?&lt;/li&gt; &lt;li&gt;How much time do I have to do this?&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Basically, the idea goes like this, if I have a small batch size, I am able to index more quickly, ensuring that we have fresher results. If I have big batch size, I am able to index more documents, and my overall indexing times goes down.&lt;/p&gt; &lt;p&gt;There is a non trivial cost associated with every indexing run, so reducing the number of indexing run is good, but the more documents I shove into a single run, the more memory will I use, and the more time it will take before the results are visible to the users.&lt;/p&gt; &lt;p&gt;* It is non trivial because there is no easy way for us to even know how many documents we have left to index (to find out is costly).&lt;/p&gt; &lt;p&gt;** Memory utilization is &lt;em&gt;hard &lt;/em&gt;to figure out in a managed world. I don’t actually have a way to &lt;em&gt;know&lt;/em&gt; how much memory I am using for indexing and how much for other stuff, and there is no real way to say “free the memory from the last indexing run”, or even estimate how much memory that took.&lt;/p&gt; &lt;p&gt;What we have decided on doing is to start from a very small (low hundreds) indexing batch size, and see what is actually going on live. If we see that we have more documents to index than the current batch size, we will slowly double the size of the batch. Slowly, because bigger batches requires more memory, and we also have to take into account current utilization, memory usage, and a bunch of other factors as well. We also go the other way around, able to reduce the indexing batch size on demand based on how much work we have to do right now.&lt;/p&gt; &lt;p&gt;We also provide an upper limit, because at some point it make sense to just do a big batch and make the indexing results visible than to try to do everything all at once. &lt;/p&gt; &lt;p&gt;The fun part in all of that is that once we have found the appropriate algorithm for this, it means that RavenDB will automatically adjust itself based on real production load. If you have an low update rate, it will favor small indexing batches and immediately execute indexing on the new documents. However, if you suddenly have a spike in traffic and the update rate goes up, RavenDB will adjust the indexing batch size so it will be able to keep up with your rate.&lt;/p&gt; &lt;p&gt;We have done some (read, a huge amount) testing with regards to this new optimization, and it turns out that under slow update frequency, we are seeing an average of 15 – 25 ms between a document update and it showing up in the indexes. That is pretty good, but what is going on when we have data just pouring in?&lt;/p&gt; &lt;p&gt;We tested this with a 3 million documents and 3 indexes. And it turn out that under this scenario, where we are trying to shove data into RavenDB as fast as it can accept it, we do see an increase in index latency. Under those condition, latency rose all the way to 1.5 seconds.&lt;/p&gt; &lt;p&gt;This is actually something that I am &lt;em&gt;very&lt;/em&gt; happy about, because we were able to automatically adjust to the changing conditions, and were still able to index things at a reasonable rate (note that under this scenario, the batch size was usually 8 – 16 thousands documents, vs. the 128 – 256 that it is normally).&lt;/p&gt; &lt;p&gt;Because we were able to adjust the batch size on the fly, we could handle sustained writes at this rate with no interruption in service and no real need to think about this from the users perspective.. Exactly what the RavenDB philosophy calls for.&lt;/p&gt;</description><link>http://ayende.com/blog/155425/the-ravendb-indexing-process-optimizationndash-tuning-why-we-have-auto-tuning?key=e8935e72-3d8c-4b63-a000-2e4f35b2fc57</link><guid>http://ayende.com/blog/155425/the-ravendb-indexing-process-optimizationndash-tuning-why-we-have-auto-tuning?key=e8935e72-3d8c-4b63-a000-2e4f35b2fc57</guid><pubDate>Tue, 24 Apr 2012 09:00:00 GMT</pubDate></item><item><title>The RavenDB indexing process: Optimization&amp;ndash;Getting documents from disk</title><description>&lt;p&gt;As I noted in my &lt;a href="http://ayende.com/blog/154721/the-ravendb-indexing-process-optimization?key=c5c0347883c34378b5bae4c17d05a292"&gt;previous post&lt;/a&gt;, we have done major optimizations for RavenDB. One of the areas where we improved the performance was reading the documents from the disk for indexing.&lt;/p&gt; &lt;p&gt;In Pseudo Code, it looks like this:&lt;/p&gt; &lt;blockquote&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;while&lt;/span&gt; database_is_running:
  stale = find_stale_indexes()
  lastIndexedEtag = find_last_indexed_etag(stale)
  docs_to_index = &lt;font style="background-color: #ffff00"&gt;get_documents_since&lt;/font&gt;(lastIndexedEtag, batch_size)
  &lt;/pre&gt;
&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
&lt;/style&gt;
&lt;/blockquote&gt;
&lt;p&gt;As it turned out, we had a major optimization option here, because of the way the data is actually structured on disk. In simple terms, we have an on disk index that lists the documents in the order in which they were updated, and then we have the actual documents themselves, which may be anywhere on the disk.&lt;/p&gt;
&lt;p&gt;Instead of loading the documents in the orders in which they were modified, we decided to try something different. We first query the information we need to find the document on disk from the index, then we sort them based on the optimal access pattern, to reduce disk movement and ensure that we have as sequential reads as possible. Then we take those results in memory and sort them based on their last update time again.&lt;/p&gt;
&lt;p&gt;This seems to be a perfectly obvious thing to do, assuming that you are aware of such things, but it is actually something that is very easy not to notice. The end result is quite promising, and it contributed to the 7+ times improvements in perf that we had for indexing costs.&lt;/p&gt;
&lt;p&gt;But surprisingly, it wasn’t the major factor, I’ll discuss a &lt;em&gt;huge&lt;/em&gt; perf boost in this area tomorrow.&lt;/p&gt;</description><link>http://ayende.com/blog/155201/the-ravendb-indexing-process-optimizationndash-getting-documents-from-disk?key=83100102-0777-4529-9bfd-9f98734fea82</link><guid>http://ayende.com/blog/155201/the-ravendb-indexing-process-optimizationndash-getting-documents-from-disk?key=83100102-0777-4529-9bfd-9f98734fea82</guid><pubDate>Mon, 23 Apr 2012 07:00:00 GMT</pubDate></item><item><title>RavenDB 1.2 work has started (and a road map)</title><description>&lt;p&gt;Two years after the launch of RavenDB 1.0, (preceded by several years of working on 1.0, of course). We are now starting to actually plan and work on RavenDB 1.2.&lt;/p&gt; &lt;p&gt;You can read the &lt;a href="http://issues.hibernatingrhinos.com/releaseNotes?q=%23%7BV+1.2%7D&amp;amp;title=Roadmap+for+RavenDB+1.2&amp;amp;token=C5EF36A41BE2DADF26934B655F57E2EA&amp;amp;verbose=false"&gt;planned roadmap here&lt;/a&gt;. RavenDB 1.2 is a big release, for several reasons.&lt;/p&gt; &lt;ul&gt; &lt;li&gt;We are going to break RavenDB into several distinct editions, from the RavenDB Basic, suitable for small apps to RavenDB Standard which is the current version and all the way up to RavenDB enterprise, which is going to get some awesome features (windows clustering, index encryption, etc). We are also going to have plans for ISVs, which will allow them royalty free distribution of RavenDB for their customers.&lt;/li&gt; &lt;li&gt;We are going to update our pricing structure. You’ll hear more about this when we have finalized pricing.&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Because I am well aware of the possible questions, I suggest reading the thread discussing both editions and pricing in the mailing list:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;&lt;a href="http://groups.google.com/group/ravendb/browse_thread/thread/f737cb1fe1420dc6/07734a5c7957a564"&gt;http://groups.google.com/group/ravendb/browse_thread/thread/f737cb1fe1420dc6/07734a5c7957a564&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href="http://groups.google.com/group/ravendb/browse_thread/thread/da5e15a75f3f6cb2/c17ff91a23f403dc"&gt;http://groups.google.com/group/ravendb/browse_thread/thread/da5e15a75f3f6cb2/c17ff91a23f403dc&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;I will repeat again that we haven’t yet made final pricing decisions, so don’t take the numbers thrown around in those threads as gospel, but they are pretty close to what we will have.&lt;/p&gt; &lt;p&gt;This is the boring commercial stuff, but I am much more interested in talking about the new RavenDB roadmap. In fact, you can actually &lt;a href="http://issues.hibernatingrhinos.com/releaseNotes?q=%23%7BV+1.2%7D&amp;amp;title=Roadmap+for+RavenDB+1.2&amp;amp;token=C5EF36A41BE2DADF26934B655F57E2EA&amp;amp;verbose=false"&gt;read all of our plans here&lt;/a&gt;. The major components for RavenDB 1.2 are:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;Better integration with C# 5.0 – much better support for async in general, async replicaiton, async sharding, etc.&lt;/li&gt; &lt;li&gt;Enterprise level features – Windows Clustering, Full Database Encryption, Indexing Priorities, Compression, etc.&lt;/li&gt; &lt;li&gt;Installer and server console - so you can manage your RavenDB installation more easily.&lt;/li&gt; &lt;li&gt;Better Admin support – scheduled backups, S3 Backups, live restores, etc.&lt;/li&gt; &lt;li&gt;Internalizing commonly used bundles – you shouldn’t have to take additional steps to make use of common functionality. &lt;/li&gt;&lt;/ul&gt; &lt;p&gt;There are other stuff, of course, but those are the main pillars. &lt;/p&gt; &lt;p&gt;As mentioned, you can &lt;a href="http://issues.hibernatingrhinos.com/releaseNotes?q=%23%7BV+1.2%7D&amp;amp;title=Roadmap+for+RavenDB+1.2&amp;amp;token=C5EF36A41BE2DADF26934B655F57E2EA&amp;amp;verbose=false"&gt;read all of that&lt;/a&gt; yourself, and we would welcome feedback on our current plans and suggestions for the new version.&lt;/p&gt;</description><link>http://ayende.com/blog/156257/ravendb-1-2-work-has-started-and-a-road-map?key=6d39de5c-d994-48db-adcc-57070edd566b</link><guid>http://ayende.com/blog/156257/ravendb-1-2-work-has-started-and-a-road-map?key=6d39de5c-d994-48db-adcc-57070edd566b</guid><pubDate>Sun, 22 Apr 2012 09:43:00 GMT</pubDate></item><item><title>The RavenDB indexing process: Optimization&amp;ndash;De-parallelizing work</title><description>&lt;p&gt;One of the major dangers in doing perf work is that you have a scenario, and you optimize the &lt;em&gt;hell&lt;/em&gt; out of that scenario. It is actually pretty easy to do without even noticing it. The problem is that when you do things like that, you are likely to be optimizing a single scenario to perform really well, but you are hurting the overall system performance.&lt;/p&gt; &lt;p&gt;In this example, we have moved heaven and earth to make sure that we are indexing things as fast as possible, and we tested with 3 indexes, on an 4 cores machine. As it turned out, we actually &lt;em&gt;had&lt;/em&gt; improved things, for &lt;em&gt;that particular scenario&lt;/em&gt;.&lt;/p&gt; &lt;p&gt;Using the same test case on a single core machine was suddenly far more heavy weight, because we were pushing a lot of work at the same time. More than the machine could process. The end result was that it actually got there, but much more slowly than if we would have run things sequentially.&lt;/p&gt; &lt;p&gt;Of course, I give you the outliers, but those are good indicators for what we found out. Initially, we thought that we could resolve that by using the TPL’s MaxDegreeOfParallelism, but it turned out to be more complex than that. We have IO bound and we have CPU bound tasks that we need to execute, and trying to execute IO heavy tasks with this would actually cause issues in this scenario.&lt;/p&gt; &lt;p&gt;We had to manually throttle things ourselves, both to ensure limited number of parallel work, and because we have a lot more information about the actual tasks than the TPL have. We can schedule them in a way that is far more efficient because we can tell what is actually going on.&lt;/p&gt; &lt;p&gt;The end result is that we are actually using less parallelism, overall, but in a more efficient manner.&lt;/p&gt; &lt;p&gt;In my next post, I’ll discuss the auto batch tuning support, which allows us to do some really amazing things from the point of view of system performance. &lt;/p&gt;</description><link>http://ayende.com/blog/155393/the-ravendb-indexing-process-optimizationndash-de-parallelizing-work?key=ca7a266b-fb3e-4642-bf6d-f38b9357bc86</link><guid>http://ayende.com/blog/155393/the-ravendb-indexing-process-optimizationndash-de-parallelizing-work?key=ca7a266b-fb3e-4642-bf6d-f38b9357bc86</guid><pubDate>Fri, 20 Apr 2012 09:00:00 GMT</pubDate></item><item><title>The RavenDB indexing process: Optimization&amp;ndash;Parallelizing work</title><description>&lt;p&gt;
	One of the things that we are doing during the index process for RavenDB is applying triggers and deciding what, if and how a document will be indexed. The actual process is a bit more involved, because we have to do additional things (like figure out which indexes have already indexed those particular documents).&lt;/p&gt;
&lt;p&gt;
	At any rate, the interesting thing is that this is a process which is pretty basic:&lt;/p&gt;
&lt;blockquote&gt;
	&lt;pre class="csharpcode"&gt;
&lt;span class="kwrd"&gt;for&lt;/span&gt; doc &lt;span class="kwrd"&gt;in&lt;/span&gt; docs:
    matchingIndexes = FindIndexesFor(doc)
    &lt;span class="kwrd"&gt;if&lt;/span&gt; matchingIndexes.Count &amp;gt; 0:
       doc = ExecuteTriggers(doc) 
       &lt;span class="kwrd"&gt;if&lt;/span&gt; doc != &lt;span class="kwrd"&gt;null&lt;/span&gt;:
          yield doc&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;p&gt;
	&lt;style type="text/css"&gt;
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }	&lt;/style&gt;
&lt;/p&gt;
&lt;p&gt;
	The interesting thing about this is that this is a set of operations that only works on a single document at a time, and the result is the modified documents.&lt;/p&gt;
&lt;p&gt;
	We were able to gain &lt;em&gt;significant&lt;/em&gt; perf boost by simply moving to a Parallel.ForEach call.&amp;nbsp; This seems simple enough, right? Parallelize the work, get better benefits.&lt;/p&gt;
&lt;p&gt;
	Except that there are issues with this as well, which I&amp;rsquo;ll touch on my next post.&lt;/p&gt;
</description><link>http://ayende.com/blog/155233/the-ravendb-indexing-process-optimizationndash-parallelizing-work?key=1b0d214b-677a-422a-8e17-fa739f5d2804</link><guid>http://ayende.com/blog/155233/the-ravendb-indexing-process-optimizationndash-parallelizing-work?key=1b0d214b-677a-422a-8e17-fa739f5d2804</guid><pubDate>Thu, 19 Apr 2012 09:00:00 GMT</pubDate></item><item><title>The RavenDB indexing process: Optimization</title><description>&lt;p&gt;The actual process done by RavenDB to index documents is a fairly complex one. In order to understand what exactly happened, I decided to break it apart to pseudo code.&lt;/p&gt; &lt;p&gt;It looks something like this:&lt;/p&gt; &lt;blockquote&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;while&lt;/span&gt; database_is_running:
  stale = find_stale_indexes()
  lastIndexedEtag = find_last_indexed_etag(stale)
  docs_to_index = get_documents_since(lastIndexedEtag, batch_size)
  
  filtered_docs = execute_read_filters(docs_to_index)
  
  indexing_work = []
  
  &lt;span class="kwrd"&gt;for&lt;/span&gt; index &lt;span class="kwrd"&gt;in&lt;/span&gt; stale:
    
    index_docs = select_matching_docs(index, filtered_docs)
    
    &lt;span class="kwrd"&gt;if&lt;/span&gt; index_docs.empty:
      set_indexed(index, lastIndexedEtag)
    &lt;span class="kwrd"&gt;else&lt;/span&gt;
      indexing_work.add(index, index_docs)
      
  &lt;span class="kwrd"&gt;for&lt;/span&gt; work &lt;span class="kwrd"&gt;in&lt;/span&gt; indexing_work:
  
     work.index(work.index_docs)&lt;/pre&gt;
&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
&lt;/style&gt;
&lt;/blockquote&gt;
&lt;p&gt;And now let me show you the areas in which we did some perf work:&lt;/p&gt;
&lt;blockquote&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;while&lt;/span&gt; database_is_running:
  stale = find_stale_indexes()
  lastIndexedEtag = find_last_indexed_etag(stale)
  docs_to_index = &lt;font style="background-color: #ffff00"&gt;get_documents_since&lt;/font&gt;(lastIndexedEtag, batch_size)
  
  filtered_docs = &lt;font style="background-color: #ffff00"&gt;execute_read_filters&lt;/font&gt;(docs_to_index)
  
  indexing_work = []
  
  &lt;span class="kwrd"&gt;for&lt;/span&gt; index &lt;span class="kwrd"&gt;in&lt;/span&gt; stale:
    
    index_docs = &lt;font style="background-color: #ffff00"&gt;select_matching_docs&lt;/font&gt;(index, filtered_docs)
    
    &lt;span class="kwrd"&gt;if&lt;/span&gt; index_docs.empty:
      set_indexed(index, lastIndexedEtag)
    &lt;span class="kwrd"&gt;else&lt;/span&gt;
      indexing_work.add(index, index_docs)
      
  &lt;font style="background-color: #ffff00"&gt;&lt;span class="kwrd"&gt;for&lt;/span&gt; work &lt;span class="kwrd"&gt;in&lt;/span&gt; indexing_work:&lt;/font&gt;
  
     work.index(work.index_docs)&lt;/pre&gt;
&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
&lt;/style&gt;
&lt;/blockquote&gt;
&lt;p&gt;All of which gives us a &lt;em&gt;major&lt;/em&gt; boost in the system performance. I’ll discuss each part of that work in detail, don’t worry &lt;img style="border-bottom-style: none; border-left-style: none; border-top-style: none; border-right-style: none" class="wlEmoticon wlEmoticon-winkingsmile" alt="Winking smile" src="http://ayende.com/blog/Images/Windows-Live-Writer/The-RavenDB-indexing-process_1177B/wlEmoticon-winkingsmile_2.png"&gt;&lt;/p&gt;</description><link>http://ayende.com/blog/154721/the-ravendb-indexing-process-optimization?key=c5c03478-83c3-4378-b5ba-e4c17d05a292</link><guid>http://ayende.com/blog/154721/the-ravendb-indexing-process-optimization?key=c5c03478-83c3-4378-b5ba-e4c17d05a292</guid><pubDate>Wed, 18 Apr 2012 09:00:00 GMT</pubDate></item><item><title>RavenDB &amp;amp; FreeDB: An optimization story</title><description>&lt;p&gt;So, as I noted in a &lt;a href="http://ayende.com/blog/154401/ravendb-amp-freedb-an-optimization-opportunity?key=707da286f3004472918a87aed724ee2c"&gt;previous post&lt;/a&gt;, we loaded RavenDB with all of the music CDs in existence (or nearly so). A total of 3.1 million disks and 43 million tracks. And we had some performance problems. But we got over them, and I am proud to give you the results:&lt;/p&gt; &lt;table border="0" cellspacing="0" cellpadding="2" width="600"&gt; &lt;tbody&gt; &lt;tr&gt; &lt;td valign="top" width="232"&gt;&amp;nbsp;&lt;/td&gt; &lt;td valign="top" width="168"&gt;Old&lt;/td&gt; &lt;td valign="top" width="200"&gt;New&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="232"&gt;Importing Data&lt;/td&gt; &lt;td valign="top" width="168"&gt;Couple of hours&lt;/td&gt; &lt;td valign="top" width="200"&gt;42 minutes&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="232"&gt;Raven/DocumentsByEntityName&lt;/td&gt; &lt;td valign="top" width="168"&gt;And hour and a half&lt;/td&gt; &lt;td valign="top" width="200"&gt;23.5 minutes&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="232"&gt;Simple index over disks&lt;/td&gt; &lt;td valign="top" width="168"&gt;Two hours and twenty minutes&lt;/td&gt; &lt;td valign="top" width="200"&gt;24.1 minutes&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="232"&gt;Full text index over disks and tracks&lt;/td&gt; &lt;td valign="top" width="168"&gt;More than seven hours&lt;/td&gt; &lt;td valign="top" width="200"&gt;37.5 minutes&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt; &lt;blockquote&gt; &lt;p&gt;Tests were run on the same machine, and the database HD was&amp;nbsp; a single 300 GB 7200 RPM drive.&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;I then decided to take this one step further, and check what would happen when we already &lt;em&gt;had&lt;/em&gt; the indexes. So we created three indexes. One Raven/DocumentsByEntityName, one for doing simple querying over disks and one for full text searches on top of all disks and tracks.&lt;/p&gt; &lt;p&gt;With 3.1 million documents streaming in, and three indexes (at least one of them decidedly non trivial), the import process took an hour and five minutes. Even more impressive, the indexing process was fast enough to keep up with the incoming data so we only had about 1.5 seconds latency between inserting a document and having it indexed. (Note that we usually seem &lt;em&gt;much&lt;/em&gt; lower times for indexing latencies, usually in the low tens of milliseconds, when we aren’t being bombarded with documents). &lt;/p&gt; &lt;p&gt;Next up, and something that we did &lt;em&gt;not&lt;/em&gt; optimize, was figuring out how costly it would be to query this. I decided to go for the big guns, and tested querying the full text search index.&lt;/p&gt; &lt;p&gt;Testing “Query:Adele” returned a result (from a cold booted database) in less than 0.8 seconds. But remember, this is after a cold boot. So let us see what happen when we issue a few other queries?&lt;/p&gt; &lt;ul&gt; &lt;li&gt;Query:Pearl - 0.65 seconds&lt;/li&gt; &lt;li&gt;Query:Abba – 0.67 seconds&lt;/li&gt; &lt;li&gt;Query:Queen – 0.56 seconds&lt;/li&gt; &lt;li&gt;Query:Smith – 0.55 seconds&lt;/li&gt; &lt;li&gt;Query:James – 0.77 seconds&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Note that I am querying radically different values, so I force different parts of the index to load. &lt;/p&gt; &lt;p&gt;Querying for “Query:Adele” again? 32 milliseconds.&lt;/p&gt; &lt;p&gt;Let us see a few more:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;Query:Adams – 0.55 seconds&lt;/li&gt; &lt;li&gt;Query:Abrahams – 0.6 seconds&lt;/li&gt; &lt;li&gt;Query:Queen – 85 milliseconds&lt;/li&gt; &lt;li&gt;Query:James – 0.1 seconds&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Now here are a few things that you might want to consider:&lt;/p&gt; &lt;ol&gt; &lt;li&gt;We have done no warm up to the database, just started it up from cold boot and started querying.&lt;/li&gt; &lt;li&gt;I actually think that we can do better than this, and this is likely to be the next place we are going to focus our optimization efforts.&lt;/li&gt; &lt;li&gt;We are doing a query here over 3.1 million documents, using full text search.&lt;/li&gt; &lt;li&gt;There is no caching involved in the speed increases.&lt;/li&gt;&lt;/ol&gt; &lt;p&gt;More goodies are coming in.&lt;/p&gt;</description><link>http://ayende.com/blog/154913/ravendb-amp-freedb-an-optimization-story?key=31bad705-6ab2-44bc-9721-bfb6c689e57a</link><guid>http://ayende.com/blog/154913/ravendb-amp-freedb-an-optimization-story?key=31bad705-6ab2-44bc-9721-bfb6c689e57a</guid><pubDate>Tue, 17 Apr 2012 09:00:00 GMT</pubDate></item><item><title>RavenDB &amp;amp; FreeDB: An optimization opportunity</title><description>&lt;h3&gt;
	Update: The numbers in this post are not relevant. I include them here solely so you would have a&amp;nbsp;&lt;em&gt;frame of reference&lt;/em&gt;. We have done a&amp;nbsp;&lt;strong&gt;&lt;u&gt;lo&lt;/u&gt;&lt;/strong&gt;&lt;u&gt;t&lt;/u&gt;&amp;nbsp;of optimization work, and the numbers are orders of magnitude faster now. See the next post for details.&lt;/h3&gt;
&lt;p&gt;
	The purpose of this post is to setup a scenario, see how RavenDB do with it, and then optimize the parts that we don&amp;rsquo;t like. This post is scheduled to go about two months after it was written, so anything that you see here is likely already fixed. In future posts, I&amp;rsquo;ll talk about the optimizations, what we did, and what was the result.&lt;/p&gt;
&lt;p&gt;
	&lt;strong&gt;System note:&lt;/strong&gt; I run those tests on a year old desktop, with all the database activity happening on a single 7200 RPM 300GB disk with 8 GB of RAM. Please don&amp;rsquo;t get to hung up on the actual numbers, I include them for reference, but real hardware on production system should kick this drastically higher. Another thing to remember is that this was an &lt;em&gt;active&lt;/em&gt; system, while all of those operations were running, I was actively working and developing on the machine. The main point is to give us some sort of a &lt;em&gt;metric&lt;/em&gt; about where we are, and to see whatever we like this or not.&lt;/p&gt;
&lt;p&gt;
	We keep looking at additional things that we can do with RavenDB, and having large amount of information to tests things with is awesome. Having non fake data is even awesomer, because fake data is predictable data, while real data tend to be much more&amp;hellip; interesting.&lt;/p&gt;
&lt;p&gt;
	That is why I decided to load the entire freedb database into RavenDB and see what is happening.&lt;/p&gt;
&lt;blockquote&gt;
	&lt;p&gt;
		&lt;strong&gt;What is freedb?&lt;/strong&gt;&lt;/p&gt;
	&lt;p&gt;
		freedb is a database to look up CD information using the internet. This is done by a client (a freedb aware application) which calculates a (nearly) unique disc ID for a CD in your CD-Rom and then queries the database. As a result, the client displays the artist, CD-title, tracklist and some additional info.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;
	The nice thing about &lt;a href="http://freedb.org"&gt;freedb&lt;/a&gt; is that you can download their data* and make use of it yourself.&lt;/p&gt;
&lt;blockquote&gt;
	&lt;p&gt;
		* The not so nice thing is that the data is in free form text format. I wrote a parser for it if you really want to use it, which you can find here: &lt;a href="https://github.com/ayende/XmcdParser"&gt;https://github.com/ayende/XmcdParser&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;
	&amp;nbsp;&lt;/p&gt;
&lt;p&gt;
	So I decided to push all of this data into RavenDB. The import process took a couple of hours (didn&amp;rsquo;t actually measure, so I am not sure exactly how much), and we ended up with a RavenDB database with: 3,133,903 documents. Memory usage during the import process was ~100&amp;nbsp; MB &amp;ndash; 150 MB (no indexes were present).&lt;/p&gt;
&lt;p&gt;
	The actual size in RavenDB is 3.59 GB with 3.69 GB reserved on the file system.&lt;/p&gt;
&lt;p&gt;
	Starting the database from cold boot takes about 4 seconds.&lt;/p&gt;
&lt;p&gt;
	This is what the document looks like:&lt;/p&gt;
&lt;p&gt;
	&lt;a href="http://ayende.com/blog/Images/Windows-Live-Writer/RavenDB--FreeDB_AA47/image_8.png"&gt;&lt;img alt="image" border="0" height="477" src="http://ayende.com/blog/Images/Windows-Live-Writer/RavenDB--FreeDB_AA47/image_thumb_3.png" style="background-image: none; border-bottom: 0px; border-left: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" width="352" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;
	A &lt;em&gt;full &lt;/em&gt;backup of the database took about 3 minutes, with all of the time dedicate for pure I/O.&lt;/p&gt;
&lt;p&gt;
	Doing an export, using smuggler (on the local machine, 128 document batches) took about 18 minutes and resulted in a 803MB file (not surprising, smuggler output is a compressed file).&lt;/p&gt;
&lt;p&gt;
	Note that we created this in a completely empty database, so the next step was to actually create an index and see how the database behaves. We create the default Raven/DocumentsByEntityName index, and got 5,870 seconds, so just over an hour and a half. For what it worth, this resulted in on disk index with a size of 125MB.&lt;/p&gt;
&lt;p&gt;
	I then tried a much more complex index:&lt;/p&gt;
&lt;p&gt;
	&lt;a href="http://ayende.com/blog/Images/Windows-Live-Writer/RavenDB--FreeDB_AA47/image_2.png"&gt;&lt;img alt="image" border="0" height="413" src="http://ayende.com/blog/Images/Windows-Live-Writer/RavenDB--FreeDB_AA47/image_thumb.png" style="background-image: none; border-bottom: 0px; border-left: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" width="893" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;
	Just to give you some idea, this index gives you &lt;strong&gt;full text search &lt;/strong&gt;support over &lt;em&gt;just about every music cd that was ever made&lt;/em&gt;. To be frank, this index scares me, because it means that we have to have index entry for every single track in the world.&lt;/p&gt;
&lt;p&gt;
	After indexing was completed, we ended up with a 700 MB on disk presence. Indexing took about 7 hours to complete. That is a lot, but remember what we are dealing with, we indexed 3.1 million documents, but we actually indexed, 52,561,894 values (remember, we index &lt;em&gt;each and every track&lt;/em&gt;).&amp;nbsp; The interesting bit is that while it took a lot of CPU (full text indexing usually does) memory usage was relatively low, it peaked about 300 MB and usually was around the 180MB).&lt;/p&gt;
&lt;p&gt;
	Searching over this index is not as fast as I would like, taking about a second to complete. Then again, the results are quite impressive:&lt;/p&gt;
&lt;p&gt;
	&lt;a href="http://ayende.com/blog/Images/Windows-Live-Writer/RavenDB--FreeDB_AA47/image_6.png"&gt;&lt;img alt="image" border="0" height="537" src="http://ayende.com/blog/Images/Windows-Live-Writer/RavenDB--FreeDB_AA47/image_thumb_2.png" style="background-image: none; border-bottom: 0px; border-left: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" width="704" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;
	Well, given that this is the equivalent of a 52 million records (in this case, &lt;em&gt;literally &lt;/em&gt;records &lt;img alt="Smile" class="wlEmoticon wlEmoticon-smile" src="http://ayende.com/blog/Images/Windows-Live-Writer/RavenDB--FreeDB_AA47/wlEmoticon-smile_2.png" style="border-bottom-style: none; border-left-style: none; border-top-style: none; border-right-style: none" /&gt;) , and we are performing full text search, quite nice.&lt;/p&gt;
&lt;p&gt;
	Let us see what happens when do something a little simpler, shall we?&lt;/p&gt;
&lt;p&gt;
	&lt;a href="http://ayende.com/blog/Images/Windows-Live-Writer/RavenDB--FreeDB_AA47/image_10.png"&gt;&lt;img alt="image" border="0" height="220" src="http://ayende.com/blog/Images/Windows-Live-Writer/RavenDB--FreeDB_AA47/image_thumb_4.png" style="background-image: none; border-bottom: 0px; border-left: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" width="448" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;
	In this case, we are &lt;em&gt;only&lt;/em&gt; indexing 3.1 millions documents, and we don&amp;rsquo;t do full text searches. This index took 2.3 hours to run.&lt;/p&gt;
&lt;p&gt;
	Queries on that are a much more satisfactory rate of starting out at 75 ms and dropping to 5 ms very quickly.&lt;/p&gt;
</description><link>http://ayende.com/blog/154401/ravendb-amp-freedb-an-optimization-opportunity?key=707da286-f300-4472-918a-87aed724ee2c</link><guid>http://ayende.com/blog/154401/ravendb-amp-freedb-an-optimization-opportunity?key=707da286-f300-4472-918a-87aed724ee2c</guid><pubDate>Mon, 16 Apr 2012 09:00:00 GMT</pubDate></item><item><title>re: Kiip&amp;rsquo;s MongoDB&amp;rsquo;s experience</title><description>&lt;p&gt;We got asked several times to respond to &lt;a href="http://blog.engineering.kiip.me/post/20988881092/a-year-with-mongodb"&gt;this post&lt;/a&gt;, about the reason Kiip moved away from MongoDB:&lt;/p&gt; &lt;p&gt;&lt;a href="http://ayende.com/blog/Images/Windows-Live-Writer/7f34976f1b29_8292/image_4.png"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://ayende.com/blog/Images/Windows-Live-Writer/7f34976f1b29_8292/image_thumb_1.png" width="638" height="80"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;On the surface, RavenDB and MongoDB are really similar, looking at the Good parts of the Kiip post, we have schemalessness, easy replication, rich query langauge and we can be access from multiple languages.&lt;/p&gt; &lt;p&gt;But under the hood, RavenDB operates in a completely different way than MongoDB does. A vast majority of the issues that Kiip run into are actually low level (&lt;em&gt;really &lt;/em&gt;low level, is some cases) issues that shouldn’t really be visible to the user. &lt;/p&gt; &lt;p&gt;&lt;strong&gt;Non-counting B-Trees&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;The fact that MongoDB uses non counting B-Trees? The only reason that the user care about that is that it actually impacts performance, but the Kiip blog mentions a bunch of other issues related to that. &lt;/p&gt; &lt;p&gt;In RavenDB, we use Lucene as the indexing format, and we really don’t care about the actual format of the indexes. We natively support Count() and limit / skip, because we feel that those are actually core parts of what most users need. In fact, our API allows us to get the total count of results of a paged query as a by product of actually making the query. There isn’t any additional cost for doing this.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;Poor Memory Management &lt;/strong&gt;&lt;/p&gt; &lt;p&gt;MongoDB relies on the OS to do the memory management, by letting the OS memory manager to do its work. That is actually quite a smart decision, because I can &lt;em&gt;guarantee &lt;/em&gt;that more work has gone into optimizing the OS memory manager than could have been invested by the MongoDB project. But that is just part of the work.&lt;/p&gt; &lt;p&gt;In RavenDB, we are actually a managed application, so we don’t have directly control over memory. That doesn’t mean that we don’t actually manage it. We have several layers of caching in place, exactly &lt;em&gt;because&lt;/em&gt; we know more than the OS about our own usage scenarios. In many cases, even if you are making a totally new request, it would never hit the disk, because we are keeping track on hot data and making sure that it resides in memory. This applies to both indexes and documents, mind. And during the indexing process we are &lt;em&gt;very&lt;/em&gt; careful about memory management. &lt;/p&gt; &lt;p&gt;Sure, the OS memory manager is more optimized, but &lt;em&gt;the database&lt;/em&gt; knows what is going on, and can predict its own usage patterns. That is how RavenDB does a lot of magic relating to auto configuration.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;Uncompressed field names&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;In MongoDB, it is considered good practice to &lt;a href="http://www.mongodb.org/display/DOCS/Optimizing+Storage+of+Small+Objects"&gt;shorten field names&lt;/a&gt; for space optimization. But MongoDB doesn’t do it for you automatically.&lt;/p&gt; &lt;p&gt;RavenDB doesn’t compress field names, but at the same time, it isn’t a good practice to do so. In fact, I think that this is a &lt;a href="http://ayende.com/blog/4669/you-saved-5-cents-and-your-code-is-not-readable-congrats"&gt;horrible little mess&lt;/a&gt;. There are a lot of arguments against compressing field names, not the least of which is that it makes it pretty hard to figure out what it is that you are actually trying to do. Looking at the raw data, something that is done fairly frequently when debugging and troubleshooting becomes harder to work with and manage:&lt;/p&gt; &lt;blockquote&gt;&lt;pre class="csharpcode"&gt;{
  &lt;span class="str"&gt;"a2"&lt;/span&gt;: &lt;span class="str"&gt;"nathan "&lt;/span&gt;,
  &lt;span class="str"&gt;"d3"&lt;/span&gt;: &lt;span class="str"&gt;""&lt;/span&gt;,
  &lt;span class="str"&gt;"a2"&lt;/span&gt;: &lt;span class="str"&gt;"2012-05-17T00:00:00.0000000"&lt;/span&gt;,
  &lt;span class="str"&gt;"h3"&lt;/span&gt;: &lt;span class="str"&gt;"2012-04-15T00:00:00.0000000"&lt;/span&gt;,
  &lt;span class="str"&gt;"r2"&lt;/span&gt;: &lt;span class="str"&gt;"archanid@sample.com"&lt;/span&gt;,
  &lt;span class="str"&gt;"o2"&lt;/span&gt;: &lt;span class="str"&gt;"8169cd4a-babf-4015-a3c7-4d503642e021"&lt;/span&gt;,
  &lt;span class="str"&gt;"o1"&lt;/span&gt;: &lt;span class="str"&gt;"products/NHProf"&lt;/span&gt;
}&lt;/pre&gt;
&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
&lt;/style&gt;
&lt;/blockquote&gt;
&lt;p&gt;Anyone wants to figure out what this document is about? And at least in this one, the data itself tells you a lot about the actual content. &lt;/p&gt;
&lt;p&gt;There are &lt;em&gt;far&lt;/em&gt; better alternatives in place. In RavenDB, we do full response / request compression, and we allow to do document compression on disk as well. If we were ever to get to the point where this would be a serious problem (and so far, it isn’t, even on large data sets), it would be less than a week of work to implement string interning inside RavenDB, so we would use the same string references for field values.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Global write lock&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;MongoDB (as of the current version at the time of writing: 2.0), has a &lt;em&gt;process-wide write lock&lt;/em&gt;. … At this point, all other operations &lt;em&gt;including reads&lt;/em&gt; are blocked because of the write lock.&lt;/p&gt;
&lt;p&gt;Now, to be fair, also have a write lock, but it isn’t nearly as bad as it is in MongoDB. RavenDB write lock is actually for… writes, and it doesn’t interfere with the either reads or indexes. It is on the list of things to remove, but the crazy part is. So far, and we have really demanding users, no one cares. The &lt;em&gt;reason&lt;/em&gt; that no one cares is that this is really small lock, and it only affects writes, it is not Stop the World type of thing.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Safe off by default&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I am just going to let Kiip’s words stand for themselves (emphasis mine): &lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;This is a &lt;em&gt;crazy &lt;/em&gt;default, although useful for &lt;em&gt;benchmarks&lt;/em&gt;. As a general analogy: it’s like a car manufacturer shipping a car with air bags off, then shrugging and saying “you could’ve turned it on” when something goes wrong. &lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;RavenDB entire &lt;em&gt;philosophy &lt;/em&gt;is around Safe by Default. That is the only thing that really make sense, because otherwise… Well… here is what happenned at Kiip:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;We &lt;em&gt;lost a sizable amount of data &lt;/em&gt;at Kiip for some time before realizing what was happening and using safe saves where they made sense (user accounts, billing, etc.).&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Offline table compaction&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Every now and then, you need to take down MongoDB and let it compact its on disk data. This is another Stop the World operation, and the only way to keep up when you do so is to have a hot standby ready.&lt;/p&gt;
&lt;p&gt;RavenDB does all maintenance task while the server is up and serving requests. You don’t need any downtime just because RavenDB need to arrange some data on disk, we take care of that live, and with no interruption in service.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Secondaries do not keep hot data in RAM&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;As Kiip explains it:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The primary doesn’t relay queries to secondary servers, preventing secondaries from maintaining hot data in memory. This severely hinders the “hot-standby” feature of replica sets, since the moment the primary fails and switches to a secondary, all the hot data must be once again faulted into memory.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;RavenDB doesn’t do so either, but for a drastically different reason. As I mentioned earlier, the way RavenDB works is quite different. When you are running a hot standby node, it will get the new data from the server and index it. We keep the index open, so for a lot of the data, it is already going to &lt;em&gt;be&lt;/em&gt; in memory. For the rest, as I mentioned, we have several layers of caches that would help prevent needing to page gigabytes on data into memory.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;As an utterly &lt;em&gt;unbiased&lt;/em&gt; observer (&lt;img style="border-bottom-style: none; border-left-style: none; border-top-style: none; border-right-style: none" class="wlEmoticon wlEmoticon-smile" alt="Smile" src="http://ayende.com/blog/Images/Windows-Live-Writer/7f34976f1b29_8292/wlEmoticon-smile_2.png"&gt;), I can say that RavenDB rocks.&lt;/p&gt;
&lt;p&gt;What we are actually seeing here is that RavenDB put different emphasis on different things. I really care for making the common application level scenarios easy and nice to work with. And I had enough time supporting production level apps that I tried very hard to make sure that RavenDB can take care of itself for most scenarios without any hand holding.&lt;/p&gt;</description><link>http://ayende.com/blog/156129/re-kiiprsquo-s-mongodbrsquo-s-experience?key=34daf972-8f8a-4613-b47d-dc2d40016f02</link><guid>http://ayende.com/blog/156129/re-kiiprsquo-s-mongodbrsquo-s-experience?key=34daf972-8f8a-4613-b47d-dc2d40016f02</guid><pubDate>Sun, 15 Apr 2012 04:29:00 GMT</pubDate></item><item><title>RavenDB Course&amp;ndash;Israel</title><description>&lt;p&gt;I got repeated calls for doing a RavenDB in Israel, and it really makes little sense not to do one here, since it is the one we would have the easiest time running. &lt;/p&gt; &lt;p&gt;Therefor, I am pleased to announce that our two days RavenDB course is going to open in Israel on the 11 – 12 July. We are going to do the course in our offices in Hadera, and part of the course will include interaction with the actual development team. &lt;/p&gt; &lt;p&gt;You can register for the course using the &lt;a href="http://www.eventi.co.il/Events/Event.aspx?eID=901125178"&gt;following link&lt;/a&gt;. We provide early bird registration until the 16th May.&lt;/p&gt; &lt;p&gt;The course is going to be in English, and is open for people from outside of Israel as well.&lt;/p&gt;</description><link>http://ayende.com/blog/155681/ravendb-coursendash-israel?key=cda0113c-9f51-4c43-bfd4-5ccdbe91d382</link><guid>http://ayende.com/blog/155681/ravendb-coursendash-israel?key=cda0113c-9f51-4c43-bfd4-5ccdbe91d382</guid><pubDate>Sun, 01 Apr 2012 10:52:00 GMT</pubDate></item><item><title>What have we been up to? And some future plans</title><description>&lt;p&gt;We have been head down for a while, doing some really cool things with RavenDB (sharding, read striping, query intersection, indexing reliability and more). But that meant that for a while,things that are not about writing code for RavenDB has been more or less on auto-pilot.&lt;/p&gt; &lt;p&gt;So here are some things that we are planning. We will increase the pace of RavenDB courses and conference presentation. You can track it all in the &lt;a href="http://ravendb.net/events"&gt;RavenDB events page&lt;/a&gt;.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;Conferences&lt;/strong&gt;&lt;/p&gt; &lt;ul&gt; &lt;li&gt;&lt;a href="http://skillsmatter.com/event/nosql/progressive-nosql-tutorials"&gt;Progressive NoSQL – RavenDB – 2nd generation document database&lt;/a&gt;.– May 9&amp;nbsp; London – I’ll be talking about RavenDB to a crowd of NoSQL enthusiastic, should be interesting, especially the compare &amp;amp; contrast part.  &lt;li&gt;&lt;a href="http://skillsmatter.com/podcast/home/ayende-ravendb/js-3919"&gt;Sharding and Scaling with RavenDB&lt;/a&gt; – May 15, London – Prepare for some truly awesome demos.  &lt;li&gt;&lt;a href="http://devsum.se/talare/ayende-rahien/"&gt;DevSum 20120 - RavenDB and the Amazing Features&lt;/a&gt; – May 23 , Stockholm, I am going to try and go through some of the more cool features of RavenDB, stuff that is going to make you go gaga wanting to use it.  &lt;li&gt;&lt;a href="http://ndcoslo.oktaset.com/t-4913"&gt;NDC 2012 – RavenDB Data Modeling&lt;/a&gt; – June 7, Oslo. Itamar is going to go over how to model data in RavenDB. This is one of the greatest challenges people moving over to RavenDB from RDBMS are facing, and Itamar is going to cover common scenarios and walkthrough about how to approach the problem.  &lt;li&gt;&lt;a href="http://oredev.org/"&gt;Ordev 2012 - Sharding and Scaling with RavenDB&lt;/a&gt; – Nov 5, Malmo.&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;&lt;strong&gt;RavenDB Courses&lt;/strong&gt;&lt;/p&gt; &lt;ul&gt; &lt;li&gt;&lt;a href="mailto:R@RavenDB Workshop"&gt;2 Days RavenDB Workshop&lt;/a&gt; – Oren Eini – May 14, London.  &lt;li&gt;&lt;a href="http://www.cornerstone.se/Web/Templates/CoursePage.aspx?id=2513&amp;amp;course=COUR2012012314201105395937&amp;amp;epslanguage=SV"&gt;2 Days RavenDB Workshop&lt;/a&gt; – Oren Eini – May 21, Stockholm.  &lt;li&gt;&lt;a href="http://www.ndcoslo.com/Workshop/ravendb"&gt;2 Days RavenDB Workshop&lt;/a&gt; – Itamar Syn-Hershko – June 4, Oslo.  &lt;li&gt;&lt;a href="http://www.labcenter.se/lab/2129"&gt;2 Days RavenDB Workshop&lt;/a&gt; – Oren Eini – June 28, Malmo.  &lt;li&gt;&lt;a href="http://skillsmatter.com/course/open-source-dot-net/ayende-rahien-ravendb-workshop-nyc/ps-3784"&gt;2 Days RavenDB Workshop&lt;/a&gt; – Itamar Syn-Hershko – Aug 21, New York.  &lt;li&gt;&lt;a href="https://skillsmatter.com/register-online/course/2436"&gt;2 Days RavenDB Workshop&lt;/a&gt; – Itamar Syn-Hershko – Sep 12, London.&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;&lt;strong&gt;NHibernate Courses&lt;/strong&gt;&lt;/p&gt; &lt;ul&gt; &lt;li&gt;&lt;a href="http://skillsmatter.com/course/open-source-dot-net/ayende-rahiens-nhibernate-3-0-workshop/ps-398"&gt;3 Days NHibernate 3.x Workshop&lt;/a&gt; – Oren Eini, May 16, London.&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;&lt;strong&gt;Not finalized yet&lt;/strong&gt;&lt;/p&gt; &lt;ul&gt; &lt;li&gt;August 2012.  &lt;ul&gt; &lt;li&gt;User groups talks in Philadelphia &amp;amp; Washington DC by Itamar Syn-Hershko.  &lt;li&gt;One day boot camp for moving from being familiar with RavenDB to being a master in Chicago.&lt;/li&gt;&lt;/ul&gt; &lt;li&gt;September 2012.  &lt;ul&gt; &lt;li&gt;RavenDB Course in Austin, Texas.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;&lt;strong&gt;Consulting Opportunities&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;We are also available for on site consulting in the following locations and times. Please contact us directly if you would like to arrange for one of RavenDB core team to show up at your door step. Or if you want me to do architecture or NHibernate consulting.&lt;/p&gt; &lt;ul&gt; &lt;li&gt;Oren Eini – Malmo, June 26 – 27.  &lt;li&gt;Oren Eini – Berlin, July 2 – 4.  &lt;li&gt;Itamar Syn-Hershko – New York, Aug 23.  &lt;li&gt;Itamar Syn-Hershko – Chicago, Aug 30 or Sep 3.  &lt;li&gt;Itamar Syn-Hershko – Austin, Sep 3.  &lt;li&gt;Itamar Syn-Hershko – Toronto, Sep 9 – 10.  &lt;li&gt;Itamar Syn-Hershko – London, Sep 11.&lt;/li&gt;&lt;/ul&gt;</description><link>http://ayende.com/blog/155649/what-have-we-been-up-to-and-some-future-plans?key=abbae717-a233-4f7f-a84c-fdeba1b59459</link><guid>http://ayende.com/blog/155649/what-have-we-been-up-to-and-some-future-plans?key=abbae717-a233-4f7f-a84c-fdeba1b59459</guid><pubDate>Fri, 30 Mar 2012 10:00:00 GMT</pubDate></item></channel></rss>
