/** * Safe update json in Memcached storage * @param Memcached $Memcached * @param string $key * @param array $array * @throws Exception */ function updateJsonInMemcached(\Memcached $Memcached, $key, array $array) { // Create new Lock instance $Lock = new MemcachedLock($Memcached, 'Lock_' . $key, MemcachedLock::FLAG_CATCH_EXCEPTIONS); // Acquire lock for 2 sec. // If lock has acquired in another thread then we will wait 3 second, // until another thread release the lock. Otherwise it throws a exception. if (!$Lock->acquire(2, 3)) { throw new Exception('Can\'t get a Lock'); } // Get value from storage $json = $Memcached->get($key); if (!$json) { $jsonArray = []; } else { $jsonArray = json_decode($json, true); } // Some operations with json $jsonArray = array_merge($jsonArray, $array); $json = json_encode($jsonArray); // Update key in storage $Memcached->set($key, $json); // Release the lock // After $lock->release() another waiting thread (Lock) will be able to update json in storage $Lock->release(); }
/** * @param int $locktime * @param int $waittime * @return MemcachedLock * @throws \MemcachedLock\Exception\LockHasAcquiredAlreadyException */ protected function createLock($locktime = 2, $waittime = 3) { $Lock = new MemcachedLock($this->Memcached, $this->prefix . self::PREFIX_LOCK); $Lock->acquire($locktime, $waittime); return $Lock; }
public function test_parallel() { $MC = $this->getMemcached(); $MC->flush(); $this->assertSame(true, $MC->set('testcount', '1000000')); unset($MC); $Storage = new MemcachedStorage(['servers' => [explode(':', MEMCACHED_TEST_SERVER)]]); $Parallel = new Parallel($Storage); $start = microtime(true) + 2; // 1st operation $Parallel->run('foo', function () use($start) { $MemcachedLock = new MemcachedLock($MC = $this->getMemcached(), 'lock_'); while (microtime(true) < $start) { // wait for start } $c = 0; for ($i = 1; $i <= 10000; ++$i) { if ($MemcachedLock->acquire(2, 3)) { $count = (int) $MC->get('testcount'); ++$count; $MC->set('testcount', $count); $MemcachedLock->release(); ++$c; } } return $c; }); // 2st operation $Parallel->run('bar', function () use($start) { $MemcachedLock = new MemcachedLock($MC = $this->getMemcached(), 'lock_'); while (microtime(true) < $start) { // wait for start } $c = 0; for ($i = 1; $i <= 10000; ++$i) { if ($MemcachedLock->acquire(2, 3)) { $count = (int) $MC->get('testcount'); ++$count; $MC->set('testcount', $count); $MemcachedLock->release(); ++$c; } } return $c; }); $MemcachedLock = new MemcachedLock($MC = $this->getMemcached(), 'lock_'); while (microtime(true) < $start) { // wait for start } $c = 0; for ($i = 1; $i <= 10000; ++$i) { if ($MemcachedLock->acquire(2, 3)) { $count = (int) $MC->get('testcount'); ++$count; $MC->set('testcount', $count); $MemcachedLock->release(); ++$c; } } $result = $Parallel->wait(['foo', 'bar']); $this->assertSame(10000, (int) $result['foo']); $this->assertSame(10000, (int) $result['bar']); $this->assertSame(10000, $c); $this->assertSame(1030000, (int) $MC->get('testcount')); $MC->flush(); }
public function test_MemcachedLock_Exceptions() { $key = static::TEST_KEY; $MemcachedLock = new MemcachedLock(static::$Memcached, $key, MemcachedLock::FLAG_USE_SELF_EXPIRE_SYNC); $this->assertSame(true, $MemcachedLock->acquire(2)); $this->assertSame(true, $MemcachedLock->isLocked()); static::$Memcached->delete($key); try { $MemcachedLock->release(); $this->assertFalse('Expect LostLockException'); } catch (\Exception $Ex) { $this->assertInstanceOf(LostLockException::class, $Ex); } $this->assertSame(false, $MemcachedLock->isLocked()); $this->assertSame(true, $MemcachedLock->acquire(2)); $this->assertSame(true, $MemcachedLock->isLocked()); static::$Memcached->delete($key); $this->assertSame(false, $MemcachedLock->isExists()); try { $MemcachedLock->isLocked(); $this->assertFalse('Expect LostLockException'); } catch (\Exception $Ex) { $this->assertInstanceOf(LostLockException::class, $Ex); } }