Bob Balaban's Blog

     
    alt

    Bob Balaban

     

    Geek-o-terica 10: "Autoupdating" in views

    Bob Balaban  April 4 2010 09:51:51 AM
    Greetings, Geeks!

    I've seen some stuff flying about recently about whether one should, or should not, disable automatic updates when iterating through the documents in a view using LotusScript or Java back-end classes, and why. Some of the points made greatly surprised me with how wrong they were, so I thought I'd give you my take on the issue.

    Background
    At the level of the Notes C API (where everything that really matters really happens), what is a view? It's a data structure that represents a snapshot of the view's index. Of course, view indexes are changing all the time, some are more volatile than others, but (in the worst case) a view can be subject to change any time a single document is created or updated in the NSF. That doesn't necessarily mean that the view gets re-indexed every time that happens, but it does mean that a "view" living in an NSF on a server, as a data structure that is shared ("used") by potentially many clients at the same time, can change out from under you while you are using it.

    So, what about the NotesView object (View in Java)? It is essentially a wrapper for a view index data structure (called an HCOLLECTION for you C API geeks). Most people use this class primarily for navigation over documents: GetFirst/NextDocument, GetNext/PreviousSibling, etc etc. Virtually all of the navigation methods in the NotesView class translate down to a single C API entry point invocation, called NIFReadEntries (the "NIF" prefix is common to many API calls having to do with views, it stands for "Notes Indexing Facility"). The job of this complex call is to take the provided "starting point", or "position"  in the view (represented by the "current" document, for example), figure out how to navigate relative to that location (next, previous, first child, whatever), and find the document in the view's index corresponding to that new location, or position, given the view's current nesting, categorization, and so on.

    This potentially complex navigation is done based on the "snapshot" of the view index currently held by the "user" (LotusScript/Java program, Notes client, remote C API program...). Now, suppose that my Java program is navigating through the documents in a view, and while it's doing that, some other program, or user, modifies the view from another client? Perhaps a new document was created in the database, and that document matches my  view's selection formula. In fact, perhaps that document just happens to sort to the top of the view, so that all of the other documents in the view have a new "position". Perhaps my own program, inside the navigation loop, makes a change to a document that I see, and re-saves that document. If that change affects the value of a column in the view, and if that column is sorted or categorized, then my current document will actually "move" to a new position in the view.

    The problem is this: when the documents in the view change position while my program is between navigational events in the view, how do I define the "next" document? Is it the document that would-have-been-next before the view changed? Or is it the document that is actually-next given what might be a new location for my "current" document? It's a puzzle!

    One good thing about the NIFReadEntries call is that when invoke it to navigate elsewhere in the view, it tells you if the view has been modified since the last time you called it. It can detect when your current "snapshot" (HCOLLECTION) of the view gets out of sync with the "real" view index on the server. Note that there is NO WAY to prevent the view from being changed, if someone or something somewhere modifies the view contents, it just changes out from under you.

    However, the implementation of the NotesView/View class gives a choice about what to do about this situation, in the form of the "AutoUpdate" property. This property is On by default, here's the logic it follows, for example, in the GetNextDocument() call:
    1. Find the position of the "current" document (it's cached in the document object during navigation)
    2. Invoke NIFReadEntries with the current position and the various navigational options set to get the "next" document
    3. Read the NOTEID and position of the next document (if there is one) returned by the call
    4. Examine the "dirty" flag returned by NIFReadEntries to detect whether the view has changed since our last call to it
    5. If the view has changed, and if the view object "autoupdate" flag is set, then
    6. Update our HCOLLECTION against the view index (this might, or might not force a re-indexing operation on the view)
    7. Re-compute the position of the "current" document in the updated index (it might, or might not have moved)
    8. Call NIFReadEntries again to navigate

    If the "AutoUpdate" flag is off, then steps 6, 7, and 8 are skipped.

    This is a powerful feature, though frankly, I nearly always turn it off when navigating views. From a programmatic point of view, the danger of having it on is that you can easily either miss documents in a view, or visit the same document multiple times, if you're not careful.

    As this post is already pretty long, I'll do a Part Deux posting exploring the ins and outs of AutoUpdate soon.

    Geek ya later!

    (Need expert application development architecture/coding help? Contact me at: bbalaban, gmail.com)
    Follow me on Twitter @LooseleafLLC
    This article ┬ęCopyright 2010 by Looseleaf Software LLC, all rights reserved. You may link to this page, but may not copy without prior approval.