Oren Eini

CEO of RavenDB

a NoSQL Open Source Document Database

Get in touch with me:

oren@ravendb.net +972 52-548-6969

Posts: 7,575
|
Comments: 51,192
Privacy Policy · Terms
filter by tags archive
time to read 2 min | 261 words

I'm browsing through the Shared Source CLI at the moment, for no good reasons...

I found the following comment in the System.String implementation...

**Action: Many years ago, VB didn't have the concept of a byte array, so enterprising
**        users created one by allocating a BSTR with an odd length and using it to
**        store bytes.  A generation later, we're still stuck supporting this behavior.

Good to show a sense of humer in the code, I always says.

Did you know that the CLR has a week reference hashtable? (Marked internal, of course, so you will not be able to use that ("Why, you horrible little man, why would you want to use a weak hashtable? Infidel")

You just love Clipboard Inheritance, don't you?

The generic Dictionary was copied from Hashtable's source - any bug
fixes here probably need to be made to the generic Dictionary as well.

(To be fair, I can't think of another way to do it)

I like this quote too:

(Knuth's Art of Computer Programming, Vol. 3, p. 528-9)
time to read 1 min | 85 words

Nothing like making a refactoring that goes through 140 compiler errors that I need to handle manually. Right now my least favoriate class in the framework is System.DateTime.

Nothing like adding a forth dimention to your application to make you realize how much you hate time.

On the other hand, I did get to create an OutOfTimeException which are going to provide me with hours of fun...

time to read 18 min | 3402 words

Logging is fairly critical to many applications, and it is especially critical when you are trying to understand in a complex application. I'm using log4net for logging, because it is so simple to start with and it can scale up to very complex needs.

The problem that I had was watching the logs. Specifically, watching the logs run in real time. The application is heavily mutli threaded, and run as a windows service. It is pretty hard to get what is going on there unless you watch the progress of the logs. At first, I simply logged to a file, and read it in notepad. This approach doesn't really scale well.

Next, I tried log4net viewer, which is really simple to get working. Just start the application, and put the following in your log4net config:

<appender name="UdpAppender"

                type="log4net.Appender.UdpAppender">

       <param name="RemoteAddress"

                 value="127.0.0.1" />

       <param name="RemotePort"

                 value="8080" />

       <layout type="log4net.Layout.XmlLayout">

              <param name="Prefix"

                        value="" />

       </layout>

</appender>

Here is what it looks like:

(Image from clipboard).png

The problem is that it is very simple, and it has several bugs that I couldn't live with (specifically, it doesn't display the information correctly if you are using sorting or filtering).

I then turned to log4j's chainsaw client, which is far more impressive feature wise. This is a java UI client, but it is very sophisticated. Almost to the point of being of no use to me, actually.

First, you need to put this in your log4net config:

<appender name="UdpAppender"

                type="log4net.Appender.UdpAppender">

       <param name="RemoteAddress"

                 value="127.0.0.1" />

       <param name="RemotePort"

                 value="8080" />

       <layout type="log4net.Layout.XmlLayoutSchemaLog4j, log4net" />

</appender>

Then, create a file called log4net.config.xml with the following content:

<?xml version="1.0" encoding="UTF-8" ?>

<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">

<log4j:configuration

       xmlns:log4j="http://jakarta.apache.org/log4j/"

       debug="false">

       <plugin name="UDPReceiver"

                     class="org.apache.log4j.net.UDPReceiver">

              <param name="Port"

                        value="8080" />

       </plugin>

</log4j:configuration>

On startup, the chainsaw will request a configuration file:

(Image from clipboard).png

Specify the location of the log4net.config.xml file that you creted previous, select don't show me this again, and click OK.

Then, you get the main UI, you need to click on the chainsawl-log tab:

(Image from clipboard).png

You should get a screen similar to this:

(Image from clipboard).png

The part marked in red is the loggers tree, which will become important in just a minute. Right now it displays just chainsaw' own internal logs.

Now, start an application that will log to the UDP Appender, and watch the tree on the right, here is how it looks like after I run a bit of NHibernate's tests:

(Image from clipboard).png

Right click on the part of the tree that interests you and select focus on '...'

You can double click on the tab header to get the tab in a seperate window (useful for utilizing screen real estate):

(Image from clipboard).png

Chainsaw how powerful filterring and coloring features, and it is pretty good in allow me to check what my application is doing in real time.

time to read 3 min | 533 words

This post hit a really sensitive point with me, Eber is showing some of the more complex forms of generics. Here is how he hold all the files in all the directories in all the computers

Dictionary<string, Dictionary<string, List<string>>> list = 
new Dictionary<string, Dictionary<string, List<string>>>();

I can't read code like this. I have a dictionary of a dictoary of a list. That is all fine and dandy, so far. The using code looks like this:

list[@\\Rhino][@"C:\Files"][5] 

The problem is that without knowing what this mean, I have no idea how to work with this. What is the first string, what is the second one, and what is the third one, for crying out loud?

Code like the above is opaque, is doesn't tell me what it is. A far better alternative would be something likes:

public class Domain
{
  public IDictionary<string,Computer> Computers { get; }
}

public class Computer
{
  public IDictionary<string, Directory> Directories { get; }
}

public class Directory
{
 public IList<string> Files { get; } 
}

This is a data structure that has a meaning. The client code looks like this:

domain.Computers[@"\\Rhino"].Directories[@"C:\Files"].Files[5]

Now I can read it without knowing having to know what the original author meant.

Yes, having generics can save us a bit of time in creating a new class, but you should ask yourself if this is worth losing the clarity of the code.

time to read 3 min | 554 words

The fastest way to get data from the database is not getting it from the database.

I talked about NHibernate's caches in the past, but I was mostly focused on entities and collection caching. Those are fairly easy to grasp. You load an entity once, and the second time, it doesn't get loaded.

Collections are slightly more complicated, since they require you to know what is going on (otherwise, you may get into a bit of problem, like I did), but they really reduce the amount of work the database has to do, since even the links between the objects are cached.

The problem is that very few applications can be structured so you can always ask for an object by its primary key. This brings us to the next (and probably final) cache.

Let us check an example:

session.CreateQuery(typeof(Post))
  .Add(Expression.Like("Content""User",MatchMode.Anywhere))
  .List();

This is a fairly expensive query, and it can't make use of the already existing cache. Even though the data may be on the cache already, NHibernate is not going to use the caches for querying, that is what databases are good at, after all. The query about will hit the database each and every time.

What can we do about it? Well, there is always the...

Query Cache

The query cache can hold the results of both types on NHibernate's queries (Criteria queries, and HQL queries)

(Image from clipboard).png(Very partial view of those interfaces)

Let us take the above query and add caching to it:

session.CreateQuery(typeof(Post))
  .Add(Expression.Like("Content""User",MatchMode.Anywhere))
  .SetCachable(true)
  .List();

Now, NHibernate will cache the results of the query, and next time that you execute the query, you will get it without the expensive hop to the database.

An important note is remembering to add hibernate.cache.use_query_cache = true to the configuration.

Of course, there are quite a bit of issues with caching querying, mostly about the freshness of the data. Which is why you need to make cached queries explictly in the code.

Use with care.

time to read 1 min | 60 words

About a week ago I recieved a really nice email, which contained updates to Reflector's Boo for 4.2, you can get it here.  You can find the source here.

The code donator is (let's see if I get it right) 李歆涛, so thanks you very much. And sorry for taking so long.

FUTURE POSTS

  1. Scaling HNSW in RavenDB: Optimizing for inadequate hardware - 5 hours from now

There are posts all the way to May 14, 2025

RECENT SERIES

  1. RavenDB News (2):
    02 May 2025 - May 2025
  2. Recording (15):
    30 Apr 2025 - Practical AI Integration with RavenDB
  3. Production Postmortem (52):
    07 Apr 2025 - The race condition in the interlock
  4. RavenDB (13):
    02 Apr 2025 - .NET Aspire integration
  5. RavenDB 7.1 (6):
    18 Mar 2025 - One IO Ring to rule them all
View all series

Syndication

Main feed Feed Stats
Comments feed   Comments Feed Stats
}