As far as terms... I think you need to look at this from the perspective of Hibernate when "understanding" these contracts. To Hibernate there really are just:
- Region - just a named handle, useful for centralized access to various information. As covered this would generally have no direct corollary in the underlying cache provider. It is really just a Hibernate concept. It is meant to provide named access to one or more grouped "data stores". What a Region "means" is ultimately up to the provider, but I think it would be best to have a common understanding regarding the role of a region (name) in terms of underlying cache configuration.
- "data store" is the concept of cache storage specific to one "cacheable" (one entity, one collection, etc). It is not actually modelled in the cache SPI. This is the part that y'alls work on cache keys messes with; I will discuss below the 2 possible ways to fix that - one of which I have already implemented in my branch work (locally)[1].
- RegionAccess is the contract for providing access to the data of a single "data store"/"cacheable". That is, when we build a EntityRegionAccess for the Person entity, e.g., that EntityRegionAccess will only ever be used to access Person cached data. This also comes into play in regards to the cache keys problem [1]. In retrospect, the name RegionAccess is not the best choice in terms of intent. Really it should be more something like CacheableCacheAccess, CacheableStoreAccess or CacheableDataAccess
So, to make it crystal clear, when someone builds TRANSACTIONAL access to a region, using role X, inserts an entity with id 123, and later builds READ_WRITE access using the same role X; should the request to fetch entity with id 123 return null? IIUC such situation should not be possible (single entity is always accessed using the same access type), and if we link cache just with the access type (instead of a region), I don't have any reason to request the restriction to single access type per region anymore. I wonder if we could shape the interface in a way to express that each role will be always accessed using the same access type, but it's probably unnecessary if that's clearly stated in javadoc.
That will never happen, and you can consider it an exception if it does. Take a peek at the RequestedCaching contract below; IMO that makes it very clear to the RegionFactory/Region that the AccessType is specific to the role (Navigable). We only ever ask the Region for an access object by the Navigable; we never pass it the AccessType after the Region is built. This is what I was saying above in this comment... after we have built the Region with RegionNameMapping and RegionBuildingContext we expect that the Region has prebuilt all the indicated access objects - we will only ever ask for those by NavigableRole. So IMO this is already expressed in the contract. But let me know if you see it differently. FWIW I am getting close to being ready to push this. Probably another hour. [1] As I understand it, hibernate-infinispan chooses to implement Region as being related to a single Cache. This adds to the problems we have been seeing with "shared regions" mainly due to the changes in how cache-keys are built. hibernate-infinispan creating a Cache per-Region is perfectly fine, in-and-of itself. Normally the cache key used into that Cache would have included the "navigable role" (entity-name, collection-role, etc) so that the data for each entity/collection/natural-id would naturally be segmented. But the change to not include that in the cache key causes problems when the Region is shared by, e.g., multiple entities whose ids could collide. However, one of two things could be changed here to make it work:
- hibernate-infinispan could instead chose to say that a Cache is created for each RegionAccess. This makes the Cache specific to a single "cacheable" - whether the name of the cacheable is part of the key is then no longer relevant.
- Continue to use the more performant keys, but be smarter about when we use that CacheKeysFactory. I have implemented this on in the topic branch. I like the way this turned out, but I do want to point out that since ORM had to go through all the effort to present the RegionFactory with all of the collected requested caching definitions[2], that the Region should take over responsibility for managing the Map of RegionAccess objects.
[2] This is how that looks in the code:
/**
* Mapping for a particular region-name to the user's caching definitions
* for the entities, collections and natural-ids to be stored in that region.
* <p/>
* Designed under the principle that each kind of "cacheable" can
* define only one AccessType and that there is only one definition
* for entity hierarchies that must be defined under the root entity name.
*/
public interface RegionNameMapping {
String getRegionName();
List<RequestedEntityCaching> getRequestedEntityCachingList();
List<RequestedCollectionCaching> getRequestedCollectionCachingList();
List<RequestedNaturalIdCaching> getRequestedNaturalIdCachingList();
}
public interface RequestedEntityCaching extends RequestedCaching {
default String getRootEntityName() {
return getCachedRole().getFullPath();
}
}
/**
* The "caching config" requested for a "cacheable".
* <p/>
* What all a "cacheable" might be is manifested in the
* specializations of this contract.
*/
public interface RequestedCaching {
NavigableRole getCachedRole();
/**
* The AccessType requested for the mapping.
*/
AccessType getAccessType();
}
...
|