/**
  * Wraps the complex pool counter interface to force the single call pattern
  * that Cirrus always uses.
  * @param $type same as type parameter on PoolCounter::factory
  * @param $user the user
  * @param $workCallback callback when pool counter is aquired.  Called with
  *   no parameters.
  * @param $errorCallback optional callback called on errors.  Called with
  *   the error string and the key as parameters.  If left undefined defaults
  *   to a function that returns a fatal status and logs an warning.
  */
 public static function doPoolCounterWork($type, $user, $workCallback, $errorCallback = null)
 {
     global $wgCirrusSearchPoolCounterKey;
     // By default the pool counter allows you to lock the same key with
     // multiple types.  That might be useful but it isn't how Cirrus thinks.
     // Instead, all keys are scoped to their type.
     if (!$user) {
         // We don't want to even use the pool counter if there isn't a user.
         return $workCallback();
     }
     $perUserKey = md5($user->getName());
     $perUserKey = "nowait:CirrusSearch:_per_user:{$perUserKey}";
     $globalKey = "{$type}:{$wgCirrusSearchPoolCounterKey}";
     if ($errorCallback === null) {
         $errorCallback = function ($error, $key, $userName) {
             $forUserName = $userName ? "for {userName} " : '';
             LoggerFactory::getInstance('CirrusSearch')->warning("Pool error {$forUserName}on {key}:  {error}", array('userName' => $userName, 'key' => $key, 'error' => $error));
             return Status::newFatal('cirrussearch-backend-error');
         };
     }
     $errorHandler = function ($key) use($errorCallback, $user) {
         return function ($status) use($errorCallback, $key, $user) {
             $status = $status->getErrorsArray();
             // anon usernames are needed within the logs to determine if
             // specific ips (such as large #'s of users behind a proxy)
             // need to be whitelisted. We do not need this information
             // for logged in users and do not store it.
             $userName = $user->isAnon() ? $user->getName() : '';
             return $errorCallback($status[0][0], $key, $userName);
         };
     };
     $doPerUserWork = function () use($type, $globalKey, $workCallback, $errorHandler) {
         // Now that we have the per user lock lets get the operation lock.
         // Note that this could block, causing the user to wait in line with their lock held.
         $work = new PoolCounterWorkViaCallback($type, $globalKey, array('doWork' => $workCallback, 'error' => $errorHandler($globalKey)));
         return $work->execute();
     };
     $work = new PoolCounterWorkViaCallback('CirrusSearch-PerUser', $perUserKey, array('doWork' => $doPerUserWork, 'error' => function ($status) use($errorHandler, $perUserKey, $doPerUserWork) {
         $errorCallback = $errorHandler($perUserKey);
         $errorResult = $errorCallback($status);
         if (Util::isUserPoolCounterActive()) {
             return $errorResult;
         } else {
             return $doPerUserWork();
         }
     }));
     return $work->execute();
 }