Daten-GAU: Wo kommen die alten Dokumente wieder her? ProblemWie aus heiterem Himmel meldet sich ein Benutzer und beschwert sich, dass in Applikation XYZ plötzlich wieder uralte Dokumente aufgetaucht sind, die schon vor langer Zeit gelöscht wurden.
Die Ursache – Teil 1 : Deletion StubsWird ein Dokument in einer Notes-Applikation gelöscht, bleibt es als sog. Deletion Stub erhalten, der nur noch einige Systeminformationen (z.B. UNID) des gelöschten Dokumentes enthält.
<Bild1>
Mit NotesPeek kann man sich die Deletion Stubs einer Datenbank anschauen.
NotesPeek: X-ray vision into Notes databases (developerWorks Artikel) NotesPeek 1.53 BETA for ND6 (Lotus Sandbox)Die Deletion Stubs sind sehr klein, müssen aber trotzdem irgendwann aus der Datenbank entfernt werden. Dies übernimmt i.d.R. der Updall-Task über Nacht mit einem Purge.
Wichtig für den Purge ist in den Replizierparametern hinterlegte Purge Intervall (siehe Abbildung).
<Bild2>
Für das Verständnis ist es wichtig zu wissen, wie Notes mit dem hier eingestellten Intervall umgeht.
Der Purge läuft dabei in einem gesonderten Intervall über die Deletion Stubs. Dieses berechnet sich wie folgt:
Purge Intervall = Anzahl Tage / 3
Bei einem solchen Purge-Lauf werden allerdings nur die Deletion Stubs entfernt, die älter als die eingestellten x Tage sind.
Im abgebildeten Beispiel hieße das, alle 30 Tage würden in der Datenbank die Deletion Stubs entfernt, die älter als 90 Tage sind. Das bedeutet, dass Löschungen zwischen 90 und 120 Tage in der Datenbank mitgeführt werden.
Siehe dazu auch die folgende Technote :
Purging documents in Lotus NotesDie Ursache – Teil 2 : ReplikationDie Deletion Stubs werden mitrepliziert. Solange ein Deletion Stub in der Applikation existiert weiß Domino, dass das zugehörige Dokument (UNID) gelöscht wurde und entfernt dieses bei einer Replikation aus anderen Repliken (bzw. ersetzt es gegen den Deletion Stub).
Das Problem tritt nun auf, wenn ein Benutzer oder Server seit längerer Zeit nicht repliziert hat, so dass die eigentlich gelöschten Dokumente noch in seiner Replik existieren, die zugehörigen Deletion Stubs aber schon durch den Purge entfernt worden sind.
In so einer Situation sieht Notes die eigentlich schon gelöschten Dokumente als neue Dokumente an, da die UNID in der Datenbank weder als Dokument noch als Deletion Stub existiert. Durch die Replikation gelangen dann diese Dokumente wieder in die Datenbank.
Dieses Verhalten ist auch in einer Technote beschrieben:
Deleted documents are reappearing after replicationWie lässt sich das Problem identifizieren? In der Regel sind Meldungen von Anwendern wenig technisch und beschränken sich auf die Aussage, dass plötzlich wieder alte Dokumente in der Applikation aufgetaucht sind.
Bei ausreichend großer Datenmenge erkennt man vermutlich relativ schnell, welche Dokumente eigentlich in der Datenbank nichts zu suchen haben. Andernfalls ist man auf die Mithilfe der Anwender angewiesen und muss sich Beispiele nennen lassen.
Hat man eine Handvoll solcher „Geister“ erkannt, lässt sich relativ einfach an den Dokumenteigenschaften prüfen, ob es sich mit hoher Wahrscheinlichkeit um ein durch Deletion Stubs verursachtes Problem handelt.
<Bild3>
Auffällig ist in diesem Fall, dass die beiden markierten Daten identisch sind und von den anderen beiden Daten abweichen. Würde es sich z.B. um per Copy&Paste eingefügte Dokumente handeln, wären mindestens die beiden Erstellt- und Hinzugefügt-Daten identisch. Hierüber hat man dann schon einmal einen Anhaltspunkt, wann das Problem „verursacht“ wurde.
Wenn man Glück hat und das Problem noch nicht allzu alt ist, kann man nun in den Server-Logs und in der Benutzeraktivität der Datenbank noch nach Bestätigung suchen. Dadurch hat man dann ggf. auch den Verursacher des Problems identifiziert und kann für die Zukunft Gegenmaßnahmen einleiten.
<Bild4>
Man sollte in so einem Fall nicht unbedingt direkt zu „erzieherischen Maßnahmen“ greifen, sondern den Benutzer auf den Sachverhalt ansprechen. Die Erfahrung zeigt, dass die Problematik dem Benutzer selber nicht bekannt ist.
Was kann man tun, um die Daten zu bereinigen?Eine Datensicherung hilft an der Stelle meistens auch nicht weiter, weil man dann entweder in der Zwischenzeit aufgetretene Änderungen verwerfen würde oder vor dem Problem stünde, eben diese in die zurückgesicherte Version zu übertragen.
Die ersten logischen Ansätze, wie z.B. eine spezielle Ansicht für die „Geister“ zu erstellen, scheitern leider daran, dass es weder über einfache Funktionen, Formelsprache oder LotusScript möglich ist, die „In dieser Datei“-Daten abzufragen.
Glücklicherweise bietet die Notes-API eine Funktion, mit der sich diese Dokumenteigenschaften ermitteln lassen.
Declare Sub W32NSFNoteGetInfo Lib "nnotes" Alias "NSFNoteGetInfo" ( _
Byval hNote As Long , _
Byval member As Integer , _
td As TIMEDATE)
hNote übergibt der Funktionen einen Handle auf das zu untersuchende Notes-Dokument.
member enthält eine Konstante für die zu ermittelnde Dokumenteigenschaft. Für das Datum „Hinzugefügt (In dieser Datei)“ ist dies der Wert 13.
Eine vollständige Beschreibung der API-Funktion gibt es bei OpenNTF.org:
Get the date/time a note was added (i.e., by replication) to its parent database . . . Reichert man diese Funktion noch etwas an und verpackt sie in einen Agent, kann man sich die Arbeit erleichtern. Der folgende Script-Code ergibt einen Agent, der über alle markierten Dokumente in einer Ansicht läuft und aus dem Menü heraus aufgerufen werden kann.
Für jedes Dokument wird das relevante Datum ermittelt und mit einem im Beispiel fest verdrahtetem Datum verglichen.
Sind die beiden Daten identisch, wird das Dokument für die spätere Bearbeitung in einen Ordner gestellt.
Hinweis: Der Agent nimmt einem nicht die Prüfung der Dokumente ab. Hierüber ist es lediglich möglich, eine Vorauswahl der zu prüfenden Dokumente zu erzeugen. Gerade bei großen Datenbanken kann man sich so wesentlich schneller durch die „Geister“ arbeiten.
DeclarationsType TIMEDATE
Innards(1) As Long
End Type
Declare Function W32ConvertTIMEDATEToText Lib "nnotes" Alias "ConvertTIMEDATEToText" ( _
Byval IntlFormat As Long , _
Byval TextFormat As Long , _
InputTime As TIMEDATE , _
Byval retTextBuffer As Lmbcs String , _
Byval TextBufferLength As Integer , _
retTextLength As Integer) As Integer
Declare Sub W32NSFNoteGetInfo Lib "nnotes" Alias "NSFNoteGetInfo" ( _
Byval hNote As Long , _
Byval member As Integer , _
td As TIMEDATE)
Const NOTE_ADDED_TO_FILE = 13
Const MAXALPHATIMEDATE = 80
Const NOERROR = 0
InitializeSub Initialize
Dim session As New NotesSession
Dim db As NotesDatabase
Dim coll As NotesDocumentCollection
Dim doc As NotesDocument
Dim td As TIMEDATE
Dim tdStr As String
Dim cbStr As Integer , bSigned As Integer
' --- der Agent darf nur Win32 Platformen durchgeführt werden
If session.Platform <> "Windows/32" Then
Msgbox "Dieser Agent kann nur auf Win32 Platformen ausgeführt werden." , 48 , "Platform wird nicht unterstützt"
Else
Set db = session.CurrentDatabase
Set coll = db.UnprocessedDocuments
If coll.Count > 0 Then
Set doc = coll.GetFirstDocument
While Not doc Is Nothing
' --- Sicherstellen, daß die Note initialisiert werden kann
bSigned = doc.IsSigned
W32NSFNoteGetInfo doc.Handle , NOTE_ADDED_TO_FILE , td
' --- Umwandlung des Datum/Zeit-Wertes in einen String für den späteren Vergleich
tdStr = String$( MAXALPHATIMEDATE + 1 , 0 )
If W32ConvertTIMEDATEToText( 0& , 0& , td , tdStr , MAXALPHATIMEDATE , cbStr ) <> NOERROR Then
Msgbox "Call to ConvertTIMEDATEToText failed.", 48 , "API Call Failure"
Else
'Msgbox "Added to File Date: " + Left$( tdStr , cbStr ) , 0 , "API Call Success"
‘--- Vergleich des ermittelten Datums gegen das kritische Datum
If Left$( tdStr , 10 ) = "02.10.2009" Then
Call doc.PutInFolder("TEMPCreated",True)
End If
End If
Set doc = coll.GetNextDocument( doc )
Wend
Close
End If
End If
End Sub
Der Ordner wird hier erstellt, wenn er nicht existiert. Sinnvoll ist es, den Ordner vorab selber zu erzeugen und in einer Spalte das Erstelldatum des Dokumentes (@Created) anzeigen zu lassen.
Da der Agent nur eine Prüfung des Datums macht, können auch Dokumente in den Ordner gelangen, die nicht durch eine solche Replikation als „Geist“ wieder in die Datenbank gelangt sind.
Man sollte daher die Dokumente in dem so gefüllten Ordner nicht einfach ungeprüft löschen. Dokumente, die jünger sind als das Purge Intervall, sind z.B. i.d.R. keine „Geister“.
Was kann man vorbeugend unternehmen?Leider nicht viel.
Das Intervall in den Datenbanken hochzusetzen, um das Problem auf diesem Weg zu verringern, sorgt für ein Wachstum der Deletion Stubs in den Datenbanken. Gerade bei Datenbanken mit sehr vielen Dokumenten und hohem Löschaufkommen sollte man sich das gut überlegen.
Die Benutzer auf Leserrechte einzuschränken, dürfte in den wenigsten Fällen funktionieren. Damit ließe sich ansonsten verhindern, dass Benutzer durch Replikation alte Dokumente zurückspielen könnten.
Auf jeden Fall ist sicherzustellen, dass zumindest die Server untereinander regelmäßig replizieren. Auf gar keinen Fall sollte man längere Zeit brachliegende Clients mit einem Server replizieren lassen, soweit das in der Macht des Administrators steht.
Links NotesPeek: X-ray vision into Notes databases (developerWorks Artikel) NotesPeek 1.53 BETA for ND6 (Lotus Sandbox) Purging documents in Lotus Notes (Technote) Deleted documents are reappearing after replication (Technote) Get the date/time a note was added (i.e., by replication) to its parent database . . .(OpenNTF.Org CodeBin)Lotus C API Toolkit for Lotus Notes and Domino documentation