Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stable10 optimize1 #28524

Merged
merged 3 commits into from
Aug 1, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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