Hi !
I'm facing a very innefficient piece of code while trying to play around
teh OpenLDAP ACl editor. Here is what I do, and what I see.
- I connect to an OpenLDAP remote server
- I pick a MDB database entry (but that could be any entry which contain
the olcAccess attributeType (every ObjectClass inheriting from
olcDatabaseConfig, ie, any backend).
- I open it, and get all the attributes and values in it
- assuming there is at least one olcAccess instance in this entry, then
the OpenLdapAclValueWithContext constructor is called 28 times !
The reason is that we are iterating across all the TreeViexer
selectionChangeListeners, and we have many (62... One per editor).
This starts in :
protected void fireSelectionChanged(final SelectionChangedEvent event) {
Object[] listeners = selectionChangedListeners.getListeners();
for (Object listener : listeners) {
final ISelectionChangedListener l =
(ISelectionChangedListener) listener;
SafeRunnable.run(new SafeRunnable() {
@Override
public void run() {
l.selectionChanged(event); ---> This get called as
many times as we have listeners
}
});
}
}
Each loop invokes the EntryEditorActionProxy.selectionChanged() method,
then the BrowserActionProxy.updateAction(), which calls
OpenEditorAction.isEnabled(), which calls the
EntryEditorWidgetCellModifier.canModify() method, which tries to figure
out what is the best editor for the selected value, and finally call the
getRawValue() of the class used to edit the value.
In my case, it ends up calling the ACL parser as many times we have
listeners (28 times), even if the listeners are totally unrelated.
Here is the stack trace :
Thread [main] (Suspended (breakpoint at line 143 in
OpenLdapAclValueEditor))
OpenLdapAclValueEditor.getRawValue(IValue) line: 143
EntryEditorWidgetCellModifier.canModify(Object, String) line: 79
OpenEditorAction.isEnabled() line: 128
EntryEditorActionProxy(BrowserActionProxy).updateAction() line: 248
EntryEditorActionProxy(BrowserActionProxy).selectionChanged(SelectionChangedEvent)
line: 237
Viewer$2.run() line: 163
SafeRunner.run(ISafeRunnable) line: 42
JFaceUtil$1.run(ISafeRunnable) line: 50
SafeRunnable.run(ISafeRunnable) line: 178
>>>>TreeViewer(Viewer).fireSelectionChanged(SelectionChangedEvent) line:
160<<<<---------------- Starting loop
TreeViewer(StructuredViewer).updateSelection(ISelection) line: 2171
TreeViewer(StructuredViewer).handleSelect(SelectionEvent) line: 1202
StructuredViewer$4.widgetSelected(SelectionEvent) line: 1231
OpenStrategy.fireSelectionEvent(SelectionEvent) line: 242
OpenStrategy.access$4(OpenStrategy, SelectionEvent) line: 236
OpenStrategy$1.handleEvent(Event) line: 408
EventTable.sendEvent(Event) line: 84
Display.sendEvent(EventTable, Event) line: 4199
Tree(Widget).sendEvent(Event) line: 1467
Tree(Widget).sendEvent(int, Event, boolean) line: 1490
Tree(Widget).sendEvent(int, Event) line: 1475
Tree(Widget).notifyListeners(int, Event) line: 1279
Display.runDeferredEvents() line: 4042
Display.applicationNextEventMatchingMask(long, long, long, long,
long, long) line: 4996
Display.applicationProc(long, long, long, long, long, long) line:
5378
OS.objc_msgSendSuper(objc_super, long, long) line: not available
[native method]
Tree(Widget).callSuper(long, long, long) line: 221
Tree(Widget).mouseDownSuper(long, long, long) line: 1101
Tree.mouseDownSuper(long, long, long) line: 2064
Tree(Widget).mouseDown(long, long, long) line: 1093
Tree(Control).mouseDown(long, long, long) line: 2563
Tree.mouseDown(long, long, long) line: 2032
Display.windowProc(long, long, long) line: 5638
OS.objc_msgSendSuper(objc_super, long, long) line: not available
[native method]
Shell(Widget).callSuper(long, long, long) line: 221
Shell(Widget).windowSendEvent(long, long, long) line: 2105
Shell.windowSendEvent(long, long, long) line: 2329
Display.windowProc(long, long, long) line: 5702
OS.objc_msgSendSuper(objc_super, long, long) line: not available
[native method]
Display.applicationSendEvent(long, long, long) line: 5139
Display.applicationProc(long, long, long) line: 5288
OS.objc_msgSend(long, long, long) line: not available [native
method]
NSApplication.sendEvent(NSEvent) line: 128
Display.readAndDispatch() line: 3666
PartRenderingEngine$9.run() line: 1151
Realm.runWithDefault(Realm, Runnable) line: 332
PartRenderingEngine.run(MApplicationElement, IEclipseContext) line:
1032
E4Workbench.createAndRunUI(MApplicationElement) line: 148
Workbench$5.run() line: 636
Realm.runWithDefault(Realm, Runnable) line: 332
Workbench.createAndRunWorkbench(Display, WorkbenchAdvisor) line: 579
PlatformUI.createAndRunWorkbench(Display, WorkbenchAdvisor) line:
150
Application.start(IApplicationContext) line: 51
EclipseAppHandle.run(Object) line: 196
EclipseAppLauncher.runApplication(Object) line: 134
EclipseAppLauncher.start(Object) line: 104
EclipseStarter.run(Object) line: 380
EclipseStarter.run(String[], Runnable) line: 235
NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) line: not
available [native method]
NativeMethodAccessorImpl.invoke(Object, Object[]) line: 62
DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 43
Method.invoke(Object, Object...) line: 497
Main.invokeFramework(String[], URL[]) line: 648
Main.basicRun(String[]) line: 603
Main.run(String[]) line: 1465
Main.main(String[]) line: 1438
The question would be : how can we avoid such thing to happen ?