Make Predis\Network\MasterSlaveReplication serializable.

Since PHP cannot serialize closures we switched to a private method to check
if a SORT command is a read-only operation, but closures are still supported
even if they will make the connection unserializable.
This commit is contained in:
Daniele Alessandri
2012-01-14 14:24:32 +01:00
parent 93163bdfb3
commit 317fb6c398
2 changed files with 62 additions and 6 deletions
+21 -6
View File
@@ -262,7 +262,7 @@ class MasterSlaveReplication implements IConnectionReplication
return true;
}
return $readonly($command);
return call_user_func($readonly, $command);
}
if (($eval = $id === 'EVAL') || $id === 'EVALSHA') {
@@ -273,13 +273,23 @@ class MasterSlaveReplication implements IConnectionReplication
return true;
}
return $readonly($command);
return call_user_func($readonly, $command);
}
}
return false;
}
/**
* Checks if a SORT command is a readable operation by parsing the arguments
* array of the specified commad instance.
*/
private function isSortReadOnly(ICommand $command)
{
$arguments = $command->getArguments();
return ($c = count($arguments)) === 1 ? true : $arguments[$c - 2] !== 'STORE';
}
/**
* Marks a command as a read-only operation. When the behaviour of a
* command can be decided only at runtime depending on its arguments,
@@ -396,10 +406,15 @@ class MasterSlaveReplication implements IConnectionReplication
'ECHO' => true,
'QUIT' => true,
'OBJECT' => true,
'SORT' => function(ICommand $command) {
$arguments = $command->getArguments();
return ($c = count($arguments)) === 1 ? true : $arguments[$c - 2] !== 'STORE';
},
'SORT' => array($this, 'isSortReadOnly'),
);
}
/**
* {@inheritdoc}
*/
public function __sleep()
{
return array('master', 'slaves', 'disallowed', 'readonly', 'readonlySHA1');
}
}
@@ -410,6 +410,29 @@ class MasterSlaveReplicationTest extends StandardTestCase
$replication->executeCommand($cmdEval);
}
/**
* @group disconnected
*/
public function testSortTriggersSwitchToMasterConnectionOnStoreModifier()
{
$profile = ServerProfile::get('dev');
$cmdSortNormal = $profile->createCommand('sort', array('key'));
$cmdSortStore = $profile->createCommand('sort', array('key', array('store' => 'key:store')));
$master = $this->getMockConnection('tcp://host1?alias=master');
$master->expects($this->once())->method('executeCommand')->with($cmdSortStore);
$slave1 = $this->getMockConnection('tcp://host2?alias=slave1');
$slave1->expects($this->once())->method('executeCommand')->with($cmdSortNormal);
$replication = new MasterSlaveReplication();
$replication->add($master);
$replication->add($slave1);
$replication->executeCommand($cmdSortNormal);
$replication->executeCommand($cmdSortStore);
}
/**
* @group disconnected
* @expectedException Predis\NotSupportedException
@@ -508,6 +531,24 @@ class MasterSlaveReplicationTest extends StandardTestCase
$replication->executeCommand($cmdEvalSha);
}
/**
* @group disconnected
*/
public function testCanBeSerialized()
{
$master = $this->getMockConnection('tcp://host1?alias=master');
$slave1 = $this->getMockConnection('tcp://host2?alias=slave1');
$replication = new MasterSlaveReplication();
$replication->add($master);
$replication->add($slave1);
$unserialized = unserialize(serialize($replication));
$this->assertEquals($master, $unserialized->getConnectionById('master'));
$this->assertEquals($slave1, $unserialized->getConnectionById('slave1'));
}
// ******************************************************************** //
// ---- HELPER METHODS ------------------------------------------------ //
// ******************************************************************** //