protected function collectGarbage() { $table = new DifferentialChangeset(); $conn_w = $table->establishConnection('w'); queryfx($conn_w, 'DELETE FROM %T WHERE dateCreated < %d LIMIT 100', DifferentialChangeset::TABLE_CACHE, $this->getGarbageEpoch()); return $conn_w->getAffectedRows() == 100; }
protected function recordCommit($commit_identifier, $epoch) { $repository = $this->getRepository(); $commit = new PhabricatorRepositoryCommit(); $commit->setRepositoryID($repository->getID()); $commit->setCommitIdentifier($commit_identifier); $commit->setEpoch($epoch); try { $commit->save(); $event = new PhabricatorTimelineEvent('cmit', array('id' => $commit->getID())); $event->recordEvent(); queryfx($repository->establishConnection('w'), 'INSERT INTO %T (repositoryID, size, lastCommitID, epoch) VALUES (%d, 1, %d, %d) ON DUPLICATE KEY UPDATE size = size + 1, lastCommitID = IF(VALUES(epoch) > epoch, VALUES(lastCommitID), lastCommitID), epoch = IF(VALUES(epoch) > epoch, VALUES(epoch), epoch)', PhabricatorRepository::TABLE_SUMMARY, $repository->getID(), $commit->getID(), $epoch); $this->commitCache[$commit_identifier] = true; } catch (AphrontQueryDuplicateKeyException $ex) { // Ignore. This can happen because we discover the same new commit // more than once when looking at history, or because of races or // data inconsistency or cosmic radiation; in any case, we're still // in a good state if we ignore the failure. $this->commitCache[$commit_identifier] = true; } $this->stillWorking(); }
public function applyInternalEffects($object, $value) { $parent = $object->getParentEvent(); $object->setInstanceOfEventPHID(null); $object->attachParentEvent(null); $rrule = $parent->newRecurrenceRule(); $object->setRecurrenceRule($rrule); $until = $parent->newUntilDateTime(); if ($until) { $object->setUntilDateTime($until); } $old_sequence_index = $object->getSequenceIndex(); $object->setSequenceIndex(0); // Stop the parent event from recurring after the start date of this event. // Since the "until" time is inclusive, rewind it by one second. We could // figure out the previous instance's time instead or use a COUNT, but this // seems simpler as long as it doesn't cause any issues. $until_cutoff = $object->newStartDateTime()->newRelativeDateTime('-PT1S')->newAbsoluteDateTime(); $parent->setUntilDateTime($until_cutoff); $parent->save(); // NOTE: If we implement "COUNT" on editable events, we need to adjust // the "COUNT" here and divide it up between the parent and the fork. // Make all following children of the old parent children of this node // instead. $conn = $object->establishConnection('w'); queryfx($conn, 'UPDATE %T SET instanceOfEventPHID = %s, sequenceIndex = (sequenceIndex - %d) WHERE instanceOfEventPHID = %s AND utcInstanceEpoch > %d', $object->getTableName(), $object->getPHID(), $old_sequence_index, $parent->getPHID(), $object->getUTCInstanceEpoch()); }
public function processRequest() { $request = $this->getRequest(); $chrono_key = $request->getStr('chronoKey'); $user = $request->getUser(); if ($request->isDialogFormPost()) { $table = new PhabricatorFeedStoryNotification(); queryfx($table->establishConnection('w'), 'UPDATE %T SET hasViewed = 1 ' . 'WHERE userPHID = %s AND hasViewed = 0 and chronologicalKey <= %s', $table->getTableName(), $user->getPHID(), $chrono_key); return id(new AphrontReloadResponse())->setURI('/notification/'); } $dialog = new AphrontDialogView(); $dialog->setUser($user); $dialog->addCancelButton('/notification/'); if ($chrono_key) { $dialog->setTitle(pht('Really mark all notifications as read?')); $dialog->addHiddenInput('chronoKey', $chrono_key); $is_serious = PhabricatorEnv::getEnvConfig('phabricator.serious-business'); if ($is_serious) { $dialog->appendChild(pht('All unread notifications will be marked as read. You can not ' . 'undo this action.')); } else { $dialog->appendChild(pht("You can't ignore your problems forever, you know.")); } $dialog->addSubmitButton(pht('Mark All Read')); } else { $dialog->setTitle(pht('No notifications to mark as read.')); $dialog->appendChild(pht('You have no unread notifications.')); } return id(new AphrontDialogResponse())->setDialog($dialog); }
private function materializeProject(PhabricatorProject $project) { if ($project->isMilestone()) { return; } $material_type = PhabricatorProjectMaterializedMemberEdgeType::EDGECONST; $member_type = PhabricatorProjectProjectHasMemberEdgeType::EDGECONST; $project_phid = $project->getPHID(); $descendants = id(new PhabricatorProjectQuery())->setViewer($this->getViewer())->withAncestorProjectPHIDs(array($project->getPHID()))->withIsMilestone(false)->withHasSubprojects(false)->execute(); $descendant_phids = mpull($descendants, 'getPHID'); if ($descendant_phids) { $source_phids = $descendant_phids; $has_subprojects = true; } else { $source_phids = array($project->getPHID()); $has_subprojects = false; } $conn_w = $project->establishConnection('w'); $project->openTransaction(); // Delete any existing materialized member edges. queryfx($conn_w, 'DELETE FROM %T WHERE src = %s AND type = %s', PhabricatorEdgeConfig::TABLE_NAME_EDGE, $project_phid, $material_type); // Copy current member edges to create new materialized edges. queryfx($conn_w, 'INSERT IGNORE INTO %T (src, type, dst, dateCreated, seq) SELECT %s, %d, dst, dateCreated, seq FROM %T WHERE src IN (%Ls) AND type = %d', PhabricatorEdgeConfig::TABLE_NAME_EDGE, $project_phid, $material_type, PhabricatorEdgeConfig::TABLE_NAME_EDGE, $source_phids, $member_type); // Update the hasSubprojects flag. queryfx($conn_w, 'UPDATE %T SET hasSubprojects = %d WHERE id = %d', $project->getTableName(), (int) $has_subprojects, $project->getID()); $project->saveTransaction(); }
protected function doUnlock() { queryfx($this->conn, 'SELECT RELEASE_LOCK(%s)', 'phabricator:' . $this->lockname); $this->conn->close(); self::$pool[] = $this->conn; $this->conn = null; }
public function testTransactionStack() { $conn = $this->newIsolatedConnection(); $conn->openTransaction(); queryfx($conn, 'INSERT'); $conn->saveTransaction(); $this->assertEqual(array('START TRANSACTION', 'INSERT', 'COMMIT'), $conn->getQueryTranscript()); $conn = $this->newIsolatedConnection(); $conn->openTransaction(); queryfx($conn, 'INSERT 1'); $conn->openTransaction(); queryfx($conn, 'INSERT 2'); $conn->killTransaction(); $conn->openTransaction(); queryfx($conn, 'INSERT 3'); $conn->openTransaction(); queryfx($conn, 'INSERT 4'); $conn->saveTransaction(); $conn->saveTransaction(); $conn->openTransaction(); queryfx($conn, 'INSERT 5'); $conn->killTransaction(); queryfx($conn, 'INSERT 6'); $conn->saveTransaction(); $this->assertEqual(array('START TRANSACTION', 'INSERT 1', 'SAVEPOINT Aphront_Savepoint_1', 'INSERT 2', 'ROLLBACK TO SAVEPOINT Aphront_Savepoint_1', 'SAVEPOINT Aphront_Savepoint_1', 'INSERT 3', 'SAVEPOINT Aphront_Savepoint_2', 'INSERT 4', 'SAVEPOINT Aphront_Savepoint_1', 'INSERT 5', 'ROLLBACK TO SAVEPOINT Aphront_Savepoint_1', 'INSERT 6', 'COMMIT'), $conn->getQueryTranscript()); }
public static function updateHint($repository_phid, $old, $new, $type) { switch ($type) { case self::HINT_NONE: break; case self::HINT_REWRITTEN: if (!$new) { throw new Exception(pht('When hinting a commit ("%s") as rewritten, you must provide ' . 'the commit it was rewritten into.', $old)); } break; case self::HINT_UNREADABLE: if ($new) { throw new Exception(pht('When hinting a commit ("%s") as unreadable, you must not ' . 'provide a new commit ("%s").', $old, $new)); } break; default: $all_types = self::getAllHintTypes(); throw new Exception(pht('Hint type ("%s") for commit ("%s") is not valid. Valid hints ' . 'are: %s.', $type, $old, implode(', ', $all_types))); } $table = new self(); $table_name = $table->getTableName(); $conn = $table->establishConnection('w'); if ($type == self::HINT_NONE) { queryfx($conn, 'DELETE FROM %T WHERE repositoryPHID = %s AND oldCommitIdentifier = %s', $table_name, $repository_phid, $old); } else { queryfx($conn, 'INSERT INTO %T (repositoryPHID, oldCommitIdentifier, newCommitIdentifier, hintType) VALUES (%s, %s, %ns, %s) ON DUPLICATE KEY UPDATE newCommitIdentifier = VALUES(newCommitIdentifier), hintType = VALUES(hintType)', $table_name, $repository_phid, $old, $new, $type); } }
public function saveVote() { if (!$this->votable) { throw new Exception("Must set votable before saving vote"); } if (!$this->user) { throw new Exception("Must set user before saving vote"); } $user = $this->user; $votable = $this->votable; $newvote = $this->vote; // prepare vote add, or update if this user is amending an // earlier vote $editor = id(new PhabricatorEdgeEditor())->setUser($user)->addEdge($user->getPHID(), $votable->getUserVoteEdgeType(), $votable->getVotablePHID(), array('data' => $newvote))->removeEdge($user->getPHID(), $votable->getUserVoteEdgeType(), $votable->getVotablePHID()); $conn = $votable->establishConnection('w'); $trans = $conn->openTransaction(); $trans->beginReadLocking(); $votable->reload(); $curvote = (int) PhabricatorEdgeQuery::loadSingleEdgeData($user->getPHID(), $votable->getUserVoteEdgeType(), $votable->getVotablePHID()); if (!$curvote) { $curvote = PonderConstants::NONE_VOTE; } // adjust votable's score by this much $delta = $newvote - $curvote; queryfx($conn, 'UPDATE %T as t SET t.`voteCount` = t.`voteCount` + %d WHERE t.`PHID` = %s', $votable->getTableName(), $delta, $votable->getVotablePHID()); $editor->save(); $trans->endReadLocking(); $trans->saveTransaction(); }
protected function collectGarbage() { $table = new PhabricatorDaemonLog(); $conn_w = $table->establishConnection('w'); queryfx($conn_w, 'DELETE FROM %T WHERE dateCreated < %d AND status != %s LIMIT 100', $table->getTableName(), $this->getGarbageEpoch(), PhabricatorDaemonLog::STATUS_RUNNING); return $conn_w->getAffectedRows() == 100; }
public function saveVote() { $actor = $this->requireActor(); if (!$this->votable) { throw new PhutilInvalidStateException('setVotable'); } $votable = $this->votable; $newvote = $this->vote; // prepare vote add, or update if this user is amending an // earlier vote $editor = id(new PhabricatorEdgeEditor())->addEdge($actor->getPHID(), $votable->getUserVoteEdgeType(), $votable->getVotablePHID(), array('data' => $newvote))->removeEdge($actor->getPHID(), $votable->getUserVoteEdgeType(), $votable->getVotablePHID()); $conn = $votable->establishConnection('w'); $trans = $conn->openTransaction(); $trans->beginReadLocking(); $votable->reload(); $curvote = (int) PhabricatorEdgeQuery::loadSingleEdgeData($actor->getPHID(), $votable->getUserVoteEdgeType(), $votable->getVotablePHID()); if (!$curvote) { $curvote = PonderVote::VOTE_NONE; } // Adjust votable's score by this much. $delta = $newvote - $curvote; queryfx($conn, 'UPDATE %T as t SET t.voteCount = t.voteCount + %d WHERE t.PHID = %s', $votable->getTableName(), $delta, $votable->getVotablePHID()); $editor->save(); $trans->endReadLocking(); $trans->saveTransaction(); }
protected function execute(ConduitAPIRequest $request) { $viewer = $request->getUser(); $repository_phid = $request->getValue('repositoryPHID'); $repository = id(new PhabricatorRepositoryQuery())->setViewer($viewer)->withPHIDs(array($repository_phid))->executeOne(); if (!$repository) { throw new Exception(pht('No repository exists with PHID "%s".', $repository_phid)); } $commit_name = $request->getValue('commit'); $commit = id(new DiffusionCommitQuery())->setViewer($viewer)->withRepository($repository)->withIdentifiers(array($commit_name))->executeOne(); if (!$commit) { throw new Exception(pht('No commit exists with identifier "%s".', $commit_name)); } $branch = PhabricatorRepositoryBranch::loadOrCreateBranch($repository->getID(), $request->getValue('branch')); $coverage = $request->getValue('coverage'); $path_map = id(new DiffusionPathIDQuery(array_keys($coverage)))->loadPathIDs(); $conn = $repository->establishConnection('w'); $sql = array(); foreach ($coverage as $path => $coverage_info) { $sql[] = qsprintf($conn, '(%d, %d, %d, %s)', $branch->getID(), $path_map[$path], $commit->getID(), $coverage_info); } $table_name = 'repository_coverage'; $conn->openTransaction(); queryfx($conn, 'DELETE FROM %T WHERE branchID = %d', $table_name, $branch->getID()); foreach (PhabricatorLiskDAO::chunkSQL($sql) as $chunk) { queryfx($conn, 'INSERT INTO %T (branchID, pathID, commitID, coverage) VALUES %Q', $table_name, $chunk); } $conn->saveTransaction(); }
public function execute(PhutilArgumentParser $args) { $is_dry = $args->getArg('dryrun'); $is_force = $args->getArg('force'); if (!$is_dry && !$is_force) { echo phutil_console_wrap("Are you completely sure you really want to permanently destroy all " . "storage for Phabricator data? This operation can not be undone and " . "your data will not be recoverable if you proceed."); if (!phutil_console_confirm('Permanently destroy all data?')) { echo "Cancelled.\n"; exit(1); } if (!phutil_console_confirm('Really destroy all data forever?')) { echo "Cancelled.\n"; exit(1); } } $api = $this->getAPI(); $patches = $this->getPatches(); $databases = $api->getDatabaseList($patches); $databases[] = $api->getDatabaseName('meta_data'); foreach ($databases as $database) { if ($is_dry) { echo "DRYRUN: Would drop database '{$database}'.\n"; } else { echo "Dropping database '{$database}'...\n"; queryfx($api->getConn('meta_data', $select_database = false), 'DROP DATABASE IF EXISTS %T', $database); } } if (!$is_dry) { echo "Storage was destroyed.\n"; } return 0; }
protected function doUnlock() { queryfx($this->conn, 'SELECT RELEASE_LOCK(%s)', $this->getName()); $this->conn->close(); self::$pool[] = $this->conn; $this->conn = null; }
protected function collectGarbage() { $table = new PhabricatorUserLog(); $conn_w = $table->establishConnection('w'); queryfx($conn_w, 'DELETE FROM %T WHERE dateCreated < %d LIMIT 100', $table->getTableName(), $this->getGarbageEpoch()); return $conn_w->getAffectedRows() == 100; }
protected function collectGarbage() { $log_table = new DrydockLog(); $conn_w = $log_table->establishConnection('w'); queryfx($conn_w, 'DELETE FROM %T WHERE epoch <= %d LIMIT 100', $log_table->getTableName(), $this->getGarbageEpoch()); return $conn_w->getAffectedRows() == 100; }
protected function collectGarbage() { $table = new MultimeterEvent(); $conn_w = $table->establishConnection('w'); queryfx($conn_w, 'DELETE FROM %T WHERE epoch < %d LIMIT 100', $table->getTableName(), $this->getGarbageEpoch()); return $conn_w->getAffectedRows() == 100; }
protected final function updateCommitData($author, $message) { $commit = $this->commit; $data = id(new PhabricatorRepositoryCommitData())->loadOneWhere('commitID = %d', $commit->getID()); if (!$data) { $data = new PhabricatorRepositoryCommitData(); } $data->setCommitID($commit->getID()); $data->setAuthorName($author); $data->setCommitMessage($message); $repository = $this->repository; $detail_parser = $repository->getDetail('detail-parser', 'PhabricatorRepositoryDefaultCommitMessageDetailParser'); if ($detail_parser) { PhutilSymbolLoader::loadClass($detail_parser); $parser_obj = newv($detail_parser, array($commit, $data)); $parser_obj->parseCommitDetails(); } $data->save(); $revision_id = $data->getCommitDetail('differential.revisionID'); if ($revision_id) { $revision = id(new DifferentialRevision())->load($revision_id); if ($revision) { queryfx($revision->establishConnection('w'), 'INSERT IGNORE INTO %T (revisionID, commitPHID) VALUES (%d, %s)', DifferentialRevision::TABLE_COMMIT, $revision->getID(), $commit->getPHID()); if ($revision->getStatus() != DifferentialRevisionStatus::COMMITTED) { $editor = new DifferentialCommentEditor($revision, $revision->getAuthorPHID(), DifferentialAction::ACTION_COMMIT); $editor->save(); } } } }
public static function reindexAbstractDocument(PhabricatorSearchAbstractDocument $doc) { $phid = $doc->getPHID(); if (!$phid) { throw new Exception("Document has no PHID!"); } $store = new PhabricatorSearchDocument(); $store->setPHID($doc->getPHID()); $store->setDocumentType($doc->getDocumentType()); $store->setDocumentTitle($doc->getDocumentTitle()); $store->setDocumentCreated($doc->getDocumentCreated()); $store->setDocumentModified($doc->getDocumentModified()); $store->replace(); $conn_w = $store->establishConnection('w'); $field_dao = new PhabricatorSearchDocumentField(); queryfx($conn_w, 'DELETE FROM %T WHERE phid = %s', $field_dao->getTableName(), $phid); foreach ($doc->getFieldData() as $field) { list($ftype, $corpus, $aux_phid) = $field; queryfx($conn_w, 'INSERT INTO %T (phid, phidType, field, auxPHID, corpus) ' . ' VALUES (%s, %s, %s, %ns, %s)', $field_dao->getTableName(), $phid, $doc->getDocumentType(), $ftype, $aux_phid, $corpus); } $sql = array(); foreach ($doc->getRelationshipData() as $relationship) { list($rtype, $to_phid, $to_type, $time) = $relationship; $sql[] = qsprintf($conn_w, '(%s, %s, %s, %s, %d)', $phid, $to_phid, $rtype, $to_type, $time); } $rship_dao = new PhabricatorSearchDocumentRelationship(); queryfx($conn_w, 'DELETE FROM %T WHERE phid = %s', $rship_dao->getTableName(), $phid); if ($sql) { queryfx($conn_w, 'INSERT INTO %T' . ' (phid, relatedPHID, relation, relatedType, relatedTime) ' . ' VALUES %Q', $rship_dao->getTableName(), implode(', ', $sql)); } }
public static function purgeDrafts($object_phid, $viewer_phid, $version) { $draft = new PhabricatorVersionedDraft(); $conn_w = $draft->establishConnection('w'); queryfx($conn_w, 'DELETE FROM %T WHERE objectPHID = %s AND authorPHID = %s AND version <= %d', $draft->getTableName(), $object_phid, $viewer_phid, $version); }
public static function updateIndex($phid, $name) { $table = new ManiphestNameIndex(); $conn_w = $table->establishConnection('w'); queryfx($conn_w, 'INSERT INTO %T (indexedObjectPHID, indexedObjectName) VALUES (%s, %s) ON DUPLICATE KEY UPDATE indexedObjectName = VALUES(indexedObjectName)', $table->getTableName(), $phid, $name); }
protected function collectGarbage() { $session_table = new PhabricatorAuthTemporaryToken(); $conn_w = $session_table->establishConnection('w'); queryfx($conn_w, 'DELETE FROM %T WHERE tokenExpires <= UNIX_TIMESTAMP() LIMIT 100', $session_table->getTableName()); return $conn_w->getAffectedRows() == 100; }
public function execute() { if (!$this->limit) { throw new Exception('You must setLimit() when leasing tasks.'); } $task_table = new PhabricatorWorkerActiveTask(); $taskdata_table = new PhabricatorWorkerTaskData(); $lease_ownership_name = $this->getLeaseOwnershipName(); $conn_w = $task_table->establishConnection('w'); // Try to satisfy the request from new, unleased tasks first. If we don't // find enough tasks, try tasks with expired leases (i.e., tasks which have // previously failed). $phases = array(self::PHASE_UNLEASED, self::PHASE_EXPIRED); $limit = $this->limit; $leased = 0; foreach ($phases as $phase) { // NOTE: If we issue `UPDATE ... WHERE ... ORDER BY id ASC`, the query // goes very, very slowly. The `ORDER BY` triggers this, although we get // the same apparent results without it. Without the ORDER BY, binary // read slaves complain that the query isn't repeatable. To avoid both // problems, do a SELECT and then an UPDATE. $rows = queryfx_all($conn_w, 'SELECT id, leaseOwner FROM %T %Q %Q %Q', $task_table->getTableName(), $this->buildWhereClause($conn_w, $phase), $this->buildOrderClause($conn_w, $phase), $this->buildLimitClause($conn_w, $limit - $leased)); // NOTE: Sometimes, we'll race with another worker and they'll grab // this task before we do. We could reduce how often this happens by // selecting more tasks than we need, then shuffling them and trying // to lock only the number we're actually after. However, the amount // of time workers spend here should be very small relative to their // total runtime, so keep it simple for the moment. if ($rows) { queryfx($conn_w, 'UPDATE %T task SET leaseOwner = %s, leaseExpires = UNIX_TIMESTAMP() + %d %Q', $task_table->getTableName(), $lease_ownership_name, self::getDefaultLeaseDuration(), $this->buildUpdateWhereClause($conn_w, $phase, $rows)); $leased += $conn_w->getAffectedRows(); if ($leased == $limit) { break; } } } if (!$leased) { return array(); } $data = queryfx_all($conn_w, 'SELECT task.*, taskdata.data _taskData, UNIX_TIMESTAMP() _serverTime FROM %T task LEFT JOIN %T taskdata ON taskdata.id = task.dataID WHERE leaseOwner = %s AND leaseExpires > UNIX_TIMESTAMP() %Q %Q', $task_table->getTableName(), $taskdata_table->getTableName(), $lease_ownership_name, $this->buildOrderClause($conn_w, $phase), $this->buildLimitClause($conn_w, $limit)); $tasks = $task_table->loadAllFromArray($data); $tasks = mpull($tasks, null, 'getID'); foreach ($data as $row) { $tasks[$row['id']]->setServerTime($row['_serverTime']); if ($row['_taskData']) { $task_data = json_decode($row['_taskData'], true); } else { $task_data = null; } $tasks[$row['id']]->setData($task_data); } return $tasks; }
protected function collectGarbage() { $table = new PhabricatorFeedStoryNotification(); $conn_w = $table->establishConnection('w'); queryfx($conn_w, 'DELETE FROM %T WHERE chronologicalKey < (%d << 32) ORDER BY chronologicalKey ASC LIMIT 100', $table->getTableName(), $this->getGarbageEpoch()); return $conn_w->getAffectedRows() == 100; }
public function collectGarbage() { $ttl = phutil_units('90 days in seconds'); $table = new MultimeterEvent(); $conn_w = $table->establishConnection('w'); queryfx($conn_w, 'DELETE FROM %T WHERE epoch < %d LIMIT 100', $table->getTableName(), PhabricatorTime::getNow() - $ttl); return $conn_w->getAffectedRows() == 100; }
protected function collectGarbage() { $cache = new PhabricatorKeyValueDatabaseCache(); $conn_w = $cache->establishConnection('w'); queryfx($conn_w, 'DELETE FROM %T WHERE cacheCreated < %d ORDER BY cacheCreated ASC LIMIT 100', $cache->getTableName(), $this->getGarbageEpoch()); return $conn_w->getAffectedRows() == 100; }
public function replaceOrDelete() { if ($this->draft == '' && !array_filter($this->metadata)) { queryfx($this->establishConnection('w'), 'DELETE FROM %T WHERE authorPHID = %s AND draftKey = %s', $this->getTableName(), $this->authorPHID, $this->draftKey); return $this; } return parent::replace(); }
protected function collectGarbage() { $table = new PhabricatorConduitToken(); $conn_w = $table->establishConnection('w'); queryfx($conn_w, 'DELETE FROM %T WHERE expires <= %d ORDER BY dateCreated ASC LIMIT 100', $table->getTableName(), PhabricatorTime::getNow()); return $conn_w->getAffectedRows() == 100; }
protected function collectGarbage() { $cache = new PhabricatorKeyValueDatabaseCache(); $conn_w = $cache->establishConnection('w'); queryfx($conn_w, 'DELETE FROM %T WHERE cacheExpires < %d ORDER BY cacheExpires ASC LIMIT 100', $cache->getTableName(), PhabricatorTime::getNow()); return $conn_w->getAffectedRows() == 100; }
public function collectGarbage() { $ttl = phutil_units('90 days in seconds'); $table = new PhabricatorMetaMTAMail(); $conn_w = $table->establishConnection('w'); queryfx($conn_w, 'DELETE FROM %T WHERE dateCreated < %d LIMIT 100', $table->getTableName(), time() - $ttl); return $conn_w->getAffectedRows() == 100; }