Optimierung Aspektorientierte Programmierung Folie: 1 Übersicht Optimierung 1.Bedeutung 2.Resource-Pooling im Allgemeinen 3.Database Connection Pooling 4.Thread-Pooling 5.Caching Christian Wettstaedt,
Optimierung Aspektorientierte Programmierung Folie: 2 1. Bedeutung Wozu Optimierung? Verbesserung der Effizienz eines Computerprogramms Aber:Optimierung im System ist meist nebensächlig und werden daher erst sehr spät umgesetzt Massive Eingriffe in Design und Implementation nötig viele betroffene Module -> “crosscutting concern” => Abhilfe durch AOP
Optimierung Aspektorientierte Programmierung Folie: 3 2. Allgemeines Resource Pooling Was ist “Resource Pooling”? - “to pool” = etwas zusammenlegen, konzentrieren die Möglichkeit zur Speicherung und Wiederver- wendung einer bestimmten Ressource bringt Performance, da das Bereitstellen bzw. Entsorgen einer Ressource sehr aufwendig sein kann Ressourcen: z.B. eine Datenbankverbindung - Auf- und Abbau der Verbindung kann mehr Zeit kosten als die eigentliche DB-Transaktion
Optimierung Aspektorientierte Programmierung Folie: 4 2. Allgemeines Resource Pooling Logik des “Resource Pooling” 2 Basis-Methoden zur Implementation des pools nötig: 1) Relevante Ressource aus dem pool beziehen 2) Eine Ressource in den pool geben
Optimierung Aspektorientierte Programmierung Folie: 5 Typische Umsetzung: public interface ResourcePool { public Resource getResource(ResourceDescription rd); public boolean putResource(Resource r); } 2. Allgemeines Resource Pooling gibt null zurück, falls Ressource nicht im pool ist gibt false zurück, falls Ressource nicht in den pool gegeben werden kann (z.B. wenn er voll ist)
Optimierung Aspektorientierte Programmierung Folie: 6 Typische Anwendung im Code: … Resource resource = resPool.getResource(rd); if (resource == null) { resource = resourceFactory.createResource(rd); }... // Benutzen der Ressource... if (resPool.putResource(resource) == false) { resource.dispose(); } 2. Allgemeines Resource Pooling
Optimierung Aspektorientierte Programmierung Folie: 7 2. Allgemeines Resource Pooling Ablaufslogik des Resource Pooling
Optimierung Aspektorientierte Programmierung Folie: 8 2. Allgemeines Resource Pooling Nachteile und Probleme des Resource Pooling: benötigt extra Speicherplatz (“space/time tradeoff”) Berücksichtigung bei der Entwicklung (“architects’s dilemma”) Früh: längere Entwicklungszeiten Spät: meist massiver Eingriff im System nötig Lösung: Design mittels Aspekten weiterer Vorteil: pooling kann auch komplett abgeschalten werden
Optimierung Aspektorientierte Programmierung Folie: 9 Design mittels Aspekten: 2 pointcuts nötig:Abfangen der join-points, an welchen eine Ressource bereitgestellt bzw. entsorgt wird public aspect ResourcePoolingAspect { private ResourcePool _rpool = new ResourcePoolImpl(); pointcut resourceCreation(ResourceDescription rd) : ; pointcut resourceDestruction(Resource r) : ; Resource around(ResourceDescription rd) : resourceCreation(rd) { Resource resource = _rpool.getResource(rd); if (resource == null) resource = proceed(rd); return resource; } void around(Resource r) : resourceDestruction(r) { if ( !_rpool.putResource(r)) proceed(r); } 2. Allgemeines Resource Pooling
Optimierung Aspektorientierte Programmierung Folie: Allgemeines Resource Pooling Logik des Resource Pooling mit Aspekten
Optimierung Aspektorientierte Programmierung Folie: Database-Connection Pooling Verbindung aufbauen (url, user, password) Verbindung schließen pool Verbindung im pool? ja nimm Verbindung aus pool url, user, password nein url, user, password Erzeuge neue Verbindung SELECT * FROM A WHERE B DB “database-connection-pooling” bereits im JDBC 2.0 enthalten Client Sichtbar Intern (JDBC bzw. Aspect) url, user, password gib aktuelle Verbindung in den pool
Optimierung Aspektorientierte Programmierung Folie: 12 Ein typisches DB-Connection-pool interface: import java.sql.*; public interface DBConnectionPool { public Connection getConnection(String url, String userName, String password) throws SQLException; public boolean putConnection(Connection connection); public void registerConnection(Connection connection, String url, String userName, String password); } 3. Database-Connection Pooling Registriert eine Verbindung nach ihrer Erzeugung →Konventioneller Weg: Anpassen jeder Methode zum Erzeugen bzw. Schließen einer Verbindung (siehe Folie 6) →AOP: Kapselung der Logik in einem Aspekt ohne vorhandenen Code zu verändern
Optimierung Aspektorientierte Programmierung Folie: Database-Connection Pooling Anforderungen an den Pooling Aspect Ressource Ressource-Pool Ressourcenbeschreibung java.sql.Connection Implementation des URL, UserName, Password DBConnectionPool interface Ressourcen-Erzeugung Ressourcen-Zerstörung pointcut: DriverManager.getConnection() pointcut: Connection.close()
Optimierung Aspektorientierte Programmierung Folie: Database-Connection Pooling import java.sql.*; public aspect DBConnectionPoolingAspect { DBConnectionPool _connPool = new SimpleDBConnectionPool(); pointcut connectionCreation(String url, String username, String password) : call(public static Connection DriverManager.getConnection(String, String, String)) && args(url, username, password); pointcut connectionRelease(Connection connection) : call(public void Connection.close()) && target(connection); Connection around(String url, String username, String password) throws SQLException : connectionCreation(url, userName, password) { Connection connection = _connPool.getConnection(url, username, password); if (connection == null) { connection = proceed(url, username, password); _connPool.registerConnection(connection, url, username, password); } return connection; } void around(Connection connection) : connectionRelease(connection) { if ( !_connPool.putConnection(connection)) { proceed(connection); }
Optimierung Aspektorientierte Programmierung Folie: 15 Was ist noch nötig? die Identifikation der Verbindung durch den pool Aber: Die Klasse Connection hat kein API zur Identifikation Abhilfe: Eine Klasse, die alle Eigenschaften einer Verbindung bündelt public class DBConnectionDescription { private String _url; private String _userName; private String _password; public DBConnectionDescription(String url, String userName, String password) { _url = url; _userName = userName; _password = password; } 3. Database-Connection Pooling
Optimierung Aspektorientierte Programmierung Folie: 16 Die Implementation des DBConnectionPool interface: import java.sql.*; import java.util.*; public class SimpleDBConnectionPool implements DBConnectionPool { List _pooledConnections = new ArrayList(); Map _connectionDescriptionMap = new HashMap(); synchronized public Connection getConnection(String url, String userName, String password) throws SQLException { DBConnectionDescription desc = new DBConnectionDescription(url, userName,password); List connectionsList = (List) _connectionDescriptionMap.get(desc); if (connectionsList == null) return null; for (int size = _pooledConnections.size(), i = 0; i < size; ++i) { Connection connection = (Connection) _pooledConnections.get(i); if (connectionsList.contains(connection)) { _pooledConnections.remove(connection); return connection; } return null; } 3. Database-Connection Pooling
Optimierung Aspektorientierte Programmierung Folie: Database-Connection Pooling synchronized public boolean putConnection(Connection connection) { _pooledConnections.add(connection); return true; } synchronized public void registerConnection(Connection connection, String url, String userName, String password) { DBConnectionDescription desc = new DBConnectionDescription(url, userName, password); List connectionsList = (List) _connectionDescriptionMap.get(desc); if (connectionsList == null) { connectionsList = new ArrayList(); _connectionDescriptionMap.put(desc, connectionsList); } connectionsList.add(connection); } Anmerkung: hier keine Größenbeschränkung des pools putConnection() liefert immer true zurück
Optimierung Aspektorientierte Programmierung Folie: 18 Überprüfen des poolings mittels einer Testklasse: import java.sql.*; public class Test { … static void printTable(String url, String table, String user, String password) throws SQLException { …// Aufbau, Nutzen und Schließen einer DB-Verbindung } printTable(“jdbc:odbc:Stock”, “price”, “user1”, “password1”); printTable(“jdbc:odbc:Stock”, “price”, “user2”, “password2”); printTable(“jdbc:odbc:Stock”, “price”, “user1”, “password1”); printTable(“jdbc:odbc:Stock”, “price”, “user2”, “password2”); } 3. Database-Connection Pooling simples Wiederholen der DB-Interaktionen zum testen des poolings Methode printtable(url, table, user, password): 1. Baut eine Verbindung auf (url, user, password) 2. Liest Daten per SQL (SELECT * FROM table) 3. Gibt die Daten aus und schließt die Verbindung
Optimierung Aspektorientierte Programmierung Folie: 19 Ein Aspect zum Aufzeichnen der Arbeitsweise: import java.sql.*; public aspect DBConnectionPoolLoggingAspect{ declare precedence *, DBConnectionPoolLoggingAspect; after(…) : call(Connection DriverManager.getConnection(…)) … { System.out.println(“For [“ + url + “,” + username + “,” + password + “]” + “/n/tCreated new : “ + connection); } after(…) : call(Connection DBConnectionPool.getConnection(…)) … {…} before(…) : call(* DBConnectionPool.putConnection(…)) … {…} before(…) : call(* Connection.close()) … {…} } 3. Database-Connection Pooling
Optimierung Aspektorientierte Programmierung Folie: Database-Connection Pooling For [jdbc:odbc:stock,user1,password1] Got from pool: null For [jdbc:odbc:stock,user1,password1] Created new : sunw 22 ibm 100 Putting in pool: For [jdbc:odbc:stock,user2,password2] Got from pool: null For [jdbc:odbc:stock,user2,password2] Created new : sunw 22 ibm 100 Putting in pool: For [jdbc:odbc:stock,user1,password1] Got from pool: sunw 22 ibm 100 Putting in pool: For [jdbc:odbc:stock,user2,password2] Got from pool: sunw 22 ibm 100 Putting in pool: Ausgabe: Datenbank Einträge
Optimierung Aspektorientierte Programmierung Folie: Database-Connection Pooling Mögliche Erweiterungen: Größe des pools beschränken Beschränkung der Zeit, die eine Verbindung aufbewahrt wird Pooling nicht für das ganze System, sondern nur für einzelne Clienten nutzbar machen
Optimierung Aspektorientierte Programmierung Folie: Thread Pooling Was ist ein Thread? Thread = dt. “Faden” -> ein “Ausführungsstrang” in der Informatik Eine nebenläufige Ausführungseinheit innerhalb eines Prozesses Mehrere Threads teilen sich dessen Betriebssystemmittel (Speicher, CPU-Zeit etc.) Zustände: Bereit Laufend Wartend Beendet
Optimierung Aspektorientierte Programmierung Folie: Thread Pooling Threads in Java: Erben von Klasse Thread oder implementieren das Interface Runnable start():ruft Thread auf und führt run() aus (Bereit->Laufend) run():Implementation der Thread-Aktion(Laufend) wait():versetzt Thread in Wartezustand(Laufend->Wartend) notify(): reaktiviert einen Thread(Wartend->Laufend) Der Thread ist beendet, wenn run() verlassen wird
Optimierung Aspektorientierte Programmierung Folie: 24 Anstatt einen Thread zu beenden -> Thread in einem pool aufbewahren Thread pooling interface: public interface ThreadPool{ public boolean putThread(Thread thread); public Thread getThread(); public boolean wakeupThread(Thread thread); } 4. Thread Pooling Gib Thread in pool und setze Ihn in Wartend-Modus Gib false zurück, wenn Thread nicht reaktiviert werden kann Hole Thread aus pool (gib Benutzrecht an den Aufrufer) ->Thread noch immer im Wartend-Modus
Optimierung Aspektorientierte Programmierung Folie: 25 Beispiel: simples Kommunizieren von mehreren clients mit einem server mittels eines Threads EchoServer 1.Erstellt ein server-socket (Schnittstelle) 2.Wartet auf eingehende Verbindungen 3.Erzeugt einen neuen Thread pro eingehender Verbindung Logik des Threads in einer extra Klasse (worker-class) (beinhaltet die run() Methode des Threads) 1.Initialisiert ein Eingabe-Stream an dem socket 2.Liest einen Text vom Eingabe-Stream (d.h. vom client) 3.Gibt den gelesenen Text an die Konsole aus > System.out.println(“Got request : “ + requestString); 4. Thread Pooling
Optimierung Aspektorientierte Programmierung Folie: 26 Aber: Der Thread soll für verschiedene Aufgaben einsetzbar sein! (d.h. er soll verschiedene worker-objects haben können) →die worker-class wird ausschließlich bei der Konstruktion des Thread aufgerufen Lösung: Eine extra Klasse zum Zuweisen eines worker-objects (d.h. dessen run() Methode) zu einem Thread public class DelegatingThread extends Thread { private Runnable _delegatee; public void setDelegatee(Runnable delegatee) { _delegatee = delegatee; } Public void run() { _delegatee.run() } 4. Thread Pooling
Optimierung Aspektorientierte Programmierung Folie: Thread Pooling DelegatingThread _delegatee _delegatee.run() workerObject1 run() workerObject2 run() Thread workerObject run() Code server-class: Runnable worker = new Echoworker(requestSocket); Thread serverThread = new Thread(worker); call pointcut serverThread Ein Thread, aber verschiedene run() Methoden möglich
Optimierung Aspektorientierte Programmierung Folie: Thread Pooling Anforderungen an den Pooling Aspect Ressource Ressource-Pool Ressourcenbeschreibung java.lang.Thread Implementation des unrelevant, da zwischen Threads ThreadPool interface nicht unterschieden wird Ressourcen-Erzeugung Ressourcen-Zerstörung pointcut: Thread.new() pointcut: Thread.run() beendet pointcut: Thread.start()
Optimierung Aspektorientierte Programmierung Folie: 29 ThreadPoolingAspect.java public aspect ThreadPoolingAspect { ThreadPool _pool = new SimpleThreadPool(); pointcut threadCreation(Runnable worker) : call(Thread.new(Runnable)) && args(worker); pointcut session(DelegatingThread thread) : execution(void DelegatingThread.run()) && this(thread); pointcut threadStart(DelegatingThread thread) : call(void Thread.start()) && target(thread); Thread around(Runnable worker) : threadCreation(worker) { DelegatingThread availableThread = (DelegatingThread) _pool.getThread(); if (availableThread == null) availableThread = new DelegatingThread(); availableThread.setDelegatee(worker); return availableThread; } void around(DelegatingThread thread) : session(thread) { while (true) { proceed(thread); _pool.putThread(thread); } void around(Thread thread) : threadStart(thread) { if (!_pool.wakeupThread(thread)) proceed(thread); } 4. Thread Pooling
Optimierung Aspektorientierte Programmierung Folie: 30 SimpleThreadPool.java public class SimpleThreadPool implements ThreadPool { List _waitingThreads = new ArrayList(); synchronized public boolean putThread(Thread thread) { _waitingThreads.add(thread); thread.wait(); return true; } synchronized public Thread getThread() { if (!_waitingThreads.isEmpty()) { Thread availableThread = (Thread) _waitingThreads.remove(0); return availableThread; } return null; } synchronized public boolean wakeupThread(Thread thread) { if (thread.isAlive()) { thread.notify(); return true; } return false; } 4. Thread Pooling
Optimierung Aspektorientierte Programmierung Folie: Thread Pooling Client pool WO Thread.new()Thread.Start()Thread.run() Thread im pool? ja Nimm Thread aus pool (Zustand: Wartend) nein Erzeuge neuen Thread (Zustand: Bereit) workerObject zuweisen Thread aus pool? ja nein Starte Thread.Start() Wecke Thread.notify() Abarbeitung der Thread Aktion.run() Anstatt zu beenden (run() wird verlassen) gib Thread in pool (Zustand: Wartend) Endlosschleife Sichtbar Intern.wait()
Optimierung Aspektorientierte Programmierung Folie: 32 server 4. Thread Pooling Test mittels eines Test-Clients (EchoClient.java) 1.Erstellt einen client-socket (TCP/IP Schnittstelle) 2.Initialisiert einen Ausgabe-Stream an dem socket 3.Liest Benutzereingaben und gibt diese weiter an den Ausgabe-Stream und somit zum server > java EchoClient host port > Deutschland > wird > Weltmeister > quit >got request: Deutschland >got request: wird >got request: Weltmeister >Ending the session port
Optimierung Aspektorientierte Programmierung Folie: Thread Pooling Aufzeichnen der Interaktionen mittels eines Aspects: public aspect ThreadPoolLoggingAspect{ after() returning(Thread thread) : execution(Thread ThreadPool.getThread(..)) { System.out.println(“Got from pool: “ + thread); } before(Thread thread) : execution(boolean ThreadPool.putThread(Thread)) … System.out.println(“Putting in pool: “ + thread + “\n”); } before(Thread thread) : execution(boolean ThreadPool.wakeupThread(Thread)) … System.out.println(“Waking up: “ + thread); }
Optimierung Aspektorientierte Programmierung Folie: Thread Pooling Aufruf des servers: java EchoServer Aufruf von 2 clients und Eingabe einiger Strings: java EchoClient localhost quit Ausgabe: Got from pool: null Waking up: Thread[Thread-1,5,main] Got request: First string Interaktion mit dem 1. Client Got request: Second string Ending the session Putting in pool: Thread[Thread-1,5,main] Got from pool: Thread[Thread-1,5,main] Waking up: Thread[Thread-1,5,main] Got request: Third string Interaktion mit dem 2. Client Got request: Fourth string Ending the session Putting in pool: Thread[Thread-1,5,main]
Optimierung Aspektorientierte Programmierung Folie: Caching Pooling: Ein exklusiver Benutzer einer Resource zu einem bestimmten Zeitpunkt Caching:Multiple Zugriffe auf eine Ressource erlaubt Beispiele: simples Datenbank-Caching XSLT caching (Extensible Stylesheet Language Transformation) →Sprache zum Umwandeln von XML Dokumenten in z.B. HTML, PDF etc. Hier: Performancezuwachs durch Wiederverwendung des Transformers
Optimierung Aspektorientierte Programmierung Folie: 36 simples Beispiel:Speichern von oft verwendeten DB-Einträgen in einem Cache Abfangen der join-points von query() und insert() der Klasse DBManager public aspect CacheManager { Map cache = new hashmap(); pointcut DBquery(String request) : call(Vector DBManager.query(String)) && args(request); Vector around(String request) : DBquery(request) { Vector result = cache.get(request); if (result == null) { result = proceed(request); cache.put(request,result); } return result; } 5. Caching
Optimierung Aspektorientierte Programmierung Folie: Caching prüfen, ob bei einem Schreibvorgang ein Cache-Eintrag ungültig wird pointcut DBinsert(String request) : call(Vector DBManager.insert(String)) && args(request); before(String request) : DBinsert(request) { if (cache.containsKey(request) == true) { cache.remove(request); } ist der Eintrag im Cache gespeichert, dann lösche diesen um Inkonsistenten zu vermeiden
Optimierung Aspektorientierte Programmierung Folie: 38 XSLT-Caching: import java.xml.transform.*; … public class Test { public static void main(String[] args) throws Exception { printTableRaw(“input1.xml”); printTablePretty(“input1.xml”); printTableRaw(“input2.xml”); printTablePretty(“input2.xml”); } private static void printTableRaw(String xmlFile) throws … { TransformerFactory tFactory = TransformerFactory.newInstance(); Transformer transformer = tFactory.newTransformer( new StreamSource(new File(“tableRaw.xsl”))); // Benutzen des Transformers } private static void printTablePretty(String xmlFile) throws … { TransformerFactory tFactory = TransformerFactory.newInstance(); Transformer transformer = tFactory.newTransformer( new StreamSource(new File(“tablePretty.xsl”))); // Benutzen des Transformers } 5. Caching Erstellt jeweils ein neues Transformer Objekt
Optimierung Aspektorientierte Programmierung Folie: 39 Logik des Caching hier: →Speichern und Wiederverwenden der Transformer für tableRaw.xsl und TablePretty.xsl import javax.xml.transform.*; public aspect TransformerCacheAspect { Map _cache = new Hashtable(); pointcut transformerCreation(Source source) : call( * TransformerFactory.newTransformer(..)) && args(source); Transformer around(Source source) throws TransformerConfigurationException : transformerCreation(source) { Transformer transformer = (Transformer) _cache.get(source.getSystemId()); if (transformer == null) { transformer = proceed(source); _cache.put(source.getSystemId(), transformer); } return transformer; } 5. Caching Das Argument des Transformers dient zur Identifikation im pool
Optimierung Aspektorientierte Programmierung Folie: Caching Aufzeichnen der Arbeitsweise mittels eines Aspects →Ausgabe: > ajc Test.java LogTransformerCreation.java TransformerCacheAspect.java > java Test Obtained transformer for: file:///F:/stylesheets/tableRaw.xsl Obtained transformer for: file:///F:/stylesheets/tablePretty.xsl Obtained transformer for: file:///F:/stylesheets/tableRaw.xsl Obtained transformer for: file:///F:/stylesheets/tablePretty.xsl Wiederverwendung der Transformer
Optimierung Aspektorientierte Programmierung Folie: Zusammenfassung Was wurde nicht beachtet? →Eine zwischengespeicherte Ressource wurde nie komplett gelöscht -> mögliches OutOfMemory Problem Aber: Pooling und Caching wurde durch AOP denkbar vereinfacht →Keine Systemweiten Codeänderungen nötig →Optimierung kann auch einfach ausgeschalten werden
Optimierung Aspektorientierte Programmierung Folie: 42 Literaturangaben Ramnivas Laddad: „AspectJ in Action“ (Manning), S. 203 – 242 Folie (simples DB Caching): Diplomarbeit Götz Bundschuh, TU Darmstadt (2002), S.52 – 55 Anmerkung: Die hier vorgestellten Code Beispiele wurden zu Demonstrations- zwecken stark vereinfacht und stellen ohne Änderung keine gute Implementation des Pooling bzw. Cachings dar.