Skip to content

Commit

Permalink
Merge pull request #28524 from owncloud/stable10-optimize1
Browse files Browse the repository at this point in the history
Stable10 optimize1
  • Loading branch information
Vincent Petry authored Aug 1, 2017
2 parents ba62aed + d6784fe commit a1b146d
Show file tree
Hide file tree
Showing 10 changed files with 580 additions and 80 deletions.
8 changes: 8 additions & 0 deletions apps/federatedfilesharing/lib/FederatedShareProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -725,6 +725,14 @@ public function getSharesByPath(Node $path) {
return $shares;
}


/**
* @inheritdoc
*/
public function getAllSharedWith($userId, $node) {
return $this->getSharedWith($userId, self::SHARE_TYPE_REMOTE, $node, -1, 0);
}

/**
* @inheritdoc
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -462,6 +462,11 @@ public function datatTestUpdate() {
];
}

public function testGetAllSharedWith() {
$shares = $this->provider->getAllSharedWith('shared', null);
$this->assertCount(0, $shares);
}


public function testGetAllSharesByNodes() {
$node = $this->createMock('\OCP\Files\File');
Expand Down
5 changes: 3 additions & 2 deletions apps/files_sharing/lib/MountProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,9 @@ public function __construct(IConfig $config, IManager $shareManager, ILogger $lo
* @return \OCP\Files\Mount\IMountPoint[]
*/
public function getMountsForUser(IUser $user, IStorageFactory $storageFactory) {
$shares = $this->shareManager->getSharedWith($user->getUID(), \OCP\Share::SHARE_TYPE_USER, null, -1);
$shares = array_merge($shares, $this->shareManager->getSharedWith($user->getUID(), \OCP\Share::SHARE_TYPE_GROUP, null, -1));
$requiredShareTypes = [\OCP\Share::SHARE_TYPE_USER, \OCP\Share::SHARE_TYPE_GROUP];
$shares = $this->shareManager->getAllSharedWith($user->getUID(), $requiredShareTypes, null);

// filter out excluded shares and group shares that includes self
$shares = array_filter($shares, function (\OCP\Share\IShare $share) use ($user) {
return $share->getPermissions() > 0 && $share->getShareOwner() !== $user->getUID();
Expand Down
35 changes: 19 additions & 16 deletions apps/files_sharing/tests/MountProviderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -112,18 +112,19 @@ public function testExcludeShares() {
$this->makeMockShare(5, 100, 'user1', '/share4', 31),
];

$userGroupUserShares = array_merge($userShares, $groupShares);

$this->user->expects($this->any())
->method('getUID')
->will($this->returnValue('user1'));

$this->shareManager->expects($this->at(0))
->method('getSharedWith')
->with('user1', \OCP\Share::SHARE_TYPE_USER)
->will($this->returnValue($userShares));
$this->shareManager->expects($this->at(1))
->method('getSharedWith')
->with('user1', \OCP\Share::SHARE_TYPE_GROUP, null, -1)
->will($this->returnValue($groupShares));
$requiredShareTypes = [\OCP\Share::SHARE_TYPE_USER, \OCP\Share::SHARE_TYPE_GROUP];
$this->shareManager->expects($this->once())
->method('getAllSharedWith')
->with('user1', $requiredShareTypes, null)
->will($this->returnValue($userGroupUserShares));
$this->shareManager->expects($this->never())
->method('getSharedWith');
$this->shareManager->expects($this->any())
->method('newShare')
->will($this->returnCallback(function() use ($rootFolder, $userManager) {
Expand Down Expand Up @@ -311,15 +312,17 @@ public function testMergeShares($userShares, $groupShares, $expectedShares, $mov
$this->user->expects($this->any())
->method('getUID')
->will($this->returnValue('user1'));

$userGroupUserShares = array_merge($userShares, $groupShares);
$requiredShareTypes = [\OCP\Share::SHARE_TYPE_USER, \OCP\Share::SHARE_TYPE_GROUP];
$this->shareManager->expects($this->once())
->method('getAllSharedWith')
->with('user1', $requiredShareTypes, null)
->will($this->returnValue($userGroupUserShares));

$this->shareManager->expects($this->never())
->method('getSharedWith');

$this->shareManager->expects($this->at(0))
->method('getSharedWith')
->with('user1', \OCP\Share::SHARE_TYPE_USER)
->will($this->returnValue($userShares));
$this->shareManager->expects($this->at(1))
->method('getSharedWith')
->with('user1', \OCP\Share::SHARE_TYPE_GROUP, null, -1)
->will($this->returnValue($groupShares));
$this->shareManager->expects($this->any())
->method('newShare')
->will($this->returnCallback(function() use ($rootFolder, $userManager) {
Expand Down
233 changes: 186 additions & 47 deletions lib/private/Share20/DefaultShareProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* @author phisch <[email protected]>
* @author Roeland Jago Douma <[email protected]>
* @author Vincent Petry <[email protected]>
* @author Piotr Mrowczynski <[email protected]>
*
* @copyright Copyright (c) 2017, ownCloud GmbH
* @license AGPL-3.0
Expand Down Expand Up @@ -674,6 +675,116 @@ private function isAccessibleResult($data) {
return true;
}

/*
* Get shared with user shares for the given userId and node
*
* @param string $userId
* @param Node|null $node
* @return DB\QueryBuilder\IQueryBuilder $qb
*/
public function getSharedWithUserQuery($userId, $node) {
$qb = $this->dbConn->getQueryBuilder();
$qb->select('s.*', 'f.fileid', 'f.path')
->selectAlias('st.id', 'storage_string_id')
->from('share', 's')
->leftJoin('s', 'filecache', 'f', $qb->expr()->eq('s.file_source', 'f.fileid'))
->leftJoin('f', 'storages', 'st', $qb->expr()->eq('f.storage', 'st.numeric_id'));

// Order by id
$qb->orderBy('s.id');

$qb->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_USER)))
->andWhere($qb->expr()->eq('share_with', $qb->createNamedParameter($userId)))
->andWhere($qb->expr()->orX(
$qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
$qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
));

// Filter by node if provided
if ($node !== null) {
$qb->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($node->getId())));
}

return $qb;
}

/*
* Get shared with group shares for the given groups and node
*
* @param IGroup[] $groups
* @param Node|null $node
* @return DB\QueryBuilder\IQueryBuilder $qb
*/
private function getSharedWithGroupQuery($groups, $node) {
$qb = $this->dbConn->getQueryBuilder();
$qb->select('s.*', 'f.fileid', 'f.path')
->selectAlias('st.id', 'storage_string_id')
->from('share', 's')
->leftJoin('s', 'filecache', 'f', $qb->expr()->eq('s.file_source', 'f.fileid'))
->leftJoin('f', 'storages', 'st', $qb->expr()->eq('f.storage', 'st.numeric_id'))
->orderBy('s.id');

// Filter by node if provided
if ($node !== null) {
$qb->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($node->getId())));
}

$groups = array_map(function(IGroup $group) { return $group->getGID(); }, $groups);

$qb->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_GROUP)))
->andWhere($qb->expr()->in('share_with', $qb->createNamedParameter(
$groups,
IQueryBuilder::PARAM_STR_ARRAY
)))
->andWhere($qb->expr()->orX(
$qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
$qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
));

return $qb;
}

/*
* Get shared with group and shared with user shares for the given groups, userId and node
*
* @param IGroup[] $groups
* @param string $userId
* @param Node|null $node
* @return DB\QueryBuilder\IQueryBuilder $qb
*/
private function getSharedWithUserGroupQuery($groups, $userId, $node) {
$qb = $this->dbConn->getQueryBuilder();
$qb->select('s.*', 'f.fileid', 'f.path')
->selectAlias('st.id', 'storage_string_id')
->from('share', 's')
->leftJoin('s', 'filecache', 'f', $qb->expr()->eq('s.file_source', 'f.fileid'))
->leftJoin('f', 'storages', 'st', $qb->expr()->eq('f.storage', 'st.numeric_id'))
->orderBy('s.id');

// Filter by node if provided
if ($node !== null) {
$qb->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($node->getId())));
}

$groups = array_map(function(IGroup $group) { return $group->getGID(); }, $groups);

$qb->andWhere($qb->expr()->orX(
$qb->expr()->andX(
$qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_GROUP)),
$qb->expr()->in('share_with', $qb->createNamedParameter(
$groups,
IQueryBuilder::PARAM_STR_ARRAY
))
),
$qb->expr()->andX(
$qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_USER)),
$qb->expr()->eq('share_with', $qb->createNamedParameter($userId))
)
));

return $qb;
}

/**
* @inheritdoc
*/
Expand All @@ -682,35 +793,15 @@ public function getSharedWith($userId, $shareType, $node, $limit, $offset) {
$shares = [];

if ($shareType === \OCP\Share::SHARE_TYPE_USER) {
//Get shares directly with this user
$qb = $this->dbConn->getQueryBuilder();
$qb->select('s.*', 'f.fileid', 'f.path')
->selectAlias('st.id', 'storage_string_id')
->from('share', 's')
->leftJoin('s', 'filecache', 'f', $qb->expr()->eq('s.file_source', 'f.fileid'))
->leftJoin('f', 'storages', 'st', $qb->expr()->eq('f.storage', 'st.numeric_id'));

// Order by id
$qb->orderBy('s.id');
// Create SharedWithUser query
$qb = $this->getSharedWithUserQuery($userId, $node);

// Set limit and offset
if ($limit !== -1) {
$qb->setMaxResults($limit);
}
$qb->setFirstResult($offset);

$qb->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_USER)))
->andWhere($qb->expr()->eq('share_with', $qb->createNamedParameter($userId)))
->andWhere($qb->expr()->orX(
$qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
$qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
));

// Filter by node if provided
if ($node !== null) {
$qb->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($node->getId())));
}

$cursor = $qb->execute();

while($data = $cursor->fetch()) {
Expand All @@ -736,36 +827,14 @@ public function getSharedWith($userId, $shareType, $node, $limit, $offset) {
break;
}

$qb = $this->dbConn->getQueryBuilder();
$qb->select('s.*', 'f.fileid', 'f.path')
->selectAlias('st.id', 'storage_string_id')
->from('share', 's')
->leftJoin('s', 'filecache', 'f', $qb->expr()->eq('s.file_source', 'f.fileid'))
->leftJoin('f', 'storages', 'st', $qb->expr()->eq('f.storage', 'st.numeric_id'))
->orderBy('s.id')
->setFirstResult(0);
// Create SharedWithGroups query
$qb = $this->getSharedWithGroupQuery($groups, $node);
$qb->setFirstResult(0);

if ($limit !== -1) {
$qb->setMaxResults($limit - count($shares));
}

// Filter by node if provided
if ($node !== null) {
$qb->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($node->getId())));
}

$groups = array_map(function(IGroup $group) { return $group->getGID(); }, $groups);

$qb->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_GROUP)))
->andWhere($qb->expr()->in('share_with', $qb->createNamedParameter(
$groups,
IQueryBuilder::PARAM_STR_ARRAY
)))
->andWhere($qb->expr()->orX(
$qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
$qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
));

$cursor = $qb->execute();
while($data = $cursor->fetch()) {
if ($offset > 0) {
Expand All @@ -792,6 +861,76 @@ public function getSharedWith($userId, $shareType, $node, $limit, $offset) {
return $shares;
}

/**
* @inheritdoc
*/
public function getAllSharedWith($userId, $node) {
// Create array of sharedWith objects (target user -> $userId or group of which user is a member
$user = $this->userManager->get($userId);

// Check if user is member of some groups and chunk them
$allGroups = $this->groupManager->getUserGroups($user, 'sharing');

// Make chunks
$sharedWithGroupChunks = array_chunk($allGroups, 100);

// Check how many group chunks do we need
$sharedWithGroupChunksNo = count($sharedWithGroupChunks);

// If there are not groups, query only user, if there are groups, query both
$chunkedResults = [];
if ($sharedWithGroupChunksNo === 0) {
// There are no groups, query only for user
$qb = $this->getSharedWithUserQuery($userId, $node);
$cursor = $qb->execute();
$chunkedResults[] = $cursor->fetchAll();
$cursor->closeCursor();
} else {
// There are groups, query both for user and for groups
$userSharesRetrieved = false;
for ($chunkNo = 0; $chunkNo < $sharedWithGroupChunksNo; $chunkNo++) {
// Get respective group chunk
$groups = $sharedWithGroupChunks[$chunkNo];

// Check if user shares were already retrieved
// One cannot retrieve user shares multiple times, since it will result in duplicated
// user shares with each query
if ($userSharesRetrieved === false) {
$qb = $this->getSharedWithUserGroupQuery($groups, $userId, $node);
$userSharesRetrieved = true;
} else {
$qb = $this->getSharedWithGroupQuery($groups, $node);
}
$cursor = $qb->execute();
$chunkedResults[] = $cursor->fetchAll();
$cursor->closeCursor();
}
}

$resolvedShares = [];
$groupShares = [];
foreach($chunkedResults as $resultBatch) {
foreach($resultBatch as $data) {
if ($this->isAccessibleResult($data)) {
$share = $this->createShare($data);
if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP){
$groupShares[] = $share;
} else {
$resolvedShares[] = $share;
}
}
}
}

//Resolve all group shares to user specific shares
if (!empty($groupShares)) {
$resolvedGroupShares = $this->resolveGroupShares($groupShares, $userId);
$resolvedShares = array_merge($resolvedShares, $resolvedGroupShares);
}

return $resolvedShares;
}

/**
* Get a share by token
*
Expand Down
Loading

0 comments on commit a1b146d

Please sign in to comment.