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/>.
*
*/
class OC_Connector_Sabre_Directory extends OC_Connector_Sabre_Node
implements \Sabre\DAV\ICollection, \Sabre\DAV\IQuota {
@ -31,6 +30,13 @@ class OC_Connector_Sabre_Directory extends OC_Connector_Sabre_Node
*/
private $dirContent;
/**
* Cached quota info
*
* @var array
*/
private $quotaInfo;
/**
* 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
$info = OC_FileChunking::decodeName($name);
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();
}
@ -101,8 +108,8 @@ class OC_Connector_Sabre_Directory extends OC_Connector_Sabre_Node
}
$newPath = $this->path . '/' . $name;
if(!$this->fileView->mkdir($newPath)) {
throw new \Sabre\DAV\Exception\Forbidden('Could not create directory '.$newPath);
if (!$this->fileView->mkdir($newPath)) {
throw new \Sabre\DAV\Exception\Forbidden('Could not create directory ' . $newPath);
}
} catch (\OCP\Files\StorageNotAvailableException $e) {
throw new \Sabre\DAV\Exception\ServiceUnavailable($e->getMessage());
@ -152,14 +159,14 @@ class OC_Connector_Sabre_Directory extends OC_Connector_Sabre_Node
$properties = array();
$paths = array();
foreach($folderContent as $info) {
foreach ($folderContent as $info) {
$name = $info->getName();
$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: 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
// 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);
foreach ($chunks as $pack) {
$placeholders = join(',', array_fill(0, count($pack), '?'));
$query = OC_DB::prepare( 'SELECT * FROM `*PREFIX*properties`'
.' WHERE `userid` = ?' . ' AND `propertypath` IN ('.$placeholders.')' );
$query = OC_DB::prepare('SELECT * FROM `*PREFIX*properties`'
. ' WHERE `userid` = ?' . ' AND `propertypath` IN (' . $placeholders . ')');
array_unshift($pack, OC_User::getUser()); // prepend userid
$result = $query->execute( $pack );
while($row = $result->fetchRow()) {
$result = $query->execute($pack);
while ($row = $result->fetchRow()) {
$propertypath = $row['propertypath'];
$propertyname = $row['propertyname'];
$propertyvalue = $row['propertyvalue'];
if($propertyname !== self::GETETAG_PROPERTYNAME) {
if ($propertyname !== self::GETETAG_PROPERTYNAME) {
$properties[$propertypath][$propertyname] = $propertyvalue;
}
}
@ -183,7 +190,7 @@ class OC_Connector_Sabre_Directory extends OC_Connector_Sabre_Node
}
$nodes = array();
foreach($folderContent as $info) {
foreach ($folderContent as $info) {
$node = $this->getChild($info->getName(), $info);
$node->setPropertyCache($properties[$this->path . '/' . $info->getName()]);
$nodes[] = $node;
@ -230,15 +237,17 @@ class OC_Connector_Sabre_Directory extends OC_Connector_Sabre_Node
* @return array
*/
public function getQuotaInfo() {
if ($this->quotaInfo) {
return $this->quotaInfo;
}
try {
$path = \OC\Files\Filesystem::getView()->getRelativePath($this->info->getPath());
$storageInfo = OC_Helper::getStorageInfo($path);
return array(
$storageInfo = OC_Helper::getStorageInfo($this->info->getPath(), $this->info);
$this->quotaInfo = array(
$storageInfo['used'],
$storageInfo['free']
);
}
catch (\OCP\Files\StorageNotAvailableException $e) {
return $this->quotaInfo;
} catch (\OCP\Files\StorageNotAvailableException $e) {
return array(0, 0);
}
}

View File

@ -155,4 +155,34 @@ class Test_OC_Connector_Sabre_Directory extends \Test\TestCase {
$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
}
}