Domino 9 und frühere Versionen > ND8: Entwicklung
Agentensterben, die zweite!
mleussner:
Moin, moin,
leider ist mein Problem mit Java und Serverabstürzen noch nicht endgültig ausgeräumt. Beim letzten Problem wurde mir sehr kompetent geholfen.
Jetzt stehe ich vor dem Dilemma, daß mein Agent die Dokumente in der DB gegen das LDAP prüfen soll. Also laufe ich über alle Dokumente (ca. 30.000) der DB und prüfe, ob im LDAP noch entsprechende Daten vorhanden sind.
Auf meinem lokalen Client läuft das auch prima. Auf dem Server gibt es einen Komplettabschuß. Der Server steht nach ca. 30s komplett und muß neu gestartet werden.
In einer Dumpdatei fand ich folgenden Output:
High number of handles (116) for private memory block 0x11b3
~~~~~~~~~~~~~~~~~~~~
Process amgr: Handle table is full:
Num Handles= 6399, Max Handles= 6399, Avail= 0
Num MemHandles= 128, Max MemHandles= 1048576, Avail=1048448
~~~~~~~~~~~~~~~~~~~~
Ich hänge mal den Code an, damit jeder sich ein Bild machen kann, was in meinem Agenten so abläuft.
Ich habe recycelt, was zu recyclen war. Glaube ich zumindest!
Aber ich lasse mich gerne vom Gegenteil überzeugen.
import lotus.domino.*;
import javax.naming.*;
import javax.naming.directory.*;
import java.io.IOException;
import java.util.Hashtable;
import javax.naming.ldap.*;
public class JavaAgent extends AgentBase {
//... diverse Variablen
static String sn = "";
static String employeeType = "";
public void searchAID(LdapContext ctx, Log log, Document activeDoc,
SearchControls ctls) {
try {
if (activeDoc.getItemValueString("AID").length() < 7) {
System.out.println("aid = leer in searchAID");
} else {
String filter = "(& (uid=" + activeDoc.getItemValueString("AID")+ ")(objectClass=ivvSIActiveUser))";
System.out.println("Suche: uid="
+ activeDoc.getItemValueString("AID"));
NamingEnumeration answer = ctx.search("", filter, ctls);
if (answer != null && answer.hasMore()) {
// do nothing
} else {
System.out.println("Doc mit AID in DIRX nicht vorhanden");
// Document markieren, wenn es gelöscht werden soll
activeDoc.appendItemValue("delete", "ja");
activeDoc.save(true, true);
}
answer.close();
// System.out.println("searchAID beendet");
}
} catch (NamingException es) {
System.out.println("NamingException aufgetreten in searchAID");
es.printStackTrace();
} catch (Exception e) {
System.out.println("Exception aufgetreten in searchAID");
e.printStackTrace();
}
}// Ende searchAID
public void searchVTRNR(LdapContext ctx, Log log, Document activeDoc,
SearchControls ctls) {
// wenn die VTRNR nicht gefunden wird, Doc löschen
try {
if (activeDoc.getItemValueString("NVTRNR").equals("")) {
System.out.println("vtrnr = leer in searchVTRNR");
} else {
String filter = "(& (ivvAgentFullNumber =" + activeDoc.getItemValueString("NVTRNR")+ ")(objectClass=ivvAgency))";
NamingEnumeration answer = ctx.search("", filter, ctls);
if (answer != null && answer.hasMore()) {
System.out.println("Doc mit VTRNR in DIRX gefunden");
// do nothing
} else {
System.out.println("Doc mit VTRNR in DIRX nicht vorhanden");
// Document markieren, wenn es gelöscht werden soll
activeDoc.replaceItemValue("delete", "ja");
activeDoc.save(true, true);
}
answer.close();
}
} catch (NotesException es) {
System.out.println("NotesException aufgetreten in searchAID");
es.printStackTrace();
} catch (Exception e) {
System.out.println("Exception aufgetreten in searchVTRNR");
e.printStackTrace();
}
}// Ende searchVTRNR
public void controldocs(Database db, Log log, LdapContext ctx,
SearchControls ctls) {
try {
View View = db.getView("ALLES");
System.out.println("View geholt");
View.refresh();
DocumentCollection coll = db.getAllDocuments();
Document activeDoc = coll.getFirstDocument();
System.out.println("View enthält "
+ View.getAllEntries().getCount() + " Docs");
System.out.println("First Doc geholt");
while (activeDoc != null) {
if (activeDoc.getItemValueString("AID").length() == 7) {
searchAID(ctx, log, activeDoc, ctls);
} else {
if (activeDoc.getItemValueString("NVTRNR").length() == 9) {
if (!activeDoc.getItemValue("NVTRNR").isEmpty()) {
searchVTRNR(ctx, log, activeDoc, ctls);
}
}
}
// activeDoc.recycle();
activeDoc = coll.getNextDocument();
}
System.out.println("DelView holen");
View DelView = db.getView("DelView");
DelView.refresh();
System.out.println("DelView refreshen");
ViewEntryCollection DelCol = DelView.getAllEntries();
System.out.println("DelView mit " + DelCol.getCount()
+ " Dokumenten leeren");
DelCol.removeAll(true);
System.out.println("DelView leeren");
System.out.println("controldocs Ende");
} catch (NotesException es) {
System.out.println("NotesException aufgetreten in controldocs");
es.printStackTrace();
} catch (Exception e) {
System.out.println("Exception aufgetreten in controldocs");
e.printStackTrace();
}
}// Ende controldocs
public static void deletedoc(Database db, Document doc) {
try {
// doc.removePermanently(true);
doc.replaceItemValue("delete", "ja");
doc.save(true, true);
} catch (Exception e) {
System.out.println("Exception aufgetreten in deletedoc");
e.printStackTrace();
}
}
public void NotesMain() {
Database db;
try {
Session session = getSession();
AgentContext agentContext = session.getAgentContext();
db = agentContext.getCurrentDatabase();
Log log = session.createLog("Neuer LDAP_Vertreterdatenabgleich #2");
// log.openNotesLog("N-H-DB01", "agentlog.nsf");
log.openNotesLog("", "agentlog.nsf");
log.logAction("Agent gestartet");
if (db.isFTIndexed()) {
System.out.println("db.isFTIndexed");
String ldapCF = "com.sun.jndi.ldap.LdapCtxFactory";
String ldapURL = "ldap://xyzserver:389/";
String ldapBaseDN = "o=verbund,c=DE";
String ldapUserID = "cn=xyz,cn=Notes,cn=Applications,o=ivv-verbund,c=DE";
String ldapPassword = "kennwort";
Hashtable env = new Hashtable(4);
env.put(Context.INITIAL_CONTEXT_FACTORY, ldapCF);
env.put(Context.PROVIDER_URL, ldapURL + ldapBaseDN);
env.put(Context.SECURITY_PRINCIPAL, ldapUserID);
env.put(Context.SECURITY_CREDENTIALS, ldapPassword);
String[] attrs = new String[19];
attrs[0] = "ivvAgentFullnumber";
...
...
attrs[16] = "sn";
attrs[17] = "uid";
attrs[18] = "givenName";
try {
long startTime = System.currentTimeMillis();
LdapContext ctx = new InitialLdapContext(env, null);
int pageSize = 500; // 1000 entries per page
byte[] cookie = null;
int total;
ctx
.setRequestControls(new Control[] { new PagedResultsControl(
pageSize, Control.NONCRITICAL) });
int a = 0;
int b = 0;
int c = 0;
// Alle Dokumente aus der DB überprüfen gegen das Dirx
long chkTimeStart = System.currentTimeMillis();
SearchControls ctls = new SearchControls();
ctls.setReturningAttributes(attrs);
ctls.setSearchScope(2);
System.out.print("controldocs gestartet");
controldocs(db, log, ctx, ctls);
ctx.close();
//...diverse Ausgaben auf die Konsole und in die LOG.NSF
log.close();
} catch (NamingException e) {
e.printStackTrace();
System.out.println("Fehler aufgetreten in NamingException");
} catch (IOException e) {
e.printStackTrace();
System.out.println("Fehler aufgetreten in IOException");
} catch (Throwable t) {
t.printStackTrace();
System.out.println("Fehler aufgetreten in NotesMain");
}
} else {
System.out
.println("Datenbank ist nicht Volltextindiziert --> TAS melden und einrichten lassen");
}
} catch (Throwable t) {
t.printStackTrace();
System.out.println("Fehler aufgetreten in NotesMain");
}
}
} // end of NotesMain
Ich hoffe auf eure Hilfe,
Martin
Ralf_M_Petter:
Äh sorry, aber soll das ein Scherz sein. In deinem Code kommt ein recycle vor und das ist auskommentiert?
Grüße
Ralf
mleussner:
Hallo Ralf,
das soll kein Scherz sein. Der Code ist ja nicht komplett. Es fehlt der komplette Teil, der die Dokumente anlegt.
Der funktioniert ja nach deiner Hilfe auch. Sowohl lokal als auch auf dem Server. Und da recycle ich ohne Ende.
Dieser zweite Teil ist das Problem. Wenn nichts recycled wird (was mir jetzt auch auffällt), dann war da meiner Meinung nach auch nichts zu recyclen.
Bis Freitag hatte ich noch die Methode getNextDocument(doc) benutzt. Das habe ich dann noch geändert.
Ohne Erfolg allerdings.
Ich weiß gar nicht mehr, warum die Zeile // activeDoc.recycle(); auskommentiert ist. Könnte das Erfolg haben?
Ich war eigentlich davon ausgegangen (meine Nicht-Notes-Java-Programmier-Kollegen auch), daß ich das activeDoc nicht recyclen muß, da es ja sofort wieder benutzt wird.
Sollte da mein Fehler liegen?
// activeDoc.recycle();
activeDoc = coll.getNextDocument();
Gruß,
Martin
Ralf_M_Petter:
--- Zitat von: mleussner am 23.11.09 - 09:39:47 ---
Ich war eigentlich davon ausgegangen (meine Nicht-Notes-Java-Programmier-Kollegen auch), daß ich das activeDoc nicht recyclen muß, da es ja sofort wieder benutzt wird.
Sollte da mein Fehler liegen?
--- Ende Zitat ---
Oje, ich sage es mal vorsichtig, aber ich würde nicht auf die Java Kenntnisse deines Kollegen vertrauen, da die Aussage mit es wird sofort wieder benutzt ein vollkommener Blödsinn ist.
Als erste musst du mal unterscheiden zwischen Variable und einem Objekt.
Eine Variable speichert nur eine Referenz auf ein Objekt im Java Heap.
Das heisst. Wenn du in deinem Code schreibst.
activeDoc=coll.getNextDocument();
testDoc=activeDoc;
Dann hast du jetzt nicht 2 Objekte sondern 2 Referenzen auf ein und das selbe Objekt.
Umgekehrt ist es natürlich auch so, dass wenn du schreibst.
activeDoc=coll.getNextDocument();
activeDoc=Coll.getNextDocument();
Dann hast du in deinem Java Heap 2 Objekte, wobei eines keine Referenz mehr hat. (Ausser es wird sonst noch irgendwo referenziert)
Wenn nun in deinem Java Heap ein Objekt ist, auf das keine Referenz mehr verweist, dann wird es vom Garbage Collector entsorgt. Das funktioniert mit nur Java Objekten auch ziemlich gut, aber nicht bei Java Objekten die auf native C++ Objekte verweisen. Die werden vom Garbage Collector nicht entsorgt, sondern müssen von dir selber mit recycle gekillt werden.
Das heisst, wenn dein Code dauernd neue DocObjekte erzeugt, dann gehen deinem Server irgendwann entweder der Hauptspeicher aus oder es gibt keine freien Handles mehr.
Richtig funktioniert der Code ca. so.
Document tempdoc=activeDoc; //Hier wird nur die Referenz auf das Objekt gesichert um sie später noch recyceln zu können.
activeDoc=coll.getNextDocument(activeDoc);
tempdoc.recycle();
Ich bin zuversichtlich, dass es dann funktioniert.
Noch eines zum Schluß. Bitte sei vorsichtig mit dem recycle von NotesObjekten die du nicht erzeugt hast. Du sollst z.B. nicht die Session eines Agents recyclen, da der Agentmanager sich selbst gerne darum kümmert.
Ich hoffe ich konnte es soweit erklären.
Grüße
Ralf
P.S. Der code enthält, aber auch noch andere Fehler, die aber nicht unbedingt zu Laufzeitfehlern führen müssen.
mleussner:
Super Ralf,
das klappt jetzt so, wie ich mir das vorgestellt habe.
Ich verstehe nur nicht, bei welchen Java Objekten native C++ Objekte verwendet werden, die ich entsorgen muß.
Ist das nicht ein Bug in der Umsetzung von Java zu C++??
Der Garbage-Collector könnte doch auch an seinen C-Unterbau weitergeben, daß da etwas nicht mehr benötigt wird.
Also erst einmal wieder vielen Dank für diese Info.
:D
Gruß,
Martin
PS: Wenn Du noch Lust hast auf die weiteren Fehler einzugehen, die anscheinend z.Zt. keine Auswirkungen haben, wäre ich dir dankbar.
Navigation
[0] Themen-Index
[#] Nächste Seite
Zur normalen Ansicht wechseln