Page Menu
Home
c4science
Search
Configure Global Search
Log In
Files
F97171511
PhutilKeyValueCacheOnDisk.php
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Subscribers
None
File Metadata
Details
File Info
Storage
Attached
Created
Fri, Jan 3, 03:51
Size
4 KB
Mime Type
text/x-php
Expires
Sun, Jan 5, 03:51 (2 d)
Engine
blob
Format
Raw Data
Handle
23344011
Attached To
rPHU libphutil
PhutilKeyValueCacheOnDisk.php
View Options
<?php
/**
* Interface to a disk cache. Storage persists across requests.
*
* This cache is very slow compared to caches like APC. It is intended as a
* specialized alternative to APC when APC is not available.
*
* This is a highly specialized cache and not appropriate for use as a
* generalized key-value cache for arbitrary application data.
*
* Also note that reading and writing keys from the cache currently involves
* loading and saving the entire cache, no matter how little data you touch.
*
* @task kvimpl Key-Value Cache Implementation
* @task storage Cache Storage
*/
final
class
PhutilKeyValueCacheOnDisk
extends
PhutilKeyValueCache
{
private
$cache
=
array
();
private
$cacheFile
;
private
$lock
;
private
$wait
=
0
;
/* -( Key-Value Cache Implementation )------------------------------------- */
public
function
isAvailable
()
{
return
true
;
}
/**
* Set duration (in seconds) to wait for the file lock.
*/
public
function
setWait
(
$wait
)
{
$this
->
wait
=
$wait
;
return
$this
;
}
public
function
getKeys
(
array
$keys
)
{
$now
=
time
();
$results
=
array
();
$reloaded
=
false
;
foreach
(
$keys
as
$key
)
{
// Try to read the value from cache. If we miss, load (or reload) the
// cache.
while
(
true
)
{
if
(
isset
(
$this
->
cache
[
$key
]))
{
$val
=
$this
->
cache
[
$key
];
if
(
empty
(
$val
[
'ttl'
])
||
$val
[
'ttl'
]
>=
$now
)
{
$results
[
$key
]
=
$val
[
'val'
];
break
;
}
}
if
(
$reloaded
)
{
break
;
}
$this
->
loadCache
(
$hold_lock
=
false
);
$reloaded
=
true
;
}
}
return
$results
;
}
public
function
setKeys
(
array
$keys
,
$ttl
=
null
)
{
if
(
$ttl
)
{
$ttl_epoch
=
time
()
+
$ttl
;
}
else
{
$ttl_epoch
=
null
;
}
$dicts
=
array
();
foreach
(
$keys
as
$key
=>
$value
)
{
$dict
=
array
(
'val'
=>
$value
,
);
if
(
$ttl_epoch
)
{
$dict
[
'ttl'
]
=
$ttl_epoch
;
}
$dicts
[
$key
]
=
$dict
;
}
$this
->
loadCache
(
$hold_lock
=
true
);
foreach
(
$dicts
as
$key
=>
$dict
)
{
$this
->
cache
[
$key
]
=
$dict
;
}
$this
->
saveCache
();
return
$this
;
}
public
function
deleteKeys
(
array
$keys
)
{
$this
->
loadCache
(
$hold_lock
=
true
);
foreach
(
$keys
as
$key
)
{
unset
(
$this
->
cache
[
$key
]);
}
$this
->
saveCache
();
return
$this
;
}
public
function
destroyCache
()
{
Filesystem
::
remove
(
$this
->
getCacheFile
());
return
$this
;
}
/* -( Cache Storage )------------------------------------------------------ */
/**
* @task storage
*/
public
function
setCacheFile
(
$file
)
{
$this
->
cacheFile
=
$file
;
return
$this
;
}
/**
* @task storage
*/
private
function
loadCache
(
$hold_lock
)
{
if
(
$this
->
lock
)
{
throw
new
Exception
(
'Trying to loadCache() with a lock!'
);
}
$lock
=
PhutilFileLock
::
newForPath
(
$this
->
getCacheFile
().
'.lock'
);
try
{
$lock
->
lock
(
$this
->
wait
);
}
catch
(
PhutilLockException
$ex
)
{
if
(
$hold_lock
)
{
throw
$ex
;
}
else
{
$this
->
cache
=
array
();
return
;
}
}
try
{
$this
->
cache
=
array
();
if
(
Filesystem
::
pathExists
(
$this
->
getCacheFile
()))
{
$cache
=
unserialize
(
Filesystem
::
readFile
(
$this
->
getCacheFile
()));
if
(
$cache
)
{
$this
->
cache
=
$cache
;
}
}
}
catch
(
Exception
$ex
)
{
$lock
->
unlock
();
throw
$ex
;
}
if
(
$hold_lock
)
{
$this
->
lock
=
$lock
;
}
else
{
$lock
->
unlock
();
}
}
/**
* @task storage
*/
private
function
saveCache
()
{
if
(!
$this
->
lock
)
{
throw
new
Exception
(
'Call loadCache($hold_lock=true) before saveCache()!'
);
}
// We're holding a lock so we're safe to do a write to a well-known file.
// Write to the same directory as the cache so the rename won't imply a
// copy across volumes.
$new
=
$this
->
getCacheFile
().
'.new'
;
Filesystem
::
writeFile
(
$new
,
serialize
(
$this
->
cache
));
Filesystem
::
rename
(
$new
,
$this
->
getCacheFile
());
$this
->
lock
->
unlock
();
$this
->
lock
=
null
;
}
/**
* @task storage
*/
private
function
getCacheFile
()
{
if
(!
$this
->
cacheFile
)
{
throw
new
Exception
(
'Call setCacheFile() before using a disk cache!'
);
}
return
$this
->
cacheFile
;
}
}
Event Timeline
Log In to Comment