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
45 public function setManager( PoolCounterConnectionManager $manager ): void {
46 $this->manager = $manager;
47 }
48
52 public function getConn() {
53 if ( !$this->conn ) {
54 $status = $this->manager->get( $this->key );
55 if ( !$status->isOK() ) {
56 return $status;
57 }
58 // @phan-suppress-next-line PhanTypeArraySuspiciousNullable
59 $this->conn = $status->value['conn'];
60 // @phan-suppress-next-line PhanTypeArraySuspiciousNullable
61 $this->hostName = $status->value['hostName'];
62
63 // Set the read timeout to be 1.5 times the pool timeout.
64 // This allows the server to time out gracefully before we give up on it.
65 stream_set_timeout( $this->conn, 0, (int)( $this->timeout * 1e6 * 1.5 ) );
66 }
67 // TODO: Convert from Status to StatusValue
68 return Status::newGood( $this->conn );
69 }
70
75 public function sendCommand( ...$args ) {
76 $args = str_replace( ' ', '%20', $args );
77 $cmd = implode( ' ', $args );
78 $status = $this->getConn();
79 if ( !$status->isOK() ) {
80 return $status;
81 }
82 $conn = $status->value;
83 $this->logger->debug( "Sending pool counter command: $cmd" );
84 if ( fwrite( $conn, "$cmd\n" ) === false ) {
85 return Status::newFatal( 'poolcounter-write-error', $this->hostName );
86 }
87 $response = fgets( $conn );
88 if ( $response === false ) {
89 return Status::newFatal( 'poolcounter-read-error', $this->hostName );
90 }
91 $response = rtrim( $response, "\r\n" );
92 $this->logger->debug( "Got pool counter response: $response" );
93 $parts = explode( ' ', $response, 2 );
94 $responseType = $parts[0];
95 switch ( $responseType ) {
96 case 'LOCKED':
97 $this->onAcquire();
98 break;
99 case 'RELEASED':
100 $this->onRelease();
101 break;
102 case 'DONE':
103 case 'NOT_LOCKED':
104 case 'QUEUE_FULL':
105 case 'TIMEOUT':
106 case 'LOCK_HELD':
107 break;
108 case 'ERROR':
109 default:
110 $parts = explode( ' ', $parts[1], 2 );
111 $errorMsg = $parts[1] ?? '(no message given)';
112 return Status::newFatal( 'poolcounter-remote-error', $errorMsg, $this->hostName );
113 }
114 return Status::newGood( constant( "PoolCounter::$responseType" ) );
115 }
116
121 public function acquireForMe( $timeout = null ) {
122 $status = $this->precheckAcquire();
123 if ( !$status->isGood() ) {
124 return $status;
125 }
126 return $this->sendCommand( 'ACQ4ME', $this->key, $this->workers, $this->maxqueue,
127 $timeout ?? $this->timeout );
128 }
129
134 public function acquireForAnyone( $timeout = null ) {
135 $status = $this->precheckAcquire();
136 if ( !$status->isGood() ) {
137 return $status;
138 }
139 return $this->sendCommand( 'ACQ4ANY', $this->key, $this->workers, $this->maxqueue,
140 $timeout ?? $this->timeout );
141 }
142
146 public function release() {
147 $status = $this->sendCommand( 'RELEASE' );
148
149 if ( $this->conn ) {
150 $this->manager->close( $this->conn );
151 $this->conn = null;
152 }
153
154 return $status;
155 }
156}
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