-
Notifications
You must be signed in to change notification settings - Fork 2.1k
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
Conversation
@IljaN @tomneedham @DeepDiver1975 Thoughts? |
lib/private/Files/Storage/Common.php
Outdated
@@ -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; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why static?
There was a problem hiding this comment.
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']); |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
$val -> $value
@DeepDiver1975 I will try also to reuse it for checksums, to avoid more queries -> https://github.com/owncloud/core/pull/28003/files#diff-be504dc886734275f06114e4306fa215L231 |
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'])) { |
There was a problem hiding this comment.
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 ->
core/lib/private/Files/Node/HookConnector.php
Line 110 in f10d105
$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.
There was a problem hiding this comment.
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"
There was a problem hiding this comment.
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 :>
There was a problem hiding this comment.
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 ?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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 ?
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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).
There was a problem hiding this comment.
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? :>
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 ? |
preTouch hook 🔫 ? @DeepDiver1975 @PVince81 @tomneedham |
Any update on pretouch ? |
We can't kill it without notifying the community. @DeepDiver1975 thoughts ? |
moving to "planned", blocked by the decision of deprecating/removing pre/post touch hooks |
can we have this PR without killing the touch event ? |
lib/private/Files/View.php
Outdated
@@ -313,6 +313,10 @@ protected function removeMount($mount, $path) { | |||
} | |||
} | |||
|
|||
public function isCacheUpdateEnabled() { |
There was a problem hiding this comment.
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) { |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
@ownclouders rebase |
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 |
looks like rebasing with gitmate does not work anymore ... |
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); |
There was a problem hiding this comment.
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)
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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"
d2fa99f
to
5e797f4
Compare
use target storage update instead
@DeepDiver1975 @PVince81 ok, I think finally this is ready :> |
$mtime = $this->sanitizeMtime( | ||
$this->request->server ['HTTP_X_OC_MTIME'] | ||
); | ||
if ($targetStorage->touch($targetInternalPath, $mtime)) { |
There was a problem hiding this comment.
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
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. |
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
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}}