示例#1
0
/**
 * 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();
 }