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,565
|
Comments: 51,184
Privacy Policy · Terms
filter by tags archive
time to read 1 min | 55 words

I got a number of queries about it. My Wiki db was lost during the servers transafer in my old host, they also manage to lose all the backups. I managed to save a bit of the Rhino Mocks documentation from the Google Cache, and I'll try to update it shortly.

Why me?

time to read 2 min | 207 words

I just chased a bug that basically resolved into:

static NHibernateNullablesSupport()
{
   tINullableType = Type.GetType("Nullables.INullableType, " + NullableAsm, false);
}

For those that are unfamiliar with GetType, the last parameter is bool throwOnError, passing false ensure that it wouldn't throw if it can't find the type. But it did.

Eventually I tracked it down to:

MbUnit.AddIn.MbUnitTestRunner.AssemblyResolveHandler

Which will try to resolve an assembly, but will throw if it is not found. Breaking the behavior of the above code. I don't mind the bug, it is reasonable action on the part of MbUnit, since I doubt that the implementer thought of this scenario. It is just I am starting to feeling that I usually have a very short time to bug finding in very wierd corner cases...

time to read 2 min | 303 words

Well, it looks like I have run into some limits with dasBlog.

I have over 2,000 posts, and close to 1,200 files in my content directory. It gets to the points that just opening the directory has a noticable delay.
Trying to run dasBlog currently takes roughly 100% of the CPU, and takes forever. This is on my machine, by the way, so it is single user only.

Trying that on the server apperantly killed it. 

Profiling it shows that the fault is probably with the template processor, AddParsedObject and InitializeMacro. That is about all the information that I managed to get from VS profiler, I am currently trying out dotTrace, to see if it can gives me a better idea about what is going on there.

Using dotTrace, the picture is much clearer, it looks like the cost is in iterating over all the past entries, you can take a look here for the details:
dasblog-perf.png

I removed all the entries from July 06 and backward, and this seems to bring the blog to a working state again. This is a temporary measure only. I am not willing to give up 2+ years of blogging. I have uploaded the dtc (dot trace snapshot) here, if anybody is interested in taking a look I can provide the full backup history, which put dasBlog through the grinder.

At the same time, I am investigating Subtext, which may be more appropriate for my kind of blog. The main concerns are not breaking links (but it is acceptable to have redirect) and having to re-do the blog design.

time to read 8 min | 1473 words

This bug caused a production system to grind to a screeching halt, under just the right amount of load. Took a while to figure out what was happening.  I created a small test that shows what the problem is.

Here is a little description:

  • The timer wakes a set of services that need to process input.
  • To avoid re-entrancy issues, I used synchornized methods.
  • Some services does non trivial amount of work.

class Program

{

      static int count = 0;

      static Timer timer;

      static void Main(string[] args)

      {

            timer = new Timer(delegate

            {

                  int temp = Interlocked.Increment(ref count);

                  ThreadPool.QueueUserWorkItem(DoLengthyWork, temp);

                  ThreadPool.QueueUserWorkItem(ReportStatus, temp);

            },null,100,100);

            Console.ReadKey();

      }

 

      [MethodImpl(MethodImplOptions.Synchronized)]

      public static void DoLengthyWork(object counter)

      {

            //do stuff that may fail on re-entry

            Thread.Sleep(1500);

            Console.WriteLine("Finished lengthy work: {0}",  counter);

      }

 

      public static void ReportStatus(object counter)

      {

            Console.WriteLine("Reporting status: {0}", counter);

      }

}

For fun, this takes about a minute to fail...

What is the problem, and what is causing it?

time to read 14 min | 2796 words

The question was brought up, and I had to find out what the behavior is under this conditions. Here is the test scenario:

class Program

{

      Hashtable t = new Hashtable();

      ManualResetEvent startAllAtOnce = new ManualResetEvent(true);

      static void Main(string[] args)

      {

            Program p = new Program();

            List<Thread> threads = new List<Thread>();

            for (int i = 0; i < 50; i++)

            {

                  Thread thread = new Thread(p.DoWork);

                  threads.Add(thread);

                  thread.Start();

            }

            p.startAllAtOnce.Set();

            foreach (Thread thread in threads)

            {

                  thread.Join();

            }

      }

 

      public void DoWork()

      {

            startAllAtOnce.WaitOne();

            if(t.ContainsKey("aabc")==false)

            {

                  Thread.Sleep(100);

                  t.Add("aabc","cc");

            }

      }

}

This method simulate a race condition, it is a very simple test case, if it throws an exception, the test is failing.

Right now, trying to run the code above will throw. Let us try something a bit more sophisticated.

[MethodImpl(MethodImplOptions.Synchronized)]

public void DoWork()

{

      startAllAtOnce.WaitOne();

      if(t.ContainsKey("aabc")==false)

      {

            Thread.Sleep(100);

            t.Add("aabc","cc");

      }

}

The method has an attribute that tells the runtime that only one thread can execute this method (per instance, by the way). Now, what happens when you throw virtual methods into the mix? Let us try this:

class Derived : Program

{

      public override void DoWork()

      {

            startAllAtOnce.WaitOne();

            if (t.ContainsKey("aabc") == false)

            {

                  Thread.Sleep(100);

                  t.Add("aabc", "cc");

            }

      }

}

Let us change the first line of Main to:

Program p = new Derived();

Now it throws. The synchronized option is not inherited. The most interesting part comes when you try to do this for across the hierarcy, where it also doesn't work (because it is using a different instance).

Just a little tibit that is interesting to know... This just went to the list of "Thing you are going to get asked if you tell me that you know .Net multi threading*".

* Asked meaning that you get Visual Stuido and ~10 minutes to figure it out.

time to read 12 min | 2250 words

Tomer Gabel commented on my post about debuggable configuration:

This may be debuggable, but it sure as hell doesn't look like configuration to me. Configuration should be declarative and should not contain complex logic (what you show above definitely falls under that category in my book). This sort of script is, as far as I'm concerned, tantamount to collating all your configurable properties into one external, dynamically-compiled class -- in other words, hardcoded.

Let me just point out what I tried to do when I started using this approach:

death.by.xml.png

Looks familiar, anyone? I have shown this image to a fair amount of people, I got a lot of guilty looks :-) and general acknowledgement that this is a very bad place to be.

Now, to Tomer's comment:

This is a dynamically compiled class, but I wouldn't call it hard coded. It has all the features of a configuration file, i.e: restart the app and it will get the chances, I even has an app when I can do this type of changes on the fly. Declarative is an issue because you start to get out of control very fast with it in even mildly complex scenarios.

When I need to change a property or a feature, I can do so by opening this in notepad, make a change, and continue, there is nothing else that is needed to happen. I routinely does such things on production (tuning parameters, etc). I believe that this approach is far more common in dynamic langauges. Configuring MediaWiki, for instnace, is done by editing a php file.

This simplify things to a large degree, no need to extract values form XML, build the object graph, transform it, etc. I can just build the final result directly. The code I have shown is also doing some glue to connect some parts of the application. I mentioned that I am not sure if it is the responsability of the configuration to do so, but that is another matter.

Where does XML configuration fails?

Repeated configuration, I need to define 10 things of the same kind, with slight variations. For instance, defining a customer, where each customer has a different connection string:

customersDatabases = {

      "Northwind"       : "Data Source=...",

      "AdventureWorks"  : "Data Source=..."

      }

     

for entry in customersDatabases:

      Application.RegisterClientDatabase(entry.Key, entry.Value, ClientOptions.UseSharedConfiguration)

Now, imagine trying to do that in XML. Specifying debug/release configuration is also much easier:

if Environment.MachineName ~= /prod/: #production

      Application.LogLevel = LogLevel.Error

      Application.CrashReport = ( EmailReport("admin@site.com"), SmsReport("132432142") )

      Application.ShowErrorToUser = false

     

if Environment.MachineName ~= /test/: # test / staging

      Application.LogLevel = LogLevel.Info

      Application.CrashReport = ( BugTrackReport("trac.build.com"), )

      Application.ShowErrorToUser = false

     

if Environment.MachineName ~= /lap/: # dev machine

      Application.LogLevel = LogLevel.Debug

      Application.CrashReport = ( ErrorMessageReport("trac.build.com"), )

      Application.ShowErrorToUser = false

Trying to do the same in XML bring you right back to trying to debug XML. Since I don't know anyone except developer / IT admin that is going to touch a configuration file anyway, the claim that it is not readable to non-dev is not an issue. It is worth mentioning, though, that it is fairly easy to build a GUI over this.

time to read 8 min | 1525 words

Okay, this is a lie, but it is nearly true. Take a look at this Binsor script:

def OnNewTransaction(transaction as ITransaction,  transactionMode as TransactionMode,  isolationMode as IsolationMode):

    transaction.Enlist( TransactionScopeResourceAdapter(transactionMode) )

 

Component(transaction_manager, ITransactionManager, DefaultTransactionManager)

IoC.Container.AddFacility("automatic_transaction_management_facility", TransactionFacility())

 

IoC.Container.Kernel.ComponentCreated += do(model as ComponentModel, instance as object):

    cast(ITransactionManager, instance).TransactionCreated += OnNewTransaction if instance isa ITransactionManager

 

activeRecordAssemblies = ( Assembly.Load("Exesto.Model"), )

 

Component(active_record_repository, IRepository, ARRepository)

Component(active_record_unit_of_work, IUnitOfWorkFactory, ActiveRecordUnitOfWorkFactory, assemblies: activeRecordAssemblies )

 

Component(just_service, JustService)

In 10 lines of code, it setup a Active Record, setup unit of work, setup automatic transaction support, bind it to my Active Record Unit Of Work Adapter (note the OnNewTransaction and registerring to the ComponentCreated event) and setup a service that uses declarative transactions.

It also slice, dice and debug ;-)

On the one hand, it opens up a whole new world of options in the configuration. On the other hand, should this stuff be in the configuration in the first place? The ability to do things on ComponentCreated, for instnace, or to register to a specific event from a service and do stuff from the configuration is very powerful. The problem is that I am very afraid of trying to maintain anything but the simplest stuff there, since it is probably the most volatile part of the application.

 

 

FUTURE POSTS

No future posts left, oh my!

RECENT SERIES

  1. Production Postmortem (52):
    07 Apr 2025 - The race condition in the interlock
  2. RavenDB (13):
    02 Apr 2025 - .NET Aspire integration
  3. RavenDB 7.1 (6):
    18 Mar 2025 - One IO Ring to rule them all
  4. RavenDB 7.0 Released (4):
    07 Mar 2025 - Moving to NLog
  5. Challenge (77):
    03 Feb 2025 - Giving file system developer ulcer
View all series

RECENT COMMENTS

Syndication

Main feed Feed Stats
Comments feed   Comments Feed Stats
}