Mindoo Blog - Cutting edge technologies - About Java, Lotus Notes and iPhone

  • Fast Notes view reading via C API: A comparison C vs. Notes.jar

    Karsten Lehmann  31 March 2010 22:09:36
    Bad day for a blog posting - this is no April fool's joke. :-)

    About 1,5 weeks ago, Nathan Freeman wrote a blog posting about the hidden NAPI plugin in Lotus Notes 8.5.1 that IBM uses to speed up the XPages framework. NAPI is an unsupported and incomplete set of Java classes that use JNI technology (Java Native Interface) to leverage functions of the Notes C API, for example to read data from a Notes view.

    According to Nathan's speed race video, the NAPI classes are much faster than using the classic Notes Java API inside the Notes.jar archive. To read 15.000 view entries, NAPI takes 1 second where Notes.jar is running for 6 seconds - a pretty impressive result.

    Last week, inspired by his comparison, we decided to develop our own C/JNI code. Of course, we like nothing more than writing C and it was a question of honour not to use IBM's NAPI plugin. :-)

    No, just kidding. Our use case was a bit different. NAPI is an Eclipse plugin, but we needed a solution that also runs in standalone Java applications.

    A few days of fun with NIF'ty things like NIFOpenCollection, NIFGetCollectionData or NIFReadEntries later, we now have our own working solution.

    The result

    We took Nathans test database with 15.000 documents to measure the performance of the different solutions. Our test code is executed from the Eclipse IDE as a small standalone application, we did not build an Eclipse plugin for it yet.
    The view looks like this:

    Image:Fast Notes view reading via C API: A comparison C vs. Notes.jar

    Three columns with text, one hidden sort column with the severity as number.

    Traversing the view and reading all column values using Notes.jar takes 2.8 seconds on our desktop test machine (Intel Core2Duo, 3 GHz, 4 GB RAM. WinXP VM in Vista)
    Please note that our test code is running exclusively in the JVM. This may explain the gap to Nathan's 6 seconds, his four test cases run in parallel which probably slows down I/O throughput, causes synchronization losses in the API and splits the CPU power.

    Speed of our C/JNI solution

    For the same scenario, the C/JNI approach only takes 0.93 seconds. You can even save more time by reducing the columns to be read. In contrast to Notes.jar, where you just have ViewEntry.getColumnValues(), which decodes all columns in a row, by using the C API you have to decode each column separately (e.g. to convert Notes LMBCS strings to Java's Unicode format).
    For example, if you decide to only decode one column, let's say the last one, the duration drops to 0,8 seconds. If you are just interested in the sort order of documents, you might only read the Note ID and skip the column decoding, which results in 0,7 seconds.

    Drawbacks

    0,93 seconds instead of 2,8 sounds pretty dramatic, but we need to keep in mind that we are not reading 10 or 100 view entries, but 15.000. So for normal lookup operations, this solution is probably an overkill. Especially because in a hybrid scenario (where most operations are done in Notes.jar, but view reading in C/JNI) we need to create a second session and may open the database and view twice, which obviously consumes some time.

    However, it looks like there is a good use case for the JNI approach in scenarios where a lot of processes access Notes data in parallel, for example on a Domino web server or in the Lotus Notes Standard Client with a lot of plugins that use Notes APIs.

    In those cases, Notes.jar turns out to be a performance bottleneck, because it does not directly wrap the C API functions, but is based on the "Lotus Software Extension Backend (LSXBE)", which does not handle multithreading very well from a performance perspective.

    Image:Fast Notes view reading via C API: A comparison C vs. Notes.jar

    Click here to read the second article about C API vs. Notes.jar - how to speed up view reading by the factor 335.

    Comments

    1Nathan T. Freeman  01.04.2010 14:04:27  Fast Notes view reading via C API: A comparison C vs. Notes.jar

    To be fair, any JNI call is also bypassing the ECL checks. Though if ECLs alone cause a 3x running time for the most common kinds of application code, then we need a way to disable them completely anyway.

    I think the real problem when you get into multi-threading is that the LSXBE is simply never going to be able to handle context-switching as well as the Harmony JVM. We're talking about software designed 20 years ago by a small group of Iris engineers versus software designed 2 years ago by a cross-company Apache engineering team.

    I'll probably do a follow-up blog post soon with the later version of my performance test plugin. When you start multi-threading, the differences are more like an order of magnitude in running time, especially if you mix up ViewEntry walks with Document walks at the same time.

    2Bob Balfe  01.04.2010 14:48:53  Fast Notes view reading via C API: A comparison C vs. Notes.jar

    Sounds like this could be a good open source initiative!

    Great analysis Karsten.

    3Julian Buss  03.04.2010 16:27:46  Fast Notes view reading via C API: A comparison C vs. Notes.jar

    question is: is this approach usable in real world products? What if there is some problem? I assume there will be no support from IBM :-)

    4Karsten Lehmann  03.04.2010 17:58:52  Fast Notes view reading via C API: A comparison C vs. Notes.jar

    Well, the C API is a supported part of Lotus Notes, the NAPI plugin is probably not.

    It should be ok to write JNI extensions that talk to the C API, but of course you risk crashes and memory leaks if there are errors in the C code.

    This definitely requires a lot of experience in that area. We have developed a C++ framework to avoid crashes/leaks and to automate the memory management, but it's stil no fun to develop. I'm sure Tammo Riedinger, who did the coding, is happy that this task is done and he can return to Java. :-)