/** * Safe update json in Redis storage * @param Redis $Redis * @param string $key * @param array $array * @throws Exception */ function updateJsonInRedis(RedisClient $Redis, $key, array $array) { // Create new Lock instance $Lock = new RedisLock($Redis, 'Lock_' . $key, RedisLock::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 = $Redis->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 $Redis->set($key, $json); // Release the lock // After $lock->release() another waiting thread (Lock) will be able to update json in storage $Lock->release(); }
public function test_RedisLock_Exceptions() { $key = static::TEST_KEY; $RedisLock = new RedisLock(static::$Redis, $key); $this->assertSame(true, $RedisLock->acquire(2)); $this->assertSame(true, $RedisLock->isLocked()); static::$Redis->del($key); try { $RedisLock->release(); $this->assertFalse('Expect LostLockException'); } catch (\Exception $Ex) { $this->assertInstanceOf(LostLockException::class, $Ex); } $this->assertSame(false, $RedisLock->isLocked()); $this->assertSame(true, $RedisLock->acquire(2)); $this->assertSame(true, $RedisLock->isLocked()); static::$Redis->del($key); $this->assertSame(false, $RedisLock->isExists()); try { $RedisLock->isLocked(); $this->assertFalse('Expect LostLockException'); } catch (\Exception $Ex) { $this->assertInstanceOf(LostLockException::class, $Ex); } }
public function test_parallel() { $Redis = $this->getRedis(); $Redis->flushall(); $this->assertSame(true, $Redis->set('testcount', '1000000')); unset($Redis); $Storage = new MemcachedStorage(['servers' => [explode(':', MEMCACHED_TEST_SERVER)]]); $Parallel = new Parallel($Storage); $start = microtime(true) + 2; // 1st operation $Parallel->run('foo', function () use($start) { $RedisLock = new RedisLock($Redis = $this->getRedis(), 'lock_test'); while (microtime(true) < $start) { // wait for start } $c = 0; for ($i = 1; $i <= 10000; ++$i) { if ($RedisLock->acquire(2, 3)) { $count = (int) $Redis->get('testcount'); ++$count; $Redis->set('testcount', $count); $RedisLock->release(); ++$c; } } return $c; }); // 2st operation $Parallel->run('bar', function () use($start) { $RedisLock = new RedisLock($Redis = $this->getRedis(), 'lock_test'); while (microtime(true) < $start) { // wait for start } $c = 0; for ($i = 1; $i <= 10000; ++$i) { if ($RedisLock->acquire(2, 3)) { $count = (int) $Redis->get('testcount'); ++$count; $Redis->set('testcount', $count); $RedisLock->release(); ++$c; } } return $c; }); $RedisLock = new RedisLock($Redis = $this->getRedis(), 'lock_test'); while (microtime(true) < $start) { // wait for start } $c = 0; for ($i = 1; $i <= 10000; ++$i) { if ($RedisLock->acquire(2, 3)) { $count = (int) $Redis->get('testcount'); ++$count; $Redis->set('testcount', $count); $RedisLock->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) $Redis->get('testcount')); $Redis->flushall(); }