Allow modern hunks to be stored deflated

Summary: Ref T4045. Ref T5179. When saving a modern hunk, deflate it if we have the function and deflating it will save a nontrivial number of bytes.

Test Plan:
  - Used `bin/hunks migrate` to move some hunks over, saw ~70-80% compression on most standard hunks.
  - Viewed changesets using compressed hunks.
  - Profiled `gzinflate()` and verified the cost is trivial (<< 1ms) at least for normal diffs.

Reviewers: btrahan

Reviewed By: btrahan

Subscribers: epriestley

Maniphest Tasks: T4045, T5179

Differential Revision: https://secure.phabricator.com/D9292
This commit is contained in:
epriestley
2014-05-25 11:41:16 -07:00
parent 5b1262c98b
commit 4b39fbe115
4 changed files with 134 additions and 44 deletions

View File

@@ -3,6 +3,7 @@
/**
* @task immutable Immutable Cache
* @task setup Setup Cache
* @task compress Compression
*/
final class PhabricatorCaches {
@@ -283,4 +284,64 @@ final class PhabricatorCaches {
return $caches;
}
/**
* Deflate a value, if deflation is available and has an impact.
*
* If the value is larger than 1KB, we have `gzdeflate()`, we successfully
* can deflate it, and it benefits from deflation, we deflate it. Otherwise
* we leave it as-is.
*
* Data can later be inflated with @{method:inflateData}.
*
* @param string String to attempt to deflate.
* @return string|null Deflated string, or null if it was not deflated.
* @task compress
*/
public static function maybeDeflateData($value) {
$len = strlen($value);
if ($len <= 1024) {
return null;
}
if (!function_exists('gzdeflate')) {
return null;
}
$deflated = gzdeflate($value);
if ($deflated === false) {
return null;
}
$deflated_len = strlen($deflated);
if ($deflated_len >= ($len / 2)) {
return null;
}
return $deflated;
}
/**
* Inflate data previously deflated by @{method:maybeDeflateData}.
*
* @param string Deflated data, from @{method:maybeDeflateData}.
* @return string Original, uncompressed data.
* @task compress
*/
public static function inflateData($value) {
if (!function_exists('gzinflate')) {
throw new Exception(
pht('gzinflate() is not available; unable to read deflated data!'));
}
$value = gzinflate($value);
if ($value === false) {
throw new Exception(pht('Failed to inflate data!'));
}
return $value;
}
}

View File

@@ -145,18 +145,10 @@ final class PhabricatorKeyValueDatabaseCache
PhabricatorEnv::getEnvConfig('cache.enable-deflate');
}
// If the value is larger than 1KB, we have gzdeflate(), we successfully
// can deflate it, and it benefits from deflation, store it deflated.
if ($can_deflate) {
$len = strlen($value);
if ($len > 1024) {
$deflated = gzdeflate($value);
if ($deflated !== false) {
$deflated_len = strlen($deflated);
if ($deflated_len < ($len / 2)) {
return array(self::CACHE_FORMAT_DEFLATE, $deflated);
}
}
$deflated = PhabricatorCaches::maybeDeflateData($value);
if ($deflated !== null) {
return array(self::CACHE_FORMAT_DEFLATE, $deflated);
}
}
@@ -168,14 +160,7 @@ final class PhabricatorKeyValueDatabaseCache
case self::CACHE_FORMAT_RAW:
return $value;
case self::CACHE_FORMAT_DEFLATE:
if (!function_exists('gzinflate')) {
throw new Exception("No gzinflate() to read deflated cache.");
}
$value = gzinflate($value);
if ($value === false) {
throw new Exception("Failed to deflate cache.");
}
return $value;
return PhabricatorCaches::inflateData($value);
default:
throw new Exception("Unknown cache format.");
}