Merge pull request #14644 from owncloud/trash-expire-command

Expire files from the trash in the background
remotes/origin/etag-endpoint
Thomas Müller 10 years ago
commit bbaf97ca43
  1. 56
      apps/files_trashbin/command/expire.php
  2. 51
      apps/files_trashbin/lib/trashbin.php
  3. 2
      apps/files_trashbin/tests/trashbin.php
  4. 53
      lib/private/command/queuebus.php
  5. 37
      tests/lib/testcase.php

@ -0,0 +1,56 @@
<?php
/**
* ownCloud - trash bin
*
* @author Robin Appelman
* @copyright 2015 Robin Appelman icewind@owncloud.com
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
* License as published by the Free Software Foundation; either
* version 3 of the License, or any later version.
*
* This library 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 along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\Files_Trashbin\Command;
use OC\Command\FileAccess;
use OCA\Files_Trashbin\Trashbin;
use OCP\Command\ICommand;
class Expire implements ICommand {
use FileAccess;
/**
* @var string
*/
private $user;
/**
* @var int
*/
private $trashBinSize;
/**
* @param string $user
* @param int $trashBinSize
*/
function __construct($user, $trashBinSize) {
$this->user = $user;
$this->trashBinSize = $trashBinSize;
}
public function handle() {
\OC_Util::tearDownFS();
\OC_Util::setupFS($this->user);
Trashbin::expire($this->trashBinSize, $this->user);
}
}

@ -23,6 +23,7 @@
namespace OCA\Files_Trashbin;
use OC\Files\Filesystem;
use OCA\Files_Trashbin\Command\Expire;
class Trashbin {
// how long do we keep files in the trash bin if no other value is defined in the config file (unit: days)
@ -211,13 +212,13 @@ class Trashbin {
}
$userTrashSize += $size;
$userTrashSize -= self::expire($userTrashSize, $user);
self::scheduleExpire($userTrashSize, $user);
// if owner !== user we also need to update the owners trash size
if ($owner !== $user) {
$ownerTrashSize = self::getTrashbinSize($owner);
$ownerTrashSize += $size;
$ownerTrashSize -= self::expire($ownerTrashSize, $owner);
self::scheduleExpire($ownerTrashSize, $owner);
}
return ($sizeOfAddedFiles === false) ? false : true;
@ -429,7 +430,7 @@ class Trashbin {
if ($view->is_dir('/files_trashbin/versions/' . $file)) {
$rootView->rename(\OC\Files\Filesystem::normalizePath($user . '/files_trashbin/versions/' . $file), \OC\Files\Filesystem::normalizePath($owner . '/files_versions/' . $ownerPath));
} else if ($versions = self::getVersionsFromTrash($versionedFile, $timestamp)) {
} else if ($versions = self::getVersionsFromTrash($versionedFile, $timestamp, $user)) {
foreach ($versions as $v) {
if ($timestamp) {
$rootView->rename($user . '/files_trashbin/versions/' . $versionedFile . '.v' . $v . '.d' . $timestamp, $owner . '/files_versions/' . $ownerPath . '.v' . $v);
@ -533,8 +534,8 @@ class Trashbin {
$file = $filename;
}
$size += self::deleteVersions($view, $file, $filename, $timestamp);
$size += self::deleteEncryptionKeys($view, $file, $filename, $timestamp);
$size += self::deleteVersions($view, $file, $filename, $timestamp, $user);
$size += self::deleteEncryptionKeys($view, $file, $filename, $timestamp, $user);
if ($view->is_dir('/files_trashbin/files/' . $file)) {
$size += self::calculateSize(new \OC\Files\View('/' . $user . '/files_trashbin/files/' . $file));
@ -555,14 +556,13 @@ class Trashbin {
* @param $timestamp
* @return int
*/
private static function deleteVersions(\OC\Files\View $view, $file, $filename, $timestamp) {
private static function deleteVersions(\OC\Files\View $view, $file, $filename, $timestamp, $user) {
$size = 0;
if (\OCP\App::isEnabled('files_versions')) {
$user = \OCP\User::getUser();
if ($view->is_dir('files_trashbin/versions/' . $file)) {
$size += self::calculateSize(new \OC\Files\view('/' . $user . '/files_trashbin/versions/' . $file));
$view->unlink('files_trashbin/versions/' . $file);
} else if ($versions = self::getVersionsFromTrash($filename, $timestamp)) {
} else if ($versions = self::getVersionsFromTrash($filename, $timestamp, $user)) {
foreach ($versions as $v) {
if ($timestamp) {
$size += $view->filesize('/files_trashbin/versions/' . $filename . '.v' . $v . '.d' . $timestamp);
@ -584,10 +584,9 @@ class Trashbin {
* @param $timestamp
* @return int
*/
private static function deleteEncryptionKeys(\OC\Files\View $view, $file, $filename, $timestamp) {
private static function deleteEncryptionKeys(\OC\Files\View $view, $file, $filename, $timestamp, $user) {
$size = 0;
if (\OCP\App::isEnabled('files_encryption')) {
$user = \OCP\User::getUser();
$keyfiles = \OC\Files\Filesystem::normalizePath('files_trashbin/keys/' . $filename);
@ -689,26 +688,18 @@ class Trashbin {
$freeSpace = self::calculateFreeSpace($size, $user);
if ($freeSpace < 0) {
self::expire($size, $user);
self::scheduleExpire($size, $user);
}
}
/**
* clean up the trash bin
*
* @param int $trashbinSize current size of the trash bin
* @param int $trashBinSize current size of the trash bin
* @param string $user
* @return int size of expired files
*/
private static function expire($trashbinSize, $user) {
// let the admin disable auto expire
$autoExpire = \OC_Config::getValue('trashbin_auto_expire', true);
if ($autoExpire === false) {
return 0;
}
$availableSpace = self::calculateFreeSpace($trashbinSize, $user);
public static function expire($trashBinSize, $user) {
$availableSpace = self::calculateFreeSpace($trashBinSize, $user);
$size = 0;
$retention_obligation = \OC_Config::getValue('trashbin_retention_obligation', self::DEFAULT_RETENTION_OBLIGATION);
@ -725,8 +716,18 @@ class Trashbin {
// delete files from trash until we meet the trash bin size limit again
$size += self::deleteFiles(array_slice($dirContent, $count), $user, $availableSpace);
}
return $size;
/**@param int $trashBinSize current size of the trash bin
* @param string $user
*/
private static function scheduleExpire($trashBinSize, $user) {
// let the admin disable auto expire
$autoExpire = \OC_Config::getValue('trashbin_auto_expire', true);
if ($autoExpire === false) {
return;
}
\OC::$server->getCommandBus()->push(new Expire($user, $trashBinSize));
}
/**
@ -827,8 +828,8 @@ class Trashbin {
* @param int $timestamp timestamp when the file was deleted
* @return array
*/
private static function getVersionsFromTrash($filename, $timestamp) {
$view = new \OC\Files\View('/' . \OCP\User::getUser() . '/files_trashbin/versions');
private static function getVersionsFromTrash($filename, $timestamp, $user) {
$view = new \OC\Files\View('/' . $user . '/files_trashbin/versions');
$versions = array();
//force rescan of versions, local storage may not have updated the cache

@ -210,6 +210,8 @@ class Test_Trashbin extends \Test\TestCase {
\OC\Files\Filesystem::unlink($folder . 'user1-4.txt');
$this->runCommands();
$filesInTrashUser2AfterDelete = OCA\Files_Trashbin\Helper::getTrashFiles('/', self::TEST_TRASHBIN_USER2);
// user2-1.txt should have been expired

@ -0,0 +1,53 @@
<?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 OC\Command;
use OCP\Command\IBus;
use OCP\Command\ICommand;
class QueueBus implements IBus {
/**
* @var (ICommand|callable)[]
*/
private $queue;
/**
* Schedule a command to be fired
*
* @param \OCP\Command\ICommand | callable $command
*/
public function push($command) {
$this->queue[] = $command;
}
/**
* Require all commands using a trait to be run synchronous
*
* @param string $trait
*/
public function requireSync($trait) {
}
/**
* @param \OCP\Command\ICommand | callable $command
*/
private function runCommand($command) {
if ($command instanceof ICommand) {
$command->handle();
} else {
$command();
}
}
public function run() {
while ($command = array_shift($this->queue)) {
$this->runCommand($command);
}
}
}

@ -22,9 +22,23 @@
namespace Test;
use OC\Command\QueueBus;
use OCP\Security\ISecureRandom;
abstract class TestCase extends \PHPUnit_Framework_TestCase {
/**
* @var \OC\Command\QueueBus
*/
private $commandBus;
protected function setUp() {
// overwrite the command bus with one we can run ourselves
$this->commandBus = new QueueBus();
\OC::$server->registerService('AsyncCommandBus', function(){
return $this->commandBus;
});
}
/**
* Returns a unique identifier as uniqid() is not reliable sometimes
*
@ -55,6 +69,7 @@ abstract class TestCase extends \PHPUnit_Framework_TestCase {
/**
* Remove all entries from the files map table
*
* @param string $dataDir
*/
static protected function tearDownAfterClassCleanFileMapper($dataDir) {
@ -66,6 +81,7 @@ abstract class TestCase extends \PHPUnit_Framework_TestCase {
/**
* Remove all entries from the storages table
*
* @throws \OC\DatabaseException
*/
static protected function tearDownAfterClassCleanStorages() {
@ -76,6 +92,7 @@ abstract class TestCase extends \PHPUnit_Framework_TestCase {
/**
* Remove all entries from the filecache table
*
* @throws \OC\DatabaseException
*/
static protected function tearDownAfterClassCleanFileCache() {
@ -91,11 +108,11 @@ abstract class TestCase extends \PHPUnit_Framework_TestCase {
*/
static protected function tearDownAfterClassCleanStrayDataFiles($dataDir) {
$knownEntries = array(
'owncloud.log' => true,
'owncloud.db' => true,
'.ocdata' => true,
'..' => true,
'.' => true,
'owncloud.log' => true,
'owncloud.db' => true,
'.ocdata' => true,
'..' => true,
'.' => true,
);
if ($dh = opendir($dataDir)) {
@ -122,8 +139,7 @@ abstract class TestCase extends \PHPUnit_Framework_TestCase {
$path = $dir . '/' . $file;
if (is_dir($path)) {
self::tearDownAfterClassCleanStrayDataUnlinkDir($path);
}
else {
} else {
@unlink($path);
}
}
@ -169,4 +185,11 @@ abstract class TestCase extends \PHPUnit_Framework_TestCase {
\OC_Util::tearDownFS();
\OC_User::setUserId('');
}
/**
* Run all commands pushed to the bus
*/
protected function runCommands() {
$this->commandBus->run();
}
}

Loading…
Cancel
Save