MediaWiki master
MemcachedPhpBagOStuff.php
Go to the documentation of this file.
1<?php
20namespace Wikimedia\ObjectCache;
21
23
36 protected $client;
37
48 public function __construct( $params ) {
49 parent::__construct( $params );
50
51 // Default class-specific parameters
52 $params += [
53 'compress_threshold' => 1500,
54 'connect_timeout' => 0.5,
55 'timeout' => 500000,
56 ];
57
58 $this->client = new MemcachedClient( $params );
59 $this->client->set_servers( $params['servers'] );
60 $this->client->set_debug( true );
61 }
62
63 protected function doGet( $key, $flags = 0, &$casToken = null ) {
64 $getToken = ( $casToken === self::PASS_BY_REF );
65 $casToken = null;
66
67 $routeKey = $this->validateKeyAndPrependRoute( $key );
68
69 // T257003: only require "gets" (instead of "get") when a CAS token is needed
70 $res = $getToken // @phan-suppress-next-line PhanTypeMismatchArgument False positive
71 ? $this->client->get( $routeKey, $casToken ) : $this->client->get( $routeKey );
72
73 if ( $this->client->_last_cmd_status !== self::ERR_NONE ) {
74 $this->setLastError( $this->client->_last_cmd_status );
75 }
76
77 return $res;
78 }
79
80 protected function doSet( $key, $value, $exptime = 0, $flags = 0 ) {
81 $routeKey = $this->validateKeyAndPrependRoute( $key );
82
83 $res = $this->client->set( $routeKey, $value, $this->fixExpiry( $exptime ) );
84
85 if ( $this->client->_last_cmd_status !== self::ERR_NONE ) {
86 $this->setLastError( $this->client->_last_cmd_status );
87 }
88
89 return $res;
90 }
91
92 protected function doDelete( $key, $flags = 0 ) {
93 $routeKey = $this->validateKeyAndPrependRoute( $key );
94
95 $res = $this->client->delete( $routeKey );
96
97 if ( $this->client->_last_cmd_status !== self::ERR_NONE ) {
98 $this->setLastError( $this->client->_last_cmd_status );
99 }
100
101 return $res;
102 }
103
104 protected function doAdd( $key, $value, $exptime = 0, $flags = 0 ) {
105 $routeKey = $this->validateKeyAndPrependRoute( $key );
106
107 $res = $this->client->add( $routeKey, $value, $this->fixExpiry( $exptime ) );
108
109 if ( $this->client->_last_cmd_status !== self::ERR_NONE ) {
110 $this->setLastError( $this->client->_last_cmd_status );
111 }
112
113 return $res;
114 }
115
116 protected function doCas( $casToken, $key, $value, $exptime = 0, $flags = 0 ) {
117 $routeKey = $this->validateKeyAndPrependRoute( $key );
118
119 $res = $this->client->cas( $casToken, $routeKey, $value, $this->fixExpiry( $exptime ) );
120
121 if ( $this->client->_last_cmd_status !== self::ERR_NONE ) {
122 $this->setLastError( $this->client->_last_cmd_status );
123 }
124
125 return $res;
126 }
127
128 protected function doIncrWithInitAsync( $key, $exptime, $step, $init ) {
129 $routeKey = $this->validateKeyAndPrependRoute( $key );
130 $watchPoint = $this->watchErrors();
131 $this->client->add( $routeKey, $init - $step, $this->fixExpiry( $exptime ) );
132 $this->client->incr( $routeKey, $step );
133
134 return !$this->getLastError( $watchPoint );
135 }
136
137 protected function doIncrWithInitSync( $key, $exptime, $step, $init ) {
138 $routeKey = $this->validateKeyAndPrependRoute( $key );
139
140 $watchPoint = $this->watchErrors();
141 $newValue = $this->client->incr( $routeKey, $step ) ?? false;
142 if ( $newValue === false && !$this->getLastError( $watchPoint ) ) {
143 // No key set; initialize
144 $success = $this->client->add( $routeKey, $init, $this->fixExpiry( $exptime ) );
145 $newValue = $success ? $init : false;
146 if ( $newValue === false && !$this->getLastError( $watchPoint ) ) {
147 // Raced out initializing; increment
148 $newValue = $this->client->incr( $routeKey, $step ) ?? false;
149 }
150 }
151
152 return $newValue;
153 }
154
155 protected function doChangeTTL( $key, $exptime, $flags ) {
156 $routeKey = $this->validateKeyAndPrependRoute( $key );
157
158 $res = $this->client->touch( $routeKey, $this->fixExpiry( $exptime ) );
159
160 if ( $this->client->_last_cmd_status !== self::ERR_NONE ) {
161 $this->setLastError( $this->client->_last_cmd_status );
162 }
163
164 return $res;
165 }
166
167 protected function doGetMulti( array $keys, $flags = 0 ) {
168 $routeKeys = [];
169 foreach ( $keys as $key ) {
170 $routeKeys[] = $this->validateKeyAndPrependRoute( $key );
171 }
172
173 $resByRouteKey = $this->client->get_multi( $routeKeys );
174
175 $res = [];
176 foreach ( $resByRouteKey as $routeKey => $value ) {
177 $res[$this->stripRouteFromKey( $routeKey )] = $value;
178 }
179
180 if ( $this->client->_last_cmd_status !== self::ERR_NONE ) {
181 $this->setLastError( $this->client->_last_cmd_status );
182 }
183
184 return $res;
185 }
186
187 protected function serialize( $value ) {
188 return is_int( $value ) ? $value : $this->client->serialize( $value );
189 }
190
191 protected function unserialize( $value ) {
192 return $this->isInteger( $value ) ? (int)$value : $this->client->unserialize( $value );
193 }
194}
195
197class_alias( MemcachedPhpBagOStuff::class, 'MemcachedPhpBagOStuff' );
array $params
The job parameters.
memcached client class implemented using (p)fsockopen()
setLastError( $error)
Set the "last error" registry due to a problem encountered during an attempted operation.
getLastError( $watchPoint=0)
Get the "last error" registry.
watchErrors()
Get a "watch point" token that can be used to get the "last error" to occur after now.
isInteger( $value)
Check if a value is an integer.
const PASS_BY_REF
Idiom for doGet() to return extra information by reference.
Store data in a memcached server or memcached cluster.
Store data on memcached servers(s) via a pure-PHP memcached client.
doGet( $key, $flags=0, &$casToken=null)
Get an item.
doSet( $key, $value, $exptime=0, $flags=0)
Set an item.
doCas( $casToken, $key, $value, $exptime=0, $flags=0)
Set an item if the current CAS token matches the provided CAS token.
__construct( $params)
Available parameters are:
doGetMulti(array $keys, $flags=0)
Get an associative array containing the item for each of the keys that have items.
doAdd( $key, $value, $exptime=0, $flags=0)
Insert an item if it does not already exist.