##// END OF EJS Templates
util: compression APIs to support revlog decompression...
Gregory Szorc -
r30798:f50c0db5 default
parent child Browse files
Show More
@@ -3000,6 +3000,8 b' class compressormanager(object):'
3000 self._bundlenames = {}
3000 self._bundlenames = {}
3001 # Internal bundle identifier to engine name.
3001 # Internal bundle identifier to engine name.
3002 self._bundletypes = {}
3002 self._bundletypes = {}
3003 # Revlog header to engine name.
3004 self._revlogheaders = {}
3003 # Wire proto identifier to engine name.
3005 # Wire proto identifier to engine name.
3004 self._wiretypes = {}
3006 self._wiretypes = {}
3005
3007
@@ -3053,6 +3055,14 b' class compressormanager(object):'
3053
3055
3054 self._wiretypes[wiretype] = name
3056 self._wiretypes[wiretype] = name
3055
3057
3058 revlogheader = engine.revlogheader()
3059 if revlogheader and revlogheader in self._revlogheaders:
3060 raise error.Abort(_('revlog header %s already registered by %s') %
3061 (revlogheader, self._revlogheaders[revlogheader]))
3062
3063 if revlogheader:
3064 self._revlogheaders[revlogheader] = name
3065
3056 self._engines[name] = engine
3066 self._engines[name] = engine
3057
3067
3058 @property
3068 @property
@@ -3121,6 +3131,13 b' class compressormanager(object):'
3121 engine.name())
3131 engine.name())
3122 return engine
3132 return engine
3123
3133
3134 def forrevlogheader(self, header):
3135 """Obtain a compression engine registered to a revlog header.
3136
3137 Will raise KeyError if the revlog header value isn't registered.
3138 """
3139 return self._engines[self._revlogheaders[header]]
3140
3124 compengines = compressormanager()
3141 compengines = compressormanager()
3125
3142
3126 class compressionengine(object):
3143 class compressionengine(object):
@@ -3186,6 +3203,16 b' class compressionengine(object):'
3186 """
3203 """
3187 return None
3204 return None
3188
3205
3206 def revlogheader(self):
3207 """Header added to revlog chunks that identifies this engine.
3208
3209 If this engine can be used to compress revlogs, this method should
3210 return the bytes used to identify chunks compressed with this engine.
3211 Else, the method should return ``None`` to indicate it does not
3212 participate in revlog compression.
3213 """
3214 return None
3215
3189 def compressstream(self, it, opts=None):
3216 def compressstream(self, it, opts=None):
3190 """Compress an iterator of chunks.
3217 """Compress an iterator of chunks.
3191
3218
@@ -3215,6 +3242,13 b' class compressionengine(object):'
3215 the data could not be compressed (too small, not compressible, etc).
3242 the data could not be compressed (too small, not compressible, etc).
3216 The returned data should have a header uniquely identifying this
3243 The returned data should have a header uniquely identifying this
3217 compression format so decompression can be routed to this engine.
3244 compression format so decompression can be routed to this engine.
3245 This header should be identified by the ``revlogheader()`` return
3246 value.
3247
3248 The object has a ``decompress(data)`` method that decompresses
3249 data. The method will only be called if ``data`` begins with
3250 ``revlogheader()``. The method should return the raw, uncompressed
3251 data or raise a ``RevlogError``.
3218
3252
3219 The object is reusable but is not thread safe.
3253 The object is reusable but is not thread safe.
3220 """
3254 """
@@ -3230,6 +3264,9 b' class _zlibengine(compressionengine):'
3230 def wireprotosupport(self):
3264 def wireprotosupport(self):
3231 return compewireprotosupport('zlib', 20, 20)
3265 return compewireprotosupport('zlib', 20, 20)
3232
3266
3267 def revlogheader(self):
3268 return 'x'
3269
3233 def compressstream(self, it, opts=None):
3270 def compressstream(self, it, opts=None):
3234 opts = opts or {}
3271 opts = opts or {}
3235
3272
@@ -3286,6 +3323,13 b' class _zlibengine(compressionengine):'
3286 return ''.join(parts)
3323 return ''.join(parts)
3287 return None
3324 return None
3288
3325
3326 def decompress(self, data):
3327 try:
3328 return zlib.decompress(data)
3329 except zlib.error as e:
3330 raise error.RevlogError(_('revlog decompress error: %s') %
3331 str(e))
3332
3289 def revlogcompressor(self, opts=None):
3333 def revlogcompressor(self, opts=None):
3290 return self.zlibrevlogcompressor()
3334 return self.zlibrevlogcompressor()
3291
3335
@@ -3357,6 +3401,9 b' class _noopengine(compressionengine):'
3357 def wireprotosupport(self):
3401 def wireprotosupport(self):
3358 return compewireprotosupport('none', 0, 10)
3402 return compewireprotosupport('none', 0, 10)
3359
3403
3404 # We don't implement revlogheader because it is handled specially
3405 # in the revlog class.
3406
3360 def compressstream(self, it, opts=None):
3407 def compressstream(self, it, opts=None):
3361 return it
3408 return it
3362
3409
@@ -3397,6 +3444,9 b' class _zstdengine(compressionengine):'
3397 def wireprotosupport(self):
3444 def wireprotosupport(self):
3398 return compewireprotosupport('zstd', 50, 50)
3445 return compewireprotosupport('zstd', 50, 50)
3399
3446
3447 def revlogheader(self):
3448 return '\x28'
3449
3400 def compressstream(self, it, opts=None):
3450 def compressstream(self, it, opts=None):
3401 opts = opts or {}
3451 opts = opts or {}
3402 # zstd level 3 is almost always significantly faster than zlib
3452 # zstd level 3 is almost always significantly faster than zlib
@@ -3425,7 +3475,9 b' class _zstdengine(compressionengine):'
3425 # pre-allocate a buffer to hold the result.
3475 # pre-allocate a buffer to hold the result.
3426 self._cctx = zstd.ZstdCompressor(level=level,
3476 self._cctx = zstd.ZstdCompressor(level=level,
3427 write_content_size=True)
3477 write_content_size=True)
3478 self._dctx = zstd.ZstdDecompressor()
3428 self._compinsize = zstd.COMPRESSION_RECOMMENDED_INPUT_SIZE
3479 self._compinsize = zstd.COMPRESSION_RECOMMENDED_INPUT_SIZE
3480 self._decompinsize = zstd.DECOMPRESSION_RECOMMENDED_INPUT_SIZE
3429
3481
3430 def compress(self, data):
3482 def compress(self, data):
3431 insize = len(data)
3483 insize = len(data)
@@ -3456,6 +3508,28 b' class _zstdengine(compressionengine):'
3456 return ''.join(chunks)
3508 return ''.join(chunks)
3457 return None
3509 return None
3458
3510
3511 def decompress(self, data):
3512 insize = len(data)
3513
3514 try:
3515 # This was measured to be faster than other streaming
3516 # decompressors.
3517 dobj = self._dctx.decompressobj()
3518 chunks = []
3519 pos = 0
3520 while pos < insize:
3521 pos2 = pos + self._decompinsize
3522 chunk = dobj.decompress(data[pos:pos2])
3523 if chunk:
3524 chunks.append(chunk)
3525 pos = pos2
3526 # Frame should be exhausted, so no finish() API.
3527
3528 return ''.join(chunks)
3529 except Exception as e:
3530 raise error.RevlogError(_('revlog decompress error: %s') %
3531 str(e))
3532
3459 def revlogcompressor(self, opts=None):
3533 def revlogcompressor(self, opts=None):
3460 opts = opts or {}
3534 opts = opts or {}
3461 return self.zstdrevlogcompressor(self._module,
3535 return self.zstdrevlogcompressor(self._module,
General Comments 0
You need to be logged in to leave comments. Login now