Bob Balaban's Blog

     
    alt

    Bob Balaban

     

    Geek-o-Terica 12: Finding databases by Replica ID vs. by path

    Bob Balaban  November 14 2010 12:43:55 AM
    Greetings, Geeks!  

    Everyone who writes application code (LotusScript or Java) in Notes/Domino uses Session.GetDatabase(, ), if not all the time, then at least frequently. I haven't done a "Geek-o-Terica" post in a while, so this seems like a good topic with which to revive the series.

    First of all, let me state that this article is NOT about whether you should use hard-coded database server/path names in your code, because you shouldn't, end of story. Why not? Because databases can (and do) move. An NSF that your app assumes is in a particular folder today might be somewhere else tomorrow (ah, those pesky admins, shuffing things around on the server again). It might even get moved to a different server. The last thing you want to do is modify your code when something moves, it can get ugly (and if you have real change processes in place, you'll have to re-test everything too).

    If you have code that refers to databases that are not the current one (i.e., not Session.CurrentDatabase), then the best practice is to use a Profile Document to store the outside database's server and path. That way, if it moves, you only have to update the Profile Document (via a form) with the new location.

    What I really wanted to talk about was the "best practice" (in quotes, because this is not necessarily a settled issue, as you'll see) for actually getting the outside database in your code. Most people don't really think about it much, they just provide the server name and the db path (hopefully from a Profile Document or other external source). But, there is another way it can be done, and in some cases, it's better. And that is, look up the database by it's Replica ID instead.

    First, how do you do that? The code pattern is easy, you just use the Database.OpenByReplicaID() function. Here's a sample from the Designer Help doc:

    Dim db As New NotesDatabase( "", "" )
    If db.OpenByReplicaID( "Moscow", "85255FA900747B84" ) Then
    Print( db.Title & " was successfully opened" )
    Else
    Print( "Unable to open database" )
    End If

    There are a couple of things about using this call that are inconvenient relative to just using Session.GetDatabase() or New Database():

         - You have to instantiate the db object first, then open it (more typing)

         - You have to get and store the replica ID (e.g., in a Profile document, also more typing), because of course you wouldn't hard-code a replica id any more than you'd hard-code a db path, right? Right?

    However, the big advantage of using the replica ID is that you don't have to know (or care) where on the server the database might be located. Given the replica ID, the server (or the Notes Client) figures out where the physical file is, and opens it for you. This doesn't eliminate the need for a Profile document in your app, as you still need to store the server name and the ID itself somewhere, but it does simplify things a bit. because if some pesky admin moves your database without telling you, you don't even have to update your Profile document. You can just laugh at them and say "Do your worst! I care not! Hahahaaa!" (actually you might not really want to say "do your worst", they might take it as a challenge...)

    There is, however, one drawback to using the replica ID technique that makes it unusable in some cases, and that has to do with failover.

    If your database is on an clustered server, you may well want to access it from your code in such a way that if the server you specify is down, you can automatically "fail over" to another server in the cluster, and get a replica of the database you specified. The way you normally do that is as follows:

    Dim db As New NotesDatabase( "", "" )
    If db.OpenWithFailover( "Moscow", "sales.nsf" ) Then
    Print( db.Title & " was successfully opened on server" & db.Server )
    Else
    Print( "Unable to open database" )
    End If

    This is nicely transparent, in that (if possible) you get a database object that references your db, whether it actually lives on the server you specified, or on another server in the cluster (the call works even if the server is not clustered). The Database.Server property reflects the server the database was actually opened on, and therefore might be different from the one you specified.

    You may have already spotted the problem with this: there's no way to open a database with failover by specifying its replica ID. This is a design flaw, going all the way back to Notes 4, simply never got plugged. Partly that's because of the way the Notes C API is set up (both the LotusScript and Java interfaces depend on the C API to do the real work), and partly it's just an oversight. Unfortunately, it means that if you want to use replica IDs to get a database in LS or Java code, you can't take advantage of failover behavior. And if you want failover, you can't get databases by replica ID.

    Happy coding! Geek ya later!

    (Need expert application development architecture/coding help?  Want me to help you invent directory services based on RDBMS?? 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.

    Comments

    1Brian Benson  11/15/2010 3:42:40 AM  Geek-o-Terica 12: Finding databases by Replica ID vs. by path

    Thanks for this Bob. I've always wondered how efficient OpenByReplicaID is vs using a path. Do you have any geek insight on that?

    2Giulio  11/15/2010 4:28:08 AM  Geek-o-Terica 12: Finding databases by Replica ID vs. by path

    Bob, I always learn something through your blog and enjoy reading it. I can see that you're presenting the replicaID vs file path option in all it's glory, but the pro's don't seem to outway the cons. And I managed to learn that there are even more cons from this post, than I previously realised.

    My 2 cents. Although you can use "OpenByReplicaID". I find it generally bad practice simply for the reason that a replica ID is meaningless to a developer. I as a developer always want to know where my database is.

    If the replica is actually corrupted, and you need to create a new copy. Using a file path makes this sort of potential problem irrelevant, and I can find my database easily. Yes I can use the catalog.nsf to find replica's but why should I refer to another database to find my data source ?

    I suppose it's a matter of taste, or appetite for risk, (ok.. ok..enough with the eating metaphors).. but I for one am not keen on the use of replica ID's as a means of specifying data sources via profiles.

    3Richard Schwartz  11/15/2010 2:07:09 PM  Geek-o-Terica 12: Finding databases by Replica ID vs. by path

    To me, the big downside to using openByReplicaID is that you are laying yourself open to the unpredictable results that occur if two replicas of the same database exist on the server. Sure, you can say that this should never happen... but someone will eventually break the rules and then everything goes haywire.

    And in all my years of Notes and Domino work, I have to say these cases have been the most agonizingly difficult to debug. The database opens fine, and many things work -- but then the code tries to open a document that you *know* is there, and it's not! Or it is there, but the values are all wrong. You open the database, and you see the document, and the readernames fields are all right, and the data values are what you expect... but you're not looking at the same database that your code is looking at! And the $64,000 question is: how long is it going to take you to realize what's going on?

    4Pierre Passin  11/16/2010 7:00:55 AM  Geek-o-Terica 12: Finding databases by Replica ID vs. by path

    I remember seeing a technote explaining that OpenByReplicaID will fail if the DB is locally encrypted.

    Also if something goes wrong with dbdirman.nsf OpenByReplicaID has some really funky behaviors.

    5Nick Wall  11/16/2010 2:08:57 PM  Geek-o-Terica 12: Finding databases by Replica ID vs. by path

    I used to use Replica ID, but it kept causing major problems with remote users and on clustered servers, as open with replica ID opens the top stacked icon on your workspace. A remote sales person in a hotel vpn-ing into network to replicate, leaves connection open in a "broadband Internet" mode (instant send of email etc), the application consists of a number of DBs (all of which have local replicas), but one of them has been switched so top stack is on the server..."Man this app is running really slow" or user has switched to offline, and if one of the DBs top stack is pointing to server replica, app will just hang. Clustered servers, if one server is taken offline for whatever reason, and if one of the top stack icons is "pointing" to other server...hang. I now never use replica ID, always path (...with fialover in clustered environment, and a config doc).

    6Bob Balaban  11/16/2010 10:04:08 PM  Geek-o-Terica 12: Finding databases by Replica ID vs. by path

    @1 - Performance of OpenByReplicaID will vary. If the server is caching NSF location info properly, finding the NSF is pretty quick. My understanding is that it uses dbdirman.nsf to do this.

    Performance on a client machine might be a little bit slower. It's not something I would worry about.

    @2 - Giulio, your points are valid. As I said, it's not a clear-cut "best practice" by any means.

    @3 - Yes, certainly that can happen, obviously it has happened to you. Personally, I'd like to see a tool (DCT? DDM?) that discovers such discrepancies, so they can be cleared up.

    @4 - Pierre, I'd be very interested in seeing that technote, do you have an ID for it?

    @5 - Nick, I don't understand your comment. So far as I know, OpenByReplicaID never goes to the workspace to check on stacked icons, or for any other reason. It's a back-end call, so it can be used safely on servers, where workspace context is not a factor.

    Also, the call takes an explicit server name as the first parameter, so I don't see how you could ever get the wrong server.

    As I recall how the code works (of course it might have changed since I last looked), OpenByReplicaID uses a C API call to translate the rep ID to a current path\name, then uses that to "open" the database.

    7Andrew Brew  12/15/2010 3:58:06 PM  Geek-o-Terica 12: Finding databases by Replica ID vs. by path

    What Rick said.

    The scenario that kept catching me out was that databases that needed to be restored (to recover an inadvertently deleted document, say) would be restored by the admins to a Domino server. Replication would be disabled, but lookups using replica IDs (which used to be standard practice here) would give unpredictable results until the restored copy was removed. Since there is usually no error (just a wrong result), it probably won't even be noticed for a while. Since neither the user nor the developer is necessarily aware that the restored instance was even created it can be quite difficult to analyse.

    8Robert  10/8/2014 9:15:11 AM  Geek-o-Terica 12: Finding databases by Replica ID vs. by path

    Hi,

    we are working with the ReplicID for over 2 years now and never had a problem with it.

    The function works on local encrypted files! But ai have to admin we do not work with clustered servers yet.

    But our code pattern proves that the db is open, or switches to another server.

    So we are fine with it.... for now.