1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-11-18 04:42:40 +01:00

Move repository URIs to a dedicated index

Summary:
Ref T4705 (there are also some other adjacent related tasks dealing with URIs).

Currently, we issue a "get repositories matching URIs: ..." query by loading every possible repository and then checking their URIs in PHP.

Instead, put URIs in a separate table. I plan for each repository to potentially have multiple URIs soon, so this prepares for that.

Test Plan:
  - Ran migrations.
  - Looked at index table, made sure it appeared sensible.
  - Ran some queries by `uri` to find repositories, found the repositories I expected.
  - Updated the remote URI of a repository, saw queries / index update appropriately.

Reviewers: chad

Reviewed By: chad

Maniphest Tasks: T4705

Differential Revision: https://secure.phabricator.com/D15005
This commit is contained in:
epriestley 2016-01-12 06:45:17 -08:00
parent d57c1d6ce2
commit 1eab16c395
10 changed files with 175 additions and 30 deletions

View file

@ -0,0 +1,7 @@
CREATE TABLE {$NAMESPACE}_repository.repository_uriindex (
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
repositoryPHID VARBINARY(64) NOT NULL,
repositoryURI LONGTEXT NOT NULL COLLATE {$COLLATE_TEXT},
KEY `key_repository` (repositoryPHID),
KEY `key_uri` (repositoryURI(128))
) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT};

View file

@ -0,0 +1,7 @@
<?php
$table = new PhabricatorRepository();
foreach (new LiskMigrationIterator($table) as $repo) {
$repo->updateURIIndex();
}

View file

@ -734,6 +734,7 @@ phutil_register_library_map(array(
'DiffusionRepositorySymbolsController' => 'applications/diffusion/controller/DiffusionRepositorySymbolsController.php', 'DiffusionRepositorySymbolsController' => 'applications/diffusion/controller/DiffusionRepositorySymbolsController.php',
'DiffusionRepositoryTag' => 'applications/diffusion/data/DiffusionRepositoryTag.php', 'DiffusionRepositoryTag' => 'applications/diffusion/data/DiffusionRepositoryTag.php',
'DiffusionRepositoryTestAutomationController' => 'applications/diffusion/controller/DiffusionRepositoryTestAutomationController.php', 'DiffusionRepositoryTestAutomationController' => 'applications/diffusion/controller/DiffusionRepositoryTestAutomationController.php',
'DiffusionRepositoryURIsIndexEngineExtension' => 'applications/diffusion/engineextension/DiffusionRepositoryURIsIndexEngineExtension.php',
'DiffusionRequest' => 'applications/diffusion/request/DiffusionRequest.php', 'DiffusionRequest' => 'applications/diffusion/request/DiffusionRequest.php',
'DiffusionResolveRefsConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionResolveRefsConduitAPIMethod.php', 'DiffusionResolveRefsConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionResolveRefsConduitAPIMethod.php',
'DiffusionResolveUserQuery' => 'applications/diffusion/query/DiffusionResolveUserQuery.php', 'DiffusionResolveUserQuery' => 'applications/diffusion/query/DiffusionResolveUserQuery.php',
@ -3009,6 +3010,7 @@ phutil_register_library_map(array(
'PhabricatorRepositoryTransaction' => 'applications/repository/storage/PhabricatorRepositoryTransaction.php', 'PhabricatorRepositoryTransaction' => 'applications/repository/storage/PhabricatorRepositoryTransaction.php',
'PhabricatorRepositoryTransactionQuery' => 'applications/repository/query/PhabricatorRepositoryTransactionQuery.php', 'PhabricatorRepositoryTransactionQuery' => 'applications/repository/query/PhabricatorRepositoryTransactionQuery.php',
'PhabricatorRepositoryType' => 'applications/repository/constants/PhabricatorRepositoryType.php', 'PhabricatorRepositoryType' => 'applications/repository/constants/PhabricatorRepositoryType.php',
'PhabricatorRepositoryURIIndex' => 'applications/repository/storage/PhabricatorRepositoryURIIndex.php',
'PhabricatorRepositoryURINormalizer' => 'applications/repository/data/PhabricatorRepositoryURINormalizer.php', 'PhabricatorRepositoryURINormalizer' => 'applications/repository/data/PhabricatorRepositoryURINormalizer.php',
'PhabricatorRepositoryURINormalizerTestCase' => 'applications/repository/data/__tests__/PhabricatorRepositoryURINormalizerTestCase.php', 'PhabricatorRepositoryURINormalizerTestCase' => 'applications/repository/data/__tests__/PhabricatorRepositoryURINormalizerTestCase.php',
'PhabricatorRepositoryURITestCase' => 'applications/repository/storage/__tests__/PhabricatorRepositoryURITestCase.php', 'PhabricatorRepositoryURITestCase' => 'applications/repository/storage/__tests__/PhabricatorRepositoryURITestCase.php',
@ -4707,6 +4709,7 @@ phutil_register_library_map(array(
'DiffusionRepositorySymbolsController' => 'DiffusionRepositoryEditController', 'DiffusionRepositorySymbolsController' => 'DiffusionRepositoryEditController',
'DiffusionRepositoryTag' => 'Phobject', 'DiffusionRepositoryTag' => 'Phobject',
'DiffusionRepositoryTestAutomationController' => 'DiffusionRepositoryEditController', 'DiffusionRepositoryTestAutomationController' => 'DiffusionRepositoryEditController',
'DiffusionRepositoryURIsIndexEngineExtension' => 'PhabricatorIndexEngineExtension',
'DiffusionRequest' => 'Phobject', 'DiffusionRequest' => 'Phobject',
'DiffusionResolveRefsConduitAPIMethod' => 'DiffusionQueryConduitAPIMethod', 'DiffusionResolveRefsConduitAPIMethod' => 'DiffusionQueryConduitAPIMethod',
'DiffusionResolveUserQuery' => 'Phobject', 'DiffusionResolveUserQuery' => 'Phobject',
@ -7415,6 +7418,7 @@ phutil_register_library_map(array(
'PhabricatorRepositoryTransaction' => 'PhabricatorApplicationTransaction', 'PhabricatorRepositoryTransaction' => 'PhabricatorApplicationTransaction',
'PhabricatorRepositoryTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'PhabricatorRepositoryTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
'PhabricatorRepositoryType' => 'Phobject', 'PhabricatorRepositoryType' => 'Phobject',
'PhabricatorRepositoryURIIndex' => 'PhabricatorRepositoryDAO',
'PhabricatorRepositoryURINormalizer' => 'Phobject', 'PhabricatorRepositoryURINormalizer' => 'Phobject',
'PhabricatorRepositoryURINormalizerTestCase' => 'PhabricatorTestCase', 'PhabricatorRepositoryURINormalizerTestCase' => 'PhabricatorTestCase',
'PhabricatorRepositoryURITestCase' => 'PhabricatorTestCase', 'PhabricatorRepositoryURITestCase' => 'PhabricatorTestCase',

View file

@ -71,7 +71,7 @@ final class DiffusionLintSaveRunner extends Phobject {
} else if ($uuid) { } else if ($uuid) {
$repository_query->withUUIDs(array($uuid)); $repository_query->withUUIDs(array($uuid));
} else if ($remote_uri) { } else if ($remote_uri) {
$repository_query->withRemoteURIs(array($remote_uri)); $repository_query->withURIs(array($remote_uri));
} }
$repository = $repository_query->executeOne(); $repository = $repository_query->executeOne();

View file

@ -0,0 +1,22 @@
<?php
final class DiffusionRepositoryURIsIndexEngineExtension
extends PhabricatorIndexEngineExtension {
const EXTENSIONKEY = 'diffusion.repositories.uri';
public function getExtensionName() {
return pht('Repository URIs');
}
public function shouldIndexObject($object) {
return ($object instanceof PhabricatorRepository);
}
public function indexObject(
PhabricatorIndexEngine $engine,
$object) {
$object->updateURIIndex();
}
}

View file

@ -63,7 +63,7 @@ final class RepositoryQueryConduitAPIMethod
$remote_uris = $request->getValue('remoteURIs', array()); $remote_uris = $request->getValue('remoteURIs', array());
if ($remote_uris) { if ($remote_uris) {
$query->withRemoteURIs($remote_uris); $query->withURIs($remote_uris);
} }
$uuids = $request->getValue('uuids', array()); $uuids = $request->getValue('uuids', array());

View file

@ -518,4 +518,8 @@ final class PhabricatorRepositoryEditor
throw new PhabricatorApplicationTransactionValidationException($errors); throw new PhabricatorApplicationTransactionValidationException($errors);
} }
protected function supportsSearch() {
return true;
}
} }

View file

@ -9,7 +9,7 @@ final class PhabricatorRepositoryQuery
private $types; private $types;
private $uuids; private $uuids;
private $nameContains; private $nameContains;
private $remoteURIs; private $uris;
private $datasourceQuery; private $datasourceQuery;
private $slugs; private $slugs;
@ -118,8 +118,8 @@ final class PhabricatorRepositoryQuery
return $this; return $this;
} }
public function withRemoteURIs(array $uris) { public function withURIs(array $uris) {
$this->remoteURIs = $uris; $this->uris = $uris;
return $this; return $this;
} }
@ -263,17 +263,6 @@ final class PhabricatorRepositoryQuery
} }
} }
// TODO: Denormalize this, too.
if ($this->remoteURIs) {
$try_uris = $this->getNormalizedPaths();
$try_uris = array_fuse($try_uris);
foreach ($repositories as $key => $repository) {
if (!isset($try_uris[$repository->getNormalizedPath()])) {
unset($repositories[$key]);
}
}
}
// Build the identifierMap // Build the identifierMap
if ($this->numericIdentifiers) { if ($this->numericIdentifiers) {
foreach ($this->numericIdentifiers as $id) { foreach ($this->numericIdentifiers as $id) {
@ -445,6 +434,8 @@ final class PhabricatorRepositoryQuery
protected function buildSelectClauseParts(AphrontDatabaseConnection $conn) { protected function buildSelectClauseParts(AphrontDatabaseConnection $conn) {
$parts = parent::buildSelectClauseParts($conn); $parts = parent::buildSelectClauseParts($conn);
$parts[] = 'r.*';
if ($this->shouldJoinSummaryTable()) { if ($this->shouldJoinSummaryTable()) {
$parts[] = 's.*'; $parts[] = 's.*';
} }
@ -462,9 +453,28 @@ final class PhabricatorRepositoryQuery
PhabricatorRepository::TABLE_SUMMARY); PhabricatorRepository::TABLE_SUMMARY);
} }
if ($this->shouldJoinURITable()) {
$joins[] = qsprintf(
$conn,
'LEFT JOIN %T uri ON r.phid = uri.repositoryPHID',
id(new PhabricatorRepositoryURIIndex())->getTableName());
}
return $joins; return $joins;
} }
protected function shouldGroupQueryResultRows() {
if ($this->shouldJoinURITable()) {
return true;
}
return parent::shouldGroupQueryResultRows();
}
private function shouldJoinURITable() {
return ($this->uris !== null);
}
private function shouldJoinSummaryTable() { private function shouldJoinSummaryTable() {
if ($this->needCommitCounts) { if ($this->needCommitCounts) {
return true; return true;
@ -592,7 +602,7 @@ final class PhabricatorRepositoryQuery
if (strlen($this->nameContains)) { if (strlen($this->nameContains)) {
$where[] = qsprintf( $where[] = qsprintf(
$conn, $conn,
'name LIKE %~', 'r.name LIKE %~',
$this->nameContains); $this->nameContains);
} }
@ -619,6 +629,16 @@ final class PhabricatorRepositoryQuery
$this->slugs); $this->slugs);
} }
if ($this->uris !== null) {
$try_uris = $this->getNormalizedPaths();
$try_uris = array_fuse($try_uris);
$where[] = qsprintf(
$conn,
'uri.repositoryURI IN (%Ls)',
$try_uris);
}
return $where; return $where;
} }
@ -635,7 +655,7 @@ final class PhabricatorRepositoryQuery
// or an `svn+ssh` URI, we could deduce how to normalize it. However, this // or an `svn+ssh` URI, we could deduce how to normalize it. However, this
// would be more complicated and it's not clear if it matters in practice. // would be more complicated and it's not clear if it matters in practice.
foreach ($this->remoteURIs as $uri) { foreach ($this->uris as $uri) {
$normalized_uris[] = new PhabricatorRepositoryURINormalizer( $normalized_uris[] = new PhabricatorRepositoryURINormalizer(
PhabricatorRepositoryURINormalizer::TYPE_GIT, PhabricatorRepositoryURINormalizer::TYPE_GIT,
$uri); $uri);

View file

@ -823,30 +823,40 @@ final class PhabricatorRepository extends PhabricatorRepositoryDAO
return $uri; return $uri;
} }
public function getNormalizedPath() { public function updateURIIndex() {
$uri = (string)$this->getCloneURIObject(); $uris = array(
(string)$this->getCloneURIObject(),
);
foreach ($uris as $key => $uri) {
$uris[$key] = $this->getNormalizedURI($uri)
->getNormalizedPath();
}
PhabricatorRepositoryURIIndex::updateRepositoryURIs(
$this->getPHID(),
$uris);
return $this;
}
private function getNormalizedURI($uri) {
switch ($this->getVersionControlSystem()) { switch ($this->getVersionControlSystem()) {
case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT: case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
$normalized_uri = new PhabricatorRepositoryURINormalizer( return new PhabricatorRepositoryURINormalizer(
PhabricatorRepositoryURINormalizer::TYPE_GIT, PhabricatorRepositoryURINormalizer::TYPE_GIT,
$uri); $uri);
break;
case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN: case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
$normalized_uri = new PhabricatorRepositoryURINormalizer( return new PhabricatorRepositoryURINormalizer(
PhabricatorRepositoryURINormalizer::TYPE_SVN, PhabricatorRepositoryURINormalizer::TYPE_SVN,
$uri); $uri);
break;
case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL: case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
$normalized_uri = new PhabricatorRepositoryURINormalizer( return new PhabricatorRepositoryURINormalizer(
PhabricatorRepositoryURINormalizer::TYPE_MERCURIAL, PhabricatorRepositoryURINormalizer::TYPE_MERCURIAL,
$uri); $uri);
break;
default: default:
throw new Exception(pht('Unrecognized version control system.')); throw new Exception(pht('Unrecognized version control system.'));
} }
return $normalized_uri->getNormalizedPath();
} }
public function isTracked() { public function isTracked() {
@ -2231,13 +2241,17 @@ final class PhabricatorRepository extends PhabricatorRepositoryDAO
public function destroyObjectPermanently( public function destroyObjectPermanently(
PhabricatorDestructionEngine $engine) { PhabricatorDestructionEngine $engine) {
$phid = $this->getPHID();
$this->openTransaction(); $this->openTransaction();
$this->delete(); $this->delete();
PhabricatorRepositoryURIIndex::updateRepositoryURIs($phid, array());
$books = id(new DivinerBookQuery()) $books = id(new DivinerBookQuery())
->setViewer($engine->getViewer()) ->setViewer($engine->getViewer())
->withRepositoryPHIDs(array($this->getPHID())) ->withRepositoryPHIDs(array($phid))
->execute(); ->execute();
foreach ($books as $book) { foreach ($books as $book) {
$engine->destroyObject($book); $engine->destroyObject($book);
@ -2245,7 +2259,7 @@ final class PhabricatorRepository extends PhabricatorRepositoryDAO
$atoms = id(new DivinerAtomQuery()) $atoms = id(new DivinerAtomQuery())
->setViewer($engine->getViewer()) ->setViewer($engine->getViewer())
->withRepositoryPHIDs(array($this->getPHID())) ->withRepositoryPHIDs(array($phid))
->execute(); ->execute();
foreach ($atoms as $atom) { foreach ($atoms as $atom) {
$engine->destroyObject($atom); $engine->destroyObject($atom);

View file

@ -0,0 +1,67 @@
<?php
final class PhabricatorRepositoryURIIndex
extends PhabricatorRepositoryDAO {
protected $repositoryPHID;
protected $repositoryURI;
protected function getConfiguration() {
return array(
self::CONFIG_TIMESTAMPS => false,
self::CONFIG_COLUMN_SCHEMA => array(
'repositoryURI' => 'text',
),
self::CONFIG_KEY_SCHEMA => array(
'key_repository' => array(
'columns' => array('repositoryPHID'),
),
'key_uri' => array(
'columns' => array('repositoryURI(128)'),
),
),
) + parent::getConfiguration();
}
public static function updateRepositoryURIs(
$repository_phid,
array $uris) {
$table = new self();
$conn_w = $table->establishConnection('w');
$sql = array();
foreach ($uris as $key => $uri) {
if (!strlen($uri)) {
unset($uris[$key]);
continue;
}
$sql[] = qsprintf(
$conn_w,
'(%s, %s)',
$repository_phid,
$uri);
}
$table->openTransaction();
queryfx(
$conn_w,
'DELETE FROM %T WHERE repositoryPHID = %s',
$table->getTableName(),
$repository_phid);
if ($sql) {
queryfx(
$conn_w,
'INSERT INTO %T (repositoryPHID, repositoryURI) VALUES %Q',
$table->getTableName(),
implode(', ', $sql));
}
$table->saveTransaction();
}
}