summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Flatz2023-05-11 09:31:37 +0200
committerDavid Flatz2023-05-11 09:31:59 +0200
commit07437f705b52888cea0fa282401b6df15ab860ce (patch)
tree119f6011680c8fc2f0e461eb099a46cc3c160be5
parent2ce012df8e3ecf24ed243dd71c0a943a51a68467 (diff)
downloaditools-07437f705b52888cea0fa282401b6df15ab860ce.tar.gz
itools-07437f705b52888cea0fa282401b6df15ab860ce.tar.bz2
itools-07437f705b52888cea0fa282401b6df15ab860ce.zip
Use flock for locking to prevent stale locks, when process gets killed
-rw-r--r--it_url.class31
1 files changed, 20 insertions, 11 deletions
diff --git a/it_url.class b/it_url.class
index 014610c..cfa2bef 100644
--- a/it_url.class
+++ b/it_url.class
@@ -605,7 +605,7 @@ static function get_cache($p = array())
{
$fileexists = $filemtime !== true;
- if ($lock = !$p['lock'] ?: it_url::_lock($path))
+ if ($lock = !$p['lock'] ?: it_url::_lock($path, $p))
{
# Touch existing file to prevent locking other getters while refreshing
if ($fileexists)
@@ -657,7 +657,7 @@ static function get_cache($p = array())
if ($filemtime = $isnewfile ? true : it_url::_expired($path, $p['maxage'])) # Outdated(non-zero int) or non-existant(true)?
{
- if ($lock = !$p['lock'] ?: it_url::_lock($path))
+ if ($lock = !$p['lock'] ?: it_url::_lock($path, $p))
{
# Touch existing file to prevent locking other getters while refreshing
if ($filemtime !== true)
@@ -759,10 +759,20 @@ static function _expired($path, $maxage, $randomexpire = 0)
* @param $path File to lock
* @return Lock handle if successfully locked file
*/
-static function _lock($path)
+static function _lock($path, $p = [])
{
- $force = EDC('nocache') || (($mtime = @filemtime("$path.lock")) && (time() - $mtime > 30)); # expire forgotten locks
- return @it::fopen("$path.lock", $force ? "w" : "x");
+ if (!($fh = it::fopen("$path.lock", "w")))
+ return false;
+
+ if (!flock($fh, LOCK_EX | LOCK_NB))
+ {
+ if (($mtime = @filemtime("$path.lock")) && (time() - $mtime > 30))
+ it::error((array)$p['it_error'] + ['title' => "stale lock epired for $path"]); # FIXME 2023-07 DF remove stale lock expiration if never triggered
+ else
+ return false;
+ }
+
+ return $fh;
}
/**
@@ -790,16 +800,15 @@ static function _waitforlockedfile($path, $p)
$sleeptime = 0.1; # seconds to wait per pass
# wait until cache is ready, then read from cache
- for ($maxpasses = $p['timeout'] / $sleeptime, $passes = 0; ($lockedbyother = file_exists("$path.lock")) && ($passes < $maxpasses); ++$passes)
- {
+ for ($maxpasses = $p['timeout'] / $sleeptime, $passes = 0; !($lock = self::_lock("$path", $p)) && ($passes < $maxpasses); ++$passes)
usleep($sleeptime * 1000000);
- clearstatcache();
- }
- if ($lockedbyother)
+ if (!$lock)
it::error((array)$p['it_error'] + ['title' => ($passes < $maxpasses ? "error getting url" : "timeout") . " in it_url::get_cache(): url={$p['url']}, passes=$passes, maxpasses=$maxpasses, path=$path"]);
+ else
+ self::_unlock($path, $lock);
- return !$lockedbyother && file_exists($path);
+ return $lock && file_exists($path);
}
/**