Example #1
0
 /**
  * @param string $identity
  * @param Document $document
  * @return void
  */
 public function upsert(string $identity, Document $document)
 {
     $converted = $this->converter->objectToArray($document);
     if ($this->collection->count([$this->identityField => $identity]) > 0) {
         $this->collection->replaceOne([$this->identityField => $identity], $converted);
     } else {
         $this->collection->insertOne($converted);
     }
 }
Example #2
0
 /**
  * {@inheritdoc}
  */
 public function storeData($key, $data, $expiration)
 {
     if ($this->collection instanceof \MongoDB\Collection) {
         $id = self::mapKey($key);
         try {
             $this->collection->replaceOne(['_id' => $id], ['_id' => $id, 'data' => serialize($data), 'expiration' => $expiration], ['upsert' => true]);
         } catch (\MongoDB\Driver\Exception\BulkWriteException $ignored) {
             // As of right now, BulkWriteException can be thrown by replaceOne in high-throughput environments where race conditions can occur
         }
     } else {
         try {
             $this->collection->save(['_id' => self::mapKey($key), 'data' => serialize($data), 'expiration' => $expiration]);
         } catch (\MongoDuplicateKeyException $ignored) {
             // Because it's Mongo, we might have had this problem because of a cache stampede
         }
     }
     return true;
 }
 /**
  * {@inheritdoc}
  */
 public function set($key, $value)
 {
     KeyUtil::validate($key);
     $serialized = $this->serialize->__invoke($value);
     try {
         $this->collection->replaceOne(array('_id' => $key), array('_id' => $key, 'value' => $serialized), array('upsert' => true));
     } catch (UnexpectedValueException $e) {
         throw UnsupportedValueException::forType('binary', $this, 0, $e);
     } catch (Exception $e) {
         throw WriteException::forException($e);
     }
 }
 /**
  * Saves an object to this collection
  *
  * @link http://www.php.net/manual/en/mongocollection.save.php
  * @param array|object $a Array to save. If an object is used, it may not have protected or private properties.
  * @param array $options Options for the save.
  * @throws MongoException if the inserted document is empty or if it contains zero-length keys. Attempting to insert an object with protected and private properties will cause a zero-length key error.
  * @throws MongoCursorException if the "w" option is set and the write fails.
  * @throws MongoCursorTimeoutException if the "w" option is set to a value greater than one and the operation takes longer than MongoCursor::$timeout milliseconds to complete. This does not kill the operation on the server, it is a client-side timeout. The operation in MongoCollection::$wtimeout is milliseconds.
  * @return array|boolean If w was set, returns an array containing the status of the save.
  * Otherwise, returns a boolean representing if the array was not empty (an empty array will not be inserted).
  */
 public function save(&$a, array $options = [])
 {
     $id = $this->ensureDocumentHasMongoId($a);
     $document = (array) $a;
     $options['upsert'] = true;
     try {
         /** @var \MongoDB\UpdateResult $result */
         $result = $this->collection->replaceOne(TypeConverter::fromLegacy(['_id' => $id]), TypeConverter::fromLegacy($document), $this->convertWriteConcernOptions($options));
     } catch (\MongoDB\Driver\Exception\Exception $e) {
         ExceptionConverter::toLegacy($e);
     }
     if (!$result->isAcknowledged()) {
         return true;
     }
     return ['ok' => 1.0, 'nModified' => $result->getModifiedCount(), 'n' => $result->getMatchedCount(), 'err' => null, 'errmsg' => null, 'updatedExisting' => $result->getUpsertedCount() == 0];
 }
 /**
  * Add to process registry. Adds based on $maxGlobalProcesses and $maxHostProcesses after a process registry cleaning.
  *
  * @param \MongoDB\Collection $collection the collection
  * @param string $id a unique id
  * @param int $minsBeforeExpire number of minutes before a process is considered expired.
  * @param int $maxGlobalProcesses max processes of an id allowed to run across all hosts.
  * @param int $maxHostProcesses max processes of an id allowed to run across a single host.
  *
  * @return boolean true if the process was added, false if not or there is too much concurrency at the moment.
  *
  * @throws \InvalidArgumentException if $id was not a string
  * @throws \InvalidArgumentException if $minsBeforeExpire was not an int
  * @throws \InvalidArgumentException if $maxGlobalProcesses was not an int
  * @throws \InvalidArgumentException if $maxHostProcesses was not an int
  */
 public static function add(\MongoDB\Collection $collection, $id, $minsBeforeExpire = PHP_INT_MAX, $maxGlobalProcesses = 1, $maxHostProcesses = 1)
 {
     if (!is_string($id)) {
         throw new \InvalidArgumentException('$id was not a string');
     }
     if (!is_int($minsBeforeExpire)) {
         throw new \InvalidArgumentException('$minsBeforeExpire was not an int');
     }
     if (!is_int($maxGlobalProcesses)) {
         throw new \InvalidArgumentException('$maxGlobalProcesses was not an int');
     }
     if (!is_int($maxHostProcesses)) {
         throw new \InvalidArgumentException('$maxHostProcesses was not an int');
     }
     $thisHostName = self::_getEncodedHostname();
     $thisPid = getmypid();
     //loop in case the update fails its optimistic concurrency check
     for ($i = 0; $i < 5; ++$i) {
         $collection->findOneAndUpdate(['_id' => $id], ['$setOnInsert' => ['hosts' => [], 'version' => new \MongoDB\BSON\ObjectID()]], ['upsert' => true]);
         $existing = $collection->findOne(['_id' => $id], ['typeMap' => ['root' => 'array', 'document' => 'array', 'array' => 'array']]);
         $replacement = $existing;
         $replacement['version'] = new \MongoDB\BSON\ObjectID();
         //clean $replacement based on their pids and expire times
         foreach ($existing['hosts'] as $hostname => $pids) {
             foreach ($pids as $pid => $expires) {
                 //our machine and not running
                 //the task expired
                 //our machine and pid is recycled (should rarely happen)
                 if ($hostname === $thisHostName && !file_exists("/proc/{$pid}") || time() >= $expires->toDateTime()->getTimestamp() || $hostname === $thisHostName && $pid === $thisPid) {
                     unset($replacement['hosts'][$hostname][$pid]);
                 }
             }
             if (empty($replacement['hosts'][$hostname])) {
                 unset($replacement['hosts'][$hostname]);
             }
         }
         $totalPidCount = 0;
         foreach ($replacement['hosts'] as $hostname => $pids) {
             $totalPidCount += count($pids);
         }
         $thisHostPids = array_key_exists($thisHostName, $replacement['hosts']) ? $replacement['hosts'][$thisHostName] : [];
         if ($totalPidCount >= $maxGlobalProcesses || count($thisHostPids) >= $maxHostProcesses) {
             return false;
         }
         // add our process
         $expireSecs = time() + $minsBeforeExpire * 60;
         if (!is_int($expireSecs)) {
             if ($minsBeforeExpire > 0) {
                 $expireSecs = self::MONGO_INT32_MAX;
             } else {
                 $expireSecs = 0;
             }
         }
         $thisHostPids[$thisPid] = new \MongoDB\BSON\UTCDateTime($expireSecs * 1000);
         $replacement['hosts'][$thisHostName] = $thisHostPids;
         $status = $collection->replaceOne(['_id' => $existing['_id'], 'version' => $existing['version']], $replacement, ['writeConcern' => new \MongoDB\Driver\WriteConcern(1, 100, true)]);
         if ($status->getMatchedCount() === 1) {
             return true;
         }
         //@codeCoverageIgnoreStart
         //hard to test the optimistic concurrency check
     }
     //too much concurrency at the moment, return false to signify not added.
     return false;
     //@codeCoverageIgnoreEnd
 }
Example #6
0
 /**
  * {@inheritdoc}
  */
 public function replaceOne($filter, $replacement, array $options = [])
 {
     $event = $this->startQueryLogging(__FUNCTION__, $filter, $replacement, $options);
     $result = parent::replaceOne($filter, $replacement, $options);
     $this->logger->logQuery($event);
     return $result;
 }
 /**
  * @see DataModelInterface::update
  */
 public function update($book)
 {
     $this->verifyBook($book);
     $result = $this->db->replaceOne(array('_id' => new ObjectId($book['id'])), $this->arrayToBook($book));
     return $result->getModifiedCount();
 }