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

Propagate etags across shared storages #14764

Merged
merged 20 commits into from
Apr 28, 2015
Merged

Conversation

icewind1991
Copy link
Contributor

Solution involves three parts

  • Watch for filesystem changes made inside a shared mount, when detected, trigger the change propagator for the owner of the storage
  • Listen to the change propagator, when it updates the etag of a shared item, mark the shares as "dirty"
  • When setting up the filesystem, trigger the change propagator for each "dirty" mountpoint

cc @PVince81 @DeepDiver1975

@icewind1991
Copy link
Contributor Author

@PVince81 I think I have all distinct cases covered by the unit tests, please check if you can think of a situation not covered

@MorrisJobke
Copy link
Contributor

@icewind1991 This was a quick merge conflict ... rebase required ;)

@icewind1991 icewind1991 force-pushed the shared-etag-propagate branch from 60df28b to 174eda0 Compare March 9, 2015 16:04
@DeepDiver1975 DeepDiver1975 added this to the 8.1-current milestone Mar 9, 2015
if ($time === null) {
$time = time();
}
$this->config->setAppValue('files_sharing', $share['id'], $time);
Copy link
Member

Choose a reason for hiding this comment

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

Will this ever be removed again? Looks like we are going to pollute the appconfig table

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I could move the timestamp to the share table (requires schema change) or use an unshare hook to cleanup

Copy link
Contributor

Choose a reason for hiding this comment

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

I remember we have a similar mechanism for external storages. Maybe that would be a candidate for a future new table for mount points ? So I'm not sure we should move it to the share table now.

Copy link
Contributor

Choose a reason for hiding this comment

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

Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe using oc_share isn't that bad an idea. At least it prevents requiring ALL share ids and makes it possible to only query the ones that have the dirty flag set.

Schema change: yes, if for 8.1.
I have the feeling that this whole fix isn't backportable anyway. 😦

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We already have a list of all shares from setting up the mounts

@PVince81
Copy link
Contributor

Had a quick look and it confirms what I thought: the fix for this will big and not backportable.
I still wonder how we managed to make it work in OC 6. Maybe it was because all you had to do is update the etag of the "Shared" folder for all users (if we ever did...)

@DeepDiver1975
Copy link
Member

Maybe it was because all you had to do is update the etag of the "Shared" folder for all users (if we ever did...)

yes - every user had a pseudo etag for the shared folder in his preferences. This approach no longer works.

@@ -0,0 +1,138 @@
<?php
/**
* Copyright (c) 2014 Robin Appelman <[email protected]>
Copy link
Contributor

Choose a reason for hiding this comment

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

Man, you live in the past!

@PVince81
Copy link
Contributor

@icewind1991 did you do a blackfire compare before and after this branch to find potential perf issues ? Performance is my first worry, second one is backportability.

$shares = Share::getAllSharesForOwner($owner);
$propagator->listen('\OC\Files', 'propagate', function ($path, $entry) use ($shares) {
foreach ($shares as $share) {
if ((int)$share['file_source'] === $entry['fileid']) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Hmmm wait, why do we need all shares ?
We only need all shares that have file_source = fileid, probably doable with a custom SQL statement.

Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe getUsersItemShare() could get you all recipients https://github.com/owncloud/core/blob/master/lib/private/share/share.php#L506

And use getUsersSharingFile https://github.com/owncloud/core/blob/master/lib/private/share/share.php#L102 for reshares, etc that will need update as well.

@PVince81
Copy link
Contributor

Sorry for the maaaany comments. The approach you used is a good idea but need a bit of tweaking.
Did you test this with reshares too ? (I haven't tested yet)

Test plan

Owner O shares "test" with recipients R1 and R2
  • upload into "test/test.txt" as O: etag propagates to root of O, R1, R2
  • upload into "test/test.txt" as R1: etag propagates to root of O, R1, R2
  • unshare "test" as O: etag propagates to O, R1, R2
R2 reshares "test" with R3
  • upload into "test/test.txt" as O: etag propagates to O, R1, R2, R3
  • upload into "test/test.txt" as R2: etag propagates to O, R1, R2, R3
  • upload into "test/test.txt" as R3: etag propagates to O, R1, R2, R3
  • unshare "test" as R2: etag propagates to R1, R2, R3
R2 reshares subdir "test/sub" with R4
  • upload into "test/test.txt" as O: etag propagates to O, R1, R2, R3 (not R4)
  • upload into "test/test.txt" as R2: etag propagates to O, R1, R2, R3 (not R4)
  • upload into "test/sub/test.txt" as O: etag propagates to O, R1, R2, R3 (through reshare of "test"), R4
  • upload into "test/sub/test.txt" as R1: etag propagates to O, R1, R2, R3 (through reshare of "test"), R4
  • upload into "test/sub/test.txt" as R4: etag propagates to O, R1, R2, R3 (through reshare of "test"), R4
  • unshare "test/sub" as R2: etag propagates to R1, R2, R3, R4
Groups
  • similar tests as above with groups

@icewind1991 icewind1991 force-pushed the shared-etag-propagate branch from 174eda0 to e8e9948 Compare March 12, 2015 14:59
@icewind1991
Copy link
Contributor Author

Did some refactoring, splitting up classes and getting rid of static stuff

* @param string $owner
*/
public function attachToPropagator(ChangePropagator $propagator, $owner) {
$shares = Share::getAllSharesForOwner($owner);
Copy link
Member

Choose a reason for hiding this comment

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

We really need to query all shares - even if the closure below is never called?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

changed it to query on demand

@PVince81
Copy link
Contributor

Happens here:

0  OC_Share_Backend_File::getSource() /srv/www/htdocs/owncloud/apps/files_sharing/lib/share/file.php:228
1  OC\Files\Cache\Shared_Cache->getSourceCache() /srv/www/htdocs/owncloud/apps/files_sharing/lib/cache.php:63
2  OC\Files\Cache\Shared_Cache->get() /srv/www/htdocs/owncloud/apps/files_sharing/lib/cache.php:98
3  OC\Files\Cache\ChangePropagator->propagateChanges() /srv/www/htdocs/owncloud/lib/private/files/cache/changepropagator.php:78
4  OCA\Files_Sharing\Propagation\ChangeWatcher->propagateForOwner() /srv/www/htdocs/owncloud/apps/files_sharing/lib/propagation/changewatcher.php:73
5  OCA\Files_Sharing\Propagation\ChangeWatcher->writeHook() /srv/www/htdocs/owncloud/apps/files_sharing/lib/propagation/changewatcher.php:40
6  call_user_func:{/srv/www/htdocs/owncloud/lib/private/hook.php:103}() /srv/www/htdocs/owncloud/lib/private/hook.php:103
7  OC_Hook::emit() /srv/www/htdocs/owncloud/lib/private/hook.php:103
8  OC\Files\View->emit_file_hooks_post() /srv/www/htdocs/owncloud/lib/private/files/view.php:513
9  OC\Files\View->file_put_contents() /srv/www/htdocs/owncloud/lib/private/files/view.php:543
10 OC\Files\View->fromTmpFile() /srv/www/htdocs/owncloud/lib/private/files/view.php:840
11 OC\Files\Filesystem::fromTmpFile() /srv/www/htdocs/owncloud/lib/private/files/filesystem.php:700
12 require_once()  /srv/www/htdocs/owncloud/apps/files/ajax/upload.php:191
13 __lambda_func() /srv/www/htdocs/owncloud/lib/private/route/route.php%28153%29%20:%20runtime-created%20function:1
14 call_user_func:{/srv/www/htdocs/owncloud/lib/private/route/router.php:272}() /srv/www/htdocs/owncloud/lib/private/route/router.php:272
15 OC\Route\Router->match() /srv/www/htdocs/owncloud/lib/private/route/router.php:272
16 OC::handleRequest() /srv/www/htdocs/owncloud/lib/base.php:853
17 {main}          /srv/www/htdocs/owncloud/index.php:40

@PVince81
Copy link
Contributor

@icewind1991 it looks like this is also triggered by the unit test "testReshareRecipientWritesToReshare" which matches the case. The test doesn't fail because it's only logged as DEBUG. Maybe the consequence is harmless or the situation is expected.
We should still add some checks to avoid logging this (or even going this code path) when expected.

@icewind1991
Copy link
Contributor Author

Ok, can reproduce it now, since it's just a debug message and doesnt seem to affect the propagation can we merge this PR and raise a new issue for the message

@PVince81
Copy link
Contributor

Ok. But I noticed that the unit test don't check the etag of "folder", I want to double check because I'm not certain that it is harmless.

@PVince81
Copy link
Contributor

@MorrisJobke review ?

@PVince81
Copy link
Contributor

I checked with a manual test, the etag of "folder" changes properly. So not sure about the consequences. During my quick debug session I had the feeling it would not propagate to owner (which is the code path where the warning appears) but somehow it still manages to propagate there, possibly through other means.

👍 for now, will raise the next ticket(s) as soon as this is merged

@scrutinizer-notifier
Copy link

A new inspection was created.

@icewind1991
Copy link
Contributor Author

Tests passed on jenkins pr

@PVince81
Copy link
Contributor

@nickvergessen @LukasReschke @DeepDiver1975 @MorrisJobke please review.

Test plan is here: #14764 (comment) (and also covered by the unit tests)

@MorrisJobke
Copy link
Contributor

I will do the review and merge once I'm fine with this.

@MorrisJobke
Copy link
Contributor

I tested most of the cases above and all succeed. I also couldn't find any errors in the logs.

Awesome work @PVince81 @icewind1991 🚀 🚢 🇮🇹 👍

MorrisJobke added a commit that referenced this pull request Apr 28, 2015
Propagate etags across shared storages
@MorrisJobke MorrisJobke merged commit de8c15e into master Apr 28, 2015
@MorrisJobke MorrisJobke deleted the shared-etag-propagate branch April 28, 2015 08:58
@PVince81
Copy link
Contributor

I will take care or raising tickets for the remaining issues.

@PVince81
Copy link
Contributor

We should also look into providing a simple backportable solution for older versions, but for that we need to first indentify which cases were exactly broken. Maybe using the "etagpropagation" unit test from this PR could help.

@PVince81
Copy link
Contributor

@karlitschek ^

@MorrisJobke
Copy link
Contributor

To share the test setup with you all - Outside the ❄️ is falling and I'm in the 🚌 and my 💻 looks like this:
bildschirmfoto von 2015-04-28 10-56-17

@PVince81
Copy link
Contributor

Raised remaining tickets:

@LukasReschke
Copy link
Member

💣 💣 💣

Broke sharing: #15913

💣 💣 💣

mmattel pushed a commit to mmattel/core that referenced this pull request May 22, 2015
@lock lock bot locked as resolved and limited conversation to collaborators Aug 12, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants