Crucible Code Review Wishlist

I have been trying out Crucible Code Review software from Atlassian (halfway through the trial) with a number of teams in my department. The competition in this area is pretty sparse, and each one has its other issues:

  • Kiln only works for Mercurial (which we may move to some day, but for now we are using SVN so we need a solution that works with that as also)
  • Review Board seems to be very popular, but just looking at the list of the dependencies gives me indigestion when considering an install on our Windows Server environment.
  • Code Collaborator is way too expensive without giving much extra (50 users in Crucible = $2200, 50 named users in Code Collaborator = $24,450)
  • Code Review Tool doesn’t have a very professional looking site, hardly any documentation and no plugin potential and no Mercurial support
  • Specatare‘s and Parasoft‘s websites are even sparser and gives almost no info (aside from a few screenshots) – not enough to make me spend the time trying it out.

On the other hand, thus far Crucible has delivered on the main functionality: establishing a medium for easily performing code reviews. The price is very fair and there is very decent documentation. We will probably go with it, just for those reasons alone.

That said, I have a number of issues with Crucible – posting them here in the hopes that someone from Atlassian will see this and can do something about some or all of them. Continue reading

Horrible Page Design at JPost.com

I just loaded up a link at jpost.com talking about how the Rami Levy supermarket chain predicts that by 2012 20% of food purchases in Israel will be online. However, when I loaded the link, it took me a minute to actually find the content. Can you see the problem here?

To make it a little bit clearer, I have added highlights – Ads are in yellow, In-site navigation is in green, and the content is in blue. The content occupies a tiny strip down the center of the page (maybe 30-40% of the total width of the page). This is surrounded on all sides several layers: Continue reading

Clearing out a Mysterious Table Lock (LCK_M_S) in Sql Server 2008

A user reported today that they were trying to query a table with 181 records and the output stopped at 178 and just hung there. I tried to replicate this and the same thing happened – also couldn’t run a Select (*) on the table. So I pulled up the Activity Monitor for the server and observed that there was only one query in process – the hung query. It listed the process as being suspended with a Wait Type of LCK_M_S. Some quick searching told me that the task was waiting to acquire a shared lock. However, it was not obvious what was locking the table. What to do?

After some more searching, I found two more posts that gave advice on what to do in the given scenario:

Based on these, I did the following:

    1. Ran Exec sp_who2 through Sql Management Studio. This gave me a list of all current processes. There was only one open process on this database at the time, so it was the likely culprit.
    2. Next, ran the code in the Sql Server Locks article above to show the process that was locking my table. Bingo – process 52.
USE DBNAME; GO;

DECLARE @dbid INT ; --what's the dbid for DBNAME?
SET @dbid = DB_ID() ;

DECLARE @objectid INT ; --what's objectid for our demo table?
SET @objectid = OBJECT_ID(N'TABLENAME') ;

--look at locking in the DB
SELECT  resource_type
       ,resource_database_id
       ,resource_associated_entity_id
       ,request_mode
       ,request_type
       ,request_session_id
FROM    sys.dm_tran_locks
WHERE   resource_database_id = @dbid ;

--limit the results to only the offending table
SELECT  *
FROM    sys.dm_tran_locks
WHERE   resource_database_id = @dbid AND
        resource_associated_entity_id = @objectid ;

After I had confirmed the identity of the process, I ran Kill 52 to kill the offending process. Everything immediately started working again with the table.

(After the fact, went back through the code with my team and found the spot where someone was running db.Connection.BeginTransation() on a data context that already had an open transaction, causing an error: “SqlConnection does not support parallel transactions“. And to make things worse, this was done outside of the try/catch/finally structure that ensured that any open transactions would be committed. Oy.)

As Pinal Dave writes:

As mentioned earlier, if you kill something important on your production server, there’s a great possibility that you’ll face some serious integrity issues, so I there’s no way I advise use this method. As the title goes, this is a dirty solution so you must utilize this only if you are confident.

It is important to keep that in mind. But that said, this technique for identifying and killing a hung transaction can definitely come in handy. (And be sure to backup your DB and transaction logs regularly!)

Numeric String Sort in C#

Scenario: you have a List<string> collection where the contents could be alpha, numeric, or alphanumeric. If you just sort the collection using the built-in Sort() method, it will use string.CompareTo(), treating each item in the collection as a string. Thus a collection with the following values ["1", "44", "22", 4", "5"] will end up being sorted as ["1", "22", "4", "44", "5"] – even though you might want the items to be treated as numbers (in which case they would be sorted as ["1", "4", "5", "22", "44"].

The solution to this is to use a custom comparer class. I put the following together:

public class NumericStringSort : IComparer {

    int IComparer.Compare(string a, string b) {
        decimal aDec;
        decimal bDec;
        if (decimal.TryParse(a, out aDec) && decimal.TryParse(b, out bDec)) {
            return aDec.CompareTo(bDec);
        } else {
            return a.CompareTo(b);
        }
    }

    public static IComparer NumericStringSorter() {
        return (IComparer) new NumericStringSort();
    }
}

As you can see, the class implements the IComparer interface. If both of the strings can be converted into decimals, then the decimal comparison is used. Otherwise the string comparison is used.

You can see a usage example through the following set of unit tests (as you can see, it also handles mixed alphanumeric sets gracefully, sorting all numeric items to the front of the list in numeric order, followed by all alpha entries in alphabetical order):

[TestFixture]
public class NumericStringSortTests {

    [Test]
    public void TestNumericSort_AllNumeric() {
        List items = new List { "1", "44", "22", "4", "5" };
        items.Sort(NumericStringSort.NumericStringSorter());
        List expectedItems = new List { "1", "4", "5", "22", "44" };
        Assert.IsTrue(items.SequenceEqual(expectedItems));
    }

    [Test]
    public void TestNumericSort_MixesAlphaNumeric() {
        List items = new List { "a", "c", "d", "b", "1", "2", "22", "3" };
        items.Sort(NumericStringSort.NumericStringSorter());
        List expectedItems = new List { "1", "2", "3", "22", "a", "b", "c", "d" };
        Assert.IsTrue(items.SequenceEqual(expectedItems));
    }

    [Test]
    public void TestNumericSort_AllAlpha() {
        List items = new List { "a", "c", "d", "b" };
        items.Sort(NumericStringSort.NumericStringSorter());
        List expectedItems = new List { "a", "b", "c", "d" };
        Assert.IsTrue(items.SequenceEqual(expectedItems));
    }
}

This is something that I have needed on previous occasions – perhaps it may be of use to someone else.

Connecting to Excel and Access Files using .Net on a 64-bit Server

If you are trying to query a MS Excel (.xls, .xlsx, .xlsb) or MS Access (.mdb, .accdb) file on a 64-bit server and are getting one of the following error messages:

  • The ‘Microsoft.Jet.OLEDB.4.0’ provider is not registered on the local machine.
  • The ‘Microsoft.ACE.OLEDB.12.0’ provider is not registered on the local machine.

Then it is necessary to install 2010 Office System Driver Beta: Data Connectivity Components on the server (the reason for this is the old Jet4.0 drover does not exist for 64 bit, and the ACE driver needed to read the newer formats is not installed by default). If you are using a version of Windows with UAC enabled, be sure to do this as Administrator.

After installing the components, use the following connection string formats (from the page linked-to above):

  • Using OLEDB, set the Provider argument of the ConnectionString property to “Microsoft.ACE.OLEDB.14.0”. Example: “Provider=Microsoft.ACE.OLEDB.12.0;Data Source=Path_To_File”
  • Using OLEDB and connecting to a Microsoft Office Excel file, add “Excel 14.0” to the Extended Properties of the OLEDB connection string defined in the previous bullet point.
  • Using ODBC:
    • Connecting to Microsoft Office Access (.mdb or .accdb): set the Connection String to “Driver={Microsoft Access Driver (*.mdb, *.accdb)};DBQ=path to mdb/accdb file”
    • Connecting to Microsoft Office Excel (.xls, .xlsx, .xlsb): set the Connection String to “Driver={Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb)};DBQ=path to xls/xlsx/xlsm/xlsb file”

Fixing the “circular file references are not allowed” Error in ASP.net

If you get the “circular file references are not allowed” error in an ASP.net Website Project and you do not have any controls that have any obvious circular references, what does the error mean and how do you fix it?

See this blog post from Siderite Zackwehdex as well as this MSDN forum post: by default, in a Website Project, ASP.net compiles one dll per folder in an ASP.net project. So if you have the following setup:

/folder1/Control1.ascx > References Control2
/folder2/Control2.ascx > References Control3
/folder1/Control3.ascx

This means that the folder1 dll will reference the folder2 dll which will again reference the folder1 dll, causing a “circular file reference”.

Even if there is not a direct path between the controls, looping into a circular reference, but there is a direct path connecting the circular reference through other controls in the same directories, it can throw the circular file references error. For example:

/folder1/Control1.ascx > References /folder2/Control2a.ascx
/folder2/Control2b.ascx > References /folder1/Control3.ascx
/folder1/Control3.ascx

Ways to fix it:

  1. Rearrange the layout of your controls (or masterpages) to remove the circular references (normally this will mean moving one control to another folder – in the example above, move control2 to folder1). This is the preferred solution.
  2. Use batch=”false” in the compilation tag of the web.config file. This will cause a new dll to be created for each control/page in the site. This should fix the error but is really lousy for performance, so it should be avoided (especially on production sites).

(This has happened to me a couple of times already, so posting it here as a reminder to myself for the next time).