php - Deleting symfony2 doctrine memcache on create/update/delete -
i'm using doctrine2 memcache (not memcached) in symfony 2.7 application. here configuration:
doctrine: orm: metadata_cache_driver: memcache result_cache_driver: memcache query_cache_driver: memcache
i'm trying delete respective cache items on entity create/update/delete. memcache doesn't support deletion using prefix, not find easy solution delete cache items of entity on cud operations. let's have property
entity, want delete caches related property
on property
create/update/delete. (i believe deleteall()
not idea in case)
deleting using namespace workaround, think namespace can set on cache driver, not on particular entity or repository. how possible distinguish namespaces each entity?
so, i'm invalidating result cache using onflush event (this way found , article old in 2012. there better recent solution?). 1 drawback of solution define each cache id each query , define of them in service class cacheinvalidator
such
namespace mybundle\listener\event; // ... class cacheinvalidator { //... protected function getcacheids() { return array( 'mybundle\entity\blogpost' => array( array( 'id' => 'posts_for_user_%d', 'vars' => array( array( 'value' => 'getuser', 'type' => 'method', ), ), 'change' => 'any', ), ), // add more entities etc here ); } }
the article author gave simple example using cache id posts_for_user_%d
. fine using such simple query. problem have many queries using lot of dynamic query parameters. example, have following method in property
repository can called various options:
public function findrecommendations($options = null) { if (isset($options['limit'])) { $limit = $options['limit']; } elseif (is_numeric($options)) { $limit = $options; } else { $limit = null; } $qb = $this->createquerybuilder('p'); $qb->where('p.recommend_flag = :recommend_flag'); $qb->setparameter('recommend_flag', 1); $qb->andwhere('date(p.expired_at) > :now'); $qb->setparameter('now', date('y-m-d')); $resultcacheparams = array( 'type' => array('%d', '%s'), 'value' => array(1, date('ymd')) ); if ($limit) { $qb->setmaxresults($limit); $resultcacheparams['type'][] = 'limit%d'; $resultcacheparams['value'][] = $limit; } $resultcacheid = vsprintf( 'property_findrecommendations_'.implode('_', $resultcacheparams['type']), $resultcacheparams['value'] ); $query = $qb->getquery(); $query->usequerycache(true); $query->setquerycachelifetime(21600); $query->useresultcache(true, 21600, $resultcacheid); return $query->getresult(); }
so, have define 2 combinations of cache id in service class - property_findrecommendations_%d_%s
, property_findrecommendations_%d_%s_limit%d
, 1 using limit , other without limit.
protected function getcacheids() { return array( 'mybundle\entity\property' => array( 'id' => 'property_findrecommendations_%d_%s', 'vars' => array( array('value' => 1), // recommend_flag array('value' => date('ymd')), ), 'change' => 'any' ), array( 'id' => 'property_findrecommendations_%d_%s_limit%d', 'vars' => array( array('value' => 1), // recommend_flag array('value' => date('ymd')), array('value' => $this->container->getparameter('max_recommend_properties')) ), 'change' => 'any' ), ); }
this 1 parameter example. there more 1 parameters method. more parameters, more combinations of cache id definitions in service class. expensive think.
the worst case queries pagination accept dynamic page
parameter. each query result each page should cached using different cache id, example property_getallproperties_%d
property_getallproperties_1 // page 1 property_getallproperties_2 // page 2 property_getallproperties_3 // page 3 ....
i can't know current page number in method getcacheids()
of service class. should calculate number of pages of properties , define array of cache ids every page number dynamically in method getcacheids()
?
i feel weird , seems workaround. in addition, have search queries depends on various parameters. think difficult define in getcacheids()
statically.
is there better , more graceful way invalidate doctrine memcache result cache?
update
one possible solution think of create new database table cache_key
, save every cache id in table. have function generate cache id according query parameters. returns cache id in format of custom_prefix
+ sha1(serialize($arrayofparameters))
, e.g., property_findrecommendations_xxxxxx
, property_getallproperties_xxxxxx
.
whenever call 2 methods findrecommendations()
, getallproperties()
, cache ids inserted (using replace
) table cache_key
below:
----------------------------------------------------- | entity | cache_id | ----------------------------------------------------- | property | property_findrecommendations_xxxxxx | | property | property_getallproperties_xxxxxx | -----------------------------------------------------
then, able retrieve them in cachevalidator
service class using entity name property
. 1 downside of insert/replace
query has executed on every query run , additonal select
executed on every onflush
event.
nonetheless, can't decide whether worth or not caches invalidated on every 6 hour according lifetime setting.
Comments
Post a Comment