Skip to content

Commit 9d65a5c

Browse files
authored
Merge pull request facebook#970 from facebook/dubtlazy
Delayed update Binary Tree for Lazy strategy
2 parents 04c00f9 + cacf47c commit 9d65a5c

File tree

9 files changed

+674
-428
lines changed

9 files changed

+674
-428
lines changed

lib/compress/zstd_compress.c

Lines changed: 103 additions & 85 deletions
Large diffs are not rendered by default.

lib/compress/zstd_lazy.c

Lines changed: 214 additions & 152 deletions
Large diffs are not rendered by default.

lib/compress/zstd_lazy.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@ extern "C" {
1818
#include "mem.h" /* U32 */
1919
#include "zstd.h" /* ZSTD_CCtx, size_t */
2020

21-
U32 ZSTD_insertAndFindFirstIndex (ZSTD_CCtx* zc, const BYTE* ip, U32 mls);
22-
void ZSTD_updateTree(ZSTD_CCtx* zc, const BYTE* const ip, const BYTE* const iend, const U32 nbCompares, const U32 mls);
23-
void ZSTD_updateTree_extDict(ZSTD_CCtx* zc, const BYTE* const ip, const BYTE* const iend, const U32 nbCompares, const U32 mls);
21+
U32 ZSTD_insertAndFindFirstIndex (ZSTD_CCtx* zc, const BYTE* ip, U32 mls); /* used in ZSTD_loadDictionaryContent() */
22+
void ZSTD_updateDUBT(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iend, U32 mls); /* used in ZSTD_loadDictionaryContent() */
23+
void ZSTD_preserveUnsortedMark (U32* const table, U32 const size, U32 const reducerValue); /*! used in ZSTD_reduceIndex(). pre-emptively increase value of ZSTD_DUBT_UNSORTED_MARK */
2424

2525
size_t ZSTD_compressBlock_btlazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize);
2626
size_t ZSTD_compressBlock_lazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize);

lib/compress/zstd_opt.c

Lines changed: 141 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010

1111
#include "zstd_compress_internal.h"
1212
#include "zstd_opt.h"
13-
#include "zstd_lazy.h" /* ZSTD_updateTree, ZSTD_updateTree_extDict */
1413

1514

1615
#define ZSTD_LITFREQ_ADD 2 /* scaling factor for litFreq, so that frequencies adapt faster to new stats. Also used for matchSum (?) */
@@ -265,6 +264,147 @@ static U32 ZSTD_insertAndFindFirstIndexHash3 (ZSTD_CCtx* const cctx, const BYTE*
265264
/*-*************************************
266265
* Binary Tree search
267266
***************************************/
267+
/** ZSTD_insertBt1() : add one or multiple positions to tree.
268+
* ip : assumed <= iend-8 .
269+
* @return : nb of positions added */
270+
static U32 ZSTD_insertBt1(ZSTD_CCtx* zc,
271+
const BYTE* const ip, const BYTE* const iend,
272+
U32 nbCompares, U32 const mls, U32 const extDict)
273+
{
274+
U32* const hashTable = zc->hashTable;
275+
U32 const hashLog = zc->appliedParams.cParams.hashLog;
276+
size_t const h = ZSTD_hashPtr(ip, hashLog, mls);
277+
U32* const bt = zc->chainTable;
278+
U32 const btLog = zc->appliedParams.cParams.chainLog - 1;
279+
U32 const btMask = (1 << btLog) - 1;
280+
U32 matchIndex = hashTable[h];
281+
size_t commonLengthSmaller=0, commonLengthLarger=0;
282+
const BYTE* const base = zc->base;
283+
const BYTE* const dictBase = zc->dictBase;
284+
const U32 dictLimit = zc->dictLimit;
285+
const BYTE* const dictEnd = dictBase + dictLimit;
286+
const BYTE* const prefixStart = base + dictLimit;
287+
const BYTE* match;
288+
const U32 current = (U32)(ip-base);
289+
const U32 btLow = btMask >= current ? 0 : current - btMask;
290+
U32* smallerPtr = bt + 2*(current&btMask);
291+
U32* largerPtr = smallerPtr + 1;
292+
U32 dummy32; /* to be nullified at the end */
293+
U32 const windowLow = zc->lowLimit;
294+
U32 matchEndIdx = current+8+1;
295+
size_t bestLength = 8;
296+
#ifdef ZSTD_C_PREDICT
297+
U32 predictedSmall = *(bt + 2*((current-1)&btMask) + 0);
298+
U32 predictedLarge = *(bt + 2*((current-1)&btMask) + 1);
299+
predictedSmall += (predictedSmall>0);
300+
predictedLarge += (predictedLarge>0);
301+
#endif /* ZSTD_C_PREDICT */
302+
303+
DEBUGLOG(8, "ZSTD_insertBt1 (%u)", current);
304+
305+
assert(ip <= iend-8); /* required for h calculation */
306+
hashTable[h] = current; /* Update Hash Table */
307+
308+
while (nbCompares-- && (matchIndex > windowLow)) {
309+
U32* const nextPtr = bt + 2*(matchIndex & btMask);
310+
size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
311+
assert(matchIndex < current);
312+
313+
#ifdef ZSTD_C_PREDICT /* note : can create issues when hlog small <= 11 */
314+
const U32* predictPtr = bt + 2*((matchIndex-1) & btMask); /* written this way, as bt is a roll buffer */
315+
if (matchIndex == predictedSmall) {
316+
/* no need to check length, result known */
317+
*smallerPtr = matchIndex;
318+
if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
319+
smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
320+
matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
321+
predictedSmall = predictPtr[1] + (predictPtr[1]>0);
322+
continue;
323+
}
324+
if (matchIndex == predictedLarge) {
325+
*largerPtr = matchIndex;
326+
if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
327+
largerPtr = nextPtr;
328+
matchIndex = nextPtr[0];
329+
predictedLarge = predictPtr[0] + (predictPtr[0]>0);
330+
continue;
331+
}
332+
#endif
333+
334+
if ((!extDict) || (matchIndex+matchLength >= dictLimit)) {
335+
assert(matchIndex+matchLength >= dictLimit); /* might be wrong if extDict is incorrectly set to 0 */
336+
match = base + matchIndex;
337+
matchLength += ZSTD_count(ip+matchLength, match+matchLength, iend);
338+
} else {
339+
match = dictBase + matchIndex;
340+
matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
341+
if (matchIndex+matchLength >= dictLimit)
342+
match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
343+
}
344+
345+
if (matchLength > bestLength) {
346+
bestLength = matchLength;
347+
if (matchLength > matchEndIdx - matchIndex)
348+
matchEndIdx = matchIndex + (U32)matchLength;
349+
}
350+
351+
if (ip+matchLength == iend) { /* equal : no way to know if inf or sup */
352+
break; /* drop , to guarantee consistency ; miss a bit of compression, but other solutions can corrupt tree */
353+
}
354+
355+
if (match[matchLength] < ip[matchLength]) { /* necessarily within buffer */
356+
/* match is smaller than current */
357+
*smallerPtr = matchIndex; /* update smaller idx */
358+
commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
359+
if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop searching */
360+
smallerPtr = nextPtr+1; /* new "candidate" => larger than match, which was smaller than target */
361+
matchIndex = nextPtr[1]; /* new matchIndex, larger than previous and closer to current */
362+
} else {
363+
/* match is larger than current */
364+
*largerPtr = matchIndex;
365+
commonLengthLarger = matchLength;
366+
if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop searching */
367+
largerPtr = nextPtr;
368+
matchIndex = nextPtr[0];
369+
} }
370+
371+
*smallerPtr = *largerPtr = 0;
372+
if (bestLength > 384) return MIN(192, (U32)(bestLength - 384)); /* speed optimization */
373+
assert(matchEndIdx > current + 8);
374+
return matchEndIdx - (current + 8);
375+
}
376+
377+
FORCE_INLINE_TEMPLATE
378+
void ZSTD_updateTree_internal(ZSTD_CCtx* zc,
379+
const BYTE* const ip, const BYTE* const iend,
380+
const U32 nbCompares, const U32 mls, const U32 extDict)
381+
{
382+
const BYTE* const base = zc->base;
383+
U32 const target = (U32)(ip - base);
384+
U32 idx = zc->nextToUpdate;
385+
DEBUGLOG(7, "ZSTD_updateTree_internal, from %u to %u (extDict:%u)",
386+
idx, target, extDict);
387+
388+
while(idx < target)
389+
idx += ZSTD_insertBt1(zc, base+idx, iend, nbCompares, mls, extDict);
390+
zc->nextToUpdate = target;
391+
}
392+
393+
void ZSTD_updateTree(ZSTD_CCtx* zc,
394+
const BYTE* ip, const BYTE* iend,
395+
U32 nbCompares, U32 mls)
396+
{
397+
ZSTD_updateTree_internal(zc, ip, iend, nbCompares, mls, 0 /*extDict*/);
398+
}
399+
400+
static void ZSTD_updateTree_extDict(ZSTD_CCtx* zc,
401+
const BYTE* const ip, const BYTE* const iend,
402+
const U32 nbCompares, const U32 mls)
403+
{
404+
ZSTD_updateTree_internal(zc, ip, iend, nbCompares, mls, 1 /*extDict*/);
405+
}
406+
407+
268408
FORCE_INLINE_TEMPLATE
269409
U32 ZSTD_insertBtAndGetAllMatches (
270410
ZSTD_CCtx* zc,

lib/compress/zstd_opt.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,11 @@
1515
extern "C" {
1616
#endif
1717

18+
#include "mem.h" /* U32 */
1819
#include "zstd.h" /* ZSTD_CCtx, size_t */
1920

21+
void ZSTD_updateTree(ZSTD_CCtx* ctx, const BYTE* ip, const BYTE* iend, U32 nbCompares, U32 mls); /* used in ZSTD_loadDictionaryContent() */
22+
2023
size_t ZSTD_compressBlock_btopt(ZSTD_CCtx* ctx, const void* src, size_t srcSize);
2124
size_t ZSTD_compressBlock_btultra(ZSTD_CCtx* ctx, const void* src, size_t srcSize);
2225

lib/decompress/zstd_decompress.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,7 @@ ZSTD_DCtx* ZSTD_createDCtx_advanced(ZSTD_customMem customMem)
204204

205205
ZSTD_DCtx* ZSTD_createDCtx(void)
206206
{
207+
DEBUGLOG(3, "ZSTD_createDCtx");
207208
return ZSTD_createDCtx_advanced(ZSTD_defaultCMem);
208209
}
209210

@@ -2247,6 +2248,7 @@ size_t ZSTD_decompress_usingDDict(ZSTD_DCtx* dctx,
22472248

22482249
ZSTD_DStream* ZSTD_createDStream(void)
22492250
{
2251+
DEBUGLOG(3, "ZSTD_createDStream");
22502252
return ZSTD_createDStream_advanced(ZSTD_defaultCMem);
22512253
}
22522254

@@ -2273,6 +2275,7 @@ size_t ZSTD_DStreamOutSize(void) { return ZSTD_BLOCKSIZE_MAX; }
22732275

22742276
size_t ZSTD_initDStream_usingDict(ZSTD_DStream* zds, const void* dict, size_t dictSize)
22752277
{
2278+
DEBUGLOG(4, "ZSTD_initDStream_usingDict");
22762279
zds->streamStage = zdss_loadHeader;
22772280
zds->lhSize = zds->inPos = zds->outStart = zds->outEnd = 0;
22782281
ZSTD_freeDDict(zds->ddictLocal);
@@ -2289,6 +2292,7 @@ size_t ZSTD_initDStream_usingDict(ZSTD_DStream* zds, const void* dict, size_t di
22892292
/* note : this variant can't fail */
22902293
size_t ZSTD_initDStream(ZSTD_DStream* zds)
22912294
{
2295+
DEBUGLOG(4, "ZSTD_initDStream");
22922296
return ZSTD_initDStream_usingDict(zds, NULL, 0);
22932297
}
22942298

@@ -2304,6 +2308,7 @@ size_t ZSTD_initDStream_usingDDict(ZSTD_DStream* zds, const ZSTD_DDict* ddict)
23042308

23052309
size_t ZSTD_resetDStream(ZSTD_DStream* zds)
23062310
{
2311+
DEBUGLOG(4, "ZSTD_resetDStream");
23072312
zds->streamStage = zdss_loadHeader;
23082313
zds->lhSize = zds->inPos = zds->outStart = zds->outEnd = 0;
23092314
zds->legacyVersion = 0;

tests/fuzz/.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,7 @@
22
corpora
33
block_decompress
44
block_round_trip
5+
simple_decompress
56
simple_round_trip
7+
stream_decompress
8+
stream_round_trip

0 commit comments

Comments
 (0)