Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 123 |
|
0.00% |
0 / 4 |
CRAP | |
0.00% |
0 / 1 |
Mcc | |
0.00% |
0 / 123 |
|
0.00% |
0 / 4 |
1560 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 7 |
|
0.00% |
0 / 1 |
2 | |||
showHelp | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
2 | |||
execute | |
0.00% |
0 / 89 |
|
0.00% |
0 / 1 |
1056 | |||
mccGetHelp | |
0.00% |
0 / 23 |
|
0.00% |
0 / 1 |
30 |
1 | <?php |
2 | /** |
3 | * This program is free software; you can redistribute it and/or modify |
4 | * it under the terms of the GNU General Public License as published by |
5 | * the Free Software Foundation; either version 2 of the License, or |
6 | * (at your option) any later version. |
7 | * |
8 | * This program is distributed in the hope that it will be useful, |
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
11 | * GNU General Public License for more details. |
12 | * |
13 | * You should have received a copy of the GNU General Public License along |
14 | * with this program; if not, write to the Free Software Foundation, Inc., |
15 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
16 | * http://www.gnu.org/copyleft/gpl.html |
17 | * |
18 | * @file |
19 | */ |
20 | |
21 | // @codeCoverageIgnoreStart |
22 | require_once __DIR__ . '/Maintenance.php'; |
23 | // @codeCoverageIgnoreEnd |
24 | |
25 | use MediaWiki\MainConfigNames; |
26 | use MediaWiki\Maintenance\Maintenance; |
27 | |
28 | /** |
29 | * Diagnostic tool for interacting with memcached. |
30 | * |
31 | * @ingroup Maintenance |
32 | */ |
33 | class Mcc extends Maintenance { |
34 | public function __construct() { |
35 | parent::__construct(); |
36 | $this->addDescription( |
37 | 'MemCached Command (mcc) is an interactive CLI that lets you interact ' . |
38 | 'with the MediaWiki memcached backends.' |
39 | ); |
40 | $this->addOption( 'cache', 'Cache type to use (a key in $wgObjectCaches)', false, true ); |
41 | $this->addOption( 'debug', 'Set debug mode on the memcached connection' ); |
42 | } |
43 | |
44 | protected function showHelp() { |
45 | parent::showHelp(); |
46 | $this->output( "Interactive commands:\n " ); |
47 | $this->output( str_replace( "\n", "\n ", $this->mccGetHelp( false ) ) ); |
48 | $this->output( "\n" ); |
49 | } |
50 | |
51 | public function execute() { |
52 | $mcc = new MemcachedClient( [ |
53 | 'persistent' => true, |
54 | 'debug' => $this->hasOption( 'debug' ), |
55 | ] ); |
56 | |
57 | $config = $this->getConfig(); |
58 | $objectCaches = $config->get( MainConfigNames::ObjectCaches ); |
59 | $mainCacheType = $config->get( MainConfigNames::MainCacheType ); |
60 | if ( $this->hasOption( 'cache' ) ) { |
61 | $cache = $this->getOption( 'cache' ); |
62 | if ( !isset( $objectCaches[$cache] ) ) { |
63 | $this->fatalError( "MediaWiki isn't configured with a cache named '$cache'" ); |
64 | } |
65 | $servers = $objectCaches[$cache]['servers']; |
66 | } elseif ( $mainCacheType === CACHE_MEMCACHED ) { |
67 | $mcc->set_servers( $config->get( MainConfigNames::MemCachedServers ) ); |
68 | } elseif ( isset( $objectCaches[$mainCacheType]['servers'] ) ) { |
69 | $mcc->set_servers( $objectCaches[$mainCacheType]['servers'] ); |
70 | } else { |
71 | $this->fatalError( "MediaWiki isn't configured for Memcached usage" ); |
72 | } |
73 | |
74 | do { |
75 | $bad = false; |
76 | $quit = false; |
77 | |
78 | $line = self::readconsole(); |
79 | if ( $line === false ) { |
80 | break; |
81 | } |
82 | |
83 | $args = explode( ' ', $line ); |
84 | $command = array_shift( $args ); |
85 | |
86 | // process command |
87 | switch ( $command ) { |
88 | case 'help': |
89 | // show a help message |
90 | print $this->mccGetHelp( array_shift( $args ) ); |
91 | break; |
92 | |
93 | case 'get': |
94 | $sub = ''; |
95 | if ( array_key_exists( 1, $args ) ) { |
96 | $sub = $args[1]; |
97 | } |
98 | print "Getting {$args[0]}[$sub]\n"; |
99 | $res = $mcc->get( $args[0] ); |
100 | if ( array_key_exists( 1, $args ) ) { |
101 | $res = $res[$args[1]]; |
102 | } |
103 | if ( $res === false ) { |
104 | # print 'Error: ' . $mcc->error_string() . "\n"; |
105 | print "MemCached error\n"; |
106 | } elseif ( is_string( $res ) ) { |
107 | print "$res\n"; |
108 | } else { |
109 | var_dump( $res ); |
110 | } |
111 | break; |
112 | |
113 | case 'getsock': |
114 | $res = $mcc->get( $args[0] ); |
115 | $sock = $mcc->get_sock( $args[0] ); |
116 | var_dump( $sock ); |
117 | break; |
118 | |
119 | case 'server': |
120 | if ( $mcc->_single_sock !== null ) { |
121 | print $mcc->_single_sock . "\n"; |
122 | break; |
123 | } |
124 | $res = $mcc->get( $args[0] ); |
125 | $hv = $mcc->_hashfunc( $args[0] ); |
126 | for ( $i = 0; $i < 3; $i++ ) { |
127 | print $mcc->_buckets[$hv % $mcc->_bucketcount] . "\n"; |
128 | $hv += $mcc->_hashfunc( $i . $args[0] ); |
129 | } |
130 | break; |
131 | |
132 | case 'set': |
133 | $key = array_shift( $args ); |
134 | if ( $args[0] == "#" && is_numeric( $args[1] ) ) { |
135 | $value = str_repeat( '*', (int)$args[1] ); |
136 | } else { |
137 | $value = implode( ' ', $args ); |
138 | } |
139 | if ( !$mcc->set( $key, $value, 0 ) ) { |
140 | # print 'Error: ' . $mcc->error_string() . "\n"; |
141 | print "MemCached error\n"; |
142 | } |
143 | break; |
144 | |
145 | case 'delete': |
146 | $key = implode( ' ', $args ); |
147 | if ( !$mcc->delete( $key ) ) { |
148 | # print 'Error: ' . $mcc->error_string() . "\n"; |
149 | print "MemCached error\n"; |
150 | } |
151 | break; |
152 | |
153 | case 'history': |
154 | if ( function_exists( 'readline_list_history' ) ) { |
155 | foreach ( readline_list_history() as $num => $line ) { |
156 | print "$num: $line\n"; |
157 | } |
158 | } else { |
159 | print "readline_list_history() not available\n"; |
160 | } |
161 | break; |
162 | |
163 | case 'dumpmcc': |
164 | var_dump( $mcc ); |
165 | break; |
166 | |
167 | case 'quit': |
168 | case 'exit': |
169 | $quit = true; |
170 | break; |
171 | |
172 | default: |
173 | $bad = true; |
174 | } |
175 | |
176 | if ( $bad ) { |
177 | if ( $command ) { |
178 | print "Bad command\n"; |
179 | } |
180 | } else { |
181 | if ( function_exists( 'readline_add_history' ) ) { |
182 | readline_add_history( $line ); |
183 | } |
184 | } |
185 | } while ( !$quit ); |
186 | } |
187 | |
188 | private function mccGetHelp( $command ) { |
189 | $output = ''; |
190 | $commandList = [ |
191 | 'get' => 'grabs something', |
192 | 'getsock' => 'lists sockets', |
193 | 'set' => 'changes something', |
194 | 'delete' => 'deletes something', |
195 | 'history' => 'show command line history', |
196 | 'server' => 'show current memcached server', |
197 | 'dumpmcc' => 'shows the whole thing', |
198 | 'exit' => 'exit mcc', |
199 | 'quit' => 'exit mcc', |
200 | 'help' => 'help about a command', |
201 | ]; |
202 | if ( !$command ) { |
203 | $command = 'fullhelp'; |
204 | } |
205 | if ( $command === 'fullhelp' ) { |
206 | $max_cmd_len = max( array_map( 'strlen', array_keys( $commandList ) ) ); |
207 | foreach ( $commandList as $cmd => $desc ) { |
208 | $output .= sprintf( "%-{$max_cmd_len}s: %s\n", $cmd, $desc ); |
209 | } |
210 | } elseif ( isset( $commandList[$command] ) ) { |
211 | $output .= "$command: $commandList[$command]\n"; |
212 | } else { |
213 | $output .= "$command: command does not exist or no help for it\n"; |
214 | } |
215 | |
216 | return $output; |
217 | } |
218 | } |
219 | |
220 | // @codeCoverageIgnoreStart |
221 | $maintClass = Mcc::class; |
222 | require_once RUN_MAINTENANCE_IF_MAIN; |
223 | // @codeCoverageIgnoreEnd |