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鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: reduce sql queries in Share::getUsersSharingFile() #41111

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

DeepDiver1975
Copy link
Member

@DeepDiver1975 DeepDiver1975 commented Nov 20, 2023

Description

Save the 馃獝 - save CPU, network, memory, energy 馃懐

Number of queries of Share::getUsersSharingFile() has been reduced from 17+ to 8

Motivation and Context

Be smart on sql queries

How Has This Been Tested?

  • 馃

Screenshots (if appropriate):

image

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Database schema changes (next release will require increase of minor version instead of patch)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Technical debt
  • Tests only (no source changes)

Checklist:

  • Code changes
  • Unit tests added
  • Acceptance tests added
  • Documentation ticket raised:
  • Changelog item, see TEMPLATE

Copy link

update-docs bot commented Nov 20, 2023

Thanks for opening this pull request! The maintainers of this repository would appreciate it if you would create a changelog item based on your changes.

@DeepDiver1975 DeepDiver1975 force-pushed the fix/sql-query-count-share-getusersharingfile branch 3 times, most recently from 2f5953e to c327327 Compare November 20, 2023 16:28
@DeepDiver1975 DeepDiver1975 force-pushed the fix/sql-query-count-share-getusersharingfile branch from c327327 to 403d025 Compare November 21, 2023 08:18
Copy link
Member

@jvillafanez jvillafanez left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have we taken into account the error handling? I see some if (\OCP\DB::isError($result)) { code removed, but not the matching code.

$s = preg_replace('/\s\s+/', ' ', $this->sql);
foreach ($this->params as $i => $param) {
$param = json_encode($param);
$pos = strpos($s, '?');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This might be problematic if the query contains ? which aren't placeholders.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

indeed - but I consider this a minor issue for the time being as this is for pure debugging purpose.
I did not find a better way. 馃し

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The json-serialized data looks good to me, just return the query and the parameters separately.
Anyway, I think we should add a TODO / FIXME at least so we're aware of this issue.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The json-serialized data looks good to me, just return the query and the parameters separately.

this has a very bad DX as it requires brain power to interpolate the strings. Does not really help to analyse the sql chaos we have ....

@@ -182,125 +185,94 @@ public static function getUsersSharingFile($path, $ownerUser, $includeOwner = fa
}
}

// let's get the parent for the next round
if ($recursive === true) {
while ($source !== -1) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess we'll have to assume that there will always be a "source == 1" entry. I think the request will crash with an "out of memory" error in case of an infinite loop, but I don't know if there is anything we could do to pinpoint where the problem is if that happens.

$source = (int)$meta['parent'];
$sources[]= $source;
} else {
break;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should log something in this case. If we don't get the parent it means that part of the tree structure is broken, which seems serious to me.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

-1 means we hit the root of the tree and we can stop.

Logic is basically unchanged it was extracted to prevent executing sql in the loop.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But we hit this break if $cache->get((int)$source) === false.
I mean, assuming we have a working tree, we'll leave the loop "naturally" because the $source will be -1 eventually. However, we enter this break if we don't get the cache info from the source file; if this happens, we might have a broken tree because we can't reach the root of the storage, so I think we should at least log something.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will have a second look ... as stated above: this code is working 鈩笍 this way for quite a long time this way .....
Nevertheless you might be right ..... thx

$qb->select('share_with', 'share_type')
->from('share')
->where($qb->expr()->in('item_source', $qb->createNamedParameter($sources, Connection::PARAM_INT_ARRAY)))
->andWhere($qb->expr()->in('share_type', $qb->createNamedParameter([3, 6], Connection::PARAM_INT_ARRAY)))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should use constants here.

->andWhere($qb->expr()->in('share_type', $qb->createNamedParameter([3, 6], Connection::PARAM_INT_ARRAY)))
->andWhere($qb->expr()->in('item_type', $qb->createNamedParameter(['file', 'folder'], Connection::PARAM_STR_ARRAY)));
$result = $qb->execute();
$rows = $result->fetchAllAssociative();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if the query is limited enough to fetch all rows at once. We could clarify with a comment that the limiting factor is that we'll search a few item sources, so we expect 10-20 entries at most (which should be fine).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was doing my calcs based on the fact that this can be 2 entries per folder depth - but this is wrong.
There can be by far more shares.

Will adapt this. THX for the hint 馃檹

@DeepDiver1975
Copy link
Member Author

Have we taken into account the error handling? I see some if (\OCP\DB::isError($result)) { code removed, but not the matching code.

To my understanding in case of errors we will receive exception from dbal. These checks are pointless from my understanding. But feel free to prove me wrong.

@DeepDiver1975 DeepDiver1975 force-pushed the fix/sql-query-count-share-getusersharingfile branch from 403d025 to 39bb864 Compare November 21, 2023 11:52
Copy link

sonarcloud bot commented Nov 21, 2023

Kudos, SonarCloud Quality Gate passed!聽 聽 Quality Gate passed

Bug A 0 Bugs
Vulnerability A 0 Vulnerabilities
Security Hotspot A 0 Security Hotspots
Code Smell A 2 Code Smells

96.1% 96.1% Coverage
0.0% 0.0% Duplication

@jvillafanez
Copy link
Member

To my understanding in case of errors we will receive exception from dbal. These checks are pointless from my understanding. But feel free to prove me wrong.

So the idea is to let the DBAL exception propagate upwards I guess. I'm ok with that, although I don't know how ownCloud will behave.

@DeepDiver1975
Copy link
Member Author

So the idea is to let the DBAL exception propagate upwards I guess. I'm ok with that, although I don't know how ownCloud will behave.

this was already the case for the old code from my understanding.

@DeepDiver1975 DeepDiver1975 force-pushed the fix/sql-query-count-share-getusersharingfile branch from 39bb864 to a5e3026 Compare November 21, 2023 16:03
@DeepDiver1975
Copy link
Member Author

DeepDiver1975 commented Nov 22, 2023

That's what you get when adding unit tests to legacy code 馃檲

1) Test\Share\GetUsersSharingFileTest::testIncludeOwner

Failed asserting that two arrays are equal.
--- Expected
+++ Actual
@@ @@
 Array (
-    'bob' => '/foo/welcome.txt'
+    'bob' => 'foo/welcome.txt'
 )

/drone/src/tests/lib/Share/GetUsersSharingFileTest.php:229
phpvfscomposer:///drone/src/lib/composer/phpunit/phpunit/phpunit:106

@DeepDiver1975
Copy link
Member Author

master is also generating the path without the leading slash .... why ever ....

@DeepDiver1975 DeepDiver1975 force-pushed the fix/sql-query-count-share-getusersharingfile branch from a5e3026 to 5d72d79 Compare November 23, 2023 09:13
@DeepDiver1975 DeepDiver1975 force-pushed the fix/sql-query-count-share-getusersharingfile branch from 5d72d79 to ccf3b98 Compare November 23, 2023 09:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants