PHP Memcached Session Locking Enable - php

I use "memcached" to store php sessions.
It is important, that request must be synchronously (to avoid duplicate transactions or operations), but while using "memcached" session, "session locking" not works.
is some method to lock "memcached" session until one request will executed?

There's nothing built in no, but you can write stuff yourself to make your code atomic.
$key = 'lockable_key_name';
$lockkey = $key.'##LOCK';
if($memcached->add($lockkey, '', 60)) {
$storedvalue = $memcached->get($key);
// do something with $storedvalue
$memcached->set($key, $newvalue);
// release
$memcached->delete($lockkey);
}
In your code you could check for the lock by doing:
if(!$memcached->get($lockkey)) {
// then do something
}
If the get method returns false then there's no lock, or the operation has hung and passed the 60 second timeout specified in the add call above.

Since you were asking for credible/official sources:
The memcached extension supports session locking since version 3.0.4, according to the changelog document on the PECL extension page: http://pecl.php.net/package-info.php?package=memcache&version=3.0.4
If you happen to run an earlier version (it means that your version of the memcached extension is more than 4 years old), you are out of luck and should upgrade.

Maybe try something like $(field_name)_is_locked = true when you start then when you are done $(field_name)_is_locked = false and pass the variable to the server when you update it.

Related

Use PHP semaphore in the same script [duplicate]

How to make functions in PHP synchronized so that same function won't be executed concurrently ? 2nd user must wait till 1st user is done with the function. Then 2nd user can execute the function.
Thanks
This basically comes down to setting a flag somewhere that the function is locked and cannot be executed until the first caller returns from that function.
This can be done in a number of ways:
use a lock file (first function locks a file name "f.lok", second function checks if the lock file exists and executes or doesn't based on that evaluation)
set a flag in the database (not recomended)
use semaphores as #JvdBerg suggested (the fastest)
When coding concurrent application always beware of race conditions and deadlocks!
UPDATE
using semaphores (not tested):
<?php
define('SEM_KEY', 1000);
function noconcurrency() {
$semRes = sem_get(SEM_KEY, 1, 0666, 0); // get the resource for the semaphore
if(sem_acquire($semRes)) { // try to acquire the semaphore. this function will block until the sem will be available
// do the work
sem_release($semRes); // release the semaphore so other process can use it
}
}
PHP needs to be compiled with sysvsem support in order to use sem_* functions
Here's a more in depth tutorial for using semaphores in PHP:
http://www.re-cycledair.com/php-dark-arts-semaphores
You are looking for a Semaphore
Bear in mind that using a semaphore (or any other blocking mechanism) can have serious peformance issues, as the requests can not be handled while the semaphore is up.
off the top of my head:
function checks if a database field called isFunctionRunning is equal 1. if not start executing
you update the database field called isFunctionRunning to 1
function does magic here
you update the database field called isFunctionRunning to 0
but somehow i think what you are trying to do is "wrong" and can be achieved in another way. could help if you said more details
edit: wasn't aware of php semaphores, the answer above will be way faster.
You can use the "flock" (file locking) function with the "LOCK_EX" (exclusive lock) flag to create a custom "synchronized" function that accepts a handler to be synchronized.
You may may found the code here.
I hope this helps.

Why does Memcached add() always succeed, regardless of expire time?

I'm adding a key using Memcached like so:
$valueToStore = time(); // some number
$success = $memcached->add( 'test_key', $valueToStore, 20 ); // cache for 20 seconds
But it's always succeeding when I call it in a different session, even before 20 seconds have passed. According to the docs at http://php.net/manual/en/memcached.add.php, it should be returning FALSE until the key expires (because the key already exists).
I'm running on a single development server with plenty of free cache space. Any idea what might be happening?
php -v returns: PHP 5.5.9-1ubuntu4.3
memcached version 2.1.0
libmemcached version 1.0.8.
You need to be distinct if you are using the Memcache class or the Memcached class. Your cache design is a bit strange. You should be checking the cache to first see if the item is there. If the item is not then store it. Also Memcache has some strange behavior on using the boolen type as the third argument. You should MEMCACHE_COMPRESSED. I think you are using Memcache.
To illustrate how to fix your problem:
$in_cache = $memcached->get('test_key');
if($in_cache)
return $in_cache;
else
$valueToStore = time();
$memcached->add('test_key', $valueToStore, MEMCACHE_COMPRESS, 20);

PHP virtual resource access serialization with automatic release

I would like to implement a quick and efficient serialization mechanism between PHP requests for virtual named resources that would unlock when the script is finished, either normally or due to error. I had eaccelerator_lock() and its corresponding eaccelerator_unlock() in the past, but eaccelerator doesn't implement that function anymore. What I want to do is something like:
lock_function("my-named-resource");
..
my_might_abort_abruptly_function();
..
unlock_function("my-named-resource");
Other PHP scripts calling lock_function() with the exact same parameter should block until this script calls unlock_function() or aborts. The resource name is unknown before the processing (it's a generated string) and can't be constrained to a small set (i.e., the locking mechanism should have good granularity). I would like to avoid try/catch code, because there are circunstances in which catch is not called. Also, any mechanism depending on manual usleep() spinning (instead of native OS blocking) should be avoided.
Mine is the only running application in the server. The system is a CentOS 6 Linux with PHP 5.3.3, Apache 2.2.15 and I have full control over it.
I explored the following alternatives:
semaphores: they are not well implemented in PHP; Linux allows arrays of thousands, while PHP only allocates one per id.
flock(): my resources are virtual, and flock() would only lock whole/real/existing files; I'd need to pre-create thousands of files and choose one to lock with a hash function. The granularity would depend on the number of files.
dio_fcntl(): I could attempt to reproduce the idea of flock() with a single file and fcntl(F_SETLK). This would have the advantage of a good granularity without the need of many files; the file could even be zero bytes long! (F_SETLK can lock beyond the end of the file). Alas! The problem is that nowhere in the documentation says that dio_fcntl() will release resources when the script terminates.
database lock: I could implement some key locking in a database with good key locking granularity, althought this is too database dependent. It would not be so quick either.
implement my own PHP extension: I'd really like to avoid that path.
The thing is, I think someone somewhere should have thought of this before me. What would be a good choice? Is there another solution I'm not seeing?
Thanks in advance. Guillermo.
You can always go old school and touch a file when your script starts and remove it when complete.
You could register_shutdown_function to remove the file.
The existence or absence of the file would indicate the locked state of the resource.
It turns out dio_open() does release the resources upon script termination. So I ended writing up the following functions:
$lockfile = $writable_dir."/serialized.lock";
function serialize_access($name)
{
$f = serialize_openfile();
if( !$f ) return false;
$h = serialize_gethash($name);
return dio_fcntl($f, F_SETLKW, array("whence"=>SEEK_SET,"start"=>$h, "length"=>1, "type"=>F_WRLCK)) >= 0;
}
function serialize_release($name)
{
$f = serialize_openfile();
if( !$f ) return false;
$h = serialize_gethash($name);
#dio_fcntl($f, F_SETLK, array("whence"=>SEEK_SET,"start"=>$h, "length"=>1, "type"=>F_UNLCK));
}
function serialize_gethash($name)
{
// Very good granularity (2^31)
return crc32($name) & 0x7fffffff;
}
function serialize_openfile()
{
global $lockfile, $serialize_file;
if( !isset($serialize_file) )
{
$serialize_file = false;
if( extension_loaded("dio") )
{
$serialize_file = #dio_open($lockfile,O_RDWR);
if( $serialize_file )
{
// Do not attempt to create the file with dio_open()
// because the file permissions get all mangled.
$prev = umask(0);
$temp = fopen($lockfile,"a");
if( $temp )
{
$serialize_file = #dio_open($lockfile,O_RDWR);
fclose($temp);
}
umask($prev);
}
}
}
return $serialize_file;
}
It seems to work very well.
implement my own PHP extension
You might want to check ninja-mutex library which does exactly what you want

cakephp comet usleep blocks everything

Below is the code that i am end up with using successful comet implementation.
$lastmodif = isset($this->params['form']['timestamp']) ? $this->params['form']['timestamp'] : 0;
$currentmodif = $already_updated[0]['Update']['lastmodified'];
while ($currentmodif <= $lastmodif)
{
usleep(5000000);
clearstatcache();
$already_updated_new = $this->Update->find('all',array
(
'conditions' => array
(
'Update.receiver_id' => $this->Auth->user('id'),
'Update.table_name' => "request_responses"
)
));
$currentmodif = $already_updated_new[0]['Update']['lastmodified'];
}
$already_updated[0]['Update']['lastmodified'] is the query result for get last updated timestamp of table.
In above code $lastmodif and $currentmodif is the timestamp that is being passed after every successful comet response.
But now problem is that when i am clicking on other links on same page nothing happens but after wait for so long its redirecting.
i think usleep is blocking other HTTP request.
i am using mysql and cakephp please guys guide me what should i do in order to solve this issue.
I have tried to flush when page is called but it shows can not modify header error as output is already sent.
Thanks.
I've met similar situation several times. It looks like Session is blocked by your sleeping script.
How to solve it in CakePHP:
call session_write_close(); at the start of your script.
There is no way to do that via Cake's Session Component or Helper
Note: If something inside script uses session - Cake will reopen session and hang all requests that use same session again. In this case you will need to close session before sleep or before any operations that take a lot of time to be finished
If your script uses sessions then you could notice such behavior. PHP locks the session file until the script completes.
This means that once a script starts a session, any other script that attempts to start a session using same session id is blocked until the previous script releases the lock (or terminates).
The workaround for this is to unlock the session before any lengthy process:
call session_start()
read/write any session variables
call session_write_close()
do lengthy processing
Yes, the usleep is blocking further requests. Depending on your hosting environment, you probably have a limited amount of processes available. I assume you have multiple users in your chat -> they all issue blocking processes unless none is available, that's why your other "links" timeout.
I would suggest to implement the wait on the client-browser side, eg
setTimeout(function() {
fetchAndPrintTheNewChats();
}, 50000000);
Any approach to do this within your PHP code will result in the same problem.
Can you share what version of cakephp you are using in case someone else who comes along might have a solution?
Cake has a session component: http://book.cakephp.org/2.0/en/core-libraries/components/sessions.html
and a session helper: http://book.cakephp.org/2.0/en/core-libraries/helpers/session.html

Synchronized functions using PHP

How to make functions in PHP synchronized so that same function won't be executed concurrently ? 2nd user must wait till 1st user is done with the function. Then 2nd user can execute the function.
Thanks
This basically comes down to setting a flag somewhere that the function is locked and cannot be executed until the first caller returns from that function.
This can be done in a number of ways:
use a lock file (first function locks a file name "f.lok", second function checks if the lock file exists and executes or doesn't based on that evaluation)
set a flag in the database (not recomended)
use semaphores as #JvdBerg suggested (the fastest)
When coding concurrent application always beware of race conditions and deadlocks!
UPDATE
using semaphores (not tested):
<?php
define('SEM_KEY', 1000);
function noconcurrency() {
$semRes = sem_get(SEM_KEY, 1, 0666, 0); // get the resource for the semaphore
if(sem_acquire($semRes)) { // try to acquire the semaphore. this function will block until the sem will be available
// do the work
sem_release($semRes); // release the semaphore so other process can use it
}
}
PHP needs to be compiled with sysvsem support in order to use sem_* functions
Here's a more in depth tutorial for using semaphores in PHP:
http://www.re-cycledair.com/php-dark-arts-semaphores
You are looking for a Semaphore
Bear in mind that using a semaphore (or any other blocking mechanism) can have serious peformance issues, as the requests can not be handled while the semaphore is up.
off the top of my head:
function checks if a database field called isFunctionRunning is equal 1. if not start executing
you update the database field called isFunctionRunning to 1
function does magic here
you update the database field called isFunctionRunning to 0
but somehow i think what you are trying to do is "wrong" and can be achieved in another way. could help if you said more details
edit: wasn't aware of php semaphores, the answer above will be way faster.
You can use the "flock" (file locking) function with the "LOCK_EX" (exclusive lock) flag to create a custom "synchronized" function that accepts a handler to be synchronized.
You may may found the code here.
I hope this helps.

Categories