Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
apc
Manage
Activity
Members
Labels
Plan
Wiki
Custom issue tracker
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Locked files
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Model registry
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Code review analytics
Insights
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Terms and privacy
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
project
apc
Commits
8794105d
Commit
8794105d
authored
6 months ago
by
Alberto Paderno
Browse files
Options
Downloads
Patches
Plain Diff
Issue
#3468201
: Clearing cache items whose IDs start with a given string is not possible
parent
1cf410e6
No related branches found
No related tags found
1 merge request
!63
Issue #3468201: Clearing cache items whose IDs start with a given string is not possible
Pipeline
#255255
passed
6 months ago
Stage: build
Stage: validate
Stage: test
Changes
4
Pipelines
2
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
.gitlab-ci.yml
+2
-2
2 additions, 2 deletions
.gitlab-ci.yml
apc.install
+16
-7
16 additions, 7 deletions
apc.install
apc.test
+36
-44
36 additions, 44 deletions
apc.test
drupal_apc_cache.inc
+23
-67
23 additions, 67 deletions
drupal_apc_cache.inc
with
77 additions
and
120 deletions
.gitlab-ci.yml
+
2
−
2
View file @
8794105d
...
...
@@ -28,5 +28,5 @@ include:
# OPT_IN_TEST_NEXT_MAJOR: '1'
# _CURL_TEMPLATES_REF: 'main'
variables
:
_PHPUNIT_CONCURRENT
:
1
_CONCURRENCY_THREADS
:
4
_PHPUNIT_CONCURRENT
:
'
1'
_CONCURRENCY_THREADS
:
'
6'
This diff is collapsed.
Click to expand it.
apc.install
+
16
−
7
View file @
8794105d
...
...
@@ -15,7 +15,7 @@
*
* @param array $patterns
* An associative array of patterns and their corresponding old patterns. Old
* patterns are replaced by the new patterns
, in the persistent variable
.
* patterns are replaced by the new patterns.
*/
function
_apc_delete_apcu_keys
(
$patterns
)
{
$apcu_enabled
=
extension_loaded
(
'apcu'
)
&&
apcu_enabled
();
...
...
@@ -125,10 +125,10 @@ function apc_update_7101() {
}
/**
* Delete the APCu keys
starting with apc_cache_ as they are
no longer used.
* Delete the APCu keys no longer used
for the cache
.
*/
function
apc_update_7102
()
{
_apc_delete_apcu_keys
(
array
(
'apc_cache_'
=>
'
apc_cache_
'
));
_apc_delete_apcu_keys
(
array
(
'apc_cache_'
=>
''
));
}
/**
...
...
@@ -139,17 +139,24 @@ function apc_update_7103() {
}
/**
* Delete the APCu keys
starting with apc_cache:: to create the new keys
.
* Delete the APCu keys
previously used for the cache
.
*/
function
apc_update_7104
()
{
_apc_delete_apcu_keys
(
array
(
'apc_cache::'
=>
''
));
}
/**
* Delete the APCu keys
starting with apc_cache:: to create the new keys
.
* Delete the APCu keys
previously used for the cache
.
*/
function
apc_update_7105
()
{
_apc_delete_apcu_keys
(
'apc_cache::[a-zA-Z0-9-_]{20,}::[a-zA-Z0-9-_]{20,}'
);
_apc_delete_apcu_keys
(
array
(
'apc_cache::[a-zA-Z0-9-_]{20,}::[a-zA-Z0-9-_]{20,}'
=>
''
));
}
/**
* Delete the cache items stored on APCu to avoid duplicate items.
*/
function
apc_update_7106
()
{
_apc_delete_apcu_keys
(
array
(
'apc_cache::'
=>
'apc_cache::[a-zA-Z0-9-_]{20,}::[a-zA-Z0-9-_]{20,}'
));
}
/**
...
...
@@ -159,8 +166,10 @@ function apc_uninstall() {
$apcu_enabled
=
extension_loaded
(
'apcu'
)
&&
apcu_enabled
();
if
(
$apcu_enabled
&&
class_exists
(
'APCUIterator'
))
{
$iterator
=
new
APCUIterator
(
'/^apc_cache::[a-zA-Z0-9-_]{40,46}::[
a-zA-Z0-9-_]{40,46
}/'
,
APC_ITER_KEY
);
$iterator
=
new
APCUIterator
(
'/^apc_cache::[a-zA-Z0-9-_]{40,46}::[
0-9a-f]{2,
}/'
,
APC_ITER_KEY
);
apcu_delete
(
$iterator
);
$iterator
=
new
APCUIterator
(
'/^apc_cache::()/'
,
APC_ITER_KEY
);
}
// Deleted all the persistent variables used by the module.
...
...
This diff is collapsed.
Click to expand it.
apc.test
+
36
−
44
View file @
8794105d
...
...
@@ -851,13 +851,13 @@ class ApcCacheClearTestCase extends ApcCacheBaseTestCase {
if
(
$this
->
assertTrue
(
!
empty
(
$stored
),
$message
))
{
$cleared_cid
=
array_pop
(
$stored
);
$options
=
array
(
'message'
=>
'@bin/@cache_id
h
as
been
removed by cache_clear_all().'
);
$options
=
array
(
'message'
=>
'@bin/@cache_id
w
as removed by cache_clear_all().'
);
cache_clear_all
(
$cleared_cid
,
$bin
);
$this
->
assertNoCacheItem
(
$bin
,
$cleared_cid
,
$options
);
$options
=
array
(
'message'
=>
'@bin/@cache_id
h
as
been not been
removed by cache_clear_all().'
);
$options
=
array
(
'message'
=>
'@bin/@cache_id
w
as
not
removed by cache_clear_all().'
);
foreach
(
$stored
as
$cid
)
{
$this
->
assertCacheItem
(
$bin
,
$cid
,
$options
);
...
...
@@ -891,25 +891,23 @@ class ApcCacheClearTestCase extends ApcCacheBaseTestCase {
$message
=
'New items have been stored in the cache.'
;
if
(
$this
->
assertTrue
(
!
empty
(
$stored
),
$message
))
{
$options
=
array
(
'message'
=>
'@bin/@cache_id
h
as
been not been
removed by cache_clear_all().'
);
$options
=
array
(
'message'
=>
'@bin/@cache_id
w
as
not
removed by cache_clear_all().'
);
cache_clear_all
(
'*'
,
$bin
);
// Since cache_clear_all() has not been called setting its last
// parameter to TRUE, '*' is the literal value for the cache ID. No
// cache item has been stored with that cache ID, so they all must still
// exist.
// Since cache_clear_all() was not called with TRUE as last parameter,
// '*' is the literal value for the cache ID. No cache item is stored
// with that cache ID, so all the cache items still exist.
foreach
(
$stored
as
$cid
)
{
$this
->
assertCacheItem
(
$bin
,
$cid
,
$options
);
}
cache_clear_all
(
'*'
,
$bin
,
TRUE
);
$options
=
array
(
'message'
=>
'@bin/@cache_id
h
as
been
removed by cache_clear_all().'
);
$options
=
array
(
'message'
=>
'@bin/@cache_id
w
as removed by cache_clear_all().'
);
// Since cache_clear_all() has been called setting its last
// parameter to TRUE, '*' matches all the cache IDs stored for the bin.
// All the existing cache IDs are cleared.
// Since cache_clear_all() was called with TRUE as last parameter, all
// the cache items were removed.
foreach
(
$stored
as
$cid
)
{
$this
->
assertNoCacheItem
(
$bin
,
$cid
,
$options
);
}
...
...
@@ -921,58 +919,52 @@ class ApcCacheClearTestCase extends ApcCacheBaseTestCase {
* Tests cache_clear_all() passing TRUE as last parameter.
*/
public
function
testClearWildcard
()
{
$cache_id_prefixes
=
array
(
'clear_first_time_by_wildcard_'
,
'clear_second_time_by_wildcard_'
);
$stored
=
array
();
if
(
$this
->
skipTest
)
{
return
;
}
// This test is temporarily disabled until an issue in the cache back-end
// class has not been fixed.
if
(
!
$this
->
pass
(
'This test is temporarily disabled.'
))
{
if
(
$this
->
assertApcuEmpty
()
&&
$this
->
assertCacheBinsOnApcu
())
{
$bin
=
$this
->
getCacheBins
()[
0
];
if
(
$this
->
assertApcuEmpty
()
&&
$this
->
assertCacheBinsOnApcu
())
{
$bin
=
$this
->
getCacheBins
()[
0
];
foreach
(
array
(
'clear_by_wildcard_'
,
'no_clear_by_wildcard_'
)
as
$prefix
)
{
foreach
(
$this
->
storageData
()
as
$id
=>
$data
)
{
$cid
=
"
$prefix$id
"
;
foreach
(
$cache_id_prefixes
as
$prefix
)
{
foreach
(
$this
->
storageData
()
as
$id
=>
$data
)
{
$cid
=
"
$prefix$id
"
;
cache_set
(
$cid
,
$data
[
'value'
],
$bin
);
cache_set
(
$cid
,
$data
[
'value'
],
$bin
);
if
(
$this
->
assertCacheItem
(
$bin
,
$cid
,
array
(
'value'
=>
$data
[
'value'
])))
{
$stored
[]
=
$cid
;
}
if
(
$this
->
assertCacheItem
(
$bin
,
$cid
,
array
(
'value'
=>
$data
[
'value'
])))
{
$stored
[]
=
$cid
;
}
}
}
$message
=
'New items
have been
stored in the cache.'
;
$message
=
'New items
were
stored in the cache.'
;
if
(
$this
->
assertTrue
(
!
empty
(
$stored
),
$message
))
{
cache_clear_all
(
'clear_by_wildcard_'
,
$bin
);
if
(
$this
->
assertTrue
(
!
empty
(
$stored
),
$message
))
{
cache_clear_all
(
$cache_id_prefixes
[
0
],
$bin
,
TRUE
);
foreach
(
$stored
as
$cid
)
{
// Check the cache ID starts with 'clear_by_wildcard_' and has been
// removed.
if
(
strpos
(
$cid
,
'clear_by_wildcard_'
)
===
0
)
{
$options
=
array
(
'message'
=>
'@bin/@cache_id has been removed by cache_clear_all().'
);
foreach
(
$stored
as
$cid
)
{
if
(
strpos
(
$cid
,
$cache_id_prefixes
[
0
])
===
0
)
{
$options
=
array
(
'message'
=>
'@bin/@cache_id was removed by cache_clear_all().'
);
$this
->
assertNoCacheItem
(
$bin
,
$cid
,
$options
);
}
else
{
$options
=
array
(
'message'
=>
'@bin/@cache_id
h
as not
been
removed by cache_clear_all().'
);
$this
->
assertNoCacheItem
(
$bin
,
$cid
,
$options
);
}
else
{
$options
=
array
(
'message'
=>
'@bin/@cache_id
w
as not removed by cache_clear_all().'
);
$this
->
assertCacheItem
(
$bin
,
$cid
,
$options
);
}
$this
->
assertCacheItem
(
$bin
,
$cid
,
$options
);
}
}
$options
=
array
(
'message'
=>
'@bin/@cache_id
h
as
been
removed by cache_clear_all().'
);
$options
=
array
(
'message'
=>
'@bin/@cache_id
w
as removed by cache_clear_all().'
);
// Since cache_clear_all() has been called setting its last
// parameter to TRUE, '*' matches all the cache IDs stored for the
// bin. All the existing cache IDs are cleared.
foreach
(
$stored
as
$cid
)
{
$this
->
assertNoCacheItem
(
$bin
,
$cid
,
$options
);
}
cache_clear_all
(
$cache_id_prefixes
[
1
],
$bin
,
TRUE
);
foreach
(
$stored
as
$cid
)
{
$this
->
assertNoCacheItem
(
$bin
,
$cid
,
$options
);
}
}
}
...
...
This diff is collapsed.
Click to expand it.
drupal_apc_cache.inc
+
23
−
67
View file @
8794105d
...
...
@@ -51,48 +51,20 @@ class DrupalApcCache implements DrupalCacheInterface {
protected
$modulePrefix
=
'apc_cache'
;
/**
* Converts binary
data
to a hexadecimal representation.
* Converts
a
binary
string
to a hexadecimal representation.
*
* @param mixed $data
* The binary data to convert. If it is an empty string, a random 4-byte
* string is generated.
* @param string $data
* The binary string to convert.
*
* @return string
* The hexadecimal representation of the binary
data
.
* The hexadecimal representation of the binary
string
.
*/
protected
function
binaryToHex
(
$data
)
{
if
(
is_array
(
$data
))
{
if
(
empty
(
$data
))
{
return
unpack
(
"H*"
,
"
\2\5\6
"
)[
1
];
}
return
unpack
(
"H*"
,
"
\0\4\6
"
.
serialize
(
$data
))[
1
];
}
elseif
(
is_bool
(
$data
))
{
return
$data
?
"
\3\0\5\1
"
:
"
\3\1\5\0
"
;
}
elseif
(
is_string
(
$data
))
{
if
(
$data
===
''
)
{
// If an empty string is an acceptable value for the caller, return an
// empty string.
return
''
;
}
return
unpack
(
"H*"
,
"
\0\0\4
$data
"
)[
1
];
}
elseif
(
is_object
(
$data
)
&&
get_class
(
$data
)
===
'stdClass'
)
{
return
unpack
(
"H*"
,
"
\0\4\3
"
.
var_export
((
object
)
(
array
)
$data
,
TRUE
))[
1
];
}
elseif
(
is_object
(
$data
))
{
return
unpack
(
"H*"
,
"
\0\4\2
"
.
var_export
(
$data
,
TRUE
))[
1
];
}
else
{
return
unpack
(
"H*"
,
"
\0\0\1
"
.
var_export
(
$data
,
TRUE
))[
1
];
}
return
unpack
(
'H*'
,
$data
)[
1
];
}
/**
* Sets the
prefix to
use for the
cache bin
.
* Sets the
one of the strings
use
d
for the
APCu storage key
.
*/
protected
function
setBinPrefix
()
{
$default_empty_prefix
=
''
;
...
...
@@ -105,7 +77,7 @@ protected function setBinPrefix() {
if
(
!
apcu_store
(
'apcu_cache::default_prefix'
,
$default_empty_prefix
))
{
// Since it was not possible to store the value to use instead of the
// empty string, set $default_empty_prefix to an empty string.
// empty string, set $default_empty_prefix
back
to an empty string.
$default_empty_prefix
=
''
;
}
}
...
...
@@ -150,24 +122,11 @@ protected function setBinPrefix() {
}
/**
* Adds the database prefix to the bin prefix.
*
* This method checks if the $prefix property is empty and if the global
* $databases variable is set and is an array. If these conditions are met,
* it generates a prefix based on the database connection information.
*
* The generated prefix is an SHA-256 hash of the concatenated values of the
* 'host', 'database', and 'prefix' keys from the 'default' array in the
* 'default' array of the $databases variable.
*
* If the generated prefix is not empty and does not end with '::', the
* '::' string is appended to the prefix.
*
* If the site is in testing mode, the generated prefix is prepended with the
* value returned by drupal_valid_test_ua().
* Sets two of the strings used for the APCu storage key.
*/
protected
function
add
DatabasePrefix
()
{
protected
function
set
DatabasePrefix
()
{
global
$databases
;
$default_empty_prefix
=
''
;
if
(
extension_loaded
(
'apcu'
)
&&
apcu_enabled
())
{
...
...
@@ -177,33 +136,31 @@ protected function addDatabasePrefix() {
$default_empty_prefix
=
drupal_random_bytes
(
8
);
if
(
!
apcu_store
(
'apcu_cache::default_prefix'
,
$default_empty_prefix
))
{
// Since it was not possible to store the value to use instead of the
// empty string, set $default_empty_prefix back to an empty string.
$default_empty_prefix
=
''
;
}
}
}
if
(
isset
(
$databases
)
&&
is_array
(
$databases
))
{
$data
=
''
;
$data
=
array
()
;
if
(
isset
(
$databases
[
'default'
][
'default'
])
&&
is_array
(
$databases
[
'default'
][
'default'
]))
{
if
(
isset
(
$databases
[
'default'
][
'default'
][
'host'
]))
{
$data
.
=
$this
->
binaryToHex
(
$databases
[
'default'
][
'default'
][
'host'
]
)
;
$data
[
'host'
]
=
$databases
[
'default'
][
'default'
][
'host'
];
}
if
(
isset
(
$databases
[
'default'
][
'default'
][
'database'
]))
{
$data
.
=
$this
->
binaryToHex
(
$databases
[
'default'
][
'default'
][
'database'
]
)
;
$data
[
'database'
]
=
$databases
[
'default'
][
'default'
][
'database'
];
}
if
(
isset
(
$databases
[
'default'
][
'default'
][
'prefix'
]))
{
$data
.
=
$this
->
binaryToHex
(
$databases
[
'default'
][
'default'
][
'prefix'
]
)
;
$data
[
'prefix'
]
=
$databases
[
'default'
][
'default'
][
'prefix'
];
}
}
if
(
empty
(
$data
))
{
$data
=
$this
->
binaryToHex
(
$default_empty_prefix
);
}
$this
->
prefixes
[
2
]
=
$data
;
$this
->
prefixes
[
2
]
=
$this
->
binaryToHex
(
serialize
(
$data
));
}
if
(
$test_prefix
=
drupal_valid_test_ua
())
{
...
...
@@ -218,10 +175,11 @@ public function __construct($bin) {
$this
->
bin
=
$bin
;
$this
->
setBinPrefix
();
$this
->
add
DatabasePrefix
();
$this
->
set
DatabasePrefix
();
$data
=
$this
->
prefixes
[
0
]
.
$this
->
bin
;
$this
->
binPrefix
=
drupal_base64_encode
(
hash
(
'sha256'
,
$data
,
TRUE
));
$data
=
$this
->
prefixes
[
0
]
.
$this
->
bin
.
$this
->
prefixes
[
1
];
$data
=
$this
->
prefixes
[
2
]
.
hash
(
'sha256'
,
$data
,
TRUE
);
$this
->
binPrefix
=
drupal_base64_encode
(
$data
);
}
/**
...
...
@@ -237,10 +195,8 @@ public function __construct($bin) {
protected
function
keyName
(
$cid
=
NULL
)
{
$key_name
=
$this
->
modulePrefix
.
'::'
.
$this
->
binPrefix
.
'::'
;
if
(
!
is_null
(
$cid
))
{
$data
=
$this
->
prefixes
[
1
]
.
$this
->
bin
.
$this
->
prefixes
[
2
]
.
$cid
;
$data
=
drupal_base64_encode
(
hash
(
'sha256'
,
$data
,
TRUE
));
$key_name
.
=
$data
;
if
(
!
is_null
(
$cid
)
&&
$cid
!=
''
)
{
$key_name
.
=
$this
->
binaryToHex
(
$cid
);
}
return
$key_name
;
...
...
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
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!
Save comment
Cancel
Please
register
or
sign in
to comment