Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
project
drupal
Commits
31bd2006
Commit
31bd2006
authored
Apr 03, 2013
by
Nathaniel Catchpole
Browse files
Issue
#1944674
by damiankloip, dawehner: Improve performance of ViewsDataCache.
parent
8c21dcb6
Changes
5
Hide whitespace changes
Inline
Side-by-side
core/modules/contact/lib/Drupal/contact/Tests/Views/ContactFieldsTest.php
View file @
31bd2006
...
...
@@ -52,6 +52,8 @@ protected function setUp() {
'bundle'
=>
'contact_message'
,
);
field_create_instance
(
$instance
);
$this
->
container
->
get
(
'views.views_data'
)
->
clear
();
}
/**
...
...
core/modules/field/lib/Drupal/field/Tests/Views/ApiDataTest.php
View file @
31bd2006
...
...
@@ -68,6 +68,8 @@ function setUp() {
);
$this
->
nodes
[]
=
$this
->
drupalCreateNode
(
$edit
);
}
$this
->
container
->
get
(
'views.views_data'
)
->
clear
();
}
/**
...
...
core/modules/field/lib/Drupal/field/Tests/Views/HandlerFieldFieldTest.php
View file @
31bd2006
...
...
@@ -69,6 +69,8 @@ protected function setUp() {
$this
->
nodes
[
$i
]
=
$this
->
drupalCreateNode
(
$edit
);
}
$this
->
container
->
get
(
'views.views_data'
)
->
clear
();
}
/**
...
...
core/modules/views/lib/Drupal/views/Tests/ViewsDataTest.php
View file @
31bd2006
...
...
@@ -21,6 +21,13 @@ class ViewsDataTest extends ViewUnitTestBase {
*/
protected
$viewsDataCache
;
/**
* Stores a count for hook_views_data being invoked.
*
* @var int
*/
protected
$count
=
0
;
public
static
function
getInfo
()
{
return
array
(
'name'
=>
'Table Data'
,
...
...
@@ -33,6 +40,7 @@ protected function setUp() {
parent
::
setUp
();
$this
->
viewsDataCache
=
$this
->
container
->
get
(
'views.views_data'
);
$this
->
state
=
$this
->
container
->
get
(
'state'
);
}
/**
...
...
@@ -42,35 +50,98 @@ protected function setUp() {
*/
public
function
testViewsFetchData
()
{
$table_name
=
'views_test_data'
;
$expected_data
=
$this
->
viewsData
();
$data
=
$this
->
viewsDataCache
->
get
(
$table_name
);
$this
->
assertEqual
(
$data
,
$expected_data
[
$table_name
],
'Make sure fetching views data by table works as expected.'
);
$data
=
$this
->
viewsDataCache
->
get
(
$this
->
randomName
());
$this
->
assertTrue
(
empty
(
$data
),
'Make sure fetching views data for an invalid table returns empty.'
);
$data
=
$this
->
viewsDataCache
->
get
();
$this
->
assertTrue
(
isset
(
$data
[
$table_name
]),
'Make sure the views_test_data info appears in the total views data.'
);
$this
->
assertEqual
(
$data
[
$table_name
],
$expected_data
[
$table_name
],
'Make sure the views_test_data has the expected values.'
);
// Verify that views_test_data_views_data() has only been called once.
$state
=
\
Drupal
::
service
(
'state'
);
$count
=
$state
->
get
(
'views_test_data_views_data_count'
);
$random_table_name
=
$this
->
randomName
();
// Invoke expected data directly from hook_views_data implementations.
$expected_data
=
$this
->
container
->
get
(
'module_handler'
)
->
invokeAll
(
'views_data'
);
// Verify that views_test_data_views_data() has only been called once after
// calling clear().
$this
->
startCount
();
$this
->
viewsDataCache
->
get
();
// Test views data has been invoked.
$this
->
assertCountIncrement
();
// Clear the storage/cache.
$this
->
viewsDataCache
->
clear
();
// Get the data again.
$this
->
viewsDataCache
->
get
();
$this
->
viewsDataCache
->
get
(
$table_name
);
// Verify that view_test_data_views_data() has run again.
$this
->
assertEqual
(
$count
+
1
,
$state
->
get
(
'views_test_data_views_data_count'
));
$this
->
viewsDataCache
->
get
(
$random_table_name
);
// Verify that view_test_data_views_data() has run once.
$this
->
assertCountIncrement
();
// Get the data again.
$this
->
viewsDataCache
->
get
(
$table_name
);
// Also request all table data.
$this
->
viewsDataCache
->
get
();
$this
->
viewsDataCache
->
get
(
$table_name
);
$this
->
viewsDataCache
->
get
(
$random_table_name
);
// Verify that view_test_data_views_data() has not run again.
$this
->
assertEqual
(
$count
+
1
,
$state
->
get
(
'views_test_data_views_data_count'
));
$this
->
assertCountIncrement
(
FALSE
);
// Clear the views data, and test all table data.
$this
->
viewsDataCache
->
clear
();
$this
->
startCount
();
$data
=
$this
->
viewsDataCache
->
get
();
$this
->
assertEqual
(
$data
,
$expected_data
,
'Make sure fetching all views data by works as expected.'
);
// Views data should be invoked once.
$this
->
assertCountIncrement
();
// Calling get() again, the count for this table should stay the same.
$data
=
$this
->
viewsDataCache
->
get
();
$this
->
assertEqual
(
$data
,
$expected_data
,
'Make sure fetching all cached views data works as expected.'
);
$this
->
assertCountIncrement
(
FALSE
);
// Clear the views data, and test data for a specific table.
$this
->
viewsDataCache
->
clear
();
$this
->
startCount
();
$data
=
$this
->
viewsDataCache
->
get
(
$table_name
);
$this
->
assertEqual
(
$data
,
$expected_data
[
$table_name
],
'Make sure fetching views data by table works as expected.'
);
// Views data should be invoked once.
$this
->
assertCountIncrement
();
// Calling get() again, the count for this table should stay the same.
$data
=
$this
->
viewsDataCache
->
get
(
$table_name
);
$this
->
assertEqual
(
$data
,
$expected_data
[
$table_name
],
'Make sure fetching cached views data by table works as expected.'
);
$this
->
assertCountIncrement
(
FALSE
);
// Test that this data is present if all views data is returned.
$data
=
$this
->
viewsDataCache
->
get
();
$this
->
assertTrue
(
isset
(
$data
[
$table_name
]),
'Make sure the views_test_data info appears in the total views data.'
);
$this
->
assertEqual
(
$data
[
$table_name
],
$expected_data
[
$table_name
],
'Make sure the views_test_data has the expected values.'
);
// Clear the views data, and test data for an invalid table.
$this
->
viewsDataCache
->
clear
();
$this
->
startCount
();
// All views data should be requested on the first try.
$data
=
$this
->
viewsDataCache
->
get
(
$random_table_name
);
$this
->
assertEqual
(
$data
,
array
(),
'Make sure fetching views data for an invalid table returns an empty array.'
);
$this
->
assertCountIncrement
();
// Test no data is rebuilt when requesting an invalid table again.
$data
=
$this
->
viewsDataCache
->
get
(
$random_table_name
);
$this
->
assertEqual
(
$data
,
array
(),
'Make sure fetching views data for an invalid table returns an empty array.'
);
$this
->
assertCountIncrement
(
FALSE
);
}
/**
* Starts a count for hook_views_data being invoked.
*/
protected
function
startCount
()
{
$count
=
$this
->
state
->
get
(
'views_test_data_views_data_count'
);
$this
->
count
=
isset
(
$count
)
?
$count
:
0
;
}
/**
* Asserts that the count for hook_views_data either equal or has increased.
*
* @param bool $equal
* Whether to assert that the count should be equal. Defaults to FALSE.
*/
protected
function
assertCountIncrement
(
$increment
=
TRUE
)
{
if
(
$increment
)
{
// If an incremented count is expected, increment this now.
$this
->
count
++
;
$message
=
'hook_views_data has been invoked.'
;
}
else
{
$message
=
'hook_views_data has not been invoked'
;
}
$this
->
assertEqual
(
$this
->
count
,
$this
->
state
->
get
(
'views_test_data_views_data_count'
),
$message
);
}
/**
...
...
core/modules/views/lib/Drupal/views/ViewsDataCache.php
View file @
31bd2006
...
...
@@ -38,111 +38,98 @@ class ViewsDataCache implements DestructableInterface {
protected
$storage
=
array
();
/**
*
The configuration factory object
.
*
An array of requested tables
.
*
* @var
\Drupal\Core\Config\ConfigFactor
y
* @var
arra
y
*/
protected
$
config
;
protected
$
requestedTables
=
array
()
;
/**
*
T
he
current language code
.
*
W
he
ther the data has been fully loaded in this request
.
*
* @var
string
* @var
bool
*/
protected
$
langcode
;
protected
$
fullyLoaded
=
FALSE
;
/**
* Whether the data has been fully loaded in this request.
* Whether views data has been rebuilt. This is set when getData() doesn't
* return anything from cache.
*
* @var bool
*/
protected
$
fullyLoaded
=
FALSE
;
protected
$
rebuildAll
=
FALSE
;
/**
* Whether or not to skip data caching and rebuild data each time.
*
* @var bool
*/
protected
$skipCache
;
protected
$skipCache
=
FALSE
;
/**
*
Whether the cache should be rebuilt. This is set when getData() is called
.
*
The current language code
.
*
* @var
bool
* @var
string
*/
protected
$
rebuildCach
e
;
protected
$
langcod
e
;
public
function
__construct
(
CacheBackendInterface
$cache_backend
,
ConfigFactory
$config
)
{
$this
->
config
=
$config
;
$this
->
cacheBackend
=
$cache_backend
;
$this
->
langcode
=
language
(
LANGUAGE_TYPE_INTERFACE
)
->
langcode
;
$this
->
skipCache
=
$
this
->
config
->
get
(
'views.settings'
)
->
get
(
'skip_cache'
);
$this
->
skipCache
=
$config
->
get
(
'views.settings'
)
->
get
(
'skip_cache'
);
}
/**
* Gets
cached
data for a particular
key, or rebuilds if necessary
.
* Gets data for a particular
table, or all tables
.
*
* @param string|null $key
* The key of the cache entry to retrieve. Defaults to NULL.
* The key of the cache entry to retrieve. Defaults to NULL, this will
* return all table data.
*
* @return array $data
*
The cached
data.
*
An array of table
data.
*/
public
function
get
(
$key
=
NULL
)
{
if
(
$key
)
{
$from_cache
=
FALSE
;
if
(
!
isset
(
$this
->
storage
[
$key
]))
{
// Prepare a cache ID.
$cid
=
$this
->
baseCid
.
':'
.
$key
;
$data
=
$this
->
cacheGet
(
$cid
);
if
(
!
empty
(
$data
->
data
))
{
if
(
$data
=
$this
->
cacheGet
(
$cid
))
{
$this
->
storage
[
$key
]
=
$data
->
data
;
$from_cache
=
TRUE
;
}
else
{
// No cache entry, rebuild.
// If there is no cached entry and data is not already fully loaded,
// rebuild. This will stop requests for invalid tables calling getData.
elseif
(
!
$this
->
fullyLoaded
)
{
$this
->
storage
=
$this
->
getData
();
$this
->
fullyLoaded
=
TRUE
;
}
}
if
(
isset
(
$this
->
storage
[
$key
]))
{
if
(
!
$from_cache
)
{
// Add this table to a list of requested tables, as it's table cache
// entry was not found.
array_push
(
$this
->
requestedTables
,
$key
);
}
return
$this
->
storage
[
$key
];
}
// If the key is invalid, return an empty array.
return
array
();
}
else
{
if
(
!
$this
->
fullyLoaded
)
{
$data
=
$this
->
cacheGet
(
$this
->
baseCid
);
if
(
!
empty
(
$data
->
data
))
{
$this
->
storage
=
$data
->
data
;
}
else
{
$this
->
storage
=
$this
->
getData
();
}
$this
->
fullyLoaded
=
TRUE
;
$this
->
storage
=
$this
->
getData
();
}
}
return
$this
->
storage
;
}
/**
* Sets the data in the cache backend for a cache key.
*
* @param string $key
* The cache key to set.
* @param mixed $value
* The value to set for this key.
*/
public
function
set
(
$key
,
$value
)
{
if
(
$this
->
skipCache
)
{
return
FALSE
;
}
$key
.
=
':'
.
$this
->
langcode
;
$this
->
cacheBackend
->
set
(
$key
,
$value
);
}
/**
* Gets data from the cache backend.
*
...
...
@@ -158,26 +145,47 @@ protected function cacheGet($cid) {
return
FALSE
;
}
$cid
.
=
':'
.
$this
->
langcode
;
return
$this
->
cacheBackend
->
get
(
$this
->
prepareCid
(
$cid
));
}
return
$this
->
cacheBackend
->
get
(
$cid
);
/**
* Prepares the cache ID by appending a language code.
*
* @param string $cid
* The cache ID to prepare.
*
* @return string
* The prepared cache ID.
*/
protected
function
prepareCid
(
$cid
)
{
return
$cid
.
':'
.
$this
->
langcode
;
}
/**
* Gets all data invoked by hook_views_data().
*
* This is requested from the cache before being rebuilt.
*
* @return array
* An array of all data.
*/
protected
function
getData
()
{
$data
=
module_invoke_all
(
'views_data'
);
drupal_alter
(
'views_data'
,
$data
);
$this
->
fullyLoaded
=
TRUE
;
$this
->
processEntityTypes
(
$data
);
if
(
$data
=
$this
->
cacheGet
(
$this
->
baseCid
))
{
return
$data
->
data
;
}
else
{
$data
=
module_invoke_all
(
'views_data'
);
drupal_alter
(
'views_data'
,
$data
);
$this
->
processEntityTypes
(
$data
);
$this
->
rebuildCache
=
TRUE
;
// Set as TRUE, so all table data will be cached.
$this
->
rebuildAll
=
TRUE
;
return
$data
;
return
$data
;
}
}
/**
...
...
@@ -245,13 +253,16 @@ public function fetchBaseTables() {
* Implements \Drupal\Core\DestructableInterface::destruct().
*/
public
function
destruct
()
{
if
(
$this
->
rebuildCache
&&
!
empty
(
$this
->
storage
))
{
// Keep a record with all data.
$this
->
set
(
$this
->
baseCid
,
$this
->
storage
);
// Save data in seperate cache entries.
foreach
(
$this
->
storage
as
$table
=>
$data
)
{
if
(
!
empty
(
$this
->
storage
)
&&
!
$this
->
skipCache
)
{
if
(
$this
->
rebuildAll
)
{
// Keep a record with all data.
$this
->
cacheBackend
->
set
(
$this
->
prepareCid
(
$this
->
baseCid
),
$this
->
storage
);
}
// Save data in seperate, per table cache entries.
foreach
(
$this
->
requestedTables
as
$table
)
{
$cid
=
$this
->
baseCid
.
':'
.
$table
;
$this
->
set
(
$cid
,
$
data
);
$this
->
cacheBackend
->
set
(
$this
->
prepareCid
(
$cid
)
,
$
this
->
storage
[
$table
]
);
}
}
}
...
...
@@ -261,6 +272,7 @@ public function destruct() {
*/
public
function
clear
()
{
$this
->
storage
=
array
();
$this
->
fullyLoaded
=
FALSE
;
$this
->
cacheBackend
->
deleteAll
();
}
}
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment