Merge pull request #15129 from owncloud/version-command-bus

expire versions in a background command
This commit is contained in:
Lukas Reschke 2015-03-26 19:55:13 +01:00
commit c8c722bc6d
7 changed files with 132 additions and 10 deletions

View File

@ -0,0 +1,58 @@
<?php
/**
* Copyright (c) 2015 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 OCA\Files_Versions\Command;
use OC\Command\FileAccess;
use OCA\Files_Versions\Storage;
use OCP\Command\ICommand;
use OCP\IUser;
class Expire implements ICommand {
use FileAccess;
/**
* @var string
*/
private $fileName;
/**
* @var int|null
*/
private $versionsSize;
/**
* @var int
*/
private $neededSpace = 0;
/**
* @var string
*/
private $user;
/**
* @param string $user
* @param string $fileName
* @param int|null $versionsSize
* @param int $neededSpace
*/
function __construct($user, $fileName, $versionsSize = null, $neededSpace = 0) {
$this->user = $user;
$this->fileName = $fileName;
$this->versionsSize = $versionsSize;
$this->neededSpace = $neededSpace;
}
public function handle() {
\OC_Util::setupFS($this->user);
Storage::expire($this->fileName, $this->versionsSize, $this->neededSpace);
\OC_Util::tearDownFS();
}
}

View File

@ -39,6 +39,8 @@
namespace OCA\Files_Versions;
use OCA\Files_Versions\Command\Expire;
class Storage {
const DEFAULTENABLED=true;
@ -156,7 +158,7 @@ class Storage {
// 1.5 times as large as the current version -> 2.5
$neededSpace = $files_view->filesize($filename) * 2.5;
self::expire($filename, $versionsSize, $neededSpace);
self::scheduleExpire($filename, $versionsSize, $neededSpace);
// disable proxy to prevent multiple fopen calls
$proxyStatus = \OC_FileProxy::$enabled;
@ -261,7 +263,7 @@ class Storage {
}
if (!$files_view->is_dir($newpath)) {
self::expire($newpath);
self::scheduleExpire($newpath);
}
}
@ -296,7 +298,7 @@ class Storage {
// rollback
if( @$users_view->rename('files_versions'.$filename.'.v'.$revision, 'files'.$filename) ) {
$files_view->touch($file, $revision);
Storage::expire($file);
Storage::scheduleExpire($file);
return true;
}else if ( $versionCreated ) {
@ -500,9 +502,24 @@ class Storage {
}
/**
* Erase a file's versions which exceed the set quota
* @param string $fileName
* @param int|null $versionsSize
* @param int $neededSpace
*/
private static function expire($filename, $versionsSize = null, $offset = 0) {
private static function scheduleExpire($fileName, $versionsSize = null, $neededSpace = 0) {
$command = new Expire(\OC::$server->getUserSession()->getUser()->getUID(), $fileName, $versionsSize, $neededSpace);
\OC::$server->getCommandBus()->push($command);
}
/**
* Expire versions which exceed the quota
*
* @param $filename
* @param int|null $versionsSize
* @param int $offset
* @return bool|int|null
*/
public static function expire($filename, $versionsSize = null, $offset = 0) {
$config = \OC::$server->getConfig();
if($config->getSystemValue('files_versions', Storage::DEFAULTENABLED)=='true') {
list($uid, $filename) = self::getUidAndFilename($filename);

View File

@ -246,6 +246,8 @@ class Test_Files_Versioning extends \Test\TestCase {
// execute rename hook of versions app
\OC\Files\Filesystem::rename("test.txt", "test2.txt");
$this->runCommands();
$this->assertFalse($this->rootView->file_exists($v1));
$this->assertFalse($this->rootView->file_exists($v2));
@ -288,8 +290,11 @@ class Test_Files_Versioning extends \Test\TestCase {
// execute rename hook of versions app
\OC\Files\Filesystem::rename('/folder1/test.txt', '/folder1/folder2/test.txt');
self::loginHelper(self::TEST_VERSIONS_USER2);
$this->runCommands();
$this->assertFalse($this->rootView->file_exists($v1));
$this->assertFalse($this->rootView->file_exists($v2));
@ -333,6 +338,8 @@ class Test_Files_Versioning extends \Test\TestCase {
self::loginHelper(self::TEST_VERSIONS_USER);
$this->runCommands();
$this->assertTrue($this->rootView->file_exists($v1));
$this->assertTrue($this->rootView->file_exists($v2));
@ -364,6 +371,8 @@ class Test_Files_Versioning extends \Test\TestCase {
// execute copy hook of versions app
\OC\Files\Filesystem::copy("test.txt", "test2.txt");
$this->runCommands();
$this->assertTrue($this->rootView->file_exists($v1));
$this->assertTrue($this->rootView->file_exists($v2));
@ -417,7 +426,9 @@ class Test_Files_Versioning extends \Test\TestCase {
public static function loginHelper($user, $create = false) {
if ($create) {
\OC_User::createUser($user, $user);
$backend = new \OC_User_Dummy();
$backend->createUser($user, $user);
\OC::$server->getUserManager()->registerBackend($backend);
}
\OC_Util::tearDownFS();

View File

@ -24,8 +24,12 @@ namespace OC\Command;
use OCP\IUser;
trait FileAccess {
protected function getUserFolder(IUser $user) {
protected function setupFS(IUser $user){
\OC_Util::setupFS($user->getUID());
}
protected function getUserFolder(IUser $user) {
$this->setupFS($user);
return \OC::$server->getUserFolder($user->getUID());
}
}

View File

@ -28,7 +28,7 @@ class QueueBus implements IBus {
/**
* @var (ICommand|callable)[]
*/
private $queue;
private $queue = [];
/**
* Schedule a command to be fired
@ -52,7 +52,13 @@ class QueueBus implements IBus {
*/
private function runCommand($command) {
if ($command instanceof ICommand) {
$command->handle();
// ensure the command can be serialized
$serialized = serialize($command);
if(strlen($serialized) > 4000) {
throw new \InvalidArgumentException('Trying to push a command which serialized form can not be stored in the database (>4000 character)');
}
$unserialized = unserialize($serialized);
$unserialized->handle();
} else {
$command();
}

View File

@ -26,6 +26,8 @@
*
*/
class OC_Hook{
public static $thrownExceptions = [];
static private $registered = array();
/**
@ -98,6 +100,7 @@ class OC_Hook{
try {
call_user_func( array( $i["class"], $i["name"] ), $params );
} catch (Exception $e){
self::$thrownExceptions[] = $e;
OC_Log::write('hook',
'error while running hook (' . $i["class"] . '::' . $i["name"] . '): '.$e->getMessage(),
OC_Log::ERROR);

View File

@ -23,6 +23,7 @@
namespace Test;
use OC\Command\QueueBus;
use OC\Files\Filesystem;
use OCP\Security\ISecureRandom;
abstract class TestCase extends \PHPUnit_Framework_TestCase {
@ -34,11 +35,19 @@ abstract class TestCase extends \PHPUnit_Framework_TestCase {
protected function setUp() {
// overwrite the command bus with one we can run ourselves
$this->commandBus = new QueueBus();
\OC::$server->registerService('AsyncCommandBus', function(){
\OC::$server->registerService('AsyncCommandBus', function () {
return $this->commandBus;
});
}
protected function tearDown() {
$hookExceptions = \OC_Hook::$thrownExceptions;
\OC_Hook::$thrownExceptions = [];
if(!empty($hookExceptions)) {
throw $hookExceptions[0];
}
}
/**
* Returns a unique identifier as uniqid() is not reliable sometimes
*
@ -190,6 +199,20 @@ abstract class TestCase extends \PHPUnit_Framework_TestCase {
* Run all commands pushed to the bus
*/
protected function runCommands() {
// get the user for which the fs is setup
$view = Filesystem::getView();
if ($view) {
list(, $user) = explode('/', $view->getRoot());
} else {
$user = null;
}
\OC_Util::tearDownFS(); // command cant reply on the fs being setup
$this->commandBus->run();
\OC_Util::tearDownFS();
if ($user) {
\OC_Util::setupFS($user);
}
}
}