1
0
mirror of synced 2025-03-05 20:36:15 +03:00

#6284 fixing actual issue, which comes from an extremely tricky L2 caching issue.

We are not hydrating some of the cached association data into entities due to keys missing in the cache association definition.
Since this is an extreme edge case that is just a mismatch between db and cache, a detailed explanation was provided in the fix snippet as well
This commit is contained in:
Marco Pivetta 2017-08-23 00:19:49 +02:00
parent c9d1f852de
commit 07b397f341
No known key found for this signature in database
GPG Key ID: 4167D3337FD9D629

View File

@ -92,13 +92,13 @@ class DefaultQueryCache implements QueryCache
return null;
}
$entry = $this->region->get($key);
$cacheEntry = $this->region->get($key);
if ( ! $entry instanceof QueryCacheEntry) {
if ( ! $cacheEntry instanceof QueryCacheEntry) {
return null;
}
if ( ! $this->validator->isValid($key, $entry)) {
if ( ! $this->validator->isValid($key, $cacheEntry)) {
$this->region->evict($key);
return null;
@ -117,11 +117,11 @@ class DefaultQueryCache implements QueryCache
return new EntityCacheKey($cm->rootEntityName, $entry['identifier']);
};
$cacheKeys = new CollectionCacheEntry(array_map($generateKeys, $entry->result));
$cacheKeys = new CollectionCacheEntry(array_map($generateKeys, $cacheEntry->result));
$entries = $region->getMultiple($cacheKeys);
// @TODO - move to cache hydration component
foreach ($entry->result as $index => $entry) {
foreach ($cacheEntry->result as $index => $entry) {
$entityEntry = is_array($entries) && array_key_exists($index, $entries) ? $entries[$index] : null;
if ($entityEntry === null) {
@ -210,6 +210,25 @@ class DefaultQueryCache implements QueryCache
$collection->setInitialized(true);
}
foreach ($data as $fieldName => $unCachedAssociationData) {
// In some scenarios, such as EAGER+ASSOCIATION+ID+CACHE, the
// cache key information in `$cacheEntry` will not contain details
// for fields that are associations.
//
// This means that `$data` keys for some associations that may
// actually not be cached will not be converted to actual association
// data, yet they contain L2 cache AssociationCacheEntry objects.
//
// We need to unwrap those associations into proxy references,
// since we don't have actual data for them except for identifiers.
if ($unCachedAssociationData instanceof AssociationCacheEntry) {
$data[$fieldName] = $this->em->getReference(
$unCachedAssociationData->class,
$unCachedAssociationData->identifier
);
}
}
$result[$index] = $this->uow->createEntity($entityEntry->class, $data, self::$hints);
}
@ -246,7 +265,6 @@ class DefaultQueryCache implements QueryCache
$data = [];
$entityName = reset($rsm->aliasMap);
$rootAlias = key($rsm->aliasMap);
$hasRelation = ( ! empty($rsm->relationMap));
$persister = $this->uow->getEntityPersister($entityName);
if ( ! ($persister instanceof CachedPersister)) {
@ -258,8 +276,6 @@ class DefaultQueryCache implements QueryCache
foreach ($result as $index => $entity) {
$identifier = $this->uow->getEntityIdentifier($entity);
$entityKey = new EntityCacheKey($entityName, $identifier);
$data[$index]['identifier'] = $identifier;
$data[$index]['associations'] = [];
if (($key->cacheMode & Cache::MODE_REFRESH) || ! $region->contains($entityKey)) {
// Cancel put result if entity put fail
@ -268,9 +284,8 @@ class DefaultQueryCache implements QueryCache
}
}
if ( ! $hasRelation) {
continue;
}
$data[$index]['identifier'] = $identifier;
$data[$index]['associations'] = [];
// @TODO - move to cache hydration components
foreach ($rsm->relationMap as $alias => $name) {