mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-22 14:52:41 +01:00
Skip loading attached objects for files when we know the file is visible
Summary: Depends on D19222. Ref T13106. We currently execute an edge query (and possibly an object query) when loading builtin files, but this is never necessary because we know these files are always visible. Instead, skip this logic for builtin files and profile image files; these files have global visibility and will never get a different policy result because of file attachment information. (In theory, we could additionally skip this for files with the most open visibility policy or some other trivially visible policy like the user's PHID, but we do actually care about the attachment data some of the time.) Test Plan: Saw queries drop from 151 to 145 on local test page. Checked file attachment data in Files, saw it still working correctly. Maniphest Tasks: T13106 Differential Revision: https://secure.phabricator.com/D19223
This commit is contained in:
parent
49e6358fce
commit
31bd3679f0
1 changed files with 57 additions and 29 deletions
|
@ -152,46 +152,74 @@ final class PhabricatorFileQuery
|
|||
}
|
||||
|
||||
protected function loadPage() {
|
||||
$files = $this->loadStandardPage(new PhabricatorFile());
|
||||
$files = $this->loadStandardPage($this->newResultObject());
|
||||
|
||||
if (!$files) {
|
||||
return $files;
|
||||
}
|
||||
|
||||
// Figure out which files we need to load attached objects for. In most
|
||||
// cases, we need to load attached objects to perform policy checks for
|
||||
// files.
|
||||
|
||||
// However, in some special cases where we know files will always be
|
||||
// visible, we skip this. See T8478 and T13106.
|
||||
$need_objects = array();
|
||||
foreach ($files as $file) {
|
||||
$always_visible = false;
|
||||
|
||||
if ($file->getIsProfileImage()) {
|
||||
$always_visible = true;
|
||||
}
|
||||
|
||||
if ($file->isBuiltin()) {
|
||||
$always_visible = true;
|
||||
}
|
||||
|
||||
if ($always_visible) {
|
||||
// We just treat these files as though they aren't attached to
|
||||
// anything. This saves a query in common cases when we're loading
|
||||
// profile images or builtins. We could be slightly more nuanced
|
||||
// about this and distinguish between "not attached to anything" and
|
||||
// "might be attached but policy checks don't need to care".
|
||||
$file->attachObjectPHIDs(array());
|
||||
continue;
|
||||
}
|
||||
|
||||
$need_objects[] = $file;
|
||||
}
|
||||
|
||||
$viewer = $this->getViewer();
|
||||
$is_omnipotent = $viewer->isOmnipotent();
|
||||
|
||||
// We need to load attached objects to perform policy checks for files.
|
||||
// First, load the edges.
|
||||
|
||||
$edge_type = PhabricatorFileHasObjectEdgeType::EDGECONST;
|
||||
$file_phids = mpull($files, 'getPHID');
|
||||
$edges = id(new PhabricatorEdgeQuery())
|
||||
->withSourcePHIDs($file_phids)
|
||||
->withEdgeTypes(array($edge_type))
|
||||
->execute();
|
||||
|
||||
// If we have any files left which do need objects, load the edges now.
|
||||
$object_phids = array();
|
||||
foreach ($files as $file) {
|
||||
$phids = array_keys($edges[$file->getPHID()][$edge_type]);
|
||||
$file->attachObjectPHIDs($phids);
|
||||
if ($need_objects) {
|
||||
$edge_type = PhabricatorFileHasObjectEdgeType::EDGECONST;
|
||||
$file_phids = mpull($need_objects, 'getPHID');
|
||||
|
||||
if ($file->getIsProfileImage()) {
|
||||
// If this is a profile image, don't bother loading related files.
|
||||
// It will always be visible, and we can get into trouble if we try
|
||||
// to load objects and end up stuck in a cycle. See T8478.
|
||||
continue;
|
||||
}
|
||||
$edges = id(new PhabricatorEdgeQuery())
|
||||
->withSourcePHIDs($file_phids)
|
||||
->withEdgeTypes(array($edge_type))
|
||||
->execute();
|
||||
|
||||
if ($is_omnipotent) {
|
||||
// If the viewer is omnipotent, we don't need to load the associated
|
||||
// objects either since they can certainly see the object. Skipping
|
||||
// this can improve performance and prevent cycles.
|
||||
continue;
|
||||
}
|
||||
foreach ($need_objects as $file) {
|
||||
$phids = array_keys($edges[$file->getPHID()][$edge_type]);
|
||||
$file->attachObjectPHIDs($phids);
|
||||
|
||||
foreach ($phids as $phid) {
|
||||
$object_phids[$phid] = true;
|
||||
if ($is_omnipotent) {
|
||||
// If the viewer is omnipotent, we don't need to load the associated
|
||||
// objects either since the viewer can certainly see the object.
|
||||
// Skipping this can improve performance and prevent cycles. This
|
||||
// could possibly become part of the profile/builtin code above which
|
||||
// short circuits attacment policy checks in cases where we know them
|
||||
// to be unnecessary.
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($phids as $phid) {
|
||||
$object_phids[$phid] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -203,7 +231,7 @@ final class PhabricatorFileQuery
|
|||
|
||||
$xforms = id(new PhabricatorTransformedFile())->loadAllWhere(
|
||||
'transformedPHID IN (%Ls)',
|
||||
$file_phids);
|
||||
mpull($files, 'getPHID'));
|
||||
$xform_phids = mpull($xforms, 'getOriginalPHID', 'getTransformedPHID');
|
||||
foreach ($xform_phids as $derived_phid => $original_phid) {
|
||||
$object_phids[$original_phid] = true;
|
||||
|
|
Loading…
Reference in a new issue