Merge pull request #14207 from owncloud/propfind-optimize

Optimize quota calculation for propfind
This commit is contained in:
Morris Jobke 2015-02-18 00:18:47 +01:00
commit 5d7d2adcbf
2 changed files with 57 additions and 18 deletions

View file

@ -20,7 +20,6 @@
* License along with this library. If not, see <http://www.gnu.org/licenses/>. * License along with this library. If not, see <http://www.gnu.org/licenses/>.
* *
*/ */
class OC_Connector_Sabre_Directory extends OC_Connector_Sabre_Node class OC_Connector_Sabre_Directory extends OC_Connector_Sabre_Node
implements \Sabre\DAV\ICollection, \Sabre\DAV\IQuota { implements \Sabre\DAV\ICollection, \Sabre\DAV\IQuota {
@ -31,6 +30,13 @@ class OC_Connector_Sabre_Directory extends OC_Connector_Sabre_Node
*/ */
private $dirContent; private $dirContent;
/**
* Cached quota info
*
* @var array
*/
private $quotaInfo;
/** /**
* Creates a new file in the directory * Creates a new file in the directory
* *
@ -66,7 +72,8 @@ class OC_Connector_Sabre_Directory extends OC_Connector_Sabre_Node
// exit if we can't create a new file and we don't updatable existing file // exit if we can't create a new file and we don't updatable existing file
$info = OC_FileChunking::decodeName($name); $info = OC_FileChunking::decodeName($name);
if (!$this->fileView->isCreatable($this->path) && if (!$this->fileView->isCreatable($this->path) &&
!$this->fileView->isUpdatable($this->path . '/' . $info['name'])) { !$this->fileView->isUpdatable($this->path . '/' . $info['name'])
) {
throw new \Sabre\DAV\Exception\Forbidden(); throw new \Sabre\DAV\Exception\Forbidden();
} }
@ -101,8 +108,8 @@ class OC_Connector_Sabre_Directory extends OC_Connector_Sabre_Node
} }
$newPath = $this->path . '/' . $name; $newPath = $this->path . '/' . $name;
if(!$this->fileView->mkdir($newPath)) { if (!$this->fileView->mkdir($newPath)) {
throw new \Sabre\DAV\Exception\Forbidden('Could not create directory '.$newPath); throw new \Sabre\DAV\Exception\Forbidden('Could not create directory ' . $newPath);
} }
} catch (\OCP\Files\StorageNotAvailableException $e) { } catch (\OCP\Files\StorageNotAvailableException $e) {
throw new \Sabre\DAV\Exception\ServiceUnavailable($e->getMessage()); throw new \Sabre\DAV\Exception\ServiceUnavailable($e->getMessage());
@ -152,14 +159,14 @@ class OC_Connector_Sabre_Directory extends OC_Connector_Sabre_Node
$properties = array(); $properties = array();
$paths = array(); $paths = array();
foreach($folderContent as $info) { foreach ($folderContent as $info) {
$name = $info->getName(); $name = $info->getName();
$paths[] = $this->path . '/' . $name; $paths[] = $this->path . '/' . $name;
$properties[$this->path.'/' . $name][self::GETETAG_PROPERTYNAME] = '"' . $info->getEtag() . '"'; $properties[$this->path . '/' . $name][self::GETETAG_PROPERTYNAME] = '"' . $info->getEtag() . '"';
} }
// TODO: move this to a beforeGetPropertiesForPath event to pre-cache properties // TODO: move this to a beforeGetPropertiesForPath event to pre-cache properties
// TODO: only fetch the requested properties // TODO: only fetch the requested properties
if(count($paths)>0) { if (count($paths) > 0) {
// //
// the number of arguments within IN conditions are limited in most databases // the number of arguments within IN conditions are limited in most databases
// we chunk $paths into arrays of 200 items each to meet this criteria // we chunk $paths into arrays of 200 items each to meet this criteria
@ -167,15 +174,15 @@ class OC_Connector_Sabre_Directory extends OC_Connector_Sabre_Node
$chunks = array_chunk($paths, 200, false); $chunks = array_chunk($paths, 200, false);
foreach ($chunks as $pack) { foreach ($chunks as $pack) {
$placeholders = join(',', array_fill(0, count($pack), '?')); $placeholders = join(',', array_fill(0, count($pack), '?'));
$query = OC_DB::prepare( 'SELECT * FROM `*PREFIX*properties`' $query = OC_DB::prepare('SELECT * FROM `*PREFIX*properties`'
.' WHERE `userid` = ?' . ' AND `propertypath` IN ('.$placeholders.')' ); . ' WHERE `userid` = ?' . ' AND `propertypath` IN (' . $placeholders . ')');
array_unshift($pack, OC_User::getUser()); // prepend userid array_unshift($pack, OC_User::getUser()); // prepend userid
$result = $query->execute( $pack ); $result = $query->execute($pack);
while($row = $result->fetchRow()) { while ($row = $result->fetchRow()) {
$propertypath = $row['propertypath']; $propertypath = $row['propertypath'];
$propertyname = $row['propertyname']; $propertyname = $row['propertyname'];
$propertyvalue = $row['propertyvalue']; $propertyvalue = $row['propertyvalue'];
if($propertyname !== self::GETETAG_PROPERTYNAME) { if ($propertyname !== self::GETETAG_PROPERTYNAME) {
$properties[$propertypath][$propertyname] = $propertyvalue; $properties[$propertypath][$propertyname] = $propertyvalue;
} }
} }
@ -183,7 +190,7 @@ class OC_Connector_Sabre_Directory extends OC_Connector_Sabre_Node
} }
$nodes = array(); $nodes = array();
foreach($folderContent as $info) { foreach ($folderContent as $info) {
$node = $this->getChild($info->getName(), $info); $node = $this->getChild($info->getName(), $info);
$node->setPropertyCache($properties[$this->path . '/' . $info->getName()]); $node->setPropertyCache($properties[$this->path . '/' . $info->getName()]);
$nodes[] = $node; $nodes[] = $node;
@ -230,15 +237,17 @@ class OC_Connector_Sabre_Directory extends OC_Connector_Sabre_Node
* @return array * @return array
*/ */
public function getQuotaInfo() { public function getQuotaInfo() {
if ($this->quotaInfo) {
return $this->quotaInfo;
}
try { try {
$path = \OC\Files\Filesystem::getView()->getRelativePath($this->info->getPath()); $storageInfo = OC_Helper::getStorageInfo($this->info->getPath(), $this->info);
$storageInfo = OC_Helper::getStorageInfo($path); $this->quotaInfo = array(
return array(
$storageInfo['used'], $storageInfo['used'],
$storageInfo['free'] $storageInfo['free']
); );
} return $this->quotaInfo;
catch (\OCP\Files\StorageNotAvailableException $e) { } catch (\OCP\Files\StorageNotAvailableException $e) {
return array(0, 0); return array(0, 0);
} }
} }

View file

@ -155,4 +155,34 @@ class Test_OC_Connector_Sabre_Directory extends \Test\TestCase {
$nodes[1]->getProperties($properties) $nodes[1]->getProperties($properties)
); );
} }
public function testGetQuotaInfo() {
$storage = $this->getMockBuilder('\OC\Files\Storage\Wrapper\Quota')
->disableOriginalConstructor()
->getMock();
$storage->expects($this->once())
->method('instanceOfStorage')
->with('\OC\Files\Storage\Wrapper\Quota')
->will($this->returnValue(true));
$storage->expects($this->once())
->method('getQuota')
->will($this->returnValue(1000));
$storage->expects($this->once())
->method('free_space')
->will($this->returnValue(800));
$this->info->expects($this->once())
->method('getSize')
->will($this->returnValue(200));
$this->info->expects($this->once())
->method('getStorage')
->will($this->returnValue($storage));
$dir = new OC_Connector_Sabre_Directory($this->view, $this->info);
$this->assertEquals([200, 800], $dir->getQuotaInfo()); //200 used, 800 free
}
} }