Ayende @ Rahien

Refunds available at head office

RavenDB Lazy Requests

In my previous post, I discussed the server side implementation of lazy requests / Multi GET. The ability to submit several requests to the server in a single round trip. RavenDB has always supported the ability to perform multiple write operations in a single batch, but now we have the reverse functionality the ability to make several reads at one. (The natural progression, the ability to make several read/write operations in a single batch will not be supported).

As it turned out, it was actually pretty hard to do, and require us to do some pretty deep refactoring to the way we were executing our requests, but in the end it is here and it is working. Here are a few examples of how it looks line from the client API point of view:

var lazyUser = session.Advanced.Lazily.Load<User>("users/ayende");
var lazyPosts = session.Query<Posts>().Take(30).Lazily();

And up until now, there is actually nothing being sent to the server. The result of those two calls are Lazy<User> and Lazy<IEnumerable<Post>>, respectively.

The reason that we are using Lazy<T> in this manner is that we want to make it very explicit when you are actually evaluating the lazy request. All the lazy requests will be sent to the server in a single roundtrip the first time that any of the lazy instances are evaluated, or you can force this to happen by calling:

session.Advanced.Eagerly.ExecuteAllPendingLazyOperations();

In order to increase the speed even more, on the server side, we are actually going to process all of those queries in parallel. So you get several factors that would speed up your application:

  • Only a single remote call is made.
  • All of the queries are actually handled in parallel on the server side.

And the best part, you usually don’t really have to think about it. If you use the Lazy API, it just works Smile.

Tags:

Posted By: Ayende Rahien

Published at

Originally posted at

Comments

Simon Bartlett
08/19/2011 10:02 AM by
Simon Bartlett

I hope .Laziliy() is only spelt incorrectly in this code sample? ;)

njy
08/19/2011 10:56 AM by
njy

There is a way from the client to enable/disable the parallel execution of batched lazy requests? I'm thinking about a classic "insert doc" -> "get latst 5 doc" flow: i would be able to use the lazy evaluation, eventually, but i also would like to mantain the order of the single requests.

Waddaya think, am i missing something?

Kurke
08/19/2011 11:47 AM by
Kurke

A question about the API - You have the .Lazily part. This means you have to duplicate your API to support each action, lazily (returns Lazy instead of T...).

What do you think about the following? var lazyUser = session.Advanced.Lazily(x => x.Load("users/ayende")); Where here Lazily is a simple extension method that returns Lazy.

(I am a young programmer, I really don't know which option to prefer :)...)

Daniel Lidström
08/19/2011 01:19 PM by
Daniel Lidström

Perhaps you should trademark that last statement: It Just Works :-) Oh, maybe it's taken already, oh well :-)

tobi
08/19/2011 02:54 PM by
tobi

I detest the fluent naming style very much. It does not even help with reading. Reminds me of the early attempts to make managers able to read code 30 years ago by using natural language syntax. Never works, never helps. Just goes against existing naming conventions.

Nabil
08/19/2011 09:57 PM by
Nabil

Agree with tobi. Don't really like the fluent Lazily in session.Advanced.Lazily.Load("users/ayende"). Would prefer consistently using Lazily() extension method throughout.

Ayende Rahien
08/20/2011 01:30 AM by
Ayende Rahien

Simon, Yes, the typo is only in the post, and has been fixed

Ayende Rahien
08/20/2011 01:31 AM by
Ayende Rahien

Njy, You can't mix read / write requests, that is not an issue

Ayende Rahien
08/20/2011 01:32 AM by
Ayende Rahien

Kurke, There are only 2 - 3 things that actually need this, and trying to implement the API that you have in mind would be freakishly complex and very brittle

Frans Bouma
08/20/2011 09:43 AM by
Frans Bouma

Executing queries in parallel on the server... That might actually be slower than executing them in sequence, due to I/O. If, say, 4 queries are executed in parallel and they touch data in multiple places on disk, it will take the HDD several step actions to fulfill the parallel queries, as it has to step back and forth. This is slow. doing the queries in sequence actually might be faster, as the HDD then doesn't have to step that often.

Walter Poch
08/20/2011 06:02 PM by
Walter Poch

Will you implement this on the Blog? I want to check how the profiler looks like after this =)

Congrats!

Alex K
08/20/2011 08:25 PM by
Alex K

I'm curious about why the two different techniques were chosen for the two scenarios in the examples given. Is it a technical limitation (inordinate difficulty of implementing Lazily for Load, maybe?) that prevents the .Lazily() from being the one API to rule them all? Would've aligned it better with PLINQ's .AsParallel(), AsOrdered(), etc. usage.

Alex K
08/20/2011 08:28 PM by
Alex K

I should read comments before I post. So instead, I'll make feature request for the blog to delete and edit the comments.

Ayende Rahien
08/21/2011 07:48 AM by
Ayende Rahien

Frans, That ignores caching and parallel IO, though

Ayende Rahien
08/21/2011 07:50 AM by
Ayende Rahien

Walter, The problem is that we tried, and it turns out that there aren't any queries that we can do this on using our architecture. It would requires us to do pull things together that are currently separated. You can look at what Raccoon Blog is doing to see how this works

Ayende Rahien
08/21/2011 07:51 AM by
Ayende Rahien

Alex, Two different use cases, as AsLazy wouldn't work, the Lazily has to be the last thing happening on the query

Comments have been closed on this topic.