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 32 | aantal honderste seconden vanaf middennacht |
| Bytes 33 t/m 56 | aantal dagen vanaf 1-1-4713 v. Chr. |
| Bytes 57 t/m 60 | aantal hele uren verschil tussen GMT en huidige tijdzone |
| Bytes 61 t/m 62 | aantal kwartieren (bovenop de hele uren) verschil tussen GMT en huidige tijdzone |
| Byte 63 | geeft aan of tijdzone ten oosten van Greenwich is |
| Byte 64 | geeft aan of DayLightSaving observatie aanstaat |
voorbeeld van een datum/tijd-veld en de interpretatie daarvan
| Replica ID | 41256998 : 002D1658 |
| Geschreven naar decimaal | 1092970904 : 2954840 |
| Geschreven naar binair | 01000001001001010110100110011000 : 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 32 | 00000000001011010001011001011000 = 2954840 honderste seconden vanaf middennacht |
| Bytes 33 t/m 56 | 001001010110100110011000 = 2451864 dagen vanaf 1-1-4713 v. Chr. |
| Bytes 57 t/m/ 60 | 0001= 1 uur verschil |
| Bytes 61 t/m/ 62 | 00 = 0 kwartieren verschil |
| Bytes 63 | 1 = tijdzone bevindt zicht ten oosten van Greenwich |
| Byte 64 | 0 = 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.
- 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.
- 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.
- 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 |