[Search] OSGi split packages
by Hardy Ferentschik
Hi there,
As part of my work for making Search OSGi ready [1], I am looking into addressing HSEARCH-1560 [2] which is about
split packages which we have between some of our Search bundles (or modules to use Maven lingo).
Basically a split package "is caused where two or more bundles export the same package name and version, usually with different contents”. [3]
In terms of OSGi, split packages are bad and should be avoided. There exists a work around [3], but afaiu it is frowned upon.
While working on an integration test trying to run Search in Apache Karaf, I was running into this problem and basically needed (for the time being)
revert to the mentioned work around.
The biggest for getting rid of split packages is org.hibernate.search which is a split packages between the engine and orm bundle. In org.hibernate.search of engine
we have:
- Environment,
- FullTextFilter,
- ProjectionConstants,
- SearchException,
- SearchFactory
- Version.
org.hibernate.search of orm contains:
- FullTextQuery,
- FullTextSession,
- FullTextSharedSessionBuilder,
- MassIndexer
- Search.
As you can see, these are quite central classes and moving any of them around will break existing code (even though updating just requires
to change import statements). If we are serious with OSGi we should address this. We always said, that Search 5 is the release where we can break
API backwards compatibility. So if we want to do this, we should do it now. On the other hand, it is a big change.
I went ahead and tried to refactor org.hibernate.search in engine, applying the following changes:
org.hibernate.search.Environment -> org.hibernate.search.cfg.Environment
org.hibernate.search.SearchFactory -> org.hibernate.search.spi.SearchFactory
org.hibernate.search.SearchException -> org.hibernate.search.exception.SearchException
org.hibernate.search.FullTextFilter -> org.hibernate.search.filter.FullTextFilter
org.hibernate.search.Version -> org.hibernate.search.engine.Version
Some of these changes I actually find quite fitting independently of the split package problem. FullTextFilter seems to have found its true home now
and Version and Environment don’t seem too bad either. The big change is SearchFactory and .SearchException.
WDYT? Is this package refactoring something worth doing and if so what do you think about the new locations of the classes? Any better suggestions?
Or do you think the orm bundle should be refactored instead?
You can see the preliminary result here [4].
—Hardy
[1] https://hibernate.atlassian.net/browse/HSEARCH-1465
[2] https://hibernate.atlassian.net/browse/HSEARCH-1560
[3] http://wiki.osgi.org/wiki/Split_Packages
[4] https://github.com/hferentschik/hibernate-search/compare/HSEARCH-1560
10 years, 8 months
ORM 3 JIRA tickets
by Brett Meyer
Recently, we've been trying to clean up ORM's JIRA tickets. There are a lot of duplication, stale issues, etc. One thought was pushing all ORM 3 tickets to the "Awaiting Test Case" state and requesting a reproducer on ORM 4 or 5. They would then fall under our policy of automatically rejecting those tickets that did not receive a test case within 3 months or so. This obviously would not include new features/improvements, anything assigned to someone, etc.
Here's an example filter that would be used:
https://hibernate.atlassian.net/issues/?filter=14660
project = HHH AND issuetype = Bug AND status in (Open, "In Progress", Reopened, "Awaiting Test Case") AND affectedVersion in ([all ORM 3 version]) AND affectedVersion not in ([all ORM 4/5 versions]) AND assignee in (EMPTY) AND reporter not in ([core contributors]) AND updated < -90d
That results in 716 tickets, providing a considerable dent.
I thought it would be important to solicit other opinions. Any suggestions or alternate ideas? Anything missing from the query that might make it too aggressive?
Brett Meyer
Red Hat, Hibernate ORM
10 years, 8 months
Session and carrying 3rd party state
by Emmanuel Bernard
I took some more time to think about our conversation from 2 IRC meeting ago
about offering the ability to carry session bound state not related to
ORM per se.
Below is a sum and a potential solution.
If you are short on time, read Goals, then the SessionSessionEventListener
approach and ignore the rest.
## Goals
The goal is to be able to carry session bound state for non-ORM projects
like search and OGM.
We want to avoid ThreadLocal use, in particular when it cannot be
protected by a try / catch for proper resource cleaning.
We want to avoid a structure that would be shared across threads concurrently
i.e. using ConcurrentHashMap with a Weak reference to the session.
It needs to be informed of a call to session.clear()
It needs to be informed of a call to session.close()
The state needs to be accessed from event listener implementations and custom
persister / loader implementations i.e. SessionImplementor and maybe
EventSource?
## Approaches
I'll discuss the approaches we explored in the meeting and then offer an
alternative one that I think is pretty interesting and fit better with
the current Session model.
### Map
This is essentially sticking a map on SessionImpl and use it to carry
state.
The following is a pseudo implementation
/**
* interface implemented by SessionImpl and the like
*/
interface SessionCompanion {
Object getCompanion(String key);
void addCompanion(String key, Object companion);
void removeCompanion(String key);
}
/**
* adds a map to the SessionImpl
*/
SessionImpl {
private Map<String, Object> companions;
public Object getCompanion(String key) { return companions.get(key); }
public void addCompanion(String key, Object value) { companions.add(key, companion); }
public void removeCompanion(String key) { companions.remove(key) }
}
The persister or event listener would call SessionCompation.*Companion method
to put and retrieve its state.
There is no clear / close event listener loop and it would need to be added.
### Delegator
Gunnar and teve discussed an approach where the delegator would be passed to
the underlying session and be accessible via an `unwrap` method.
I have not followed the details but this approach has one major flaw: the
delegator (OgmSession, FullTextSession etc) is not always created and thus
would not be necessarily available.
A somewhat similar idea involving passing the session owner has the same
drawback. And another one described by Gunnar in
https://hibernate.atlassian.net/browse/OGM-469
### The type-safe map approach
This approach is vaguely similar to the Map approach except that the payload is
represented and looked up by Class. This has the benefit of not having
namespace problems and is generally less String-y.
/**
* interface implemented by SessionImpl and the like
*/
interface SessionCompanion {
T getCompanion(Class<T> type);
void addCompanion(Object companion);
void removeCompanion(Class<?> type)
}
SessionImpl {
//could also use an array or an ArrayList
private Map<Class<?>, Object> companions;
public T getCompanion(Class<T> type) { return (T) companions.get(type); }
public void addCompanion(Object companion) { companions.add(companion.getClass(), type); }
public void removeCompanion(Class<T> type) { companions.remove(type); }
}
Like in the Map approach, the persister or custom event listener would interact
with SessionCompanion.
There are open issues like what should be done when two objects of the same
type are added to the same session.
Likewise the clear / close hook issues need to be addressed.
### the SessionEventListener approach
I did not know but there is a concept of `SessionEventListener` which can be
added to a `SessionImplementor`. It has hooks that are addressing most of the
goals.
//interface already exists
interface SessionImplementor {
public SessionEventListenerManager getEventListenerManager();
}
//interface already exists
public interface SessionEventListenerManager extends SessionEventListener {
// add this method to be able to retrieve a specific listener holding some state for a 3rd party project
List<SessionEventListener> getSessionEventListeners();
}
OGM or Search would implement a `SessionEventListener` and attach an instance to a session via `Session.addEventListeners()`.
It would require to add a method to retrieve the list of `SessionEventListener`s attached to a `SessionEventListenerManager`.
List<SessionEventListeners> listeners = sessionImplementor.getSessionEventListenerManager().getEnlistedListeners();
OgmSessionEventListener ogmListener = findOrAddOgmListener(sessionImplementor, listeners);
ogmListener.someStuff();
## What about clear and close?
We have a few ways to react to these.
SessionEventListener is already called back when a flush begins / ends as well as when Session closes.
We need to either:
- add a clear begins / ends callback
- have the third party project add a ClearEventListener which would access the SessionEventListeners and do some magic.
The first approach has my preference and would do:
public interface SessionEventListener {
[...]
void clearStart();
void clearEnd();
}
What do you guys think? The SessionEventListener approach feels more natural.
Emmanuel
10 years, 8 months
[OGM] CI jobs hang
by Gunnar Morling
Hi,
For some reason, the CI jobs for OGM can't be executed (all jobs, master,
java8, PR seem affected) . They hang forever in an initial state, i.e.
there is no console output and also the sub-jobs are not dispatched (these
are matrix projects). Worse, they can't even be canceled (trying to do so
has no effect), only a server restart helps.
Have there been any recent changes to the job (or server) config which may
cause this? I found https://issues.jenkins-ci.org/browse/JENKINS-9688 which
indicates, that the jobs may be waiting eternally for a resource which they
can't acquire (I don't see any resources requested in the job config, but I
vaguely remember something around JGroups channels).
Does anyone know what's going on here?
--Gunnar
10 years, 8 months