]> source.dussan.org Git - nextcloud-server.git/commitdiff
preserve cache data when doing a cross storage move
authorRobin Appelman <icewind@owncloud.com>
Wed, 1 Apr 2015 13:12:59 +0000 (15:12 +0200)
committerRobin Appelman <icewind@owncloud.com>
Mon, 13 Apr 2015 15:10:01 +0000 (17:10 +0200)
lib/private/files/cache/cache.php
lib/private/files/cache/updater.php
tests/lib/files/cache/updater.php

index c5e118946e5d6b37a81bdf424cbd3813cea75c66..fd4c5715a67a3258f5afd8a2f7c50a08edb5edef 100644 (file)
@@ -463,6 +463,43 @@ class Cache {
                \OC_DB::executeAudited($sql, array($target, md5($target), basename($target), $newParentId, $sourceId));
        }
 
+       /**
+        * Move a file or folder in the cache
+        *
+        * @param \OC\Files\Cache\Cache $sourceCache
+        * @param string $sourcePath
+        * @param string $targetPath
+        * @throws \OC\DatabaseException
+        */
+       public function moveFromCache(Cache $sourceCache, $sourcePath, $targetPath) {
+               // normalize source and target
+               $sourcePath = $this->normalize($sourcePath);
+               $targetPath = $this->normalize($targetPath);
+
+               $sourceData = $sourceCache->get($sourcePath);
+               $sourceId = $sourceData['fileid'];
+               $newParentId = $this->getParentId($targetPath);
+
+               if ($sourceData['mimetype'] === 'httpd/unix-directory') {
+                       //find all child entries
+                       $sql = 'SELECT `path`, `fileid` FROM `*PREFIX*filecache` WHERE `storage` = ? AND `path` LIKE ?';
+                       $result = \OC_DB::executeAudited($sql, [$sourceCache->getNumericStorageId(), $sourcePath . '/%']);
+                       $childEntries = $result->fetchAll();
+                       $sourceLength = strlen($sourcePath);
+                       \OC_DB::beginTransaction();
+                       $query = \OC_DB::prepare('UPDATE `*PREFIX*filecache` SET `storage` = ?, `path` = ?, `path_hash` = ? WHERE `fileid` = ?');
+
+                       foreach ($childEntries as $child) {
+                               $newTargetPath = $targetPath . substr($child['path'], $sourceLength);
+                               \OC_DB::executeAudited($query, [$this->getNumericStorageId(), $newTargetPath, md5($newTargetPath), $child['fileid']]);
+                       }
+                       \OC_DB::commit();
+               }
+
+               $sql = 'UPDATE `*PREFIX*filecache` SET `storage` =  ?, `path` = ?, `path_hash` = ?, `name` = ?, `parent` =? WHERE `fileid` = ?';
+               \OC_DB::executeAudited($sql, [$this->getNumericStorageId(), $targetPath, md5($targetPath), basename($targetPath), $newParentId, $sourceId]);
+       }
+
        /**
         * remove all entries for files that are stored on the storage from the cache
         */
index 5d2ac608cfd8704a864b91217c69af55272b7ca1..14aecf01220ac8690799fc41f4c78b373eadb72e 100644 (file)
@@ -144,30 +144,29 @@ class Updater {
                list($targetStorage, $targetInternalPath) = $this->view->resolvePath($target);
 
                if ($sourceStorage && $targetStorage) {
+                       $targetCache = $targetStorage->getCache($sourceInternalPath);
+                       if ($targetCache->inCache($targetInternalPath)) {
+                               $targetCache->remove($targetInternalPath);
+                       }
                        if ($sourceStorage === $targetStorage) {
-                               $cache = $sourceStorage->getCache($sourceInternalPath);
-                               if ($cache->inCache($targetInternalPath)) {
-                                       $cache->remove($targetInternalPath);
-                               }
-                               $cache->move($sourceInternalPath, $targetInternalPath);
-
-                               if (pathinfo($sourceInternalPath, PATHINFO_EXTENSION) !== pathinfo($targetInternalPath, PATHINFO_EXTENSION)) {
-                                       // handle mime type change
-                                       $mimeType = $sourceStorage->getMimeType($targetInternalPath);
-                                       $fileId = $cache->getId($targetInternalPath);
-                                       $cache->update($fileId, array('mimetype' => $mimeType));
-                               }
-
-                               $cache->correctFolderSize($sourceInternalPath);
-                               $cache->correctFolderSize($targetInternalPath);
-                               $this->correctParentStorageMtime($sourceStorage, $sourceInternalPath);
-                               $this->correctParentStorageMtime($targetStorage, $targetInternalPath);
-                               $this->propagator->addChange($source);
-                               $this->propagator->addChange($target);
+                               $targetCache->move($sourceInternalPath, $targetInternalPath);
                        } else {
-                               $this->remove($source);
-                               $this->update($target);
+                               $targetCache->moveFromCache($sourceStorage->getCache(), $sourceInternalPath, $targetInternalPath);
+                       }
+
+                       if (pathinfo($sourceInternalPath, PATHINFO_EXTENSION) !== pathinfo($targetInternalPath, PATHINFO_EXTENSION)) {
+                               // handle mime type change
+                               $mimeType = $sourceStorage->getMimeType($targetInternalPath);
+                               $fileId = $targetCache->getId($targetInternalPath);
+                               $targetCache->update($fileId, array('mimetype' => $mimeType));
                        }
+
+                       $targetCache->correctFolderSize($sourceInternalPath);
+                       $targetCache->correctFolderSize($targetInternalPath);
+                       $this->correctParentStorageMtime($sourceStorage, $sourceInternalPath);
+                       $this->correctParentStorageMtime($targetStorage, $targetInternalPath);
+                       $this->propagator->addChange($source);
+                       $this->propagator->addChange($target);
                        $this->propagator->propagateChanges();
                }
        }
index 7c3ebd5a6f9d340ca43b9df8e9eb5f4ccf046ea9..726ee3604790945f55c0899a22d6d8ea4eed4d9c 100644 (file)
@@ -172,4 +172,78 @@ class Updater extends \Test\TestCase {
                $this->assertTrue($this->cache->inCache('foo.txt'));
                $this->assertFalse($this->cache->inCache('bar.txt'));
        }
+
+       public function testMoveCrossStorage() {
+               $storage2 = new Temporary(array());
+               $cache2 = $storage2->getCache();
+               Filesystem::mount($storage2, array(), '/bar');
+               $this->storage->file_put_contents('foo.txt', 'qwerty');
+
+               $this->updater->update('foo.txt');
+
+               $this->assertTrue($this->cache->inCache('foo.txt'));
+               $this->assertFalse($cache2->inCache('bar.txt'));
+               $cached = $this->cache->get('foo.txt');
+
+               // "rename"
+               $storage2->file_put_contents('bar.txt', 'qwerty');
+               $this->storage->unlink('foo.txt');
+
+               $this->assertTrue($this->cache->inCache('foo.txt'));
+               $this->assertFalse($cache2->inCache('bar.txt'));
+
+               $this->updater->rename('foo.txt', 'bar/bar.txt');
+
+               $this->assertFalse($this->cache->inCache('foo.txt'));
+               $this->assertTrue($cache2->inCache('bar.txt'));
+
+               $cachedTarget = $cache2->get('bar.txt');
+               $this->assertEquals($cached['mtime'], $cachedTarget['mtime']);
+               $this->assertEquals($cached['size'], $cachedTarget['size']);
+               $this->assertEquals($cached['etag'], $cachedTarget['etag']);
+               $this->assertEquals($cached['fileid'], $cachedTarget['fileid']);
+       }
+
+       public function testMoveFolderCrossStorage() {
+               $storage2 = new Temporary(array());
+               $cache2 = $storage2->getCache();
+               Filesystem::mount($storage2, array(), '/bar');
+               $this->storage->mkdir('foo');
+               $this->storage->mkdir('foo/bar');
+               $this->storage->file_put_contents('foo/foo.txt', 'qwerty');
+               $this->storage->file_put_contents('foo/bar.txt', 'foo');
+               $this->storage->file_put_contents('foo/bar/bar.txt', 'qwertyuiop');
+
+               $this->storage->getScanner()->scan('');
+
+               $this->assertTrue($this->cache->inCache('foo/foo.txt'));
+               $this->assertTrue($this->cache->inCache('foo/bar.txt'));
+               $this->assertTrue($this->cache->inCache('foo/bar/bar.txt'));
+               $cached = [];
+               $cached[] = $this->cache->get('foo/foo.txt');
+               $cached[] = $this->cache->get('foo/bar.txt');
+               $cached[] = $this->cache->get('foo/bar/bar.txt');
+
+               $this->view->rename('/foo', '/bar/foo');
+
+               $this->assertFalse($this->cache->inCache('foo/foo.txt'));
+               $this->assertFalse($this->cache->inCache('foo/bar.txt'));
+               $this->assertFalse($this->cache->inCache('foo/bar/bar.txt'));
+               $this->assertTrue($cache2->inCache('foo/foo.txt'));
+               $this->assertTrue($cache2->inCache('foo/bar.txt'));
+               $this->assertTrue($cache2->inCache('foo/bar/bar.txt'));
+
+               $cachedTarget = [];
+               $cachedTarget[] = $cache2->get('foo/foo.txt');
+               $cachedTarget[] = $cache2->get('foo/bar.txt');
+               $cachedTarget[] = $cache2->get('foo/bar/bar.txt');
+
+               foreach ($cached as $i => $old) {
+                       $new = $cachedTarget[$i];
+                       $this->assertEquals($old['mtime'], $new['mtime']);
+                       $this->assertEquals($old['size'], $new['size']);
+                       $this->assertEquals($old['etag'], $new['etag']);
+                       $this->assertEquals($old['fileid'], $new['fileid']);
+               }
+       }
 }