MediaWiki master
PoolCounterClient.php
Go to the documentation of this file.
1<?php
21namespace MediaWiki\PoolCounter;
22
24
33 private $conn;
34
38 private $hostName;
39
43 private $manager;
44
48 public function setManager( PoolCounterConnectionManager $manager ): void {
49 $this->manager = $manager;
50 }
51
55 public function getConn() {
56 if ( !isset( $this->conn ) ) {
57 $status = $this->manager->get( $this->key );
58 if ( !$status->isOK() ) {
59 return $status;
60 }
61 // @phan-suppress-next-line PhanTypeArraySuspiciousNullable
62 $this->conn = $status->value['conn'];
63 // @phan-suppress-next-line PhanTypeArraySuspiciousNullable
64 $this->hostName = $status->value['hostName'];
65
66 // Set the read timeout to be 1.5 times the pool timeout.
67 // This allows the server to time out gracefully before we give up on it.
68 stream_set_timeout( $this->conn, 0, (int)( $this->timeout * 1e6 * 1.5 ) );
69 }
70 // TODO: Convert from Status to StatusValue
71 return Status::newGood( $this->conn );
72 }
73
78 public function sendCommand( ...$args ) {
79 $args = str_replace( ' ', '%20', $args );
80 $cmd = implode( ' ', $args );
81 $status = $this->getConn();
82 if ( !$status->isOK() ) {
83 return $status;
84 }
85 $conn = $status->value;
86 $this->logger->debug( "Sending pool counter command: $cmd" );
87 if ( fwrite( $conn, "$cmd\n" ) === false ) {
88 return Status::newFatal( 'poolcounter-write-error', $this->hostName );
89 }
90 $response = fgets( $conn );
91 if ( $response === false ) {
92 return Status::newFatal( 'poolcounter-read-error', $this->hostName );
93 }
94 $response = rtrim( $response, "\r\n" );
95 $this->logger->debug( "Got pool counter response: $response" );
96 $parts = explode( ' ', $response, 2 );
97 $responseType = $parts[0];
98 switch ( $responseType ) {
99 case 'LOCKED':
100 $this->onAcquire();
101 break;
102 case 'RELEASED':
103 $this->onRelease();
104 break;
105 case 'DONE':
106 case 'NOT_LOCKED':
107 case 'QUEUE_FULL':
108 case 'TIMEOUT':
109 case 'LOCK_HELD':
110 break;
111 case 'ERROR':
112 default:
113 $parts = explode( ' ', $parts[1], 2 );
114 $errorMsg = $parts[1] ?? '(no message given)';
115 return Status::newFatal( 'poolcounter-remote-error', $errorMsg, $this->hostName );
116 }
117 return Status::newGood( constant( "PoolCounter::$responseType" ) );
118 }
119
124 public function acquireForMe( $timeout = null ) {
125 $status = $this->precheckAcquire();
126 if ( !$status->isGood() ) {
127 return $status;
128 }
129 return $this->sendCommand( 'ACQ4ME', $this->key, $this->workers, $this->maxqueue,
130 $timeout ?? $this->timeout );
131 }
132
137 public function acquireForAnyone( $timeout = null ) {
138 $status = $this->precheckAcquire();
139 if ( !$status->isGood() ) {
140 return $status;
141 }
142 return $this->sendCommand( 'ACQ4ANY', $this->key, $this->workers, $this->maxqueue,
143 $timeout ?? $this->timeout );
144 }
145
149 public function release() {
150 $status = $this->sendCommand( 'RELEASE' );
151
152 if ( $this->conn ) {
153 $this->manager->close( $this->conn );
154 $this->conn = null;
155 }
156
157 return $status;
158 }
159}
setManager(PoolCounterConnectionManager $manager)
Helper for \MediaWiki\PoolCounter\PoolCounterClient.
Semaphore semantics to restrict how many workers may concurrently perform a task.
Generic operation result class Has warning/error list, boolean status and arbitrary value.
Definition Status.php:54