summaryrefslogtreecommitdiffstats
path: root/apps
diff options
context:
space:
mode:
authorBjörn Schießle <schiessle@owncloud.com>2013-06-25 09:39:01 +0200
committerBjörn Schießle <schiessle@owncloud.com>2013-07-12 11:24:19 +0200
commite15914316521bb6d9d791926434c9c6ce5b0aa91 (patch)
tree97078f179a841bdd58cc9e8bcb7d8299190cb7ad /apps
parent3abe68176ff09ca579ff9e5f15872fb5cab8ff4d (diff)
downloadnextcloud-server-e15914316521bb6d9d791926434c9c6ce5b0aa91.tar.gz
nextcloud-server-e15914316521bb6d9d791926434c9c6ce5b0aa91.zip
call expire function before writing the new version to make sure to have enough free space
Diffstat (limited to 'apps')
-rw-r--r--apps/files_versions/lib/versions.php159
1 files changed, 96 insertions, 63 deletions
diff --git a/apps/files_versions/lib/versions.php b/apps/files_versions/lib/versions.php
index 2f8262475b4..6abf278ddab 100644
--- a/apps/files_versions/lib/versions.php
+++ b/apps/files_versions/lib/versions.php
@@ -113,6 +113,18 @@ class Storage {
mkdir($versionsFolderName.'/'.$info['dirname'], 0750, true);
}
+ $versionsSize = self::getVersionsSize($uid);
+ if ( $versionsSize === false || $versionsSize < 0 ) {
+ $versionsSize = self::calculateSize($uid);
+ }
+
+ // assumptgion: we need filesize($filename) for the new version +
+ // some more free space for the modified file which might be
+ // 1.5 times as large as the current version -> 2.5
+ $neededSpace = $files_view->filesize($filename) * 2.5;
+
+ $versionsSize = self::expire($filename, $versionsSize, $neededSpace);
+
// disable proxy to prevent multiple fopen calls
$proxyStatus = \OC_FileProxy::$enabled;
\OC_FileProxy::$enabled = false;
@@ -123,11 +135,6 @@ class Storage {
// reset proxy state
\OC_FileProxy::$enabled = $proxyStatus;
- $versionsSize = self::getVersionsSize($uid);
- if ( $versionsSize === false || $versionsSize < 0 ) {
- $versionsSize = self::calculateSize($uid);
- }
-
$versionsSize += $users_view->filesize('files'.$filename);
// expire old revisions if necessary
@@ -175,12 +182,12 @@ class Storage {
if ($files_view->file_exists($newpath)) {
return self::store($new_path);
}
-
+
$abs_newpath = $versions_view->getLocalFile($newpath);
if ( $files_view->is_dir($oldpath) && $versions_view->is_dir($oldpath) ) {
$versions_view->rename($oldpath, $newpath);
- } else if ( ($versions = Storage::getVersions($uid, $oldpath)) ) {
+ } else if ( ($versions = Storage::getVersions($uid, $oldpath)) ) {
$info=pathinfo($abs_newpath);
if(!file_exists($info['dirname'])) mkdir($info['dirname'], 0750, true);
foreach ($versions as $v) {
@@ -391,7 +398,7 @@ class Storage {
/**
* @brief Erase a file's versions which exceed the set quota
*/
- private static function expire($filename, $versionsSize = null) {
+ private static function expire($filename, $versionsSize = null, $offset = 0) {
if(\OCP\Config::getSystemValue('files_versions', Storage::DEFAULTENABLED)=='true') {
list($uid, $filename) = self::getUidAndFilename($filename);
$versions_fileview = new \OC\Files\View('/'.$uid.'/files_versions');
@@ -424,76 +431,39 @@ class Storage {
$rootInfo = $files_view->getFileInfo('/');
$free = $quota-$rootInfo['size']; // remaining free space for user
if ( $free > 0 ) {
- $availableSpace = ($free * self::DEFAULTMAXSIZE / 100) - $versionsSize; // how much space can be used for versions
+ $availableSpace = ($free * self::DEFAULTMAXSIZE / 100) - ($versionsSize + $offset); // how much space can be used for versions
} else {
- $availableSpace = $free-$versionsSize;
+ $availableSpace = $free - $versionsSize - $offset;
}
} else {
- $availableSpace = $quota;
+ $availableSpace = $quota - $offset;
}
// after every 1000s run reduce the number of all versions not only for the current file
$random = rand(0, 1000);
if ($random == 0) {
- $result = Storage::getAllVersions($uid);
- $versions_by_file = $result['by_file'];
- $all_versions = $result['all'];
+ $allFiles = true;
} else {
- $all_versions = Storage::getVersions($uid, $filename);
- $versions_by_file[$filename] = $all_versions;
+ $allFiles = false;
}
- $time = time();
+ $all_versions = Storage::getVersions($uid, $filename);
+ $versions_by_file[$filename] = $all_versions;
- // it is possible to expire versions from more than one file
- // iterate through all given files
- foreach ($versions_by_file as $filename => $versions) {
- $versions = array_reverse($versions); // newest version first
+ $sizeOfDeletedVersions = self::delOldVersions($versions_by_file, $all_versions, $versions_fileview);
+ $availableSpace = $availableSpace + $sizeOfDeletedVersions;
+ $versionsSize = $versionsSize - $sizeOfDeletedVersions;
- $interval = 1;
- $step = Storage::$max_versions_per_interval[$interval]['step'];
- if (Storage::$max_versions_per_interval[$interval]['intervalEndsAfter'] == -1) {
- $nextInterval = -1;
- } else {
- $nextInterval = $time - Storage::$max_versions_per_interval[$interval]['intervalEndsAfter'];
- }
+ // if still not enough free space we rearrange the versions from all files
+ if ($availableSpace < 0 || $allFiles) {
+ $result = Storage::getAllVersions($uid);
+ $versions_by_file = $result['by_file'];
+ $all_versions = $result['all'];
- $firstVersion = reset($versions);
- $firstKey = key($versions);
- $prevTimestamp = $firstVersion['version'];
- $nextVersion = $firstVersion['version'] - $step;
- $remaining_versions[$firstKey] = $firstVersion;
- unset($versions[$firstKey]);
-
- foreach ($versions as $key => $version) {
- $newInterval = true;
- while ( $newInterval ) {
- if ( $nextInterval == -1 || $version['version'] >= $nextInterval ) {
- if ( $version['version'] > $nextVersion ) {
- //distance between two version too small, delete version
- $versions_fileview->unlink($version['path'].'.v'.$version['version']);
- $availableSpace += $version['size'];
- $versionsSize -= $version['size'];
- unset($all_versions[$key]); // update array with all versions
- } else {
- $nextVersion = $version['version'] - $step;
- }
- $newInterval = false; // version checked so we can move to the next one
- } else { // time to move on to the next interval
- $interval++;
- $step = Storage::$max_versions_per_interval[$interval]['step'];
- $nextVersion = $prevTimestamp - $step;
- if ( Storage::$max_versions_per_interval[$interval]['intervalEndsAfter'] == -1 ) {
- $nextInterval = -1;
- } else {
- $nextInterval = $time - Storage::$max_versions_per_interval[$interval]['intervalEndsAfter'];
- }
- $newInterval = true; // we changed the interval -> check same version with new interval
- }
- }
- $prevTimestamp = $version['version'];
- }
+ $sizeOfDeletedVersions = self::delOldVersions($versions_by_file, $all_versions, $versions_fileview);
+ $availableSpace = $availableSpace + $sizeOfDeletedVersions;
+ $versionsSize = $versionsSize - $sizeOfDeletedVersions;
}
// Check if enough space is available after versions are rearranged.
@@ -513,4 +483,67 @@ class Storage {
return false;
}
+
+ /**
+ * @brief delete old version from a given list of versions
+ *
+ * @param array $versions_by_file list of versions ordered by files
+ * @param array $all_versions all versions accross multiple files
+ * @param $versions_fileview OC\Files\View on data/user/files_versions
+ * @return size of releted versions
+ */
+ private static function delOldVersions($versions_by_file, &$all_versions, $versions_fileview) {
+
+ $time = time();
+ $size = 0;
+
+ // delete old versions for every given file
+ foreach ($versions_by_file as $versions) {
+ $versions = array_reverse($versions); // newest version first
+
+ $interval = 1;
+ $step = Storage::$max_versions_per_interval[$interval]['step'];
+ if (Storage::$max_versions_per_interval[$interval]['intervalEndsAfter'] == -1) {
+ $nextInterval = -1;
+ } else {
+ $nextInterval = $time - Storage::$max_versions_per_interval[$interval]['intervalEndsAfter'];
+ }
+
+ $firstVersion = reset($versions);
+ $firstKey = key($versions);
+ $prevTimestamp = $firstVersion['version'];
+ $nextVersion = $firstVersion['version'] - $step;
+ unset($versions[$firstKey]);
+
+ foreach ($versions as $key => $version) {
+ $newInterval = true;
+ while ($newInterval) {
+ if ($nextInterval == -1 || $version['version'] >= $nextInterval) {
+ if ($version['version'] > $nextVersion) {
+ //distance between two version too small, delete version
+ $versions_fileview->unlink($version['path'] . '.v' . $version['version']);
+ $size += $version['size'];
+ unset($all_versions[$key]); // update array with all versions
+ } else {
+ $nextVersion = $version['version'] - $step;
+ }
+ $newInterval = false; // version checked so we can move to the next one
+ } else { // time to move on to the next interval
+ $interval++;
+ $step = Storage::$max_versions_per_interval[$interval]['step'];
+ $nextVersion = $prevTimestamp - $step;
+ if (Storage::$max_versions_per_interval[$interval]['intervalEndsAfter'] == -1) {
+ $nextInterval = -1;
+ } else {
+ $nextInterval = $time - Storage::$max_versions_per_interval[$interval]['intervalEndsAfter'];
+ }
+ $newInterval = true; // we changed the interval -> check same version with new interval
+ }
+ }
+ $prevTimestamp = $version['version'];
+ }
+ }
+ return $size;
+ }
+
}