Skip to content
This repository has been archived by the owner on Jan 5, 2022. It is now read-only.

Repush to 2.1.1 with compatibility and bug fixes #46

Merged
merged 14 commits into from
May 4, 2014
Merged
2 changes: 1 addition & 1 deletion Core/Daemon.php
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@ public static function getInstance()
try
{
$o = new static;
$o->getopt();
$o->setup_plugins();
$o->setup_workers();
$o->check_environment();
Expand Down Expand Up @@ -240,7 +241,6 @@ protected function __construct()
$this->set('filename', $argv[0]);
$this->set('start_time', time());
$this->pid(getmypid());
$this->getopt();
}

/**
Expand Down
24 changes: 12 additions & 12 deletions Core/Lib/Memcache.php
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ public function ns($namespace = null)
* @param integer $timeout_override The retry timeout in seconds
* @return mixed The value from Memcache or False
*/
public function getWithRetry($key, $flags = false, $timeout_override = false)
public function getWithRetry($key, $timeout_override = false)
{
if ($timeout_override)
$max_tries = intval($timeout_override / 0.10);
Expand All @@ -76,7 +76,7 @@ public function getWithRetry($key, $flags = false, $timeout_override = false)

for ($i=0; $i<$max_tries; $i++)
{
$value = $this->get($key, $flags);
$value = $this->get($key);
if(false == empty($value))
return $value;

Expand All @@ -94,7 +94,7 @@ public function getWithRetry($key, $flags = false, $timeout_override = false)
* @param integer $expire
* @return boolean
*/
public function set($key, $var, $flags = null, $expire = null)
public function set($key, $var, $expire = 0)
{
if ($this->auto_retry)
$max_tries = intval($this->auto_retry_timeout / 0.10);
Expand All @@ -106,7 +106,7 @@ public function set($key, $var, $flags = null, $expire = null)

for ($i=0; $i<$max_tries; $i++)
{
if(parent::set($this->key($key), $var, $flags, $expire))
if(parent::set($this->key($key), $var, $expire))
return true;

usleep(100000);
Expand All @@ -121,29 +121,29 @@ public function set($key, $var, $flags = null, $expire = null)
* @param string $flags
* @return mixed
*/
public function get($key, $flags = null)
public function get($key)
{
return parent::get($this->key($key), $flags);
return parent::get($this->key($key));
}

public function decrement($key, $value = 1)
public function decrement($key, $offset = 1)
{
return parent::decrement($this->key($key), $value);
return parent::decrement($this->key($key), $offset);
}

public function increment($key, $value = 1)
public function increment($key, $offset = 1)
{
return parent::increment($this->key($key), $value);
return parent::increment($this->key($key), $offset);
}

public function delete($key)
{
return parent::delete($this->key($key));
}

public function replace($key, $var, $flags = null, $expire = null)
public function replace($key, $var, $expire = 0)
{
return parent::replace($this->key($key), $var, $flags, $expire);
return parent::replace($this->key($key), $var, $expire);
}

/**
Expand Down
34 changes: 6 additions & 28 deletions Core/Lock/File.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class Core_Lock_File extends Core_Lock_Lock implements Core_IPlugin

protected $filename;

public function __construct(Core_Daemon $daemon, Array $args = array())
public function __construct(Core_Daemon $daemon, array $args = array())
{
parent::__construct($daemon, $args);
if (isset($args['path']))
Expand All @@ -40,52 +40,30 @@ public function setup()
public function teardown()
{
// If the lockfile was set by this process, remove it. If filename is empty, this is being called before setup()
if (!empty($this->filename) && $this->pid == @file_get_contents($this->filename))
if (!empty($this->filename) && $this->pid == $this->get())
@unlink($this->filename);
}

public function check_environment(Array $errors = array())
public function check_environment(array $errors = array())
{
if (is_writable($this->path) == false)
if (!is_writable($this->path))
$errors[] = 'Lock File Path ' . $this->path . ' Not Writable.';

return $errors;
}

public function set()
protected function set()
{
$lock = $this->check();

if ($lock)
throw new Exception('Core_Lock_File::set Failed. Additional Lock Detected. PID: ' . $lock);

// The lock value will contain the process PID
file_put_contents($this->filename, $this->pid);

touch($this->filename);
}

protected function get()
{
if (file_exists($this->filename) == false)
if (!file_exists($this->filename))
return false;

$lock = file_get_contents($this->filename);

// If we're seeing our own lock..
if ($lock == $this->pid)
return false;

// If the process that wrote the lock is no longer running
$cmd_output = `ps -p $lock`;
if (strpos($cmd_output, $lock) === false)
return false;

// If the lock is expired
clearstatcache();
if ((filemtime($this->filename) + $this->ttl + Core_Lock_Lock::$LOCK_TTL_PADDING_SECONDS) < time())
return false;

return $lock;
}
}
56 changes: 33 additions & 23 deletions Core/Lock/Lock.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@
*/
abstract class Core_Lock_Lock implements Core_IPlugin
{
public static $LOCK_TTL_PADDING_SECONDS = 2.0;
public static $LOCK_UNIQUE_ID = 'daemon_lock';
public static $LOCK_UNIQUE_ID = 'pid';

/**
* The pid of the current daemon -- Set automatically by the constructor.
Expand All @@ -24,30 +23,19 @@ abstract class Core_Lock_Lock implements Core_IPlugin
*/
public $daemon_name;

/**
* This is added to the const LOCK_TTL_SECONDS to determine how long the lock should last -- any lock provider should be
* self-expiring using these TTL's. This is done to minimize likelihood of errant locks being left behind after a kill or crash that
* would have to be manually removed.
*
* @var float Number of seconds the lock should be active -- padded with Core_Lock_Lock::LOCK_TTL_PADDING_SECONDS
*/
public $ttl = 0;

/**
* The array of args passed-in at instantiation
* @var Array
*/
protected $args = array();

public function __construct(Core_Daemon $daemon, Array $args = array())
public function __construct(Core_Daemon $daemon, array $args = array())
{
$this->pid = getmypid();
$this->daemon_name = get_class($daemon);
$this->ttl = $daemon->loop_interval();
$this->args = $args;

$daemon->on(Core_Daemon::ON_INIT, array($this, 'set'));
$daemon->on(Core_Daemon::ON_PREEXECUTE, array($this, 'set'));
$daemon->on(Core_Daemon::ON_INIT, array($this, 'run'));

$that = $this;
$daemon->on(Core_Daemon::ON_PIDCHANGE, function ($args) use ($that) {
Expand All @@ -61,7 +49,7 @@ public function __construct(Core_Daemon $daemon, Array $args = array())
* @abstract
* @return void
*/
abstract public function set();
abstract protected function set();

/**
* Read the lock from whatever shared medium it's written to.
Expand All @@ -76,18 +64,40 @@ abstract protected function get();

/**
* Check for the existence of a lock.
* Cache results of get() check for 1/10 a second.
*
* @return bool|int Either false or the PID of the process that has set the lock
*/
public function check()
protected function check()
{
static $get = false;
static $get_time = false;
$pid = $this->get();

$get = $this->get();
$get_time = microtime(true);
// pid should be a positive number
if (!$pid)
return false;

// If we're seeing our own lock..
if ($pid == $this->pid)
return false;

return $get;
// If the process that wrote the lock is no longer running
$cmd_output = `ps -p $pid`;
if (strpos($cmd_output, $pid) === false)
return false;

return $pid;
}

/**
* Implements main plugin logic - die if lock exists or create it otherwise.
*
* @return null
*/
public function run()
{
$lock = $this->check();
if ($lock)
throw new Exception(get_class($this) . '::' . __FUNCTION__ . ' failed. Existing lock detected from PID: ' . $lock);

$this->set();
}
}
36 changes: 10 additions & 26 deletions Core/Lock/Memcached.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,6 @@ class Core_Lock_Memcached extends Core_Lock_Lock implements Core_IPlugin
*/
public $memcache_servers = array();

public function __construct()
{
$this->pid = getmypid();
}

public function setup()
{
// Connect to memcache
Expand All @@ -40,46 +35,35 @@ public function setup()
public function teardown()
{
// If this PID set this lock, release it
$lock = $this->memcache->get(Core_Lock_Lock::$LOCK_UNIQUE_ID);
if ($lock == $this->pid)
if ($this->get() == $this->pid)
$this->memcache->delete(Core_Lock_Lock::$LOCK_UNIQUE_ID);
}

public function check_environment(Array $errors = array())
{
$errors = array();

if (false == (is_array($this->memcache_servers) && count($this->memcache_servers)))
if (!(is_array($this->memcache_servers) && count($this->memcache_servers)))
$errors[] = 'Memcache Plugin: Memcache Servers Are Not Set';
if (false == class_exists('Core_Memcache'))
$errors[] = 'Memcache Plugin: Dependant Class "Core_Memcache" Is Not Loaded';
if (false == class_exists('Memcached'))
$errors[] = 'Memcache Plugin: PHP Memcached Extension Is Not Loaded';

if (!class_exists('Memcached'))
$errors[] = 'Memcache Plugin: PHP Memcached Extension Is Not Loaded';
if (!class_exists('Core_Lib_Memcache'))
$errors[] = 'Memcache Plugin: Dependant Class "Core_Lib_Memcache" Is Not Loaded';

return $errors;
}

public function set()
protected function set()
{
$lock = $this->check();
if ($lock)
throw new Exception('Core_Lock_Memcached::set Failed. Existing Lock Detected from PID ' . $lock);

$timeout = Core_Lock_Lock::$LOCK_TTL_PADDING_SECONDS + $this->ttl;
$this->memcache->set(Core_Lock_Lock::$LOCK_UNIQUE_ID, $this->pid, false, $timeout);
$this->memcache->set(Core_Lock_Lock::$LOCK_UNIQUE_ID, $this->pid);
}

protected function get()
{
$lock = $this->memcache->get(Core_Lock_Lock::$LOCK_UNIQUE_ID);

// Ensure we're not seeing our own lock
if ($lock == $this->pid)
return false;

// If We're here, there's another lock... return the pid..
return $lock;
}
}
29 changes: 7 additions & 22 deletions Core/Lock/Shm.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,6 @@ class Core_Lock_Shm extends Core_Lock_Lock implements Core_IPlugin
* @var Resource
*/
private $shm = false;

public function __construct()
{
$this->pid = getmypid();
}

public function setup()
{
Expand All @@ -27,8 +22,7 @@ public function setup()
public function teardown()
{
// If this PID set this lock, release it
$lock = shm_get_var($this->shm, self::ADDRESS);
if ($lock == $this->pid) {
if ($this->get() == $this->pid) {
shm_remove($this->shm);
shm_detach($this->shm);
}
Expand All @@ -40,27 +34,18 @@ public function check_environment(Array $errors = array())
return $errors;
}

public function set()
protected function set()
{
$lock = $this->check();
if ($lock)
throw new Exception('Core_Lock_Shm::set Failed. Existing Lock Detected from PID ' . $lock);

shm_put_var($this->shm, self::ADDRESS, array('pid' => $this->pid, 'time' => time()));
shm_put_var($this->shm, self::ADDRESS, $this->pid);
}

protected function get()
{
if (!shm_has_var($this->shm, self::ADDRESS))
return false;

$lock = shm_get_var($this->shm, self::ADDRESS);

// Ensure we're not seeing our own lock
if ($lock['pid'] == $this->pid)
return false;

// If it's expired...
if ($lock['time'] + $this->ttl + Core_Lock_Lock::$LOCK_TTL_PADDING_SECONDS >= time())
return $lock;

return false;
return $lock;
}
}
Loading