Domino-nieuwsbrief e-office het Replica ID
      
welkom     nieuws 2008     nieuws 2007     nieuws 2006     nieuws 2005     Lotus Notes Domino     e-office

het Replica ID
Wat is een Replica ID?
Het Replica ID is de sleutel waarmee Lotus Domino Notes-databases van elkaar onderscheidt. Databases die hetzelfde Replica ID hebben, worden beschouwd als replica's van elkaar en kunnen repliceren.

Hoe wordt een Replica ID gegenereerd?
Elke database die in Notes wordt gemaakt, wordt voorzien van een Replica ID. Het is van groot belang dat Lotus Notes aan elke nieuwe Notes-database een uniek Replica ID toekent. Het Replica ID wordt daarom samengesteld op basis van de datum en tijd - tot op de hondertste seconde nauwkeurig - waarop de database wordt aangemaakt. In het Replica ID zit verder geen user- of servernaam versleuteld.

Wat is een Replica ID technisch gezien?
Een Replica ID ziet er in de UI uit als een string en wel in het formaat <8 karakters>:<8 karakters>. De dubbele punt is er puur voor het gemak, omdat u anders een lange reeks karakters ziet. Echter, in werkelijkheid is het Replica ID een ordinair datum/tijd-veld: een 8 bytes getal, of te wel 8 x 8 = 64 eenen en nullen achter elkaar.

Waarom komen er alleen de karakters A t/m F en getallen voor in het Replica ID?
Het is u mischien opgevallen dat alleen de karakters A t/m F en getallen voorkomen in het Replica ID. Dit komt omdat het Replica ID uit twee hexadecimale getallen bestaat. In ons numeriek stelsel is het grondgetal 10. Dat wil zeggen dat 20 2 maal 10 voorstelt. In het hexadecimale stelsel is 16 het grondgetal. Dat wil zeggen: 20 stelt 2 maal 16 voor (=32 decimaal). De karakters A t/m F stellen in het hexadecimale stelsel de getallen 10 t/m 15 voor. A0 is dus 10 maal 16 (=160 decimaal).
De eerder genoemde 64 eenen en nullen zijn genoteerd in het binaire stelsel. Door dit 64 lange binaire getal niet binair, niet decimaal maar hexadecimaal te tonen wordt het een stuk korter en kan het eenvoudiger worden gelezen of genoteerd door gebruikers.

Waarom bewaart Lotus Notes het Replica ID anders?
Op zich zou het Replica ID gewoon een string kunnen zijn. Dit is immers ook de vorm waarin de gebruikers het zien. Echter, door het als getal te bewaren wordt ruimte bespaard. In string-vorm neemt het 8+8=16 karakters in beslag. Een karakter is 1 byte en dus zouden er 16 bytes nodig zijn. In getal vorm is dat helft. Maar dit is niet de 'hele' reden, leest u nog even verder....

Wat is de overeenkomst tussen een Replica ID en de datum/tijd?
Zoals eerder aangegeven wordt het Replica ID gegenereerd op basis van de huidige datum/tijd. Een datum/tijd-veld in Notes bevat meer dan alleen de datum en tijd. Het bevat namelijk DayLightSavings- en TimeZone-informatie.

De 64 bytes die een datum/tijd-veld in beslag nemen, worden als volgt gebruikt :
Bytes 1 t/m 32aantal honderste seconden vanaf middennacht
Bytes 33 t/m 56aantal dagen vanaf 1-1-4713 v. Chr.
Bytes 57 t/m 60aantal hele uren verschil tussen GMT en huidige tijdzone
Bytes 61 t/m 62aantal kwartieren (bovenop de hele uren) verschil tussen GMT en huidige tijdzone
Byte 63geeft aan of tijdzone ten oosten van Greenwich is
Byte 64geeft aan of DayLightSaving observatie aanstaat

voorbeeld van een datum/tijd-veld en de interpretatie daarvan
Replica ID41256998 : 002D1658
Geschreven naar decimaal1092970904 : 2954840
Geschreven naar binair01000001001001010110100110011000 : 00000000001011010001011001011000

Door middel van de binaire representatie kan de datum/tijd worden geconstrureerd. Let op: de telling loopt van rechts naar links. Dit betekent dat byte 0 zich rechts bevindt en byte 64 helemaal links.

Bytes 1 t/m 3200000000001011010001011001011000 = 2954840 honderste seconden vanaf middennacht
Bytes 33 t/m 56001001010110100110011000 = 2451864 dagen vanaf 1-1-4713 v. Chr.
Bytes 57 t/m/ 600001= 1 uur verschil
Bytes 61 t/m/ 62 00 = 0 kwartieren verschil
Bytes 631 = tijdzone bevindt zicht ten oosten van Greenwich
Byte 640 = DayLightsaving wordt niet geobserveerd
Dit alles komt overeen met : 15 november 2000 8:12:28:40 CET
Kortom: de database met Replica ID 41256998:002D1658 is gemaakt op op 15 november 2000 7:12:28:40 in Centraal Europa.

Hoe kunt u het Replicatie ID van een database opvragen?
Dit gaat heel eenvoudig via de ReplicID property in de NotesDatabase class

Hoe kunt u het Replica ID aanpassen?
Het Relplica ID kunt u niet aanpassen met LotusScript, @-formulas of de Notes client. Echter, met behulp van C API functies kunt u dit wel aanpassen.
Gelukkig kunt u deze functies 'eenvoudig' aanroepen vanuit LotusScript.

Type DBREPLICAINFO
ID As Double '4 integers
Flags As Integer
CutoffInterval As Integer
Cutoff As Double '4 integers
End Type

Declare Function NSFDbClose Lib "nnotes.dll" (Byval HandleDatabase As Long) As Integer
Declare Function NSFDbOpen Lib "nnotes.dll" (Byval Pathname As String, HandleDatabase As Long) As Integer
Declare Sub OSCurrentTIMEDATE Lib "nnotes.dll" (retTimeDate As Double)
Declare Function NSFDbReplicaInfoSet Lib "nnotes.dll" ( Byval HandleDatabase As Long, replInfoStruct As DBREPLICAINFO ) As Integer
Declare Function NSFDbReplicaInfoGet Lib "nnotes.dll" ( Byval HandleDatabase As Long, replInfoStruct As DBREPLICAINFO ) As Integer

Dim hDb As Long
Dim hDbReplicaInfo As DBReplicaInfo
Dim result As Long
Dim sFileName As String

sFileName="Hier de complete padnaam invullen. Volgens mij moet servernaam!!padnaam ook werken"
result=NSFDbOpen(sFileName,hDb)
If result<>0 Then
'Handle error
End If

result=NSFDbReplicaInfoGet(hDb, hDbReplicaInfo)
If result<>0 Then
'Handle error
End If

Call OSCurrentTimeDate(hDbReplicaInfo.ID) 'In feite is een Replica ID niets anders dan een tijd variabele !

result=NSFDbReplicaInfoSet(hDb, hDbReplicaInfo)
If result<>0 Then
'Handle error
End If

Call NSFDbClose(hDb)

Hoe kunt u een datum/tijd-veld interpreteren als een Replica ID?
Theoretisch gezien kunt u volgens het voorgaande voorbeeld een datum/tijd terug herleiden naar een Replica ID. Echter, de NotesDateTime class in LotusScript geeft niet de honderste seconden weer zodat dit niet werkt. U kunt wel de @-formula @Text(<datum/tijd>;"*") gebruiken : @Text([11/15/00 7:12:28:40 GMT]:"*") bijvoorbeeld. Let op: dit werkt alleen in Forms en Views. In LotusScript zou u Evaluate kunnen gebruiken om de @-formula te gebruiken. Maar dit zal niet lukken omdat u nog steeds niet over de honderste seconden kunt beschikken om de juiste datum/tijd aan Evaluate te geven.

Hoe kunt u een Replica ID interpreteren als een datum/tijd-veld?
Ook hiervoor geldt dat dit theorisch mogelijk is. In de praktijk loopt u tegen het probleem aan dat u de property DST van het NotesDateTime object niet kunt beïnvloeden.

  1. Het eenvoudigste (en bullet proof) is om gebruik te maken van Catalog.nsf. De Catalog taak maakt voor elke database op de server een document aan. Het veld ReplicaID, dat een datum/tijd-veld is op zo'n document, kunt u dan gebruiken.
  2. Indien dit om wat voor reden niet kan, dan kunt u het ook berekenen. Gebruik daarvoor de bijgevoegde code in de agent 'ReplicaIDToNotesItem' in onderstaande database.
  3. Tenslotte kunt u gebruik maken van een agent die het niet via de LotusScript doet maar via API call's. Zie agent 'ReplicaIDToNotesItem2' in onderstaande database. Lees wel goed de opmerkingen bij de functie 'createNotesItemOnDocument'

Class replica ID
Class ReplicaID
Private ReplicaID As String
Private DayLightSavingsObserved As Integer
Private EastOfGMT As Integer
Private ZoneDifferenceHours As Integer
Private ZoneDifferenceQuarters As Integer
Private Days As Long 'since 1 januari 4713 BC
Private Hours As Long
Private Minutes As Long
Private Seconds As Long
Private HSeconds As Long
Private Initialised As Integer

Sub New( ReplicaID As String )
Me.ReplicaID = ReplicaID
Initialised = False
End Sub

Public Function setReplicaID( ReplicaID As String )
Me.ReplicaID = ReplicaID
Initialised = False
End Function

Public Function createNotesItemOnDocument( doc As NotesDocument, ItemName As String ) As String
'Creates a NotesItem reprensting the ReplicID on the supplied NotesDocument (doc) with the supplied name (ItemName)
'Caller must check the result. Result is "" if succesful or an error message if not
Dim sTime As String

If ( doc Is Nothing ) Or (ItemName = "" ) Then
createNotesItemOnDocument = "Illegal paramaters input"
Goto Done
End If

Call Initialise()

'Undocumented feature of the NotesDateTime class : you can specify the hunderths of seconds and time zone !!
sTime = Trim$(Str$( Hours)) + ":"+ Trim$(Str$( Minutes )) + ":" + Trim$(Str$( Seconds )) + ":" + Trim$(Str$( HSeconds )) + " GMT"
Dim ndt As New NotesDateTime("11/7/2000 "+sTime )
Call ndt.adjustday( Days-2451856) '2451856 days corresponds with 7 nov 2000

If ndt.IsDST <> DayLightSavingsObserved Then
'Unfort. we can not change the DST on a NotesDateTime.
'As workaround , you could change the location cod (clients) or server doc (server)
'but for now,.....bad luck !
createNotesItemOnDocument = "Cannot calculate item because DST differs between here and location created"
Goto Done
End If

Call doc.ReplaceItemValue( ItemName,ndt)

Done:
End Function

Private Function Initialise()

Dim HighLong As Long 'Innards(0) of TIMEDATE
Dim LowLong As Long 'Innards(1) of TIMEDATE

If Initialsed Then Goto Done

If ( ( Instr( ReplicaID,":") = 9 ) And ( Len(ReplicaID)=17 ) ) = False Then
ErrorMessage = "Invalid ReplicaID"
Goto Done
End If

HighLong = Clng("&H"+Right(ReplicaID,8)) 'Number of hundredths of seconds since midnight, Greenwich mean time 0=high
LowLong = Clng("&H"+Left(ReplicaID,8) )

s32 = getLongAsBinaryString( HighLong )
Print s32

hs = HighLong
Hours = Int( hs / 360000 )
hs = hs - Hours*360000
Minutes = Int( hs / 6000 )
hs = hs - Minutes * 6000
Seconds = Int( hs / 100 )
HSeconds = hs - Seconds * 100

s32 = getLongAsBinaryString( LowLong )
Print s32
Days = Clng( "&B"+Right$( s32,24) )
If Left$( s32,1)="1" Then DayLightSavingsObserved = True Else DayLightSavingsObserved = False
If Mid$( s32,2,1)="1" Then EastOfGMT= True Else EastOfGMT = False
ZoneDifferenceQuarters = Cint( "&B"+Mid$(s32,3,2) )
ZoneDifferenceHours = Cint( "&B"+Mid$(s32,5,4) )

Done:
Initialised = True

End Function

Private Function getLongAsBinaryString( n As Long ) As String
'Returns n as a 32 binary string

Dim s32 As String
Dim s As String

s32 = String$( 32, "0" )
s = Bin$(n)
s32 = Left$( s32,32-Len(s) ) + s

getLongAsBinaryString = s32

End Function

End Class