Skip to content
This repository has been archived by the owner on May 7, 2020. It is now read-only.

Maintaining ReadyMarkers in a dedicated service #4203

Merged
merged 1 commit into from
Sep 14, 2017

Conversation

sjsf
Copy link
Contributor

@sjsf sjsf commented Sep 6, 2017

...instead of using the SCR for it.

The reason behind this is that on at least one commercial OSGi server when running with activated security manager, registering services takes quite long (up to several hundreds of milliseconds per service). When running on limited hardware resources, this significantly impacts the startup times. Therefore it does not look like such a nice idea to register hundreds of services just as "Ready Markers".

As an improvement to this, I suggest to have a single service which holds these ready markers and other components can register as listeners.

This does not mean we shouldn't use services for the "startup level"solution (see #1896). However, it simply turned out that it is not necessarily a good idea to flood the SCR with "marker" services.

Signed-off-by: Simon Kaufmann simon.kfm@googlemail.com

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file was committed by accident, right? :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh yes, thanks!

@maggu2810
Copy link
Contributor

What is the reason to open the trackers async and create multiple schedulers that only use case is to schedule one Job on activation? Does the open of a tracker block the activation such long?

private final String type;

public ReadyMarkerFilter() {
this.type = null;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this(null, null);

this.identifier = identifier;
}

public String getType() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could mark that the return type is non null.

return type;
}

public String getIdentifier() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could mark that the return type is non null.

@Component
public class ReadyServiceImpl implements ReadyService {

private static final Logger logger = LoggerFactory.getLogger(ReadyServiceImpl.class);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't see the need to use a logger in a static context, so could we keep the logger instance non static?

public class ReadyServiceImpl implements ReadyService {

private static final Logger logger = LoggerFactory.getLogger(ReadyServiceImpl.class);
private static final ReadyMarkerFilter ANY = new ReadyMarkerFilter();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps we could make the ANY constructor (that uses null twice) private to and use a static function that returns an instance (no need for a singleton). Perhaps the meaning of ReadyMarkerFilter.any() is more intuitive then new ReadyMarkerFilter().

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If i make that private, there is no public constructor left. My intention was to keep the one with arguments private in order to prevent the constructor-mess we had at other places and rather have the builder-like pattern using with...()-Methods.

So do I understand you right that using ReadyMarkerFilter.any().withType("..."); is the usage you are suggesting?

Copy link
Contributor

@maggu2810 maggu2810 Sep 7, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No 😉

If I understand the current situation correctly you can create three different type of ready marker filters.

  • filter type, created by ReadyMarkerFilter.withType(String type)
  • filter identifier, created by ReadyMarkerFilter.withIdentifier(String type)
  • filter nothing (the any one), created by new ReadyMarkerFilter()

Correct me if I am wrong.

So, I just think about making all constructors private and use for the last one a factory method, too. All three functions should return immutable objects.

  • filter type, created by ReadyMarkerFilter.withType(String type)
  • filter identifier, created by ReadyMarkerFilter.withIdentifier(String type)
  • filter nothing (the any one), created by ReadyMarkerFilter.any()

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, that's the misunderstanding... the with...(...)-Methods are not static. Therefore you can create:

  • filter nothing, created by new ReadyMarkerFilter()
  • filter type, created by new ReadyMarkerFilter().withType(String type)
  • filter identifier, created by new ReadyMarkerFilter().withIdentifier(String identifier)
  • filter for both, created by new ReadyMarkerFilter().withType(String type).withIdentifier(String identifier)

The reasoning was to have a design is that it can be evolved/extended with further parameters without creating a mess with the string arguments in constructors. I'm really not sure it these two parameters will be the only ones needed in future.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the with...(...)-Methods are not static

It seems I have forgotten how to read...

@sjsf
Copy link
Contributor Author

sjsf commented Sep 7, 2017

Does the open of a tracker block the activation such long?

Yes, during tracker-opening, all matching bundles will be "added" to that tracker synchronously by the framework.
I couldn't believe it myself, but running it on this specific runtime with enabled security manager on a rather-not-so-powerful hardware took several seconds to scan all bundles.

@@ -41,18 +46,27 @@
private XmlDocumentBundleTracker<List<ConfigDescription>> configDescriptionTracker;

private ConfigI18nLocalizationService configI18nLocalizerService;
private ReadyService readyService;

private ScheduledExecutorService scheduler = ThreadPoolManager.getScheduledPool("xml-processing");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you define "xml-processing" somewhere as a constant and reuse it? Would make it easier to keep track of the created thread pools.

}
ScheduledFuture<?> future = scheduler.schedule(() -> {
processBundle(bundle);
ScheduledFuture<?> future = scheduler.schedule(new Runnable() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you use "submit"?

bindingInfoReader, this, READY_MARKER);
bindingInfoTracker.open();
bindingInfoReader, this, READY_MARKER, readyService);
trackerJob = scheduler.schedule(() -> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

submit?

thingTypeTracker.open();
READY_MARKER, readyService);

trackerJob = scheduler.schedule(() -> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

submit?

* @author Simon Kaufmann - initial contribution and API.
*
*/
@NonNullByDefault
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did we already agree on using that annotation?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No idea, I lost the overview...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Check this to get an overview again :-)

}

private void notifyTrackers(ReadyMarker readyMarker, Consumer<ReadyTracker> action) {
trackers.entrySet().stream().filter(entry -> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not a change request but a suggestion:

trackers.entrySet().stream().filter(entry -> entry.getValue().apply(readyMarker)).map(entry -> entry.getKey())
.forEach(action);

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or

trackers.entrySet().stream().filter(entry -> entry.getValue().apply(readyMarker)).map(Entry::getKey)
.forEach(action);

Copy link
Contributor Author

@sjsf sjsf Sep 11, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've been using the block-notation on purpose, to force the auto-formatter to insert line-breaks in places where the human brain can follow. I couldn't figure out how to make JDT do do something similar automatically. Do you by any chance have an idea?

Copy link
Contributor

@amitjoy amitjoy Sep 11, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah now I understand. What I usually do to achieve this is that I manually make changes to the stream notations and turn off autoformatter for certain section.

// @formatter:off
trackers.entrySet().stream()
                    .filter(entry -> entry.getValue().apply(readyMarker))
                    .map(Entry::getKey)
                    .forEach(action);
// @formatter:on

...instead of using the SCR for it.

Signed-off-by: Simon Kaufmann <simon.kfm@googlemail.com>
@kaikreuzer kaikreuzer merged commit 72523bc into eclipse-archived:master Sep 14, 2017
@kaikreuzer kaikreuzer added this to the 0.9.0 milestone Nov 30, 2017
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants