zstd-ruby 1.3.2.0 → 1.3.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/ext/zstdruby/libzstd/BUCK +31 -10
  4. data/ext/zstdruby/libzstd/common/bitstream.h +1 -1
  5. data/ext/zstdruby/libzstd/common/mem.h +15 -13
  6. data/ext/zstdruby/libzstd/common/pool.c +1 -2
  7. data/ext/zstdruby/libzstd/common/zstd_common.c +10 -4
  8. data/ext/zstdruby/libzstd/common/zstd_internal.h +52 -170
  9. data/ext/zstdruby/libzstd/compress/zstd_compress.c +434 -337
  10. data/ext/zstdruby/libzstd/compress/{zstd_compress.h → zstd_compress_internal.h} +191 -36
  11. data/ext/zstdruby/libzstd/compress/zstd_double_fast.c +1 -0
  12. data/ext/zstdruby/libzstd/compress/zstd_double_fast.h +3 -2
  13. data/ext/zstdruby/libzstd/compress/zstd_fast.c +1 -0
  14. data/ext/zstdruby/libzstd/compress/zstd_fast.h +3 -2
  15. data/ext/zstdruby/libzstd/compress/zstd_lazy.c +66 -50
  16. data/ext/zstdruby/libzstd/compress/zstd_lazy.h +3 -2
  17. data/ext/zstdruby/libzstd/compress/zstd_ldm.h +3 -2
  18. data/ext/zstdruby/libzstd/compress/zstd_opt.c +504 -676
  19. data/ext/zstdruby/libzstd/compress/zstd_opt.h +2 -2
  20. data/ext/zstdruby/libzstd/compress/zstdmt_compress.c +130 -80
  21. data/ext/zstdruby/libzstd/compress/zstdmt_compress.h +15 -7
  22. data/ext/zstdruby/libzstd/decompress/zstd_decompress.c +41 -31
  23. data/ext/zstdruby/libzstd/deprecated/zbuff_compress.c +1 -0
  24. data/ext/zstdruby/libzstd/dictBuilder/zdict.c +1 -1
  25. data/ext/zstdruby/libzstd/legacy/zstd_v01.c +1 -1
  26. data/ext/zstdruby/libzstd/legacy/zstd_v02.c +1 -74
  27. data/ext/zstdruby/libzstd/legacy/zstd_v03.c +1 -74
  28. data/ext/zstdruby/libzstd/legacy/zstd_v04.c +1 -72
  29. data/ext/zstdruby/libzstd/legacy/zstd_v05.c +1 -73
  30. data/ext/zstdruby/libzstd/legacy/zstd_v06.c +1 -77
  31. data/ext/zstdruby/libzstd/legacy/zstd_v07.c +1 -77
  32. data/ext/zstdruby/libzstd/zstd.h +43 -30
  33. data/lib/zstd-ruby/version.rb +1 -1
  34. metadata +4 -4
@@ -11,12 +11,12 @@
11
11
  #ifndef ZSTD_OPT_H
12
12
  #define ZSTD_OPT_H
13
13
 
14
- #include "zstd_compress.h"
15
-
16
14
  #if defined (__cplusplus)
17
15
  extern "C" {
18
16
  #endif
19
17
 
18
+ #include "zstd.h" /* ZSTD_CCtx, size_t */
19
+
20
20
  size_t ZSTD_compressBlock_btopt(ZSTD_CCtx* ctx, const void* src, size_t srcSize);
21
21
  size_t ZSTD_compressBlock_btultra(ZSTD_CCtx* ctx, const void* src, size_t srcSize);
22
22
 
@@ -24,7 +24,7 @@
24
24
  #include <string.h> /* memcpy, memset */
25
25
  #include "pool.h" /* threadpool */
26
26
  #include "threading.h" /* mutex */
27
- #include "zstd_internal.h" /* MIN, ERROR, ZSTD_*, ZSTD_highbit32 */
27
+ #include "zstd_compress_internal.h" /* MIN, ERROR, ZSTD_*, ZSTD_highbit32 */
28
28
  #include "zstdmt_compress.h"
29
29
 
30
30
 
@@ -140,9 +140,12 @@ static size_t ZSTDMT_sizeof_bufferPool(ZSTDMT_bufferPool* bufPool)
140
140
  return poolSize + totalBufferSize;
141
141
  }
142
142
 
143
- static void ZSTDMT_setBufferSize(ZSTDMT_bufferPool* bufPool, size_t bSize)
143
+ static void ZSTDMT_setBufferSize(ZSTDMT_bufferPool* const bufPool, size_t const bSize)
144
144
  {
145
+ ZSTD_pthread_mutex_lock(&bufPool->poolMutex);
146
+ DEBUGLOG(4, "ZSTDMT_setBufferSize: bSize = %u", (U32)bSize);
145
147
  bufPool->bufferSize = bSize;
148
+ ZSTD_pthread_mutex_unlock(&bufPool->poolMutex);
146
149
  }
147
150
 
148
151
  /** ZSTDMT_getBuffer() :
@@ -150,28 +153,31 @@ static void ZSTDMT_setBufferSize(ZSTDMT_bufferPool* bufPool, size_t bSize)
150
153
  static buffer_t ZSTDMT_getBuffer(ZSTDMT_bufferPool* bufPool)
151
154
  {
152
155
  size_t const bSize = bufPool->bufferSize;
153
- DEBUGLOG(5, "ZSTDMT_getBuffer");
156
+ DEBUGLOG(5, "ZSTDMT_getBuffer: bSize = %u", (U32)bufPool->bufferSize);
154
157
  ZSTD_pthread_mutex_lock(&bufPool->poolMutex);
155
158
  if (bufPool->nbBuffers) { /* try to use an existing buffer */
156
159
  buffer_t const buf = bufPool->bTable[--(bufPool->nbBuffers)];
157
160
  size_t const availBufferSize = buf.size;
158
161
  bufPool->bTable[bufPool->nbBuffers] = g_nullBuffer;
159
- if ((availBufferSize >= bSize) & (availBufferSize <= 10*bSize)) {
162
+ if ((availBufferSize >= bSize) & ((availBufferSize>>3) <= bSize)) {
160
163
  /* large enough, but not too much */
164
+ DEBUGLOG(5, "ZSTDMT_getBuffer: provide buffer %u of size %u",
165
+ bufPool->nbBuffers, (U32)buf.size);
161
166
  ZSTD_pthread_mutex_unlock(&bufPool->poolMutex);
162
167
  return buf;
163
168
  }
164
169
  /* size conditions not respected : scratch this buffer, create new one */
165
- DEBUGLOG(5, "existing buffer does not meet size conditions => freeing");
170
+ DEBUGLOG(5, "ZSTDMT_getBuffer: existing buffer does not meet size conditions => freeing");
166
171
  ZSTD_free(buf.start, bufPool->cMem);
167
172
  }
168
173
  ZSTD_pthread_mutex_unlock(&bufPool->poolMutex);
169
174
  /* create new buffer */
170
- DEBUGLOG(5, "create a new buffer");
175
+ DEBUGLOG(5, "ZSTDMT_getBuffer: create a new buffer");
171
176
  { buffer_t buffer;
172
177
  void* const start = ZSTD_malloc(bSize, bufPool->cMem);
173
178
  buffer.start = start; /* note : start can be NULL if malloc fails ! */
174
179
  buffer.size = (start==NULL) ? 0 : bSize;
180
+ DEBUGLOG(5, "ZSTDMT_getBuffer: created buffer of size %u", (U32)bSize);
175
181
  return buffer;
176
182
  }
177
183
  }
@@ -184,12 +190,14 @@ static void ZSTDMT_releaseBuffer(ZSTDMT_bufferPool* bufPool, buffer_t buf)
184
190
  ZSTD_pthread_mutex_lock(&bufPool->poolMutex);
185
191
  if (bufPool->nbBuffers < bufPool->totalBuffers) {
186
192
  bufPool->bTable[bufPool->nbBuffers++] = buf; /* stored for later use */
193
+ DEBUGLOG(5, "ZSTDMT_releaseBuffer: stored buffer of size %u in slot %u",
194
+ (U32)buf.size, (U32)(bufPool->nbBuffers-1));
187
195
  ZSTD_pthread_mutex_unlock(&bufPool->poolMutex);
188
196
  return;
189
197
  }
190
198
  ZSTD_pthread_mutex_unlock(&bufPool->poolMutex);
191
199
  /* Reached bufferPool capacity (should not happen) */
192
- DEBUGLOG(5, "buffer pool capacity reached => freeing ");
200
+ DEBUGLOG(5, "ZSTDMT_releaseBuffer: pool capacity reached => freeing ");
193
201
  ZSTD_free(buf.start, bufPool->cMem);
194
202
  }
195
203
 
@@ -302,7 +310,7 @@ static void ZSTDMT_releaseCCtx(ZSTDMT_CCtxPool* pool, ZSTD_CCtx* cctx)
302
310
  typedef struct {
303
311
  buffer_t src;
304
312
  const void* srcStart;
305
- size_t dictSize;
313
+ size_t prefixSize;
306
314
  size_t srcSize;
307
315
  buffer_t dstBuff;
308
316
  size_t cSize;
@@ -324,11 +332,11 @@ typedef struct {
324
332
  void ZSTDMT_compressChunk(void* jobDescription)
325
333
  {
326
334
  ZSTDMT_jobDescription* const job = (ZSTDMT_jobDescription*)jobDescription;
327
- ZSTD_CCtx* cctx = ZSTDMT_getCCtx(job->cctxPool);
328
- const void* const src = (const char*)job->srcStart + job->dictSize;
335
+ ZSTD_CCtx* const cctx = ZSTDMT_getCCtx(job->cctxPool);
336
+ const void* const src = (const char*)job->srcStart + job->prefixSize;
329
337
  buffer_t dstBuff = job->dstBuff;
330
- DEBUGLOG(5, "job (first:%u) (last:%u) : dictSize %u, srcSize %u",
331
- job->firstChunk, job->lastChunk, (U32)job->dictSize, (U32)job->srcSize);
338
+ DEBUGLOG(5, "ZSTDMT_compressChunk: job (first:%u) (last:%u) : prefixSize %u, srcSize %u ",
339
+ job->firstChunk, job->lastChunk, (U32)job->prefixSize, (U32)job->srcSize);
332
340
 
333
341
  if (cctx==NULL) {
334
342
  job->cSize = ERROR(memory_allocation);
@@ -342,38 +350,48 @@ void ZSTDMT_compressChunk(void* jobDescription)
342
350
  goto _endJob;
343
351
  }
344
352
  job->dstBuff = dstBuff;
353
+ DEBUGLOG(5, "ZSTDMT_compressChunk: received dstBuff of size %u", (U32)dstBuff.size);
345
354
  }
346
355
 
347
- if (job->cdict) { /* should only happen for first segment */
348
- size_t const initError = ZSTD_compressBegin_usingCDict_advanced(cctx, job->cdict, job->params.fParams, job->fullFrameSize);
349
- DEBUGLOG(5, "using CDict");
356
+ if (job->cdict) {
357
+ size_t const initError = ZSTD_compressBegin_advanced_internal(cctx, NULL, 0, ZSTD_dm_auto, job->cdict, job->params, job->fullFrameSize);
358
+ DEBUGLOG(4, "ZSTDMT_compressChunk: init using CDict (windowLog=%u)", job->params.cParams.windowLog);
359
+ assert(job->firstChunk); /* only allowed for first job */
350
360
  if (ZSTD_isError(initError)) { job->cSize = initError; goto _endJob; }
351
361
  } else { /* srcStart points at reloaded section */
352
- if (!job->firstChunk) job->params.fParams.contentSizeFlag = 0; /* ensure no srcSize control */
353
- { ZSTD_CCtx_params jobParams = job->params;
354
- size_t const forceWindowError =
355
- ZSTD_CCtxParam_setParameter(&jobParams, ZSTD_p_forceMaxWindow, !job->firstChunk);
356
- /* Force loading dictionary in "content-only" mode (no header analysis) */
357
- size_t const initError = ZSTD_compressBegin_advanced_internal(cctx, job->srcStart, job->dictSize, ZSTD_dm_rawContent, jobParams, job->fullFrameSize);
358
- if (ZSTD_isError(initError) || ZSTD_isError(forceWindowError)) {
362
+ U64 const pledgedSrcSize = job->firstChunk ? job->fullFrameSize : ZSTD_CONTENTSIZE_UNKNOWN;
363
+ ZSTD_CCtx_params jobParams = job->params; /* do not modify job->params ! copy it, modify the copy */
364
+ size_t const forceWindowError = ZSTD_CCtxParam_setParameter(&jobParams, ZSTD_p_forceMaxWindow, !job->firstChunk);
365
+ if (ZSTD_isError(forceWindowError)) {
366
+ DEBUGLOG(5, "ZSTD_CCtxParam_setParameter error : %s ", ZSTD_getErrorName(forceWindowError));
367
+ job->cSize = forceWindowError;
368
+ goto _endJob;
369
+ }
370
+ DEBUGLOG(5, "ZSTDMT_compressChunk: invoking ZSTD_compressBegin_advanced_internal with windowLog = %u ", jobParams.cParams.windowLog);
371
+ { size_t const initError = ZSTD_compressBegin_advanced_internal(cctx,
372
+ job->srcStart, job->prefixSize, ZSTD_dm_rawContent, /* load dictionary in "content-only" mode (no header analysis) */
373
+ NULL,
374
+ jobParams, pledgedSrcSize);
375
+ if (ZSTD_isError(initError)) {
376
+ DEBUGLOG(5, "ZSTD_compressBegin_advanced_internal error : %s ", ZSTD_getErrorName(initError));
359
377
  job->cSize = initError;
360
378
  goto _endJob;
361
- }
362
- } }
363
- if (!job->firstChunk) { /* flush and overwrite frame header when it's not first segment */
379
+ } }
380
+ }
381
+ if (!job->firstChunk) { /* flush and overwrite frame header when it's not first job */
364
382
  size_t const hSize = ZSTD_compressContinue(cctx, dstBuff.start, dstBuff.size, src, 0);
365
- if (ZSTD_isError(hSize)) { job->cSize = hSize; goto _endJob; }
383
+ if (ZSTD_isError(hSize)) { job->cSize = hSize; /* save error code */ goto _endJob; }
366
384
  ZSTD_invalidateRepCodes(cctx);
367
385
  }
368
386
 
369
- DEBUGLOG(5, "Compressing : ");
370
- DEBUG_PRINTHEX(4, job->srcStart, 12);
387
+ DEBUGLOG(5, "Compressing into dstBuff of size %u", (U32)dstBuff.size);
388
+ DEBUG_PRINTHEX(6, job->srcStart, 12);
371
389
  job->cSize = (job->lastChunk) ?
372
390
  ZSTD_compressEnd (cctx, dstBuff.start, dstBuff.size, src, job->srcSize) :
373
391
  ZSTD_compressContinue(cctx, dstBuff.start, dstBuff.size, src, job->srcSize);
374
- DEBUGLOG(5, "compressed %u bytes into %u bytes (first:%u) (last:%u)",
392
+ DEBUGLOG(5, "compressed %u bytes into %u bytes (first:%u) (last:%u) ",
375
393
  (unsigned)job->srcSize, (unsigned)job->cSize, job->firstChunk, job->lastChunk);
376
- DEBUGLOG(5, "dstBuff.size : %u ; => %s", (U32)dstBuff.size, ZSTD_getErrorName(job->cSize));
394
+ DEBUGLOG(5, "dstBuff.size : %u ; => %s ", (U32)dstBuff.size, ZSTD_getErrorName(job->cSize));
377
395
 
378
396
  _endJob:
379
397
  ZSTDMT_releaseCCtx(job->cctxPool, cctx);
@@ -403,13 +421,14 @@ struct ZSTDMT_CCtx_s {
403
421
  ZSTDMT_CCtxPool* cctxPool;
404
422
  ZSTD_pthread_mutex_t jobCompleted_mutex;
405
423
  ZSTD_pthread_cond_t jobCompleted_cond;
424
+ ZSTD_CCtx_params params;
406
425
  size_t targetSectionSize;
407
426
  size_t inBuffSize;
408
427
  size_t dictSize;
409
428
  size_t targetDictSize;
410
429
  inBuff_t inBuff;
411
- ZSTD_CCtx_params params;
412
430
  XXH64_state_t xxhState;
431
+ unsigned singleThreaded;
413
432
  unsigned jobIDMask;
414
433
  unsigned doneJobID;
415
434
  unsigned nextJobID;
@@ -430,20 +449,32 @@ static ZSTDMT_jobDescription* ZSTDMT_allocJobsTable(U32* nbJobsPtr, ZSTD_customM
430
449
  nbJobs * sizeof(ZSTDMT_jobDescription), cMem);
431
450
  }
432
451
 
433
- /* Internal only */
434
- size_t ZSTDMT_initializeCCtxParameters(ZSTD_CCtx_params* params, unsigned nbThreads)
452
+ /* ZSTDMT_CCtxParam_setNbThreads():
453
+ * Internal use only */
454
+ size_t ZSTDMT_CCtxParam_setNbThreads(ZSTD_CCtx_params* params, unsigned nbThreads)
435
455
  {
456
+ if (nbThreads > ZSTDMT_NBTHREADS_MAX) nbThreads = ZSTDMT_NBTHREADS_MAX;
457
+ if (nbThreads < 1) nbThreads = 1;
436
458
  params->nbThreads = nbThreads;
437
459
  params->overlapSizeLog = ZSTDMT_OVERLAPLOG_DEFAULT;
438
460
  params->jobSize = 0;
439
- return 0;
461
+ return nbThreads;
462
+ }
463
+
464
+ /* ZSTDMT_getNbThreads():
465
+ * @return nb threads currently active in mtctx.
466
+ * mtctx must be valid */
467
+ size_t ZSTDMT_getNbThreads(const ZSTDMT_CCtx* mtctx)
468
+ {
469
+ assert(mtctx != NULL);
470
+ return mtctx->params.nbThreads;
440
471
  }
441
472
 
442
473
  ZSTDMT_CCtx* ZSTDMT_createCCtx_advanced(unsigned nbThreads, ZSTD_customMem cMem)
443
474
  {
444
475
  ZSTDMT_CCtx* mtctx;
445
476
  U32 nbJobs = nbThreads + 2;
446
- DEBUGLOG(3, "ZSTDMT_createCCtx_advanced");
477
+ DEBUGLOG(3, "ZSTDMT_createCCtx_advanced (nbThreads = %u)", nbThreads);
447
478
 
448
479
  if (nbThreads < 1) return NULL;
449
480
  nbThreads = MIN(nbThreads , ZSTDMT_NBTHREADS_MAX);
@@ -453,7 +484,7 @@ ZSTDMT_CCtx* ZSTDMT_createCCtx_advanced(unsigned nbThreads, ZSTD_customMem cMem)
453
484
 
454
485
  mtctx = (ZSTDMT_CCtx*) ZSTD_calloc(sizeof(ZSTDMT_CCtx), cMem);
455
486
  if (!mtctx) return NULL;
456
- ZSTDMT_initializeCCtxParameters(&mtctx->params, nbThreads);
487
+ ZSTDMT_CCtxParam_setNbThreads(&mtctx->params, nbThreads);
457
488
  mtctx->cMem = cMem;
458
489
  mtctx->allJobsCompleted = 1;
459
490
  mtctx->factory = POOL_create_advanced(nbThreads, 0, cMem);
@@ -545,17 +576,23 @@ size_t ZSTDMT_sizeof_CCtx(ZSTDMT_CCtx* mtctx)
545
576
  }
546
577
 
547
578
  /* Internal only */
548
- size_t ZSTDMT_CCtxParam_setMTCtxParameter(
549
- ZSTD_CCtx_params* params, ZSTDMT_parameter parameter, unsigned value) {
579
+ size_t ZSTDMT_CCtxParam_setMTCtxParameter(ZSTD_CCtx_params* params,
580
+ ZSTDMT_parameter parameter, unsigned value) {
581
+ DEBUGLOG(4, "ZSTDMT_CCtxParam_setMTCtxParameter");
550
582
  switch(parameter)
551
583
  {
552
- case ZSTDMT_p_sectionSize :
584
+ case ZSTDMT_p_jobSize :
585
+ DEBUGLOG(4, "ZSTDMT_CCtxParam_setMTCtxParameter : set jobSize to %u", value);
586
+ if ( (value > 0) /* value==0 => automatic job size */
587
+ & (value < ZSTDMT_JOBSIZE_MIN) )
588
+ value = ZSTDMT_JOBSIZE_MIN;
553
589
  params->jobSize = value;
554
- return 0;
590
+ return value;
555
591
  case ZSTDMT_p_overlapSectionLog :
592
+ if (value > 9) value = 9;
556
593
  DEBUGLOG(4, "ZSTDMT_p_overlapSectionLog : %u", value);
557
594
  params->overlapSizeLog = (value >= 9) ? 9 : value;
558
- return 0;
595
+ return value;
559
596
  default :
560
597
  return ERROR(parameter_unsupported);
561
598
  }
@@ -563,9 +600,10 @@ size_t ZSTDMT_CCtxParam_setMTCtxParameter(
563
600
 
564
601
  size_t ZSTDMT_setMTCtxParameter(ZSTDMT_CCtx* mtctx, ZSTDMT_parameter parameter, unsigned value)
565
602
  {
603
+ DEBUGLOG(4, "ZSTDMT_setMTCtxParameter");
566
604
  switch(parameter)
567
605
  {
568
- case ZSTDMT_p_sectionSize :
606
+ case ZSTDMT_p_jobSize :
569
607
  return ZSTDMT_CCtxParam_setMTCtxParameter(&mtctx->params, parameter, value);
570
608
  case ZSTDMT_p_overlapSectionLog :
571
609
  return ZSTDMT_CCtxParam_setMTCtxParameter(&mtctx->params, parameter, value);
@@ -601,7 +639,7 @@ static size_t ZSTDMT_compress_advanced_internal(
601
639
  size_t const overlapSize = (overlapRLog>=9) ? 0 : (size_t)1 << (params.cParams.windowLog - overlapRLog);
602
640
  unsigned nbChunks = computeNbChunks(srcSize, params.cParams.windowLog, params.nbThreads);
603
641
  size_t const proposedChunkSize = (srcSize + (nbChunks-1)) / nbChunks;
604
- size_t const avgChunkSize = ((proposedChunkSize & 0x1FFFF) < 0x7FFF) ? proposedChunkSize + 0xFFFF : proposedChunkSize; /* avoid too small last block */
642
+ size_t const avgChunkSize = (((proposedChunkSize-1) & 0x1FFFF) < 0x7FFF) ? proposedChunkSize + 0xFFFF : proposedChunkSize; /* avoid too small last block */
605
643
  const char* const srcStart = (const char*)src;
606
644
  size_t remainingSrcSize = srcSize;
607
645
  unsigned const compressWithinDst = (dstCapacity >= ZSTD_compressBound(srcSize)) ? nbChunks : (unsigned)(dstCapacity / ZSTD_compressBound(avgChunkSize)); /* presumes avgChunkSize >= 256 KB, which should be the case */
@@ -610,7 +648,8 @@ static size_t ZSTDMT_compress_advanced_internal(
610
648
  assert(jobParams.nbThreads == 0);
611
649
  assert(mtctx->cctxPool->totalCCtx == params.nbThreads);
612
650
 
613
- DEBUGLOG(4, "nbChunks : %2u (chunkSize : %u bytes) ", nbChunks, (U32)avgChunkSize);
651
+ DEBUGLOG(4, "ZSTDMT_compress_advanced_internal: nbChunks=%2u (rawSize=%u bytes; fixedSize=%u) ",
652
+ nbChunks, (U32)proposedChunkSize, (U32)avgChunkSize);
614
653
  if (nbChunks==1) { /* fallback to single-thread mode */
615
654
  ZSTD_CCtx* const cctx = mtctx->cctxPool->cctx[0];
616
655
  if (cdict) return ZSTD_compress_usingCDict_advanced(cctx, dst, dstCapacity, src, srcSize, cdict, jobParams.fParams);
@@ -639,9 +678,9 @@ static size_t ZSTDMT_compress_advanced_internal(
639
678
 
640
679
  mtctx->jobs[u].src = g_nullBuffer;
641
680
  mtctx->jobs[u].srcStart = srcStart + frameStartPos - dictSize;
642
- mtctx->jobs[u].dictSize = dictSize;
681
+ mtctx->jobs[u].prefixSize = dictSize;
643
682
  mtctx->jobs[u].srcSize = chunkSize;
644
- mtctx->jobs[u].cdict = mtctx->nextJobID==0 ? cdict : NULL;
683
+ mtctx->jobs[u].cdict = (u==0) ? cdict : NULL;
645
684
  mtctx->jobs[u].fullFrameSize = srcSize;
646
685
  mtctx->jobs[u].params = jobParams;
647
686
  /* do not calculate checksum within sections, but write it in header for first section */
@@ -659,7 +698,7 @@ static size_t ZSTDMT_compress_advanced_internal(
659
698
  XXH64_update(&xxh64, srcStart + frameStartPos, chunkSize);
660
699
  }
661
700
 
662
- DEBUGLOG(5, "posting job %u (%u bytes)", u, (U32)chunkSize);
701
+ DEBUGLOG(5, "ZSTDMT_compress_advanced_internal: posting job %u (%u bytes)", u, (U32)chunkSize);
663
702
  DEBUG_PRINTHEX(6, mtctx->jobs[u].srcStart, 12);
664
703
  POOL_add(mtctx->factory, ZSTDMT_compressChunk, &mtctx->jobs[u]);
665
704
 
@@ -753,13 +792,14 @@ size_t ZSTDMT_initCStream_internal(
753
792
  const ZSTD_CDict* cdict, ZSTD_CCtx_params params,
754
793
  unsigned long long pledgedSrcSize)
755
794
  {
756
- DEBUGLOG(4, "ZSTDMT_initCStream_internal");
795
+ DEBUGLOG(4, "ZSTDMT_initCStream_internal (pledgedSrcSize=%u)", (U32)pledgedSrcSize);
757
796
  /* params are supposed to be fully validated at this point */
758
797
  assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams)));
759
798
  assert(!((dict) && (cdict))); /* either dict or cdict, not both */
760
799
  assert(zcs->cctxPool->totalCCtx == params.nbThreads);
800
+ zcs->singleThreaded = (params.nbThreads==1) | (pledgedSrcSize <= ZSTDMT_JOBSIZE_MIN); /* do not trigger multi-threading when srcSize is too small */
761
801
 
762
- if (params.nbThreads==1) {
802
+ if (zcs->singleThreaded) {
763
803
  ZSTD_CCtx_params const singleThreadParams = ZSTDMT_makeJobCCtxParams(params);
764
804
  DEBUGLOG(4, "single thread mode");
765
805
  assert(singleThreadParams.nbThreads == 0);
@@ -767,6 +807,7 @@ size_t ZSTDMT_initCStream_internal(
767
807
  dict, dictSize, cdict,
768
808
  singleThreadParams, pledgedSrcSize);
769
809
  }
810
+ DEBUGLOG(4, "multi-threading mode (%u threads)", params.nbThreads);
770
811
 
771
812
  if (zcs->allJobsCompleted == 0) { /* previous compression not correctly finished */
772
813
  ZSTDMT_waitForAllJobsCompleted(zcs);
@@ -777,7 +818,6 @@ size_t ZSTDMT_initCStream_internal(
777
818
  zcs->params = params;
778
819
  zcs->frameContentSize = pledgedSrcSize;
779
820
  if (dict) {
780
- DEBUGLOG(4,"cdictLocal: %08X", (U32)(size_t)zcs->cdictLocal);
781
821
  ZSTD_freeCDict(zcs->cdictLocal);
782
822
  zcs->cdictLocal = ZSTD_createCDict_advanced(dict, dictSize,
783
823
  ZSTD_dlm_byCopy, dictMode, /* note : a loadPrefix becomes an internal CDict */
@@ -785,20 +825,20 @@ size_t ZSTDMT_initCStream_internal(
785
825
  zcs->cdict = zcs->cdictLocal;
786
826
  if (zcs->cdictLocal == NULL) return ERROR(memory_allocation);
787
827
  } else {
788
- DEBUGLOG(4,"cdictLocal: %08X", (U32)(size_t)zcs->cdictLocal);
789
828
  ZSTD_freeCDict(zcs->cdictLocal);
790
829
  zcs->cdictLocal = NULL;
791
830
  zcs->cdict = cdict;
792
831
  }
793
832
 
833
+ assert(params.overlapSizeLog <= 9);
794
834
  zcs->targetDictSize = (params.overlapSizeLog==0) ? 0 : (size_t)1 << (params.cParams.windowLog - (9 - params.overlapSizeLog));
795
- DEBUGLOG(4, "overlapLog : %u ", params.overlapSizeLog);
796
- DEBUGLOG(4, "overlap Size : %u KB", (U32)(zcs->targetDictSize>>10));
835
+ DEBUGLOG(4, "overlapLog=%u => %u KB", params.overlapSizeLog, (U32)(zcs->targetDictSize>>10));
797
836
  zcs->targetSectionSize = params.jobSize ? params.jobSize : (size_t)1 << (params.cParams.windowLog + 2);
798
- zcs->targetSectionSize = MAX(ZSTDMT_SECTION_SIZE_MIN, zcs->targetSectionSize);
799
- zcs->targetSectionSize = MAX(zcs->targetDictSize, zcs->targetSectionSize);
800
- DEBUGLOG(4, "Section Size : %u KB", (U32)(zcs->targetSectionSize>>10));
837
+ if (zcs->targetSectionSize < ZSTDMT_JOBSIZE_MIN) zcs->targetSectionSize = ZSTDMT_JOBSIZE_MIN;
838
+ if (zcs->targetSectionSize < zcs->targetDictSize) zcs->targetSectionSize = zcs->targetDictSize; /* job size must be >= overlap size */
839
+ DEBUGLOG(4, "Job Size : %u KB (note : set to %u)", (U32)(zcs->targetSectionSize>>10), params.jobSize);
801
840
  zcs->inBuffSize = zcs->targetDictSize + zcs->targetSectionSize;
841
+ DEBUGLOG(4, "inBuff Size : %u KB", (U32)(zcs->inBuffSize>>10));
802
842
  ZSTDMT_setBufferSize(zcs->bufPool, MAX(zcs->inBuffSize, ZSTD_compressBound(zcs->targetSectionSize)) );
803
843
  zcs->inBuff.buffer = g_nullBuffer;
804
844
  zcs->dictSize = 0;
@@ -816,7 +856,7 @@ size_t ZSTDMT_initCStream_advanced(ZSTDMT_CCtx* mtctx,
816
856
  unsigned long long pledgedSrcSize)
817
857
  {
818
858
  ZSTD_CCtx_params cctxParams = mtctx->params;
819
- DEBUGLOG(5, "ZSTDMT_initCStream_advanced");
859
+ DEBUGLOG(5, "ZSTDMT_initCStream_advanced (pledgedSrcSize=%u)", (U32)pledgedSrcSize);
820
860
  cctxParams.cParams = params.cParams;
821
861
  cctxParams.fParams = params.fParams;
822
862
  return ZSTDMT_initCStream_internal(mtctx, dict, dictSize, ZSTD_dm_auto, NULL,
@@ -838,9 +878,12 @@ size_t ZSTDMT_initCStream_usingCDict(ZSTDMT_CCtx* mtctx,
838
878
 
839
879
 
840
880
  /* ZSTDMT_resetCStream() :
841
- * pledgedSrcSize is optional and can be zero == unknown */
881
+ * pledgedSrcSize can be zero == unknown (for the time being)
882
+ * prefer using ZSTD_CONTENTSIZE_UNKNOWN,
883
+ * as `0` might mean "empty" in the future */
842
884
  size_t ZSTDMT_resetCStream(ZSTDMT_CCtx* zcs, unsigned long long pledgedSrcSize)
843
885
  {
886
+ if (!pledgedSrcSize) pledgedSrcSize = ZSTD_CONTENTSIZE_UNKNOWN;
844
887
  if (zcs->params.nbThreads==1)
845
888
  return ZSTD_resetCStream(zcs->cctxPool->cctx[0], pledgedSrcSize);
846
889
  return ZSTDMT_initCStream_internal(zcs, NULL, 0, ZSTD_dm_auto, 0, zcs->params,
@@ -852,7 +895,7 @@ size_t ZSTDMT_initCStream(ZSTDMT_CCtx* zcs, int compressionLevel) {
852
895
  ZSTD_CCtx_params cctxParams = zcs->params;
853
896
  cctxParams.cParams = params.cParams;
854
897
  cctxParams.fParams = params.fParams;
855
- return ZSTDMT_initCStream_internal(zcs, NULL, 0, ZSTD_dm_auto, NULL, cctxParams, 0);
898
+ return ZSTDMT_initCStream_internal(zcs, NULL, 0, ZSTD_dm_auto, NULL, cctxParams, ZSTD_CONTENTSIZE_UNKNOWN);
856
899
  }
857
900
 
858
901
 
@@ -860,12 +903,12 @@ static size_t ZSTDMT_createCompressionJob(ZSTDMT_CCtx* zcs, size_t srcSize, unsi
860
903
  {
861
904
  unsigned const jobID = zcs->nextJobID & zcs->jobIDMask;
862
905
 
863
- DEBUGLOG(4, "preparing job %u to compress %u bytes with %u preload ",
906
+ DEBUGLOG(5, "ZSTDMT_createCompressionJob: preparing job %u to compress %u bytes with %u preload ",
864
907
  zcs->nextJobID, (U32)srcSize, (U32)zcs->dictSize);
865
908
  zcs->jobs[jobID].src = zcs->inBuff.buffer;
866
909
  zcs->jobs[jobID].srcStart = zcs->inBuff.buffer.start;
867
910
  zcs->jobs[jobID].srcSize = srcSize;
868
- zcs->jobs[jobID].dictSize = zcs->dictSize;
911
+ zcs->jobs[jobID].prefixSize = zcs->dictSize;
869
912
  assert(zcs->inBuff.filled >= srcSize + zcs->dictSize);
870
913
  zcs->jobs[jobID].params = zcs->params;
871
914
  /* do not calculate checksum within sections, but write it in header for first section */
@@ -911,7 +954,7 @@ static size_t ZSTDMT_createCompressionJob(ZSTDMT_CCtx* zcs, size_t srcSize, unsi
911
954
  zcs->params.fParams.checksumFlag = 0;
912
955
  } }
913
956
 
914
- DEBUGLOG(4, "posting job %u : %u bytes (end:%u) (note : doneJob = %u=>%u)",
957
+ DEBUGLOG(5, "ZSTDMT_createCompressionJob: posting job %u : %u bytes (end:%u) (note : doneJob = %u=>%u)",
915
958
  zcs->nextJobID,
916
959
  (U32)zcs->jobs[jobID].srcSize,
917
960
  zcs->jobs[jobID].lastChunk,
@@ -930,6 +973,7 @@ static size_t ZSTDMT_createCompressionJob(ZSTDMT_CCtx* zcs, size_t srcSize, unsi
930
973
  static size_t ZSTDMT_flushNextJob(ZSTDMT_CCtx* zcs, ZSTD_outBuffer* output, unsigned blockToFlush)
931
974
  {
932
975
  unsigned const wJobID = zcs->doneJobID & zcs->jobIDMask;
976
+ DEBUGLOG(5, "ZSTDMT_flushNextJob");
933
977
  if (zcs->doneJobID == zcs->nextJobID) return 0; /* all flushed ! */
934
978
  ZSTD_PTHREAD_MUTEX_LOCK(&zcs->jobCompleted_mutex);
935
979
  while (zcs->jobs[wJobID].jobCompleted==0) {
@@ -942,7 +986,8 @@ static size_t ZSTDMT_flushNextJob(ZSTDMT_CCtx* zcs, ZSTD_outBuffer* output, unsi
942
986
  { ZSTDMT_jobDescription job = zcs->jobs[wJobID];
943
987
  if (!job.jobScanned) {
944
988
  if (ZSTD_isError(job.cSize)) {
945
- DEBUGLOG(5, "compression error detected ");
989
+ DEBUGLOG(5, "job %u : compression error detected : %s",
990
+ zcs->doneJobID, ZSTD_getErrorName(job.cSize));
946
991
  ZSTDMT_waitForAllJobsCompleted(zcs);
947
992
  ZSTDMT_releaseAllJobResources(zcs);
948
993
  return job.cSize;
@@ -991,15 +1036,18 @@ size_t ZSTDMT_compressStream_generic(ZSTDMT_CCtx* mtctx,
991
1036
  {
992
1037
  size_t const newJobThreshold = mtctx->dictSize + mtctx->targetSectionSize;
993
1038
  unsigned forwardInputProgress = 0;
1039
+ DEBUGLOG(5, "ZSTDMT_compressStream_generic ");
994
1040
  assert(output->pos <= output->size);
995
1041
  assert(input->pos <= input->size);
1042
+
1043
+ if (mtctx->singleThreaded) { /* delegate to single-thread (synchronous) */
1044
+ return ZSTD_compressStream_generic(mtctx->cctxPool->cctx[0], output, input, endOp);
1045
+ }
1046
+
996
1047
  if ((mtctx->frameEnded) && (endOp==ZSTD_e_continue)) {
997
1048
  /* current frame being ended. Only flush/end are allowed */
998
1049
  return ERROR(stage_wrong);
999
1050
  }
1000
- if (mtctx->params.nbThreads==1) { /* delegate to single-thread (synchronous) */
1001
- return ZSTD_compressStream_generic(mtctx->cctxPool->cctx[0], output, input, endOp);
1002
- }
1003
1051
 
1004
1052
  /* single-pass shortcut (note : synchronous-mode) */
1005
1053
  if ( (mtctx->nextJobID == 0) /* just started */
@@ -1068,32 +1116,34 @@ size_t ZSTDMT_compressStream(ZSTDMT_CCtx* zcs, ZSTD_outBuffer* output, ZSTD_inBu
1068
1116
  }
1069
1117
 
1070
1118
 
1071
- static size_t ZSTDMT_flushStream_internal(ZSTDMT_CCtx* zcs, ZSTD_outBuffer* output, unsigned endFrame)
1119
+ static size_t ZSTDMT_flushStream_internal(ZSTDMT_CCtx* mtctx, ZSTD_outBuffer* output, unsigned endFrame)
1072
1120
  {
1073
- size_t const srcSize = zcs->inBuff.filled - zcs->dictSize;
1121
+ size_t const srcSize = mtctx->inBuff.filled - mtctx->dictSize;
1122
+ DEBUGLOG(5, "ZSTDMT_flushStream_internal");
1074
1123
 
1075
- if ( ((srcSize > 0) || (endFrame && !zcs->frameEnded))
1076
- && (zcs->nextJobID <= zcs->doneJobID + zcs->jobIDMask) ) {
1077
- CHECK_F( ZSTDMT_createCompressionJob(zcs, srcSize, endFrame) );
1124
+ if ( ((srcSize > 0) || (endFrame && !mtctx->frameEnded))
1125
+ && (mtctx->nextJobID <= mtctx->doneJobID + mtctx->jobIDMask) ) {
1126
+ DEBUGLOG(5, "ZSTDMT_flushStream_internal : create a new job");
1127
+ CHECK_F( ZSTDMT_createCompressionJob(mtctx, srcSize, endFrame) );
1078
1128
  }
1079
1129
 
1080
1130
  /* check if there is any data available to flush */
1081
- return ZSTDMT_flushNextJob(zcs, output, 1 /* blockToFlush */);
1131
+ return ZSTDMT_flushNextJob(mtctx, output, 1 /* blockToFlush */);
1082
1132
  }
1083
1133
 
1084
1134
 
1085
- size_t ZSTDMT_flushStream(ZSTDMT_CCtx* zcs, ZSTD_outBuffer* output)
1135
+ size_t ZSTDMT_flushStream(ZSTDMT_CCtx* mtctx, ZSTD_outBuffer* output)
1086
1136
  {
1087
1137
  DEBUGLOG(5, "ZSTDMT_flushStream");
1088
- if (zcs->params.nbThreads==1)
1089
- return ZSTD_flushStream(zcs->cctxPool->cctx[0], output);
1090
- return ZSTDMT_flushStream_internal(zcs, output, 0 /* endFrame */);
1138
+ if (mtctx->singleThreaded)
1139
+ return ZSTD_flushStream(mtctx->cctxPool->cctx[0], output);
1140
+ return ZSTDMT_flushStream_internal(mtctx, output, 0 /* endFrame */);
1091
1141
  }
1092
1142
 
1093
- size_t ZSTDMT_endStream(ZSTDMT_CCtx* zcs, ZSTD_outBuffer* output)
1143
+ size_t ZSTDMT_endStream(ZSTDMT_CCtx* mtctx, ZSTD_outBuffer* output)
1094
1144
  {
1095
1145
  DEBUGLOG(4, "ZSTDMT_endStream");
1096
- if (zcs->params.nbThreads==1)
1097
- return ZSTD_endStream(zcs->cctxPool->cctx[0], output);
1098
- return ZSTDMT_flushStream_internal(zcs, output, 1 /* endFrame */);
1146
+ if (mtctx->singleThreaded)
1147
+ return ZSTD_endStream(mtctx->cctxPool->cctx[0], output);
1148
+ return ZSTDMT_flushStream_internal(mtctx, output, 1 /* endFrame */);
1099
1149
  }
@@ -50,7 +50,7 @@ ZSTDLIB_API size_t ZSTDMT_compressCCtx(ZSTDMT_CCtx* mtctx,
50
50
  /* === Streaming functions === */
51
51
 
52
52
  ZSTDLIB_API size_t ZSTDMT_initCStream(ZSTDMT_CCtx* mtctx, int compressionLevel);
53
- ZSTDLIB_API size_t ZSTDMT_resetCStream(ZSTDMT_CCtx* mtctx, unsigned long long pledgedSrcSize); /**< pledgedSrcSize is optional and can be zero == unknown */
53
+ ZSTDLIB_API size_t ZSTDMT_resetCStream(ZSTDMT_CCtx* mtctx, unsigned long long pledgedSrcSize); /**< if srcSize is not known at reset time, use ZSTD_CONTENTSIZE_UNKNOWN. Note: for compatibility with older programs, 0 means the same as ZSTD_CONTENTSIZE_UNKNOWN, but it may change in the future, to mean "empty" */
54
54
 
55
55
  ZSTDLIB_API size_t ZSTDMT_compressStream(ZSTDMT_CCtx* mtctx, ZSTD_outBuffer* output, ZSTD_inBuffer* input);
56
56
 
@@ -60,8 +60,8 @@ ZSTDLIB_API size_t ZSTDMT_endStream(ZSTDMT_CCtx* mtctx, ZSTD_outBuffer* output);
60
60
 
61
61
  /* === Advanced functions and parameters === */
62
62
 
63
- #ifndef ZSTDMT_SECTION_SIZE_MIN
64
- # define ZSTDMT_SECTION_SIZE_MIN (1U << 20) /* 1 MB - Minimum size of each compression job */
63
+ #ifndef ZSTDMT_JOBSIZE_MIN
64
+ # define ZSTDMT_JOBSIZE_MIN (1U << 20) /* 1 MB - Minimum size of each compression job */
65
65
  #endif
66
66
 
67
67
  ZSTDLIB_API size_t ZSTDMT_compress_advanced(ZSTDMT_CCtx* mtctx,
@@ -84,13 +84,13 @@ ZSTDLIB_API size_t ZSTDMT_initCStream_usingCDict(ZSTDMT_CCtx* mtctx,
84
84
  /* ZSTDMT_parameter :
85
85
  * List of parameters that can be set using ZSTDMT_setMTCtxParameter() */
86
86
  typedef enum {
87
- ZSTDMT_p_sectionSize, /* size of input "section". Each section is compressed in parallel. 0 means default, which is dynamically determined within compression functions */
88
- ZSTDMT_p_overlapSectionLog /* Log of overlapped section; 0 == no overlap, 6(default) == use 1/8th of window, >=9 == use full window */
87
+ ZSTDMT_p_jobSize, /* Each job is compressed in parallel. By default, this value is dynamically determined depending on compression parameters. Can be set explicitly here. */
88
+ ZSTDMT_p_overlapSectionLog /* Each job may reload a part of previous job to enhance compressionr ratio; 0 == no overlap, 6(default) == use 1/8th of window, >=9 == use full window */
89
89
  } ZSTDMT_parameter;
90
90
 
91
91
  /* ZSTDMT_setMTCtxParameter() :
92
92
  * allow setting individual parameters, one at a time, among a list of enums defined in ZSTDMT_parameter.
93
- * The function must be called typically after ZSTD_createCCtx().
93
+ * The function must be called typically after ZSTD_createCCtx() but __before ZSTDMT_init*() !__
94
94
  * Parameters not explicitly reset by ZSTDMT_init*() remain the same in consecutive compression sessions.
95
95
  * @return : 0, or an error code (which can be tested using ZSTD_isError()) */
96
96
  ZSTDLIB_API size_t ZSTDMT_setMTCtxParameter(ZSTDMT_CCtx* mtctx, ZSTDMT_parameter parameter, unsigned value);
@@ -112,7 +112,15 @@ ZSTDLIB_API size_t ZSTDMT_compressStream_generic(ZSTDMT_CCtx* mtctx,
112
112
 
113
113
  size_t ZSTDMT_CCtxParam_setMTCtxParameter(ZSTD_CCtx_params* params, ZSTDMT_parameter parameter, unsigned value);
114
114
 
115
- size_t ZSTDMT_initializeCCtxParameters(ZSTD_CCtx_params* params, unsigned nbThreads);
115
+ /* ZSTDMT_CCtxParam_setNbThreads()
116
+ * Set nbThreads, and clamp it correctly,
117
+ * also reset jobSize and overlapLog */
118
+ size_t ZSTDMT_CCtxParam_setNbThreads(ZSTD_CCtx_params* params, unsigned nbThreads);
119
+
120
+ /* ZSTDMT_getNbThreads():
121
+ * @return nb threads currently active in mtctx.
122
+ * mtctx must be valid */
123
+ size_t ZSTDMT_getNbThreads(const ZSTDMT_CCtx* mtctx);
116
124
 
117
125
  /*! ZSTDMT_initCStream_internal() :
118
126
  * Private use only. Init streaming operation.