8000 feature #28598 [Cache] support configuring multiple Memcached servers… · symfony/symfony@e6deb09 · GitHub
[go: up one dir, main page]

Skip to content

Commit e6deb09

Browse files
committed
feature #28598 [Cache] support configuring multiple Memcached servers in one DSN (nicolas-grekas)
This PR was merged into the 4.2-dev branch. Discussion ---------- [Cache] support configuring multiple Memcached servers in one DSN | Q | A | ------------- | --- | Branch? | master | Bug fix? | no | New feature? | yes | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | #27855 | License | MIT | Doc PR | symfony/symfony-docs#10402 Useful to reconfigure dynamically an array of memcached servers (eg removing a dead one or adding a new one). DSN format is e.g. `memcached://localhost?host[foo.bar]=3`. To ease generating the DSN programmatically, it works also with `memcached:?host[localhost]&host[localhost:12345]&host[/some/memcached.sock:]=3`. The key of the "host" parameter is a "host:port" pair, the value is the weight of the "host:port" pair. Sockets need to be specified with the trailing `:` (as shown in the last example). Commits ------- 8e0605a [Cache] support configuring multiple Memcached servers in one DSN
2 parents 60fac5c + 8e0605a commit e6deb09

File tree

5 files changed

+80
-10
lines changed

5 files changed

+80
-10
lines changed

src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/CachePoolPass.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ public static function getServiceProvider(ContainerBuilder $container, $name)
133133
{
134134
$container->resolveEnvPlaceholders($name, null, $usedEnvs);
135135

136-
if ($usedEnvs || preg_match('#^[a-z]++://#', $name)) {
136+
if ($usedEnvs || preg_match('#^[a-z]++:#', $name)) {
137137
$dsn = $name;
138138

139139
if (!$container->hasDefinition($name = '.cache_connection.'.ContainerBuilder::hash($dsn))) {

src/Symfony/Component/Cache/Adapter/AbstractAdapter.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ public static function createConnection($dsn, array $options = array())
151151
if (0 === strpos($dsn, 'redis://')) {
152152
return RedisAdapter::createConnection($dsn, $options);
153153
}
154-
if (0 === strpos($dsn, 'memcached://')) {
154+
if (0 === strpos($dsn, 'memcached:')) {
155155
return MemcachedAdapter::createConnection($dsn, $options);
156156
}
157157

src/Symfony/Component/Cache/CHANGELOG.md

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

7+
* added support for configuring multiple Memcached servers in one DSN
78
* added `MarshallerInterface` and `DefaultMarshaller` to allow changing the serializer and provide one that automatically uses igbinary when available
89
* added `CacheInterface`, which provides stampede protection via probabilistic early expiration and should become the preferred way to use a cache
910
* added sub-second expiry accuracy for backends that support it

src/Symfony/Component/Cache/Tests/Adapter/MemcachedAdapterTest.php

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,4 +192,46 @@ public function provideDsnWithOptions()
192192
array(\Memcached::OPT_SOCKET_RECV_SIZE => 1, \Memcached::OPT_SOCKET_SEND_SIZE => 2, \Memcached::OPT_RETRY_TIMEOUT => 8),
193193
);
194194
}
195+
196+
public function testMultiServerDsn()
197+
{
198+
$dsn = 'memcached:?host[localhost]&host[localhost:12345]&host[/some/memcached.sock:]=3';
199+
$client = MemcachedAdapter::createConnection($dsn);
200+
201+
$expected = array(
202+
0 => array(
203+
'host' => 'localhost',
204+
'port' => 11211,
205+
'type' => 'TCP',
206+
),
207+
1 => array(
208+
'host' => 'localhost',
209+
'port' => 12345,
210+
'type' => 'TCP',
211+
),
212+
2 => array(
213+
'host' => '/some/memcached.sock',
214+
'port' => 0,
215+
'type' => 'SOCKET',
216+
),
217+
);
218+
$this->assertSame($expected, $client->getServerList());
219+
220+
$dsn = 'memcached://localhost?host[foo.bar]=3';
221+
$client = MemcachedAdapter::createConnection($dsn);
222+
223+
$expected = array(
224+
0 => array(
225+
'host' => 'localhost',
226+
'port' => 11211,
227+
'type' => 'TCP',
228+
),
229+
1 => array(
230+
'host' => 'foo.bar',
231+
'port' => 11211,
232+
'type' => 'TCP',
233+
),
234+
);
235+
$this->assertSame($expected, $client->getServerList());
236+
}
195237
}

src/Symfony/Component/Cache/Traits/MemcachedTrait.php

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -99,19 +99,43 @@ public static function createConnection($servers, array $options = array())
9999
if (\is_array($dsn)) {
100100
continue;
101101
}
102-
if (0 !== strpos($dsn, 'memcached://')) {
103-
throw new InvalidArgumentException(sprintf('Invalid Memcached DSN: %s does not start with "memcached://"', $dsn));
102+
if (0 !== strpos($dsn, 'memcached:')) {
103+
throw new InvalidArgumentException(sprintf('Invalid Memcached DSN: %s does not start with "memcached:"', $dsn));
104104
}
105-
$params = preg_replace_callback('#^memcached://(?:([^@]*+)@)?#', function ($m) use (&$username, &$password) {
106-
if (!empty($m[1])) {
107-
list($username, $password) = explode(':', $m[1], 2) + array(1 => null);
105+
$params = preg_replace_callback('#^memcached:(//)?(?:([^@]*+)@)?#', function ($m) use (&$username, &$password) {
106+
if (!empty($m[2])) {
107+
list($username, $password) = explode(':', $m[2], 2) + array(1 => null);
108108
}
109109

110-
return 'file://';
110+
return 'file:'.($m[1] ?? '');
111111
}, $dsn);
112112
if (false === $params = parse_url($params)) {
113113
throw new InvalidArgumentException(sprintf('Invalid Memcached DSN: %s', $dsn));
114114
}
115+
$query = $hosts = array();
116+
if (isset($params['query'])) {
117+
parse_str($params['query'], $query);
118+
119+
if (isset($query['host'])) {
120+
if (!\is_array($hosts = $query['host'])) {
121+
throw new InvalidArgumentException(sprintf('Invalid Memcached DSN: %s', $dsn));
122+
}
123+
foreach ($hosts as $host => $weight) {
124+
if (false === $port = strrpos($host, ':')) {
125+
$hosts[$host] = array($host, 11211, (int) $weight);
126+
} else {
127+
$hosts[$host] = array(substr($host, 0, $port), (int) substr($host, 1 + $port), (int) $weight);
128+
}
129+
}
130+
$hosts = array_values($hosts);
131+
unset($query['host']);
132+
}
133+
if ($hosts && !isset($params['host']) && !isset($params['path'])) {
134+
unset($servers[$i]);
135+
$servers = array_merge($servers, $hosts);
136+
continue;
137+
}
138+
}
115139
if (!isset($params['host']) && !isset($params['path'])) {
116140
throw new InvalidArgumentException(sprintf('Invalid Memcached DSN: %s', $dsn));
117141
}
@@ -124,13 +148,16 @@ public static function createConnection($servers, array $options = array())
124148
'port' => isset($params['host']) ? 11211 : null,
125149
'weight' => 0,
126150
);
127-
if (isset($params['query'])) {
128-
parse_str($params['query'], $query);
151+
if ($query) {
129152
$params += $query;
130153
$options = $query + $options;
131154
}
132155

133156
$servers[$i] = array($params['host'], $params['port'], $params['weight']);
157+
158+
if ($hosts) {
159+
$servers = array_merge($servers, $hosts);
160+
}
134161
}
135162

136163
// set client's options< 17AE /span>

0 commit comments

Comments
 (0)
0