Autor Thema: Agentensterben, die zweite!  (Gelesen 2582 mal)

Offline mleussner

  • Frischling
  • *
  • Beiträge: 26
  • Geschlecht: Männlich
  • Gegenseitige Hilfe macht selbst arme Leute reich.
Agentensterben, die zweite!
« am: 23.11.09 - 07:45:13 »
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
Ein gutes Gedächtnis ist nicht so gut wie ein bisschen Tinte.

SunOS 5.10 & Server 2003
Release 8.5.2FP2HF232
Notes Release 8.5.2FP2

Offline Ralf_M_Petter

  • Gold Platin u.s.w. member:)
  • *****
  • Beiträge: 1.879
  • Geschlecht: Männlich
  • Jeder ist seines eigenen Glückes Schmied
    • Ralf's Blog
Re: Agentensterben, die zweite!
« Antwort #1 am: 23.11.09 - 08:59:12 »
Äh sorry, aber soll das ein Scherz sein. In deinem Code kommt ein recycle vor und das ist auskommentiert?

Grüße

Ralf
Jede Menge Tipps und Tricks zu IT Themen findet Ihr auf meinem Blog  Everything about IT  Eine wahre Schatzkiste sind aber sicher die Beiträge zu meinem Lieblingsthema Tipps und Tricks zu IBM Notes/Domino Schaut doch einfach mal rein.

Offline mleussner

  • Frischling
  • *
  • Beiträge: 26
  • Geschlecht: Männlich
  • Gegenseitige Hilfe macht selbst arme Leute reich.
Re: Agentensterben, die zweite!
« Antwort #2 am: 23.11.09 - 09:39:47 »
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
Ein gutes Gedächtnis ist nicht so gut wie ein bisschen Tinte.

SunOS 5.10 & Server 2003
Release 8.5.2FP2HF232
Notes Release 8.5.2FP2

Offline Ralf_M_Petter

  • Gold Platin u.s.w. member:)
  • *****
  • Beiträge: 1.879
  • Geschlecht: Männlich
  • Jeder ist seines eigenen Glückes Schmied
    • Ralf's Blog
Re: Agentensterben, die zweite!
« Antwort #3 am: 23.11.09 - 10:00:53 »

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?


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.
« Letzte Änderung: 23.11.09 - 10:04:59 von Ralf_M_Petter »
Jede Menge Tipps und Tricks zu IT Themen findet Ihr auf meinem Blog  Everything about IT  Eine wahre Schatzkiste sind aber sicher die Beiträge zu meinem Lieblingsthema Tipps und Tricks zu IBM Notes/Domino Schaut doch einfach mal rein.

Offline mleussner

  • Frischling
  • *
  • Beiträge: 26
  • Geschlecht: Männlich
  • Gegenseitige Hilfe macht selbst arme Leute reich.
Re: Agentensterben, die zweite!
« Antwort #4 am: 23.11.09 - 14:08:05 »
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.
Ein gutes Gedächtnis ist nicht so gut wie ein bisschen Tinte.

SunOS 5.10 & Server 2003
Release 8.5.2FP2HF232
Notes Release 8.5.2FP2

Offline Ralf_M_Petter

  • Gold Platin u.s.w. member:)
  • *****
  • Beiträge: 1.879
  • Geschlecht: Männlich
  • Jeder ist seines eigenen Glückes Schmied
    • Ralf's Blog
Re: Agentensterben, die zweite!
« Antwort #5 am: 23.11.09 - 14:25:15 »
Alle Notes Objekte haben einen C++ Unterbau der wiederum auf einen C Unterbau aufbaut. Die Problematik ist, dass deine JVM von diesem Unterbau gar nichts weiß.

Bei Recycle gelten folgende Regeln:

Übergeordnete Objekte recyceln untergeordnete automatisch wenn Sie recycelt werden.

z.B. wenn du ein Database Objekt hast und z.B. mehrere View Objekte, dann werden beim recyceln der Database automatisch  die View Objekte mitrecycelt. Wenn man die Session recycelt, werden alle NotesObjekte die aus dieser Session erstellt wurden mitrecycelt.

Deshalb sollte man in Java Programmen zum Schluß auf jeden Fall die Session recyceln.

Aber in Agents bekommt man die Session vom Agentmanager, deshalb darf man die Session auf keinen Fall recyceln. Meiner Meinung nach ist in Agents die Best Practice nur NotesObekte zu recyceln, die in Schleifen verwendet weren. wie z.B. den Doc Objekt. Alle anderen würde ich nicht recyceln und dem Agent Manager überlassen.

Grüße

Ralf

Jede Menge Tipps und Tricks zu IT Themen findet Ihr auf meinem Blog  Everything about IT  Eine wahre Schatzkiste sind aber sicher die Beiträge zu meinem Lieblingsthema Tipps und Tricks zu IBM Notes/Domino Schaut doch einfach mal rein.

Offline flaite

  • Gold Platin u.s.w. member:)
  • *****
  • Beiträge: 2.966
    • mein del.icio.us
Re: Agentensterben, die zweite!
« Antwort #6 am: 23.11.09 - 16:31:05 »
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++??
Falsche Richtung. Da wird nix irgendwo "umgesetzt". Das läuft über JNI. JNI bindet C-Referenzen in Java Objekten. Der Garbage Collector muß schon aus Performance-Gründen grundsätzlich so konstruiert sein, dass er nicht viel über die C-Referenzen weiss. Das ist in der SWT Bibliothek von Eclipse auch nicht anders. Da werden auch native Systemressourcen des OS per JNI eingebunden und da muß auch der Anwendungsentwickler die Objekte entsorgen.

Von einem Bug kann man nicht reden. Es ist durch die Architektur von Garbage Kollektoren bedingt. Garbage-Kollektoren mit Wissen über in JNI eingebundene Objekte wären deutlich langsamer.

Zitat
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.

Da braucht man übrigens kein Java Programmierer zu sein.
Auch in LotusScript oder JavaScript sind die Referenz eines Objekts und das Objekt selbst 2 unterschiedliche Dinge.
Und letztlich entspricht es auch der Logik in der physischen Welt.
Ich schreibe mit Bleistift das Wort Köln.
Wenn ich das mit einem Radiergummi entferne, ist dann die mit dem Geschriebenen referenzierte Stadt ausradiert  ???
 
« Letzte Änderung: 23.11.09 - 16:40:58 von Pitiyankee »
Ich stimm nicht mit allen überein, aber mit vielen und sowieso unterhaltsam -> https://www.youtube.com/channel/UCr9qCdqXLm2SU0BIs6d_68Q

---

Aquí no se respeta ni la ley de la selva.
(Hier respektiert man nicht einmal das Gesetz des Dschungels)

Nicanor Parra, San Fabian, Región del Bio Bio, República de Chile

 

Impressum Atnotes.de  -  Powered by Syslords Solutions  -  Datenschutz