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,640
|
Comments: 51,263
Privacy Policy · Terms
filter by tags archive
time to read 7 min | 1259 words

I am using SVK as a way to learn Distributed SCM, and it has been fine so far, except for one big issue. I am trying to apply SVN patches against SVK repositories. Actually, I setup SVK so I work against a local mirror, so the workflow is exactly the same, but the revision numbers are different. Trying to apply a patch just doesn't work because of that.

You can go into the patch and edit the root revision, so it is not hard to make this work, except...

SVK doesn't give me any mapping between the local revision and the source revisions (maybe it does, and someone will tell me). This means that in order to find the right version I have to do some annoying digging.

Here is a small program to solve the problem. Usage: svkrev [repository path] [source revision to look for]

Example:

C:\Users\Administrator>svkrev //mirror/nhcontrib 195
exec: svk log --xml //mirror/nhcontrib
exec: svk propget svm:headrev //mirror/nhcontrib --revprop -r 10298
exec: svk propget svm:headrev //mirror/nhcontrib --revprop -r 10260
:=349
exec: svk propget svm:headrev //mirror/nhcontrib --revprop -r 10092
:=195
Found: 10092

By the way, can you find the huge perf boost here?

class Program
{
    static void Main(string[] args)
    {
        string path = args[0]; // "//mirror/nhcontrib"
        var revisionToSearchFor = int.Parse(args[1]); // 195
        string logAsXml = ExecuteProcessAndReturnOutput("log --xml "+ path);
        var doc = new XmlDocument();
        doc.LoadXml(logAsXml);
        var list = new ArrayList();
        foreach (var node in doc.SelectNodes("/log/logentry/@revision"))
        {
            list.Add(node);
        }
        for (int i = 0; i < list.Count;i++ )
        {
            XmlNode node = (XmlNode)list[i];
            int revision = int.Parse(node.Value);
            string output = ExecuteProcessAndReturnOutput("propget svm:headrev " + path + " --revprop -r " + revision);
            if (string.IsNullOrEmpty(output.Trim()) == false)
            {
                var currentRevision = int.Parse(output.Split(':')[1].Trim());
                Console.WriteLine(":=" + currentRevision);
                if (currentRevision == revisionToSearchFor)
                {
                    Console.WriteLine("Found: " + revision);
                    return;
                }
                i += (currentRevision - revisionToSearchFor -1);
            }
        }
    }

    public static string ExecuteProcessAndReturnOutput(string args)
    {
        var output = new StringBuilder();
        string err = null;
        var psi = new ProcessStartInfo
                      {
                          FileName = @"c:\Program Files\svk\svk.bat",
                          Arguments = args,
                          RedirectStandardOutput = true,
                          RedirectStandardError = true,
                          CreateNoWindow = true,
                          UseShellExecute = false
                      };
        Console.WriteLine("exec: svk "+ args);
        Process svk = Process.Start(psi);
        ThreadPool.QueueUserWorkItem(delegate
        {
            err = svk.StandardError.ReadToEnd();
        });
        ThreadPool.QueueUserWorkItem(delegate
        {
            string line;
            while ((line = svk.StandardOutput.ReadLine()) != null)
            {
                Debug.WriteLine(line);
                output.AppendLine(line);
            }
        });
        svk.WaitForExit();
        if (string.IsNullOrEmpty(err) == false)
            throw new InvalidOperationException(err);
        svk.WaitForExit();
        Thread.Sleep(500);
        return output.ToString();
    }
}
time to read 2 min | 202 words

Here is something that most people just don't think about, but it hits some people at the high end. Rhino Mocks is extremely efficient mocking framework, for just about any scenario. However, when it comes the time to mock large amount of interfaces (where large is in the hundreds to thousands), or if you have large interfaces (with dozens or hundreds of methods), it is costly to create the mocks. Rhino Mocks does some caching internally, but it is noticeable issue to some people.

We are talking about an extra second or two for even most pathological cases here, so in general it wouldn't warrant anything special from the library, except that there is a twist to that. Under the debugger, the amount of time spent actually generating the mock can go up by several orders of magnitudes. To add insult to injury, Visual Studio 2005 has several bugs in the debugger that will cause it to crush & burn under several such scenarios.

Karl Lew has been kind enough to not only provide a patch for Rhino Mocks to help this problem, but also document it.

Thanks, and sorry for taking so long to get to it.

time to read 2 min | 371 words

I was very impressed when I saw how Subversion handles the complexity of having data of hierarchical nature that needs to be serialized to XML. Check this out.

<?xml version="1.0" encoding="utf-8"?>
<S:editor-report xmlns:S="svn:">
  <S:target-revision rev="11"/>
  <S:open-root rev="-1"/>
  <S:open-directory name="tags" rev="-1"/>
  <S:add-directory name="tags/asd"/>
  <S:close-directory/>
  <S:close-directory/>
  <S:close-directory/>
</S:editor-report>

And here is another one:

<?xml version="1.0" encoding="utf-8"?>
<S:editor-report xmlns:S="svn:">
  <S:target-revision rev="15"/>
  <S:open-root rev="-1"/>
  <S:open-directory name="trunk" rev="-1"/>
  <S:open-file name="trunk/a.txt" rev="-1"/>
  <S:apply-textdelta checksum="eabc96676e7defda414a1eed33bdfb09">
    U1ZOAAAQEwETk2FzZDENCjINCjMNCjQNCjUNCjY=
  </S:apply-textdelta>
  <S:close-file checksum="c6301e5dad1330a7b9bd5491702c801b"/>
  <S:close-directory/>
  <S:close-directory/>
</S:editor-report>

I was, as they say incredibly happy with this Work Time Fun.

FUTURE POSTS

No future posts left, oh my!

RECENT SERIES

  1. API Design (10):
    29 Jan 2026 - Don't try to guess
  2. Recording (20):
    05 Dec 2025 - Build AI that understands your business
  3. Webinar (8):
    16 Sep 2025 - Building AI Agents in RavenDB
  4. RavenDB 7.1 (7):
    11 Jul 2025 - The Gen AI release
  5. Production postmorterm (2):
    11 Jun 2025 - The rookie server's untimely promotion
View all series

Syndication

Main feed ... ...
Comments feed   ... ...