Thursday, June 14, 2012

Working around RavenDB and Safe-By-Default

I have seen these questions from time to time.
"How can I get all of the documents in RavenDB?"
"How can I force RavenDB to return more documents that the "safe-by-default" limits?"
The questions above usually stem from someone needing to work around the "safe-by-default" protection due to some sort of special circumstance. So if you find yourself needing these techniques more often than not, then you are doing it wrong.

You can change the RavenDB configuration by increasing the default PageSize, but that is a global change. Instead you need to do two things.
  1. Ensure that you start a new DocumentSession when you reach the  MaxNumberOfRequestsPerSession limit.
  2. Make sure you page the query with respect to the RavenDB PageSize (which is 1024 by default).
The RavenDB paging mechanism will not override the configured maximum number of items allowed per page. So if you try to Take() more than the configured limit, you will not get an error. Instead RavenDB's safe-by-default kicks in and will impose the configured page size on your results.

Below is an example that gets all document id values that match the predicate.

IDocumentSession session = null;
try
{
    session = MvcApplication.DocumentStore.OpenSession();

    List<string> ravenPageIds = null;
    const int RAVEN_MAX_PAGE_SIZE = 1024;
    int currentPageNumber = 0;

    do
    {
        List<string> tempRavenPageIds  = (from p in session.Query<Page>()
                                          where p.IsActive == true
                                          select p.Id)
                                          .Skip(currentPageNumber++ * RAVEN_MAX_PAGE_SIZE)
                                          .Take(RAVEN_MAX_PAGE_SIZE).ToList();

        ravenPageIds.AddRange(tempRavenPageIds);

        if (session.Advanced.NumberOfRequests >= session.Advanced.MaxNumberOfRequestsPerSession)
        {
            session.Dispose();
            session = MvcApplication.DocumentStore.OpenSession();
        }
    } while (tempRavenPageIds.Count == RAVEN_MAX_PAGE_SIZE);
}
finally
{
    session.Dispose();
}

We had code similar to this that needed to run when an MVC Application started (in order to build page routing table). But since then, we were able to refactor the code such that we no longer need to employ this technique. Rather than simply throw it away, perhaps you may find it useful.


Links