BatchFetchQueuepublic class BatchFetchQueue extends Object Tracks entity and collection keys that are available for batch
fetching, and the queries which were used to load entities, which
can be re-used as a subquery for loading owned collections. |
Fields Summary |
---|
public static final Object | MARKER | private final Map | batchLoadableEntityKeysDefines a sequence of {@link EntityKey} elements that are currently
elegible for batch-fetching.
Even though this is a map, we only use the keys. A map was chosen in
order to utilize a {@link SequencedHashMap} to maintain sequencing
as well as uniqueness.
TODO : this would be better as a SequencedReferenceSet, but no such beast exists! | private final Map | subselectsByEntityKeyA map of {@link SubselectFetch subselect-fetch descriptors} keyed by the
{@link EntityKey) against which the descriptor is registered. | private final PersistenceContext | contextThe owning persistence context. |
Constructors Summary |
---|
public BatchFetchQueue(PersistenceContext context)Constructs a queue for the given context.
this.context = context;
|
Methods Summary |
---|
public void | addBatchLoadableEntityKey(EntityKey key)If an EntityKey represents a batch loadable entity, add
it to the queue.
Note that the contract here is such that any key passed in should
previously have been been checked for existence within the
{@link PersistenceContext}; failure to do so may cause the
referenced entity to be included in a batch even though it is
already associated with the {@link PersistenceContext}.
if ( key.isBatchLoadable() ) {
batchLoadableEntityKeys.put( key, MARKER );
}
| public void | addSubselect(EntityKey key, SubselectFetch subquery)Adds a subselect fetch decriptor for the given entity key.
subselectsByEntityKey.put(key, subquery);
| public void | clear()Clears all entries from this fetch queue.
batchLoadableEntityKeys.clear();
subselectsByEntityKey.clear();
| public void | clearSubselects()Clears all pending subselect fetches from the queue.
Called after flushing.
subselectsByEntityKey.clear();
| public java.io.Serializable[] | getCollectionBatch(org.hibernate.persister.collection.CollectionPersister collectionPersister, java.io.Serializable id, int batchSize, org.hibernate.EntityMode entityMode)Get a batch of uninitialized collection keys for a given role
Serializable[] keys = new Serializable[batchSize];
keys[0] = id;
int i = 1;
//int count = 0;
int end = -1;
boolean checkForEnd = false;
// this only works because collection entries are kept in a sequenced
// map by persistence context (maybe we should do like entities and
// keep a separate sequences set...)
Iterator iter = context.getCollectionEntries().entrySet().iterator(); //TODO: calling entrySet on an IdentityMap is SLOW!!
while ( iter.hasNext() ) {
Map.Entry me = (Map.Entry) iter.next();
CollectionEntry ce = (CollectionEntry) me.getValue();
PersistentCollection collection = (PersistentCollection) me.getKey();
if ( !collection.wasInitialized() && ce.getLoadedPersister() == collectionPersister ) {
if ( checkForEnd && i == end ) {
return keys; //the first key found after the given key
}
//if ( end == -1 && count > batchSize*10 ) return keys; //try out ten batches, max
final boolean isEqual = collectionPersister.getKeyType().isEqual(
id,
ce.getLoadedKey(),
entityMode,
collectionPersister.getFactory()
);
if ( isEqual ) {
end = i;
//checkForEnd = false;
}
else if ( !isCached( ce.getLoadedKey(), collectionPersister, entityMode ) ) {
keys[i++] = ce.getLoadedKey();
//count++;
}
if ( i == batchSize ) {
i = 1; //end of array, start filling again from start
if ( end != -1 ) {
checkForEnd = true;
}
}
}
}
return keys; //we ran out of keys to try
| public java.io.Serializable[] | getEntityBatch(org.hibernate.persister.entity.EntityPersister persister, java.io.Serializable id, int batchSize, org.hibernate.EntityMode entityMode)Get a batch of unloaded identifiers for this class, using a slightly
complex algorithm that tries to grab keys registered immediately after
the given key.
Serializable[] ids = new Serializable[batchSize];
ids[0] = id; //first element of array is reserved for the actual instance we are loading!
int i = 1;
int end = -1;
boolean checkForEnd = false;
Iterator iter = batchLoadableEntityKeys.keySet().iterator();
while ( iter.hasNext() ) {
EntityKey key = (EntityKey) iter.next();
if ( key.getEntityName().equals( persister.getEntityName() ) ) { //TODO: this needn't exclude subclasses...
if ( checkForEnd && i == end ) {
//the first id found after the given id
return ids;
}
if ( persister.getIdentifierType().isEqual( id, key.getIdentifier(), entityMode ) ) {
end = i;
}
else {
if ( !isCached( key, persister, entityMode ) ) {
ids[i++] = key.getIdentifier();
}
}
if ( i == batchSize ) {
i = 1; //end of array, start filling again from start
if (end!=-1) checkForEnd = true;
}
}
}
return ids; //we ran out of ids to try
| public SubselectFetch | getSubselect(EntityKey key)Retrieve the fetch descriptor associated with the given entity key.
return (SubselectFetch) subselectsByEntityKey.get(key);
| private boolean | isCached(EntityKey entityKey, org.hibernate.persister.entity.EntityPersister persister, org.hibernate.EntityMode entityMode)
if ( persister.hasCache() ) {
CacheKey key = new CacheKey(
entityKey.getIdentifier(),
persister.getIdentifierType(),
entityKey.getEntityName(),
entityMode,
context.getSession().getFactory()
);
return persister.getCache().getCache().get( key ) != null;
}
return false;
| private boolean | isCached(java.io.Serializable collectionKey, org.hibernate.persister.collection.CollectionPersister persister, org.hibernate.EntityMode entityMode)
if ( persister.hasCache() ) {
CacheKey cacheKey = new CacheKey(
collectionKey,
persister.getKeyType(),
persister.getRole(),
entityMode,
context.getSession().getFactory()
);
return persister.getCache().getCache().get( cacheKey ) != null;
}
return false;
| public void | removeBatchLoadableEntityKey(EntityKey key)After evicting or deleting or loading an entity, we don't
need to batch fetch it anymore, remove it from the queue
if necessary
if ( key.isBatchLoadable() ) batchLoadableEntityKeys.remove(key);
| public void | removeSubselect(EntityKey key)After evicting or deleting an entity, we don't need to
know the query that was used to load it anymore (don't
call this after loading the entity, since we might still
need to load its collections)
subselectsByEntityKey.remove(key);
|
|