<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0"><channel><title>Ayende @ Rahien</title><link>https://ayende.com/blog/</link><description>Ayende @ Rahien</description><copyright>Copyright (C) Ayende Rahien  2004 - 2017 (c) 2017</copyright><ttl>60</ttl><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/AyendeRahien" /><feedburner:info uri="ayenderahien" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><item><title>Inside RavenDB 4.0: Chapter 6 is done</title><description>&lt;p&gt;I’ve just completed writing chapter 6 (distributed RavenDB) and &lt;a href="https://github.com/ravendb/book/releases/tag/v4.0.6-preview"&gt;pushed a preview up&lt;/a&gt;. This put the page count at over 200 pages so far, with another two thirds or so left. &lt;/p&gt;&lt;p&gt;This chapter was really hard to write, and I would really appreciate any feedback that you have on the text and on the distributed nature of RavenDB 4.0 in general. It is very similar and a different beast entirely then 3.x.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/AyendeRahien/~4/im9KLKQXqSU" height="1" width="1" alt=""/&gt;</description><link>http://feedproxy.google.com/~r/AyendeRahien/~3/im9KLKQXqSU/inside-ravendb-4-0-chapter-6-is-done</link><guid isPermaLink="false">https://ayende.com/blog/179073/inside-ravendb-4-0-chapter-6-is-done?Key=392ff8b8-8d1b-4f59-b7ff-d516ccb6d78e</guid><pubDate>Mon, 17 Jul 2017 06:00:00 GMT</pubDate><feedburner:origLink>https://ayende.com/blog/179073/inside-ravendb-4-0-chapter-6-is-done?Key=392ff8b8-8d1b-4f59-b7ff-d516ccb6d78e</feedburner:origLink></item><item><title>Reviewing Resin: Part III</title><description>&lt;p&gt;In the &lt;a href="https://ayende.com/blog/178946/reviewing-resin-part-ii?key=154eea776556429294f50838c0174e89"&gt;previous part&lt;/a&gt;, I started looking at UpsertTransacction, but got sidetracked into the utils functions. Let us focus back on this. The key parts of UpsertRansaction are:&lt;/p&gt;&lt;p&gt;&lt;a href="https://ayende.com/blog/Images/Open-Live-Writer/Reviewing-Resin-Part-II_1352E/image_6.png"&gt;&lt;img width="320" height="45" title="image" style="margin: 0px; border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="image" src="https://ayende.com/blog/Images/Open-Live-Writer/Reviewing-Resin-Part-II_1352E/image_thumb_2.png" border="0"&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;Let us see what they are. The DocumentStream is the source of the documents that will be written in this transaction, its job is to get the documents to be indexed, to give them a unique id if they don’t already have one and hash them.&lt;/p&gt;&lt;p&gt;I’m not sure yet what is the point there, but we have this:&lt;/p&gt;&lt;p&gt;&lt;a href="https://ayende.com/blog/Images/Open-Live-Writer/Reviewing-Resin-Part-II_1352E/image_8.png"&gt;&lt;img width="1053" height="151" title="image" style="margin: 0px; border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="image" src="https://ayende.com/blog/Images/Open-Live-Writer/Reviewing-Resin-Part-II_1352E/image_thumb_3.png" border="0"&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;Which sounds bad. The likelihood is small, but it isn’t a crypto hash, so likely very easily broken. For example, look at what happened to &lt;a href="https://en.wikipedia.org/wiki/MurmurHash#Vulnerabilities"&gt;MurmurHash&lt;/a&gt;. &lt;/p&gt;&lt;p&gt;I think that this is later used to handle some partitioning in the trie, but I’m not sure yet. We’ll look at the _storeWriter later. Let us see what the UpsertTransaction does. It builds a trie, then push each of the document from the stream to through the trie. The code is doing a lot of allocations, but I’m going to stop harping at that from now on.&lt;/p&gt;&lt;p&gt;The trie is called for each term for each document with the following information:&lt;/p&gt;&lt;p&gt;&lt;a href="https://ayende.com/blog/Images/Open-Live-Writer/Reviewing-Resin-Part-II_1352E/image_12.png"&gt;&lt;img width="762" height="36" title="image" style="margin: 0px; border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="image" src="https://ayende.com/blog/Images/Open-Live-Writer/Reviewing-Resin-Part-II_1352E/image_thumb_5.png" border="0"&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;The code isn’t actually using tuple, I just collapsed a few classes to make it clear what the input is. &lt;/p&gt;&lt;p&gt;This is what will eventually allow the trie to do lookups on a term and find the matching document, I’m assuming.&lt;/p&gt;&lt;p&gt;That method is going to start a new task for that particular field name, if it is new, and push the new list of words for that field into the work queue for that task. The bad thing here is that we are talking about a &lt;em&gt;blocking&lt;/em&gt; task, so if you have a lot of fields, you are going to spawn off a &lt;em&gt;lot&lt;/em&gt; of threads, one per field name.&lt;/p&gt;&lt;p&gt;What I know now is that we are going to have a trie per field, and it is likely, based on the design decisions made so far, that a trie isn’t a small thing. &lt;/p&gt;&lt;p&gt;Next, the UpsertTransaction need to write the document, this is done taking the document we are processing and turning that into a dictionary of short to string. I’m not sure how it is supposed to handle multiple values for the same field, but I’ll ignore that for now. That dictionary is then saved into a file and its length and positions are returned.&lt;/p&gt;&lt;p&gt;I know that I said that I won’t talk about performance, but I looked at the serialization code and I saw that it is using compression, like this. This is done on a field by field basis, while you could probably benefit from compressing them all together.&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;&lt;a href="https://ayende.com/blog/Images/Open-Live-Writer/Reviewing-Resin-Part-II_1352E/image_16.png"&gt;&lt;img width="983" height="269" title="image" style="margin: 0px; border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="image" src="https://ayende.com/blog/Images/Open-Live-Writer/Reviewing-Resin-Part-II_1352E/image_thumb_7.png" border="0"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Those are a lot of allocations, and then we go a bit deeper:&lt;/p&gt;&lt;p&gt;&lt;a href="https://ayende.com/blog/Images/Open-Live-Writer/Reviewing-Resin-Part-II_1352E/image_4.png"&gt;&lt;img width="706" height="210" title="image" style="margin: 0px; border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="image" src="https://ayende.com/blog/Images/Open-Live-Writer/Reviewing-Resin-Part-II_1352E/image_thumb.png" border="0"&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;First, we have the allocation of the memory stream, then the ToArray call, and that happens, per field, per document. Actually, if we go &lt;em&gt;up&lt;/em&gt;, we’ll see: &lt;/p&gt;&lt;p&gt;&lt;a href="https://ayende.com/blog/Images/Open-Live-Writer/Reviewing-Resin-Part-II_1352E/image_20.png"&gt;&lt;img width="802" height="193" title="image" style="margin: 0px; border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="image" src="https://ayende.com/blog/Images/Open-Live-Writer/Reviewing-Resin-Part-II_1352E/image_thumb_9.png" border="0"&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;So it is allocations all the way down. &lt;/p&gt;&lt;p&gt;Okay, let us focus on what is going on in terms of files:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;"write.lock" – this one is pretty obvious&lt;/li&gt;&lt;li&gt;*.da – stands for document address. Holds a series of (long Position, int Size) of document addresses. I assume that this is using the same sort as something else, not sure yet. The fact that this is fixed size means that we can easily skip into it.&lt;/li&gt;&lt;li&gt;*.rdoc – documents are stored here. Contains the actual serialized data for the documents (the Dictionary&amp;lt;short, Field&amp;gt;), this is the target for the addresses that are held by the “*.da” files.&lt;/li&gt;&lt;li&gt;*.pk – holds document hashes. Holds a list of document pk hash and a flag saying if it is deleted, I’m assuming. From context, it looks like the hash is a way to update documents across transactions. &lt;/li&gt;&lt;li&gt;*.kix – key index. Text file holding the names of all the fields across the entire transaction. &lt;/li&gt;&lt;li&gt;*.pos – posting file. This one holds the tries that were built during the transaction. This is basically just List&amp;lt;(int DocumentId, int Count)&amp;gt;, but I’m not sure how they are used just yet. It looks like this is how Resin is able to get the total term frequency per document. It looks like this is also sorted.&lt;/li&gt;&lt;li&gt;*.tri – the trie files that actually contain the specific values for a particular field. The name pattern is “{indexVersion}-{fieldName}.tri”. That means that your field names are limited to valid file names, by the way.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;The last part of the UpsertTransaction is the commit, which essentially boil down to this:&lt;/p&gt;&lt;p&gt;&lt;a href="https://ayende.com/blog/Images/Open-Live-Writer/Reviewing-Resin-Part-II_1352E/image_13.png"&gt;&lt;img width="517" height="157" title="image" style="margin: 0px; border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="image" src="https://ayende.com/blog/Images/Open-Live-Writer/Reviewing-Resin-Part-II_1352E/image_thumb_1.png" border="0"&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;I think that this was very insightful read, I have a much better understanding of how Resin actually work. I’m going to speculate wildly, and then use my next post to check further into that.&lt;/p&gt;&lt;p&gt;Let us say that we want to search for all users who live in New York City. We can do that by opening the “636348272149533175-City.tri” file. The 636348272149533175 is the index version, by the way.&lt;/p&gt;&lt;p&gt;Using the trie, we search for the value of New York City. The trie value actually give us a (long Position, int Size) into the 636348272149533175.pos file, which holds the posting. Basically, we now have an array of (int DocumentId, int Count) of the documents that matched that particular value. &lt;/p&gt;&lt;p&gt;If we want to retrieve those documents, we can use the 636348272149533175.da file, which holds the addresses of the documents. Again, this is effectively an array of (long Position, int Size) that we can index into using the DocumentId. This points to the location on the 636348272149533175.rdoc file, which holds the actual document data. &lt;/p&gt;&lt;p&gt;I’m not sure yet what the point of *.pa and *.kix is, but I’m sure the next post we’ll figure it out.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/AyendeRahien/~4/sO1Qszcpy6s" height="1" width="1" alt=""/&gt;</description><link>http://feedproxy.google.com/~r/AyendeRahien/~3/sO1Qszcpy6s/reviewing-resin-part-iii</link><guid isPermaLink="false">https://ayende.com/blog/178947/reviewing-resin-part-iii?Key=c73f964b-561b-4bfa-ab80-a72624d4e568</guid><pubDate>Fri, 14 Jul 2017 09:00:00 GMT</pubDate><feedburner:origLink>https://ayende.com/blog/178947/reviewing-resin-part-iii?Key=c73f964b-561b-4bfa-ab80-a72624d4e568</feedburner:origLink></item><item><title>RavenDB 4.0: The admin’s backdoor is piping hot</title><description>&lt;p&gt;&lt;a href="https://ayende.com/blog/Images/Open-Live-Writer/4e6b2f6c6fe8_12B92/image_2.png"&gt;&lt;img width="356" height="256" title="image" align="right" style="border: 0px currentcolor; border-image: none; float: right; display: inline; background-image: none;" alt="image" src="https://ayende.com/blog/Images/Open-Live-Writer/4e6b2f6c6fe8_12B92/image_thumb.png" border="0"&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;We take security very seriously. With the move to &lt;a href="https://ayende.com/blog/178977/ravendb-4-0-securing-the-keys-to-the-kingdom"&gt;X509 certificates only for authentication&lt;/a&gt; (on all RavenDB editions) I feel that we have a really good story around securing RavenDB and controlling access to it. &lt;/p&gt;&lt;p&gt;Almost. One of the more annoying things about security is that you also need to consider the hard cases, such as the administrators messing up &lt;em&gt;badly&lt;/em&gt;. As in, losing the credentials that allows you to administrator RavenDB. This can happen because the database has just run without issue for so long that no one can remember where the keys are. That isn’t supposed to happen, but RavenDB has been in production usage for close to a decade now, which mean that we have seen our fair share of mess ups (both our own and by customers).&lt;/p&gt;&lt;p&gt;In some cases, we have had to help a customer manage a &lt;em&gt;third &lt;/em&gt;system handover between different hosting providers, which felt very much half like forensic and half like hacking. In short, when we design a system now, we also consider the fact that as secure as we want the system to be, there must be a way for an authorized person to get in.&lt;/p&gt;&lt;p&gt;If this made you cringe, you are in good company. I both love and hate this feature. I love it because it is going to be very useful, I hate it because it was a headache to figure it right. But I’m jumping ahead of myself. What &lt;em&gt;is&lt;/em&gt; this backdoor that I’m talking about?&lt;/p&gt;&lt;p&gt;Properly configured RavenDB will require a client certificate (that was registered in the cluster) to access the server. However, in addition to listening over HTTPS, RavenDB will also listen for commands on standard input. An admin can use the standard input / output as a way to talk with RavenDB without requiring any authentication. Basically, we expose a mini shell that you can use to enter commands and inspect and change our state.&lt;/p&gt;&lt;p&gt;Here is how it looks like when running in console mode:&lt;/p&gt;&lt;p&gt;&lt;a href="https://ayende.com/blog/Images/Open-Live-Writer/4e6b2f6c6fe8_12B92/image_4.png"&gt;&lt;img width="644" height="428" title="image" style="border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="image" src="https://ayende.com/blog/Images/Open-Live-Writer/4e6b2f6c6fe8_12B92/image_thumb_1.png" border="0"&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;From a security point of view, if a user is able to access my standard input, that usually means that they are the one that have run this process or are able to so. RavenDB obviously won’t have any setuid bits turned on, so no need to worry about a user tricking us to do something that the user don’t have permissions to do.&lt;/p&gt;&lt;p&gt;So using the console is a really nice way for us to offer the administrator an escape hatch to start messing with the internals of RavenDB in interesting way. However, that only work if you are running RavenDB in interactive mode. What about when running as a service or daemon? They don’t have a standard input that is available to the admin. In fact, in most production deployments, you won’t have an easy time at &lt;em&gt;all&lt;/em&gt; trying to connect to the console. &lt;/p&gt;&lt;p&gt;So that option is out, sadly. Or is it?&lt;/p&gt;&lt;p&gt;The nice thing about operating systems is that we can lean on them. In this case, we expose the exact same console that we have for stdin / stdout using Named Pipes (actually, Unix Sockets in Linux / Mac, but pretty much the same idea). The idea is that those are both methods for inter process communication that are local to the machine and can be secured by the operating system directly. In this case, we make sure that the pipe is only accessible to the RavenDB user (and to root / Administrator, obviously). That means that an admin can log into the box, run a single command and land in the RavenDB admin shell where he can manage the server. For example, by registering a new certificate in the server &lt;img class="wlEmoticon wlEmoticon-smile" style="" alt="Smile" src="https://ayende.com/blog/Images/Open-Live-Writer/4e6b2f6c6fe8_12B92/wlEmoticon-smile_2.png"&gt;.&lt;/p&gt;&lt;p&gt;Because only the user running the RavenDB process or an administrator / root can access the pipe (ensured by setting the proper ACL on the pipe during creation) we know that there isn’t any security risk here. An admin can already override any security in the box, and the permissions are always on the user level, not the process level, so if you are running as the same user as the RavenDB process you can already do anything that RavenDB can do. &lt;/p&gt;&lt;p&gt;After we ensured that our security isn’t harmed by this option, we can relax knowing that we have an easy (and safe) way for the administrator to manage the server in an emergency. &lt;/p&gt;&lt;p&gt;In fact, the most obvious usage of this feature is during initial cluster setup, when you &lt;em&gt;don’t&lt;/em&gt; have anything yet. This allow you to enter the system as a trusted party and do the initial configuration.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/AyendeRahien/~4/hSpXEJXJ7HE" height="1" width="1" alt=""/&gt;</description><link>http://feedproxy.google.com/~r/AyendeRahien/~3/hSpXEJXJ7HE/ravendb-4-0-the-admins-backdoor-is-piping-hot</link><guid isPermaLink="false">https://ayende.com/blog/179009/ravendb-4-0-the-admins-backdoor-is-piping-hot?Key=9c84ed81-fb07-45d6-9bfd-933676c2d1d7</guid><pubDate>Thu, 13 Jul 2017 09:00:00 GMT</pubDate><feedburner:origLink>https://ayende.com/blog/179009/ravendb-4-0-the-admins-backdoor-is-piping-hot?Key=9c84ed81-fb07-45d6-9bfd-933676c2d1d7</feedburner:origLink></item><item><title>Reviewing Resin: Part II</title><description>&lt;p&gt;In the &lt;a href="https://ayende.com/blog/178945/reviewing-resin-part-i?key=457d59ed93ed44cebbb25ace8f71d561"&gt;first pat&lt;/a&gt; of this series, I looked into how &lt;a href="https://github.com/kreeben/resin"&gt;Resin&lt;/a&gt; is tokenizing and analyzing text. I&amp;rsquo;m still reading the code from the tests (this is because the Tests folder sorted higher then the Resin folder, basically) and I now moved to the second file, CollectorTests.&lt;/p&gt;
&lt;p&gt;That one has a really interesting start:&lt;/p&gt;
&lt;blockquote&gt;
&lt;script src="https://gist.github.com/ayende/0534678b901b08d3a0d34f7ab9ca8f75.js"&gt;&lt;/script&gt;
&lt;/blockquote&gt;
&lt;p&gt;There are a lot of really interesting things here, UpsertTransaction, document structure, issuing queries, etc. UpsertTransaction is a good place to start looking around, so let us poke in. When looking at it, we can se a &lt;em&gt;lot&lt;/em&gt; of usage in the Utils class, so I&amp;rsquo;ll look at that first.&lt;/p&gt;
&lt;blockquote&gt;
&lt;script src="https://gist.github.com/ayende/60b4e3e3b050d957a317cef66a01acb0.js"&gt;&lt;/script&gt;
&lt;/blockquote&gt;
&lt;p&gt;This is probably a bad idea. While using the current time ticks seems like it would generate ever increasing values, that is actually &lt;em&gt;not&lt;/em&gt; the case, certainly not with local time (clock shift, daylight saving, etc). Using that for the purpose of generating a file id is probably a mistake. It is better to use our own counter, and just keep track of the last one we used on the file system itself.&lt;/p&gt;
&lt;p&gt;Then we have this:&lt;/p&gt;
&lt;blockquote&gt;
&lt;script src="https://gist.github.com/ayende/1e8593aa5b3ba72603fe09f12e17a397.js"&gt;&lt;/script&gt;
&lt;/blockquote&gt;
&lt;p&gt;It took me a while to figure out what was going on there, and then more to frantically search where this is used. Basically, this is used in fuzzy searches, and it will allocate a new instance of the string on each call. Given that fuzzy search is popular in full text search usage, and that this is called a &lt;em&gt;lot&lt;/em&gt; during any such search, this is going to allocate like crazy. It would be better to move the entire thing to using mutable buffers, instead of passing strings around.&lt;/p&gt;
&lt;p&gt;Then we go to the locking, and I had to run it a few times to realize what is going on.&lt;/p&gt;
&lt;blockquote&gt;
&lt;script src="https://gist.github.com/ayende/2c0bc28b25cded03663cbd2b6433c11b.js"&gt;&lt;/script&gt;
&lt;/blockquote&gt;
&lt;p&gt;And this isn&amp;rsquo;t the way to do this at all. Basically, this relies on the file system to fail when you are trying to copy a file into an already existing file. However, that is a really bad way to go about doing that. The OS and the file system already have locking primitives that you can use, and they are going to be much better then this option. For example, consider what happens after a crash, is the directory locked or not? There is no real way to answer that, since the process might have crashed, leaving the file in place, or it might be doing things, expected that this is locked.&lt;/p&gt;
&lt;p&gt;Moving on, we have this simple looking method:&lt;/p&gt;
&lt;blockquote&gt;
&lt;script src="https://gist.github.com/ayende/179b0633bac229100055e1bcd6bf48b5.js"&gt;&lt;/script&gt;
&lt;/blockquote&gt;
&lt;p&gt;I know I&amp;rsquo;m harping on that, but this method is doing a lot of allocations by using lambdas, and depending on the number of files, the delegate indirection can be quite costly.&amp;nbsp; For that matter, there is also the issue of error handling. If there is a lock file in this directory when this is called, this will throw.&lt;/p&gt;
&lt;p&gt;Our final code for this post is:&lt;/p&gt;
&lt;blockquote&gt;
&lt;script src="https://gist.github.com/ayende/36bf2abedb8ae9acb19ff8dcdaa645b5.js"&gt;&lt;/script&gt;
&lt;/blockquote&gt;
&lt;p&gt;I really don&amp;rsquo;t like this code, it is something that &lt;em&gt;look&lt;/em&gt; like it is cheap, but it will:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Sort all the index files in the folder&lt;/li&gt;
&lt;li&gt;Open all of them&lt;/li&gt;
&lt;li&gt;Read some data&lt;/li&gt;
&lt;li&gt;Sum over that data&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Leaving aside that the deserialization code has the typical issue of not checking that the the entire buffer was read, this can cause a lot of I/O on the system, but luckily this function is never called.&lt;/p&gt;
&lt;p&gt;Okay, so we didn&amp;rsquo;t actually get to figure out what UpsertTransaction is, we&amp;rsquo;ll look at that in the next post.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/AyendeRahien/~4/SOM6kVUMftk" height="1" width="1" alt=""/&gt;</description><link>http://feedproxy.google.com/~r/AyendeRahien/~3/SOM6kVUMftk/reviewing-resin-part-ii</link><guid isPermaLink="false">https://ayende.com/blog/178946/reviewing-resin-part-ii?Key=154eea77-6556-4292-94f5-0838c0174e89</guid><pubDate>Wed, 12 Jul 2017 09:00:00 GMT</pubDate><feedburner:origLink>https://ayende.com/blog/178946/reviewing-resin-part-ii?Key=154eea77-6556-4292-94f5-0838c0174e89</feedburner:origLink></item><item><title>Reviewing Resin: Part I</title><description>&lt;p&gt;&lt;a href="https://github.com/kreeben/resin"&gt;Resin&lt;/a&gt; is a “Cross-platform document database and search engine with query language, API and CLI”. It is written in C#, and while I admit that reading C# code isn’t as challenging as diving into a new language, a project that has a completely new approach to a subject that is near and dear to my heart is always welcome.&amp;nbsp; It is also small, coming at about 6,500 lines of code, so that make for quick reading.&lt;/p&gt;&lt;p&gt;I’m reviewing commit &lt;a title="https://github.com/kreeben/resin/commit/ddbffff88995226fa52236f6dd6af4a48c833f7a" href="https://github.com/kreeben/resin/commit/ddbffff88995226fa52236f6dd6af4a48c833f7a"&gt;ddbffff88995226fa52236f6dd6af4a48c833f7a&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;As usual, I’m going to start reading the code in alphabetical file order, and then jump around as it make sense. The very first file I run into is Tests/AnalyzerTests where we find the following:&lt;/p&gt;&lt;blockquote&gt;&lt;script src="https://gist.github.com/ayende/6cad644744d4c5307919c2711bab8726.js"&gt;&lt;/script&gt;&lt;/blockquote&gt;&lt;p&gt;This is really interesting, primarily because of what it tells me. Analyzers are pretty much only used for full text search, such as Lucene or Noise. Jumping into the analyzer, we see:&lt;/p&gt;&lt;p&gt;&lt;a href="https://ayende.com/blog/Images/Open-Live-Writer/Reviewing-Resin_1169A/image_2.png"&gt;&lt;img width="786" height="387" title="image" style="margin: 0px; border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="image" src="https://ayende.com/blog/Images/Open-Live-Writer/Reviewing-Resin_1169A/image_thumb.png" border="0"&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;This tell me quite a few things. To start with, this is a &lt;em&gt;young&lt;/em&gt; project. The first commit is less then 18 months ago and I’m judging it with the same eye I use to looking at our own code. This code needs to be improved, for several reasons.&lt;/p&gt;&lt;p&gt;First, we have a virtual method call here, probably intended to be an extension point down the line. Currently, it isn’t used, and we pay the virtual call cost for no reason. Next we have the return value. IEnumerable is great, but this method is using &lt;em&gt;yield&lt;/em&gt;, which means that we’ll have a new instance created per document. For the same reason, the &lt;em&gt;tokenDic&lt;/em&gt; is also problematic. This one is created per field’s value, which is going to cost.&lt;/p&gt;&lt;p&gt;One of the first thing you want to have when you start worrying about performance is controlling your allocations. Reducing allocations in this case, by reusing the dictionary instance, or avoiding the &lt;em&gt;yield&lt;/em&gt; would help. Lucene did a lot of stuff right in that regard, and it ensures that you can reuse instances wherever possible (almost always), since that can dramatically improve performance.&lt;/p&gt;&lt;p&gt;Other than this, we can also see that we have Analyze and Index features, for now I’m going to assume that they are identical to Lucene until proven otherwise. This was the analyzer, but what is going on with the &lt;em&gt;tokenizer? &lt;/em&gt;Usually that is a lot more low level. &lt;/p&gt;&lt;p&gt;The core of the tokenizer is this method (I prettified it a bit to make it fit better on screen):&lt;/p&gt;&lt;p&gt;&lt;a href="https://ayende.com/blog/Images/Open-Live-Writer/Reviewing-Resin_1169A/image_4.png"&gt;&lt;img width="754" height="320" title="image" style="margin: 0px; border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="image" src="https://ayende.com/blog/Images/Open-Live-Writer/Reviewing-Resin_1169A/image_thumb_1.png" border="0"&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;As far as I can tell so far, most of the effort in the codebase has gone into the data structures used, not to police allocations or get absolute performance. However, even so this would be one of the first places I would look at whenever performance work would start. (To be fair, speaking with the author of this code, I &lt;em&gt;know&lt;/em&gt; there hasn’t been any profiling / benchmarking on the code). &lt;/p&gt;&lt;p&gt;This code is going to be at the heart of any indexing, and for each value, it is going to:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Allocate another string with the lowered case value.&lt;/li&gt;&lt;li&gt;Allocate a character buffer of the same size as the string.&lt;/li&gt;&lt;ul&gt;&lt;li&gt;Process that character buffer.&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;Allocate another string from that buffer.&lt;/li&gt;&lt;li&gt;Split that string.&lt;/li&gt;&lt;li&gt;Use a lambda on each of the parts and evaluate that against the stopwords.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;That is going to have a huge amount of allocations / computation that can be saved. Without changing anything external to this function, we can write the following:&lt;/p&gt;&lt;blockquote&gt;&lt;script src="https://gist.github.com/ayende/cd33da1e581029f5b1f340658023f434.js"&gt;&lt;/script&gt;&lt;/blockquote&gt;&lt;p&gt;This will do the same, but at a greatly reduced allocation cost. A better alternative here would be to change the design. Instead of having to allocate a new list, send a buffer and don’t deal with strings directly, instead, deal with a spans. Until we .NET Core 2.0 is out, I’m going to skip spans and just use direct tokens, like so:&lt;/p&gt;&lt;blockquote&gt;&lt;script src="https://gist.github.com/ayende/7b5f5d7266a1b3812bffbb27d71332cf.js"&gt;&lt;/script&gt;&lt;/blockquote&gt;&lt;p&gt;There are a few important things here. First, the code now don’t do any string allocations, instead, it is operating on the string characters directly. We have the IsStopword method that is now more complex, because it needs to do the check without allocating a string and while being efficient about it. How it left as an exercise for the reader, but it shouldn’t be too hard.&lt;/p&gt;&lt;p&gt;One thing that might not be obvious is that tokens list that we get as an argument. The idea here is that the caller code can reuse this list (and memory) between calls, but that would require a major change in the code.&lt;/p&gt;&lt;p&gt;In general, &lt;em&gt;not&lt;/em&gt; operating on strings at all would be a great thing indeed. We can work with direct character buffers, which will allow us to be mutable. Again, spans would probably fit right into this and be of great help.&lt;/p&gt;&lt;p&gt;That is enough for now, I know we just started, but I’ll continue this in the next post.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/AyendeRahien/~4/Hv5kwiWBXtw" height="1" width="1" alt=""/&gt;</description><link>http://feedproxy.google.com/~r/AyendeRahien/~3/Hv5kwiWBXtw/reviewing-resin-part-i</link><guid isPermaLink="false">https://ayende.com/blog/178945/reviewing-resin-part-i?Key=457d59ed-93ed-44ce-bbb2-5ace8f71d561</guid><pubDate>Tue, 11 Jul 2017 09:00:00 GMT</pubDate><feedburner:origLink>https://ayende.com/blog/178945/reviewing-resin-part-i?Key=457d59ed-93ed-44ce-bbb2-5ace8f71d561</feedburner:origLink></item><item><title>RavenDB 4.0: Securing the keys to the kingdom</title><description>&lt;p&gt;&lt;a href="https://ayende.com/blog/Images/Open-Live-Writer/RavenDB-4.0-and-the-key-to-security_81CF/image_4.png"&gt;&lt;img width="400" height="400" title="image" align="right" style="border: 0px currentcolor; border-image: none; float: right; display: inline; background-image: none;" alt="image" src="https://ayende.com/blog/Images/Open-Live-Writer/RavenDB-4.0-and-the-key-to-security_81CF/image_thumb_1.png" border="0"&gt;&lt;/a&gt;A major design goal for RavenDB is that it would be easy and convenient to user. A major constraint is that it must be secured. As you can imagine, those two are quite often work against one another. Security is often anything but easy to use, and it is rarely convenient.&amp;nbsp; &lt;/p&gt;&lt;p&gt;Previously, we have used Windows Authentication and OAuth to secure access to RavenDB. That works and has been deployed in the wild for quite some time. It is also a major pain whenever there is an issue. If the connection to the domain controller drops, we might have authentication delays of many seconds, and trying to debug Active Directory issues in production deployments can be… a bit of a pain, in the same way that an audit by the IRS that starts with SWAT team bashing down your door is mildly annoying.&amp;nbsp; OAuth, on the other hand, is much better, since it is under our control, and we can figure out exactly what is going on with it if need be.&lt;/p&gt;&lt;p&gt;Since RavenDB 4.0 is running on Windows, Linux &amp;amp; Mac, we decided to drop the Windows Authentication support and just use OAuth. The problem is that if we choose to support HTTP, we have to rely on extremely complex protocols that attempt to secure authentication using plain text, but don’t usually deliver good results and are typically a pain to debug and support. Or, we can use HTTPS and just let SSL/TLS to handle it all for us. A good example of the difference can be seen in OAuth 1.0 vs OAuth 2.0. &lt;/p&gt;&lt;p&gt;When we built RavenDB 1.0, roughly around 2009, the operating environment was quite different. In 2017, &lt;em&gt;not&lt;/em&gt; using HTTPS is pretty much a sin into itself. As we started security modeling for RavenDB 4.0, it became obvious that we couldn’t really support any security on top of HTTP without effectively having to implement most of the properties of HTTPS ourselves. I’m many things, but I’m not a security expert, not by a long shot. Given the chance to &lt;a href="https://twitter.com/mshelton/status/883678420202160129"&gt;implement my own security protocol&lt;/a&gt;, I would gladly do that, for a toy project or a weekend hackfest. But there is no way I would trust my own security in production against serious attacks. That pretty much led us to the realization that we have to require HTTPS for anything that require security. &lt;/p&gt;&lt;p&gt;That includes running inside the organization, exposed to the public internet, running inside the cloud or in a shared datacenter, etc. Pretty much, unless you have HTTPS, there is no real &lt;em&gt;point &lt;/em&gt;in talking about security. Given that, it meant that we could shift our baseline approach to security. If we are always going to require HTTPS for security, it means that we are operating in an environment that is much nicer for us to apply security.&lt;/p&gt;&lt;p&gt;Now, you can choose to run HTTP only, and avoid the need for certificate management, etc. However, at that point, you aren’t running a secure system, or you are already running it in a trusted and secured environment. In that case, we want to be clear that there isn’t any point to try to apply security policy (such as who can access what). Any network sniffer can figure out the access tokens and pretend to be whomever they want, if you are using HTTP. &lt;/p&gt;&lt;p&gt;With HTTPS required, we now move to the realm of having the admin take care of the certificates, securing them, renewal, etc. That is the part where it isn’t as easy or convenient as we could wish for. However, once we had that as a baseline, it opens an interesting path for security. Instead of relying on our own solution, we can use the builtin one and use x509 certificates from the client for authentication. This has the advantage that it is widely supported, standardized and secured. It is a bit less convenient then just a password, but the advantage is that any security system already in place know how to deal with, store, authorize and manage access to certificates.&lt;/p&gt;&lt;p&gt;The idea is that you can go to RavenDB and either register or generate a x509 certificate. To that certificate an administrator can assign permissions (such as what dbs it is allowed to access). From that point on, a client (RavenDB, browser, curl, etc) can connect to RavenDB and just issue REST requests. There is no need to do anything else for the system to work. Contrast that with how you would typically have to deal authentication using OAuth, by sending the token, keeping it fresh manually, etc.&lt;/p&gt;&lt;p&gt;Using x509 also has the distinct advantage that it is widely trusted. We intend to provide this level of security to all editions of RavenDB (so the Community Edition will also be able to use it). &lt;/p&gt;&lt;p&gt;A nice accidental feature of this decision is that we are going to be able to apply authentication at the connection level, and connection pooling means that we are likely going to have connections live for a long time. That means that we only need to pay the authentication cost once, instead of per request, with OAuth.&lt;/p&gt;&lt;p&gt;To simplify matters, we’ll likely just use the client certificates for authenticating the client, so we’ll not care if they are from a trusted root, etc. We’ll just require that the admin register the valid certificate with the cluster so they will be recognized. If you need to stop using a certificate, you can delete its registration or generate a new certificate to take its place. On the client side, it means that the DocumentStore will expose a X509Certificate property that you can set (or the equivalent in other clients). That means that you can use your own policies on the client to determine how to store the certificate. &lt;/p&gt;&lt;p&gt;On the server side, by the way, we’ll expose an extension point that will allow you to retrieve the certificate using your own policies. For example, if you are using Azure Key Vault or Hashicorp Vault or even your own HSM. This is done by invoking a process you specify, so you can write your own scripts / mini programs and apply whatever logic you need. This creates a clean separation between RavenDB and the secret store in use.&lt;/p&gt;&lt;p&gt;Authentication between servers is also done using SSL and certificates. We expect that we’ll commonly have all the servers running the same wildcard certificate, in which case they will obviously trust each other. Alternatively, you can also specify additional certificates that will be treated as servers. This is useful for when you are running with separate certificate for each server, but it is also a critical part of certificate rotation. When your certificate is about to expire, the admin will register the new certificate as trusted, and then start replacing the certificates of each of the nodes in turn. This allow us to run with both old and new certificates concurrently during this process.&lt;/p&gt;&lt;p&gt;We considered relying on some properties of the certificate itself, but it seemed like an error prune process. It is better to have the admin explicitly state, both for clients and server certificates which one we should actually trust, and at what level.&lt;/p&gt;&lt;p&gt;I would really appreciate any commentary you have about this feature, both in terms of ease of use, acceptability and obviously its security.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/AyendeRahien/~4/jEYC24B-jf8" height="1" width="1" alt=""/&gt;</description><link>http://feedproxy.google.com/~r/AyendeRahien/~3/jEYC24B-jf8/ravendb-4-0-securing-the-keys-to-the-kingdom</link><guid isPermaLink="false">https://ayende.com/blog/178977/ravendb-4-0-securing-the-keys-to-the-kingdom?Key=aac24722-2a15-4449-a8ad-f156725d51e6</guid><pubDate>Mon, 10 Jul 2017 09:00:00 GMT</pubDate><feedburner:origLink>https://ayende.com/blog/178977/ravendb-4-0-securing-the-keys-to-the-kingdom?Key=aac24722-2a15-4449-a8ad-f156725d51e6</feedburner:origLink></item><item><title>Bad bugs makes for self assigning issues</title><description>&lt;p&gt;One of our developers just added the following bug:&lt;/p&gt;&lt;p&gt;&lt;a href="https://ayende.com/blog/Images/Open-Live-Writer/Bad-bugs_B294/image_2.png"&gt;&lt;img width="781" height="75" title="image" style="border-image: none; display: inline; background-image: none;" alt="image" src="https://ayende.com/blog/Images/Open-Live-Writer/Bad-bugs_B294/image_thumb.png" border="0"&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;This is in an area that of the code that this particular developer is not regularly traversing*. The image above includes the full contents of the bug. And that caused me to immediately assign it back to its opener.&lt;/p&gt;&lt;p&gt;The problem?&amp;nbsp; If you say that you got an error, &lt;em&gt;include the error&lt;/em&gt;. In many cases, you can save a lot of time and guessing. &lt;/p&gt;&lt;p&gt;For an internal bug, where the person who opened it is available, we have much lower bar for bug report quality. Most bugs are closed relatively quickly anyway. But lower bar for bug report quality still means there is a bar.&lt;/p&gt;&lt;p&gt;* I started to say, not responsible for, but we don’t have code ownership, so that wouldn’t have been right.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/AyendeRahien/~4/M39BDLiq2tQ" height="1" width="1" alt=""/&gt;</description><link>http://feedproxy.google.com/~r/AyendeRahien/~3/M39BDLiq2tQ/bad-bugs-makes-for-self-assigning-issues</link><guid isPermaLink="false">https://ayende.com/blog/178882/bad-bugs-makes-for-self-assigning-issues?Key=dd006fb4-f6a4-4ac6-922c-b01bfdb9cb7a</guid><pubDate>Fri, 07 Jul 2017 09:00:00 GMT</pubDate><feedburner:origLink>https://ayende.com/blog/178882/bad-bugs-makes-for-self-assigning-issues?Key=dd006fb4-f6a4-4ac6-922c-b01bfdb9cb7a</feedburner:origLink></item><item><title>The ghost of the zombie of revisions past</title><description>&lt;p&gt;I &lt;a href="https://ayende.com/blog/178817/zombies-vs-ghosts-the-great-debate?Key=84f15b74-7689-4c6a-8d57-64c4a475e417"&gt;talked&lt;/a&gt; about difficult naming decisions, and this one was certainly one of the more lively ones. &lt;/p&gt;&lt;p&gt;We bounced between zombies, orphans and ghosts, with a bunch of crazy stuff going in between. At one point it was suggested we’ll just make up a word, but my suggestion to use &lt;a href="https://wiki.lspace.org/mediawiki/The_Dictionary_of_Eye-Watering_Words"&gt;Welchet&lt;/a&gt; was sadly declined by all, including a rather rude comment by the author of this blog about what kind of jokes are appropriate for the workplace. &lt;/p&gt;&lt;p&gt;After we settled the discussion on ghosts, there was another discussion about whatever we should use Inky, Blinky, Pinky and Clyde. I tell you, when we aren’t building distributed databases, the office is a hotbed for nerd references. &lt;/p&gt;&lt;p&gt;And then an idea cam along. Which I really liked, so we talked about this in the morning and I’m showing screenshots at a blog post a bit before midnight. The feature is called the revision bin. &lt;/p&gt;&lt;p&gt;In the UI, you can see it as one of the top level elements. &lt;/p&gt;&lt;p&gt;&lt;a href="https://ayende.com/blog/Images/Open-Live-Writer/The-ghost-of-the-zombie-of-revisions-pas_1434A/image_2.png"&gt;&lt;img width="156" height="38" title="image" style="border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="image" src="https://ayende.com/blog/Images/Open-Live-Writer/The-ghost-of-the-zombie-of-revisions-pas_1434A/image_thumb.png" border="0"&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;In essence, this is a recycle bin for revisions. RavenDB can be configured to keep revisions of documents as they change, and even keep track of them after they were deleted. However, that presented a problem. If you deleted a document that had revisions, how would you tell that it was there in the first place? Just knowing the document id and looking for that wouldn’t work very well. So we created the revisions bin, whose content looks like this:&lt;/p&gt;&lt;p&gt;&lt;a href="https://ayende.com/blog/Images/Open-Live-Writer/The-ghost-of-the-zombie-of-revisions-pas_1434A/image_4.png"&gt;&lt;img width="543" height="116" title="image" style="margin: 0px; border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="image" src="https://ayende.com/blog/Images/Open-Live-Writer/The-ghost-of-the-zombie-of-revisions-pas_1434A/image_thumb_1.png" border="0"&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;And from there you can go to:&lt;/p&gt;&lt;p&gt;&lt;a href="https://ayende.com/blog/Images/Open-Live-Writer/The-ghost-of-the-zombie-of-revisions-pas_1434A/image_6.png"&gt;&lt;img width="871" height="403" title="image" style="margin: 0px; border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="image" src="https://ayende.com/blog/Images/Open-Live-Writer/The-ghost-of-the-zombie-of-revisions-pas_1434A/image_thumb_2.png" border="0"&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;For that matter, if we recreate this document again, you’ll be able to see its entire history, including across deletes.&lt;/p&gt;&lt;p&gt;&lt;a href="https://ayende.com/blog/Images/Open-Live-Writer/The-ghost-of-the-zombie-of-revisions-pas_1434A/image_8.png"&gt;&lt;img width="286" height="256" title="image" style="margin: 0px; border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="image" src="https://ayende.com/blog/Images/Open-Live-Writer/The-ghost-of-the-zombie-of-revisions-pas_1434A/image_thumb_3.png" border="0"&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;Now admittedly this is a nice looking UI, and the skull on the menu is a nice touch, if a bit morbid. However, why make such a noise about such a feature?&lt;/p&gt;&lt;p&gt;The answer is that the revisions bin isn’t &lt;em&gt;that&lt;/em&gt; important, but keeping track of deletes of documents using revisions is quite important, since it allow subscriptions and ETL to handle them in a clean and easy to grok manner. And in order to actually explain &lt;em&gt;that&lt;/em&gt;, we needed to be able to show the users what we are talking about.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/AyendeRahien/~4/6FYPlCdwRIw" height="1" width="1" alt=""/&gt;</description><link>http://feedproxy.google.com/~r/AyendeRahien/~3/6FYPlCdwRIw/the-ghost-of-the-zombie-of-revisions-past</link><guid isPermaLink="false">https://ayende.com/blog/178849/the-ghost-of-the-zombie-of-revisions-past?Key=e5ea3d9f-79d1-4229-9995-4b7808087287</guid><pubDate>Thu, 06 Jul 2017 09:00:00 GMT</pubDate><feedburner:origLink>https://ayende.com/blog/178849/the-ghost-of-the-zombie-of-revisions-past?Key=e5ea3d9f-79d1-4229-9995-4b7808087287</feedburner:origLink></item><item><title>RavenDB 4.0 on Mac OSX</title><description>&lt;p&gt;So we just got this result:&lt;/p&gt;&lt;p&gt;&lt;a href="https://ayende.com/blog/Images/Open-Live-Writer/544b2a558cc0_AD96/Screenshot%20from%202017-07-04%2012-11-06_2.png"&gt;&lt;img width="1437" height="903" title="Screenshot from 2017-07-04 12-11-06" style="border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="Screenshot from 2017-07-04 12-11-06" src="https://ayende.com/blog/Images/Open-Live-Writer/544b2a558cc0_AD96/Screenshot%20from%202017-07-04%2012-11-06_thumb.png" border="0"&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;We are not in the process of making sure that it all actually works, but it is very encouraging that we have been able to get there.&lt;/p&gt;&lt;p&gt;This will very likely be in the next beta build for RavenDB. &lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/AyendeRahien/~4/KqkjD1BH19A" height="1" width="1" alt=""/&gt;</description><link>http://feedproxy.google.com/~r/AyendeRahien/~3/KqkjD1BH19A/ravendb-4-0-on-mac-osx</link><guid isPermaLink="false">https://ayende.com/blog/178913/ravendb-4-0-on-mac-osx?Key=a801c62e-2bb9-449d-bd0d-128a5e13f8a9</guid><pubDate>Wed, 05 Jul 2017 09:00:00 GMT</pubDate><feedburner:origLink>https://ayende.com/blog/178913/ravendb-4-0-on-mac-osx?Key=a801c62e-2bb9-449d-bd0d-128a5e13f8a9</feedburner:origLink></item><item><title>RavenDB 4.0: Unbounded results sets</title><description>&lt;p&gt;Unbounded result sets are a pet peeve of mine. I have seen them destroy application performance more then once. With RavenDB, I decided to cut that problem at the knees and placed a hard limit on the number of results that you can get from the server. Unless you configured it differently, you couldn’t get more than 1,024 results per query. I was very happy with this decisions, and there have been numerous cases where this has been able to save an application from serious issues.&lt;/p&gt;&lt;p&gt;Unfortunately, users &lt;em&gt;hated&lt;/em&gt; it. Even though it was configurable, and even though you could effectively turn it off, just the fact that it was there was enough to make people angry.&lt;/p&gt;&lt;p&gt;Don’t get me wrong, I absolutely understand some of the issues raised. In particular, if the data goes over a certain size we suddenly show wrong results or error, leaving the app in a “we need to fix this NOW”. It is an easy mistake to make. In fact, in this blog, I noticed a few months back that I couldn’t get entries from 2014 to show up in the archive. The underlying reason was exactly that, I’m getting the number of items per month, and I’ve been blogging for more than 128 months, so the data got truncated. &lt;/p&gt;&lt;p&gt;In RavenDB 4.0 we removed the limit. If you don’t specify a limit in a query, you’ll get exactly how many results there are in the database. You can ask RavenDB to raise an error if you didn’t specify a limit clause, which is a way for you to verify that you won’t run into this issue in production, but it is off by default and will probably better match the new user expectations.&lt;/p&gt;&lt;p&gt;The underlying issue of loading too many results is still there, of course. And we still want to do something about it. What we did was raise alerts. &lt;/p&gt;&lt;p&gt;I have made a query on a large set (160,000 results, about 400 MB in all) and the following popped up in the RavenDB Studio:&lt;/p&gt;&lt;p&gt;&lt;a href="https://ayende.com/blog/Images/Open-Live-Writer/RavenDB-4.0-Unbounded-results-sets_12B7B/image_4.png"&gt;&lt;img width="155" height="70" title="image" style="margin: 0px; border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="image" src="https://ayende.com/blog/Images/Open-Live-Writer/RavenDB-4.0-Unbounded-results-sets_12B7B/image_thumb_1.png" border="0"&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;This tells the admin that it have some information that it needs to look at. This is intentionally non obtrusive. &lt;/p&gt;&lt;p&gt;When you click on the notifications, you’ll get the following message.&lt;/p&gt;&lt;p&gt;&lt;a href="https://ayende.com/blog/Images/Open-Live-Writer/RavenDB-4.0-Unbounded-results-sets_12B7B/image_2.png"&gt;&lt;img width="340" height="302" title="image" style="margin: 0px; border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="image" src="https://ayende.com/blog/Images/Open-Live-Writer/RavenDB-4.0-Unbounded-results-sets_12B7B/image_thumb.png" border="0"&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;And if you’ll click on the details, you’ll see the actual details of the operations that triggered this warning.&lt;/p&gt;&lt;p&gt;&lt;a href="https://ayende.com/blog/Images/Open-Live-Writer/RavenDB-4.0-Unbounded-results-sets_12B7B/image_6.png"&gt;&lt;img width="1115" height="313" title="image" style="margin: 0px; border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="image" src="https://ayende.com/blog/Images/Open-Live-Writer/RavenDB-4.0-Unbounded-results-sets_12B7B/image_thumb_2.png" border="0"&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;I actually created an issue so we’ll supply you with more information (such as the index, the query, duration and the total size that it generated over the network). &lt;/p&gt;&lt;p&gt;I think that this gives the admin enough information to act upon, but will not cause hardship to the application. This make it something that we Should Fix instead Get the OnCall Guy.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/AyendeRahien/~4/4a27-deTKdk" height="1" width="1" alt=""/&gt;</description><link>http://feedproxy.google.com/~r/AyendeRahien/~3/4a27-deTKdk/ravendb-4-0-unbounded-results-sets</link><guid isPermaLink="false">https://ayende.com/blog/178823/ravendb-4-0-unbounded-results-sets?Key=0d3aa611-119e-4844-b7d8-92dbd28a18f5</guid><pubDate>Tue, 04 Jul 2017 09:00:00 GMT</pubDate><feedburner:origLink>https://ayende.com/blog/178823/ravendb-4-0-unbounded-results-sets?Key=0d3aa611-119e-4844-b7d8-92dbd28a18f5</feedburner:origLink></item><item><title>Batch processing with subscriptions in RavenDB 4.0</title><description>&lt;p&gt;Subscription is a somewhat neglected feature in RavenDB. It was created to handle a specific customer need and grew from there, but it had relatively little traction and was a bit of a pain to use. When we looked at the things we wanted to do in RavenDB 4.0 re-working how people use subscription was high enough in the list that it got a dedicated dev for about a year.&lt;/p&gt;
&lt;p&gt;Here is how a subscription looks like in RavenDB 3.x.&lt;/p&gt;
&lt;blockquote&gt;
&lt;script src="https://gist.github.com/ayende/d0c244c7125492ff02bcb4e46c1f2cb0.js"&gt;&lt;/script&gt;
&lt;/blockquote&gt;
&lt;p&gt;It is only available from code, and the model used is heavily influenced by Reactive Extensions. It give you reliable subscription to data, even if the client or server went down, it could recover on restart, but it was complex to do the more advanced things. There are events that you can register to respond to things that are happening, but there isn&amp;rsquo;t a complete story. Other things, such as automatic failover or responding to deletes were flat out impossible.&lt;/p&gt;
&lt;p&gt;With RavenDB 4.0, we decided to do things differently. I &lt;a href="https://ayende.com/blog/178562/ravendb-4-0-data-subscriptions-part-i"&gt;talked&lt;/a&gt;&amp;nbsp;&lt;a href="https://ayende.com/blog/178593/ravendb-4-0-data-subscriptions-part-ii"&gt;about&lt;/a&gt; this before several times, but recently we completed a major restructuring and simplification of the user visible behavior that I&amp;rsquo;m really happy about. To start with, we ditched the Reactive Extensions and IObservable model. This is just not the right fit for the kind of things we want to do. Instead, we are going with full blown batch processing.&lt;/p&gt;
&lt;blockquote&gt;
&lt;script src="https://gist.github.com/ayende/4b11b06ddfcff169c19faf2142222867.js"&gt;&lt;/script&gt;
&lt;/blockquote&gt;
&lt;p&gt;Instead of being called once per item, we are going to call you one per &lt;em&gt;batch&lt;/em&gt;. This is actually how things are going over the wire, and exposing it directly to the user make our life a lot easier. It also means that you have much better model to actually do things in a batch mode. Such as applying modification to all the items in the batch and saving them back in a single operation.&lt;/p&gt;
&lt;p&gt;Subscriptions in RavenDB 4.0 are also fault tolerant and highly available (both client &amp;amp; server), allow to access versioned and deleted snapshots, allow to apply complex filtering and transformations on the server side and in general a lot more suitable for the task we intend them for.&lt;/p&gt;
&lt;p&gt;Perhaps what is more exciting is that subscriptions are available to all the clients, and in some cases, it just make more sense to write them as a batch processing script. Consider:&lt;/p&gt;
&lt;blockquote&gt;
&lt;script src="https://gist.github.com/ayende/6ff839512f61a696beb13fb379fd7f39.js"&gt;&lt;/script&gt;
&lt;/blockquote&gt;
&lt;p&gt;This is the kind of thing that can really make the operations team happy, because they can do targeted jobs with very little friction. I spend the whole of &lt;a href="https://github.com/ravendb/book/releases"&gt;Chapter 5&lt;/a&gt; talking about subscriptions, and I think it is well worth it.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/AyendeRahien/~4/c9VgjERDoe0" height="1" width="1" alt=""/&gt;</description><link>http://feedproxy.google.com/~r/AyendeRahien/~3/c9VgjERDoe0/batch-processing-with-subscriptions-in-ravendb-4-0</link><guid isPermaLink="false">https://ayende.com/blog/178822/batch-processing-with-subscriptions-in-ravendb-4-0?Key=e878a137-755d-45ce-b15c-cfec21d82105</guid><pubDate>Mon, 03 Jul 2017 09:00:00 GMT</pubDate><feedburner:origLink>https://ayende.com/blog/178822/batch-processing-with-subscriptions-in-ravendb-4-0?Key=e878a137-755d-45ce-b15c-cfec21d82105</feedburner:origLink></item><item><title>We won’t be fixing this race condition</title><description>&lt;p&gt;During the work on restoring backup, the developer in charge came up with the following problematic scenario.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Start restoring backup of database Northwind on node A, which can take quite some time for large database&lt;/li&gt;&lt;li&gt;Create a database named Northwind on node B while the restore is taking place.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;The problem is that during the restore the database doesn’t exists in a proper form in the cluster until it is done restoring. During that time, if an administrator is attempting to create a database it will look like it is working, but it will actually create a new database on all the other nodes and fail on the node where the restore is going on.&lt;/p&gt;&lt;p&gt;When the restore will complete, it will either remove the previously created database or it will join it and replicate the restored data to the rest of the nodes, depending exactly on when the restore and the new db creation happened. &lt;/p&gt;&lt;p&gt;Now, trying to resolve this issue involve us coordinating the restore process around the cluster. However, that also means that we need to do heartbeats during the restore process (to the entire cluster), handle timeouts and recovery and effectively take upon us a pretty big burden of pretty complicated code. Indeed, the first draft of the fix for this issue suffered from the weakness that it would only work when running on a single node, and only work in a cluster mode in very specific cases. &lt;/p&gt;&lt;p&gt;In this case, it is a very rare scenario that require an admin (not just a standard user) to do two things that you’ll not usually expect them together, and the outcome of this is a bit confusing even if you managed, but there isn’t any data loss. &lt;/p&gt;&lt;p&gt;The solution was to document that during the restore process you shouldn’t create a database with the same name but instead let RavenDB complete and then let the database span additional nodes. That is a much simpler alternative to going in to a distributed mode reasoning just for something that is an operator error in the first place. &lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/AyendeRahien/~4/q5W6NTaKMDU" height="1" width="1" alt=""/&gt;</description><link>http://feedproxy.google.com/~r/AyendeRahien/~3/q5W6NTaKMDU/we-wont-be-fixing-this-race-condition</link><guid isPermaLink="false">https://ayende.com/blog/178821/we-wont-be-fixing-this-race-condition?Key=149d577d-41ec-4182-bdec-27f13a3a7be3</guid><pubDate>Fri, 30 Jun 2017 09:00:00 GMT</pubDate><feedburner:origLink>https://ayende.com/blog/178821/we-wont-be-fixing-this-race-condition?Key=149d577d-41ec-4182-bdec-27f13a3a7be3</feedburner:origLink></item><item><title>Bug stories: The memory ownership in the timeout</title><description>&lt;p&gt;&lt;a href="https://ayende.com/blog/Images/Open-Live-Writer/Bug-stories-The-memory-ownership-in-the-_D55C/image_2.png"&gt;&lt;img width="324" height="324" title="image" align="right" style="border: 0px currentcolor; border-image: none; float: right; display: inline; background-image: none;" alt="image" src="https://ayende.com/blog/Images/Open-Live-Writer/Bug-stories-The-memory-ownership-in-the-_D55C/image_thumb.png" border="0"&gt;&lt;/a&gt;We are running a lot of tests right now on RavenDB, in all sort of interesting configurations. Some of the more interesting results came from testing wildly heterogeneous systems. Put a node on a fast Windows machine, connect it to a couple of Raspberry PIs, a &lt;em&gt;cheap&lt;/em&gt; Windows tablet over WiFi and a slow Linux machine and see how that kind of cluster is handling high load.&lt;/p&gt;&lt;p&gt;This has turned out a number of bugs, the issue with the &lt;a href="https://ayende.com/blog/178818/bug-stories-the-data-corruption-in-the-cluster?key=c3a59ff5329543738f6df5289eea4364"&gt;TCP read buffer corruption&lt;/a&gt; is one such example, but another is the reason for this post. In one of our test runs, the RavenDB process crashed with invalid memory access. That was interesting to see. Tracking down the issue led us to the piece of code that is handling incoming replication. In particular, the issue was possible if the following happened:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Node A is significantly slower than node B, primarily with regards to disk I/O.&lt;/li&gt;&lt;li&gt;Node B is being hit with enough load that it send large requests to node A.&lt;/li&gt;&lt;li&gt;There is a Node C that is also trying to replicate the same information (because it noticed that node A isn’t catching fast enough and is trying to help).&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;The root cause was that we had a bit of code that looked like this:&lt;/p&gt;&lt;blockquote&gt;&lt;script src="https://gist.github.com/ayende/aa918c28a95e085f25d86b4274ab57ec.js"&gt;&lt;/script&gt;&lt;/blockquote&gt;&lt;p&gt;Basically, we read the data from the network into a buffer, and now we hand it off to the transaction merger to run. However, if there is a &lt;em&gt;lot&lt;/em&gt; of load on the server, it is possible that the transaction merger will not have a chance to return in time.&amp;nbsp; We try to abort the connection here, since something is obviously wrong, and we do just that. The problem is that we sent a buffer to the transaction merger, and while it might not have gotten to processing our request yet (or haven’t completed it, at least), there is no way for us to actually be able to pull the request out (it might have already started executing, after all). &lt;/p&gt;&lt;p&gt;The code didn’t consider that, and what happened when we did get a timeout is that the buffer was returned to the pool, and if it was freed in time, we would get an access violation exception if we were lucky, or just garbage in the buffer (that we previously validated, so we didn’t check again) that would likely also cause a crash.&lt;/p&gt;&lt;p&gt;The solution was to wait for the task to complete, but ping the other host to let it know that we are still alive, and that the connection shouldn’t be aborted.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/AyendeRahien/~4/eV20MlBVTWU" height="1" width="1" alt=""/&gt;</description><link>http://feedproxy.google.com/~r/AyendeRahien/~3/eV20MlBVTWU/bug-stories-the-memory-ownership-in-the-timeout</link><guid isPermaLink="false">https://ayende.com/blog/178820/bug-stories-the-memory-ownership-in-the-timeout?Key=69f62941-eacd-444d-ae6d-5cbabfd9ef65</guid><pubDate>Thu, 29 Jun 2017 09:00:00 GMT</pubDate><feedburner:origLink>https://ayende.com/blog/178820/bug-stories-the-memory-ownership-in-the-timeout?Key=69f62941-eacd-444d-ae6d-5cbabfd9ef65</feedburner:origLink></item><item><title>The things that come out late at night</title><description>&lt;p&gt;The following is the opening paragraphs for discussion RavenDB 4.0 clustering and distribution model in the Inside RavenDB 4.0 book.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;You might be familiar with the term "murder of crows" as a way to refer to a group for crows[1]. It has been used in literature and arts many times. Of less reknown is the group term for ravens, which is "unkindness". Personally, in the name of all ravens, I'm torn between being insulted and amused.&lt;/p&gt;
&lt;p&gt;Professionally, setting up RavenDB as a cluster on a group of machines is a charming exercise (however, that term is actually reserved for finches) that bring a sense of exaltation (taken too, by larks) by how pain free this is. I'll now end my voyage into the realm of ornithology's etymology and stop speaking in tongues.&lt;/p&gt;
&lt;p&gt;On a more serious note, the fact that RavenDB clustering is easy to setup is quite important, because it means that it is much more approachable.&lt;/p&gt;
&lt;hr align="left" size="1" width="33%" /&gt;
&lt;p&gt;[1] If you are interested in learning why, I found &lt;a href="https://www.quora.com/Why-is-a-group-of-crows-called-a-murder"&gt;this answer&lt;/a&gt; fascinating&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It was amusing to write, and it got me to actually start writing that part of the book. Although I&amp;rsquo;m not sure if this will survive editing and actually end up in the book.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/AyendeRahien/~4/u5ncU4l9QVI" height="1" width="1" alt=""/&gt;</description><link>http://feedproxy.google.com/~r/AyendeRahien/~3/u5ncU4l9QVI/the-things-that-come-out-late-at-night</link><guid isPermaLink="false">https://ayende.com/blog/178881/the-things-that-come-out-late-at-night?Key=d338ab45-e462-4255-a169-a53a4c78fde1</guid><pubDate>Wed, 28 Jun 2017 09:47:00 GMT</pubDate><feedburner:origLink>https://ayende.com/blog/178881/the-things-that-come-out-late-at-night?Key=d338ab45-e462-4255-a169-a53a4c78fde1</feedburner:origLink></item><item><title>Bug stories: How do I call myself?</title><description>&lt;p&gt;&lt;a href="https://ayende.com/blog/Images/Open-Live-Writer/Bug-stories-How-do-I-call-myself_D32D/image_5.png"&gt;&lt;img width="349" height="197" title="image" align="right" style="border: 0px currentcolor; border-image: none; float: right; display: inline; background-image: none;" alt="image" src="https://ayende.com/blog/Images/Open-Live-Writer/Bug-stories-How-do-I-call-myself_D32D/image_thumb_1.png" border="0"&gt;&lt;/a&gt;This bug is actually one of the primary reasons we had a Beta 2 release for RavenDB 4.0 so quickly. &lt;/p&gt;&lt;p&gt;The problem is easy to state, we had a problem in any non trivial deployment setup where clients would be utterly unable to connect to us. Let us examine what I mean by non trivial setup, shall we? &lt;/p&gt;&lt;p&gt;A trivial setup is when you are running locally, binding to “http://localhost:8080”. In this case, everything is simple, and you can bind to the appropriate interface and when a client connects to you, you let it know that your URL is “http://localhost:8080”. &lt;/p&gt;&lt;p&gt;Hm… this doesn’t make sense. If a client just connected to us, why do we need to let it know what is the URL that it need to connect to us? &lt;/p&gt;&lt;p&gt;Well, if there is just a single node, we don’t. But RavenDB 4.0 allows you to connect to any node in the cluster and ask it where a particular database is located. So the first thing that happens when you connect to a RavenDB server is that you find out where you really need to go. In the case of a single node, the answer is “you are going to talk to me”, but in the case of a cluster, it might be some other node entirely. And this is where things begin to be a bit problematic. The problem is that we need to know what to call ourselves when a client connects to us. &lt;/p&gt;&lt;p&gt;That isn’t as easy as it might sound. Consider the case where the user configure the server url to be “http://0.0.0.0:8080”. We can’t give that to the client, so we default to sending back the host name in that case. And this is where things started to get tricky. In many cases, the host name is not something that make sense.&lt;/p&gt;&lt;p&gt;Oh, for internal deployments, you can usually rely on it, but if you are deploying to AWS, for example, the machine host name is of very little use in routing to that particular machine. Or, for that matter, a docker container host name isn’t particularly useful when you consider it from the outside. &lt;/p&gt;&lt;p&gt;The problem is that with RavenDB, we had a single configuration value that was used both for the binding to the network and for letting the user know how to connect to us. That didn’t work when you had routers in the middle. For example, if my public docker IP is 10.0.75.2, that doesn’t mean that this is the IP that I can bind to inside the container. And the same is true whenever you have any complex network topology (putting nginx in front of the server, for example). &lt;/p&gt;&lt;p&gt;The resolution for that was pretty simple, we added a new configuration value that will separate the host that we bind to from the host that we report to the outside world. In this manner, you can bind to one IP but let the world know that you should be reached via another.&amp;nbsp; &lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/AyendeRahien/~4/IC65JSUYybc" height="1" width="1" alt=""/&gt;</description><link>http://feedproxy.google.com/~r/AyendeRahien/~3/IC65JSUYybc/bug-stories-how-do-i-call-myself</link><guid isPermaLink="false">https://ayende.com/blog/178819/bug-stories-how-do-i-call-myself?Key=beaa4df8-bcb4-4024-a477-d574bb61c704</guid><pubDate>Wed, 28 Jun 2017 09:00:00 GMT</pubDate><feedburner:origLink>https://ayende.com/blog/178819/bug-stories-how-do-i-call-myself?Key=beaa4df8-bcb4-4024-a477-d574bb61c704</feedburner:origLink></item><item><title>Bug stories: The data corruption in the cluster</title><description>&lt;p&gt;&lt;a href="https://ayende.com/blog/Images/Open-Live-Writer/Bug-stories-The-data-corruption-in-the-c_C7BB/image_2.png"&gt;&lt;img width="400" height="300" title="image" align="right" style="border: 0px currentcolor; border-image: none; float: right; display: inline; background-image: none;" alt="image" src="https://ayende.com/blog/Images/Open-Live-Writer/Bug-stories-The-data-corruption-in-the-c_C7BB/image_thumb.png" border="0"&gt;&lt;/a&gt;The bug started as pretty much all others. “We have a problem when replicating from a Linux machine to a Windows machine, I’m seeing some funny values there”. This didn’t raise any alarm bells, after all, that was the point of checking what was going on in a mixed mode cluster. We didn’t &lt;em&gt;expect&lt;/em&gt; any issues, but it wasn’t surprising that they happened. &lt;/p&gt;&lt;p&gt;The bug in question showed up as an invalid database id in some documents. In particular, it meant that we might have node A, node B and node C in the cluster, and running a particular scenario suddenly started also reporting node Ω, node Σ and other fun stuff like that. &lt;/p&gt;&lt;p&gt;And so the investigation began. We were able to reproduce this error once we put enough load on the cluster (typically around the 20th million document write or so), and it was never consistent. &lt;/p&gt;&lt;p&gt;We looked at how we save the data to disk, we looked at how we ready it, we scanned all the incoming and outgoing data. We sniffed raw TCP sockets and we looked at everything from the threading model to random corruption of data on the wire to our own code reading the data to manual review of the TCP code in the Linux kernel.&lt;/p&gt;&lt;p&gt;The later might require some explanation, it turned out that setting TCP_NODELAY on Linux would make the issue go away. That only made things a lot harder to figure out. What was worse, this corruption only ever happened in this particular location, never anywhere else. It was &lt;em&gt;maddening&lt;/em&gt;, and about three people worked on this particular issue for over a week with the sole result being: “We know where it roughly happening, but no idea why or how”.&lt;/p&gt;&lt;p&gt;That in itself was a very valuable thing to have, and along the way we were able to fix a bunch of other stuff that was found under this level of scrutiny. But the original problem persisted, quite annoyingly. &lt;/p&gt;&lt;p&gt;Eventually, we tracked it down to this method:&lt;/p&gt;&lt;blockquote&gt;&lt;script src="https://gist.github.com/ayende/306b04e2de7e7b382bf7716c8771c638.js"&gt;&lt;/script&gt;&lt;/blockquote&gt;&lt;p&gt;We were there before, and we looked at the code, and it looked fine. Except that it wasn’t. In particular, there is a problem when the range we want to move is overlapped with the range we want to move it to. &lt;/p&gt;&lt;p&gt;For example, consider that we have a buffer of 32KB, and we read from the network 7 bytes. We then consumed 2 of those bytes. In the image below, you can see that as the Origin, with the consumed bytes shown as ghosts.&lt;/p&gt;&lt;p&gt;&lt;a href="https://ayende.com/blog/Images/Open-Live-Writer/Bug-stories-The-data-corruption-in-the-c_C7BB/image_6.png"&gt;&lt;img width="663" height="239" title="image" style="margin: 0px; border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="image" src="https://ayende.com/blog/Images/Open-Live-Writer/Bug-stories-The-data-corruption-in-the-c_C7BB/image_thumb_2.png" border="0"&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;What we need to do now is to move the “Joyou” to the beginning of the buffer, but note that we need to move it from 2 – 7 to 0 – 5, which are overlapping ranges. The issue is that we want to be able to fully read “Joyous”, which require us to do some work to make sure that we can do that. This ReadExactly piece of code was written with the knowledge that at most it will be called with 16 bytes to read, and the buffer size is 32KB, so there was an implicit assumption that those ranges can’t overlap.&lt;/p&gt;&lt;p&gt;when they do… Well, you can see in the image how the data is changed with each iteration of the loop. The end result is that we have corrupted our buffer and mess everything up. The Linux TCP stack had no issue, it was all in our code. The problem is that while it is rare, it is perfectly fine to fragment the data you send into multiple packets, each with very small length. The reason why TCP_NODELAY “fixed” the issue was that it probably didn’t trigger the multiple small buffers one after another in that particular scenario. It is also worth noting that we tracked this down to specific load pattern that would cause the sender to split packets in this way to generate this error condition.&lt;/p&gt;&lt;p&gt;That didn’t actually fix anything, since it could still happen, but I traced the code, and I think that this happened with more regularity since we hit the buffer just right to send a value over the buffer size in just the wrong way. The fix for this, by the way, is to avoid the manual buffer copying and to use &lt;em&gt;memove(), &lt;/em&gt;which is safe to use for overlapped ranges.&lt;/p&gt;&lt;p&gt;That leave us with the question, why did it take us so long to find this out? For that matter, how could this error surface only in this particular case? There is nothing really special with the database id, and this particular method is called a &lt;em&gt;lot&lt;/em&gt; by the code. &lt;/p&gt;&lt;p&gt;Figuring this out took even more time, basically, this bug was hidden by the way our code validate the incoming stream. We don’t trust data from the network, and we run it through a set of validations to ensure that it is safe to consume. When this error happened in the normal course of things, higher level code would typically detect that as corruption and close the connection. The other side would retry and since this is timing dependent, it will very likely be able to proceed. The issue with database ids is that they are opaque binary values (they are guids, so no structure at all that is meaningful for the application). That means that only when we got this particular issue on that particular field (and other field at all) will we be able to pass validation and actually get the error. &lt;/p&gt;&lt;p&gt;The fix was &lt;a href="https://github.com/ravendb/ravendb/commit/37eaf41b3d2bd08f8f5ed53d9ca7e3312bafd9ec"&gt;annoyingly simply&lt;/a&gt; given the amount of time we spent finding it, but we have been able to root out a significant bug as a result of the real world tests we run.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/AyendeRahien/~4/N8KjufOX4F4" height="1" width="1" alt=""/&gt;</description><link>http://feedproxy.google.com/~r/AyendeRahien/~3/N8KjufOX4F4/bug-stories-the-data-corruption-in-the-cluster</link><guid isPermaLink="false">https://ayende.com/blog/178818/bug-stories-the-data-corruption-in-the-cluster?Key=c3a59ff5-3295-4373-8f6d-f5289eea4364</guid><pubDate>Tue, 27 Jun 2017 09:00:00 GMT</pubDate><feedburner:origLink>https://ayende.com/blog/178818/bug-stories-the-data-corruption-in-the-cluster?Key=c3a59ff5-3295-4373-8f6d-f5289eea4364</feedburner:origLink></item><item><title>Zombies vs. Ghosts: The great debate</title><description>&lt;p&gt;&lt;a href="https://ayende.com/blog/Images/Open-Live-Writer/Zombies-vs.-Ghosts-The-great-debate_C335/image_4.png"&gt;&lt;img width="599" height="234" title="image" align="right" style="border: 0px currentcolor; border-image: none; float: right; display: inline; background-image: none;" alt="image" src="https://ayende.com/blog/Images/Open-Live-Writer/Zombies-vs.-Ghosts-The-great-debate_C335/image_thumb_1.png" border="0"&gt;&lt;/a&gt;We have a feature in RavenDB that may leave behind some traces when a document is gone. The actual details aren’t really important for the story. Those traces are there for a reason, and a user have a good reason to want to see them in the UI. &lt;/p&gt;&lt;p&gt;That meant that we needed to come up with a name for them. After a short pause, we selected Zombies, because they are the remnants of real documents that are hanging around. That seem to mesh well with the technical terminology already in use (zombie processes, for example) and a reference to the current popularity of zombies in culture (books, movies, etc) which many of our guys enjoy.&lt;/p&gt;&lt;p&gt;Note that in this case, I’m specifically using the term guys to refer to our male developers. One of our female developers didn’t like the terminology. Because Zombies are creepy, and we don’t want that in our UI. &lt;/p&gt;&lt;p&gt;There was a discussion on the terminology we’ll use that was very interesting, because it was on clearly defined gender lines. &lt;em&gt;None&lt;/em&gt; of the guys had any issue with the term, and that included a few that considered zombie movies to be yucky as well. All the women, on the other hand, thought (to varying degrees) that zombies isn’t the appropriate term to use.&lt;/p&gt;&lt;p&gt;We threw a few other ones around, such as orphans, but one of the features we wanted to have is the ability to wipe those traces, and “kill all orphans” is not something that I think would go well in our UI.&lt;/p&gt;&lt;p&gt;Eventually the idea to use the term ghosts was brought up, and it was liked by all. It has all the connotations desired to explain what this is (the remnants of a deleted document), but the images it evoked was Casper the Friendly Ghost and Pacman, apparently. &lt;/p&gt;&lt;p&gt;Given that while none of the guys thought there was a problem with zombies, but no one was also particularly attached to the name, and on the other hand we had strong opposition to the term and an alternative that made everyone happy, we switched to that terminology.&lt;/p&gt;&lt;p&gt;Fun fact, I was telling my wife this story and I wasn’t able to complete the description of the debate before she suggested using the Pacman image. &lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/AyendeRahien/~4/OS-Km52hlLw" height="1" width="1" alt=""/&gt;</description><link>http://feedproxy.google.com/~r/AyendeRahien/~3/OS-Km52hlLw/zombies-vs-ghosts-the-great-debate</link><guid isPermaLink="false">https://ayende.com/blog/178817/zombies-vs-ghosts-the-great-debate?Key=84f15b74-7689-4c6a-8d57-64c4a475e417</guid><pubDate>Mon, 26 Jun 2017 09:00:00 GMT</pubDate><feedburner:origLink>https://ayende.com/blog/178817/zombies-vs-ghosts-the-great-debate?Key=84f15b74-7689-4c6a-8d57-64c4a475e417</feedburner:origLink></item><item><title>Inventory management in MongoDB: A design philosophy I find baffling</title><description>&lt;p&gt;&lt;img align="right" style="float: right; display: inline;" alt="Related image" src="https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSJDu5_ZY112Qiys-n2q0RUFHM8-0a-aM5DvgQPAD6HyrHqO6ts2Jzdsw"&gt;I’m reading &lt;a href="https://www.manning.com/books/mongodb-in-action"&gt;MongoDB in Action&lt;/a&gt; right now. It is an interesting book and I wanted to learn more about the approach to using MongoDB, rather then just be familiar with the feature set and what it can do. But this post isn’t about the book, it is about something that I read, and as I was reading it I couldn’t help but put down the book and actually think it through.&lt;/p&gt;&lt;p&gt;More specifically, I’m talking about &lt;a href="https://github.com/banker/inventory/blob/master/lib/inventory.rb"&gt;this little guy&lt;/a&gt;. This is a small Ruby class that was presented in the book as part of an inventory management system. In particular, this piece of code is supposed to allow you to sell limited inventory items and ensure that you won’t sell stuff that you don’t have. The example is that if you have 10 rakes in the stores, you can only sell 10 rakes. The approach that is taken is quite nice, by simulating the notion of having a document per each of the rakes in the store and allowing users to place them in their cart. In this manner, you prevent the possibility of a selling more than you actually have.&lt;/p&gt;&lt;p&gt;What I take strong issue with is the way this is implemented. MongoDB doesn’t have multi document transactions, but the solution presented requires it. Therefor, the approach outlined in the book is to try to build transactional semantics from the client side. I write databases for a living, and I find that concept utterly baffling. Clients shouldn’t try to do stuff like that, not only would they most likely get it wrong, but they’ll do that extremely inefficiently.&lt;/p&gt;&lt;p&gt;Let us consider the following tidbit of code:&lt;/p&gt;&lt;blockquote&gt;&lt;script src="https://gist.github.com/ayende/c8ec9b1363f66ea25c05fb4c07bae423.js"&gt;&lt;/script&gt;&lt;/blockquote&gt;&lt;p&gt;The idea here is that the fetcher is supposed to be able to atomically add the products to the order. If there aren’t enough available products to be added, the entire thing is supposed to be rolled back. As a business operation, this make a lot of sense. The actual implementation, however, made me wince. &lt;/p&gt;&lt;p&gt;What it does, if it was SQL, is the following:&lt;/p&gt;&lt;blockquote&gt;&lt;script src="https://gist.github.com/ayende/abd73ba33c6ea2d79e032f050623f6a3.js"&gt;&lt;/script&gt;&lt;/blockquote&gt;&lt;p&gt;I intentionally used SQL here, both to simplify the issue for people who aren’t familiar with MongoDB and to explain the major dissonance that I have with this approach. That little add_to_cart call that we had earlier resulted in no less than &lt;strong&gt;eight&lt;/strong&gt; network roundtrips. That is in the happy case.&amp;nbsp; There is also the failure mode to consider, which involved resetting all the work done so far. &lt;/p&gt;&lt;p&gt;The thing that really bothers me is that I can’t believe that this is something that you’ll actually want to do except as an intellectual exercise. I mean, sure, how we can pretend to get transactions from non transactional store is interesting, but given the costs of doing this or the possibility of failure or the fact that this is a non atomic state transition or… you get my point, right?&lt;/p&gt;&lt;p&gt;In the case of this code, the whole process is non atomic. That means that outside observers can see the changes as they are happening. It also opens you up for a lot of Bad Stuff in terms of abusing the system. If the user is malicious, they can use the fact that this “transaction” is going to be running back and forth to the database (and thus taking a &lt;em&gt;lot&lt;/em&gt; of time) and just open another tab to initiate an action while this is going on, resulting in operations on invalid state. In the example that the book give, we can use that to force purchases of invalid items. &lt;/p&gt;&lt;p&gt;If you think that this is unrealistic, &lt;a href="http://josipfranjkovic.blogspot.co.il/2015/04/race-conditions-on-facebook.html"&gt;consider this page&lt;/a&gt;, which talks about doing things like &lt;em&gt;making money appear from thin air&lt;/em&gt; using just this sort of approaches.&lt;/p&gt;&lt;p&gt;Another thing that really bugged me about this code is that it has “error handling” I use that in quotes because it is like a security blanket for a 2 years old. Having it there might calm things up, but it doesn’t actually change anything. In particular, this kind of error handling &lt;em&gt;looks&lt;/em&gt; right, but it is horribly broken if you consider what kind of actual errors can happen here. If the process running this code failed for any reason, the “transaction” is going to stay in an invalid state. It is possible that one of your rake will just disappear into thin air, as a result. It is supposed to be in &lt;em&gt;someone’s&lt;/em&gt; cart, but it isn’t.&amp;nbsp; The same can be the case if the server had an issue midway or just a regular network hiccup. &lt;/p&gt;&lt;p&gt;I’m aware that this is code that was written explicitly to be readable and easy to explain, rather then be able to withstand the vagaries of production, but still, this is a very dangerous thing to do. &lt;/p&gt;&lt;p&gt;As an aside, not quite related to the topic of this post, but one thing that really bugged me in the book so far is the &lt;em&gt;number&lt;/em&gt; of remote requests that are commonly required to do things. Is there an assumption that the database in question is nearby or very cheap to access, because the entire design philosophy I use is to assume that going over the network is expensive, so let us give the users a lot of ways to reduce that cost. In contrast, at least in the book, there is a lot of stuff that is just making remote calls like there is a fire sale that will close in 5 minutes. &lt;/p&gt;&lt;p&gt;To be fair to the book, it notes that there is a possibility of failure here and explain how to handle one part of it (it missed the error conditions in the error handling) and call this out explicitly as something that should be done with consideration.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/AyendeRahien/~4/XFsIfhi4TTo" height="1" width="1" alt=""/&gt;</description><link>http://feedproxy.google.com/~r/AyendeRahien/~3/XFsIfhi4TTo/inventory-management-in-mongodb-a-design-philosophy-i-find-baffling</link><guid isPermaLink="false">https://ayende.com/blog/178785/inventory-management-in-mongodb-a-design-philosophy-i-find-baffling?Key=e9d8f617-cd97-4328-a380-e30e30c4f450</guid><pubDate>Sat, 24 Jun 2017 11:45:00 GMT</pubDate><feedburner:origLink>https://ayende.com/blog/178785/inventory-management-in-mongodb-a-design-philosophy-i-find-baffling?Key=e9d8f617-cd97-4328-a380-e30e30c4f450</feedburner:origLink></item><item><title>PR Review: avoid too many parameters</title><description>&lt;p&gt;During code review I run into these two sections, which raised a flag. Can you tell why?&lt;/p&gt;&lt;p&gt;&lt;a href="https://ayende.com/blog/Images/Open-Live-Writer/Design-guideline-avoid-too-many-paramete_B52/image_2.png"&gt;&lt;img width="780" height="64" title="image" style="margin: 0px; border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="image" src="https://ayende.com/blog/Images/Open-Live-Writer/Design-guideline-avoid-too-many-paramete_B52/image_thumb.png" border="0"&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="https://ayende.com/blog/Images/Open-Live-Writer/Design-guideline-avoid-too-many-paramete_B52/image_4.png"&gt;&lt;img width="861" height="64" title="image" style="margin: 0px; border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="image" src="https://ayende.com/blog/Images/Open-Live-Writer/Design-guideline-avoid-too-many-paramete_B52/image_thumb_1.png" border="0"&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;The problem with this type of code is two fold. First, we add optional parameters, to reduce the number of breaking changes we have. The problem with that is that we already have parameters on the call, and eventually you’ll get to something like this:&lt;/p&gt;&lt;p&gt;&lt;a href="https://ayende.com/blog/Images/Open-Live-Writer/Design-guideline-avoid-too-many-paramete_B52/image_10.png"&gt;&lt;img width="503" height="283" title="image" style="border: 0px currentcolor; border-image: none; display: inline; background-image: none;" alt="image" src="https://ayende.com/blog/Images/Open-Live-Writer/Design-guideline-avoid-too-many-paramete_B52/image_thumb_4.png" border="0"&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;Which is the queen of optional parameters method, and you can probably guess how it looks internally. &lt;/p&gt;&lt;p&gt;In the first case, we can add the new optional parameter to the… &lt;em&gt;options &lt;/em&gt;variable that we are already sending this method. This way, we don’t have to worry about breaking changes, and we already have a way to setup options, determine defaults, etc.&lt;/p&gt;&lt;p&gt;In the second case, we are passing two bools to the method, and there isn’t a preexisting parameters object. Instead of creating one, we can use a Flags enum, whose bits we can set to determine what exactly the behavior of this method should be. That is generally much easier to maintain in the long run.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/AyendeRahien/~4/VqE1k5aT6G8" height="1" width="1" alt=""/&gt;</description><link>http://feedproxy.google.com/~r/AyendeRahien/~3/VqE1k5aT6G8/pr-review-avoid-too-many-parameters</link><guid isPermaLink="false">https://ayende.com/blog/178721/pr-review-avoid-too-many-parameters?Key=737eb266-1341-4d8c-864a-293e9e33897a</guid><pubDate>Fri, 23 Jun 2017 09:00:00 GMT</pubDate><feedburner:origLink>https://ayende.com/blog/178721/pr-review-avoid-too-many-parameters?Key=737eb266-1341-4d8c-864a-293e9e33897a</feedburner:origLink></item><item><title>Inside RavenDB 4.0 book–Chapter 4 &amp; 5 are done</title><description>&lt;p&gt;&lt;a href="https://ayende.com/blog/Images/Open-Live-Writer/Inside-Raven.0-bookChapter-4--5-are-done_1405E/image_2.png"&gt;&lt;img width="250" height="195" title="image" align="right" style="border: 0px currentcolor; border-image: none; float: right; display: inline; background-image: none;" alt="image" src="https://ayende.com/blog/Images/Open-Live-Writer/Inside-Raven.0-bookChapter-4--5-are-done_1405E/image_thumb.png" border="0"&gt;&lt;/a&gt;The RavenDB 4.0 book is going really well, this week I have managed to write about 20,000 words and the current page count is at 166. At this rate, it is going to turn into a monster in terms of how big it is going to be.&lt;/p&gt;&lt;p&gt;The book so far covers the client API, how to model data in a document database and how to use batch processing in RavenDB with subscriptions. The full drafts are available &lt;a href="https://github.com/ravendb/book/releases/tag/v4.0.4-preview"&gt;here&lt;/a&gt;, and I would really appreciate any feedback you have. &lt;/p&gt;&lt;p&gt;Next topic is to start talking about clustering and this is going to be real fun.&lt;/p&gt;&lt;p&gt;I’m also looking for a technical editor for the book. Someone who can both tell me that I missed a semi column in a code listing and tell me why my phrasing / spelling / grammar is poor (and likely all three at once and some other stuff that I don’t even know). If you know someone, or better yet, interested and capable, send me a line.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/AyendeRahien/~4/oiTSwMTrSr0" height="1" width="1" alt=""/&gt;</description><link>http://feedproxy.google.com/~r/AyendeRahien/~3/oiTSwMTrSr0/inside-ravendb-4-0-book-chapter-4-5-are-done</link><guid isPermaLink="false">https://ayende.com/blog/178753/inside-ravendb-4-0-book-chapter-4-5-are-done?Key=bfb2e93d-0027-4af3-af12-fa50331e4e3b</guid><pubDate>Thu, 22 Jun 2017 09:00:00 GMT</pubDate><feedburner:origLink>https://ayende.com/blog/178753/inside-ravendb-4-0-book-chapter-4-5-are-done?Key=bfb2e93d-0027-4af3-af12-fa50331e4e3b</feedburner:origLink></item></channel></rss>
