Wichtig
Detail
Wichtig
Detail
Wenn die tl:KnowledgeBase ein tl:TLObject erstellt, zum Beispiel als Ergebnis einer Suche, muss sie die passende Implementierungsklasse für dessen tl:TLClass raussuchen.
Verbesserung
Die Zuordnung von Implementierungsklasse zu tl:TLClass soll gecacht werden. Dadurch muss nicht für jedes TLObjects erneut nach der Java Klasse gesucht werden.
Umsetzung
In tl:DynamicBinding wurde ein Cache eingebaut. Siehe: DynamicBinding._implementationClasses. Der Cache speichert die Zuordnung der tl:TLID eines tl:TLType zum Java Class Objekt der tl:TLObject Implementierung. Dadurch wird de-facto etwas mehr gespeichert, als nur die Auflösung des qualifizierten Klassennamens in das Class Objekt, was die Performance weiter verbessert. Andererseits macht es die Verallgemeinerung schwieriger. Aber es ist derzeit sowieso nicht konkret geplant, an weiteren Stellen die Klassenauflösung zu cachen.
Hintergrund
Im Rahmen von #26910 wurde ermittelt, dass es sich hier lohnt zu optimieren. Beim Senden eines Changeset von 300 000 Objekten war diese Stelle nach anderen Optimierungen für 2/3 der verbliebenen Laufzeit verantwortlich.
Beispiel Stacktrace
at com.top_logic.knowledge.wrap.binding.DynamicBinding.findImplClass(DynamicBinding.java:152) at com.top_logic.knowledge.wrap.binding.DynamicBinding.createBinding(DynamicBinding.java:133) at com.top_logic.knowledge.wrap.ImplementationFactory.createBinding(ImplementationFactory.java:53) at com.top_logic.knowledge.service.db2.KnowledgeItemImpl.createWrapper(KnowledgeItemImpl.java:46) at com.top_logic.knowledge.service.db2.WrappedKnowledgeItem.initWrapper(WrappedKnowledgeItem.java:28) at com.top_logic.knowledge.service.db2.DBKnowledgeItem.onLoad(DBKnowledgeItem.java:259) at com.top_logic.knowledge.service.db2.DBKnowledgeBase.createItem(DBKnowledgeBase.java:5158) at com.top_logic.knowledge.service.db2.DBKnowledgeBase.findOrCreateItem(DBKnowledgeBase.java:5122) at com.top_logic.knowledge.service.db2.DBKnowledgeBase.findOrCreateItem(DBKnowledgeBase.java:5090) at com.top_logic.knowledge.service.db2.MonomorphicSearch$FullObjectResult.findNext(MonomorphicSearch.java:321) at com.top_logic.basic.sql.ResultSetBasedIterator.findNext(ResultSetBasedIterator.java:44) at com.top_logic.basic.col.CloseableIteratorBase.hasNext(CloseableIteratorBase.java:31) at com.top_logic.basic.col.CloseableIteratorAdapter.hasNext(CloseableIteratorAdapter.java:29) at com.top_logic.knowledge.service.db2.DBKnowledgeBase.toList(DBKnowledgeBase.java:1926) at com.top_logic.knowledge.service.db2.DBKnowledgeBase.search(DBKnowledgeBase.java:1912) at com.top_logic.knowledge.service.BulkIdLoad.resolveIdentifiers(BulkIdLoad.java:186) at com.top_logic.knowledge.service.BulkIdLoad.loadUncachedInRevision(BulkIdLoad.java:126) at com.top_logic.kafka.knowledge.service.exporter.TypeFilterRewriter.resolveCallbacks(TypeFilterRewriter.java:161) at com.top_logic.kafka.knowledge.service.exporter.TypeFilterRewriter.rewrite(TypeFilterRewriter.java:149)
Test
TestClassCaching überprüft, ob ConcurrentHashMap.computeIfAbsent(...) schneller ist, als Class.forName(...). Aktuell ist das deutlich der Fall. Letzteres benötigt mehr als 10x so lange. (JDK 11, Linux)
Einschränkungen: Die Map hat nur einen Eintrag und es wird immer genau dieser Eintrag geholt. Allerdings ist die Performance von get(key) von Maps nicht sehr vom Füllstand der Map abhängig. Der allgemeine Overhead um einen Eintrag zu holen, sowie die Synchronisierung aufgrund von **`Concurrent`**`HashMap` sollte hier den Ausschlag geben. Zusätzlich cacht der tatsächliche Cache mehr als nur diese Zuordnung, und dürfte daher noch mehr Zeit sparen.