I see 5 output each time when I run this code:
<?php
$v = 5;
apc_store('vwxyz',$v,3);
$before = apc_fetch('vwxyz');
sleep(5);
$after = apc_fetch('vwxyz'); //should be false
echo $before;
echo "<br>";
echo $after;
$later = apc_fetch('vwxyz'); //OK this should definitely be false
echo "<br>";
echo $later;
Shouldn't the cached entry be cleared from the cache and return false to apc_fetch()? The user_ttl setting is 2 for APC. I'm still trying to figure out what user_ttl does (the documentation is quite cryptic).
From the manual:
Time To Live; store var in the cache for ttl seconds. After the ttl
has passed, the stored variable will be expunged from the cache (on
the next request). If no ttl is supplied (or if the ttl is 0), the
value will persist until it is removed from the cache manually, or
otherwise fails to exist in the cache (clear, restart, etc.).
So it says that the item gets removed from the cache after the TTL on the next request. So the item isn't removed from cache until your next request which is why you keep getting 5.
Related
I have a simple script that counts from 1 to 5000 with a for loop. It flushes output in real time to browser and shows a progress bar with %.
What I have: If I leave the page, the process interrupts. If I come back, it starts from 0.
What I want to achieve: If I leave the page, the process continues and, If I come back , it shows the right percentage.
Example: I run the process, it counts till 54, I leave the page for 10 seconds, when I come back it shows me 140 and continues to flush.
Is it possible?
I would suggest you to use server workers - scripts which are intended to run independently from webserver context.
The most common way of doing it - usage of message queues (RabbitMQ, Qless, etc). Event should be initiated by the script in web context, but the actual task should be executed by queue listener in a different context.
What you have asked seems quite simple to do with a session. (Purely assuming on the use case given). This is not running any process in the background, it just simply keep track of the time and show the progress. That's why I said "based on what you asked". If you want to keep track of any real background tasks, then I believe the case would be totally different, and you will have to change the wordings of your question as well ;)
Something like this would do.
<?php
session_start();
$s = &$_SESSION;
$sleep = 1; //seconds
//check if we have a value set in session before, if not set default = 0.
if(!isset($s['last'])){
$s['last'] = 0;
}
//check if we have a last time set in session before. if not set a default = curret time.
if(!isset($s['time'])){
$s['time'] = time();
}
//get the idle time of the user.
$idle = time() - $s['time'];
//start the loop..and set starting point.
$start = $s['last'] + ($idle / $sleep);
for( $i = $start; $i < 100; $i++){
echo $i . '<br />';
$s['last']++;
$s['time'] = time();
flush();
sleep($sleep);
}
Hope it helps!!
I'm using zend_shm_cache functions as a fast storage of variables. My problem is that the cache doesn't seem to get cleared after TTL is over. Example:
zend_shm_cache_store( $key = 'test3', 'value', 2 );
foreach( range(1,5) as $timer ){
sleep( 1 );
echo $timer.' - ' .zend_shm_cache_fetch( $key ).'<br/>';
}
Returns:
1 - value
2 -
3 - value
4 - value
5 - value
I would expect the cache to be empty after second second. Can you explain what's happening or propose a solution?
I got the answer in the documentation of APCU:
After the ttl has passed, the stored variable will be expunged from
the cache (on the next request).
As my code runs in only one request the cache is never deleted even when its time has expired.
When user closes the browser and the session gets killed, I need to update my database of current users. So I have set up a simple cron job that deletes the row.
DELETE FROM visit WHERE unix_timestamp(time)<unix_timestamp(now()-600) and sessionid <>(LIST OF SESSIONS ..need help)
I can get the session files thanks to this code provided here on StackOverflow(thanks)
$sessions = array();
$path = realpath(session_save_path());
$files = array_diff(scandir($path), array('.', '..'));
foreach ($files as $file)
{
$sessions[$file] = unserialize(file_get_contents($path . '/' . $file));
}
echo '<pre>';
print_r($sessions);
echo '</pre>';
My question is are those files returned by the second half of the code the list of active sessions? Basically I'm trying to verify that all the rows that will be deleted will contain sessions that are not part of the "ACTIVE' list supposedly returned by unserialize(file_get_contents($path . '/' . $file));
I have read that another approach would be to check the last activity timestamp (if it's greater than say 10 minutes). But I don't know how to record "last activities' onto the database.
Thanks
Whoa!
Reference counting is not a good way to keep track of sessions - particularly if the sessions are stored in a completely separate substrate. Trying to maintain a list of the active sessions seperate from the active session list is a redundancy.
I'd start again. Use a db-bound session handler. It's up to you if you allow sessions older than gc_maxlifetime to be reloaded (default handler does allow this).
Then (e.g. treating expired sessions as no longer active):
SELECT COUNT(*)
FROM sessions
WHERE last_updated>(UNIX_TIMESTAMP() + ' . ini_get('gc_maxlifetime') . ')
My question is are those files returned by the second half of the code the list of active sessions?
As per above, that depends on your definition of active. Some of these will be older than gc_maxlifetime - but (using the default handler) will still be usable.
If you're not bothered about reuse of stale sessions/reuse of the same login details, counting the files in session_save_path() will probably be faster - but the DB approach is more accurate and flexible.
I have a fairly expensive server call that I need to cache for 30 seconds. It seems however that I can not get the cache to expire.
In the code below, after the first time it caches, it will never get past $return->cache_data, even after the time() + 30 seconds.
Note, I can even print $cache->expire and it is definitely set to a time past 30 seconds ago and never updates.
I've manually cleared cache many times to confirm I get the same results.
Does anything look wrong with this?
function mymodule_get_something($id) {
// set the unique cache id
$cid = 'id-'. $id;
// return data if there's an un-expired cache entry
// *** $cache ALWAYS gets populated with my expired data
if ($cache = cache_get($cid, 'cache_mymodule')) {
return $cache->data;
}
// set my super expensive data call here
$something = array('Double Decker Taco', 'Burrito Supreme');
// set the cache to expire in 30 seconds
cache_set($cid, $something, 'cache_mymodule', time() + 30);
// return my data
return $something;
}
There's nothing wrong with your code as such, I think the problem is in how cache_set behaves. From the docs page, passing a UNIX timestamp:
Indicates that the item should be kept at least until the given time, after which it behaves like CACHE_TEMPORARY.
CACHE_TEMPORARY behaves like this:
Indicates that the item should be removed at the next general cache wipe.
My best guess is that because you're not implicitly forcing that general cache wipe (using cache_clear_all()) the cache object will persist.
I think a simple way around it would just be to manually test the expiry time after your cache check, and let it fall through to re-setting that cache object if it has expired:
if ($cache = cache_get($cid, 'cache_mymodule')) {
if ($cache->expire > REQUEST_TIME) {
return $cache->data;
}
}
Time to time, I receive this strange warning message. It is usually gone on page reload. What does that mean. I googled but to no avail.
Warning: include(): GC cache entry '/.../...class.php' (dev=2049 ino=37120489) was on gc-list for 3840 seconds in /.../...class.php on line 111
Definitely this issue goes from APC, source code from package apc-3.1.6-r1. When item is inserted into user cache or file cache, this function is called.
static void process_pending_removals(apc_cache_t* cache TSRMLS_DC)
{
slot_t** slot;
time_t now;
/* This function scans the list of removed cache entries and deletes any
* entry whose reference count is zero (indicating that it is no longer
* being executed) or that has been on the pending list for more than
* cache->gc_ttl seconds (we issue a warning in the latter case).
*/
if (!cache->header->deleted_list)
return;
slot = &cache->header->deleted_list;
now = time(0);
while (*slot != NULL) {
int gc_sec = cache->gc_ttl ? (now - (*slot)->deletion_time) : 0;
if ((*slot)->value->ref_count <= 0 || gc_sec > cache->gc_ttl) {
slot_t* dead = *slot;
if (dead->value->ref_count > 0) {
switch(dead->value->type) {
case APC_CACHE_ENTRY_FILE:
apc_warning("GC cache entry '%s' (dev=%d ino=%d) was on gc-list for %d seconds" TSRMLS_CC,
dead->value->data.file.filename, dead->key.data.file.device, dead->key.data.file.inode, gc_sec);
break;
case APC_CACHE_ENTRY_USER:
apc_warning("GC cache entry '%s'was on gc-list for %d seconds" TSRMLS_CC, dead->value->data.user.info, gc_sec);
break;
}
}
*slot = dead->next;
free_slot(dead TSRMLS_CC);
}
else {
slot = &(*slot)->next;
}
}
}
From APC configuration ( http://cz.php.net/manual/en/apc.configuration.php#ini.apc.gc-ttl )
apc.gc_ttl integer
The number of seconds that a cache entry may remain on the garbage-collection list. This value provides a fail-safe in the event that a server process dies while executing a cached source file; if that source file is modified, the memory allocated for the old version will not be reclaimed until this TTL reached. Set to zero to disable this feature.
We get messages "GC cache entry '%s' (dev=%d ino=%d) was on gc-list for %d seconds" or "GC cache entry '%s'was on gc-list for %d seconds" in this condition:
(gc_sec > cache->gc_ttl) && (dead->value->ref_count > 0)
First condition means, item was deleted later then apc.gc_ttl seconds ago and its still in garbage collector list. Seconds condition means, item is still referenced.
e.g. when process unexpectedly died, reference is not decreased. First apc.ttl seconds is active in APC cache, then is deleted (there isn't next hit on this item). Now item is on garbage collector list (GC) and apc.gc_ttl timeout is running. When apc.gc_ttl is less then (now - item_deletion_time), warning is written and item is completely flushed.
Try to check your logs (web server, php, system/kernel) to critical errors, e.g. php, web server segfault.