1+ <?php
2+
3+ namespace Aternos \Etcd ;
4+
5+ use Aternos \Etcd \Exception \InvalidClientException ;
6+ use Flexihash \Flexihash ;
7+
8+ /**
9+ * Class ShardedClient
10+ *
11+ * @package Aternos\Etcd
12+ */
13+ class ShardedClient implements ClientInterface
14+ {
15+ /**
16+ * @var ClientInterface[]
17+ */
18+ protected $ clients = [];
19+
20+ /**
21+ * @var ClientInterface[]
22+ */
23+ protected $ keyCache = [];
24+
25+ /**
26+ * @var Flexihash
27+ */
28+ protected $ hash = null ;
29+
30+ /**
31+ * ShardedClient constructor.
32+ *
33+ * @param ClientInterface[] $clients
34+ * @throws InvalidClientException
35+ */
36+ public function __construct (array $ clients )
37+ {
38+ foreach ($ clients as $ client ) {
39+ if (!$ client instanceof ClientInterface) {
40+ throw new InvalidClientException ("Invalid client in client list. " );
41+ }
42+
43+ $ this ->clients [$ client ->getHostname ()] = $ client ;
44+ }
45+ }
46+
47+ /**
48+ * Get the correct client object for that key through consistent hashing
49+ *
50+ * @param string $key
51+ * @return ClientInterface
52+ * @throws \Flexihash\Exception
53+ */
54+ protected function getClientFromKey (string $ key ): ClientInterface
55+ {
56+ if (isset ($ this ->keyCache [$ key ])) {
57+ return $ this ->keyCache [$ key ];
58+ }
59+
60+ if ($ this ->hash === null ) {
61+ $ this ->hash = new Flexihash ();
62+ foreach ($ this ->clients as $ client ) {
63+ $ this ->hash ->addTarget ($ client ->getHostname ());
64+ }
65+ }
66+
67+ $ clientHostname = $ this ->hash ->lookup ($ key );
68+ $ this ->keyCache [$ key ] = $ this ->clients [$ clientHostname ];
69+ return $ this ->keyCache [$ key ];
70+ }
71+
72+
73+ public function getHostname (): string
74+ {
75+ return implode ("- " , array_keys ($ this ->clients ));
76+ }
77+
78+ /**
79+ * @inheritDoc
80+ * @throws \Flexihash\Exception
81+ */
82+ public function put (string $ key , $ value , bool $ prevKv = false , int $ lease = 0 , bool $ ignoreLease = false , bool $ ignoreValue = false )
83+ {
84+ return $ this ->getClientFromKey ($ key )->put ($ key , $ value , $ prevKv , $ lease , $ ignoreLease , $ ignoreValue );
85+ }
86+
87+ /**
88+ * @inheritDoc
89+ * @throws \Flexihash\Exception
90+ */
91+ public function get (string $ key )
92+ {
93+ return $ this ->getClientFromKey ($ key )->get ($ key );
94+ }
95+
96+ /**
97+ * @inheritDoc
98+ * @throws \Flexihash\Exception
99+ */
100+ public function delete (string $ key )
101+ {
102+ return $ this ->getClientFromKey ($ key )->delete ($ key );
103+ }
104+
105+ /**
106+ * @inheritDoc
107+ * @throws \Flexihash\Exception
108+ */
109+ public function putIf (string $ key , $ value , $ previousValue , bool $ returnNewValueOnFail = false )
110+ {
111+ return $ this ->getClientFromKey ($ key )->putIf ($ key , $ value , $ previousValue , $ returnNewValueOnFail );
112+ }
113+
114+ /**
115+ * @inheritDoc
116+ * @throws \Flexihash\Exception
117+ */
118+ public function deleteIf (string $ key , $ previousValue , bool $ returnNewValueOnFail = false )
119+ {
120+ return $ this ->getClientFromKey ($ key )->deleteIf ($ key , $ previousValue , $ returnNewValueOnFail );
121+ }
122+ }
0 commit comments