/** * Puts shallow read and/or write locks on files * * Resources with a shallow lock on it can only be modified in the same * request as they were placed and not by parallel requests (in different * server threads/processes). However, as soon as the request ends, the lock * will be released. * * Write locks can not be set if there is already a read or write lock set. * Read locks can not be set if there is already a write lock set. There can * be multiple read locks on the same resource! * * @param array $write paths to write-lock, use an empty array to skip * @param array $read paths to read-lock * @return void */ public function shallowLock($write, $read = array()) { $whashes = $rhashes = array(); foreach ($write as $value) { $whashes[] = BeeHub_DB::escape_string(hash('sha256', $value, true)); } foreach ($read as $value) { $rhashes[] = BeeHub_DB::escape_string(hash('sha256', $value, true)); } sort($whashes, SORT_STRING); sort($rhashes, SORT_STRING); if (!empty($whashes)) { BeeHub_DB::query('INSERT IGNORE INTO `shallowLocks` VALUES (' . implode('),(', $whashes) . ');'); $whashes = implode(',', $whashes); $whashes = "SELECT * FROM `shallowLocks` WHERE `pathhash` IN ({$whashes}) FOR UPDATE;"; } else { $whashes = null; } if (!empty($rhashes)) { BeeHub_DB::query('INSERT IGNORE INTO `shallowLocks` VALUES (' . implode('),(', $rhashes) . ');'); $rhashes = implode(',', $rhashes); $rhashes = "SELECT * FROM `shallowLocks` WHERE `pathhash` IN ({$rhashes}) LOCK IN SHARE MODE;"; } else { $rhashes = null; } $microsleeptimer = 10000; // also functions as success flag while ($microsleeptimer) { if ($microsleeptimer > 1280000) { $microsleeptimer = 1280000; } BeeHub_DB::query('START TRANSACTION'); if ($whashes) { try { BeeHub_DB::query($whashes)->free_result(); } catch (BeeHub_Deadlock $e) { BeeHub_DB::query('ROLLBACK'); usleep($microsleeptimer); $microsleeptimer *= 2; continue; } catch (BeeHub_Timeout $e) { BeeHub_DB::query('ROLLBACK'); throw new DAV_Status(DAV::HTTP_SERVICE_UNAVAILABLE); } } if ($rhashes) { try { BeeHub_DB::query($rhashes)->free_result(); } catch (BeeHub_Deadlock $e) { BeeHub_DB::query('ROLLBACK'); usleep($microsleeptimer); $microsleeptimer *= 2; continue; } catch (BeeHub_Timeout $e) { BeeHub_DB::query('ROLLBACK'); throw new DAV_Status(DAV::HTTP_SERVICE_UNAVAILABLE); } } $microsleeptimer = 0; } }