MediaWiki master
MemcachedPhpBagOStuff.php
Go to the documentation of this file.
1<?php
24namespace Wikimedia\ObjectCache;
25
27
35 protected $client;
36
47 public function __construct( $params ) {
48 parent::__construct( $params );
49
50 // Default class-specific parameters
51 $params += [
52 'compress_threshold' => 1500,
53 'connect_timeout' => 0.5,
54 'timeout' => 500000,
55 ];
56
57 $this->client = new MemcachedClient( $params );
58 $this->client->set_servers( $params['servers'] );
59 $this->client->set_debug( true );
60 }
61
62 protected function doGet( $key, $flags = 0, &$casToken = null ) {
63 $getToken = ( $casToken === self::PASS_BY_REF );
64 $casToken = null;
65
66 $routeKey = $this->validateKeyAndPrependRoute( $key );
67
68 // T257003: only require "gets" (instead of "get") when a CAS token is needed
69 $res = $getToken // @phan-suppress-next-line PhanTypeMismatchArgument False positive
70 ? $this->client->get( $routeKey, $casToken ) : $this->client->get( $routeKey );
71
72 if ( $this->client->_last_cmd_status !== self::ERR_NONE ) {
73 $this->setLastError( $this->client->_last_cmd_status );
74 }
75
76 return $res;
77 }
78
79 protected function doSet( $key, $value, $exptime = 0, $flags = 0 ) {
80 $routeKey = $this->validateKeyAndPrependRoute( $key );
81
82 $res = $this->client->set( $routeKey, $value, $this->fixExpiry( $exptime ) );
83
84 if ( $this->client->_last_cmd_status !== self::ERR_NONE ) {
85 $this->setLastError( $this->client->_last_cmd_status );
86 }
87
88 return $res;
89 }
90
91 protected function doDelete( $key, $flags = 0 ) {
92 $routeKey = $this->validateKeyAndPrependRoute( $key );
93
94 $res = $this->client->delete( $routeKey );
95
96 if ( $this->client->_last_cmd_status !== self::ERR_NONE ) {
97 $this->setLastError( $this->client->_last_cmd_status );
98 }
99
100 return $res;
101 }
102
103 protected function doAdd( $key, $value, $exptime = 0, $flags = 0 ) {
104 $routeKey = $this->validateKeyAndPrependRoute( $key );
105
106 $res = $this->client->add( $routeKey, $value, $this->fixExpiry( $exptime ) );
107
108 if ( $this->client->_last_cmd_status !== self::ERR_NONE ) {
109 $this->setLastError( $this->client->_last_cmd_status );
110 }
111
112 return $res;
113 }
114
115 protected function doCas( $casToken, $key, $value, $exptime = 0, $flags = 0 ) {
116 $routeKey = $this->validateKeyAndPrependRoute( $key );
117
118 $res = $this->client->cas( $casToken, $routeKey, $value, $this->fixExpiry( $exptime ) );
119
120 if ( $this->client->_last_cmd_status !== self::ERR_NONE ) {
121 $this->setLastError( $this->client->_last_cmd_status );
122 }
123
124 return $res;
125 }
126
127 protected function doIncrWithInitAsync( $key, $exptime, $step, $init ) {
128 $routeKey = $this->validateKeyAndPrependRoute( $key );
129 $watchPoint = $this->watchErrors();
130 $this->client->add( $routeKey, $init - $step, $this->fixExpiry( $exptime ) );
131 $this->client->incr( $routeKey, $step );
132
133 return !$this->getLastError( $watchPoint );
134 }
135
136 protected function doIncrWithInitSync( $key, $exptime, $step, $init ) {
137 $routeKey = $this->validateKeyAndPrependRoute( $key );
138
139 $watchPoint = $this->watchErrors();
140 $newValue = $this->client->incr( $routeKey, $step ) ?? false;
141 if ( $newValue === false && !$this->getLastError( $watchPoint ) ) {
142 // No key set; initialize
143 $success = $this->client->add( $routeKey, $init, $this->fixExpiry( $exptime ) );
144 $newValue = $success ? $init : false;
145 if ( $newValue === false && !$this->getLastError( $watchPoint ) ) {
146 // Raced out initializing; increment
147 $newValue = $this->client->incr( $routeKey, $step ) ?? false;
148 }
149 }
150
151 return $newValue;
152 }
153
154 protected function doChangeTTL( $key, $exptime, $flags ) {
155 $routeKey = $this->validateKeyAndPrependRoute( $key );
156
157 $res = $this->client->touch( $routeKey, $this->fixExpiry( $exptime ) );
158
159 if ( $this->client->_last_cmd_status !== self::ERR_NONE ) {
160 $this->setLastError( $this->client->_last_cmd_status );
161 }
162
163 return $res;
164 }
165
166 protected function doGetMulti( array $keys, $flags = 0 ) {
167 $routeKeys = [];
168 foreach ( $keys as $key ) {
169 $routeKeys[] = $this->validateKeyAndPrependRoute( $key );
170 }
171
172 $resByRouteKey = $this->client->get_multi( $routeKeys );
173
174 $res = [];
175 foreach ( $resByRouteKey as $routeKey => $value ) {
176 $res[$this->stripRouteFromKey( $routeKey )] = $value;
177 }
178
179 if ( $this->client->_last_cmd_status !== self::ERR_NONE ) {
180 $this->setLastError( $this->client->_last_cmd_status );
181 }
182
183 return $res;
184 }
185
186 protected function serialize( $value ) {
187 return is_int( $value ) ? $value : $this->client->serialize( $value );
188 }
189
190 protected function unserialize( $value ) {
191 return $this->isInteger( $value ) ? (int)$value : $this->client->unserialize( $value );
192 }
193}
194
196class_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.
Base class for memcached clients.
A wrapper class for the pure-PHP memcached client, exposing a BagOStuff interface.
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.