Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit3270165

Browse files
Add new Zookeeper Data Store. Add functional test for Zookeeper Data Store. Modify Store Factory to support initialization of Zookeeper Data Store.
1 parent57c76a4 commit3270165

File tree

7 files changed

+277
-2
lines changed

7 files changed

+277
-2
lines changed

‎.travis.yml‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ addons:
1313
-ldap-utils
1414
-slapd
1515
-librabbitmq-dev
16+
-zookeeperd
17+
-libzookeeper-mt-dev
1618

1719
env:
1820
global:
@@ -161,6 +163,7 @@ before_install:
161163
tfold ext.mongodb tpecl mongodb-1.5.0 mongodb.so $INI
162164
tfold ext.amqp tpecl amqp-1.9.3 amqp.so $INI
163165
tfold ext.igbinary tpecl igbinary-2.0.6 igbinary.so $INI
166+
tfold ext.zookeeper tpecl zookeeper-0.5.0 zookeeper.so $INI
164167
done
165168
166169
-|

‎phpunit.xml.dist‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
<envname="LDAP_PORT"value="3389" />
2020
<envname="REDIS_HOST"value="localhost" />
2121
<envname="MEMCACHED_HOST"value="localhost" />
22+
<envname="ZOOKEEPER_HOST"value="localhost" />
2223
</php>
2324

2425
<testsuites>

‎src/Symfony/Component/Lock/CHANGELOG.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ CHANGELOG
55
-----
66

77
* added the PDO Store
8+
* Add a new Zookeeper Data Store for Lock Component.
89

910
3.4.0
1011
-----

‎src/Symfony/Component/Lock/Store/StoreFactory.php‎

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,9 @@
2222
class StoreFactory
2323
{
2424
/**
25-
* @param \Redis|\RedisArray|\RedisCluster|\Predis\Client|\Memcached $connection
25+
* @param \Redis|\RedisArray|\RedisCluster|\Predis\Client|\Memcached|\Zookeeper $connection
2626
*
27-
* @return RedisStore|MemcachedStore
27+
* @return RedisStore|MemcachedStore|ZookeeperStore
2828
*/
2929
publicstaticfunctioncreateStore($connection)
3030
{
@@ -34,6 +34,9 @@ public static function createStore($connection)
3434
if ($connectioninstanceof \Memcached) {
3535
returnnewMemcachedStore($connection);
3636
}
37+
if ($connectioninstanceof \Zookeeper) {
38+
returnnewZookeeperStore($connection);
39+
}
3740

3841
thrownewInvalidArgumentException(sprintf('Unsupported Connection: %s.',\get_class($connection)));
3942
}
Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespaceSymfony\Component\Lock\Store;
13+
14+
useSymfony\Component\Lock\Exception\LockAcquiringException;
15+
useSymfony\Component\Lock\Exception\LockConflictedException;
16+
useSymfony\Component\Lock\Exception\LockReleasingException;
17+
useSymfony\Component\Lock\Exception\NotSupportedException;
18+
useSymfony\Component\Lock\Key;
19+
useSymfony\Component\Lock\StoreInterface;
20+
21+
/**
22+
* ZookeeperStore is a StoreInterface implementation using Zookeeper as store engine.
23+
*
24+
* @author Ganesh Chandrasekaran <gchandrasekaran@wayfair.com>
25+
*/
26+
class ZookeeperStoreimplements StoreInterface
27+
{
28+
private$zookeeper;
29+
30+
publicfunction__construct(\Zookeeper$zookeeper)
31+
{
32+
$this->zookeeper =$zookeeper;
33+
}
34+
35+
/**
36+
* {@inheritdoc}
37+
*/
38+
publicfunctionsave(Key$key)
39+
{
40+
if ($this->exists($key)) {
41+
return;
42+
}
43+
44+
$resource =$this->getKeyResource($key);
45+
$token =$this->getUniqueToken($key);
46+
47+
$this->createNewLock($resource,$token);
48+
}
49+
50+
/**
51+
* {@inheritdoc}
52+
*/
53+
publicfunctiondelete(Key$key)
54+
{
55+
if (!$this->exists($key)) {
56+
return;
57+
}
58+
$resource =$this->getKeyResource($key);
59+
try {
60+
$this->zookeeper->delete($resource);
61+
}catch (\ZookeeperException$exception) {
62+
// For Zookeeper Ephemeral Nodes, the node will be deleted upon session death. But, if we want to unlock
63+
// the lock before proceeding further in the session, the client should be aware of this
64+
thrownewLockReleasingException($exception);
65+
}
66+
}
67+
68+
/**
69+
* {@inheritdoc}
70+
*/
71+
publicfunctionexists(Key$key):bool
72+
{
73+
$resource =$this->getKeyResource($key);
74+
try {
75+
return$this->zookeeper->get($resource) ===$this->getUniqueToken($key);
76+
}catch (\ZookeeperException$ex) {
77+
returnfalse;
78+
}
79+
}
80+
81+
/**
82+
* {@inheritdoc}
83+
*/
84+
publicfunctionwaitAndSave(Key$key)
85+
{
86+
thrownewNotSupportedException();
87+
}
88+
89+
/**
90+
* {@inheritdoc}
91+
*/
92+
publicfunctionputOffExpiration(Key$key,$ttl)
93+
{
94+
thrownewNotSupportedException();
95+
}
96+
97+
/**
98+
* Creates a zookeeper node.
99+
*
100+
* @param string $node The node which needs to be created
101+
* @param string $value The value to be assigned to a zookeeper node
102+
*
103+
* @throws LockConflictedException
104+
* @throws LockAcquiringException
105+
*/
106+
privatefunctioncreateNewLock(string$node,string$value)
107+
{
108+
// Default Node Permissions
109+
$acl =array(array('perms' => \Zookeeper::PERM_ALL,'scheme' =>'world','id' =>'anyone'));
110+
// This ensures that the nodes are deleted when the client session to zookeeper server ends.
111+
$type = \Zookeeper::EPHEMERAL;
112+
113+
try {
114+
$this->zookeeper->create($node,$value,$acl,$type);
115+
}catch (\ZookeeperException$ex) {
116+
if (\Zookeeper::NODEEXISTS ===$ex->getCode()) {
117+
thrownewLockConflictedException($ex);
118+
}
119+
120+
thrownewLockAcquiringException($ex);
121+
}
122+
}
123+
124+
privatefunctiongetKeyResource(Key$key):string
125+
{
126+
// Since we do not support storing locks as multi-level nodes, we convert them to be stored at root level.
127+
// For example: foo/bar will become /foo-bar and /foo/bar will become /-foo-bar
128+
$resource = (string)$key;
129+
130+
if (false !==\strpos($resource,'/')) {
131+
$resource =\strtr($resource,array('/' =>'-')).'-'.sha1($resource);
132+
}
133+
134+
if ('' ===$resource) {
135+
$resource =sha1($resource);
136+
}
137+
138+
return'/'.$resource;
139+
}
140+
141+
privatefunctiongetUniqueToken(Key$key):string
142+
{
143+
if (!$key->hasState(self::class)) {
144+
$token =base64_encode(random_bytes(32));
145+
$key->setState(self::class,$token);
146+
}
147+
148+
return$key->getState(self::class);
149+
}
150+
}

‎src/Symfony/Component/Lock/StoreInterface.php‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@
1111

1212
namespaceSymfony\Component\Lock;
1313

14+
useSymfony\Component\Lock\Exception\LockAcquiringException;
1415
useSymfony\Component\Lock\Exception\LockConflictedException;
16+
useSymfony\Component\Lock\Exception\LockReleasingException;
1517
useSymfony\Component\Lock\Exception\NotSupportedException;
1618

1719
/**
@@ -24,6 +26,7 @@ interface StoreInterface
2426
/**
2527
* Stores the resource if it's not locked by someone else.
2628
*
29+
* @throws LockAcquiringException
2730
* @throws LockConflictedException
2831
*/
2932
publicfunctionsave(Key$key);
@@ -52,6 +55,8 @@ public function putOffExpiration(Key $key, $ttl);
5255

5356
/**
5457
* Removes a resource from the storage.
58+
*
59+
* @throws LockReleasingException
5560
*/
5661
publicfunctiondelete(Key$key);
5762

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespaceSymfony\Component\Lock\Tests\Store;
13+
14+
useSymfony\Component\Lock\Key;
15+
useSymfony\Component\Lock\Store\StoreFactory;
16+
useSymfony\Component\Lock\Store\ZookeeperStore;
17+
18+
/**
19+
* @author Ganesh Chandrasekaran <gchandrasekaran@wayfair.com>
20+
*
21+
* @requires extension zookeeper
22+
*/
23+
class ZookeeperStoreTestextends AbstractStoreTest
24+
{
25+
publicfunctiongetStore():ZookeeperStore
26+
{
27+
$zookeeper_server =getenv('ZOOKEEPER_HOST').':2181';
28+
29+
try {
30+
$zookeeper =new \Zookeeper(implode(',',array($zookeeper_server)));
31+
}catch (\ZookeeperConnectionException$exception) {
32+
self::markTestSkipped($exception->getMessage());
33+
}
34+
35+
return StoreFactory::createStore($zookeeper);
36+
}
37+
38+
publicfunctiontestSaveSucceedsWhenPathContainsMoreThanOneNode()
39+
{
40+
$store =$this->getStore();
41+
$resource ='/baseNode/lockNode';
42+
$key =newKey($resource);
43+
44+
$store->save($key);
45+
$this->assertTrue($store->exists($key));
46+
47+
$store->delete($key);
48+
$this->assertFalse($store->exists($key));
49+
}
50+
51+
publicfunctiontestSaveSucceedsWhenPathContainsOneNode()
52+
{
53+
$store =$this->getStore();
54+
$resource ='/baseNode';
55+
$key =newKey($resource);
56+
57+
$store->save($key);
58+
$this->assertTrue($store->exists($key));
59+
60+
$store->delete($key);
61+
$this->assertFalse($store->exists($key));
62+
}
63+
64+
publicfunctiontestSaveSucceedsWhenPathsContainSameFirstNode()
65+
{
66+
$store =$this->getStore();
67+
$resource ='foo/bar';
68+
$key =newKey($resource);
69+
70+
$store->save($key);
71+
$this->assertTrue($store->exists($key));
72+
73+
$resource2 ='foo';
74+
$key2 =newKey($resource2);
75+
76+
$this->assertFalse($store->exists($key2));
77+
$store->save($key2);
78+
$this->assertTrue($store->exists($key2));
79+
80+
$store->delete($key2);
81+
$this->assertFalse($store->exists($key2));
82+
83+
$store->delete($key);
84+
$this->assertFalse($store->exists($key));
85+
}
86+
87+
publicfunctiontestRootPathIsLockable()
88+
{
89+
$store =$this->getStore();
90+
$resource ='/';
91+
$key =newKey($resource);
92+
93+
$store->save($key);
94+
$this->assertTrue($store->exists($key));
95+
96+
$store->delete($key);
97+
$this->assertFalse($store->exists($key));
98+
}
99+
100+
publicfunctiontestEmptyStringIsLockable()
101+
{
102+
$store =$this->getStore();
103+
$resource ='';
104+
$key =newKey($resource);
105+
106+
$store->save($key);
107+
$this->assertTrue($store->exists($key));
108+
109+
$store->delete($key);
110+
$this->assertFalse($store->exists($key));
111+
}
112+
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp