Browse Source

call expire function before writing the new version to make sure to have enough free space

tags/v6.0.0alpha2
Björn Schießle 11 years ago
parent
commit
e159143165
1 changed files with 96 additions and 63 deletions
  1. 96
    63
      apps/files_versions/lib/versions.php

+ 96
- 63
apps/files_versions/lib/versions.php View File

@@ -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;
}

}

Loading…
Cancel
Save