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

Optimize PUT - with custom mtime, use storage instead of view #28003

Merged
merged 1 commit into from
Jun 25, 2018

Conversation

mrow4a
Copy link
Contributor

@mrow4a mrow4a commented May 24, 2017

Description

As in the title, I am trying to avoid unnecessarily queries delivering this information different way then just querying the database twice.

This PR saves few queries in the tested example, 4 READ and 4 WRITE (!), needs 2 aditional LOCK updates, so +2 WRITE.

PR reduces the number of queries from 92 to 82 for new, and from 111 to 101 for edited file (SELECTS and UPDATES)

How did I test

Smashbox basic test

docker run -e SMASHBOX_URL=172.42.16.124:80/octest -e SMASHBOX_USERNAME=admin -e SMASHBOX_ACCOUNT_PASSWORD=admin -e SMASHBOX_PASSWORD=admin owncloud/smashbox lib/test_basicSync.py

Using diagnostic, compared number of queries

Previous impl - single put new file

{"type":"SUMMARY","reqId":"0S1oOpIXAOJaU7i66fAL","time":"2018-05-16T15:19:45+00:00","remoteAddr":"::1","user":"admin","method":"PUT","url":"/octest/remote.php/dav/files/admin/testnew.txt","diagnostics":{"totalSQLQueries":92,"totalSQLDurationmsec":15.33818244934082,"totalSQLParams":205,"totalEvents":16,"totalEventsDurationmsec":44.87967491149902}}

Previous impl - single put edit file

{"type":"SUMMARY","reqId":"QxoT5rglLIWSHBJl3XRb","time":"2018-05-16T15:19:45+00:00","remoteAddr":"::1","user":"admin","method":"PUT","url":"/octest/remote.php/dav/files/admin/testnew.txt","diagnostics":{"totalSQLQueries":111,"totalSQLDurationmsec":17.354965209960938,"totalSQLParams":259,"totalEvents":16,"totalEventsDurationmsec":59.42058563232422}}

Current impl - single put new file

{"type":"SUMMARY","reqId":"5L9J79Am5wkkeqfKY7Wr","time":"2018-05-16T15:21:18+00:00","remoteAddr":"::1","user":"admin","method":"PUT","url":"/octest/remote.php/dav/files/admin/testnew.txt","diagnostics":{"totalSQLQueries":82,"totalSQLDurationmsec":13.219833374023438,"totalSQLParams":175,"totalEvents":16,"totalEventsDurationmsec":58.83908271789551}}

Current impl - single put edit file

{"type":"SUMMARY","reqId":"AWPSyMmw8aCWHDmHnKZ0","time":"2018-05-16T15:21:18+00:00","remoteAddr":"::1","user":"admin","method":"PUT","url":"/octest/remote.php/dav/files/admin/testnew.txt","diagnostics":{"totalSQLQueries":101,"totalSQLDurationmsec":15.613555908203125,"totalSQLParams":223,"totalEvents":16,"totalEventsDurationmsec":50.08506774902344}}

@mrow4a
Copy link
Contributor Author

mrow4a commented May 24, 2017

@IljaN @tomneedham @DeepDiver1975 Thoughts?

@mrow4a mrow4a changed the title Set mtime from MemoryCache instead of using touch() Optimize PUT - set mtime from cache instead of using touch() May 25, 2017
@@ -76,7 +77,13 @@
protected $mountOptions = [];
protected $owner = null;

/** @var CappedMemoryCache Key is path, value is array of metadata key-value pairs */
private static $metadata;
Copy link
Member

Choose a reason for hiding this comment

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

why static?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hmm, seems this wrapper wont need it static, seems you are right.

// allow sync clients to send the mtime along in a header
$request = \OC::$server->getRequest();
if (isset($request->server['HTTP_X_OC_MTIME'])) {
$storage->addMetaData($internalPath, 'mtime', $request->server['HTTP_X_OC_MTIME']);
Copy link
Member

Choose a reason for hiding this comment

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

where is the actual write operation of the meta data?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Will add description to that. It does not write any metadata hardly "to disk", any new call to getMetadata (e.g. in ->update) will have metadata overwritten with this.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Maybe I should call it cacheMetadata or sth?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Copy link
Member

Choose a reason for hiding this comment

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

but the touch operation you are replacing was storing the mtime in file cache - my question is where this storing of information is happening now

* @param string $key
* @param string $val
*/
public function addMetaData($path, $key, $val);
Copy link
Member

Choose a reason for hiding this comment

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

$val -> $value

@mrow4a
Copy link
Contributor Author

mrow4a commented May 26, 2017

@DeepDiver1975 I will try also to reuse it for checksums, to avoid more queries -> https://github.com/owncloud/core/pull/28003/files#diff-be504dc886734275f06114e4306fa215L231

@mrow4a
Copy link
Contributor Author

mrow4a commented May 26, 2017

Ok, I see this wont be that easy, since "touch" literally touches the file, and this needs to be done separately @DeepDiver1975 .. ehh. This not only affects database but mtime of existing file on disk.

// allow sync clients to send the mtime along in a header
$request = \OC::$server->getRequest();
if (isset($request->server['HTTP_X_OC_MTIME'])) {
// Touch will update mtime of file at storage, scan and emit the hooks
if ($this->fileView->touch($this->path, $request->server['HTTP_X_OC_MTIME'])) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

The only problem which I see here, that touch() without previous call to update() will pass to preTouch hook, NonExistingNode ->

$this->root->emit('\OC\Files', 'preTouch', [$node]);

Question is, what do we need it for and if it is ok to call touch() on non-existing yet node.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

In case of update, pretouch will receive "previous version"

Copy link
Contributor Author

@mrow4a mrow4a May 26, 2017

Choose a reason for hiding this comment

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

PostTouch is executed after the scan, and receives new, correct node :>

Copy link
Contributor Author

Choose a reason for hiding this comment

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

For now, I dont see anything using that https://github.com/search?q=org%3Aowncloud+preTouch&type=Code, delete this hook ? @DeepDiver1975 @PVince81 ?

Copy link
Contributor

Choose a reason for hiding this comment

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

These hooks could be used by third party apps so deleting would be API breakage.

Copy link
Contributor

Choose a reason for hiding this comment

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

why is this a problem ?

Copy link
Contributor Author

@mrow4a mrow4a May 30, 2017

Choose a reason for hiding this comment

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

This particular preTouch adds additional queries (WRITEs/READs/UPDATEs) to each PUT files, does not matter if that app is using your pre-touch or not.

When you apply the solution above, you get rid of some queries.. when you remove preTouch you get rid of additional queries needed for LOCK, since this preTouch does locking+filecache query.

Problem with solution above is that we pass different things to preTouch, not sure if the correct ones. Will be good to know what app using preTouch requires in the input @DeepDiver1975 @PVince81

Copy link
Contributor

Choose a reason for hiding this comment

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

If we delete pretouch, would there be an alternative hook for developers to listen to ? Is there another hook ?

Would require informing the developers mailing list and wait a bit for feedback.
If we remove it, it would be in 10.1 and not backportable (which is fine).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@PVince81 So, do we remove preTouch? :>

@mrow4a mrow4a changed the title Optimize PUT - set mtime from cache instead of using touch() Optimize PUT - with custom mtime, reuse touch() for runnig update() May 26, 2017
@PVince81
Copy link
Contributor

PVince81 commented Jul 4, 2017

I don't think we can remove the "touch" hook which might be used by third party app, that would be API breakage. So we might need to abandon this optimization.

@DeepDiver1975 agree ? or kill the hook ?

@mrow4a
Copy link
Contributor Author

mrow4a commented Jul 27, 2017

preTouch hook 🔫 ? @DeepDiver1975 @PVince81 @tomneedham

@mrow4a
Copy link
Contributor Author

mrow4a commented Aug 3, 2017

Any update on pretouch ?

@PVince81
Copy link
Contributor

PVince81 commented Aug 3, 2017

Any update on pretouch ?

We can't kill it without notifying the community.
Also I don't feel good about killing this in a minor release (10.0.3).

@DeepDiver1975 thoughts ?

@PVince81
Copy link
Contributor

moving to "planned", blocked by the decision of deprecating/removing pre/post touch hooks

@PVince81 PVince81 added this to the planned milestone Aug 10, 2017
@PVince81 PVince81 modified the milestones: development, planned Nov 2, 2017
@PVince81 PVince81 modified the milestones: planned, development Nov 22, 2017
@PVince81 PVince81 modified the milestones: development, planned Jan 12, 2018
@PVince81
Copy link
Contributor

can we have this PR without killing the touch event ?

@@ -313,6 +313,10 @@ protected function removeMount($mount, $path) {
}
}

public function isCacheUpdateEnabled() {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Will remove, it should be in previous commit.

* @param Storage $targetStorage
* @param $targetInternalPath
*/
private function handleMetadataUpdate(\OC\Files\Storage\Storage $targetStorage, $targetInternalPath) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

now we use the same function to commit mtime and propagate update - both in chunked and in single PUT

@mrow4a mrow4a changed the title Optimize PUT - with custom mtime, reuse touch() for running update() Optimize PUT - with custom mtime, use storage instead of view May 16, 2018
Copy link
Contributor

@PVince81 PVince81 left a comment

Choose a reason for hiding this comment

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

👍

@DeepDiver1975
Copy link
Member

@ownclouders rebase

@ownclouders
Copy link
Contributor

Hey! I'm GitMate.io! This pull request is being rebased automatically. Please DO NOT push while rebase is in progress or your changes would be lost permanently ⚠️

@DeepDiver1975
Copy link
Member

looks like rebasing with gitmate does not work anymore ...

@mrow4a
Copy link
Contributor Author

mrow4a commented May 19, 2018

It was with newest master when you rebased I think.

}

// since we skipped the view we need to scan and emit the hooks ourselves
$targetStorage->getUpdater()->update($targetInternalPath);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@PVince81 I am thinking, should we pass to update function mtime, or not? I cannot scratch my head over the case in which mtime wont be updated (updater should detect it I think)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Maybe for safety we should call updater with mtime in case HTTP_X_OC_MTIME is set, and without in case it is not, thoughts?

Copy link
Contributor

Choose a reason for hiding this comment

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

maybe pass it in explicitly so it involves less magic. magic being "remembering that the function is reading a global var / header"

@PVince81 PVince81 modified the milestones: triage, maybe some day May 22, 2018
@mrow4a mrow4a force-pushed the optimize_put_5 branch 4 times, most recently from d2fa99f to 5e797f4 Compare June 17, 2018 08:46
use target storage update instead
@mrow4a
Copy link
Contributor Author

mrow4a commented Jun 25, 2018

@DeepDiver1975 @PVince81 ok, I think finally this is ready :>

$mtime = $this->sanitizeMtime(
$this->request->server ['HTTP_X_OC_MTIME']
);
if ($targetStorage->touch($targetInternalPath, $mtime)) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

If someone wonders what essential changes, it is that we now use $targetStorage->touch & $targetStorage->getUpdater()->update($targetInternalPath, $mtime) instead of $this->fileView->touch (which calls updater update() internally) & $targetStorage->getUpdater()->update($targetInternalPath, $mtime).

Thus we call update 1x, instead 2x

@lock
Copy link

lock bot commented Jul 30, 2019

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

@lock lock bot locked as resolved and limited conversation to collaborators Jul 30, 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.

6 participants