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

Proper copy/move between multiple local storages #13360

Merged
merged 12 commits into from
Apr 14, 2015
Merged

Conversation

icewind1991
Copy link
Contributor

This allows storage backends to implement logic for efficient copying/moving between storage backends (i.e. from local storage to local storage)

Part of the work for https://github.com/owncloud/enterprise/issues/472

Next step is having the shared storage pass the copy/move operation to the underlying storage using the same interface so it trigers the local->local copy/move logic

cc @DeepDiver1975 @PVince81

Test plan @jnfrmarks @SergioBertolinSG

from/to local shared mounted (e.g. SMB) shared mounted
local
shared
mounted (e.g. SMB)
shared mounted

@DeepDiver1975 DeepDiver1975 added this to the 8.0-current milestone Jan 14, 2015
* @param string $targetInternalPath
* @return bool
*/
public function crossMove($sourceStorage, $sourceInternalPath, $targetInternalPath) {
Copy link
Member

Choose a reason for hiding this comment

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

enforce type of $sourceStorage?

Copy link
Contributor

Choose a reason for hiding this comment

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

Also add PHP docs

Copy link
Contributor

Choose a reason for hiding this comment

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

Rename to "moveFromStorage" ?

Should we actually return false or still attempt to download the file then delete it remotely ?

@PVince81
Copy link
Contributor

I guess this is also a step forward to fix file id stability ? (at least when copying from local to local, not ext storages)

* @var \OC\Files\Storage\Local $sourceStorage
*/
$rootStorage = new Local(['datadir' => '/']);
return $rootStorage->copy($sourceStorage->getSourcePath($sourceInternalPath), $this->getSourcePath($targetInternalPath));
Copy link
Contributor

Choose a reason for hiding this comment

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

Should we add "getSourcePath()" to the Storage interface ?
I see that method is protected on the Local storage but public in SharedStorage.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Should we add "getSourcePath()" to the Storage interface

No, it only makes sense for some backends, and the Local and Shared versions both mean something different

@icewind1991
Copy link
Contributor Author

I guess this is also a step forward to fix file id stability ? (at least when copying from local to local, not ext storages)

No, the cache operations are uneffected

@icewind1991
Copy link
Contributor Author

Added more unit tests

/**
* @var \OCP\Files\Storage\ICrossCopyStorage | \OCP\Files\Storage $storage2
*/
if ($storage2->instanceOfStorage('\OCP\Files\Storage\ICrossCopyStorage') and
Copy link
Contributor

Choose a reason for hiding this comment

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

Another idea is to have "Common" always implement "moveFromStorage" and "copyFromStorage" as a simple download + copy (streamcopy). Then have specializations like Local add an additional check and do the rename() instead.

This way the new interface + check might not even be needed ?

function testMoveBetweenStorageCrossNonLocal() {
$storage1 = $this->getTestStorage(true, '\Test\Files\TemporaryNoLocal');
$storage2 = $this->getTestStorage(true, '\Test\Files\TemporaryNoLocal');
$this->moveBetweenStorages($storage1, $storage2);
Copy link
Contributor

Choose a reason for hiding this comment

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

Add a test when moving from a "Local + Cross" storage to a "non Local non Cross" storage ?
And also the reverse way.

@PVince81
Copy link
Contributor

The reason I'd like to have the cross copy logic in "Common" is to have a fallback in any case.
Currently we're expecting the caller of "crossMove()" to know in what situation it is ok to call this method. From an API consumer point of view I should not have to care. I just need a method "moveFromStorage($storage1, $storage2, ...)" and that method takes care of either optimizing, if possible, or falling back to the default stream copy logic when not.

@icewind1991
Copy link
Contributor Author

@PVince81 done, this also cleans up View::copy and View::rename a bit 😄

}
}
} else {
$source = $sourceStorage->fopen($sourceInternalPath, 'r');
Copy link
Contributor

Choose a reason for hiding this comment

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

Question: will this go through the storage wrappers or bypass them ?

When we had this on $view level the fopen() was done on the view.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It will use the storage wrappers

@PVince81
Copy link
Contributor

This is already a great improvement! Thanks for the changes 😄

Can you add a unit test for the cases where moving from a cross to non-cross, etc ?

* @var \OC\Files\Storage\Local $sourceStorage
*/
$rootStorage = new Local(['datadir' => '/']);
return $rootStorage->rename($sourceStorage->getSourcePath($sourceInternalPath), $this->getSourcePath($targetInternalPath));
Copy link
Contributor

Choose a reason for hiding this comment

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

Hmmm... what happens if $sourceStorage is a "local external storage mount" ?
I guess this should also work because it will rely on PHP's system rename with the absolute paths, then ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes

@PVince81
Copy link
Contributor

@DeepDiver1975 are we sure to want this in 8.0 ?

If we only merge this PR, I have the feeling that there isn't much benefit apart from situations where people use the "Local" external storage. The benefit will only start to show itself as soon as the SharedStorage part (the next step) is implemented. (please correct me if wrong @icewind1991)

So unless both are planned for 8.0, we should probably set this PR here to 8.1.

What do you think ?

$storage1->unlink($internalPath1);
}
}
return $storage2->moveFromStorage($storage1, $internalPath1, $internalPath2);
Copy link
Contributor

Choose a reason for hiding this comment

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

Are you sure we should return here directly ?
This would prevent proxy/hooks to be triggered in the lines below.

@PVince81 PVince81 mentioned this pull request Jan 16, 2015
3 tasks
@icewind1991
Copy link
Contributor Author

Note that this will be easy to implement for the refactored shared storage by implementing it for the jail wrapper

@ghost
Copy link

ghost commented Apr 13, 2015

Refer to this link for build results (access rights to CI server needed):
https://ci.owncloud.org//job/pull-request-analyser-ng-simple/11464/
🚀 Test PASSed.🚀
chuck

@PVince81
Copy link
Contributor

Will this clash / is this compatible with #15360 ?

@PVince81
Copy link
Contributor

Note: this also needs to be tested with encryption (once #15578 is fixed) because it might be affected.
I guess we could still first merge this and test afterwards.

Going to test this

@PVince81
Copy link
Contributor

from/to local shared mounted (e.g. SMB) shared mounted
local
shared
mounted (e.g. SMB)
shared mounted

Note: I also tested moving from share to share as recipient when the owner is the same, and also when the owner is different. (because the same owner would be the same local storage)

For "shared mounted" to "shared mounted", I tried with two different target storages and also the same (two different folders shared from the same user's personal ext storage)

All looks fine 👍

@PVince81
Copy link
Contributor

I noticed that if I move a big file from "a" to "b" where both are on the same SFTP storage, but shared separately with me, it still takes a long time. I guess this PR doesn't cover such cases ? (because the underlying storage is the same, so moving the file from one place to the other should be faster)

@PVince81
Copy link
Contributor

Ok, this PR is only for underlying local storages. A later step would be to do this for any type of storage.

@icewind1991
Copy link
Contributor Author

Yes, this PR doesn't optimize all cases with shared storages yet

@icewind1991
Copy link
Contributor Author

@DeepDiver1975 @LukasReschke @MorrisJobke please review

@scrutinizer-notifier
Copy link

A new inspection was created.

@ghost
Copy link

ghost commented Apr 14, 2015

Refer to this link for build results (access rights to CI server needed):
https://ci.owncloud.org//job/pull-request-analyser-ng-simple/11489/
🚀 Test PASSed.🚀
chuck

@MorrisJobke
Copy link
Contributor

I tested this with some of the above test cases and it works (and there are no errors in the log) 👍

MorrisJobke added a commit that referenced this pull request Apr 14, 2015
Proper copy/move between multiple local storages
@MorrisJobke MorrisJobke merged commit 82cab25 into master Apr 14, 2015
@MorrisJobke MorrisJobke deleted the cross-storage-move branch April 14, 2015 12:35
@PVince81
Copy link
Contributor

🍻

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.

10 participants