Two inmates has escaped from Qteziot prison (link - hebrew). I spent two years of my life in there, trying very hard to make sure that it wouldn't happen...
This really sucks.
Two inmates has escaped from Qteziot prison (link - hebrew). I spent two years of my life in there, trying very hard to make sure that it wouldn't happen...
This really sucks.
It is 2AM right now, and I am chatting with someone about Inversion of Control containers... The kicker is that we are on the same timezone, sigh...
First, let me describe the scenario, I am using Object Builder in a web application to manage the services of the application. Under load, we started to get exceptions from deep within Object Builder. I should also preface this by saying that I have very little knowledge of Object Builder and it is entirely possible that I am commiting some grave error in using it.
Anyway, here is a simple wrapper for Object Builder:
public class BuilderHelper
{
private Locator _locator = null;
public BuilderHelper():this(new Locator())
{
}
public BuilderHelper(Locator locator)
{
this._locator = locator;
if (!_locator.Contains(typeof(ILifetimeContainer)))
_locator.Add(typeof(ILifetimeContainer), new LifetimeContainer());
}
public T Build<T>()
{
BuilderStrategyChain chain = new BuilderStrategyChain();
chain.Add(new SingletonStrategy());
chain.Add(new CreationStrategy());
PolicyList policies = new PolicyList();
policies.SetDefault<ICreationPolicy>(new DefaultCreationPolicy());
BuilderContext builderContext = new BuilderContext(chain, _locator, policies);
T result;
result = (T)builderContext.HeadOfChain.BuildUp(builderContext, typeof(T), null, null);
return result;
}
}
And here is the client code:
[TestClass]
public class StressTestingFixture
{
private int count = 1000;
[TestMethod]
public void SimulateHeavyLoad()
{
ArrayList list = ArrayList.Synchronized(new ArrayList());
ManualResetEvent wait = new ManualResetEvent(false);
Locator locator = new Locator();
WaitCallback callback = delegate
{
wait.WaitOne();//This is required so there will be a lot of threads creating objects at the same time
try
{
BuilderHelper builder = new BuilderHelper(locator);
Something i1 = builder.Build<Something>();
if (count % 7 == 0)//need to make sure that GC Collection occurs, so it would clear the WeakRefDictionary
GC.Collect(2);
}
catch (Exception e)
{
string txt = e.ToString();
Console.WriteLine(txt);
list.Add(txt);
}
finally
{
Interlocked.Decrement(ref count);
}
};
for (int i = 0; i < count; i++)
{
ThreadPool.QueueUserWorkItem(callback);
}
wait.Set();
while (count > 0 && list.Count == 0)
Thread.Sleep(15);
if (list.Count > 0)
{
Assert.Fail((string)list[0]);
}
}
private class Something
{
}
}
The error I am getting:
To say that this is worrying is a major understatement...
Any EntLib experts that can shed some light into this?
Since I was asked, here is a demo application for using Active Record and Repository<T>. Please note that this is an internal application that I use to merely test some ideas, so it is a bit rough, and there isn't any real functionality.
Here are the links to the source online:
Pierre Henrie is running an NHibernate contest. I am not applicable for this contest, but I think that I can safely add that the prize is highly desirable for anyone using NHibernate.
Go make a guess...
Note: I just spend quite a bit time writing this, I am putting it on my blog so I will remember it exsts.
Who am I?
I was urgently called today to solve a problem in one of my applications. The problem was that for some reason, the application would stop process incoming files, a restart would fix this issue for a short while, after which the problem would re-appear. The application is heavily multi threaded, and has a lot of logging built in to help diagnose issues that may crop up.
The problem is that the problem never even showed up in the logs. It was as if the application stopped watching the directory, but it should never do that. I began to consider framework bugs and was about to start investigating how to investigate this issue when I noticed a recurring pattern in the logs:
Cycle #123:
Checking status of Item #42: Not yet ready
Checking status of Item #43: Not yet ready
Checking status of Item #44: Not yet ready
Checking status of Item #45: Not yet ready
Checking status of Item #46: Not yet ready
Cycle #124:
Checking status of Item #42: Not yet ready
Checking status of Item #43: Not yet ready
Checking status of Item #44: Not yet ready
Checking status of Item #45: Not yet ready
Checking status of Item #46: Not yet ready
Hm... an item is sent to another machine for processing, and the communication between the two parts is done via a web service, on a fairly slow connection.
What happened was interesting, there was a large number of items that has not been processed yet, and at every cycle (~1 minute) all of them were checked indepdently. The problem was that when it got to the point where enough of them were being queries, the next cycle began before the first one could begin.
Since checking the status of all the items was done on a thread pool thread, and since processing a new item (and logging it) also accurrs on a thread pool thread. After the application has been running for a while, asking the second server for status starts to consume most of the thread pool threads, and processing of new items is delayed until their turn in the queue arrives (although that is not guranteed).
The "fix": change the cycle time for checking status to 10 minutes and asking the other side to start processing this on more than a dialy basis.
Please note that this is no longer supported behavior in NHibernate 2.1 and up. It was a hack to begin with, and it isn't guaranteed to continue working.
I can't think of a good name for this post, but it is a very cool discovery. First, let us examine the scenario, a customer of mine has bought a database of localized data, which had the following structure:
Now, what the customer wanted to be able to do is something like this:
Product product = session.Get<Product>(5);
productName.Text = product.Name;
And get the correct name for the user's culture. In addition to that, they didn't want to have to load the all the product names collection and get the name in memory. The database include several hundred thousnads of products, localized to several languagues, so this is a big perf concern.
I thought about this quite a bit, and was nearly at the point where I told them that it can't be done when I recalled that NHibernate 1.2 added filters capabilities. A quick testing proved that it is possible to do this with NHibernate, using the following approach:
First, we need to map the product, like this:
<class name='Product'>
<id name='Id'
column='id'>
<generator class='native'/>
</id>
<property name='Amount'/>
<property name='Size'/>
<property name='Name'
formula='(SELECT ProductNames.Name FROM ProductNames
WHERE ProductNames.Id = id and ProductNames.CultureId = :CultureFilter.CultureId)'/>
</class>
Please note the Name property, we map it using a formula, which is just a piece of SQL that we put in the mapping. The new thing here is that we can refer to :CultureFilter.CultureId in the formula. Where does it come from? As you can see above, we need this to be transparent to the developer when using the code.
The secret is in the following bit of mapping:
<filter-def name='CultureFilter'>
<filter-param name='CultureId' type='System.Int32'/>
</filter-def>
Here we define a filter, which takes parameters, usually a class will use the filter-def parameters to express a filter according to this parameters. But we don't want to filter the results, we want to just have it happen. It turns out to be that using the full name of the filter parameter is something that NHibernate understand anywhere, so...
//This is usually in Application_BeginRequest
session.EnableFilter("CultureFilter").SetParameter("CultureId", Thread.CurrentThread.CurrentCulture.LCID);
Product product = session.Get<Product>(5);
productName.Text = product.Name;
And you get exactly what you wanted! I was very pleased when I was able to come up with such an elegant solution :-D
In response to a question about why extend NUnit instead of MS Test, Scott Bellware gives one of the most eloquent response that I have seen in a long time.
I personally don't use MS Test. It's a niche product built by a team that was largely detached from the developer testing community. It's mostly visual glitz aimed at people who don't really have the experience to be discerning, and who can be manipulated into buying tools by blinking lights and shiny surfaces. The VSTS product line segmentation is out of touch with the reality of the cross-functional roles that developers are increasingly called to play. It's way over-priced.
There would be little value in me writing extensions for MS Test. The limited community of folks who have adopted it are largely following Microsoft's guidance on developer testing and thus are missing the BDD point as widely as Microsoft missed the TDD point. The open source world is innovating in this space much faster than Microsoft can hope to - both in tooling and the appraches driving the tooling.
The above summarizes my opinions on MS Test much better than I could.
I am currently thinking about my next project, and I really want to use Active Record, and at the same time, I really want to be able to utilize Repository<T> and decorators chains or not.
A long time ago I made sure that Active Record will be usable without utilizing the "Active Record"-ness of it, so it wasn't that hard to build an IRepository<T> implementation for it, implementing UnitOfWork was a bit more tricky, since I wanted to keep the option to use NHibernate / Active Record at will, as always, another layer of abstraction is always the answer.
I went to such lengths mainly because I didn't want just to get the Active Record RAD capabilities, but to take advantages of the other advantages that it offers (Validation is one, ARDatabind is another, etc). I am not so sure that this is a good idea, though.
I am considerring using Active Record to just generate the mapping (since it has very strong cross-inferencing capabilities), but I am not sure if that is a good idea in the long run...
Any ideas?
No future posts left, oh my!