Skip to content

Commit 2c63ac3

Browse files
committed
Adds cache to ItemIdForQueryLookup
1 parent 2759b04 commit 2c63ac3

File tree

5 files changed

+267
-1
lines changed

5 files changed

+267
-1
lines changed

src/Cache/CachedEntityStore.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@ class CachedEntityStore extends EntityStore {
2626
*/
2727
private $entityIdForTermCache;
2828

29+
/**
30+
* @var EntityIdForQueryCache
31+
*/
32+
private $entityIdForQueryCache;
33+
2934
/**
3035
* @param EntityStore $entityStore
3136
* @param Cache $cache
@@ -35,6 +40,7 @@ public function __construct( EntityStore $entityStore, Cache $cache, $lifeTime =
3540
$this->entityStore = $entityStore;
3641
$this->entityCache = new EntityDocumentCache( $cache, $lifeTime );
3742
$this->entityIdForTermCache = new EntityIdForTermCache( $cache, $lifeTime );
43+
$this->entityIdForQueryCache = new EntityIdForQueryCache( $cache, $lifeTime );
3844
}
3945

4046
/**
@@ -83,7 +89,7 @@ public function getPropertyIdForTermLookup() {
8389
* @see EntityStore::getItemIdForQueryLookup
8490
*/
8591
public function getItemIdForQueryLookup() {
86-
return $this->entityStore->getItemIdForQueryLookup();
92+
return new CachedItemIdForQueryLookup( $this->entityStore->getItemIdForQueryLookup(), $this->entityIdForQueryCache );
8793
}
8894

8995
/**
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
<?php
2+
3+
namespace Wikibase\EntityStore\Cache;
4+
5+
use Ask\Language\Description\Description;
6+
use Ask\Language\Option\QueryOptions;
7+
use OutOfBoundsException;
8+
use Wikibase\EntityStore\ItemIdForQueryLookup;
9+
10+
/**
11+
* Internal class
12+
*
13+
* @licence GPLv2+
14+
* @author Thomas Pellissier Tanon
15+
*/
16+
class CachedItemIdForQueryLookup implements ItemIdForQueryLookup {
17+
18+
/**
19+
* @var ItemIdForQueryLookup
20+
*/
21+
private $itemIdForQueryLookup;
22+
23+
/**
24+
* @var EntityIdForQueryCache
25+
*/
26+
private $entityIdForQueryCache;
27+
28+
/**
29+
* @param ItemIdForQueryLookup $itemIdForQueryLookup
30+
* @param EntityIdForQueryCache $entityIdForQueryCache
31+
*/
32+
public function __construct(
33+
ItemIdForQueryLookup $itemIdForQueryLookup,
34+
EntityIdForQueryCache $entityIdForQueryCache
35+
) {
36+
$this->itemIdForQueryLookup = $itemIdForQueryLookup;
37+
$this->entityIdForQueryCache = $entityIdForQueryCache;
38+
}
39+
40+
/**
41+
* @see ItemIdForQueryLookup::getItemIdsForQuery
42+
*/
43+
public function getItemIdsForQuery( Description $description, QueryOptions $queryOptions = null ) {
44+
try {
45+
return $this->entityIdForQueryCache->fetch( $description, $queryOptions, 'item' );
46+
} catch( OutOfBoundsException $e ) {
47+
$itemIds = $this->itemIdForQueryLookup->getItemIdsForQuery( $description, $queryOptions );
48+
$this->entityIdForQueryCache->save( $description, $queryOptions, 'item', $itemIds );
49+
return $itemIds;
50+
}
51+
}
52+
}
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
<?php
2+
3+
namespace Wikibase\EntityStore\Cache;
4+
5+
use Ask\Language\Description\Description;
6+
use Ask\Language\Option\QueryOptions;
7+
use Doctrine\Common\Cache\Cache;
8+
use OutOfBoundsException;
9+
use RuntimeException;
10+
use Wikibase\DataModel\Entity\EntityId;
11+
12+
/**
13+
* @licence GPLv2+
14+
* @author Thomas Pellissier Tanon
15+
*/
16+
class EntityIdForQueryCache {
17+
18+
const CACHE_ID_PREFIX = 'wikibase-store-entityforquery-';
19+
20+
const CACHE_LIFE_TIME = 86400;
21+
22+
/**
23+
* @var Cache
24+
*/
25+
private $cache;
26+
27+
/**
28+
* @var int
29+
*/
30+
private $lifeTime;
31+
32+
/**
33+
* @param Cache $cache
34+
* @param int $lifeTime
35+
*/
36+
public function __construct( Cache $cache, $lifeTime = 0 ) {
37+
$this->cache = $cache;
38+
$this->lifeTime = $lifeTime;
39+
}
40+
41+
/**
42+
* @param Description $description
43+
* @param QueryOptions $queryOptions
44+
* @param string $entityType
45+
* @return EntityId[]
46+
*/
47+
public function fetch( Description $description, QueryOptions $queryOptions = null, $entityType ) {
48+
$result = $this->cache->fetch( $this->getCacheId( $description, $queryOptions, $entityType ) );
49+
50+
if( $result === false ) {
51+
throw new OutOfBoundsException( 'The search is not in the cache.' );
52+
}
53+
54+
return $result;
55+
}
56+
57+
/**
58+
* @param Description $description
59+
* @param QueryOptions $queryOptions
60+
* @param string $entityType
61+
* @return boolean
62+
*/
63+
public function contains( Description $description, QueryOptions $queryOptions = null, $entityType ) {
64+
return $this->cache->contains( $this->getCacheId( $description, $queryOptions, $entityType ) );
65+
}
66+
67+
/**
68+
* @param Description $description
69+
* @param QueryOptions $queryOptions
70+
* @param string $entityType
71+
* @param EntityId[] $entityIds
72+
*/
73+
public function save( Description $description, QueryOptions $queryOptions = null, $entityType, array $entityIds ) {
74+
if( !$this->cache->save(
75+
$this->getCacheId( $description, $queryOptions, $entityType ),
76+
$entityIds,
77+
$this->lifeTime
78+
) ) {
79+
throw new RuntimeException( 'The cache failed to save.' );
80+
}
81+
}
82+
83+
private function getCacheId( Description $description, QueryOptions $queryOptions = null, $entityType ) {
84+
$key = self::CACHE_ID_PREFIX . WIKIBASE_DATAMODEL_VERSION . '-' .
85+
$entityType . '-' . $description->getHash();
86+
87+
if( $queryOptions !== null ) {
88+
$key .= '-' . $queryOptions->getOffset() . '-' . $queryOptions->getLimit();
89+
}
90+
91+
return $key;
92+
}
93+
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
<?php
2+
3+
namespace Wikibase\EntityStore\Cache;
4+
5+
use Ask\Language\Description\AnyValue;
6+
use OutOfBoundsException;
7+
use Wikibase\DataModel\Entity\ItemId;
8+
9+
/**
10+
* @covers Wikibase\EntityStore\Cache\CachedItemIdForQueryLookup
11+
*
12+
* @licence GPLv2+
13+
* @author Thomas Pellissier Tanon
14+
*/
15+
class CachedItemIdForQueryLookupTest extends \PHPUnit_Framework_TestCase {
16+
17+
public function testGetItemsForQueryWithCacheHit() {
18+
$itemIds = array( new ItemId( 'Q1' ) );
19+
20+
$itemIdForQueryLookupMock = $this->getMockBuilder( 'Wikibase\EntityStore\ItemIdForQueryLookup' )
21+
->disableOriginalConstructor()
22+
->getMock();
23+
24+
$entityIdForQueryCacheMock = $this->getMockBuilder( 'Wikibase\EntityStore\Cache\EntityIdForQueryCache' )
25+
->disableOriginalConstructor()
26+
->getMock();
27+
$entityIdForQueryCacheMock->expects( $this->once() )
28+
->method( 'fetch' )
29+
->with( $this->equalTo( new AnyValue() ), $this->isNull(), $this->equalTo( 'item' ) )
30+
->willReturn( $itemIds );
31+
32+
$itemIdForQueryLookup = new CachedItemIdForQueryLookup( $itemIdForQueryLookupMock, $entityIdForQueryCacheMock );
33+
$this->assertEquals(
34+
$itemIds,
35+
$itemIdForQueryLookup->getItemIdsForQuery( new AnyValue() )
36+
);
37+
}
38+
39+
public function testGetItemsForQueryWithCacheMiss() {
40+
$itemIds = array( new ItemId( 'Q1' ) );
41+
42+
$itemIdForQueryLookupMock = $this->getMockBuilder( 'Wikibase\EntityStore\ItemIdForQueryLookup' )
43+
->disableOriginalConstructor()
44+
->getMock();
45+
$itemIdForQueryLookupMock->expects( $this->once() )
46+
->method( 'getItemIdsForQuery' )
47+
->with( $this->equalTo( new AnyValue() ) )
48+
->willReturn( $itemIds );
49+
50+
$entityIdForQueryCacheMock = $this->getMockBuilder( 'Wikibase\EntityStore\Cache\EntityIdForQueryCache' )
51+
->disableOriginalConstructor()
52+
->getMock();
53+
$entityIdForQueryCacheMock->expects( $this->once() )
54+
->method( 'fetch' )
55+
->with( $this->equalTo( new AnyValue() ), $this->isNull(), $this->equalTo( 'item' ) )
56+
->willThrowException( new OutOfBoundsException() );
57+
58+
$itemIdForQueryLookup = new CachedItemIdForQueryLookup( $itemIdForQueryLookupMock, $entityIdForQueryCacheMock );
59+
$this->assertEquals(
60+
$itemIds,
61+
$itemIdForQueryLookup->getItemIdsForQuery( new AnyValue() )
62+
);
63+
}
64+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<?php
2+
3+
namespace Wikibase\EntityStore\Cache;
4+
5+
use Ask\Language\Description\AnyValue;
6+
use Ask\Language\Option\QueryOptions;
7+
use Doctrine\Common\Cache\ArrayCache;
8+
use Wikibase\DataModel\Entity\ItemId;
9+
10+
/**
11+
* @covers Wikibase\EntityStore\Cache\EntityIdForQueryCache
12+
*
13+
* @licence GPLv2+
14+
* @author Thomas Pellissier Tanon
15+
*/
16+
class EntityIdForQueryCacheTest extends \PHPUnit_Framework_TestCase {
17+
18+
public function testFetch() {
19+
$cache = new EntityIdForQueryCache( new ArrayCache() );
20+
$cache->save( new AnyValue(), null, 'item', array( new ItemId( 'Q42' ) ) );
21+
22+
$this->assertEquals( array( new ItemId( 'Q42' ) ), $cache->fetch( new AnyValue(), null, 'item' ) );
23+
}
24+
25+
public function testFetchWithOptions() {
26+
$cache = new EntityIdForQueryCache( new ArrayCache() );
27+
$cache->save( new AnyValue(), new QueryOptions( 10, 0 ), 'item', array( new ItemId( 'Q42' ) ) );
28+
29+
$this->assertEquals( array( new ItemId( 'Q42' ) ), $cache->fetch( new AnyValue(), new QueryOptions( 10, 0 ), 'item' ) );
30+
}
31+
32+
public function testFetchWithException() {
33+
$this->setExpectedException( '\OutOfBoundsException' );
34+
35+
$cache = new EntityIdForQueryCache( new ArrayCache() );
36+
$cache->fetch( new AnyValue(), null, 'item' );
37+
}
38+
39+
public function testContainsTrue() {
40+
$cache = new EntityIdForQueryCache( new ArrayCache() );
41+
$cache->save(new AnyValue(), null, 'item', array( new ItemId( 'Q42' ) ) );
42+
43+
$this->assertTrue( $cache->contains( new AnyValue(), null, 'item' ) );
44+
}
45+
46+
public function testContainsFalse() {
47+
$cache = new EntityIdForQueryCache( new ArrayCache() );
48+
49+
$this->assertFalse( $cache->contains( new AnyValue(), null, 'item' ) );
50+
}
51+
}

0 commit comments

Comments
 (0)