remove old propagation logic
This commit is contained in:
parent
74e8c25a5b
commit
62cc316c6a
|
@ -60,8 +60,5 @@ if (OCP\Config::getAppValue('files_external', 'allow_user_mounting', 'yes') == '
|
|||
"name" => $l->t('External storage')
|
||||
]);
|
||||
|
||||
// connecting hooks
|
||||
OCP\Util::connectHook('OC_Filesystem', 'post_initMountPoints', '\OC_Mount_Config', 'initMountPointsHook');
|
||||
|
||||
$mountProvider = $appContainer->query('OCA\Files_External\Config\ConfigAdapter');
|
||||
\OC::$server->getMountProviderCollection()->registerProvider($mountProvider);
|
||||
|
|
|
@ -74,36 +74,6 @@ class OC_Mount_Config {
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook that mounts the given user's visible mount points
|
||||
*
|
||||
* @param array $data
|
||||
*/
|
||||
public static function initMountPointsHook($data) {
|
||||
if ($data['user']) {
|
||||
$user = \OC::$server->getUserManager()->get($data['user']);
|
||||
if (!$user) {
|
||||
\OC::$server->getLogger()->warning(
|
||||
'Cannot init external mount points for non-existant user "' . $data['user'] . '".',
|
||||
['app' => 'files_external']
|
||||
);
|
||||
return;
|
||||
}
|
||||
$userView = new \OC\Files\View('/' . $user->getUID() . '/files');
|
||||
$changePropagator = new \OC\Files\Cache\ChangePropagator($userView);
|
||||
$etagPropagator = new \OCA\Files_External\EtagPropagator($user, $changePropagator, \OC::$server->getConfig());
|
||||
$etagPropagator->propagateDirtyMountPoints();
|
||||
\OCP\Util::connectHook(
|
||||
\OC\Files\Filesystem::CLASSNAME,
|
||||
\OC\Files\Filesystem::signal_create_mount,
|
||||
$etagPropagator, 'updateHook');
|
||||
\OCP\Util::connectHook(
|
||||
\OC\Files\Filesystem::CLASSNAME,
|
||||
\OC\Files\Filesystem::signal_delete_mount,
|
||||
$etagPropagator, 'updateHook');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the mount points for the given user.
|
||||
* The mount point is relative to the data directory.
|
||||
|
|
|
@ -1,141 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* @author Morris Jobke <hey@morrisjobke.de>
|
||||
* @author Robin Appelman <icewind@owncloud.com>
|
||||
* @author Vincent Petry <pvince81@owncloud.com>
|
||||
*
|
||||
* @copyright Copyright (c) 2015, ownCloud, Inc.
|
||||
* @license AGPL-3.0
|
||||
*
|
||||
* This code is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License, version 3,
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
*/
|
||||
|
||||
namespace OCA\Files_External;
|
||||
|
||||
use OC\Files\Filesystem;
|
||||
|
||||
/**
|
||||
* Updates the etag of parent folders whenever a new external storage mount
|
||||
* point has been created or deleted. Updates need to be triggered using
|
||||
* the updateHook() method.
|
||||
*
|
||||
* There are two modes of operation:
|
||||
* - for personal mount points, the etag is propagated directly
|
||||
* - for system mount points, a dirty flag is saved in the configuration and
|
||||
* the etag will be updated the next time propagateDirtyMountPoints() is called
|
||||
*/
|
||||
class EtagPropagator {
|
||||
/**
|
||||
* @var \OCP\IUser
|
||||
*/
|
||||
protected $user;
|
||||
|
||||
/**
|
||||
* @var \OC\Files\Cache\ChangePropagator
|
||||
*/
|
||||
protected $changePropagator;
|
||||
|
||||
/**
|
||||
* @var \OCP\IConfig
|
||||
*/
|
||||
protected $config;
|
||||
|
||||
/**
|
||||
* @param \OCP\IUser $user current user, must match the propagator's
|
||||
* user
|
||||
* @param \OC\Files\Cache\ChangePropagator $changePropagator change propagator
|
||||
* initialized with a view for $user
|
||||
* @param \OCP\IConfig $config
|
||||
*/
|
||||
public function __construct($user, $changePropagator, $config) {
|
||||
$this->user = $user;
|
||||
$this->changePropagator = $changePropagator;
|
||||
$this->config = $config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Propagate the etag changes for all mountpoints marked as dirty and mark the mountpoints as clean
|
||||
*
|
||||
* @param int $time
|
||||
*/
|
||||
public function propagateDirtyMountPoints($time = null) {
|
||||
if ($time === null) {
|
||||
$time = time();
|
||||
}
|
||||
$mountPoints = $this->getDirtyMountPoints();
|
||||
foreach ($mountPoints as $mountPoint) {
|
||||
$this->changePropagator->addChange($mountPoint);
|
||||
$this->config->setUserValue($this->user->getUID(), 'files_external', $mountPoint, $time);
|
||||
}
|
||||
if (count($mountPoints)) {
|
||||
$this->changePropagator->propagateChanges($time);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all mountpoints we need to update the etag for
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
protected function getDirtyMountPoints() {
|
||||
$dirty = array();
|
||||
$mountPoints = $this->config->getAppKeys('files_external');
|
||||
foreach ($mountPoints as $mountPoint) {
|
||||
if (substr($mountPoint, 0, 1) === '/') {
|
||||
$updateTime = $this->config->getAppValue('files_external', $mountPoint);
|
||||
$userTime = $this->config->getUserValue($this->user->getUID(), 'files_external', $mountPoint);
|
||||
if ($updateTime > $userTime) {
|
||||
$dirty[] = $mountPoint;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $dirty;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $mountPoint
|
||||
* @param int $time
|
||||
*/
|
||||
protected function markDirty($mountPoint, $time = null) {
|
||||
if ($time === null) {
|
||||
$time = time();
|
||||
}
|
||||
$this->config->setAppValue('files_external', $mountPoint, $time);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update etags for mount points for known user
|
||||
* For global or group mount points, updating the etag for every user is not feasible
|
||||
* instead we mark the mount point as dirty and update the etag when the filesystem is loaded for the user
|
||||
* For personal mount points, the change is propagated directly
|
||||
*
|
||||
* @param array $params hook parameters
|
||||
* @param int $time update time to use when marking a mount point as dirty
|
||||
*/
|
||||
public function updateHook($params, $time = null) {
|
||||
if ($time === null) {
|
||||
$time = time();
|
||||
}
|
||||
$users = $params[Filesystem::signal_param_users];
|
||||
$type = $params[Filesystem::signal_param_mount_type];
|
||||
$mountPoint = $params[Filesystem::signal_param_path];
|
||||
$mountPoint = Filesystem::normalizePath($mountPoint);
|
||||
if ($type === \OC_Mount_Config::MOUNT_TYPE_GROUP or $users === 'all') {
|
||||
$this->markDirty($mountPoint, $time);
|
||||
} else {
|
||||
$this->changePropagator->addChange($mountPoint);
|
||||
$this->changePropagator->propagateChanges($time);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,350 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* @author Joas Schilling <nickvergessen@owncloud.com>
|
||||
* @author Morris Jobke <hey@morrisjobke.de>
|
||||
* @author Robin Appelman <icewind@owncloud.com>
|
||||
*
|
||||
* @copyright Copyright (c) 2015, ownCloud, Inc.
|
||||
* @license AGPL-3.0
|
||||
*
|
||||
* This code is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License, version 3,
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
*/
|
||||
|
||||
namespace Tests\Files_External;
|
||||
|
||||
use OC\Files\Filesystem;
|
||||
use OC\User\User;
|
||||
|
||||
/**
|
||||
* Class EtagPropagator
|
||||
*
|
||||
* @group DB
|
||||
*
|
||||
* @package Tests\Files_External
|
||||
*/
|
||||
class EtagPropagator extends \Test\TestCase {
|
||||
protected function getUser() {
|
||||
return new User($this->getUniqueID(), null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \PHPUnit_Framework_MockObject_MockObject | \OC\Files\Cache\ChangePropagator
|
||||
*/
|
||||
protected function getChangePropagator() {
|
||||
return $this->getMockBuilder('\OC\Files\Cache\ChangePropagator')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \PHPUnit_Framework_MockObject_MockObject | \OCP\IConfig
|
||||
*/
|
||||
protected function getConfig() {
|
||||
$appConfig = array();
|
||||
$userConfig = array();
|
||||
$mock = $this->getMockBuilder('\OCP\IConfig')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$mock->expects($this->any())
|
||||
->method('getAppValue')
|
||||
->will($this->returnCallback(function ($appId, $key, $default = null) use (&$appConfig) {
|
||||
if (isset($appConfig[$appId]) and isset($appConfig[$appId][$key])) {
|
||||
return $appConfig[$appId][$key];
|
||||
} else {
|
||||
return $default;
|
||||
}
|
||||
}));
|
||||
$mock->expects($this->any())
|
||||
->method('setAppValue')
|
||||
->will($this->returnCallback(function ($appId, $key, $value) use (&$appConfig) {
|
||||
if (!isset($appConfig[$appId])) {
|
||||
$appConfig[$appId] = array();
|
||||
}
|
||||
$appConfig[$appId][$key] = $value;
|
||||
}));
|
||||
$mock->expects($this->any())
|
||||
->method('getAppKeys')
|
||||
->will($this->returnCallback(function ($appId) use (&$appConfig) {
|
||||
if (!isset($appConfig[$appId])) {
|
||||
$appConfig[$appId] = array();
|
||||
}
|
||||
return array_keys($appConfig[$appId]);
|
||||
}));
|
||||
|
||||
$mock->expects($this->any())
|
||||
->method('getUserValue')
|
||||
->will($this->returnCallback(function ($userId, $appId, $key, $default = null) use (&$userConfig) {
|
||||
if (isset($userConfig[$userId]) and isset($userConfig[$userId][$appId]) and isset($userConfig[$userId][$appId][$key])) {
|
||||
return $userConfig[$userId][$appId][$key];
|
||||
} else {
|
||||
return $default;
|
||||
}
|
||||
}));
|
||||
$mock->expects($this->any())
|
||||
->method('setUserValue')
|
||||
->will($this->returnCallback(function ($userId, $appId, $key, $value) use (&$userConfig) {
|
||||
if (!isset($userConfig[$userId])) {
|
||||
$userConfig[$userId] = array();
|
||||
}
|
||||
if (!isset($userConfig[$userId][$appId])) {
|
||||
$userConfig[$userId][$appId] = array();
|
||||
}
|
||||
$userConfig[$userId][$appId][$key] = $value;
|
||||
}));
|
||||
|
||||
return $mock;
|
||||
}
|
||||
|
||||
public function testSingleUserMount() {
|
||||
$time = time();
|
||||
$user = $this->getUser();
|
||||
$config = $this->getConfig();
|
||||
$changePropagator = $this->getChangePropagator();
|
||||
$propagator = new \OCA\Files_External\EtagPropagator($user, $changePropagator, $config);
|
||||
|
||||
$changePropagator->expects($this->once())
|
||||
->method('addChange')
|
||||
->with('/test');
|
||||
$changePropagator->expects($this->once())
|
||||
->method('propagateChanges')
|
||||
->with($time);
|
||||
|
||||
$propagator->updateHook(array(
|
||||
Filesystem::signal_param_path => '/test',
|
||||
Filesystem::signal_param_mount_type => \OC_Mount_Config::MOUNT_TYPE_USER,
|
||||
Filesystem::signal_param_users => $user->getUID(),
|
||||
), $time);
|
||||
}
|
||||
|
||||
public function testGlobalMountNoDirectUpdate() {
|
||||
$time = time();
|
||||
$user = $this->getUser();
|
||||
$config = $this->getConfig();
|
||||
$changePropagator = $this->getChangePropagator();
|
||||
$propagator = new \OCA\Files_External\EtagPropagator($user, $changePropagator, $config);
|
||||
|
||||
// not updated directly
|
||||
$changePropagator->expects($this->never())
|
||||
->method('addChange');
|
||||
$changePropagator->expects($this->never())
|
||||
->method('propagateChanges');
|
||||
|
||||
$propagator->updateHook(array(
|
||||
Filesystem::signal_param_path => '/test',
|
||||
Filesystem::signal_param_mount_type => \OC_Mount_Config::MOUNT_TYPE_USER,
|
||||
Filesystem::signal_param_users => 'all',
|
||||
), $time);
|
||||
|
||||
// mount point marked as dirty
|
||||
$this->assertEquals(array('/test'), $config->getAppKeys('files_external'));
|
||||
$this->assertEquals($time, $config->getAppValue('files_external', '/test'));
|
||||
}
|
||||
|
||||
public function testGroupMountNoDirectUpdate() {
|
||||
$time = time();
|
||||
$user = $this->getUser();
|
||||
$config = $this->getConfig();
|
||||
$changePropagator = $this->getChangePropagator();
|
||||
$propagator = new \OCA\Files_External\EtagPropagator($user, $changePropagator, $config);
|
||||
|
||||
// not updated directly
|
||||
$changePropagator->expects($this->never())
|
||||
->method('addChange');
|
||||
$changePropagator->expects($this->never())
|
||||
->method('propagateChanges');
|
||||
|
||||
$propagator->updateHook(array(
|
||||
Filesystem::signal_param_path => '/test',
|
||||
Filesystem::signal_param_mount_type => \OC_Mount_Config::MOUNT_TYPE_GROUP,
|
||||
Filesystem::signal_param_users => 'test',
|
||||
), $time);
|
||||
|
||||
// mount point marked as dirty
|
||||
$this->assertEquals(array('/test'), $config->getAppKeys('files_external'));
|
||||
$this->assertEquals($time, $config->getAppValue('files_external', '/test'));
|
||||
}
|
||||
|
||||
public function testGlobalMountNoDirtyMountPoint() {
|
||||
$time = time();
|
||||
$user = $this->getUser();
|
||||
$config = $this->getConfig();
|
||||
$changePropagator = $this->getChangePropagator();
|
||||
$propagator = new \OCA\Files_External\EtagPropagator($user, $changePropagator, $config);
|
||||
|
||||
$changePropagator->expects($this->never())
|
||||
->method('addChange');
|
||||
$changePropagator->expects($this->never())
|
||||
->method('propagateChanges');
|
||||
|
||||
$propagator->propagateDirtyMountPoints($time);
|
||||
|
||||
$this->assertEquals(0, $config->getUserValue($user->getUID(), 'files_external', '/test', 0));
|
||||
}
|
||||
|
||||
public function testGlobalMountDirtyMountPointFirstTime() {
|
||||
$time = time();
|
||||
$user = $this->getUser();
|
||||
$config = $this->getConfig();
|
||||
$changePropagator = $this->getChangePropagator();
|
||||
$propagator = new \OCA\Files_External\EtagPropagator($user, $changePropagator, $config);
|
||||
|
||||
$config->setAppValue('files_external', '/test', $time - 10);
|
||||
|
||||
$changePropagator->expects($this->once())
|
||||
->method('addChange')
|
||||
->with('/test');
|
||||
$changePropagator->expects($this->once())
|
||||
->method('propagateChanges')
|
||||
->with($time);
|
||||
|
||||
$propagator->propagateDirtyMountPoints($time);
|
||||
|
||||
$this->assertEquals($time, $config->getUserValue($user->getUID(), 'files_external', '/test'));
|
||||
}
|
||||
|
||||
public function testGlobalMountNonDirtyMountPoint() {
|
||||
$time = time();
|
||||
$user = $this->getUser();
|
||||
$config = $this->getConfig();
|
||||
$changePropagator = $this->getChangePropagator();
|
||||
$propagator = new \OCA\Files_External\EtagPropagator($user, $changePropagator, $config);
|
||||
|
||||
$config->setAppValue('files_external', '/test', $time - 10);
|
||||
$config->setUserValue($user->getUID(), 'files_external', '/test', $time - 10);
|
||||
|
||||
$changePropagator->expects($this->never())
|
||||
->method('addChange');
|
||||
$changePropagator->expects($this->never())
|
||||
->method('propagateChanges');
|
||||
|
||||
$propagator->propagateDirtyMountPoints($time);
|
||||
|
||||
$this->assertEquals($time - 10, $config->getUserValue($user->getUID(), 'files_external', '/test'));
|
||||
}
|
||||
|
||||
public function testGlobalMountNonDirtyMountPointOtherUser() {
|
||||
$time = time();
|
||||
$user = $this->getUser();
|
||||
$user2 = $this->getUser();
|
||||
$config = $this->getConfig();
|
||||
$changePropagator = $this->getChangePropagator();
|
||||
$propagator = new \OCA\Files_External\EtagPropagator($user, $changePropagator, $config);
|
||||
|
||||
$config->setAppValue('files_external', '/test', $time - 10);
|
||||
$config->setUserValue($user2->getUID(), 'files_external', '/test', $time - 10);
|
||||
|
||||
$changePropagator->expects($this->once())
|
||||
->method('addChange')
|
||||
->with('/test');
|
||||
$changePropagator->expects($this->once())
|
||||
->method('propagateChanges')
|
||||
->with($time);
|
||||
|
||||
$propagator->propagateDirtyMountPoints($time);
|
||||
|
||||
$this->assertEquals($time, $config->getUserValue($user->getUID(), 'files_external', '/test'));
|
||||
}
|
||||
|
||||
public function testGlobalMountDirtyMountPointSecondTime() {
|
||||
$time = time();
|
||||
$user = $this->getUser();
|
||||
$config = $this->getConfig();
|
||||
$changePropagator = $this->getChangePropagator();
|
||||
$propagator = new \OCA\Files_External\EtagPropagator($user, $changePropagator, $config);
|
||||
|
||||
$config->setAppValue('files_external', '/test', $time - 10);
|
||||
$config->setUserValue($user->getUID(), 'files_external', '/test', $time - 20);
|
||||
|
||||
$changePropagator->expects($this->once())
|
||||
->method('addChange')
|
||||
->with('/test');
|
||||
$changePropagator->expects($this->once())
|
||||
->method('propagateChanges')
|
||||
->with($time);
|
||||
|
||||
$propagator->propagateDirtyMountPoints($time);
|
||||
|
||||
$this->assertEquals($time, $config->getUserValue($user->getUID(), 'files_external', '/test'));
|
||||
}
|
||||
|
||||
public function testGlobalMountMultipleUsers() {
|
||||
$time = time();
|
||||
$config = $this->getConfig();
|
||||
$user1 = $this->getUser();
|
||||
$user2 = $this->getUser();
|
||||
$user3 = $this->getUser();
|
||||
$changePropagator1 = $this->getChangePropagator();
|
||||
$changePropagator2 = $this->getChangePropagator();
|
||||
$changePropagator3 = $this->getChangePropagator();
|
||||
$propagator1 = new \OCA\Files_External\EtagPropagator($user1, $changePropagator1, $config);
|
||||
$propagator2 = new \OCA\Files_External\EtagPropagator($user2, $changePropagator2, $config);
|
||||
$propagator3 = new \OCA\Files_External\EtagPropagator($user3, $changePropagator3, $config);
|
||||
|
||||
$config->setAppValue('files_external', '/test', $time - 10);
|
||||
|
||||
$changePropagator1->expects($this->once())
|
||||
->method('addChange')
|
||||
->with('/test');
|
||||
$changePropagator1->expects($this->once())
|
||||
->method('propagateChanges')
|
||||
->with($time);
|
||||
|
||||
$propagator1->propagateDirtyMountPoints($time);
|
||||
|
||||
$this->assertEquals($time, $config->getUserValue($user1->getUID(), 'files_external', '/test'));
|
||||
$this->assertEquals(0, $config->getUserValue($user2->getUID(), 'files_external', '/test', 0));
|
||||
$this->assertEquals(0, $config->getUserValue($user3->getUID(), 'files_external', '/test', 0));
|
||||
|
||||
$changePropagator2->expects($this->once())
|
||||
->method('addChange')
|
||||
->with('/test');
|
||||
$changePropagator2->expects($this->once())
|
||||
->method('propagateChanges')
|
||||
->with($time);
|
||||
|
||||
$propagator2->propagateDirtyMountPoints($time);
|
||||
|
||||
$this->assertEquals($time, $config->getUserValue($user1->getUID(), 'files_external', '/test'));
|
||||
$this->assertEquals($time, $config->getUserValue($user2->getUID(), 'files_external', '/test', 0));
|
||||
$this->assertEquals(0, $config->getUserValue($user3->getUID(), 'files_external', '/test', 0));
|
||||
}
|
||||
|
||||
public function testGlobalMountMultipleDirtyMountPoints() {
|
||||
$time = time();
|
||||
$user = $this->getUser();
|
||||
$config = $this->getConfig();
|
||||
$changePropagator = $this->getChangePropagator();
|
||||
$propagator = new \OCA\Files_External\EtagPropagator($user, $changePropagator, $config);
|
||||
|
||||
$config->setAppValue('files_external', '/test', $time - 10);
|
||||
$config->setAppValue('files_external', '/foo', $time - 50);
|
||||
$config->setAppValue('files_external', '/bar', $time - 70);
|
||||
|
||||
$config->setUserValue($user->getUID(), 'files_external', '/foo', $time - 70);
|
||||
$config->setUserValue($user->getUID(), 'files_external', '/bar', $time - 70);
|
||||
|
||||
$changePropagator->expects($this->exactly(2))
|
||||
->method('addChange');
|
||||
$changePropagator->expects($this->once())
|
||||
->method('propagateChanges')
|
||||
->with($time);
|
||||
|
||||
$propagator->propagateDirtyMountPoints($time);
|
||||
|
||||
$this->assertEquals($time, $config->getUserValue($user->getUID(), 'files_external', '/test'));
|
||||
$this->assertEquals($time, $config->getUserValue($user->getUID(), 'files_external', '/foo'));
|
||||
$this->assertEquals($time - 70, $config->getUserValue($user->getUID(), 'files_external', '/bar'));
|
||||
}
|
||||
}
|
|
@ -1,125 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* @author Morris Jobke <hey@morrisjobke.de>
|
||||
* @author Robin Appelman <icewind@owncloud.com>
|
||||
*
|
||||
* @copyright Copyright (c) 2015, ownCloud, Inc.
|
||||
* @license AGPL-3.0
|
||||
*
|
||||
* This code is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License, version 3,
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
*/
|
||||
|
||||
namespace OC\Files\Cache;
|
||||
|
||||
use OC\Files\Filesystem;
|
||||
use OC\Hooks\BasicEmitter;
|
||||
|
||||
/**
|
||||
* Propagates changes in etag and mtime up the filesystem tree
|
||||
*
|
||||
* @package OC\Files\Cache
|
||||
*/
|
||||
class ChangePropagator extends BasicEmitter {
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
protected $changedFiles = array();
|
||||
|
||||
/**
|
||||
* @var \OC\Files\View
|
||||
*/
|
||||
protected $view;
|
||||
|
||||
/**
|
||||
* @param \OC\Files\View $view
|
||||
*/
|
||||
public function __construct(\OC\Files\View $view) {
|
||||
$this->view = $view;
|
||||
}
|
||||
|
||||
public function addChange($path) {
|
||||
$this->changedFiles[] = $path;
|
||||
}
|
||||
|
||||
public function getChanges() {
|
||||
return $this->changedFiles;
|
||||
}
|
||||
|
||||
/**
|
||||
* propagate the registered changes to their parent folders
|
||||
*
|
||||
* @param int $time (optional) the mtime to set for the folders, if not set the current time is used
|
||||
*/
|
||||
public function propagateChanges($time = null) {
|
||||
$changes = $this->getChanges();
|
||||
$this->changedFiles = [];
|
||||
if (!$time) {
|
||||
$time = time();
|
||||
}
|
||||
foreach ($changes as $change) {
|
||||
/**
|
||||
* @var \OC\Files\Storage\Storage $storage
|
||||
* @var string $internalPath
|
||||
*/
|
||||
|
||||
$absolutePath = $this->view->getAbsolutePath($change);
|
||||
$mount = $this->view->getMount($change);
|
||||
$storage = $mount->getStorage();
|
||||
$internalPath = $mount->getInternalPath($absolutePath);
|
||||
if ($storage) {
|
||||
$propagator = $storage->getPropagator();
|
||||
$propagatedEntries = $propagator->propagateChange($internalPath, $time);
|
||||
|
||||
foreach ($propagatedEntries as $entry) {
|
||||
$absolutePath = Filesystem::normalizePath($mount->getMountPoint() . '/' . $entry['path']);
|
||||
$relativePath = $this->view->getRelativePath($absolutePath);
|
||||
$this->emit('\OC\Files', 'propagate', [$relativePath, $entry]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getAllParents() {
|
||||
$parents = array();
|
||||
foreach ($this->getChanges() as $path) {
|
||||
$parents = array_values(array_unique(array_merge($parents, $this->getParents($path))));
|
||||
}
|
||||
return $parents;
|
||||
}
|
||||
|
||||
/**
|
||||
* get all parent folders of $path
|
||||
*
|
||||
* @param string $path
|
||||
* @return string[]
|
||||
*/
|
||||
protected function getParents($path) {
|
||||
$parts = explode('/', $path);
|
||||
|
||||
// remove the singe file
|
||||
array_pop($parts);
|
||||
$result = array('/');
|
||||
$resultPath = '';
|
||||
foreach ($parts as $part) {
|
||||
if ($part) {
|
||||
$resultPath .= '/' . $part;
|
||||
$result[] = $resultPath;
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
}
|
|
@ -26,8 +26,6 @@
|
|||
|
||||
namespace OC\Files\Utils;
|
||||
|
||||
use OC\Files\View;
|
||||
use OC\Files\Cache\ChangePropagator;
|
||||
use OC\Files\Filesystem;
|
||||
use OC\ForbiddenException;
|
||||
use OC\Hooks\PublicEmitter;
|
||||
|
@ -50,11 +48,6 @@ class Scanner extends PublicEmitter {
|
|||
*/
|
||||
private $user;
|
||||
|
||||
/**
|
||||
* @var \OC\Files\Cache\ChangePropagator
|
||||
*/
|
||||
protected $propagator;
|
||||
|
||||
/**
|
||||
* @var \OCP\IDBConnection
|
||||
*/
|
||||
|
@ -73,7 +66,6 @@ class Scanner extends PublicEmitter {
|
|||
public function __construct($user, $db, ILogger $logger) {
|
||||
$this->logger = $logger;
|
||||
$this->user = $user;
|
||||
$this->propagator = new ChangePropagator(new View(''));
|
||||
$this->db = $db;
|
||||
}
|
||||
|
||||
|
@ -116,14 +108,6 @@ class Scanner extends PublicEmitter {
|
|||
$scanner->listen('\OC\Files\Cache\Scanner', 'postScanFolder', function ($path) use ($mount, $emitter) {
|
||||
$emitter->emit('\OC\Files\Utils\Scanner', 'postScanFolder', array($mount->getMountPoint() . $path));
|
||||
});
|
||||
// propagate etag and mtimes when files are changed or removed
|
||||
$propagator = $this->propagator;
|
||||
$propagatorListener = function ($path) use ($mount, $propagator) {
|
||||
$fullPath = Filesystem::normalizePath($mount->getMountPoint() . $path);
|
||||
$propagator->addChange($fullPath);
|
||||
};
|
||||
$scanner->listen('\OC\Files\Cache\Scanner', 'addToCache', $propagatorListener);
|
||||
$scanner->listen('\OC\Files\Cache\Scanner', 'removeFromCache', $propagatorListener);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -139,7 +123,6 @@ class Scanner extends PublicEmitter {
|
|||
$this->attachListener($mount);
|
||||
$scanner->backgroundScan();
|
||||
}
|
||||
$this->propagator->propagateChanges(time());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -181,7 +164,6 @@ class Scanner extends PublicEmitter {
|
|||
$this->db->commit();
|
||||
}
|
||||
}
|
||||
$this->propagator->propagateChanges(time());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,137 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* Copyright (c) 2014 Robin Appelman <icewind@owncloud.com>
|
||||
* This file is licensed under the Affero General Public License version 3 or
|
||||
* later.
|
||||
* See the COPYING-README file.
|
||||
*/
|
||||
|
||||
namespace Test\Files\Cache;
|
||||
|
||||
use OC\Files\Filesystem;
|
||||
use OC\Files\Storage\Temporary;
|
||||
use OC\Files\View;
|
||||
|
||||
/**
|
||||
* Class ChangePropagator
|
||||
*
|
||||
* @group DB
|
||||
*
|
||||
* @package Test\Files\Cache
|
||||
*/
|
||||
class ChangePropagator extends \Test\TestCase {
|
||||
/**
|
||||
* @var \OC\Files\Cache\ChangePropagator
|
||||
*/
|
||||
private $propagator;
|
||||
|
||||
/**
|
||||
* @var \OC\Files\View
|
||||
*/
|
||||
private $view;
|
||||
|
||||
/**
|
||||
* @var \OC\Files\Storage\Storage
|
||||
*/
|
||||
private $storage;
|
||||
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->storage = new Temporary(array());
|
||||
$root = $this->getUniqueID('/');
|
||||
Filesystem::mount($this->storage, array(), $root);
|
||||
$this->view = new View($root);
|
||||
$this->propagator = new \OC\Files\Cache\ChangePropagator($this->view);
|
||||
}
|
||||
|
||||
public function testGetParentsSingle() {
|
||||
$this->propagator->addChange('/foo/bar/asd');
|
||||
$this->assertEquals(array('/', '/foo', '/foo/bar'), $this->propagator->getAllParents());
|
||||
}
|
||||
|
||||
public function testGetParentsMultiple() {
|
||||
$this->propagator->addChange('/foo/bar/asd');
|
||||
$this->propagator->addChange('/foo/qwerty');
|
||||
$this->propagator->addChange('/foo/asd/bar');
|
||||
$this->assertEquals(array('/', '/foo', '/foo/bar', '/foo/asd'), $this->propagator->getAllParents());
|
||||
}
|
||||
|
||||
public function testSinglePropagate() {
|
||||
$this->view->mkdir('/foo');
|
||||
$this->view->mkdir('/foo/bar');
|
||||
$this->view->file_put_contents('/foo/bar/sad.txt', 'qwerty');
|
||||
|
||||
$oldInfo1 = $this->view->getFileInfo('/');
|
||||
$oldInfo2 = $this->view->getFileInfo('/foo');
|
||||
$oldInfo3 = $this->view->getFileInfo('/foo/bar');
|
||||
|
||||
$time = time() + 50;
|
||||
|
||||
$this->propagator->addChange('/foo/bar/sad.txt');
|
||||
$this->propagator->propagateChanges($time);
|
||||
|
||||
$newInfo1 = $this->view->getFileInfo('/');
|
||||
$newInfo2 = $this->view->getFileInfo('/foo');
|
||||
$newInfo3 = $this->view->getFileInfo('/foo/bar');
|
||||
|
||||
$this->assertEquals($newInfo1->getMTime(), $time);
|
||||
$this->assertEquals($newInfo2->getMTime(), $time);
|
||||
$this->assertEquals($newInfo3->getMTime(), $time);
|
||||
|
||||
$this->assertNotSame($oldInfo1->getEtag(), $newInfo1->getEtag());
|
||||
$this->assertNotSame($oldInfo2->getEtag(), $newInfo2->getEtag());
|
||||
$this->assertNotSame($oldInfo3->getEtag(), $newInfo3->getEtag());
|
||||
}
|
||||
|
||||
public function testDontLowerMtime() {
|
||||
$time = time();
|
||||
$this->view->mkdir('/foo');
|
||||
$this->view->mkdir('/foo/bar');
|
||||
|
||||
$cache = $this->storage->getCache();
|
||||
$cache->put('', ['mtime' => $time - 50]);
|
||||
$cache->put('foo', ['mtime' => $time - 150]);
|
||||
$cache->put('foo/bar', ['mtime' => $time - 250]);
|
||||
|
||||
$this->propagator->addChange('/foo/bar/foo');
|
||||
$this->propagator->propagateChanges($time - 100);
|
||||
|
||||
$this->assertEquals(50, $time - $cache->get('')['mtime']);
|
||||
$this->assertEquals(100, $time - $cache->get('foo')['mtime']);
|
||||
$this->assertEquals(100, $time - $cache->get('foo/bar')['mtime']);
|
||||
}
|
||||
|
||||
public function testPropagateCrossStorage() {
|
||||
$storage = new Temporary();
|
||||
$this->view->mkdir('/foo');
|
||||
Filesystem::mount($storage, [], $this->view->getAbsolutePath('/foo/submount'));
|
||||
$this->view->mkdir('/foo/submount/bar');
|
||||
$this->view->file_put_contents('/foo/submount/bar/sad.txt', 'qwerty');
|
||||
|
||||
$oldInfo1 = $this->view->getFileInfo('/');
|
||||
$oldInfo2 = $this->view->getFileInfo('/foo');
|
||||
$oldInfo3 = $this->view->getFileInfo('/foo/submount');
|
||||
$oldInfo4 = $this->view->getFileInfo('/foo/submount/bar');
|
||||
|
||||
$time = time() + 50;
|
||||
|
||||
$this->propagator->addChange('/foo/submount/bar/sad.txt');
|
||||
$this->propagator->propagateChanges($time);
|
||||
|
||||
$newInfo1 = $this->view->getFileInfo('/');
|
||||
$newInfo2 = $this->view->getFileInfo('/foo');
|
||||
$newInfo3 = $this->view->getFileInfo('/foo/submount');
|
||||
$newInfo4 = $this->view->getFileInfo('/foo/submount/bar');
|
||||
|
||||
$this->assertEquals($newInfo1->getMTime(), $time);
|
||||
$this->assertEquals($newInfo2->getMTime(), $time);
|
||||
$this->assertEquals($newInfo3->getMTime(), $time);
|
||||
$this->assertEquals($newInfo4->getMTime(), $time);
|
||||
|
||||
$this->assertNotSame($oldInfo1->getEtag(), $newInfo1->getEtag());
|
||||
$this->assertNotSame($oldInfo2->getEtag(), $newInfo2->getEtag());
|
||||
$this->assertNotSame($oldInfo3->getEtag(), $newInfo3->getEtag());
|
||||
$this->assertNotSame($oldInfo4->getEtag(), $newInfo3->getEtag());
|
||||
}
|
||||
}
|
|
@ -30,14 +30,6 @@ class TestScanner extends \OC\Files\Utils\Scanner {
|
|||
protected function getMounts($dir) {
|
||||
return $this->mounts;
|
||||
}
|
||||
|
||||
public function getPropagator() {
|
||||
return $this->propagator;
|
||||
}
|
||||
|
||||
public function setPropagator($propagator) {
|
||||
$this->propagator = $propagator;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -144,59 +136,6 @@ class Scanner extends \Test\TestCase {
|
|||
$this->assertTrue($cache->inCache('folder/bar.txt'));
|
||||
}
|
||||
|
||||
public function testChangePropagator() {
|
||||
/**
|
||||
* @var \OC\Files\Cache\ChangePropagator $propagator
|
||||
*/
|
||||
$propagator = $this->getMock('\OC\Files\Cache\ChangePropagator', array('propagateChanges'), array(), '', false);
|
||||
|
||||
$storage = new Temporary(array());
|
||||
$mount = new MountPoint($storage, '/foo');
|
||||
Filesystem::getMountManager()->addMount($mount);
|
||||
$cache = $storage->getCache();
|
||||
|
||||
$storage->mkdir('folder');
|
||||
$storage->file_put_contents('foo.txt', 'qwerty');
|
||||
$storage->file_put_contents('folder/bar.txt', 'qwerty');
|
||||
|
||||
$scanner = new TestScanner('', \OC::$server->getDatabaseConnection(), \OC::$server->getLogger());
|
||||
$originalPropagator = $scanner->getPropagator();
|
||||
$scanner->setPropagator($propagator);
|
||||
$scanner->addMount($mount);
|
||||
|
||||
$scanner->scan('');
|
||||
|
||||
$changes = $propagator->getChanges();
|
||||
$parents = $propagator->getAllParents();
|
||||
sort($changes);
|
||||
sort($parents);
|
||||
$this->assertEquals(array('/foo', '/foo/folder', '/foo/folder/bar.txt', '/foo/foo.txt'), $changes);
|
||||
$this->assertEquals(array('/', '/foo', '/foo/folder'), $parents);
|
||||
|
||||
$cache->put('foo.txt', array('storage_mtime' => time() - 50));
|
||||
|
||||
$propagator = $this->getMock('\OC\Files\Cache\ChangePropagator', array('propagateChanges'), array(), '', false);
|
||||
$scanner->setPropagator($propagator);
|
||||
$storage->file_put_contents('foo.txt', 'asdasd');
|
||||
|
||||
$scanner->scan('');
|
||||
|
||||
$changes = $propagator->getChanges();
|
||||
$parents = $propagator->getAllParents();
|
||||
$this->assertEquals(array('/foo/foo.txt'), $changes);
|
||||
$this->assertEquals(array('/', '/foo'), $parents);
|
||||
|
||||
$scanner->setPropagator($originalPropagator);
|
||||
|
||||
$oldInfo = $cache->get('');
|
||||
$cache->put('foo.txt', array('storage_mtime' => time() - 70));
|
||||
$storage->file_put_contents('foo.txt', 'asdasd');
|
||||
|
||||
$scanner->scan('');
|
||||
$newInfo = $cache->get('');
|
||||
$this->assertNotEquals($oldInfo['etag'], $newInfo['etag']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
|
|
Loading…
Reference in New Issue